* Add an additional argument to get_vnode() that gets the fs_vnode_ops of the

node. That is needed for a layered filesystem to be able to construct a full
  fs_vnode out of a volume/inode pair.
* Adapt places where get_vnode is used. Sadly this is a C API and we can't just
  use a default NULL for that argument.
* Introduce a flag B_VNODE_WANTS_OVERLAY_SUB_NODE that can be returned in the
  flags field of a fs get_vnode call. A filesystem can use this flag to indicate
  that it doesn't support the full set of fs features (attributes, write support)
  and it'd like to have unsupported calls emulated by an overlay sub node.
* Add a perliminary overlay filesystem that emulates file attributes using files
  on a filesystem where attributes aren't supported. It does currently only
  support reading attributes/attribute directories though. All other calls are
  just passed through to the super filesystem.
* Adjust places where a HAS_FS_CALL() is taken as a guarantee that the operation
  is supported. For the overlay filesystem we may later return a B_UNSUPPORTED,
  so make sure that in that case proper fallback options are taken.
* Make the iso9660 filesystem request overlay sub nodes. This can be fine tuned
  later to only trigger where there are features on a CD that need emulation
  at all.

If you happened to know the attribute file format and location you could build
an iso with read-only attribute support now. Note that this won't be enough to
get a bootable iso-only image as the query and index support is yet missing.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@29177 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz 2009-02-09 23:06:31 +00:00
parent c8530759dd
commit 00405f2286
21 changed files with 1186 additions and 46 deletions

View File

@ -43,6 +43,7 @@ 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
@ -307,7 +308,7 @@ extern status_t publish_vnode(fs_volume *volume, ino_t vnodeID,
void *privateNode, fs_vnode_ops *ops, int type,
uint32 flags);
extern status_t get_vnode(fs_volume *volume, ino_t vnodeID,
void **_privateNode);
void **_privateNode, fs_vnode_ops **_vnodeOps);
extern status_t put_vnode(fs_volume *volume, ino_t vnodeID);
extern status_t acquire_vnode(fs_volume *volume, ino_t vnodeID);
extern status_t remove_vnode(fs_volume *volume, ino_t vnodeID);

View File

@ -344,7 +344,8 @@ extern fssh_status_t fssh_publish_vnode(fssh_fs_volume *volume,
fssh_vnode_id vnodeID, void *privateNode,
fssh_fs_vnode_ops *ops, int type, uint32_t flags);
extern fssh_status_t fssh_get_vnode(fssh_fs_volume *volume,
fssh_vnode_id vnodeID, void **_privateNode);
fssh_vnode_id vnodeID, void **_privateNode,
fssh_fs_vnode_ops **_vnodeOps);
extern fssh_status_t fssh_put_vnode(fssh_fs_volume *volume,
fssh_vnode_id vnodeID);
extern fssh_status_t fssh_acquire_vnode(fssh_fs_volume *volume,

View File

@ -2701,7 +2701,7 @@ AttributeIterator::GetNext(char* name, size_t* _length, uint32* _type,
// if you haven't yet access to the attributes directory, get it
if (fAttributes == NULL) {
if (get_vnode(volume->FSVolume(), volume->ToVnode(fInode->Attributes()),
(void**)&fAttributes) != B_OK) {
(void**)&fAttributes, NULL) != B_OK) {
FATAL(("get_vnode() failed in AttributeIterator::GetNext(ino_t"
" = %Ld,name = \"%s\")\n", fInode->ID(), name));
return B_ENTRY_NOT_FOUND;

View File

@ -354,7 +354,8 @@ public:
{
Unset();
return fStatus = get_vnode(volume->FSVolume(), id, (void**)&fInode);
return fStatus = get_vnode(volume->FSVolume(), id, (void**)&fInode,
NULL);
}
status_t SetTo(Volume* volume, block_run run)

View File

@ -556,7 +556,7 @@ bfs_lookup(fs_volume* _volume, fs_vnode* _directory, const char* file,
locker.Unlock();
Inode* inode;
status = get_vnode(volume->FSVolume(), *_vnodeID, (void**)&inode);
status = get_vnode(volume->FSVolume(), *_vnodeID, (void**)&inode, NULL);
if (status != B_OK) {
REPORT_ERROR(status);
return B_ENTRY_NOT_FOUND;

View File

@ -1493,7 +1493,7 @@ cdda_lookup(fs_volume* _volume, fs_vnode* _dir, const char* name, ino_t* _id)
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
status = get_vnode(volume->FSVolume(), inode->ID(), NULL);
status = get_vnode(volume->FSVolume(), inode->ID(), NULL, NULL);
if (status < B_OK)
return status;

View File

@ -310,7 +310,7 @@ Volume::Mount(const char* deviceName, uint32 flags)
if ((fBlockCache = opener.InitCache(NumBlocks(), fBlockSize)) == NULL)
return B_ERROR;
status = get_vnode(fFSVolume, EXT2_ROOT_NODE, (void**)&fRootNode);
status = get_vnode(fFSVolume, EXT2_ROOT_NODE, (void**)&fRootNode, NULL);
if (status != B_OK) {
TRACE("could not create root node: get_vnode() failed!\n");
return status;

View File

@ -319,7 +319,7 @@ ext2_lookup(fs_volume* _volume, fs_vnode* _directory, const char* name,
break;
}
return get_vnode(volume->FSVolume(), *_vnodeID, NULL);
return get_vnode(volume->FSVolume(), *_vnodeID, NULL, NULL);
}

View File

@ -433,7 +433,7 @@ findfile(nspace *vol, vnode *dir, const char *file, ino_t *vnid,
if (vnid)
*vnid = found_vnid;
if (node)
result = get_vnode(vol->volume, found_vnid, (void **)node);
result = get_vnode(vol->volume, found_vnid, (void **)node, NULL);
result = B_OK;
} else {
result = ENOENT;

View File

@ -890,7 +890,7 @@ dosfs_create(fs_volume *_vol, fs_vnode *_dir, const char *name, int omode,
*vnid = dummy.vnid;
dummy.magic = ~VNODE_MAGIC;
result = get_vnode(_vol, *vnid, (void **)&file);
result = get_vnode(_vol, *vnid, (void **)&file, NULL);
if (result < B_OK) {
if (vol->fs_flags & FS_FLAGS_OP_SYNC)
_dosfs_sync(vol);
@ -1155,7 +1155,7 @@ dosfs_rename(fs_volume *_vol, fs_vnode *_odir, const char *oldname,
if (vnid == vol->root_vnode.vnid)
break;
result = get_vnode(_vol, vnid, (void **)&dir);
result = get_vnode(_vol, vnid, (void **)&dir, NULL);
if (result < B_OK)
goto bi1;
parent = dir->dir_vnid;

View File

@ -224,12 +224,12 @@ fs_walk(fs_volume *_vol, fs_vnode *_base, const char *file, ino_t *_vnodeID)
// base directory
TRACE(("fs_walk - found \".\" file.\n"));
*_vnodeID = baseNode->id;
return get_vnode(_vol, *_vnodeID, (void **)&newNode);
return get_vnode(_vol, *_vnodeID, NULL, NULL);
} else if (strcmp(file, "..") == 0) {
// parent directory
TRACE(("fs_walk - found \"..\" file.\n"));
*_vnodeID = baseNode->parID;
return get_vnode(_vol, *_vnodeID, (void **)&newNode);
return get_vnode(_vol, *_vnodeID, NULL, NULL);
}
// look up file in the directory
@ -272,7 +272,7 @@ fs_walk(fs_volume *_vol, fs_vnode *_base, const char *file, ino_t *_vnodeID)
TRACE(("fs_walk - New vnode id is %Ld\n", *_vnodeID));
result = get_vnode(_vol, *_vnodeID,
(void **)&newNode);
(void **)&newNode, NULL);
if (result == B_OK) {
newNode->parID = baseNode->id;
done = true;
@ -349,7 +349,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 = 0;
*_flags = B_VNODE_WANTS_OVERLAY_SUB_NODE;
if ((newNode->flags & ISO_ISDIR) == 0) {
newNode->cache = file_cache_create(ns->id, vnodeID,

View File

@ -898,7 +898,7 @@ fs_walk(fs_volume *_volume, fs_vnode *_base, const char *file, ino_t *vnid)
isLink=S_ISLNK(st.st_mode);
}
if ((result=get_vnode (_volume,*vnid,(void **)&dummy))<B_OK)
if ((result=get_vnode (_volume,*vnid,(void **)&dummy,NULL))<B_OK)
return result;
return B_OK;
@ -1755,7 +1755,7 @@ fs_create(fs_volume *_volume, fs_vnode *_dir, const char *name, int omode, int p
*vnid=st.st_ino;
if ((result=get_vnode(_volume,*vnid,&dummy))<B_OK)
if ((result=get_vnode(_volume,*vnid,&dummy,NULL))<B_OK)
return result;
if (S_ISDIR(st.st_mode))
@ -1901,7 +1901,7 @@ fs_unlink(fs_volume *_volume, fs_vnode *_dir, const char *name)
insert_node (ns,newNode);
if ((result=get_vnode(_volume,st.st_ino,(void **)&dummy))<B_OK)
if ((result=get_vnode(_volume,st.st_ino,(void **)&dummy,NULL))<B_OK)
{
XDRInPacketDestroy (&reply);
XDROutPacketDestroy (&call);
@ -2195,7 +2195,7 @@ fs_rmdir(fs_volume *_volume, fs_vnode *_dir, const char *name)
insert_node (ns,newNode);
if ((result=get_vnode(_volume,st.st_ino,(void **)&dummy))<B_OK)
if ((result=get_vnode(_volume,st.st_ino,(void **)&dummy,NULL))<B_OK)
{
XDRInPacketDestroy(&reply);
XDROutPacketDestroy(&call);
@ -2341,7 +2341,7 @@ fs_symlink(fs_volume *_volume, fs_vnode *_dir, const char *name, const char *pat
if (result==B_OK)
{
void *dummy;
if ((result=get_vnode(_volume,st.st_ino,&dummy))<B_OK)
if ((result=get_vnode(_volume,st.st_ino,&dummy,NULL))<B_OK)
return result;
XDRInPacketDestroy (&reply);

View File

@ -294,7 +294,7 @@ Volume::GetKeyOffsetForName(const char *name, int len, uint64 *result)
status_t
Volume::GetVNode(ino_t id, VNode **node)
{
return get_vnode(GetFSVolume(), id, (void**)node);
return get_vnode(GetFSVolume(), id, (void**)node, NULL);
}
// PutVNode

View File

@ -407,7 +407,8 @@ add_partition(struct devfs* fs, struct devfs_vnode* device, const char* name,
// increase reference count of raw device -
// the partition device really needs it
status = get_vnode(fs->volume, device->id, (void**)&partition->raw_device);
status = get_vnode(fs->volume, device->id, (void**)&partition->raw_device,
NULL);
if (status < B_OK)
goto err1;
@ -937,7 +938,7 @@ devfs_lookup(fs_volume *_volume, fs_vnode *_dir, const char *name, ino_t *_id)
{
struct devfs *fs = (struct devfs *)_volume->private_volume;
struct devfs_vnode *dir = (struct devfs_vnode *)_dir->private_node;
struct devfs_vnode *vnode, *vdummy;
struct devfs_vnode *vnode;
status_t status;
TRACE(("devfs_lookup: entry dir %p, name '%s'\n", dir, name));
@ -958,7 +959,7 @@ devfs_lookup(fs_volume *_volume, fs_vnode *_dir, const char *name, ino_t *_id)
return B_ENTRY_NOT_FOUND;
}
status = get_vnode(fs->volume, vnode->id, (void**)&vdummy);
status = get_vnode(fs->volume, vnode->id, NULL, NULL);
if (status < B_OK)
return status;
@ -1062,7 +1063,7 @@ devfs_create(fs_volume* _volume, fs_vnode* _dir, const char* name, int openMode,
if (openMode & O_EXCL)
return B_FILE_EXISTS;
status = get_vnode(fs->volume, vnode->id, NULL);
status = get_vnode(fs->volume, vnode->id, NULL, NULL);
if (status < B_OK)
return status;
@ -2091,7 +2092,7 @@ devfs_unpublish_device(BaseDevice* device, bool disconnect)
{
devfs_vnode* node;
status_t status = get_vnode(sDeviceFileSystem->volume, device->ID(),
(void**)&node);
(void**)&node, NULL);
if (status != B_OK)
return status;

View File

@ -12,6 +12,7 @@ KernelMergeObject kernel_fs.o :
fifo.cpp
KPath.cpp
node_monitor.cpp
overlay.cpp
rootfs.cpp
socket.cpp
vfs.cpp

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,16 @@
/*
* Copyright 2009, Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <mmlr@mlotz.ch>
*/
#ifndef _VFS_OVERLAY_H
#define _VFS_OVERLAY_H
#include <fs_interface.h>
status_t create_overlay_vnode(fs_volume *superVolume, fs_vnode *vnode);
#endif // _VFS_OVERLAY_H

View File

@ -284,8 +284,7 @@ remove_node(struct rootfs *fs, struct rootfs_vnode *directory,
{
// schedule this vnode to be removed when it's ref goes to zero
void* dummy;
bool gotNode = (get_vnode(fs->volume, vnode->id, &dummy) == B_OK);
bool gotNode = (get_vnode(fs->volume, vnode->id, NULL, NULL) == B_OK);
status_t status = B_OK;
if (gotNode)
@ -432,7 +431,7 @@ rootfs_lookup(fs_volume *_volume, fs_vnode *_dir, const char *name, ino_t *_id)
{
struct rootfs *fs = (struct rootfs *)_volume->private_volume;
struct rootfs_vnode *dir = (struct rootfs_vnode *)_dir->private_node;
struct rootfs_vnode *vnode,*vdummy;
struct rootfs_vnode *vnode;
status_t status;
TRACE(("rootfs_lookup: entry dir %p, name '%s'\n", dir, name));
@ -448,7 +447,7 @@ rootfs_lookup(fs_volume *_volume, fs_vnode *_dir, const char *name, ino_t *_id)
goto err;
}
status = get_vnode(fs->volume, vnode->id, (void**)&vdummy);
status = get_vnode(fs->volume, vnode->id, NULL, NULL);
if (status < B_OK)
goto err;

View File

@ -54,6 +54,7 @@
#include "fifo.h"
#include "io_requests.h"
#include "overlay.h"
//#define TRACE_VFS
@ -1180,6 +1181,9 @@ 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;
}
@ -1253,7 +1257,8 @@ restart:
bool publishSpecialSubNode = false;
if (gotNode) {
vnode->type = type;
publishSpecialSubNode = is_special_node_type(type)
publishSpecialSubNode = (is_special_node_type(type)
|| (flags & B_VNODE_WANTS_OVERLAY_SUB_NODE) != 0)
&& (flags & B_VNODE_DONT_CREATE_SPECIAL_SUB_NODE) == 0;
}
@ -2485,8 +2490,9 @@ get_vnode_name(struct vnode *vnode, struct vnode *parent, struct dirent *buffer,
if (HAS_FS_CALL(vnode, get_vnode_name)) {
// The FS supports getting the name of a vnode.
return FS_CALL(vnode, get_vnode_name, buffer->d_name,
(char*)buffer + bufferSize - buffer->d_name);
if (FS_CALL(vnode, get_vnode_name, buffer->d_name,
(char*)buffer + bufferSize - buffer->d_name) == B_OK)
return B_OK;
}
// The FS doesn't support getting the name of a vnode. So we search the
@ -3584,7 +3590,8 @@ publish_vnode(fs_volume *volume, ino_t vnodeID, void *privateNode,
extern "C" status_t
get_vnode(fs_volume *volume, ino_t vnodeID, void **_fsNode)
get_vnode(fs_volume *volume, ino_t vnodeID, void **_privateNode,
fs_vnode_ops **_vnodeOps)
{
struct vnode *vnode;
@ -3608,10 +3615,16 @@ get_vnode(fs_volume *volume, ino_t vnodeID, void **_fsNode)
return status;
}
if (_fsNode != NULL)
*_fsNode = resolvedNode.private_node;
} else if (_fsNode != NULL)
*_fsNode = vnode->private_node;
if (_privateNode != NULL)
*_privateNode = resolvedNode.private_node;
if (_vnodeOps != NULL)
*_vnodeOps = resolvedNode.ops;
} else {
if (_privateNode != NULL)
*_privateNode = vnode->private_node;
if (_vnodeOps != NULL)
*_vnodeOps = vnode->ops;
}
return B_OK;
}
@ -4005,7 +4018,7 @@ vfs_get_fs_node_from_path(fs_volume *volume, const char *path, bool kernel,
}
// Use get_vnode() to resolve the cookie for the right layer.
status = get_vnode(volume, vnode->id, _node);
status = get_vnode(volume, vnode->id, _node, NULL);
put_vnode(vnode);
return status;

View File

@ -401,14 +401,16 @@ synchronous_io(io_request* request, DoIO& io)
status_t
vfs_vnode_io(struct vnode* vnode, void* cookie, io_request* request)
{
if (!HAS_FS_CALL(vnode, io)) {
status_t result = B_ERROR;
if (!HAS_FS_CALL(vnode, io)
|| (result = FS_CALL(vnode, io, cookie, request)) == B_UNSUPPORTED) {
// no io() call -- fall back to synchronous I/O
IOBuffer* buffer = request->Buffer();
VnodeIO io(request->IsWrite(), buffer->IsPhysical(), vnode, cookie);
return synchronous_io(request, io);
}
return FS_CALL(vnode, io, cookie, request);
return result;
}

View File

@ -1985,7 +1985,8 @@ fssh_publish_vnode(fssh_fs_volume *volume, fssh_vnode_id vnodeID,
extern "C" fssh_status_t
fssh_get_vnode(fssh_fs_volume *volume, fssh_vnode_id vnodeID, void **fsNode)
fssh_get_vnode(fssh_fs_volume *volume, fssh_vnode_id vnodeID,
void **privateNode, fssh_fs_vnode_ops **vnodeOps)
{
struct vnode *vnode;
@ -2009,9 +2010,16 @@ fssh_get_vnode(fssh_fs_volume *volume, fssh_vnode_id vnodeID, void **fsNode)
return status;
}
*fsNode = resolvedNode.private_node;
} else
*fsNode = vnode->private_node;
if (privateNode != NULL)
*privateNode = resolvedNode.private_node;
if (vnodeOps != NULL)
*vnodeOps = resolvedNode.ops;
} else {
if (privateNode != NULL)
*privateNode = vnode->private_node;
if (vnodeOps != NULL)
*vnodeOps = vnode->ops;
}
return FSSH_B_OK;
}
@ -2443,7 +2451,7 @@ vfs_get_fs_node_from_path(fssh_fs_volume *volume, const char *path, bool kernel,
}
// Use get_vnode() to resolve the cookie for the right layer.
status = ::fssh_get_vnode(volume, vnode->id, _node);
status = ::fssh_get_vnode(volume, vnode->id, _node, NULL);
put_vnode(vnode);
return FSSH_B_OK;