Improved fs_unmount(): it will now free all vnodes directly via free_vnode(),
and no longer relies on put_vnode() for the root node. This will also call the FS release/remove vnode calls. Extended comments. Added "flags" parameter to unmount. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@10289 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
+27
-27
@@ -4086,11 +4086,11 @@ err1:
|
|||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
fs_unmount(char *path, bool kernel)
|
fs_unmount(char *path, uint32 flags, bool kernel)
|
||||||
{
|
{
|
||||||
struct fs_mount *mount;
|
struct fs_mount *mount;
|
||||||
struct vnode *vnode;
|
struct vnode *vnode;
|
||||||
int err;
|
status_t err;
|
||||||
|
|
||||||
FUNCTION(("vfs_unmount: entry. path = '%s', kernel %d\n", path, kernel));
|
FUNCTION(("vfs_unmount: entry. path = '%s', kernel %d\n", path, kernel));
|
||||||
|
|
||||||
@@ -4132,12 +4132,13 @@ fs_unmount(char *path, bool kernel)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* grab the vnode master mutex to keep someone from creating
|
// grab the vnode master mutex to keep someone from creating
|
||||||
* a vnode while we're figuring out if we can continue
|
// a vnode while we're figuring out if we can continue
|
||||||
*/
|
|
||||||
mutex_lock(&sVnodeMutex);
|
mutex_lock(&sVnodeMutex);
|
||||||
|
|
||||||
/* simulate the root vnode having it's refcount decremented */
|
// simplify the loop below: we decrement the root vnode ref_count
|
||||||
|
// by the known number of references: one for the fs_mount, one
|
||||||
|
// from the path_to_vnode() call above
|
||||||
mount->root_vnode->ref_count -= 2;
|
mount->root_vnode->ref_count -= 2;
|
||||||
|
|
||||||
// cycle through the list of vnodes associated with this mount and
|
// cycle through the list of vnodes associated with this mount and
|
||||||
@@ -4145,39 +4146,38 @@ fs_unmount(char *path, bool kernel)
|
|||||||
vnode = NULL;
|
vnode = NULL;
|
||||||
while ((vnode = (struct vnode *)list_get_next_item(&mount->vnodes, vnode)) != NULL) {
|
while ((vnode = (struct vnode *)list_get_next_item(&mount->vnodes, vnode)) != NULL) {
|
||||||
if (vnode->busy || vnode->ref_count != 0) {
|
if (vnode->busy || vnode->ref_count != 0) {
|
||||||
|
// there are still vnodes in use on this mount, so we cannot unmount yet
|
||||||
|
// ToDo: cut read/write access file descriptors, depending on the B_FORCE_UNMOUNT flag
|
||||||
mount->root_vnode->ref_count += 2;
|
mount->root_vnode->ref_count += 2;
|
||||||
mutex_unlock(&sVnodeMutex);
|
mutex_unlock(&sVnodeMutex);
|
||||||
put_vnode(mount->root_vnode);
|
put_vnode(mount->root_vnode);
|
||||||
|
|
||||||
return EBUSY;
|
return B_BUSY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we can safely continue, mark all of the vnodes busy and this mount
|
// we can safely continue, mark all of the vnodes busy and this mount
|
||||||
* structure in unmounting state
|
// structure in unmounting state
|
||||||
*/
|
|
||||||
while ((vnode = (struct vnode *)list_get_next_item(&mount->vnodes, vnode)) != NULL) {
|
|
||||||
if (vnode != mount->root_vnode)
|
|
||||||
vnode->busy = true;
|
|
||||||
}
|
|
||||||
mount->unmounting = true;
|
mount->unmounting = true;
|
||||||
|
|
||||||
/* add 2 back to the root vnode's ref */
|
while ((vnode = (struct vnode *)list_get_next_item(&mount->vnodes, vnode)) != NULL) {
|
||||||
mount->root_vnode->ref_count += 2;
|
vnode->busy = true;
|
||||||
|
hash_remove(sVnodeTable, vnode);
|
||||||
|
}
|
||||||
|
|
||||||
mutex_unlock(&sVnodeMutex);
|
mutex_unlock(&sVnodeMutex);
|
||||||
|
|
||||||
mount->covers_vnode->covered_by = NULL;
|
mount->covers_vnode->covered_by = NULL;
|
||||||
put_vnode(mount->covers_vnode);
|
put_vnode(mount->covers_vnode);
|
||||||
|
|
||||||
/* release the ref on the root vnode twice */
|
// Free all vnodes associated with this mount.
|
||||||
put_vnode(mount->root_vnode);
|
// They will be removed from the mount list by free_vnode(), so
|
||||||
put_vnode(mount->root_vnode);
|
// we don't have to do this.
|
||||||
|
while ((vnode = (struct vnode *)list_get_next_item(&mount->vnodes, NULL)) != NULL) {
|
||||||
|
free_vnode(vnode, false);
|
||||||
|
}
|
||||||
|
|
||||||
// ToDo: when full vnode cache in place, will need to force
|
// remove the mount structure from the hash table
|
||||||
// a putvnode/removevnode here
|
|
||||||
|
|
||||||
/* remove the mount structure from the hash table */
|
|
||||||
mutex_lock(&sMountMutex);
|
mutex_lock(&sMountMutex);
|
||||||
hash_remove(sMountsTable, mount);
|
hash_remove(sMountsTable, mount);
|
||||||
mutex_unlock(&sMountMutex);
|
mutex_unlock(&sMountMutex);
|
||||||
@@ -4405,12 +4405,12 @@ _kern_mount(const char *path, const char *device, const char *fs_name,
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
_kern_unmount(const char *path)
|
_kern_unmount(const char *path, uint32 flags)
|
||||||
{
|
{
|
||||||
char pathBuffer[B_PATH_NAME_LENGTH + 1];
|
char pathBuffer[B_PATH_NAME_LENGTH + 1];
|
||||||
strlcpy(pathBuffer, path, B_PATH_NAME_LENGTH);
|
strlcpy(pathBuffer, path, B_PATH_NAME_LENGTH);
|
||||||
|
|
||||||
return fs_unmount(pathBuffer, true);
|
return fs_unmount(pathBuffer, flags, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -5080,7 +5080,7 @@ _user_mount(const char *userPath, const char *userDevice, const char *userFileSy
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
_user_unmount(const char *userPath)
|
_user_unmount(const char *userPath, uint32 flags)
|
||||||
{
|
{
|
||||||
char path[B_PATH_NAME_LENGTH + 1];
|
char path[B_PATH_NAME_LENGTH + 1];
|
||||||
int status;
|
int status;
|
||||||
@@ -5089,7 +5089,7 @@ _user_unmount(const char *userPath)
|
|||||||
if (status < 0)
|
if (status < 0)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
return fs_unmount(path, false);
|
return fs_unmount(path, flags, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user