diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index 08bdda339a9..a59e122cd07 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -674,7 +674,7 @@ foffset_lock(struct file *fp, int flags) { volatile short *flagsp; off_t res; - short state; + short state, vflag; KASSERT((flags & FOF_OFFSET) == 0, ("FOF_OFFSET passed")); @@ -692,7 +692,9 @@ foffset_lock(struct file *fp, int flags) * It is now protected by the FOFFSET_LOCKED flag. */ flagsp = &fp->f_vnread_flags; - if (atomic_cmpset_acq_short(flagsp, 0, FOFFSET_LOCKED)) + vflag = *flagsp & FDEVFS_VNODE; + if (atomic_cmpset_acq_short(flagsp, vflag, + FOFFSET_LOCKED | vflag)) return (fp->f_offset); sleepq_lock(&fp->f_vnread_flags); @@ -700,13 +702,13 @@ foffset_lock(struct file *fp, int flags) for (;;) { if ((state & FOFFSET_LOCKED) == 0) { if (!atomic_fcmpset_acq_short(flagsp, &state, - FOFFSET_LOCKED)) + FOFFSET_LOCKED | vflag)) continue; break; } if ((state & FOFFSET_LOCK_WAITING) == 0) { if (!atomic_fcmpset_acq_short(flagsp, &state, - state | FOFFSET_LOCK_WAITING)) + state | FOFFSET_LOCK_WAITING | vflag)) continue; } DROP_GIANT(); @@ -724,7 +726,7 @@ void foffset_unlock(struct file *fp, off_t val, int flags) { volatile short *flagsp; - short state; + short state, vflag; KASSERT((flags & FOF_OFFSET) == 0, ("FOF_OFFSET passed")); @@ -733,19 +735,23 @@ foffset_unlock(struct file *fp, off_t val, int flags) if ((flags & FOF_NEXTOFF) != 0) fp->f_nextoff = val; +#if OFF_MAX <= LONG_MAX + /* foffset_lock will still take the lock if OFF_MAX > LONG_MAX */ if ((flags & FOF_NOLOCK) != 0) return; +#endif flagsp = &fp->f_vnread_flags; state = *flagsp; + vflag = state & FDEVFS_VNODE; if ((state & FOFFSET_LOCK_WAITING) == 0 && - atomic_cmpset_rel_short(flagsp, state, 0)) + atomic_cmpset_rel_short(flagsp, state, vflag)) return; sleepq_lock(&fp->f_vnread_flags); MPASS((fp->f_vnread_flags & FOFFSET_LOCKED) != 0); MPASS((fp->f_vnread_flags & FOFFSET_LOCK_WAITING) != 0); - fp->f_vnread_flags = 0; + fp->f_vnread_flags = vflag; sleepq_broadcast(&fp->f_vnread_flags, SLEEPQ_SLEEP, 0, 0); sleepq_release(&fp->f_vnread_flags); }