devfs now supports the I/O scheduler mechanism and automatically uses it

for all raw disk devices.
Minor cleanup.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@8685 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2004-08-28 13:33:31 +00:00
parent 6e3462b57e
commit a48a5ab889

View File

@ -6,6 +6,8 @@
** Distributed under the terms of the NewOS License. ** Distributed under the terms of the NewOS License.
*/ */
#include "IOScheduler.h"
#include <SupportDefs.h> #include <SupportDefs.h>
#include <KernelExport.h> #include <KernelExport.h>
#include <Drivers.h> #include <Drivers.h>
@ -62,6 +64,7 @@ struct devfs_stream {
void *ident; void *ident;
device_hooks *ops; device_hooks *ops;
struct devfs_part_map *part_map; struct devfs_part_map *part_map;
IOScheduler *scheduler;
} dev; } dev;
struct stream_symlink { struct stream_symlink {
char *path; char *path;
@ -320,31 +323,28 @@ devfs_get_partition_info( struct devfs *fs, struct devfs_vnode *v,
static status_t static status_t
devfs_set_partition( struct devfs *fs, struct devfs_vnode *v, devfs_set_partition(struct devfs *fs, struct devfs_vnode *vnode,
struct devfs_cookie *cookie, void *buf, size_t len) struct devfs_cookie *cookie, partition_info &info, size_t length)
{ {
struct devfs_part_map *part_map;
struct devfs_vnode *part_node; struct devfs_vnode *part_node;
int res; status_t status;
char part_name[30];
partition_info info = *(partition_info *)buf; if (length != sizeof(partition_info)
|| vnode->stream.type != STREAM_TYPE_DEVICE)
if (v->stream.type != STREAM_TYPE_DEVICE) return B_BAD_VALUE;
return EINVAL;
// we don't support nested partitions // we don't support nested partitions
if (v->stream.u.dev.part_map) if (vnode->stream.u.dev.part_map)
return EINVAL; return B_BAD_VALUE;
// reduce checks to a minimum - things like negative offsets could be useful // reduce checks to a minimum - things like negative offsets could be useful
if (info.size < 0) if (info.size < 0)
return EINVAL; return B_BAD_VALUE;
// create partition map // create partition map
part_map = (struct devfs_part_map *)malloc(sizeof(*part_map)); struct devfs_part_map *part_map = (struct devfs_part_map *)malloc(sizeof(*part_map));
if (!part_map) if (part_map == NULL)
return ENOMEM; return B_NO_MEMORY;
part_map->offset = info.offset; part_map->offset = info.offset;
part_map->size = info.size; part_map->size = info.size;
@ -352,58 +352,74 @@ devfs_set_partition( struct devfs *fs, struct devfs_vnode *v,
part_map->session = info.session; part_map->session = info.session;
part_map->partition = info.partition; part_map->partition = info.partition;
sprintf(part_name, "%li_%li", info.session, info.partition); char name[30];
sprintf(name, "%li_%li", info.session, info.partition);
mutex_lock(&sDeviceFileSystem->lock); mutex_lock(&sDeviceFileSystem->lock);
// you cannot change a partition once set // you cannot change a partition once set
if (devfs_find_in_dir( v->parent, part_name)) { if (devfs_find_in_dir(vnode->parent, name)) {
res = EINVAL; status = B_BAD_VALUE;
goto err1; goto err1;
} }
// increase reference count of raw device - // increase reference count of raw device -
// the partition device really needs it // the partition device really needs it
// (at least to resolve its name on GET_PARTITION_INFO) // (at least to resolve its name on GET_PARTITION_INFO)
res = get_vnode(fs->id, v->id, (fs_vnode *)&part_map->raw_vnode); status = get_vnode(fs->id, vnode->id, (fs_vnode *)&part_map->raw_vnode);
if (res < 0) if (status < B_OK)
goto err1; goto err1;
// now create the partition node // now create the partition vnode
part_node = devfs_create_vnode(fs, part_name); part_node = devfs_create_vnode(fs, name);
if (part_node == NULL) { if (part_node == NULL) {
res = B_NO_MEMORY; status = B_NO_MEMORY;
goto err2; goto err2;
} }
part_node->stream.type = STREAM_TYPE_DEVICE; part_node->stream.type = STREAM_TYPE_DEVICE;
part_node->stream.u.dev.ident = v->stream.u.dev.ident; part_node->stream.u.dev.ident = vnode->stream.u.dev.ident;
part_node->stream.u.dev.ops = v->stream.u.dev.ops; part_node->stream.u.dev.ops = vnode->stream.u.dev.ops;
part_node->stream.u.dev.part_map = part_map; part_node->stream.u.dev.part_map = part_map;
part_node->stream.u.dev.scheduler = vnode->stream.u.dev.scheduler;
hash_insert(fs->vnode_list_hash, part_node); hash_insert(fs->vnode_list_hash, part_node);
devfs_insert_in_dir(v->parent, part_node); devfs_insert_in_dir(vnode->parent, part_node);
mutex_unlock(&sDeviceFileSystem->lock); mutex_unlock(&sDeviceFileSystem->lock);
TRACE(("SET_PARTITION: Added partition\n")); TRACE(("SET_PARTITION: Added partition\n"));
return B_OK;
return B_NO_ERROR;
err1: err1:
mutex_unlock(&sDeviceFileSystem->lock); mutex_unlock(&sDeviceFileSystem->lock);
free(part_map); free(part_map);
return res; return status;
err2: err2:
mutex_unlock(&sDeviceFileSystem->lock); mutex_unlock(&sDeviceFileSystem->lock);
put_vnode(fs->id, v->id); put_vnode(fs->id, vnode->id);
free(part_map); free(part_map);
return res; return status;
}
static inline void
translate_partition_access(devfs_part_map *map, off_t &offset, size_t &size)
{
if (offset < 0)
offset = 0;
if (offset > map->size) {
size = 0;
return;
}
size = min_c(size, map->size - offset);
offset += map->offset;
} }
@ -702,13 +718,12 @@ devfs_fsync(fs_volume _fs, fs_vnode _v)
} }
static ssize_t static status_t
devfs_read(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie, off_t pos, devfs_read(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie, off_t pos,
void *buffer, size_t *_length) void *buffer, size_t *_length)
{ {
struct devfs_vnode *vnode = (struct devfs_vnode *)_vnode; struct devfs_vnode *vnode = (struct devfs_vnode *)_vnode;
struct devfs_cookie *cookie = (struct devfs_cookie *)_cookie; struct devfs_cookie *cookie = (struct devfs_cookie *)_cookie;
struct devfs_part_map *part_map;
TRACE(("devfs_read: vnode %p, cookie %p, pos %Ld, len %p\n", vnode, cookie, pos, _length)); TRACE(("devfs_read: vnode %p, cookie %p, pos %Ld, len %p\n", vnode, cookie, pos, _length));
@ -718,16 +733,21 @@ devfs_read(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie, off_t pos,
//if (cookie->stream->type != STREAM_TYPE_DEVICE) //if (cookie->stream->type != STREAM_TYPE_DEVICE)
// return EINVAL; // return EINVAL;
part_map = vnode->stream.u.dev.part_map; if (vnode->stream.u.dev.part_map)
if (part_map) { translate_partition_access(vnode->stream.u.dev.part_map, pos, *_length);
if (pos < 0)
pos = 0;
if (pos > part_map->size) if (*_length == 0)
return 0; return B_OK;
*_length = min_c(*_length, part_map->size - pos); // if this device has an I/O scheduler attached, the request must go through it
pos += part_map->offset; if (IOScheduler *scheduler = vnode->stream.u.dev.scheduler) {
IORequest request(cookie->u.dev.dcookie, pos, buffer, *_length);
status_t status = scheduler->Process(request);
if (status == B_OK)
*_length = request.Size();
return status;
} }
// pass the call through to the device // pass the call through to the device
@ -735,7 +755,7 @@ devfs_read(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie, off_t pos,
} }
static ssize_t static status_t
devfs_write(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie, off_t pos, devfs_write(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie, off_t pos,
const void *buffer, size_t *_length) const void *buffer, size_t *_length)
{ {
@ -744,26 +764,26 @@ devfs_write(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie, off_t pos,
TRACE(("devfs_write: vnode %p, cookie %p, pos %Ld, len %p\n", vnode, cookie, pos, _length)); TRACE(("devfs_write: vnode %p, cookie %p, pos %Ld, len %p\n", vnode, cookie, pos, _length));
if (vnode->stream.type == STREAM_TYPE_DEVICE) { if (vnode->stream.type != STREAM_TYPE_DEVICE)
struct devfs_part_map *part_map = vnode->stream.u.dev.part_map; return B_BAD_VALUE;
int written;
if (part_map) { if (vnode->stream.u.dev.part_map)
if (pos < 0) translate_partition_access(vnode->stream.u.dev.part_map, pos, *_length);
pos = 0;
if (pos > part_map->size) if (*_length == 0)
return 0; return B_OK;
*_length = min_c(*_length, part_map->size - pos); if (IOScheduler *scheduler = vnode->stream.u.dev.scheduler) {
pos += part_map->offset; IORequest request(cookie->u.dev.dcookie, pos, buffer, *_length);
}
written = vnode->stream.u.dev.ops->write(cookie->u.dev.dcookie, pos, buffer, _length); status_t status = scheduler->Process(request);
return written; if (status == B_OK)
*_length = request.Size();
return status;
} }
return B_BAD_VALUE; return vnode->stream.u.dev.ops->write(cookie->u.dev.dcookie, pos, buffer, _length);
} }
@ -875,10 +895,10 @@ devfs_ioctl(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie, ulong op, void *b
if (vnode->stream.type == STREAM_TYPE_DEVICE) { if (vnode->stream.type == STREAM_TYPE_DEVICE) {
switch (op) { switch (op) {
case B_GET_PARTITION_INFO: case B_GET_PARTITION_INFO:
return devfs_get_partition_info(fs, vnode, cookie, buffer, length); return devfs_get_partition_info(fs, vnode, cookie, (partition_info *)buffer, length);
case B_SET_PARTITION: case B_SET_PARTITION:
return devfs_set_partition(fs, vnode, cookie, buffer, length); return devfs_set_partition(fs, vnode, cookie, *(partition_info *)buffer, length);
} }
return vnode->stream.u.dev.ops->control(cookie->u.dev.dcookie, op, buffer, length); return vnode->stream.u.dev.ops->control(cookie->u.dev.dcookie, op, buffer, length);
@ -1353,29 +1373,23 @@ devfs_publish_partition(const char *path, const partition_info *info)
extern "C" status_t extern "C" status_t
devfs_publish_device(const char *path, void *ident, device_hooks *ops) devfs_publish_device(const char *path, void *ident, device_hooks *ops)
{ {
int err = 0; status_t status = B_OK;
int i, last;
char temp[B_PATH_NAME_LENGTH + 1]; char temp[B_PATH_NAME_LENGTH + 1];
struct devfs_vnode *dir; struct devfs_vnode *dir;
struct devfs_vnode *v; struct devfs_vnode *v;
bool at_leaf;
TRACE(("devfs_publish_device: entry path '%s', ident %p, hooks %p\n", path, ident, ops)); TRACE(("devfs_publish_device: entry path '%s', ident %p, hooks %p\n", path, ident, ops));
if (ops == NULL || path == NULL) { if (sDeviceFileSystem == NULL) {
panic("devfs_publish_device called with NULL pointer!\n");
return B_BAD_VALUE;
}
if (ops->open == NULL || ops->close == NULL
|| ops->read == NULL || ops->write == NULL)
return B_BAD_VALUE;
if (!sDeviceFileSystem) {
panic("devfs_publish_device called before devfs mounted\n"); panic("devfs_publish_device called before devfs mounted\n");
return B_ERROR; return B_ERROR;
} }
if (ops == NULL || path == NULL || path[0] == '/'
|| ops->open == NULL || ops->close == NULL
|| ops->read == NULL || ops->write == NULL)
return B_BAD_VALUE;
// copy the path over to a temp buffer so we can munge it // copy the path over to a temp buffer so we can munge it
strlcpy(temp, path, B_PATH_NAME_LENGTH); strlcpy(temp, path, B_PATH_NAME_LENGTH);
@ -1385,13 +1399,14 @@ devfs_publish_device(const char *path, void *ident, device_hooks *ops)
// parse the path passed in, stripping out '/' // parse the path passed in, stripping out '/'
dir = sDeviceFileSystem->root_vnode; dir = sDeviceFileSystem->root_vnode;
v = NULL; v = NULL;
i = 0; int32 i = 0, last = 0;
last = 0; bool atLeaf = false;
at_leaf = false; bool isDisk = false;
for (;;) { for (;;) {
if(temp[i] == 0) { if (temp[i] == 0) {
at_leaf = true; // we'll be done after this one atLeaf = true; // we'll be done after this one
} else if(temp[i] == '/') { } else if (temp[i] == '/') {
temp[i] = 0; temp[i] = 0;
i++; i++;
} else { } else {
@ -1404,7 +1419,7 @@ devfs_publish_device(const char *path, void *ident, device_hooks *ops)
// we have a path component // we have a path component
v = devfs_find_in_dir(dir, &temp[last]); v = devfs_find_in_dir(dir, &temp[last]);
if (v) { if (v) {
if (!at_leaf) { if (!atLeaf) {
// we are not at the leaf of the path, so as long as // we are not at the leaf of the path, so as long as
// this is a dir we're okay // this is a dir we're okay
if (v->stream.type == STREAM_TYPE_DIR) { if (v->stream.type == STREAM_TYPE_DIR) {
@ -1416,41 +1431,49 @@ devfs_publish_device(const char *path, void *ident, device_hooks *ops)
// we are at the leaf and hit another node // we are at the leaf and hit another node
// or we aren't but hit a non-dir node. // or we aren't but hit a non-dir node.
// we're screwed // we're screwed
err = B_FILE_EXISTS; status = B_FILE_EXISTS;
goto err; goto out;
} else { } else {
v = devfs_create_vnode(sDeviceFileSystem, &temp[last]); v = devfs_create_vnode(sDeviceFileSystem, &temp[last]);
if (!v) { if (!v) {
err = ENOMEM; status = B_NO_MEMORY;
goto err; goto out;
} }
} }
// set up the new vnode // set up the new vnode
if (at_leaf) { if (atLeaf) {
// this is the last component // this is the last component
v->stream.type = STREAM_TYPE_DEVICE; v->stream.type = STREAM_TYPE_DEVICE;
v->stream.u.dev.ident = ident; v->stream.u.dev.ident = ident;
v->stream.u.dev.ops = ops; v->stream.u.dev.ops = ops;
// every raw disk gets an I/O scheduler object attached
if (isDisk && !strcmp(&temp[last], "raw"))
v->stream.u.dev.scheduler = new IOScheduler(path, ops);
} else { } else {
// this is a dir // this is a dir
v->stream.type = STREAM_TYPE_DIR; v->stream.type = STREAM_TYPE_DIR;
v->stream.u.dir.dir_head = NULL; v->stream.u.dir.dir_head = NULL;
v->stream.u.dir.jar_head = NULL; v->stream.u.dir.jar_head = NULL;
// mark disk devices - they might get an I/O scheduler
if (last == 0 && !strcmp(temp, "disk"))
isDisk = true;
} }
hash_insert(sDeviceFileSystem->vnode_list_hash, v); hash_insert(sDeviceFileSystem->vnode_list_hash, v);
devfs_insert_in_dir(dir, v); devfs_insert_in_dir(dir, v);
if (at_leaf) if (atLeaf)
break; break;
last = i; last = i;
dir = v; dir = v;
} }
err: out:
mutex_unlock(&sDeviceFileSystem->lock); mutex_unlock(&sDeviceFileSystem->lock);
return err; return status;
} }