* 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
This commit is contained in:
Ingo Weinhold
2004-09-13 14:53:09 +00:00
parent f3736c4994
commit 79c795cc5d
+90 -3
View File
@@ -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;