* 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:
@@ -91,7 +91,7 @@ struct fs_mount {
|
|||||||
char *mount_point;
|
char *mount_point;
|
||||||
char *device_name;
|
char *device_name;
|
||||||
char *fs_name;
|
char *fs_name;
|
||||||
recursive_lock rlock;
|
recursive_lock rlock; // guards the vnodes list
|
||||||
struct vnode *root_vnode;
|
struct vnode *root_vnode;
|
||||||
struct vnode *covers_vnode;
|
struct vnode *covers_vnode;
|
||||||
struct list vnodes;
|
struct list vnodes;
|
||||||
@@ -100,8 +100,40 @@ struct fs_mount {
|
|||||||
|
|
||||||
static mutex sFileSystemsMutex;
|
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;
|
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;
|
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;
|
static mutex sVnodeMutex;
|
||||||
|
|
||||||
#define VNODE_HASH_TABLE_SIZE 1024
|
#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
|
// add the vnode to the mount structure
|
||||||
mutex_lock(&sMountMutex);
|
mutex_lock(&sMountMutex);
|
||||||
vnode->mount = find_mount(mountID);
|
vnode->mount = find_mount(mountID);
|
||||||
if (!vnode->mount) {
|
if (!vnode->mount || vnode->mount->unmounting) {
|
||||||
mutex_unlock(&sMountMutex);
|
mutex_unlock(&sMountMutex);
|
||||||
free(vnode);
|
free(vnode);
|
||||||
return B_ENTRY_NOT_FOUND;
|
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
|
static status_t
|
||||||
dec_vnode_ref_count(struct vnode *vnode, bool reenter)
|
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
|
static void
|
||||||
inc_vnode_ref_count(struct vnode *vnode)
|
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 *
|
static struct vnode *
|
||||||
lookup_vnode(mount_id mountID, vnode_id vnodeID)
|
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
|
static status_t
|
||||||
get_vnode(mount_id mountID, vnode_id vnodeID, struct vnode **_vnode, int reenter)
|
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
|
static inline void
|
||||||
put_vnode(struct vnode *vnode)
|
put_vnode(struct vnode *vnode)
|
||||||
{
|
{
|
||||||
@@ -850,12 +934,14 @@ vnode_path_to_vnode(struct vnode *vnode, char *path, bool traverseLeafLink,
|
|||||||
vnode = nextVnode;
|
vnode = nextVnode;
|
||||||
|
|
||||||
// see if we hit a mount point
|
// see if we hit a mount point
|
||||||
|
mutex_lock(&sMountOpMutex);
|
||||||
if (vnode->covered_by) {
|
if (vnode->covered_by) {
|
||||||
nextVnode = vnode->covered_by;
|
nextVnode = vnode->covered_by;
|
||||||
inc_vnode_ref_count(nextVnode);
|
inc_vnode_ref_count(nextVnode);
|
||||||
put_vnode(vnode);
|
put_vnode(vnode);
|
||||||
vnode = nextVnode;
|
vnode = nextVnode;
|
||||||
}
|
}
|
||||||
|
mutex_unlock(&sMountOpMutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
*_vnode = vnode;
|
*_vnode = vnode;
|
||||||
@@ -3471,7 +3557,8 @@ fs_mount(char *path, const char *device, const char *fsName, void *args, bool ke
|
|||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto err7;
|
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)
|
if (mount->covers_vnode)
|
||||||
mount->covers_vnode->covered_by = mount->root_vnode;
|
mount->covers_vnode->covered_by = mount->root_vnode;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user