From a26c24392042ca7bfad2e78f73a0b75c463c0455 Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Sat, 14 Feb 2009 20:30:49 +0000 Subject: [PATCH] * Adding volume ops to the overlay filesystem. * Remove the previous method of applying the overlay by flags. In the future the overlay can just be mounted as a filesystem layer. This is probably how layers were intended to work in the first place. * Move the filesystem module info and filesystem name from the fs_mount to the fs_volume structure. Filesystem layering is done by having multiple layered volumes and we want to be able to have a different fs per layer. * Adapt VFS code to this move. * Implement mounting layered filesystems. Specifying multiple filesystems separated by a colon on mount will cause the layers to be set up and the corresponding filesystems to be mounted at that layer. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@29199 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/os/drivers/fs_interface.h | 23 +- .../file_systems/iso9660/kernel_interface.cpp | 6 +- src/system/kernel/fs/vfs.cpp | 205 ++++++++++++------ 3 files changed, 156 insertions(+), 78 deletions(-) diff --git a/headers/os/drivers/fs_interface.h b/headers/os/drivers/fs_interface.h index 6b3ec1c936..fb4a8ac737 100644 --- a/headers/os/drivers/fs_interface.h +++ b/headers/os/drivers/fs_interface.h @@ -43,7 +43,6 @@ struct file_io_vec { // flags for publish_vnode() and fs_volume_ops::get_vnode() #define B_VNODE_PUBLISH_REMOVED 0x01 #define B_VNODE_DONT_CREATE_SPECIAL_SUB_NODE 0x02 -#define B_VNODE_WANTS_OVERLAY_SUB_NODE 0x04 #ifdef __cplusplus @@ -54,16 +53,18 @@ typedef struct fs_volume fs_volume; typedef struct fs_volume_ops fs_volume_ops; typedef struct fs_vnode fs_vnode; typedef struct fs_vnode_ops fs_vnode_ops; - +typedef struct file_system_module_info file_system_module_info; struct fs_volume { - dev_t id; - partition_id partition; - int32 layer; - void* private_volume; - fs_volume_ops* ops; - fs_volume* sub_volume; - fs_volume* super_volume; + dev_t id; + partition_id partition; + int32 layer; + void* private_volume; + fs_volume_ops* ops; + fs_volume* sub_volume; + fs_volume* super_volume; + file_system_module_info* file_system; + char* file_system_name; }; struct fs_vnode { @@ -240,7 +241,7 @@ struct fs_vnode_ops { fs_volume *superVolume, fs_vnode *superVnode); }; -typedef struct file_system_module_info { +struct file_system_module_info { struct module_info info; const char* short_name; const char* pretty_name; @@ -290,7 +291,7 @@ typedef struct file_system_module_info { const char *parameters, disk_job_id job); status_t (*initialize)(int fd, partition_id partition, const char *name, const char *parameters, off_t partitionSize, disk_job_id job); -} file_system_module_info; +}; /* file system add-ons only prototypes */ diff --git a/src/add-ons/kernel/file_systems/iso9660/kernel_interface.cpp b/src/add-ons/kernel/file_systems/iso9660/kernel_interface.cpp index 101653e267..aa9f62bdd2 100644 --- a/src/add-ons/kernel/file_systems/iso9660/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/iso9660/kernel_interface.cpp @@ -137,8 +137,8 @@ fs_mount(fs_volume *_volume, const char *device, uint32 flags, volume->id = _volume->id; result = publish_vnode(_volume, *_rootID, &volume->rootDirRec, - &gISO9660VnodeOps, volume->rootDirRec.attr.stat[FS_DATA_FORMAT].st_mode, - B_VNODE_WANTS_OVERLAY_SUB_NODE); + &gISO9660VnodeOps, + volume->rootDirRec.attr.stat[FS_DATA_FORMAT].st_mode, 0); if (result != B_OK) { block_cache_delete(volume->fBlockCache, false); free(volume); @@ -350,7 +350,7 @@ fs_read_vnode(fs_volume *_vol, ino_t vnodeID, fs_vnode *_node, _node->private_node = newNode; _node->ops = &gISO9660VnodeOps; *_type = newNode->attr.stat[FS_DATA_FORMAT].st_mode & ~(S_IWUSR | S_IWGRP | S_IWOTH); - *_flags = B_VNODE_WANTS_OVERLAY_SUB_NODE; + *_flags = 0; if ((newNode->flags & ISO_ISDIR) == 0) { newNode->cache = file_cache_create(ns->id, vnodeID, diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp index 19ae4c618d..654cfc3fcd 100644 --- a/src/system/kernel/fs/vfs.cpp +++ b/src/system/kernel/fs/vfs.cpp @@ -54,7 +54,6 @@ #include "fifo.h" #include "io_requests.h" -#include "overlay.h" //#define TRACE_VFS @@ -304,8 +303,7 @@ struct fs_mount { fs_mount() : volume(NULL), - device_name(NULL), - fs_name(NULL) + device_name(NULL) { recursive_lock_init(&rlock, "mount rlock"); } @@ -314,16 +312,23 @@ struct fs_mount { { recursive_lock_destroy(&rlock); free(device_name); - free(fs_name); - free(volume); + + while (volume) { + fs_volume* superVolume = volume->super_volume; + + if (volume->file_system != NULL) + put_module(volume->file_system->info.name); + + free(volume->file_system_name); + free(volume); + volume = superVolume; + } } struct fs_mount* next; - file_system_module_info* fs; dev_t id; fs_volume* volume; char* device_name; - char* fs_name; recursive_lock rlock; // guards the vnodes list struct vnode* root_vnode; struct vnode* covers_vnode; @@ -865,13 +870,6 @@ put_mount(struct fs_mount *mount) } -static status_t -put_file_system(file_system_module_info *fs) -{ - return put_module(fs->info.name); -} - - /*! Tries to open the specified file system module. Accepts a file system name of the form "bfs" or "file_systems/bfs/v1". Returns a pointer to file system module interface, or NULL if it @@ -900,7 +898,7 @@ get_file_system(const char *fsName) and returns a compatible fs_info.fsh_name name ("bfs" in both cases). The name is allocated for you, and you have to free() it when you're done with it. - Returns NULL if the required memory is no available. + Returns NULL if the required memory is not available. */ static char * get_file_system_name(const char *fsName) @@ -930,6 +928,39 @@ get_file_system_name(const char *fsName) } +/*! Accepts a list of file system names separated by a colon, one for each + layer and returns the file system name for the specified layer. + The name is allocated for you, and you have to free() it when you're + done with it. + Returns NULL if the required memory is not available or if there is no + name for the specified layer. +*/ +static char * +get_file_system_name_for_layer(const char *fsNames, int32 layer) +{ + while (layer >= 0) { + const char *end = strchr(fsNames, ':'); + if (end == NULL) { + if (layer == 0) + return strdup(fsNames); + return NULL; + } + + if (layer == 0) { + size_t length = end - fsNames + 1; + char *result = (char *)malloc(length); + strlcpy(result, fsNames, length); + return result; + } + + fsNames = end + 1; + layer--; + } + + return NULL; +} + + static int vnode_compare(void *_vnode, const void *_key) { @@ -1181,9 +1212,6 @@ create_special_sub_node(struct vnode* vnode, uint32 flags) if (S_ISFIFO(vnode->type)) return create_fifo_vnode(vnode->mount->volume, vnode); - if ((flags & B_VNODE_WANTS_OVERLAY_SUB_NODE) != 0) - return create_overlay_vnode(vnode->mount->volume, vnode); - return B_BAD_VALUE; } @@ -1257,8 +1285,7 @@ restart: bool publishSpecialSubNode = false; if (gotNode) { vnode->type = type; - publishSpecialSubNode = (is_special_node_type(type) - || (flags & B_VNODE_WANTS_OVERLAY_SUB_NODE) != 0) + publishSpecialSubNode = is_special_node_type(type) && (flags & B_VNODE_DONT_CREATE_SPECIAL_SUB_NODE) == 0; } @@ -2987,7 +3014,6 @@ _dump_mount(struct fs_mount *mount) kprintf("MOUNT: %p\n", mount); kprintf(" id: %ld\n", mount->id); kprintf(" device_name: %s\n", mount->device_name); - kprintf(" fs_name: %s\n", mount->fs_name); kprintf(" root_vnode: %p\n", mount->root_vnode); kprintf(" covers_vnode: %p\n", mount->covers_vnode); kprintf(" partition: %p\n", mount->partition); @@ -2998,9 +3024,11 @@ _dump_mount(struct fs_mount *mount) fs_volume *volume = mount->volume; while (volume != NULL) { kprintf(" volume %p:\n", volume); - kprintf(" layer: %ld\n", volume->layer); - kprintf(" private_volume: %p\n", volume->private_volume); - kprintf(" ops: %p\n", volume->ops); + kprintf(" layer: %ld\n", volume->layer); + kprintf(" private_volume: %p\n", volume->private_volume); + kprintf(" ops: %p\n", volume->ops); + kprintf(" file_system: %p\n", volume->file_system); + kprintf(" file_system_name: %s\n", volume->file_system_name); volume = volume->super_volume; } @@ -3076,7 +3104,15 @@ dump_mounts(int argc, char **argv) hash_open(sMountsTable, &iterator); while ((mount = (struct fs_mount *)hash_next(sMountsTable, &iterator)) != NULL) { kprintf("%p%4ld %p %p %p %s\n", mount, mount->id, mount->root_vnode, - mount->covers_vnode, mount->volume->private_volume, mount->fs_name); + mount->covers_vnode, mount->volume->private_volume, + mount->volume->file_system_name); + + fs_volume* volume = mount->volume; + while (volume->super_volume != NULL) { + volume = volume->super_volume; + kprintf(" %p %s\n", + volume->private_volume, volume->file_system_name); + } } hash_close(sMountsTable, &iterator, false); @@ -3539,8 +3575,7 @@ publish_vnode(fs_volume *volume, ino_t vnodeID, void *privateNode, if (status == B_OK) { vnode->type = type; vnode->remove = (flags & B_VNODE_PUBLISH_REMOVED) != 0; - publishSpecialSubNode = (is_special_node_type(type) - || (flags & B_VNODE_WANTS_OVERLAY_SUB_NODE) != 0) + publishSpecialSubNode = is_special_node_type(type) && (flags & B_VNODE_DONT_CREATE_SPECIAL_SUB_NODE) == 0; } @@ -6742,7 +6777,9 @@ fs_mount(char* path, const char* device, const char* fsName, uint32 flags, const char* args, bool kernel) { struct ::fs_mount* mount; - status_t status = 0; + status_t status = B_OK; + fs_volume* volume = NULL; + int32 layer = 0; FUNCTION(("fs_mount: entry. path = '%s', fs_name = '%s'\n", path, fsName)); @@ -6860,18 +6897,6 @@ fs_mount(char* path, const char* device, const char* fsName, uint32 flags, if (mount == NULL) return B_NO_MEMORY; - mount->volume = (fs_volume*)malloc(sizeof(fs_volume)); - if (mount->volume == NULL) { - delete mount; - return B_NO_MEMORY; - } - - mount->fs_name = get_file_system_name(fsName); - if (mount->fs_name == NULL) { - status = B_NO_MEMORY; - goto err1; - } - mount->device_name = strdup(device); // "device" can be NULL @@ -6879,12 +6904,6 @@ fs_mount(char* path, const char* device, const char* fsName, uint32 flags, if (status != B_OK) goto err1; - mount->fs = get_file_system(fsName); - if (mount->fs == NULL) { - status = ENODEV; - goto err1; - } - // initialize structure mount->id = sNextMountID++; mount->partition = NULL; @@ -6892,14 +6911,62 @@ fs_mount(char* path, const char* device, const char* fsName, uint32 flags, mount->covers_vnode = NULL; mount->unmounting = false; mount->owns_file_device = false; + mount->volume = NULL; - mount->volume->id = mount->id; - mount->volume->partition = partition != NULL ? partition->ID() : -1; - mount->volume->layer = 0; - mount->volume->private_volume = NULL; - mount->volume->ops = NULL; - mount->volume->sub_volume = NULL; - mount->volume->super_volume = NULL; + // build up the volume(s) + while (true) { + char* layerFSName = get_file_system_name_for_layer(fsName, layer); + if (layerFSName == NULL) { + if (layer == 0) { + status = B_NO_MEMORY; + goto err1; + } + + break; + } + + volume = (fs_volume*)malloc(sizeof(fs_volume)); + if (volume == NULL) { + status = B_NO_MEMORY; + free(layerFSName); + goto err1; + } + + volume->id = mount->id; + volume->partition = partition != NULL ? partition->ID() : -1; + volume->layer = layer++; + volume->private_volume = NULL; + volume->ops = NULL; + volume->sub_volume = NULL; + volume->super_volume = NULL; + volume->file_system = NULL; + volume->file_system_name = NULL; + + volume->file_system_name = get_file_system_name(layerFSName); + if (volume->file_system_name == NULL) { + status = B_NO_MEMORY; + free(layerFSName); + free(volume); + goto err1; + } + + volume->file_system = get_file_system(layerFSName); + if (volume->file_system == NULL) { + status = ENODEV; + free(layerFSName); + free(volume->file_system_name); + free(volume); + goto err1; + } + + if (mount->volume == NULL) + mount->volume = volume; + else { + volume->super_volume = mount->volume; + mount->volume->sub_volume = volume; + mount->volume = volume; + } + } // insert mount struct into list before we call FS's mount() function // so that vnodes can be created for this mount @@ -6916,7 +6983,8 @@ fs_mount(char* path, const char* device, const char* fsName, uint32 flags, goto err2; } - status = mount->fs->mount(mount->volume, device, flags, args, &rootID); + status = mount->volume->file_system->mount(mount->volume, device, flags, + args, &rootID); if (status < 0) { // ToDo: why should we hide the error code from the file system here? //status = ERR_VFS_GENERAL; @@ -6942,10 +7010,19 @@ fs_mount(char* path, const char* device, const char* fsName, uint32 flags, mount->covers_vnode = coveredVnode; - // mount it - status = mount->fs->mount(mount->volume, device, flags, args, &rootID); - if (status < B_OK) - goto err3; + // mount it/them + fs_volume* volume = mount->volume; + while (volume) { + status = volume->file_system->mount(volume, device, flags, args, + &rootID); + if (status < B_OK) { + if (volume->sub_volume) + goto err4; + goto err3; + } + + volume = volume->super_volume; + } } // the root node is supposed to be owned by the file system - it must @@ -6998,8 +7075,6 @@ err2: mutex_lock(&sMountMutex); hash_remove(sMountsTable, mount); mutex_unlock(&sMountMutex); - - put_file_system(mount->fs); err1: delete mount; @@ -7174,9 +7249,6 @@ fs_unmount(char *path, dev_t mountID, uint32 flags, bool kernel) FS_MOUNT_CALL_NO_PARAMS(mount, unmount); notify_unmount(mount->id); - // release the file system - put_file_system(mount->fs); - // dereference the partition and mark it unmounted if (partition) { partition->SetVolumeID(-1); @@ -7283,7 +7355,12 @@ fs_read_info(dev_t device, struct fs_info *info) if (status == B_OK) { info->dev = mount->id; info->root = mount->root_vnode->id; - strlcpy(info->fsh_name, mount->fs_name, sizeof(info->fsh_name)); + + fs_volume* volume = mount->volume; + while (volume->super_volume != NULL) + volume = volume->super_volume; + + strlcpy(info->fsh_name, volume->file_system_name, sizeof(info->fsh_name)); if (mount->device_name != NULL) { strlcpy(info->device_name, mount->device_name, sizeof(info->device_name));