[prev in list] [next in list] [prev in thread] [next in thread]
List: haiku-commits
Subject: [haiku-commits] haiku: hrev46458 - in src: add-ons/kernel/drivers/disk/virtual/ram_disk bin bin/pkgm
From: ingo_weinhold () gmx ! de
Date: 2013-11-30 16:03:08
Message-ID: 20131130160308.22E585C0DB9 () vmrepo ! haiku-os ! org
[Download RAW message or body]
hrev46458 adds 7 changesets to branch 'master'
old head: 0d9151c9ff7935d618ba4718f15136a0e185936b
new head: 25a83d13b95b7ef244ecff48dc1b0e027dcad340
overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=25a83d1+%5E0d9151c
----------------------------------------------------------------------------
065e6eb: ramdisk: Support file backing
* When registering a ram disk, a file can be specified. Its content will
be loaded into the ram disk:
echo register <file> > /dev/disk/virtual/ramdisk/control
* At any time changes to the ram disk data can be written back to the
file:
echo flush /path/to/ramdisk > /dev/disk/virtual/ramdisk/control
If not explicitly written back, the changes will be lost on reboot.
e26c3df: devfs: Remove superfluous create() hook
We don't support creation of files and the VFS calls open() when an
entry already exists.
4a5eb16: ramdisk: Add required DEBUG_PAGE_ACCESS_*() macros
28092be: devfs: Add devfs_{get,put}_device()
devfs_get_device() returns the device for a given path (if any), also
acquiring a reference to its vnode (thus ensuring the device won't go
away). devfs_put_device() puts the device vnode's reference.
aea2cb9: device_manager: Implement unpublish_device()
5df58b5: Move TextTable from pkgman to libshared
25a83d1: ramdisk: Switch to CLI command for user interface
* Drop the old "echo to control device" interface in favor of an ioctl
interface.
* Add CLI program "ramdisk" to manage RAM disks.
[ Ingo Weinhold <ingo_weinhold@gmx.de> ]
----------------------------------------------------------------------------
12 files changed, 1120 insertions(+), 304 deletions(-)
headers/private/file_systems/ram_disk/ram_disk.h | 47 ++
.../private/shared}/TextTable.h | 9 +
.../drivers/disk/virtual/ram_disk/ram_disk.cpp | 744 +++++++++++++------
src/bin/Jamfile | 5 +
src/bin/pkgman/Jamfile | 3 +-
src/bin/pkgman/command_search.cpp | 2 +-
src/bin/ramdisk.cpp | 477 ++++++++++++
src/kits/shared/Jamfile | 1 +
src/{bin/pkgman => kits/shared}/TextTable.cpp | 8 +-
src/system/kernel/device_manager/devfs.cpp | 96 +--
src/system/kernel/device_manager/devfs_private.h | 8 +-
.../kernel/device_manager/device_manager.cpp | 24 +-
############################################################################
Commit: 065e6eb2f4d661a462bd89130ed3ba6fd9813a45
URL: http://cgit.haiku-os.org/haiku/commit/?id=065e6eb
Author: Ingo Weinhold <ingo_weinhold@gmx.de>
Date: Fri Nov 29 01:07:14 2013 UTC
ramdisk: Support file backing
* When registering a ram disk, a file can be specified. Its content will
be loaded into the ram disk:
echo register <file> > /dev/disk/virtual/ramdisk/control
* At any time changes to the ram disk data can be written back to the
file:
echo flush /path/to/ramdisk > /dev/disk/virtual/ramdisk/control
If not explicitly written back, the changes will be lost on reboot.
----------------------------------------------------------------------------
diff --git a/src/add-ons/kernel/drivers/disk/virtual/ram_disk/ram_disk.cpp \
b/src/add-ons/kernel/drivers/disk/virtual/ram_disk/ram_disk.cpp index \
9437897..c0a9e63 100644
--- a/src/add-ons/kernel/drivers/disk/virtual/ram_disk/ram_disk.cpp
+++ b/src/add-ons/kernel/drivers/disk/virtual/ram_disk/ram_disk.cpp
@@ -100,12 +100,12 @@ struct ControlDevice : Device {
{
}
- status_t Register(const char* fileName, uint64 deviceSize)
+ status_t Register(const char* filePath, uint64 deviceSize)
{
device_attr attrs[] = {
{B_DEVICE_PRETTY_NAME, B_STRING_TYPE,
{string: "RAM Disk Raw Device"}},
- {kFilePathItem, B_STRING_TYPE, {string: fileName}},
+ {kFilePathItem, B_STRING_TYPE, {string: filePath}},
{kDeviceSizeItem, B_UINT64_TYPE, {ui64: deviceSize}},
{NULL}
};
@@ -130,6 +130,7 @@ struct RawDevice : Device, DoublyLinkedListLinkImpl<RawDevice> {
fIndex(-1),
fDeviceSize(0),
fDeviceName(NULL),
+ fFilePath(NULL),
fCache(NULL),
fDMAResource(NULL),
fIOScheduler(NULL)
@@ -144,14 +145,19 @@ struct RawDevice : Device, DoublyLinkedListLinkImpl<RawDevice> \
{ }
free(fDeviceName);
+ free(fFilePath);
}
int32 Index() const { return fIndex; }
off_t DeviceSize() const { return fDeviceSize; }
const char* DeviceName() const { return fDeviceName; }
- status_t Init(uint64 deviceSize)
+ status_t Init(const char* filePath, uint64 deviceSize)
{
+ fFilePath = filePath != NULL ? strdup(filePath) : NULL;
+ if (filePath != NULL && fFilePath == NULL)
+ return B_NO_MEMORY;
+
fDeviceSize = (deviceSize + B_PAGE_SIZE - 1) / B_PAGE_SIZE
* B_PAGE_SIZE;
@@ -206,6 +212,14 @@ struct RawDevice : Device, DoublyLinkedListLinkImpl<RawDevice> {
return error;
}
+ if (fFilePath != NULL) {
+ error = _LoadFile();
+ if (error != B_OK) {
+ Unprepare();
+ return error;
+ }
+ }
+
// no DMA restrictions
const dma_restrictions restrictions = {};
@@ -254,6 +268,140 @@ struct RawDevice : Device, DoublyLinkedListLinkImpl<RawDevice> \
{ }
}
+ status_t Flush()
+ {
+ static const size_t kPageCountPerIteration = 1024;
+ static const size_t kMaxGapSize = 15;
+
+ int fd = open(fFilePath, O_WRONLY);
+ if (fd < 0)
+ return errno;
+ FileDescriptorCloser fdCloser(fd);
+
+ vm_page** pages = new(std::nothrow) vm_page*[kPageCountPerIteration];
+ ArrayDeleter<vm_page*> pagesDeleter(pages);
+
+ uint8* buffer = (uint8*)malloc(kPageCountPerIteration * B_PAGE_SIZE);
+ MemoryDeleter bufferDeleter(buffer);
+
+ if (pages == NULL || buffer == NULL)
+ return B_NO_MEMORY;
+
+ // Iterate through all pages of the cache and write those back that have
+ // been modified.
+ AutoLocker<VMCache> locker(fCache);
+
+ status_t error = B_OK;
+
+ for (off_t offset = 0; offset < fDeviceSize;) {
+ // find the first modified page at or after the current offset
+ VMCachePagesTree::Iterator it
+ = fCache->pages.GetIterator(offset / B_PAGE_SIZE, true, true);
+ vm_page* firstModified;
+ while ((firstModified = it.Next()) != NULL
+ && !firstModified->modified) {
+ }
+
+ if (firstModified == NULL)
+ break;
+
+ if (firstModified->busy) {
+ fCache->WaitForPageEvents(firstModified, PAGE_EVENT_NOT_BUSY,
+ true);
+ continue;
+ }
+
+ pages[0] = firstModified;
+ page_num_t firstPageIndex = firstModified->cache_offset;
+ offset = firstPageIndex * B_PAGE_SIZE;
+
+ // Collect more pages until the gap between two modified pages gets
+ // too large or we hit the end of our array.
+ size_t previousModifiedIndex = 0;
+ size_t previousIndex = 0;
+ while (vm_page* page = it.Next()) {
+ page_num_t index = page->cache_offset - firstPageIndex;
+ if (page->busy
+ || index >= kPageCountPerIteration
+ || index - previousModifiedIndex > kMaxGapSize) {
+ break;
+ }
+
+ pages[index] = page;
+
+ // clear page array gap since the previous page
+ if (previousIndex + 1 < index) {
+ memset(pages + previousIndex + 1, 0,
+ (index - previousIndex - 1) * sizeof(vm_page*));
+ }
+
+ previousIndex = index;
+ if (page->modified)
+ previousModifiedIndex = index;
+ }
+
+ // mark all pages we want to write busy
+ size_t pagesToWrite = previousModifiedIndex + 1;
+ for (size_t i = 0; i < pagesToWrite; i++) {
+ if (pages[i] != NULL)
+ pages[i]->busy = true;
+ }
+
+ locker.Unlock();
+
+ // copy the pages to our buffer
+ for (size_t i = 0; i < pagesToWrite; i++) {
+ if (vm_page* page = pages[i]) {
+ error = vm_memcpy_from_physical(buffer + i * B_PAGE_SIZE,
+ page->physical_page_number * B_PAGE_SIZE, B_PAGE_SIZE,
+ false);
+ if (error != B_OK) {
+ dprintf("ramdisk: error copying page %" B_PRIu64
+ " data: %s\n", (uint64)page->physical_page_number,
+ strerror(error));
+ break;
+ }
+ } else
+ memset(buffer + i * B_PAGE_SIZE, 0, B_PAGE_SIZE);
+ }
+
+ // write the buffer
+ if (error == B_OK) {
+ ssize_t bytesWritten = pwrite(fd, buffer,
+ pagesToWrite * B_PAGE_SIZE, offset);
+ if (bytesWritten < 0) {
+ dprintf("ramdisk: error writing pages to file: %s\n",
+ strerror(bytesWritten));
+ error = bytesWritten;
+ }
+ else if ((size_t)bytesWritten != pagesToWrite * B_PAGE_SIZE) {
+ dprintf("ramdisk: error writing pages to file: short "
+ "write (%zd/%zu)\n", bytesWritten,
+ pagesToWrite * B_PAGE_SIZE);
+ error = B_ERROR;
+ }
+ }
+
+ // mark the pages unbusy, on success also unmodified
+ locker.Lock();
+
+ for (size_t i = 0; i < pagesToWrite; i++) {
+ if (vm_page* page = pages[i]) {
+ if (error == B_OK)
+ page->modified = false;
+ fCache->MarkPageUnbusy(page);
+ }
+ }
+
+ if (error != B_OK)
+ break;
+
+ offset += pagesToWrite * B_PAGE_SIZE;
+ }
+
+ return error;
+ }
+
status_t DoIO(IORequest* request)
{
return fIOScheduler->ScheduleRequest(request);
@@ -296,6 +444,9 @@ private:
while (length > 0) {
vm_page* page = pages[index];
+ if (isWrite)
+ page->modified = true;
+
error = _CopyData(page, vecs, vecOffset, isWrite);
if (error != B_OK)
break;
@@ -412,6 +563,7 @@ private:
pageData = (uint8*)virtualAddress;
}
+ status_t error = B_OK;
size_t length = B_PAGE_SIZE;
while (length > 0) {
size_t toCopy = std::min((generic_size_t)length,
@@ -425,13 +577,13 @@ private:
phys_addr_t vecAddress = vecs->base + vecOffset;
- status_t error = toPage
+ error = toPage
? vm_memcpy_from_physical(pageData, vecAddress, toCopy, false)
: (page != NULL
? vm_memcpy_to_physical(vecAddress, pageData, toCopy, false)
: vm_memset_physical(vecAddress, 0, toCopy));
if (error != B_OK)
- return error;
+ break;
pageData += toCopy;
length -= toCopy;
@@ -443,13 +595,132 @@ private:
thread_unpin_from_current_cpu(thread);
}
- return B_OK;
+ return error;
+ }
+
+ status_t _LoadFile()
+ {
+ static const size_t kPageCountPerIteration = 1024;
+
+ int fd = open(fFilePath, O_RDONLY);
+ if (fd < 0)
+ return errno;
+ FileDescriptorCloser fdCloser(fd);
+
+ vm_page** pages = new(std::nothrow) vm_page*[kPageCountPerIteration];
+ ArrayDeleter<vm_page*> pagesDeleter(pages);
+
+ uint8* buffer = (uint8*)malloc(kPageCountPerIteration * B_PAGE_SIZE);
+ MemoryDeleter bufferDeleter(buffer);
+ // TODO: Ideally we wouldn't use a buffer to read the file content,
+ // but read into the pages we allocated directly. Unfortunately
+ // there's no API to do that yet.
+
+ if (pages == NULL || buffer == NULL)
+ return B_NO_MEMORY;
+
+ status_t error = B_OK;
+
+ page_num_t allocatedPages = 0;
+ off_t offset = 0;
+ off_t sizeRemaining = fDeviceSize;
+ while (sizeRemaining > 0) {
+ // Note: fDeviceSize is B_PAGE_SIZE aligned.
+ size_t pagesToRead = std::min(kPageCountPerIteration,
+ size_t(sizeRemaining / B_PAGE_SIZE));
+
+ // allocate the missing pages
+ if (allocatedPages < pagesToRead) {
+ vm_page_reservation reservation;
+ vm_page_reserve_pages(&reservation,
+ pagesToRead - allocatedPages, VM_PRIORITY_SYSTEM);
+
+ while (allocatedPages < pagesToRead) {
+ pages[allocatedPages++]
+ = vm_page_allocate_page(&reservation, PAGE_STATE_WIRED);
+ }
+
+ vm_page_unreserve_pages(&reservation);
+ }
+
+ // read from the file
+ size_t bytesToRead = pagesToRead * B_PAGE_SIZE;
+ ssize_t bytesRead = pread(fd, buffer, bytesToRead, offset);
+ if (bytesRead < 0) {
+ error = bytesRead;
+ break;
+ }
+ size_t pagesRead = (bytesRead + B_PAGE_SIZE - 1) / B_PAGE_SIZE;
+ if (pagesRead < pagesToRead) {
+ error = B_ERROR;
+ break;
+ }
+
+ // clear the last read page, if partial
+ if ((size_t)bytesRead < pagesRead * B_PAGE_SIZE) {
+ memset(buffer + bytesRead, 0,
+ pagesRead * B_PAGE_SIZE - bytesRead);
+ }
+
+ // copy data to allocated pages
+ for (size_t i = 0; i < pagesRead; i++) {
+ vm_page* page = pages[i];
+ error = vm_memcpy_to_physical(
+ page->physical_page_number * B_PAGE_SIZE,
+ buffer + i * B_PAGE_SIZE, B_PAGE_SIZE, false);
+ if (error != B_OK)
+ break;
+ }
+
+ if (error != B_OK)
+ break;
+
+ // Add pages to cache. Ignore clear pages, though. Move those to the
+ // beginning of the array, so we can reuse them in the next
+ // iteration.
+ AutoLocker<VMCache> locker(fCache);
+
+ size_t clearPages = 0;
+ for (size_t i = 0; i < pagesRead; i++) {
+ uint64* pageData = (uint64*)(buffer + i * B_PAGE_SIZE);
+ bool isClear = true;
+ for (size_t k = 0; isClear && k < B_PAGE_SIZE / 8; k++)
+ isClear = pageData[k] == 0;
+
+ if (isClear)
+ pages[clearPages++] = pages[i];
+ else
+ fCache->InsertPage(pages[i], offset + i * B_PAGE_SIZE);
+ }
+
+ locker.Unlock();
+
+ // Move any left-over allocated pages to the end of the empty pages
+ // and compute the new allocated pages count.
+ if (pagesRead < allocatedPages) {
+ size_t count = allocatedPages - pagesRead;
+ memcpy(pages + clearPages, pages + pagesRead,
+ count * sizeof(vm_page*));
+ clearPages += count;
+ }
+ allocatedPages = clearPages;
+
+ offset += pagesRead * B_PAGE_SIZE;
+ sizeRemaining -= pagesRead * B_PAGE_SIZE;
+ }
+
+ // free left-over allocated pages
+ for (size_t i = 0; i < allocatedPages; i++)
+ vm_page_free(NULL, pages[i]);
+
+ return error;
}
private:
int32 fIndex;
off_t fDeviceSize;
char* fDeviceName;
+ char* fFilePath;
VMCache* fCache;
DMAResource* fDMAResource;
IOScheduler* fIOScheduler;
@@ -557,6 +828,22 @@ parse_command_line(char* buffer, char**& _argv, int& _argc)
}
+static RawDevice*
+find_raw_device(const char* deviceName)
+{
+ if (strncmp(deviceName, "/dev/", 5) == 0)
+ deviceName += 5;
+
+ for (RawDeviceList::Iterator it = sDeviceList.GetIterator();
+ RawDevice* device = it.Next();) {
+ if (strcmp(device->DeviceName(), deviceName) == 0)
+ return device;
+ }
+
+ return NULL;
+}
+
+
// #pragma mark - driver
@@ -591,18 +878,17 @@ ram_disk_driver_register_device(device_node* parent)
static status_t
ram_disk_driver_init_driver(device_node* node, void** _driverCookie)
{
-// const char* fileName;
uint64 deviceSize;
-// if (sDeviceManager->get_attr_string(node, kFilePathItem, &fileName, false)
-// == B_OK) {
if (sDeviceManager->get_attr_uint64(node, kDeviceSizeItem, &deviceSize,
false) == B_OK) {
+ const char* filePath = NULL;
+ sDeviceManager->get_attr_string(node, kFilePathItem, &filePath, false);
+
RawDevice* device = new(std::nothrow) RawDevice(node);
if (device == NULL)
return B_NO_MEMORY;
-// status_t error = device->Init(fileName);
- status_t error = device->Init(deviceSize);
+ status_t error = device->Init(filePath, deviceSize);
if (error != B_OK) {
delete device;
return error;
@@ -686,6 +972,7 @@ ram_disk_control_device_read(void* cookie, off_t position, void* \
buffer, }
+
static status_t
ram_disk_control_device_write(void* cookie, off_t position, const void* data,
size_t* _length)
@@ -724,38 +1011,68 @@ ram_disk_control_device_write(void* cookie, off_t position, \
const void* data, // execute command
if (strcmp(argv[0], "help") == 0) {
// help
-// dprintf("register <path>\n");
-// dprintf(" Registers file <path> as a new ram disk device.\n");
- dprintf("register <size>\n");
- dprintf(" Registers a new ram disk device with size <size>.\n");
+ dprintf("register (<path> | -s <size>)\n");
+ dprintf(" Registers a new ram disk device backed by file <path> or\n"
+ " an unbacked ram disk device with size <size>.\n");
dprintf("unregister <device>\n");
dprintf(" Unregisters <device>.\n");
+ dprintf("flush <device>\n");
+ dprintf(" Writes <device> changes back to the file associated with\n"
+ " it, if any.\n");
} else if (strcmp(argv[0], "register") == 0) {
// register
- if (argc != 2) {
- dprintf("Usage: register <size>\n");
+ if (argc < 2 || argc > 3 || (argc == 3 && strcmp(argv[1], "-s") != 0)) {
+ dprintf("Usage: register (<path> | -s <size>)\n");
return B_BAD_VALUE;
}
- // parse size argument
- char* end;
- uint64 deviceSize = strtoll(argv[1], &end, 0);
- if (end == argv[1]) {
- dprintf("Invalid size argument: \"%s\"\n", argv[1]);
- return B_BAD_VALUE;
- }
+ KPath path;
+ uint64 deviceSize = 0;
- switch (*end) {
- case 'g':
- deviceSize *= 1024;
- case 'm':
- deviceSize *= 1024;
- case 'k':
- deviceSize *= 1024;
- break;
+ if (argc == 2) {
+ // get a normalized file path
+ status_t error = path.SetTo(argv[1], true);
+ if (error != B_OK) {
+ dprintf("Invalid path \"%s\": %s\n", argv[1], strerror(error));
+ return B_BAD_VALUE;
+ }
+
+ struct stat st;
+ if (lstat(path.Path(), &st) != 0) {
+ dprintf("Failed to stat \"%s\": %s\n", path.Path(),
+ strerror(errno));
+ return errno;
+ }
+
+ if (!S_ISREG(st.st_mode)) {
+ dprintf("\"%s\" is not a file!\n", path.Path());
+ return B_BAD_VALUE;
+ }
+
+ deviceSize = st.st_size;
+ } else {
+ // parse size argument
+ const char* sizeString = argv[2];
+ char* end;
+ deviceSize = strtoll(sizeString, &end, 0);
+ if (end == sizeString) {
+ dprintf("Invalid size argument: \"%s\"\n", sizeString);
+ return B_BAD_VALUE;
+ }
+
+ switch (*end) {
+ case 'g':
+ deviceSize *= 1024;
+ case 'm':
+ deviceSize *= 1024;
+ case 'k':
+ deviceSize *= 1024;
+ break;
+ }
}
- return device->Register(NULL, deviceSize);
+ return device->Register(path.Length() > 0 ? path.Path() : NULL,
+ deviceSize);
} else if (strcmp(argv[0], "unregister") == 0) {
// unregister
if (argc != 2) {
@@ -764,41 +1081,65 @@ ram_disk_control_device_write(void* cookie, off_t position, \
const void* data, }
const char* deviceName = argv[1];
- if (strncmp(deviceName, "/dev/", 5) == 0)
- deviceName += 5;
// find the device in the list and unregister it
MutexLocker locker(sDeviceListLock);
- for (RawDeviceList::Iterator it = sDeviceList.GetIterator();
- RawDevice* device = it.Next();) {
- if (strcmp(device->DeviceName(), deviceName) == 0) {
- // TODO: Race condition: We should mark the device as going to
- // be unregistered, so no one else can try the same after we
- // unlock!
- locker.Unlock();
+ if (RawDevice* device = find_raw_device(deviceName)) {
+ // TODO: Race condition: We should mark the device as going to
+ // be unregistered, so no one else can try the same after we
+ // unlock!
+ locker.Unlock();
// TODO: The following doesn't work! unpublish_device(), as per implementation
// (partially commented out) and unregister_node() returns B_BUSY.
- status_t error = sDeviceManager->unpublish_device(
- device->Node(), device->DeviceName());
- if (error != B_OK) {
- dprintf("Failed to unpublish device \"%s\": %s\n",
- deviceName, strerror(error));
- return error;
- }
-
- error = sDeviceManager->unregister_node(device->Node());
- if (error != B_OK) {
- dprintf("Failed to unregister node \"%s\": %s\n",
- deviceName, strerror(error));
- return error;
- }
+ status_t error = sDeviceManager->unpublish_device(
+ device->Node(), device->DeviceName());
+ if (error != B_OK) {
+ dprintf("Failed to unpublish device \"%s\": %s\n",
+ deviceName, strerror(error));
+ return error;
+ }
- return B_OK;
+ error = sDeviceManager->unregister_node(device->Node());
+ if (error != B_OK) {
+ dprintf("Failed to unregister node \"%s\": %s\n",
+ deviceName, strerror(error));
+ return error;
}
+
+ return B_OK;
}
dprintf("Device \"%s\" not found!\n", deviceName);
return B_BAD_VALUE;
+ } else if (strcmp(argv[0], "flush") == 0) {
+ // flush
+ if (argc != 2) {
+ dprintf("Usage: unregister <device>\n");
+ return B_BAD_VALUE;
+ }
+
+ const char* deviceName = argv[1];
+
+ // find the device in the list and flush it
+ MutexLocker locker(sDeviceListLock);
+ RawDevice* device = find_raw_device(deviceName);
+ if (device == NULL) {
+ dprintf("Device \"%s\" not found!\n", deviceName);
+ return B_BAD_VALUE;
+ }
+
+ // TODO: Race condition: Once we unlock someone could unregister the
+ // device. We should probably open the device by path, and use a
+ // special ioctl.
+ locker.Unlock();
+
+ status_t error = device->Flush();
+ if (error != B_OK) {
+ dprintf("Failed to flush device: %s\n", strerror(error));
+ return error;
+ }
+
+ return B_OK;
} else {
dprintf("Invalid command \"%s\"!\n", argv[0]);
return B_BAD_VALUE;
############################################################################
Commit: e26c3df48cc8599688803a11f35535ec3f89c6b6
URL: http://cgit.haiku-os.org/haiku/commit/?id=e26c3df
Author: Ingo Weinhold <ingo_weinhold@gmx.de>
Date: Fri Nov 29 15:05:56 2013 UTC
devfs: Remove superfluous create() hook
We don't support creation of files and the VFS calls open() when an
entry already exists.
----------------------------------------------------------------------------
diff --git a/src/system/kernel/device_manager/devfs.cpp \
b/src/system/kernel/device_manager/devfs.cpp index ca77751..6127269 100644
--- a/src/system/kernel/device_manager/devfs.cpp
+++ b/src/system/kernel/device_manager/devfs.cpp
@@ -1082,70 +1082,6 @@ devfs_remove_vnode(fs_volume* _volume, fs_vnode* _v, bool \
reenter)
static status_t
-devfs_create(fs_volume* _volume, fs_vnode* _dir, const char* name, int openMode,
- int perms, void** _cookie, ino_t* _newVnodeID)
-{
- struct devfs_vnode* dir = (struct devfs_vnode*)_dir->private_node;
- struct devfs* fs = (struct devfs*)_volume->private_volume;
- struct devfs_cookie* cookie;
- struct devfs_vnode* vnode;
- status_t status = B_OK;
-
- TRACE(("devfs_create: dir %p, name \"%s\", openMode 0x%x, fs_cookie %p \n",
- dir, name, openMode, _cookie));
-
- RecursiveLocker locker(fs->lock);
-
- // look it up
- vnode = devfs_find_in_dir(dir, name);
- if (vnode == NULL)
- return EROFS;
-
- if ((openMode & O_EXCL) != 0)
- return B_FILE_EXISTS;
-
- status = get_vnode(fs->volume, vnode->id, NULL);
- if (status != B_OK)
- return status;
-
- locker.Unlock();
-
- *_newVnodeID = vnode->id;
-
- cookie = (struct devfs_cookie*)malloc(sizeof(struct devfs_cookie));
- if (cookie == NULL) {
- status = B_NO_MEMORY;
- goto err1;
- }
-
- if (S_ISCHR(vnode->stream.type)) {
- BaseDevice* device = vnode->stream.u.dev.device;
- status = device->InitDevice();
- if (status != B_OK)
- goto err2;
-
- char path[B_FILE_NAME_LENGTH];
- get_device_name(vnode, path, sizeof(path));
-
- status = device->Open(path, openMode, &cookie->device_cookie);
- if (status != B_OK) {
- device->UninitDevice();
- goto err2;
- }
- }
-
- *_cookie = cookie;
- return B_OK;
-
-err2:
- free(cookie);
-err1:
- put_vnode(fs->volume, vnode->id);
- return status;
-}
-
-
-static status_t
devfs_open(fs_volume* _volume, fs_vnode* _vnode, int openMode,
void** _cookie)
{
@@ -1978,7 +1914,7 @@ fs_vnode_ops kVnodeOps = {
NULL,
/* file */
- &devfs_create,
+ NULL, // create
&devfs_open,
&devfs_close,
&devfs_free_cookie,
############################################################################
Commit: 4a5eb160530cec0e87772e2aa3aa1a7f1703b55e
URL: http://cgit.haiku-os.org/haiku/commit/?id=4a5eb16
Author: Ingo Weinhold <ingo_weinhold@gmx.de>
Date: Fri Nov 29 23:24:42 2013 UTC
ramdisk: Add required DEBUG_PAGE_ACCESS_*() macros
----------------------------------------------------------------------------
diff --git a/src/add-ons/kernel/drivers/disk/virtual/ram_disk/ram_disk.cpp \
b/src/add-ons/kernel/drivers/disk/virtual/ram_disk/ram_disk.cpp index \
c0a9e63..529b61b 100644
--- a/src/add-ons/kernel/drivers/disk/virtual/ram_disk/ram_disk.cpp
+++ b/src/add-ons/kernel/drivers/disk/virtual/ram_disk/ram_disk.cpp
@@ -343,8 +343,10 @@ struct RawDevice : Device, DoublyLinkedListLinkImpl<RawDevice> {
// mark all pages we want to write busy
size_t pagesToWrite = previousModifiedIndex + 1;
for (size_t i = 0; i < pagesToWrite; i++) {
- if (pages[i] != NULL)
+ if (vm_page* page = pages[i]) {
+ DEBUG_PAGE_ACCESS_START(page);
pages[i]->busy = true;
+ }
}
locker.Unlock();
@@ -390,6 +392,7 @@ struct RawDevice : Device, DoublyLinkedListLinkImpl<RawDevice> {
if (error == B_OK)
page->modified = false;
fCache->MarkPageUnbusy(page);
+ DEBUG_PAGE_ACCESS_END(page);
}
}
@@ -485,6 +488,7 @@ private:
continue;
}
+ DEBUG_PAGE_ACCESS_START(page);
page->busy = true;
} else
missingPages++;
@@ -531,10 +535,13 @@ private:
if (success) {
fCache->InsertPage(page, offset);
fCache->MarkPageUnbusy(page);
+ DEBUG_PAGE_ACCESS_END(page);
} else
vm_page_free(NULL, page);
- } else
+ } else {
fCache->MarkPageUnbusy(page);
+ DEBUG_PAGE_ACCESS_END(page);
+ }
}
offset += B_PAGE_SIZE;
@@ -687,10 +694,12 @@ private:
for (size_t k = 0; isClear && k < B_PAGE_SIZE / 8; k++)
isClear = pageData[k] == 0;
- if (isClear)
+ if (isClear) {
pages[clearPages++] = pages[i];
- else
+ } else {
fCache->InsertPage(pages[i], offset + i * B_PAGE_SIZE);
+ DEBUG_PAGE_ACCESS_END(pages[i]);
+ }
}
locker.Unlock();
############################################################################
Commit: 28092be1969370f0c4a92536ed066c5700cc56f0
URL: http://cgit.haiku-os.org/haiku/commit/?id=28092be
Author: Ingo Weinhold <ingo_weinhold@gmx.de>
Date: Fri Nov 29 23:26:43 2013 UTC
devfs: Add devfs_{get,put}_device()
devfs_get_device() returns the device for a given path (if any), also
acquiring a reference to its vnode (thus ensuring the device won't go
away). devfs_put_device() puts the device vnode's reference.
----------------------------------------------------------------------------
diff --git a/src/system/kernel/device_manager/devfs.cpp \
b/src/system/kernel/device_manager/devfs.cpp index 6127269..88564a9 100644
--- a/src/system/kernel/device_manager/devfs.cpp
+++ b/src/system/kernel/device_manager/devfs.cpp
@@ -2143,6 +2143,34 @@ devfs_unpublish_device(BaseDevice* device, bool disconnect)
}
+/*! Gets the device for a given devfs relative path.
+ If successful the call must be balanced with a call to devfs_put_device().
+*/
+status_t
+devfs_get_device(const char* path, BaseDevice*& _device)
+{
+ devfs_vnode* node;
+ status_t status = get_node_for_path(sDeviceFileSystem, path, &node);
+ if (status != B_OK)
+ return status;
+
+ if (!S_ISCHR(node->stream.type) || node->stream.u.dev.partition != NULL) {
+ put_vnode(sDeviceFileSystem->volume, node->id);
+ return B_BAD_VALUE;
+ }
+
+ _device = node->stream.u.dev.device;
+ return B_OK;
+}
+
+
+void
+devfs_put_device(BaseDevice* device)
+{
+ put_vnode(sDeviceFileSystem->volume, device->ID());
+}
+
+
void
devfs_compute_geometry_size(device_geometry* geometry, uint64 blockCount,
uint32 blockSize)
@@ -2175,5 +2203,3 @@ devfs_publish_device(const char* path, device_hooks* hooks)
{
return legacy_driver_publish(path, hooks);
}
-
-
diff --git a/src/system/kernel/device_manager/devfs_private.h \
b/src/system/kernel/device_manager/devfs_private.h index dc0ea91..7436513 100644
--- a/src/system/kernel/device_manager/devfs_private.h
+++ b/src/system/kernel/device_manager/devfs_private.h
@@ -16,8 +16,10 @@ namespace BPrivate {
using BPrivate::BaseDevice;
-status_t devfs_publish_device(const char* path, BaseDevice* device);
-status_t devfs_unpublish_device(BaseDevice* device, bool disconnect);
-status_t devfs_get_device(dev_t device, ino_t node, BaseDevice** _device);
+status_t devfs_publish_device(const char* path, BaseDevice* device);
+status_t devfs_unpublish_device(BaseDevice* device, bool disconnect);
+
+status_t devfs_get_device(const char* path, BaseDevice*& _device);
+void devfs_put_device(BaseDevice* device);
#endif /* DEVFS_PRIVATE_H */
############################################################################
Commit: aea2cb917eb329bf2b56b64097e113d4417ba3b1
URL: http://cgit.haiku-os.org/haiku/commit/?id=aea2cb9
Author: Ingo Weinhold <ingo_weinhold@gmx.de>
Date: Fri Nov 29 23:27:30 2013 UTC
device_manager: Implement unpublish_device()
----------------------------------------------------------------------------
diff --git a/src/system/kernel/device_manager/device_manager.cpp \
b/src/system/kernel/device_manager/device_manager.cpp index 5de0b31..5537aa0 100644
--- a/src/system/kernel/device_manager/device_manager.cpp
+++ b/src/system/kernel/device_manager/device_manager.cpp
@@ -757,21 +757,17 @@ unpublish_device(device_node *node, const char *path)
if (path == NULL)
return B_BAD_VALUE;
- RecursiveLocker _(sLock);
-
-#if 0
- DeviceList::ConstIterator iterator = node->Devices().GetIterator();
- while (iterator.HasNext()) {
- Device* device = iterator.Next();
- if (!strcmp(device->Path(), path)) {
- node->RemoveDevice(device);
- delete device;
- return B_OK;
- }
- }
-#endif
+ BaseDevice* baseDevice;
+ status_t error = devfs_get_device(path, baseDevice);
+ if (error != B_OK)
+ return error;
+ CObjectDeleter<BaseDevice> baseDevicePutter(baseDevice, &devfs_put_device);
+
+ Device* device = dynamic_cast<Device*>(baseDevice);
+ if (device == NULL || device->Node() != node)
+ return B_BAD_VALUE;
- return B_ENTRY_NOT_FOUND;
+ return devfs_unpublish_device(device, true);
}
############################################################################
Commit: 5df58b522b52d5914bf8b49fc47ff46fde56877f
URL: http://cgit.haiku-os.org/haiku/commit/?id=5df58b5
Author: Ingo Weinhold <ingo_weinhold@gmx.de>
Date: Sat Nov 30 15:18:03 2013 UTC
Move TextTable from pkgman to libshared
----------------------------------------------------------------------------
diff --git a/src/bin/pkgman/TextTable.h b/headers/private/shared/TextTable.h
similarity index 91%
rename from src/bin/pkgman/TextTable.h
rename to headers/private/shared/TextTable.h
index dd94bfe..3d37e38 100644
--- a/src/bin/pkgman/TextTable.h
+++ b/headers/private/shared/TextTable.h
@@ -11,6 +11,9 @@
#include <StringList.h>
+namespace BPrivate {
+
+
class TextTable {
public:
TextTable();
@@ -39,4 +42,10 @@ private:
};
+} // namespace BPrivate
+
+
+using ::BPrivate::TextTable;
+
+
#endif // TEXT_TABLE_H
diff --git a/src/bin/pkgman/Jamfile b/src/bin/pkgman/Jamfile
index e225036..3ff4b48 100644
--- a/src/bin/pkgman/Jamfile
+++ b/src/bin/pkgman/Jamfile
@@ -17,8 +17,7 @@ BinCommand pkgman :
JobStateListener.cpp
PackageManager.cpp
pkgman.cpp
- TextTable.cpp
:
- package be
+ libshared.a package be
$(TARGET_LIBSUPC++) $(TARGET_LIBSTDC++)
;
diff --git a/src/bin/pkgman/command_search.cpp b/src/bin/pkgman/command_search.cpp
index d84cff1..23c1ce2 100644
--- a/src/bin/pkgman/command_search.cpp
+++ b/src/bin/pkgman/command_search.cpp
@@ -18,11 +18,11 @@
#include <set>
#include <package/solver/SolverPackage.h>
+#include <TextTable.h>
#include "Command.h"
#include "PackageManager.h"
#include "pkgman.h"
-#include "TextTable.h"
// TODO: internationalization!
diff --git a/src/kits/shared/Jamfile b/src/kits/shared/Jamfile
index e170392..6a44e76 100644
--- a/src/kits/shared/Jamfile
+++ b/src/kits/shared/Jamfile
@@ -45,6 +45,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
ShakeTrackingFilter.cpp
StringForRate.cpp
StringForSize.cpp
+ TextTable.cpp
Thread.cpp
Variant.cpp
;
diff --git a/src/bin/pkgman/TextTable.cpp b/src/kits/shared/TextTable.cpp
similarity index 98%
rename from src/bin/pkgman/TextTable.cpp
rename to src/kits/shared/TextTable.cpp
index f173665..2601205 100644
--- a/src/bin/pkgman/TextTable.cpp
+++ b/src/kits/shared/TextTable.cpp
@@ -4,13 +4,16 @@
*/
-#include "TextTable.h"
+#include <TextTable.h>
#include <stdio.h>
#include <algorithm>
+namespace BPrivate {
+
+
// #pragma mark - Column
@@ -272,3 +275,6 @@ TextTable::Print(int32 maxWidth)
fputs(line.String(), stdout);
}
}
+
+
+} // namespace BPrivate
############################################################################
Revision: hrev46458
Commit: 25a83d13b95b7ef244ecff48dc1b0e027dcad340
URL: http://cgit.haiku-os.org/haiku/commit/?id=25a83d1
Author: Ingo Weinhold <ingo_weinhold@gmx.de>
Date: Sat Nov 30 16:01:49 2013 UTC
ramdisk: Switch to CLI command for user interface
* Drop the old "echo to control device" interface in favor of an ioctl
interface.
* Add CLI program "ramdisk" to manage RAM disks.
----------------------------------------------------------------------------
diff --git a/headers/private/file_systems/ram_disk/ram_disk.h \
b/headers/private/file_systems/ram_disk/ram_disk.h new file mode 100644
index 0000000..0a8279a
--- /dev/null
+++ b/headers/private/file_systems/ram_disk/ram_disk.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _PRIVATE_FILE_SYSTEMS_RAM_DISK_RAM_DISK_H
+#define _PRIVATE_FILE_SYSTEMS_RAM_DISK_RAM_DISK_H
+
+
+#include <Drivers.h>
+#include <StorageDefs.h>
+
+
+#define RAM_DISK_CONTROL_DEVICE_NAME "disk/virtual/ram/control"
+#define RAM_DISK_RAW_DEVICE_BASE_NAME "disk/virtual/ram"
+
+
+enum {
+ RAM_DISK_IOCTL_REGISTER = B_DEVICE_OP_CODES_END + 1,
+ RAM_DISK_IOCTL_UNREGISTER,
+ RAM_DISK_IOCTL_FLUSH,
+ RAM_DISK_IOCTL_INFO
+};
+
+
+struct ram_disk_ioctl_register {
+ uint64 size;
+ char path[B_PATH_NAME_LENGTH];
+
+ // return value
+ int32 id;
+};
+
+
+struct ram_disk_ioctl_unregister {
+ int32 id;
+};
+
+
+struct ram_disk_ioctl_info {
+ // return values
+ int32 id;
+ uint64 size;
+ char path[B_PATH_NAME_LENGTH];
+};
+
+
+#endif // _PRIVATE_FILE_SYSTEMS_RAM_DISK_RAM_DISK_H
diff --git a/src/add-ons/kernel/drivers/disk/virtual/ram_disk/ram_disk.cpp \
b/src/add-ons/kernel/drivers/disk/virtual/ram_disk/ram_disk.cpp index \
529b61b..8807d27 100644
--- a/src/add-ons/kernel/drivers/disk/virtual/ram_disk/ram_disk.cpp
+++ b/src/add-ons/kernel/drivers/disk/virtual/ram_disk/ram_disk.cpp
@@ -4,6 +4,8 @@
*/
+#include <file_systems/ram_disk/ram_disk.h>
+
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
@@ -50,12 +52,12 @@ static const char* const kControlDeviceModuleName
static const char* const kRawDeviceModuleName
= "drivers/disk/virtual/ram_disk/raw/device_v1";
-static const char* const kControlDeviceName
- = "disk/virtual/ram/control";
-static const char* const kRawDeviceBaseName = "disk/virtual/ram";
+static const char* const kControlDeviceName = RAM_DISK_CONTROL_DEVICE_NAME;
+static const char* const kRawDeviceBaseName = RAM_DISK_RAW_DEVICE_BASE_NAME;
static const char* const kFilePathItem = "ram_disk/file_path";
static const char* const kDeviceSizeItem = "ram_disk/device_size";
+static const char* const kDeviceIDItem = "ram_disk/id";
struct RawDevice;
@@ -65,6 +67,11 @@ struct device_manager_info* sDeviceManager;
static RawDeviceList sDeviceList;
static mutex sDeviceListLock = MUTEX_INITIALIZER("ram disk device list");
+static uint64 sUsedRawDeviceIDs = 0;
+
+
+static int32 allocate_raw_device_id();
+static void free_raw_device_id(int32 id);
struct Device {
@@ -100,19 +107,37 @@ struct ControlDevice : Device {
{
}
- status_t Register(const char* filePath, uint64 deviceSize)
+ status_t Register(const char* filePath, uint64 deviceSize, int32& _id)
{
+ int32 id = allocate_raw_device_id();
+ if (id < 0)
+ return B_BUSY;
+
device_attr attrs[] = {
{B_DEVICE_PRETTY_NAME, B_STRING_TYPE,
{string: "RAM Disk Raw Device"}},
- {kFilePathItem, B_STRING_TYPE, {string: filePath}},
{kDeviceSizeItem, B_UINT64_TYPE, {ui64: deviceSize}},
+ {kDeviceIDItem, B_UINT32_TYPE, {ui32: (uint32)id}},
+ {kFilePathItem, B_STRING_TYPE, {string: filePath}},
{NULL}
};
- return sDeviceManager->register_node(
+ // If filePath is NULL, remove the attribute.
+ if (filePath == NULL) {
+ size_t count = sizeof(attrs) / sizeof(attrs[0]);
+ memset(attrs + count - 2, 0, sizeof(attrs[0]));
+ }
+
+ status_t error = sDeviceManager->register_node(
sDeviceManager->get_parent_node(Node()), kDriverModuleName, attrs,
NULL, NULL);
+ if (error != B_OK) {
+ free_raw_device_id(id);
+ return error;
+ }
+
+ _id = id;
+ return B_OK;
}
virtual status_t PublishDevice()
@@ -127,7 +152,8 @@ struct RawDevice : Device, DoublyLinkedListLinkImpl<RawDevice> {
RawDevice(device_node* node)
:
Device(node),
- fIndex(-1),
+ fID(-1),
+ fUnregistered(false),
fDeviceSize(0),
fDeviceName(NULL),
fFilePath(NULL),
@@ -139,7 +165,7 @@ struct RawDevice : Device, DoublyLinkedListLinkImpl<RawDevice> {
virtual ~RawDevice()
{
- if (fIndex >= 0) {
+ if (fID >= 0) {
MutexLocker locker(sDeviceListLock);
sDeviceList.Remove(this);
}
@@ -148,12 +174,20 @@ struct RawDevice : Device, DoublyLinkedListLinkImpl<RawDevice> \
{ free(fFilePath);
}
- int32 Index() const { return fIndex; }
+ int32 ID() const { return fID; }
off_t DeviceSize() const { return fDeviceSize; }
const char* DeviceName() const { return fDeviceName; }
- status_t Init(const char* filePath, uint64 deviceSize)
+ bool IsUnregistered() const { return fUnregistered; }
+
+ void SetUnregistered(bool unregistered)
+ {
+ fUnregistered = unregistered;
+ }
+
+ status_t Init(int32 id, const char* filePath, uint64 deviceSize)
{
+ fID = id;
fFilePath = filePath != NULL ? strdup(filePath) : NULL;
if (filePath != NULL && fFilePath == NULL)
return B_NO_MEMORY;
@@ -167,23 +201,10 @@ struct RawDevice : Device, DoublyLinkedListLinkImpl<RawDevice> \
{ return B_BAD_VALUE;
}
- // find a free slot
- fIndex = 0;
- RawDevice* nextDevice = NULL;
- MutexLocker locker(sDeviceListLock);
- for (RawDeviceList::Iterator it = sDeviceList.GetIterator();
- (nextDevice = it.Next()) != NULL;) {
- if (nextDevice->Index() > fIndex)
- break;
- fIndex = nextDevice->Index() + 1;
- }
-
- sDeviceList.InsertBefore(nextDevice, this);
-
// construct our device path
KPath path(kRawDeviceBaseName);
char buffer[32];
- snprintf(buffer, sizeof(buffer), "%" B_PRId32 "/raw", fIndex);
+ snprintf(buffer, sizeof(buffer), "%" B_PRId32 "/raw", fID);
status_t error = path.Append(buffer);
if (error != B_OK)
@@ -191,6 +212,17 @@ struct RawDevice : Device, DoublyLinkedListLinkImpl<RawDevice> {
fDeviceName = path.DetachBuffer();
+ // insert into device list
+ RawDevice* nextDevice = NULL;
+ MutexLocker locker(sDeviceListLock);
+ for (RawDeviceList::Iterator it = sDeviceList.GetIterator();
+ (nextDevice = it.Next()) != NULL;) {
+ if (nextDevice->ID() > fID)
+ break;
+ }
+
+ sDeviceList.InsertBefore(nextDevice, this);
+
return B_OK;
}
@@ -268,6 +300,15 @@ struct RawDevice : Device, DoublyLinkedListLinkImpl<RawDevice> {
}
}
+ void GetInfo(ram_disk_ioctl_info& _info) const
+ {
+ _info.id = fID;
+ _info.size = fDeviceSize;
+ memset(&_info.path, 0, sizeof(_info.path));
+ if (fFilePath != NULL)
+ strlcpy(_info.path, fFilePath, sizeof(_info.path));
+ }
+
status_t Flush()
{
static const size_t kPageCountPerIteration = 1024;
@@ -726,7 +767,8 @@ private:
}
private:
- int32 fIndex;
+ int32 fID;
+ bool fUnregistered;
off_t fDeviceSize;
char* fDeviceName;
char* fFilePath;
@@ -756,100 +798,157 @@ private:
// #pragma mark -
-static bool
-parse_command_line(char* buffer, char**& _argv, int& _argc)
+static int32
+allocate_raw_device_id()
{
- // Process the argument string. We split at whitespace, heeding quotes and
- // escaped characters. The processed arguments are written to the given
- // buffer, separated by single null chars.
- char* start = buffer;
- char* out = buffer;
- bool pendingArgument = false;
- int argc = 0;
- while (*start != '\0') {
- // ignore whitespace
- if (isspace(*start)) {
- if (pendingArgument) {
- *out = '\0';
- out++;
- argc++;
- pendingArgument = false;
- }
- start++;
- continue;
+ MutexLocker deviceListLocker(sDeviceListLock);
+ for (size_t i = 0; i < sizeof(sUsedRawDeviceIDs) * 8; i++) {
+ if ((sUsedRawDeviceIDs & ((uint64)1 << i)) == 0) {
+ sUsedRawDeviceIDs |= (uint64)1 << i;
+ return (int32)i;
}
+ }
- pendingArgument = true;
+ return -1;
+}
- if (*start == '"' || *start == '\'') {
- // quoted text -- continue until closing quote
- char quote = *start;
- start++;
- while (*start != '\0' && *start != quote) {
- if (*start == '\\' && quote == '"') {
- start++;
- if (*start == '\0')
- break;
- }
- *out = *start;
- start++;
- out++;
- }
- if (*start != '\0')
- start++;
- } else {
- // unquoted text
- if (*start == '\\') {
- // escaped char
- start++;
- if (start == '\0')
- break;
- }
+static void
+free_raw_device_id(int32 id)
+{
+ MutexLocker deviceListLocker(sDeviceListLock);
+ sUsedRawDeviceIDs &= ~((uint64)1 << id);
+}
- *out = *start;
- start++;
- out++;
- }
- }
- if (pendingArgument) {
- *out = '\0';
- argc++;
+static RawDevice*
+find_raw_device(int32 id)
+{
+ for (RawDeviceList::Iterator it = sDeviceList.GetIterator();
+ RawDevice* device = it.Next();) {
+ if (device->ID() == id)
+ return device;
}
- // allocate argument vector
- char** argv = new(std::nothrow) char*[argc + 1];
- if (argv == NULL)
- return false;
+ return NULL;
+}
+
- // fill vector
- start = buffer;
- for (int i = 0; i < argc; i++) {
- argv[i] = start;
- start += strlen(start) + 1;
+static status_t
+ioctl_register(ControlDevice* controlDevice, ram_disk_ioctl_register* request)
+{
+ KPath path;
+ uint64 deviceSize = 0;
+
+ if (request->path[0] != '\0') {
+ // check if the path is null-terminated
+ if (strnlen(request->path, sizeof(request->path))
+ == sizeof(request->path)) {
+ return B_BAD_VALUE;
+ }
+
+ // get a normalized file path
+ status_t error = path.SetTo(request->path, true);
+ if (error != B_OK) {
+ dprintf("ramdisk: register: Invalid path \"%s\": %s\n",
+ request->path, strerror(error));
+ return B_BAD_VALUE;
+ }
+
+ struct stat st;
+ if (lstat(path.Path(), &st) != 0) {
+ dprintf("ramdisk: register: Failed to stat \"%s\": %s\n",
+ path.Path(), strerror(errno));
+ return errno;
+ }
+
+ if (!S_ISREG(st.st_mode)) {
+ dprintf("ramdisk: register: \"%s\" is not a file!\n", path.Path());
+ return B_BAD_VALUE;
+ }
+
+ deviceSize = st.st_size;
+ } else {
+ deviceSize = request->size;
}
- argv[argc] = NULL;
- _argv = argv;
- _argc = argc;
- return true;
+ return controlDevice->Register(path.Length() > 0 ? path.Path() : NULL,
+ deviceSize, request->id);
}
-static RawDevice*
-find_raw_device(const char* deviceName)
+static status_t
+ioctl_unregister(ControlDevice* controlDevice,
+ ram_disk_ioctl_unregister* request)
{
- if (strncmp(deviceName, "/dev/", 5) == 0)
- deviceName += 5;
+ // find the device in the list and unregister it
+ MutexLocker locker(sDeviceListLock);
+ RawDevice* device = find_raw_device(request->id);
+ if (device == NULL)
+ return B_ENTRY_NOT_FOUND;
+
+ // mark unregistered before we unlock
+ if (device->IsUnregistered())
+ return B_BUSY;
+ device->SetUnregistered(true);
+ locker.Unlock();
+
+ device_node* node = device->Node();
+ status_t error = sDeviceManager->unpublish_device(node,
+ device->DeviceName());
+ if (error != B_OK) {
+ dprintf("ramdisk: unregister: Failed to unpublish device \"%s\": %s\n",
+ device->DeviceName(), strerror(error));
+ return error;
+ }
- for (RawDeviceList::Iterator it = sDeviceList.GetIterator();
- RawDevice* device = it.Next();) {
- if (strcmp(device->DeviceName(), deviceName) == 0)
- return device;
+ error = sDeviceManager->unregister_node(node);
+ // Note: B_BUSY is OK. The node will removed as soon as possible.
+ if (error != B_OK && error != B_BUSY) {
+ dprintf("ramdisk: unregister: Failed to unregister node for device %"
+ B_PRId32 ": %s\n", request->id, strerror(error));
+ return error;
}
- return NULL;
+ return B_OK;
+}
+
+
+static status_t
+ioctl_info(RawDevice* device, ram_disk_ioctl_info* request)
+{
+ device->GetInfo(*request);
+ return B_OK;
+}
+
+
+template<typename DeviceType, typename Request>
+static status_t
+handle_ioctl(DeviceType* device,
+ status_t (*handler)(DeviceType*, Request*), void* buffer)
+{
+ // copy request to the kernel heap
+ if (buffer == NULL || !IS_USER_ADDRESS(buffer))
+ return B_BAD_ADDRESS;
+
+ Request* request = new(std::nothrow) Request;
+ if (request == NULL)
+ return B_NO_MEMORY;
+ ObjectDeleter<Request> requestDeleter(request);
+
+ if (user_memcpy(request, buffer, sizeof(Request)) != B_OK)
+ return B_BAD_ADDRESS;
+
+ // handle the ioctl
+ status_t error = handler(device, request);
+ if (error != B_OK)
+ return error;
+
+ // copy the request back to userland
+ if (user_memcpy(buffer, request, sizeof(Request)) != B_OK)
+ return B_BAD_ADDRESS;
+
+ return B_OK;
}
@@ -890,6 +989,12 @@ ram_disk_driver_init_driver(device_node* node, void** \
_driverCookie) uint64 deviceSize;
if (sDeviceManager->get_attr_uint64(node, kDeviceSizeItem, &deviceSize,
false) == B_OK) {
+ int32 id = -1;
+ sDeviceManager->get_attr_uint32(node, kDeviceIDItem, (uint32*)&id,
+ false);
+ if (id < 0)
+ return B_ERROR;
+
const char* filePath = NULL;
sDeviceManager->get_attr_string(node, kFilePathItem, &filePath, false);
@@ -897,7 +1002,7 @@ ram_disk_driver_init_driver(device_node* node, void** \
_driverCookie) if (device == NULL)
return B_NO_MEMORY;
- status_t error = device->Init(filePath, deviceSize);
+ status_t error = device->Init(id, filePath, deviceSize);
if (error != B_OK) {
delete device;
return error;
@@ -920,6 +1025,8 @@ static void
ram_disk_driver_uninit_driver(void* driverCookie)
{
Device* device = (Device*)driverCookie;
+ if (RawDevice* rawDevice = dynamic_cast<RawDevice*>(device))
+ free_raw_device_id(rawDevice->ID());
delete device;
}
@@ -976,185 +1083,15 @@ static status_t
ram_disk_control_device_read(void* cookie, off_t position, void* buffer,
size_t* _length)
{
- *_length = 0;
- return B_OK;
+ return B_BAD_VALUE;
}
-
static status_t
ram_disk_control_device_write(void* cookie, off_t position, const void* data,
size_t* _length)
{
- ControlDevice* device = (ControlDevice*)cookie;
-
- if (position != 0)
- return B_BAD_VALUE;
-
- // copy data to stack buffer
- char* buffer = (char*)malloc(*_length + 1);
- if (buffer == NULL)
- return B_NO_MEMORY;
- MemoryDeleter bufferDeleter(buffer);
-
- if (IS_USER_ADDRESS(data)) {
- if (user_memcpy(buffer, data, *_length) != B_OK)
- return B_BAD_ADDRESS;
- } else
- memcpy(buffer, data, *_length);
-
- buffer[*_length] = '\0';
-
- // parse arguments
- char** argv;
- int argc;
- if (!parse_command_line(buffer, argv, argc))
- return B_NO_MEMORY;
- ArrayDeleter<char*> argvDeleter(argv);
-
- if (argc == 0) {
- dprintf("\"help\" for usage!\n");
- return B_BAD_VALUE;
- }
-
- // execute command
- if (strcmp(argv[0], "help") == 0) {
- // help
- dprintf("register (<path> | -s <size>)\n");
- dprintf(" Registers a new ram disk device backed by file <path> or\n"
- " an unbacked ram disk device with size <size>.\n");
- dprintf("unregister <device>\n");
- dprintf(" Unregisters <device>.\n");
- dprintf("flush <device>\n");
- dprintf(" Writes <device> changes back to the file associated with\n"
- " it, if any.\n");
- } else if (strcmp(argv[0], "register") == 0) {
- // register
- if (argc < 2 || argc > 3 || (argc == 3 && strcmp(argv[1], "-s") != 0)) {
- dprintf("Usage: register (<path> | -s <size>)\n");
- return B_BAD_VALUE;
- }
-
- KPath path;
- uint64 deviceSize = 0;
-
- if (argc == 2) {
- // get a normalized file path
- status_t error = path.SetTo(argv[1], true);
- if (error != B_OK) {
- dprintf("Invalid path \"%s\": %s\n", argv[1], strerror(error));
- return B_BAD_VALUE;
- }
-
- struct stat st;
- if (lstat(path.Path(), &st) != 0) {
- dprintf("Failed to stat \"%s\": %s\n", path.Path(),
- strerror(errno));
- return errno;
- }
-
- if (!S_ISREG(st.st_mode)) {
- dprintf("\"%s\" is not a file!\n", path.Path());
- return B_BAD_VALUE;
- }
-
- deviceSize = st.st_size;
- } else {
- // parse size argument
- const char* sizeString = argv[2];
- char* end;
- deviceSize = strtoll(sizeString, &end, 0);
- if (end == sizeString) {
- dprintf("Invalid size argument: \"%s\"\n", sizeString);
- return B_BAD_VALUE;
- }
-
- switch (*end) {
- case 'g':
- deviceSize *= 1024;
- case 'm':
- deviceSize *= 1024;
- case 'k':
- deviceSize *= 1024;
- break;
- }
- }
-
- return device->Register(path.Length() > 0 ? path.Path() : NULL,
- deviceSize);
- } else if (strcmp(argv[0], "unregister") == 0) {
- // unregister
- if (argc != 2) {
- dprintf("Usage: unregister <device>\n");
- return B_BAD_VALUE;
- }
-
- const char* deviceName = argv[1];
-
- // find the device in the list and unregister it
- MutexLocker locker(sDeviceListLock);
- if (RawDevice* device = find_raw_device(deviceName)) {
- // TODO: Race condition: We should mark the device as going to
- // be unregistered, so no one else can try the same after we
- // unlock!
- locker.Unlock();
-// TODO: The following doesn't work! unpublish_device(), as per implementation
-// (partially commented out) and unregister_node() returns B_BUSY.
- status_t error = sDeviceManager->unpublish_device(
- device->Node(), device->DeviceName());
- if (error != B_OK) {
- dprintf("Failed to unpublish device \"%s\": %s\n",
- deviceName, strerror(error));
- return error;
- }
-
- error = sDeviceManager->unregister_node(device->Node());
- if (error != B_OK) {
- dprintf("Failed to unregister node \"%s\": %s\n",
- deviceName, strerror(error));
- return error;
- }
-
- return B_OK;
- }
-
- dprintf("Device \"%s\" not found!\n", deviceName);
- return B_BAD_VALUE;
- } else if (strcmp(argv[0], "flush") == 0) {
- // flush
- if (argc != 2) {
- dprintf("Usage: unregister <device>\n");
- return B_BAD_VALUE;
- }
-
- const char* deviceName = argv[1];
-
- // find the device in the list and flush it
- MutexLocker locker(sDeviceListLock);
- RawDevice* device = find_raw_device(deviceName);
- if (device == NULL) {
- dprintf("Device \"%s\" not found!\n", deviceName);
- return B_BAD_VALUE;
- }
-
- // TODO: Race condition: Once we unlock someone could unregister the
- // device. We should probably open the device by path, and use a
- // special ioctl.
- locker.Unlock();
-
- status_t error = device->Flush();
- if (error != B_OK) {
- dprintf("Failed to flush device: %s\n", strerror(error));
- return error;
- }
-
- return B_OK;
- } else {
- dprintf("Invalid command \"%s\"!\n", argv[0]);
- return B_BAD_VALUE;
- }
-
- return B_OK;
+ return B_BAD_VALUE;
}
@@ -1162,6 +1099,16 @@ static status_t
ram_disk_control_device_control(void* cookie, uint32 op, void* buffer,
size_t length)
{
+ ControlDevice* device = (ControlDevice*)cookie;
+
+ switch (op) {
+ case RAM_DISK_IOCTL_REGISTER:
+ return handle_ioctl(device, &ioctl_register, buffer);
+
+ case RAM_DISK_IOCTL_UNREGISTER:
+ return handle_ioctl(device, &ioctl_unregister, buffer);
+ }
+
return B_BAD_VALUE;
}
@@ -1347,6 +1294,21 @@ ram_disk_raw_device_control(void* _cookie, uint32 op, void* \
buffer, case B_SET_INTERRUPTABLE_IO:
case B_FLUSH_DRIVE_CACHE:
return B_OK;
+
+ case RAM_DISK_IOCTL_FLUSH:
+ {
+ status_t error = device->Flush();
+ if (error != B_OK) {
+ dprintf("ramdisk: flush: Failed to flush device: %s\n",
+ strerror(error));
+ return error;
+ }
+
+ return B_OK;
+ }
+
+ case RAM_DISK_IOCTL_INFO:
+ return handle_ioctl(device, &ioctl_info, buffer);
}
return B_BAD_VALUE;
diff --git a/src/bin/Jamfile b/src/bin/Jamfile
index 5cb2794..67c51e6 100644
--- a/src/bin/Jamfile
+++ b/src/bin/Jamfile
@@ -126,6 +126,11 @@ StdBinCommands
urlwrapper.cpp
: be $(TARGET_LIBSUPC++) : $(haiku-utils_rsrc) ;
+# standard commands that need libbe.so, libsupc++.so, and libshared.a
+StdBinCommands
+ ramdisk.cpp
+ : libshared.a be $(TARGET_LIBSUPC++) : $(haiku-utils_rsrc) ;
+
# commands that need libbe.so and the stub catalog
StdBinCommands
clockconfig.cpp
diff --git a/src/bin/ramdisk.cpp b/src/bin/ramdisk.cpp
new file mode 100644
index 0000000..b6070ea
--- /dev/null
+++ b/src/bin/ramdisk.cpp
@@ -0,0 +1,477 @@
+/*
+ * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <Entry.h>
+#include <Path.h>
+#include <String.h>
+
+#include <AutoDeleter.h>
+#include <TextTable.h>
+
+#include <file_systems/ram_disk/ram_disk.h>
+
+
+extern const char* __progname;
+static const char* kProgramName = __progname;
+
+static const char* const kUsage =
+ "Usage: %s <command> [ <options> ]\n"
+ "Controls RAM disk devices.\n"
+ "\n"
+ "Commands:\n"
+ " create (-s <size> | <path>)\n"
+ " Creates a new RAM disk.\n"
+ " delete <id>\n"
+ " Deletes an existing RAM disk.\n"
+ " flush <id>\n"
+ " Writes modified data of an existing RAM disk back to its file.\n"
+ " help\n"
+ " Print this usage info.\n"
+ " list\n"
+ " List all RAM disks.\n"
+;
+
+static const char* const kCreateUsage =
+ "Usage: %s %s (-s <size> | <path>)\n"
+ "Creates a new RAM disk device. If the <size> argument is specified, a\n"
+ "new zeroed RAM disk with that size (in bytes, suffixes 'k', 'm', 'g' are\n"
+ "interpreted as KiB, MiB, GiB) is registered.\n"
+ "Alternatively a file path can be specified. In that case the RAM disk \n"
+ "data are initially read from that file and at any later point the\n"
+ "modified RAM disk data can be written back to the same file upon request\n"
+ "(via the \"flush\" command). The size of the RAM disk is implied by that\n"
+ "of the file.\n"
+;
+
+static const char* const kDeleteUsage =
+ "Usage: %s %s <id>\n"
+ "Deletes the existing RAM disk with ID <id>. All modified data will be\n"
+ "lost.\n"
+;
+
+static const char* const kFlushUsage =
+ "Usage: %s %s <id>\n"
+ "Writes all modified data of the RAM disk with ID <id> back to the file\n"
+ "specified when the RAM disk was created. Fails, if the RAM disk had been\n"
+ "created without an associated file.\n"
+;
+
+static const char* const kListUsage =
+ "Usage: %s %s\n"
+ "Lists all existing RAM disks.\n"
+;
+
+static const char* const kRamDiskControlDevicePath
+ = "/dev/" RAM_DISK_CONTROL_DEVICE_NAME;
+static const char* const kRamDiskRawDeviceBasePath
+ = "/dev/" RAM_DISK_RAW_DEVICE_BASE_NAME;
+
+static const char* sCommandName = NULL;
+static const char* sCommandUsage = NULL;
+
+
+static void
+print_usage_and_exit(bool error)
+{
+ if (sCommandUsage != NULL) {
+ fprintf(error ? stderr : stdout, sCommandUsage, kProgramName,
+ sCommandName);
+ } else
+ fprintf(error ? stderr : stdout, kUsage, kProgramName);
+ exit(error ? 1 : 0);
+}
+
+
+static status_t
+execute_control_device_ioctl(int operation, void* request)
+{
+ // open the ram disk control device
+ int fd = open(kRamDiskControlDevicePath, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "Error: Failed to open RAM disk control device \"%s\": "
+ "%s\n", kRamDiskControlDevicePath, strerror(errno));
+ return errno;
+ }
+ FileDescriptorCloser fdCloser(fd);
+
+ // issue the request
+ if (ioctl(fd, operation, request) < 0)
+ return errno;
+
+ return B_OK;
+}
+
+
+static int
+command_register(int argc, const char* const* argv)
+{
+ sCommandUsage = kCreateUsage;
+
+ int64 deviceSize = -1;
+
+ while (true) {
+ static struct option sLongOptions[] = {
+ { "size", required_argument, 0, 's' },
+ { "help", no_argument, 0, 'h' },
+ { 0, 0, 0, 0 }
+ };
+
+ opterr = 0; // don't print errors
+ int c = getopt_long(argc, (char**)argv, "+s:h", sLongOptions, NULL);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'h':
+ print_usage_and_exit(false);
+ break;
+
+ case 's':
+ {
+ const char* sizeString = optarg;
+ char* end;
+ deviceSize = strtoll(sizeString, &end, 0);
+ if (end != sizeString && deviceSize > 0) {
+ int64 originalDeviceSize = deviceSize;
+ switch (*end) {
+ case 'g':
+ deviceSize *= 1024;
+ case 'm':
+ deviceSize *= 1024;
+ case 'k':
+ deviceSize *= 1024;
+ end++;
+ break;
+ case '\0':
+ break;
+ default:
+ deviceSize = -1;
+ break;
+ }
+
+ if (deviceSize > 0 && originalDeviceSize > deviceSize)
+ deviceSize = -1;
+ }
+
+ if (deviceSize <= 0) {
+ fprintf(stderr, "Error: Invalid size argument: \"%s\"\n",
+ sizeString);
+ return 1;
+ }
+
+ // check maximum size
+ system_info info;
+ get_system_info(&info);
+ if (deviceSize / B_PAGE_SIZE > (int64)info.max_pages * 2 / 3) {
+ fprintf(stderr, "Error: Given RAM disk size too large.\n");
+ return 1;
+ }
+
+ break;
+ }
+
+ default:
+ print_usage_and_exit(true);
+ break;
+ }
+ }
+
+ // The remaining optional argument is the file path. It may only be
+ // specified, if no size has been specified.
+ const char* path = optind < argc ? argv[optind++] : NULL;
+ if (optind < argc || (deviceSize >= 0) == (path != NULL))
+ print_usage_and_exit(true);
+
+ // prepare the request
+ ram_disk_ioctl_register request;
+ request.size = (uint64)deviceSize;
+ request.path[0] = '\0';
+ request.id = -1;
+
+ if (path != NULL) {
+ // verify the path
+ BEntry entry;
+ status_t error = entry.SetTo(path, true);
+ if (error == B_OK && !entry.Exists())
+ error = B_ENTRY_NOT_FOUND;
+ if (error != B_OK) {
+ fprintf(stderr, "Error: Failed to resolve path \"%s\": %s\n",
+ path, strerror(error));
+ return 1;
+ }
+
+ if (!entry.IsFile()) {
+ fprintf(stderr, "Error: \"%s\" is not a file.\n", path);
+ return 1;
+ }
+
+ BPath normalizedPath;
+ error = entry.GetPath(&normalizedPath);
+ if (error != B_OK) {
+ fprintf(stderr, "Error: Failed to normalize path \"%s\": %s\n",
+ path, strerror(error));
+ return 1;
+ }
+
+ if (strlcpy(request.path, normalizedPath.Path(), sizeof(request.path))
+ >= sizeof(request.path)) {
+ fprintf(stderr, "Error: Normalized path too long.\n");
+ return 1;
+ }
+ }
+
+ status_t error = execute_control_device_ioctl(RAM_DISK_IOCTL_REGISTER,
+ &request);
+ if (error != B_OK) {
+ fprintf(stderr, "Error: Failed to create RAM disk device: %s\n",
+ strerror(error));
+ return 1;
+ }
+
+ printf("RAM disk device created as \"%s/%" B_PRId32 "/raw\"\n",
+ kRamDiskRawDeviceBasePath, request.id);
+ return 0;
+}
+
+
+static int
+command_unregister(int argc, const char* const* argv)
+{
+ sCommandUsage = kDeleteUsage;
+
+ while (true) {
+ static struct option sLongOptions[] = {
+ { "help", no_argument, 0, 'h' },
+ { 0, 0, 0, 0 }
+ };
+
+ opterr = 0; // don't print errors
+ int c = getopt_long(argc, (char**)argv, "+h", sLongOptions, NULL);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'h':
+ print_usage_and_exit(false);
+ break;
+
+ default:
+ print_usage_and_exit(true);
+ break;
+ }
+ }
+
+ // The remaining argument is the device ID.
+ if (optind + 1 != argc)
+ print_usage_and_exit(true);
+
+ const char* idString = argv[optind++];
+ char* end;
+ long long id = strtol(idString, &end, 0);
+ if (end == idString || *end != '\0' || id < 0 || id > INT32_MAX) {
+ fprintf(stderr, "Error: Invalid ID \"%s\".\n", idString);
+ return 1;
+ }
+
+ // check whether the raw device for that ID exists
+ BString path;
+ path.SetToFormat("%s/%s/raw", kRamDiskRawDeviceBasePath, idString);
+ struct stat st;
+ if (lstat(path, &st) != 0) {
+ fprintf(stderr, "Error: No RAM disk with ID %s.\n", idString);
+ return 1;
+ }
+
+ // issue the request
+ ram_disk_ioctl_unregister request;
+ request.id = (int32)id;
+
+ status_t error = execute_control_device_ioctl(RAM_DISK_IOCTL_UNREGISTER,
+ &request);
+ if (error != B_OK) {
+ fprintf(stderr, "Error: Failed to delete RAM disk device: %s\n",
+ strerror(error));
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int
+command_flush(int argc, const char* const* argv)
+{
+ sCommandUsage = kFlushUsage;
+
+ while (true) {
+ static struct option sLongOptions[] = {
+ { "help", no_argument, 0, 'h' },
+ { 0, 0, 0, 0 }
+ };
+
+ opterr = 0; // don't print errors
+ int c = getopt_long(argc, (char**)argv, "+h", sLongOptions, NULL);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'h':
+ print_usage_and_exit(false);
+ break;
+
+ default:
+ print_usage_and_exit(true);
+ break;
+ }
+ }
+
+ // The remaining argument is the device ID.
+ if (optind + 1 != argc)
+ print_usage_and_exit(true);
+
+ const char* idString = argv[optind++];
+ char* end;
+ long long id = strtol(idString, &end, 0);
+ if (end == idString || *end != '\0' || id < 0 || id > INT32_MAX) {
+ fprintf(stderr, "Error: Invalid ID \"%s\".\n", idString);
+ return 1;
+ }
+
+ // open the raw device
+ BString path;
+ path.SetToFormat("%s/%s/raw", kRamDiskRawDeviceBasePath, idString);
+ int fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "Error: Failed to open RAM disk device \"%s\"\n",
+ path.String());
+ return 1;
+ }
+ FileDescriptorCloser fdCloser(fd);
+
+ // issue the request
+ if (ioctl(fd, RAM_DISK_IOCTL_FLUSH, NULL) < 0) {
+ fprintf(stderr, "Error: Failed to flush RAM disk device: %s\n",
+ strerror(errno));
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int
+command_list(int argc, const char* const* argv)
+{
+ sCommandUsage = kListUsage;
+
+ while (true) {
+ static struct option sLongOptions[] = {
+ { "help", no_argument, 0, 'h' },
+ { 0, 0, 0, 0 }
+ };
+
+ opterr = 0; // don't print errors
+ int c = getopt_long(argc, (char**)argv, "+h", sLongOptions, NULL);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'h':
+ print_usage_and_exit(false);
+ break;
+
+ default:
+ print_usage_and_exit(true);
+ break;
+ }
+ }
+
+ // There shouldn't be any remaining arguments.
+ if (optind != argc)
+ print_usage_and_exit(true);
+
+ // iterate through the RAM disk device directory and search for raw devices
+ DIR* dir = opendir(kRamDiskRawDeviceBasePath);
+ if (dir == NULL) {
+ fprintf(stderr, "Error: Failed to open RAM disk device directory: %s\n",
+ strerror(errno));
+ return 1;
+ }
+ CObjectDeleter<DIR, int> dirCloser(dir, &closedir);
+
+ TextTable table;
+ table.AddColumn("ID", B_ALIGN_RIGHT);
+ table.AddColumn("Size", B_ALIGN_RIGHT);
+ table.AddColumn("Associated file");
+
+ while (dirent* entry = readdir(dir)) {
+ // check, if the entry name could be an ID
+ const char* idString = entry->d_name;
+ char* end;
+ long long id = strtol(idString, &end, 0);
+ if (end == idString || *end != '\0' || id < 0 || id > INT32_MAX)
+ continue;
+
+ // open the raw device
+ BString path;
+ path.SetToFormat("%s/%s/raw", kRamDiskRawDeviceBasePath, idString);
+ int fd = open(path, O_RDONLY);
+ if (fd < 0)
+ continue;
+ FileDescriptorCloser fdCloser(fd);
+
+ // issue the request
+ ram_disk_ioctl_info request;
+ if (ioctl(fd, RAM_DISK_IOCTL_INFO, &request) < 0)
+ continue;
+
+ int32 rowIndex = table.CountRows();
+ table.SetTextAt(rowIndex, 0, BString() << request.id);
+ table.SetTextAt(rowIndex, 1, BString() << request.size);
+ table.SetTextAt(rowIndex, 2, request.path);
+ }
+
+ if (table.CountRows() > 0)
+ table.Print(INT32_MAX);
+ else
+ printf("No RAM disks.\n");
+
+ return 0;
+}
+
+
+int
+main(int argc, const char* const* argv)
+{
+ if (argc < 2)
+ print_usage_and_exit(true);
+
+ if (strcmp(argv[1], "help") == 0 || strcmp(argv[1], "--help") == 0
+ || strcmp(argv[1], "-h") == 0) {
+ print_usage_and_exit(false);
+ }
+
+ sCommandName = argv[1];
+
+ if (strcmp(sCommandName, "create") == 0)
+ return command_register(argc - 1, argv + 1);
+ if (strcmp(sCommandName, "delete") == 0)
+ return command_unregister(argc - 1, argv + 1);
+ if (strcmp(sCommandName, "flush") == 0)
+ return command_flush(argc - 1, argv + 1);
+ if (strcmp(sCommandName, "list") == 0)
+ return command_list(argc - 1, argv + 1);
+
+ print_usage_and_exit(true);
+}
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic