Added a more or less clean implementation of devfs_publish_partition(); might

be changed later.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@9532 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2004-10-27 15:21:11 +00:00
parent b81068c0c8
commit 0ec71451f5
2 changed files with 107 additions and 82 deletions

View File

@ -38,14 +38,8 @@
struct devfs_part_map {
off_t offset;
off_t size;
uint32 logical_block_size;
struct devfs_vnode *raw_vnode;
// following info could be recreated on the fly, but it's not worth it
uint32 session;
uint32 partition;
struct devfs_vnode *raw_device;
partition_info info;
};
struct devfs_stream {
@ -188,7 +182,7 @@ devfs_delete_vnode(struct devfs *fs, struct devfs_vnode *vnode, bool force_delet
if (S_ISCHR(vnode->stream.type)) {
// for partitions, we have to release the raw device
if (vnode->stream.u.dev.part_map)
put_vnode(fs->id, vnode->stream.u.dev.part_map->raw_vnode->id);
put_vnode(fs->id, vnode->stream.u.dev.part_map->raw_device->id);
// remove API conversion from old to new drivers
if (vnode->stream.u.dev.node == NULL)
@ -316,43 +310,30 @@ devfs_is_dir_empty(struct devfs_vnode *dir)
static status_t
devfs_get_partition_info( struct devfs *fs, struct devfs_vnode *v,
struct devfs_cookie *cookie, void *buf, size_t len)
devfs_get_partition_info(struct devfs *fs, struct devfs_vnode *v,
struct devfs_cookie *cookie, void *buffer, size_t length)
{
// ToDo: make me userspace safe!
struct devfs_part_map *map = v->stream.u.dev.part_map;
partition_info *info = (partition_info *)buf;
struct devfs_part_map *part_map = v->stream.u.dev.part_map;
if (!S_ISCHR(v->stream.type) || map == NULL || length != sizeof(partition_info))
return B_BAD_VALUE;
if (!S_ISCHR(v->stream.type) || part_map == NULL)
return EINVAL;
info->offset = part_map->offset;
info->size = part_map->size;
info->logical_block_size = part_map->logical_block_size;
info->session = part_map->session;
info->partition = part_map->partition;
// XXX: todo - create raw device name out of raw_vnode
// we need vfs support for that (see vfs_get_cwd)
strcpy(info->device, "something_raw");
return B_NO_ERROR;
return user_memcpy(buffer, &map->info, sizeof(partition_info));
}
static status_t
devfs_set_partition(struct devfs *fs, struct devfs_vnode *vnode,
struct devfs_cookie *cookie, partition_info &info, size_t length)
add_partition(struct devfs *fs, struct devfs_vnode *device,
const char *name, const partition_info &info)
{
struct devfs_vnode *part_node;
struct devfs_vnode *partition;
status_t status;
if (length != sizeof(partition_info) || !S_ISCHR(vnode->stream.type))
if (!S_ISCHR(device->stream.type))
return B_BAD_VALUE;
// we don't support nested partitions
if (vnode->stream.u.dev.part_map)
if (device->stream.u.dev.part_map)
return B_BAD_VALUE;
// reduce checks to a minimum - things like negative offsets could be useful
@ -360,23 +341,16 @@ devfs_set_partition(struct devfs *fs, struct devfs_vnode *vnode,
return B_BAD_VALUE;
// create partition map
struct devfs_part_map *part_map = (struct devfs_part_map *)malloc(sizeof(*part_map));
if (part_map == NULL)
struct devfs_part_map *map = (struct devfs_part_map *)malloc(sizeof(struct devfs_part_map));
if (map == NULL)
return B_NO_MEMORY;
part_map->offset = info.offset;
part_map->size = info.size;
part_map->logical_block_size = info.logical_block_size;
part_map->session = info.session;
part_map->partition = info.partition;
memcpy(&map->info, &info, sizeof(partition_info));
char name[30];
sprintf(name, "%li_%li", info.session, info.partition);
mutex_lock(&sDeviceFileSystem->lock);
mutex_lock(&fs->lock);
// you cannot change a partition once set
if (devfs_find_in_dir(vnode->parent, name)) {
if (devfs_find_in_dir(device->parent, name)) {
status = B_BAD_VALUE;
goto err1;
}
@ -384,44 +358,44 @@ devfs_set_partition(struct devfs *fs, struct devfs_vnode *vnode,
// increase reference count of raw device -
// the partition device really needs it
// (at least to resolve its name on GET_PARTITION_INFO)
status = get_vnode(fs->id, vnode->id, (fs_vnode *)&part_map->raw_vnode);
status = get_vnode(fs->id, device->id, (fs_vnode *)&map->raw_device);
if (status < B_OK)
goto err1;
// now create the partition vnode
part_node = devfs_create_vnode(fs, vnode->parent, name);
if (part_node == NULL) {
partition = devfs_create_vnode(fs, device->parent, name);
if (partition == NULL) {
status = B_NO_MEMORY;
goto err2;
}
part_node->stream.type = vnode->stream.type;
part_node->stream.u.dev.node = vnode->stream.u.dev.node;
part_node->stream.u.dev.info = vnode->stream.u.dev.info;
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.scheduler = vnode->stream.u.dev.scheduler;
partition->stream.type = device->stream.type;
partition->stream.u.dev.node = device->stream.u.dev.node;
partition->stream.u.dev.info = device->stream.u.dev.info;
partition->stream.u.dev.ops = device->stream.u.dev.ops;
partition->stream.u.dev.part_map = map;
partition->stream.u.dev.scheduler = device->stream.u.dev.scheduler;
hash_insert(fs->vnode_list_hash, part_node);
hash_insert(fs->vnode_list_hash, partition);
devfs_insert_in_dir(vnode->parent, part_node);
devfs_insert_in_dir(device->parent, partition);
mutex_unlock(&sDeviceFileSystem->lock);
mutex_unlock(&fs->lock);
TRACE(("SET_PARTITION: Added partition\n"));
return B_OK;
err1:
mutex_unlock(&sDeviceFileSystem->lock);
mutex_unlock(&fs->lock);
free(part_map);
free(map);
return status;
err2:
mutex_unlock(&sDeviceFileSystem->lock);
put_vnode(fs->id, vnode->id);
free(part_map);
err2:
mutex_unlock(&fs->lock);
put_vnode(fs->id, device->id);
free(map);
return status;
}
@ -432,13 +406,13 @@ translate_partition_access(devfs_part_map *map, off_t &offset, size_t &size)
if (offset < 0)
offset = 0;
if (offset > map->size) {
if (offset > map->info.size) {
size = 0;
return;
}
size = min_c(size, map->size - offset);
offset += map->offset;
size = min_c(size, map->info.size - offset);
offset += map->info.offset;
}
@ -469,6 +443,13 @@ create_new_driver_info(device_hooks *ops)
}
static status_t
get_node_for_path(const char *path, struct devfs_vnode **_node)
{
return vfs_get_fs_node_from_path(sDeviceFileSystem->id, path, true, (void **)_node);
}
static status_t
devfs_publish_device(const char *path, pnp_node_info *node, pnp_devfs_driver_info *info, device_hooks *ops)
{
@ -1128,7 +1109,7 @@ devfs_ioctl(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie, ulong op, void *b
return devfs_get_partition_info(fs, vnode, cookie, (partition_info *)buffer, length);
case B_SET_PARTITION:
return devfs_set_partition(fs, vnode, cookie, *(partition_info *)buffer, length);
return B_NOT_ALLOWED;
}
return vnode->stream.u.dev.info->control(cookie->u.dev.dcookie, op, buffer, length);
@ -1280,7 +1261,7 @@ devfs_read_stat(fs_volume _fs, fs_vnode _vnode, struct stat *stat)
// if it's a real block device, then let's report a useful size
if (vnode->stream.u.dev.part_map != NULL) {
stat->st_size = vnode->stream.u.dev.part_map->size;
stat->st_size = vnode->stream.u.dev.part_map->info.size;
#if 0
} else if (vnode->stream.u.dev.info->control(cookie->u.dev.dcookie,
B_GET_GEOMETRY, &geometry, sizeof(struct device_geometry)) >= B_OK) {
@ -1584,11 +1565,29 @@ devfs_unpublish_partition(const char *path)
extern "C" status_t
devfs_publish_partition(const char *path, const partition_info *info)
{
if (info == NULL)
if (path == NULL || info == NULL)
return B_BAD_VALUE;
dprintf("publish partition: %s (device \"%s\", offset %Ld, size %Ld)\n", path, info->device, info->offset, info->size);
return B_OK;
TRACE(("publish partition: %s (device \"%s\", offset %Ld, size %Ld)\n",
path, info->device, info->offset, info->size));
// the partition and device paths must be the same until the leaves
const char *lastPath = strrchr(path, '/');
const char *lastDevice = strrchr(info->device, '/');
if (lastPath == NULL || lastDevice == NULL
|| lastPath - path != lastDevice - info->device
|| strncmp(path, info->device, lastPath - path))
return B_BAD_VALUE;
devfs_vnode *device;
status_t status = get_node_for_path(info->device, &device);
if (status != B_OK)
return status;
status = add_partition(sDeviceFileSystem, device, lastPath + 1, *info);
put_vnode(sDeviceFileSystem->id, device->id);
return status;
}

View File

@ -1612,6 +1612,31 @@ vfs_get_vnode(mount_id mountID, vnode_id vnodeID, void **_vnode)
}
extern "C" status_t
vfs_get_fs_node_from_path(mount_id mountID, const char *path, bool kernel, void **_node)
{
char buffer[SYS_MAX_PATH_LEN + 1];
struct vnode *vnode;
status_t status;
PRINT(("vfs_get_fs_node_from_path(mountID = %ld, path = \"%s\", kernel %d)\n", mountID, path, kernel));
strlcpy(buffer, path, sizeof(buffer));
status = path_to_vnode(buffer, true, &vnode, kernel);
if (status < B_OK)
return status;
if (vnode->device != mountID) {
// wrong mount ID - must not gain access on foreign file system nodes
put_vnode(vnode);
return B_BAD_VALUE;
}
*_node = vnode->private_node;
return B_OK;
}
status_t
vfs_get_module_path(const char *basePath, const char *moduleName, char *pathBuffer,
size_t bufferSize)
@ -2053,19 +2078,20 @@ vfs_mount_boot_file_system()
// make the boot partition (and probably others) available
KDiskDeviceManager::CreateDefault();
status_t status;
#if 0
KDiskDeviceManager *manager = KDiskDeviceManager::Default();
status_t status = manager->InitialDeviceScan();
if (status != B_OK)
panic("KDiskDeviceManager::InitialDeviceScan() failed: %s\n", strerror(status));
// ToDo: do this for real... (no hacks allowed :))
for (;;) {
snooze(500000);
if (manager->CountJobs() == 0)
break;
}
status = manager->InitialDeviceScan();
if (status == B_OK) {
// ToDo: do this for real... (no hacks allowed :))
for (;;) {
snooze(500000);
if (manager->CountJobs() == 0)
break;
}
} else
dprintf("KDiskDeviceManager::InitialDeviceScan() failed: %s\n", strerror(status));
#endif
file_system_info *bootfs;