[Midnightbsd-cvs] src [7929] trunk/sys/kern/vfs_vnops.c: Fix locking for f_offset, vn_read() and vn_write() cases only.
laffer1 at midnightbsd.org
laffer1 at midnightbsd.org
Wed Sep 14 17:06:39 EDT 2016
Revision: 7929
http://svnweb.midnightbsd.org/src/?rev=7929
Author: laffer1
Date: 2016-09-14 17:06:39 -0400 (Wed, 14 Sep 2016)
Log Message:
-----------
Fix locking for f_offset, vn_read() and vn_write() cases only.
Obtained from: FreeBSD
Modified Paths:
--------------
trunk/sys/kern/vfs_vnops.c
Modified: trunk/sys/kern/vfs_vnops.c
===================================================================
--- trunk/sys/kern/vfs_vnops.c 2016-09-14 21:04:28 UTC (rev 7928)
+++ trunk/sys/kern/vfs_vnops.c 2016-09-14 21:06:39 UTC (rev 7929)
@@ -512,6 +512,66 @@
return (error);
}
+static void
+foffset_lock(struct file *fp, struct uio *uio, int flags)
+{
+ struct mtx *mtxp;
+
+ if ((flags & FOF_OFFSET) != 0)
+ return;
+
+ /*
+ * According to McKusick the vn lock was protecting f_offset here.
+ * It is now protected by the FOFFSET_LOCKED flag.
+ */
+ mtxp = mtx_pool_find(mtxpool_sleep, fp);
+ mtx_lock(mtxp);
+ while (fp->f_vnread_flags & FOFFSET_LOCKED) {
+ fp->f_vnread_flags |= FOFFSET_LOCK_WAITING;
+ msleep(&fp->f_vnread_flags, mtxp, PUSER -1,
+ "vnread offlock", 0);
+ }
+ fp->f_vnread_flags |= FOFFSET_LOCKED;
+ uio->uio_offset = fp->f_offset;
+ mtx_unlock(mtxp);
+}
+
+static int
+get_advice(struct file *fp, struct uio *uio)
+{
+ struct mtx *mtxp;
+ int ret;
+
+ ret = POSIX_FADV_NORMAL;
+ if (fp->f_advice == NULL)
+ return (ret);
+
+ mtxp = mtx_pool_find(mtxpool_sleep, fp);
+ mtx_lock(mtxp);
+ if (uio->uio_offset >= fp->f_advice->fa_start &&
+ uio->uio_offset + uio->uio_resid <= fp->f_advice->fa_end)
+ ret = fp->f_advice->fa_advice;
+ mtx_unlock(mtxp);
+ return (ret);
+}
+
+static void
+foffset_unlock(struct file *fp, struct uio *uio, int flags)
+{
+ struct mtx *mtxp;
+
+ if ((flags & FOF_OFFSET) != 0)
+ return;
+
+ fp->f_offset = uio->uio_offset;
+ mtxp = mtx_pool_find(mtxpool_sleep, fp);
+ mtx_lock(mtxp);
+ if (fp->f_vnread_flags & FOFFSET_LOCK_WAITING)
+ wakeup(&fp->f_vnread_flags);
+ fp->f_vnread_flags = 0;
+ mtx_unlock(mtxp);
+}
+
/*
* File table vnode read routine.
*/
@@ -524,14 +584,14 @@
struct thread *td;
{
struct vnode *vp;
+ struct mtx *mtxp;
int error, ioflag;
- struct mtx *mtxp;
int advice, vfslocked;
off_t offset, start, end;
KASSERT(uio->uio_td == td, ("uio_td %p is not td %p",
uio->uio_td, td));
- mtxp = NULL;
+ KASSERT(flags & FOF_OFFSET, ("No FOF_OFFSET"));
vp = fp->f_vnode;
ioflag = 0;
if (fp->f_flag & FNONBLOCK)
@@ -538,30 +598,8 @@
ioflag |= IO_NDELAY;
if (fp->f_flag & O_DIRECT)
ioflag |= IO_DIRECT;
- advice = POSIX_FADV_NORMAL;
+ advice = get_advice(fp, uio);
vfslocked = VFS_LOCK_GIANT(vp->v_mount);
- /*
- * According to McKusick the vn lock was protecting f_offset here.
- * It is now protected by the FOFFSET_LOCKED flag.
- */
- if ((flags & FOF_OFFSET) == 0 || fp->f_advice != NULL) {
- mtxp = mtx_pool_find(mtxpool_sleep, fp);
- mtx_lock(mtxp);
- if ((flags & FOF_OFFSET) == 0) {
- while (fp->f_vnread_flags & FOFFSET_LOCKED) {
- fp->f_vnread_flags |= FOFFSET_LOCK_WAITING;
- msleep(&fp->f_vnread_flags, mtxp, PUSER -1,
- "vnread offlock", 0);
- }
- fp->f_vnread_flags |= FOFFSET_LOCKED;
- uio->uio_offset = fp->f_offset;
- }
- if (fp->f_advice != NULL &&
- uio->uio_offset >= fp->f_advice->fa_start &&
- uio->uio_offset + uio->uio_resid <= fp->f_advice->fa_end)
- advice = fp->f_advice->fa_advice;
- mtx_unlock(mtxp);
- }
vn_lock(vp, LK_SHARED | LK_RETRY);
switch (advice) {
@@ -581,14 +619,6 @@
if (error == 0)
#endif
error = VOP_READ(vp, uio, ioflag, fp->f_cred);
- if ((flags & FOF_OFFSET) == 0) {
- fp->f_offset = uio->uio_offset;
- mtx_lock(mtxp);
- if (fp->f_vnread_flags & FOFFSET_LOCK_WAITING)
- wakeup(&fp->f_vnread_flags);
- fp->f_vnread_flags = 0;
- mtx_unlock(mtxp);
- }
fp->f_nextoff = uio->uio_offset;
VOP_UNLOCK(vp, 0);
if (error == 0 && advice == POSIX_FADV_NOREUSE &&
@@ -610,6 +640,7 @@
*/
start = offset;
end = uio->uio_offset - 1;
+ mtxp = mtx_pool_find(mtxpool_sleep, fp);
mtx_lock(mtxp);
if (fp->f_advice != NULL &&
fp->f_advice->fa_advice == POSIX_FADV_NOREUSE) {
@@ -641,13 +672,14 @@
{
struct vnode *vp;
struct mount *mp;
+ struct mtx *mtxp;
int error, ioflag, lock_flags;
- struct mtx *mtxp;
int advice, vfslocked;
off_t offset, start, end;
KASSERT(uio->uio_td == td, ("uio_td %p is not td %p",
uio->uio_td, td));
+ KASSERT(flags & FOF_OFFSET, ("No FOF_OFFSET"));
vp = fp->f_vnode;
vfslocked = VFS_LOCK_GIANT(vp->v_mount);
if (vp->v_type == VREG)
@@ -666,6 +698,8 @@
if (vp->v_type != VCHR &&
(error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
goto unlock;
+
+ advice = get_advice(fp, uio);
if ((MNT_SHARED_WRITES(mp) ||
((mp == NULL) && MNT_SHARED_WRITES(vp->v_mount))) &&
@@ -676,19 +710,6 @@
}
vn_lock(vp, lock_flags | LK_RETRY);
- if ((flags & FOF_OFFSET) == 0)
- uio->uio_offset = fp->f_offset;
- advice = POSIX_FADV_NORMAL;
- mtxp = NULL;
- if (fp->f_advice != NULL) {
- mtxp = mtx_pool_find(mtxpool_sleep, fp);
- mtx_lock(mtxp);
- if (fp->f_advice != NULL &&
- uio->uio_offset >= fp->f_advice->fa_start &&
- uio->uio_offset + uio->uio_resid <= fp->f_advice->fa_end)
- advice = fp->f_advice->fa_advice;
- mtx_unlock(mtxp);
- }
switch (advice) {
case POSIX_FADV_NORMAL:
case POSIX_FADV_SEQUENTIAL:
@@ -706,8 +727,6 @@
if (error == 0)
#endif
error = VOP_WRITE(vp, uio, ioflag, fp->f_cred);
- if ((flags & FOF_OFFSET) == 0)
- fp->f_offset = uio->uio_offset;
fp->f_nextoff = uio->uio_offset;
VOP_UNLOCK(vp, 0);
if (vp->v_type != VCHR)
@@ -746,6 +765,7 @@
*/
start = offset;
end = uio->uio_offset - 1;
+ mtxp = mtx_pool_find(mtxpool_sleep, fp);
mtx_lock(mtxp);
if (fp->f_advice != NULL &&
fp->f_advice->fa_advice == POSIX_FADV_NOREUSE) {
@@ -830,11 +850,15 @@
else
doio = vn_write;
vp = fp->f_vnode;
+ foffset_lock(fp, uio, flags);
+
if (uio->uio_segflg != UIO_USERSPACE || vp->v_type != VREG ||
((mp = vp->v_mount) != NULL &&
(mp->mnt_kern_flag & MNTK_NO_IOPF) == 0) ||
- !vn_io_fault_enable)
- return (doio(fp, uio, active_cred, flags, td));
+ !vn_io_fault_enable) {
+ error = doio(fp, uio, active_cred, flags | FOF_OFFSET, td);
+ goto out_last;
+ }
/*
* The UFS follows IO_UNIT directive and replays back both
@@ -867,7 +891,7 @@
}
save = vm_fault_disable_pagefaults();
- error = doio(fp, uio, active_cred, flags, td);
+ error = doio(fp, uio, active_cred, flags | FOF_OFFSET, td);
if (error != EFAULT)
goto out;
@@ -918,7 +942,8 @@
td->td_ma = ma;
td->td_ma_cnt = cnt;
- error = doio(fp, &short_uio, active_cred, flags, td);
+ error = doio(fp, &short_uio, active_cred, flags | FOF_OFFSET,
+ td);
vm_page_unhold_pages(ma, cnt);
adv = len - short_uio.uio_resid;
@@ -941,6 +966,8 @@
vm_fault_enable_pagefaults(save);
vn_rangelock_unlock(vp, rl_cookie);
free(uio_clone, M_IOV);
+out_last:
+ foffset_unlock(fp, uio, flags);
return (error);
}
More information about the Midnightbsd-cvs
mailing list