Allow concurrent read(2)/readv(2) access to a file.

Lock file offset against multiple read calls.

Submitted by:	ups
Obtained from:	Yahoo!
MFC after:	2 weeks
This commit is contained in:
Paul Saab 2006-05-16 07:50:54 +00:00
parent e0cf717542
commit 6befa6ae1b
2 changed files with 24 additions and 5 deletions

View File

@ -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);

View File

@ -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() */