diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/kern/vfs_vnops.c | 21 | ||||
-rw-r--r-- | sys/sys/file.h | 8 |
2 files changed, 24 insertions, 5 deletions
diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index f05abbf..dabfdf0 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -495,11 +495,18 @@ vn_read(fp, uio, active_cred, flags, td) vfslocked = VFS_LOCK_GIANT(vp->v_mount); VOP_LEASE(vp, td, fp->f_cred, LEASE_READ); /* - * According to McKusick the vn lock is protecting f_offset here. - * Once this field has it's own lock we can acquire this shared. + * 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) { - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); + FILE_LOCK(fp); + while(fp->f_vnread_flags & FOFFSET_LOCKED) { + fp->f_vnread_flags |= FOFFSET_LOCK_WAITING; + msleep(&fp->f_vnread_flags,fp->f_mtxp,PUSER -1,"vnread offlock",0); + } + fp->f_vnread_flags |= FOFFSET_LOCKED; + FILE_UNLOCK(fp); + vn_lock(vp, LK_SHARED | LK_RETRY, td); uio->uio_offset = fp->f_offset; } else vn_lock(vp, LK_SHARED | LK_RETRY, td); @@ -511,8 +518,14 @@ vn_read(fp, uio, active_cred, flags, td) if (error == 0) #endif error = VOP_READ(vp, uio, ioflag, fp->f_cred); - if ((flags & FOF_OFFSET) == 0) + if ((flags & FOF_OFFSET) == 0) { fp->f_offset = uio->uio_offset; + FILE_LOCK(fp); + if (fp->f_vnread_flags & FOFFSET_LOCK_WAITING) + wakeup(&fp->f_vnread_flags); + fp->f_vnread_flags = 0; + FILE_UNLOCK(fp); + } fp->f_nextoff = uio->uio_offset; VOP_UNLOCK(vp, 0, td); VFS_UNLOCK_GIANT(vfslocked); diff --git a/sys/sys/file.h b/sys/sys/file.h index 2292d42..16b0e35 100644 --- a/sys/sys/file.h +++ b/sys/sys/file.h @@ -117,7 +117,13 @@ struct file { /* DFLAG_SEEKABLE specific fields */ off_t f_offset; - + short f_vnread_flags; /* + * (f) home grown sleep lock for f_offset + * Used only for shared vnode locking in + * vnread() + */ +#define FOFFSET_LOCKED 0x1 +#define FOFFSET_LOCK_WAITING 0x2 /* DTYPE_SOCKET specific fields */ short f_gcflag; /* used by thread doing fd garbage collection */ #define FMARK 0x1 /* mark during gc() */ |