Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/vfs_vnops.c
Show First 20 Lines • Show All 1,662 Lines • ▼ Show 20 Lines | vn_start_write_refed(struct mount *mp, int flags, bool mplocked) | ||||
mp->mnt_writeopcount++; | mp->mnt_writeopcount++; | ||||
unlock: | unlock: | ||||
if (error != 0 || (flags & V_XSLEEP) != 0) | if (error != 0 || (flags & V_XSLEEP) != 0) | ||||
MNT_REL(mp); | MNT_REL(mp); | ||||
MNT_IUNLOCK(mp); | MNT_IUNLOCK(mp); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | |||||
* The routine guarantees to not take any locks. Howerver, since it performs | |||||
kib: However | |||||
* two separate operations internally it may still fail and require cleanup | |||||
* (if the second op fails, it is possible that reverting the first one would | |||||
* require locks). | |||||
* Callers are expected to handle it as follows: | |||||
* error == 0 indicates success and requires a matching vn_finished_write. | |||||
* error !=0 && *mpp != NULL require matching vfs_rel. | |||||
kibUnsubmitted Not Done Inline Actions!= 0 there and line below. kib: != 0 there and line below. | |||||
* error !=0 && *mpp == NULL have nothing to clean up. | |||||
*/ | |||||
static int | |||||
vn_start_write_nb(struct vnode *vp, struct mount **mpp) | |||||
{ | |||||
struct mount *mp; | |||||
int error; | |||||
if ((error = VOP_GETWRITEMOUNT(vp, mpp, V_NONBLOCKING)) != 0) | |||||
*mpp = NULL; | |||||
if ((mp = *mpp) == NULL) | |||||
return (error); | |||||
if (!vn_suspendable(mp)) | |||||
return (0); | |||||
if (vfs_op_thread_enter(mp)) { | |||||
MPASS((mp->mnt_kern_flag & MNTK_SUSPEND) == 0); | |||||
vfs_mp_count_add_pcpu(mp, writeopcount, 1); | |||||
vfs_op_thread_exit(mp); | |||||
return (0); | |||||
} | |||||
return (EAGAIN); | |||||
} | |||||
int | int | ||||
vn_start_write(struct vnode *vp, struct mount **mpp, int flags) | vn_start_write(struct vnode *vp, struct mount **mpp, int flags) | ||||
{ | { | ||||
struct mount *mp; | struct mount *mp; | ||||
int error; | int error; | ||||
KASSERT((flags & V_MNTREF) == 0 || (*mpp != NULL && vp == NULL), | KASSERT((flags & V_MNTREF) == 0 || (*mpp != NULL && vp == NULL), | ||||
("V_MNTREF requires mp")); | ("V_MNTREF requires mp")); | ||||
error = 0; | if (__predict_false((flags & V_NONBLOCKING) != 0)) { | ||||
KASSERT(((flags & ~V_NONBLOCKING) == 0), | |||||
("incompatible or unhandled flags passed")); | |||||
return (vn_start_write_nb(vp, mpp)); | |||||
} | |||||
/* | /* | ||||
* If a vnode is provided, get and return the mount point that | * If a vnode is provided, get and return the mount point that | ||||
* to which it will write. | * to which it will write. | ||||
*/ | */ | ||||
if (vp != NULL) { | if (vp != NULL) { | ||||
if ((error = VOP_GETWRITEMOUNT(vp, mpp)) != 0) { | if ((error = VOP_GETWRITEMOUNT(vp, mpp, 0)) != 0) { | ||||
*mpp = NULL; | *mpp = NULL; | ||||
if (error != EOPNOTSUPP) | if (error != EOPNOTSUPP) | ||||
return (error); | return (error); | ||||
return (0); | return (0); | ||||
} | } | ||||
} | } | ||||
if ((mp = *mpp) == NULL) | if ((mp = *mpp) == NULL) | ||||
return (0); | return (0); | ||||
if (!vn_suspendable(mp)) { | |||||
if (vp != NULL || (flags & V_MNTREF) != 0) | |||||
vfs_rel(mp); | |||||
return (0); | |||||
} | |||||
/* | /* | ||||
* VOP_GETWRITEMOUNT() returns with the mp refcount held through | * VOP_GETWRITEMOUNT() returns with the mp refcount held through | ||||
* a vfs_ref(). | * a vfs_ref(). | ||||
* As long as a vnode is not provided we need to acquire a | * As long as a vnode is not provided we need to acquire a | ||||
* refcount for the provided mountpoint too, in order to | * refcount for the provided mountpoint too, in order to | ||||
* emulate a vfs_ref(). | * emulate a vfs_ref(). | ||||
*/ | */ | ||||
if (vp == NULL && (flags & V_MNTREF) == 0) | if (vp == NULL && (flags & V_MNTREF) == 0) | ||||
vfs_ref(mp); | vfs_ref(mp); | ||||
if (!vn_suspendable(mp)) | |||||
return (0); | |||||
return (vn_start_write_refed(mp, flags, false)); | return (vn_start_write_refed(mp, flags, false)); | ||||
} | } | ||||
/* | /* | ||||
* Secondary suspension. Used by operations such as vop_inactive | * Secondary suspension. Used by operations such as vop_inactive | ||||
* routines that are needed by the higher level functions. These | * routines that are needed by the higher level functions. These | ||||
* are allowed to proceed until all the higher level functions have | * are allowed to proceed until all the higher level functions have | ||||
* completed (indicated by mnt_writeopcount dropping to zero). At that | * completed (indicated by mnt_writeopcount dropping to zero). At that | ||||
* time, these operations are halted until the suspension is over. | * time, these operations are halted until the suspension is over. | ||||
*/ | */ | ||||
int | int | ||||
vn_start_secondary_write(struct vnode *vp, struct mount **mpp, int flags) | vn_start_secondary_write(struct vnode *vp, struct mount **mpp, int flags) | ||||
{ | { | ||||
struct mount *mp; | struct mount *mp; | ||||
int error; | int error; | ||||
KASSERT((flags & V_MNTREF) == 0 || (*mpp != NULL && vp == NULL), | KASSERT((flags & V_MNTREF) == 0 || (*mpp != NULL && vp == NULL), | ||||
("V_MNTREF requires mp")); | ("V_MNTREF requires mp")); | ||||
retry: | retry: | ||||
if (vp != NULL) { | if (vp != NULL) { | ||||
if ((error = VOP_GETWRITEMOUNT(vp, mpp)) != 0) { | if ((error = VOP_GETWRITEMOUNT(vp, mpp, 0)) != 0) { | ||||
*mpp = NULL; | *mpp = NULL; | ||||
if (error != EOPNOTSUPP) | if (error != EOPNOTSUPP) | ||||
return (error); | return (error); | ||||
return (0); | return (0); | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* If we are not suspended or have not yet reached suspended | * If we are not suspended or have not yet reached suspended | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | |||||
* operation is the last one, notify the suspender that the suspension is | * operation is the last one, notify the suspender that the suspension is | ||||
* now in effect. | * now in effect. | ||||
*/ | */ | ||||
void | void | ||||
vn_finished_write(struct mount *mp) | vn_finished_write(struct mount *mp) | ||||
{ | { | ||||
int c; | int c; | ||||
if (mp == NULL || !vn_suspendable(mp)) | if (mp == NULL) | ||||
return; | return; | ||||
if (!vn_suspendable(mp)) { | |||||
vfs_rel(mp); | |||||
return; | |||||
} | |||||
if (vfs_op_thread_enter(mp)) { | if (vfs_op_thread_enter(mp)) { | ||||
vfs_mp_count_sub_pcpu(mp, writeopcount, 1); | vfs_mp_count_sub_pcpu(mp, writeopcount, 1); | ||||
vfs_mp_count_sub_pcpu(mp, ref, 1); | vfs_mp_count_sub_pcpu(mp, ref, 1); | ||||
vfs_op_thread_exit(mp); | vfs_op_thread_exit(mp); | ||||
return; | return; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 1,323 Lines • Show Last 20 Lines |
However