Author: mjg
Date: Mon May 25 04:56:41 2020
New Revision: 361440
URL: https://svnweb.freebsd.org/changeset/base/361440

Log:
  vfs: restore mtx-protected foffset locking for 32 bit platforms
  
  They depend on it to accurately read the offset.
  
  The new code is not used as it would add an interrupt enable/disable
  trip on top of the atomic.
  
  This also fixes a bug where 32-bit nolock request would still lock the offset.
  
  No changes for 64-bit.
  
  Reported by:  emaste

Modified:
  head/sys/kern/vfs_vnops.c

Modified: head/sys/kern/vfs_vnops.c
==============================================================================
--- head/sys/kern/vfs_vnops.c   Mon May 25 04:17:01 2020        (r361439)
+++ head/sys/kern/vfs_vnops.c   Mon May 25 04:56:41 2020        (r361440)
@@ -672,6 +672,7 @@ vn_rdwr_inchunks(enum uio_rw rw, struct vnode *vp, voi
        return (error);
 }
 
+#if OFF_MAX <= LONG_MAX
 off_t
 foffset_lock(struct file *fp, int flags)
 {
@@ -681,14 +682,12 @@ foffset_lock(struct file *fp, int flags)
 
        KASSERT((flags & FOF_OFFSET) == 0, ("FOF_OFFSET passed"));
 
-#if OFF_MAX <= LONG_MAX
        /*
         * Caller only wants the current f_offset value.  Assume that
         * the long and shorter integer types reads are atomic.
         */
        if ((flags & FOF_NOLOCK) != 0)
                return (fp->f_offset);
-#endif
 
        /*
         * According to McKusick the vn lock was protecting f_offset here.
@@ -737,10 +736,8 @@ foffset_unlock(struct file *fp, off_t val, int flags)
        if ((flags & FOF_NEXTOFF) != 0)
                fp->f_nextoff = val;
 
-#if OFF_MAX <= LONG_MAX
        if ((flags & FOF_NOLOCK) != 0)
                return;
-#endif
 
        flagsp = &fp->f_vnread_flags;
        state = atomic_load_16(flagsp);
@@ -755,6 +752,53 @@ foffset_unlock(struct file *fp, off_t val, int flags)
        sleepq_broadcast(&fp->f_vnread_flags, SLEEPQ_SLEEP, 0, 0);
        sleepq_release(&fp->f_vnread_flags);
 }
+#else
+off_t
+foffset_lock(struct file *fp, int flags)
+{
+       struct mtx *mtxp;
+       off_t res;
+
+       KASSERT((flags & FOF_OFFSET) == 0, ("FOF_OFFSET passed"));
+
+       mtxp = mtx_pool_find(mtxpool_sleep, fp);
+       mtx_lock(mtxp);
+       if ((flags & FOF_NOLOCK) == 0) {
+               while (fp->f_vnread_flags & FOFFSET_LOCKED) {
+                       fp->f_vnread_flags |= FOFFSET_LOCK_WAITING;
+                       msleep(&fp->f_vnread_flags, mtxp, PUSER -1,
+                           "vofflock", 0);
+               }
+               fp->f_vnread_flags |= FOFFSET_LOCKED;
+       }
+       res = fp->f_offset;
+       mtx_unlock(mtxp);
+       return (res);
+}
+
+void
+foffset_unlock(struct file *fp, off_t val, int flags)
+{
+       struct mtx *mtxp;
+
+       KASSERT((flags & FOF_OFFSET) == 0, ("FOF_OFFSET passed"));
+
+       mtxp = mtx_pool_find(mtxpool_sleep, fp);
+       mtx_lock(mtxp);
+       if ((flags & FOF_NOUPDATE) == 0)
+               fp->f_offset = val;
+       if ((flags & FOF_NEXTOFF) != 0)
+               fp->f_nextoff = val;
+       if ((flags & FOF_NOLOCK) == 0) {
+               KASSERT((fp->f_vnread_flags & FOFFSET_LOCKED) != 0,
+                   ("Lost FOFFSET_LOCKED"));
+               if (fp->f_vnread_flags & FOFFSET_LOCK_WAITING)
+                       wakeup(&fp->f_vnread_flags);
+               fp->f_vnread_flags = 0;
+       }
+       mtx_unlock(mtxp);
+}
+#endif
 
 void
 foffset_lock_uio(struct file *fp, struct uio *uio, int flags)
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to