* 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
This commit is contained in:
parent
95da064570
commit
a26c243920
@ -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 */
|
||||
|
@ -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,
|
||||
|
@ -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));
|
||||
|
Loading…
Reference in New Issue
Block a user