Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/vfs_mount.c
Show First 20 Lines • Show All 941 Lines • ▼ Show 20 Lines | if (error == 0) { | ||||
else | else | ||||
error = EBUSY; | error = EBUSY; | ||||
VI_UNLOCK(vp); | VI_UNLOCK(vp); | ||||
} | } | ||||
if (error != 0) { | if (error != 0) { | ||||
vput(vp); | vput(vp); | ||||
return (error); | return (error); | ||||
} | } | ||||
vn_seqc_write_begin(vp); | |||||
VOP_UNLOCK(vp); | VOP_UNLOCK(vp); | ||||
/* Allocate and initialize the filesystem. */ | /* Allocate and initialize the filesystem. */ | ||||
mp = vfs_mount_alloc(vp, vfsp, fspath, td->td_ucred); | mp = vfs_mount_alloc(vp, vfsp, fspath, td->td_ucred); | ||||
/* XXXMAC: pass to vfs_mount_alloc? */ | /* XXXMAC: pass to vfs_mount_alloc? */ | ||||
mp->mnt_optnew = *optlist; | mp->mnt_optnew = *optlist; | ||||
/* Set the mount level flags. */ | /* Set the mount level flags. */ | ||||
mp->mnt_flag = (fsflags & (MNT_UPDATEMASK | MNT_ROOTFS | MNT_RDONLY)); | mp->mnt_flag = (fsflags & (MNT_UPDATEMASK | MNT_ROOTFS | MNT_RDONLY)); | ||||
Show All 16 Lines | if (error1 != 0) { | ||||
printf("VFS_UNMOUNT returned %d\n", error1); | printf("VFS_UNMOUNT returned %d\n", error1); | ||||
} | } | ||||
vfs_unbusy(mp); | vfs_unbusy(mp); | ||||
mp->mnt_vnodecovered = NULL; | mp->mnt_vnodecovered = NULL; | ||||
vfs_mount_destroy(mp); | vfs_mount_destroy(mp); | ||||
VI_LOCK(vp); | VI_LOCK(vp); | ||||
vp->v_iflag &= ~VI_MOUNT; | vp->v_iflag &= ~VI_MOUNT; | ||||
VI_UNLOCK(vp); | VI_UNLOCK(vp); | ||||
vn_seqc_write_end(vp); | |||||
vrele(vp); | vrele(vp); | ||||
return (error); | return (error); | ||||
} | } | ||||
vn_seqc_write_begin(newdp); | |||||
VOP_UNLOCK(newdp); | VOP_UNLOCK(newdp); | ||||
if (mp->mnt_opt != NULL) | if (mp->mnt_opt != NULL) | ||||
vfs_freeopts(mp->mnt_opt); | vfs_freeopts(mp->mnt_opt); | ||||
mp->mnt_opt = mp->mnt_optnew; | mp->mnt_opt = mp->mnt_optnew; | ||||
*optlist = NULL; | *optlist = NULL; | ||||
/* | /* | ||||
Show All 20 Lines | vfs_domount_first( | ||||
TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); | TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); | ||||
mtx_unlock(&mountlist_mtx); | mtx_unlock(&mountlist_mtx); | ||||
vfs_event_signal(NULL, VQ_MOUNT, 0); | vfs_event_signal(NULL, VQ_MOUNT, 0); | ||||
vn_lock(newdp, LK_EXCLUSIVE | LK_RETRY); | vn_lock(newdp, LK_EXCLUSIVE | LK_RETRY); | ||||
VOP_UNLOCK(vp); | VOP_UNLOCK(vp); | ||||
EVENTHANDLER_DIRECT_INVOKE(vfs_mounted, mp, newdp, td); | EVENTHANDLER_DIRECT_INVOKE(vfs_mounted, mp, newdp, td); | ||||
VOP_UNLOCK(newdp); | VOP_UNLOCK(newdp); | ||||
mountcheckdirs(vp, newdp); | mountcheckdirs(vp, newdp); | ||||
vn_seqc_write_end(vp); | |||||
vn_seqc_write_end(newdp); | |||||
vrele(newdp); | vrele(newdp); | ||||
if ((mp->mnt_flag & MNT_RDONLY) == 0) | if ((mp->mnt_flag & MNT_RDONLY) == 0) | ||||
vfs_allocate_syncvnode(mp); | vfs_allocate_syncvnode(mp); | ||||
vfs_op_exit(mp); | vfs_op_exit(mp); | ||||
vfs_unbusy(mp); | vfs_unbusy(mp); | ||||
return (0); | return (0); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | if ((vp->v_iflag & VI_MOUNT) != 0 || vp->v_mountedhere != NULL) { | ||||
vput(vp); | vput(vp); | ||||
return (EBUSY); | return (EBUSY); | ||||
} | } | ||||
vp->v_iflag |= VI_MOUNT; | vp->v_iflag |= VI_MOUNT; | ||||
VI_UNLOCK(vp); | VI_UNLOCK(vp); | ||||
VOP_UNLOCK(vp); | VOP_UNLOCK(vp); | ||||
vfs_op_enter(mp); | vfs_op_enter(mp); | ||||
vn_seqc_write_begin(vp); | |||||
rootvp = NULL; | |||||
MNT_ILOCK(mp); | MNT_ILOCK(mp); | ||||
if ((mp->mnt_kern_flag & MNTK_UNMOUNT) != 0) { | if ((mp->mnt_kern_flag & MNTK_UNMOUNT) != 0) { | ||||
MNT_IUNLOCK(mp); | MNT_IUNLOCK(mp); | ||||
error = EBUSY; | error = EBUSY; | ||||
goto end; | goto end; | ||||
} | } | ||||
mp->mnt_flag &= ~MNT_UPDATEMASK; | mp->mnt_flag &= ~MNT_UPDATEMASK; | ||||
mp->mnt_flag |= fsflags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE | | mp->mnt_flag |= fsflags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE | | ||||
MNT_SNAPSHOT | MNT_ROOTFS | MNT_UPDATEMASK | MNT_RDONLY); | MNT_SNAPSHOT | MNT_ROOTFS | MNT_UPDATEMASK | MNT_RDONLY); | ||||
if ((mp->mnt_flag & MNT_ASYNC) == 0) | if ((mp->mnt_flag & MNT_ASYNC) == 0) | ||||
mp->mnt_kern_flag &= ~MNTK_ASYNC; | mp->mnt_kern_flag &= ~MNTK_ASYNC; | ||||
rootvp = vfs_cache_root_clear(mp); | rootvp = vfs_cache_root_clear(mp); | ||||
MNT_IUNLOCK(mp); | MNT_IUNLOCK(mp); | ||||
if (rootvp != NULL) | |||||
vrele(rootvp); | |||||
mp->mnt_optnew = *optlist; | mp->mnt_optnew = *optlist; | ||||
vfs_mergeopts(mp->mnt_optnew, mp->mnt_opt); | vfs_mergeopts(mp->mnt_optnew, mp->mnt_opt); | ||||
/* | /* | ||||
* Mount the filesystem. | * Mount the filesystem. | ||||
* XXX The final recipients of VFS_MOUNT just overwrite the ndp they | * XXX The final recipients of VFS_MOUNT just overwrite the ndp they | ||||
* get. No freeing of cn_pnbuf. | * get. No freeing of cn_pnbuf. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 107 Lines • ▼ Show 20 Lines | vfs_domount_update( | ||||
mp->mnt_optnew = NULL; | mp->mnt_optnew = NULL; | ||||
if ((mp->mnt_flag & MNT_RDONLY) == 0) | if ((mp->mnt_flag & MNT_RDONLY) == 0) | ||||
vfs_allocate_syncvnode(mp); | vfs_allocate_syncvnode(mp); | ||||
else | else | ||||
vfs_deallocate_syncvnode(mp); | vfs_deallocate_syncvnode(mp); | ||||
end: | end: | ||||
vfs_op_exit(mp); | vfs_op_exit(mp); | ||||
if (rootvp != NULL) { | |||||
vn_seqc_write_end(rootvp); | |||||
vrele(rootvp); | |||||
} | |||||
vn_seqc_write_end(vp); | |||||
vfs_unbusy(mp); | vfs_unbusy(mp); | ||||
VI_LOCK(vp); | VI_LOCK(vp); | ||||
vp->v_iflag &= ~VI_MOUNT; | vp->v_iflag &= ~VI_MOUNT; | ||||
VI_UNLOCK(vp); | VI_UNLOCK(vp); | ||||
vrele(vp); | vrele(vp); | ||||
return (error != 0 ? error : export_error); | return (error != 0 ? error : export_error); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 474 Lines • ▼ Show 20 Lines | dounmount(struct mount *mp, int flags, struct thread *td) | ||||
if ((mp->mnt_kern_flag & MNTK_UNMOUNT) != 0 || | if ((mp->mnt_kern_flag & MNTK_UNMOUNT) != 0 || | ||||
(mp->mnt_flag & MNT_UPDATE) != 0 || | (mp->mnt_flag & MNT_UPDATE) != 0 || | ||||
!TAILQ_EMPTY(&mp->mnt_uppers)) { | !TAILQ_EMPTY(&mp->mnt_uppers)) { | ||||
dounmount_cleanup(mp, coveredvp, 0); | dounmount_cleanup(mp, coveredvp, 0); | ||||
return (EBUSY); | return (EBUSY); | ||||
} | } | ||||
mp->mnt_kern_flag |= MNTK_UNMOUNT; | mp->mnt_kern_flag |= MNTK_UNMOUNT; | ||||
rootvp = vfs_cache_root_clear(mp); | rootvp = vfs_cache_root_clear(mp); | ||||
if (coveredvp != NULL) | |||||
vn_seqc_write_begin(coveredvp); | |||||
if (flags & MNT_NONBUSY) { | if (flags & MNT_NONBUSY) { | ||||
MNT_IUNLOCK(mp); | MNT_IUNLOCK(mp); | ||||
error = vfs_check_usecounts(mp); | error = vfs_check_usecounts(mp); | ||||
MNT_ILOCK(mp); | MNT_ILOCK(mp); | ||||
if (error != 0) { | if (error != 0) { | ||||
vn_seqc_write_end(coveredvp); | |||||
dounmount_cleanup(mp, coveredvp, MNTK_UNMOUNT); | dounmount_cleanup(mp, coveredvp, MNTK_UNMOUNT); | ||||
if (rootvp != NULL) | if (rootvp != NULL) { | ||||
vn_seqc_write_end(rootvp); | |||||
vrele(rootvp); | vrele(rootvp); | ||||
} | |||||
return (error); | return (error); | ||||
} | } | ||||
} | } | ||||
/* Allow filesystems to detect that a forced unmount is in progress. */ | /* Allow filesystems to detect that a forced unmount is in progress. */ | ||||
if (flags & MNT_FORCE) { | if (flags & MNT_FORCE) { | ||||
mp->mnt_kern_flag |= MNTK_UNMOUNTF; | mp->mnt_kern_flag |= MNTK_UNMOUNTF; | ||||
MNT_IUNLOCK(mp); | MNT_IUNLOCK(mp); | ||||
/* | /* | ||||
Show All 12 Lines | dounmount(struct mount *mp, int flags, struct thread *td) | ||||
MNT_IUNLOCK(mp); | MNT_IUNLOCK(mp); | ||||
KASSERT(mp->mnt_lockref == 0, | KASSERT(mp->mnt_lockref == 0, | ||||
("%s: invalid lock refcount in the drain path @ %s:%d", | ("%s: invalid lock refcount in the drain path @ %s:%d", | ||||
__func__, __FILE__, __LINE__)); | __func__, __FILE__, __LINE__)); | ||||
KASSERT(error == 0, | KASSERT(error == 0, | ||||
("%s: invalid return value for msleep in the drain path @ %s:%d", | ("%s: invalid return value for msleep in the drain path @ %s:%d", | ||||
__func__, __FILE__, __LINE__)); | __func__, __FILE__, __LINE__)); | ||||
if (rootvp != NULL) | /* | ||||
* We want to keep the vnode around so that we can vn_seqc_write_end | |||||
* after we are done with unmount. Downgrade our reference to a mere | |||||
* hold count so that we don't interefere with anything. | |||||
*/ | |||||
if (rootvp != NULL) { | |||||
vhold(rootvp); | |||||
vrele(rootvp); | vrele(rootvp); | ||||
} | |||||
if (mp->mnt_flag & MNT_EXPUBLIC) | if (mp->mnt_flag & MNT_EXPUBLIC) | ||||
vfs_setpublicfs(NULL, NULL, NULL); | vfs_setpublicfs(NULL, NULL, NULL); | ||||
/* | |||||
* From now, we can claim that the use reference on the | |||||
* coveredvp is ours, and the ref can be released only by | |||||
* successfull unmount by us, or left for later unmount | |||||
* attempt. The previously acquired hold reference is no | |||||
* longer needed to protect the vnode from reuse. | |||||
*/ | |||||
if (coveredvp != NULL) | |||||
vdrop(coveredvp); | |||||
vfs_periodic(mp, MNT_WAIT); | vfs_periodic(mp, MNT_WAIT); | ||||
MNT_ILOCK(mp); | MNT_ILOCK(mp); | ||||
async_flag = mp->mnt_flag & MNT_ASYNC; | async_flag = mp->mnt_flag & MNT_ASYNC; | ||||
mp->mnt_flag &= ~MNT_ASYNC; | mp->mnt_flag &= ~MNT_ASYNC; | ||||
mp->mnt_kern_flag &= ~MNTK_ASYNC; | mp->mnt_kern_flag &= ~MNTK_ASYNC; | ||||
MNT_IUNLOCK(mp); | MNT_IUNLOCK(mp); | ||||
cache_purgevfs(mp, false); /* remove cache entries for this file sys */ | cache_purgevfs(mp, false); /* remove cache entries for this file sys */ | ||||
vfs_deallocate_syncvnode(mp); | vfs_deallocate_syncvnode(mp); | ||||
Show All 18 Lines | if ((mp->mnt_flag & MNT_ASYNC) != 0 && | ||||
(mp->mnt_kern_flag & MNTK_NOASYNC) == 0) | (mp->mnt_kern_flag & MNTK_NOASYNC) == 0) | ||||
mp->mnt_kern_flag |= MNTK_ASYNC; | mp->mnt_kern_flag |= MNTK_ASYNC; | ||||
if (mp->mnt_kern_flag & MNTK_MWAIT) { | if (mp->mnt_kern_flag & MNTK_MWAIT) { | ||||
mp->mnt_kern_flag &= ~MNTK_MWAIT; | mp->mnt_kern_flag &= ~MNTK_MWAIT; | ||||
wakeup(mp); | wakeup(mp); | ||||
} | } | ||||
vfs_op_exit_locked(mp); | vfs_op_exit_locked(mp); | ||||
MNT_IUNLOCK(mp); | MNT_IUNLOCK(mp); | ||||
if (coveredvp) | if (coveredvp) { | ||||
vn_seqc_write_end(coveredvp); | |||||
VOP_UNLOCK(coveredvp); | VOP_UNLOCK(coveredvp); | ||||
vdrop(coveredvp); | |||||
} | |||||
if (rootvp != NULL) { | |||||
vn_seqc_write_end(rootvp); | |||||
vdrop(rootvp); | |||||
} | |||||
return (error); | return (error); | ||||
} | } | ||||
mtx_lock(&mountlist_mtx); | mtx_lock(&mountlist_mtx); | ||||
TAILQ_REMOVE(&mountlist, mp, mnt_list); | TAILQ_REMOVE(&mountlist, mp, mnt_list); | ||||
mtx_unlock(&mountlist_mtx); | mtx_unlock(&mountlist_mtx); | ||||
EVENTHANDLER_DIRECT_INVOKE(vfs_unmounted, mp, td); | EVENTHANDLER_DIRECT_INVOKE(vfs_unmounted, mp, td); | ||||
if (coveredvp != NULL) { | if (coveredvp != NULL) { | ||||
coveredvp->v_mountedhere = NULL; | coveredvp->v_mountedhere = NULL; | ||||
vn_seqc_write_end(coveredvp); | |||||
VOP_UNLOCK(coveredvp); | VOP_UNLOCK(coveredvp); | ||||
vdrop(coveredvp); | |||||
} | |||||
if (rootvp != NULL) { | |||||
vn_seqc_write_end(rootvp); | |||||
vdrop(rootvp); | |||||
} | } | ||||
vfs_event_signal(NULL, VQ_UNMOUNT, 0); | vfs_event_signal(NULL, VQ_UNMOUNT, 0); | ||||
if (rootvnode != NULL && mp == rootvnode->v_mount) { | if (rootvnode != NULL && mp == rootvnode->v_mount) { | ||||
vrele(rootvnode); | vrele(rootvnode); | ||||
rootvnode = NULL; | rootvnode = NULL; | ||||
} | } | ||||
if (mp == rootdevmp) | if (mp == rootdevmp) | ||||
rootdevmp = NULL; | rootdevmp = NULL; | ||||
▲ Show 20 Lines • Show All 569 Lines • Show Last 20 Lines |