From 79c795cc5d1fc151092c1434ad36165fe98a2ed5 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Mon, 13 Sep 2004 14:53:09 +0000 Subject: [PATCH] * create_new_vnode() now also fails, if the volume is about to be unmounted. * Clarified a comment in fs_mount(). * Added a bit of documentation regarding the mutexes and the basic vnode functions. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@8930 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/kernel/core/fs/vfs.cpp | 93 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 90 insertions(+), 3 deletions(-) diff --git a/src/kernel/core/fs/vfs.cpp b/src/kernel/core/fs/vfs.cpp index 153e2f34f2..7f18dfcc88 100755 --- a/src/kernel/core/fs/vfs.cpp +++ b/src/kernel/core/fs/vfs.cpp @@ -91,7 +91,7 @@ struct fs_mount { char *mount_point; char *device_name; char *fs_name; - recursive_lock rlock; + recursive_lock rlock; // guards the vnodes list struct vnode *root_vnode; struct vnode *covers_vnode; struct list vnodes; @@ -100,8 +100,40 @@ struct fs_mount { static mutex sFileSystemsMutex; +/** \brief Guards sMountsTable. + + The holder is allowed to read access the sMountsTable. Write access + additionally requires the sMountOpMutex (which has to be locked before + acquiring sMountMutex). Manipulation of the fs_mount structures themselves + (and their destruction) requires different locks though. +*/ static mutex sMountMutex; + +/** \brief Guards mount/unmount operations. + + The fs_mount() and fs_unmount() hold the mutex during their whole operation. + That is locking the mutex ensures that no FS is mounted/unmounted. In + particular this means that + - sMountsTable will not be modified, + - the fields immutable after initialization of the fs_mount structures in + sMountsTable will not be modified, + - vnode::covered_by of any vnode in sVnodeTable will not be modified, + + The thread trying to lock the mutex must not hold sVnodeMutex or + sMountMutex. +*/ static mutex sMountOpMutex; + +/** \brief Guards sVnodeTable. + + The holder is allowed to read/write access sVnodeTable and to + to any unbusy vnode in that table, save + to the immutable fields (device, id, private_node, mount) to which + only read-only access is allowed, and to the field covered_by, which is + guarded by sMountOpMutex. + + The thread trying to lock the mutex must not hold sMountMutex. +*/ static mutex sVnodeMutex; #define VNODE_HASH_TABLE_SIZE 1024 @@ -491,7 +523,7 @@ create_new_vnode(struct vnode **_vnode, mount_id mountID, vnode_id vnodeID) // add the vnode to the mount structure mutex_lock(&sMountMutex); vnode->mount = find_mount(mountID); - if (!vnode->mount) { + if (!vnode->mount || vnode->mount->unmounting) { mutex_unlock(&sMountMutex); free(vnode); return B_ENTRY_NOT_FOUND; @@ -509,6 +541,18 @@ create_new_vnode(struct vnode **_vnode, mount_id mountID, vnode_id vnodeID) } +/** \brief Decrements the reference counter of the given vnode and deletes it, + if the counter dropped to 0. + + The caller must, of course, own a reference to the vnode to call this + function. + The caller must not hold the sVnodeMutex or the sMountMutex. + + \param vnode the vnode. + \param reenter \c true, if this function is called (indirectly) from within + a file system. + \return \c B_OK, if everything went fine, an error code otherwise. +*/ static status_t dec_vnode_ref_count(struct vnode *vnode, bool reenter) { @@ -556,6 +600,13 @@ dec_vnode_ref_count(struct vnode *vnode, bool reenter) } +/** \brief Increments the reference counter of the given vnode. + + The caller must either already have a reference to the vnode or hold + the sVnodeMutex. + + \param vnode the vnode. +*/ static void inc_vnode_ref_count(struct vnode *vnode) { @@ -564,6 +615,16 @@ inc_vnode_ref_count(struct vnode *vnode) } +/** \brief Looks up a vnode by mount and node ID in the sVnodeTable. + + The caller must hold the sVnodeMutex. + + \param mountID the mount ID. + \param vnodeID the node ID. + + \return The vnode structure, if it was found in the hash table, \c NULL + otherwise. +*/ static struct vnode * lookup_vnode(mount_id mountID, vnode_id vnodeID) { @@ -576,6 +637,20 @@ lookup_vnode(mount_id mountID, vnode_id vnodeID) } +/** \brief Retrieves a vnode for a given mount ID, node ID pair. + + If the node is not yet in memory, it will be loaded. + + The caller must not hold the sVnodeMutex or the sMountMutex. + + \param mountID the mount ID. + \param vnodeID the node ID. + \param _vnode Pointer to a vnode* variable into which the pointer to the + retrieved vnode structure shall be written. + \param reenter \c true, if this function is called (indirectly) from within + a file system. + \return \c B_OK, if everything when fine, an error code otherwise. +*/ static status_t get_vnode(mount_id mountID, vnode_id vnodeID, struct vnode **_vnode, int reenter) { @@ -642,6 +717,15 @@ err: } +/** \brief Decrements the reference counter of the given vnode and deletes it, + if the counter dropped to 0. + + The caller must, of course, own a reference to the vnode to call this + function. + The caller must not hold the sVnodeMutex or the sMountMutex. + + \param vnode the vnode. +*/ static inline void put_vnode(struct vnode *vnode) { @@ -850,12 +934,14 @@ vnode_path_to_vnode(struct vnode *vnode, char *path, bool traverseLeafLink, vnode = nextVnode; // see if we hit a mount point + mutex_lock(&sMountOpMutex); if (vnode->covered_by) { nextVnode = vnode->covered_by; inc_vnode_ref_count(nextVnode); put_vnode(vnode); vnode = nextVnode; } + mutex_unlock(&sMountOpMutex); } *_vnode = vnode; @@ -3471,7 +3557,8 @@ fs_mount(char *path, const char *device, const char *fsName, void *args, bool ke if (err < 0) goto err7; - // XXX may be a race here + // No race here, since fs_mount() is the only function changing + // covers_vnode (and holds sMountOpMutex at that time). if (mount->covers_vnode) mount->covers_vnode->covered_by = mount->root_vnode;