summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorps <ps@FreeBSD.org>2006-05-16 07:50:54 +0000
committerps <ps@FreeBSD.org>2006-05-16 07:50:54 +0000
commit83af4cc4336ad4d5435cc793284c93d7f3a3d3df (patch)
tree28e4946bfc0384c068e61749662f568f6e1b6385
parentf568b4c78d29cd24a82f765e0dc6598d565dfa20 (diff)
downloadFreeBSD-src-83af4cc4336ad4d5435cc793284c93d7f3a3d3df.zip
FreeBSD-src-83af4cc4336ad4d5435cc793284c93d7f3a3d3df.tar.gz
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
-rw-r--r--sys/kern/vfs_vnops.c21
-rw-r--r--sys/sys/file.h8
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() */
OpenPOWER on IntegriCloud