[Midnightbsd-cvs] src [7930] trunk/sys: Extend the KPI to lock and unlock f_offset member of struct file.
laffer1 at midnightbsd.org
laffer1 at midnightbsd.org
Wed Sep 14 17:09:43 EDT 2016
Revision: 7930
http://svnweb.midnightbsd.org/src/?rev=7930
Author: laffer1
Date: 2016-09-14 17:09:43 -0400 (Wed, 14 Sep 2016)
Log Message:
-----------
Extend the KPI to lock and unlock f_offset member of struct file. It
now fully encapsulates all accesses to f_offset, and extends f_offset
locking to other consumers that need it, in particular, to lseek() and
variants of getdirentries().
Modified Paths:
--------------
trunk/sys/compat/linux/linux_file.c
trunk/sys/fs/devfs/devfs_vnops.c
trunk/sys/kern/kern_descrip.c
trunk/sys/kern/vfs_syscalls.c
trunk/sys/kern/vfs_vnops.c
trunk/sys/sys/file.h
trunk/sys/ufs/ffs/ffs_alloc.c
Modified: trunk/sys/compat/linux/linux_file.c
===================================================================
--- trunk/sys/compat/linux/linux_file.c 2016-09-14 21:06:39 UTC (rev 7929)
+++ trunk/sys/compat/linux/linux_file.c 2016-09-14 21:09:43 UTC (rev 7930)
@@ -356,15 +356,16 @@
return (EBADF);
}
+ off = foffset_lock(fp, 0);
vp = fp->f_vnode;
vfslocked = VFS_LOCK_GIANT(vp->v_mount);
if (vp->v_type != VDIR) {
VFS_UNLOCK_GIANT(vfslocked);
+ foffset_unlock(fp, off, 0);
fdrop(fp, td);
return (EINVAL);
}
- off = fp->f_offset;
buflen = max(LINUX_DIRBLKSIZ, nbytes);
buflen = min(buflen, MAXBSIZE);
@@ -513,7 +514,6 @@
goto eof;
}
- fp->f_offset = off;
if (justone)
nbytes = resid + linuxreclen;
@@ -526,6 +526,7 @@
VOP_UNLOCK(vp, 0);
VFS_UNLOCK_GIANT(vfslocked);
+ foffset_unlock(fp, off, 0);
fdrop(fp, td);
free(buf, M_TEMP);
free(lbuf, M_TEMP);
Modified: trunk/sys/fs/devfs/devfs_vnops.c
===================================================================
--- trunk/sys/fs/devfs/devfs_vnops.c 2016-09-14 21:06:39 UTC (rev 7929)
+++ trunk/sys/fs/devfs/devfs_vnops.c 2016-09-14 21:09:43 UTC (rev 7930)
@@ -1170,9 +1170,7 @@
if (ioflag & O_DIRECT)
ioflag |= IO_DIRECT;
- if ((flags & FOF_OFFSET) == 0)
- uio->uio_offset = fp->f_offset;
-
+ foffset_lock_uio(fp, uio, flags | FOF_NOLOCK);
error = dsw->d_read(dev, uio, ioflag);
if (uio->uio_resid != resid || (error == 0 && resid != 0))
vfs_timestamp(&dev->si_atime);
@@ -1179,9 +1177,7 @@
td->td_fpop = fpop;
dev_relthread(dev, ref);
- if ((flags & FOF_OFFSET) == 0)
- fp->f_offset = uio->uio_offset;
- fp->f_nextoff = uio->uio_offset;
+ foffset_unlock_uio(fp, uio, flags | FOF_NOLOCK | FOF_NEXTOFF);
return (error);
}
@@ -1648,8 +1644,7 @@
ioflag = fp->f_flag & (O_NONBLOCK | O_DIRECT | O_FSYNC);
if (ioflag & O_DIRECT)
ioflag |= IO_DIRECT;
- if ((flags & FOF_OFFSET) == 0)
- uio->uio_offset = fp->f_offset;
+ foffset_lock_uio(fp, uio, flags | FOF_NOLOCK);
resid = uio->uio_resid;
@@ -1661,9 +1656,7 @@
td->td_fpop = fpop;
dev_relthread(dev, ref);
- if ((flags & FOF_OFFSET) == 0)
- fp->f_offset = uio->uio_offset;
- fp->f_nextoff = uio->uio_offset;
+ foffset_unlock_uio(fp, uio, flags | FOF_NOLOCK | FOF_NEXTOFF);
return (error);
}
Modified: trunk/sys/kern/kern_descrip.c
===================================================================
--- trunk/sys/kern/kern_descrip.c 2016-09-14 21:06:39 UTC (rev 7929)
+++ trunk/sys/kern/kern_descrip.c 2016-09-14 21:09:43 UTC (rev 7930)
@@ -472,6 +472,7 @@
int vfslocked;
u_int old, new;
uint64_t bsize;
+ off_t foffset;
vfslocked = 0;
error = 0;
@@ -613,14 +614,15 @@
}
flp = (struct flock *)arg;
if (flp->l_whence == SEEK_CUR) {
- if (fp->f_offset < 0 ||
+ foffset = foffset_get(fp);
+ if (foffset < 0 ||
(flp->l_start > 0 &&
- fp->f_offset > OFF_MAX - flp->l_start)) {
+ foffset > OFF_MAX - flp->l_start)) {
FILEDESC_SUNLOCK(fdp);
error = EOVERFLOW;
break;
}
- flp->l_start += fp->f_offset;
+ flp->l_start += foffset;
}
/*
@@ -714,15 +716,16 @@
break;
}
if (flp->l_whence == SEEK_CUR) {
+ foffset = foffset_get(fp);
if ((flp->l_start > 0 &&
- fp->f_offset > OFF_MAX - flp->l_start) ||
+ foffset > OFF_MAX - flp->l_start) ||
(flp->l_start < 0 &&
- fp->f_offset < OFF_MIN - flp->l_start)) {
+ foffset < OFF_MIN - flp->l_start)) {
FILEDESC_SUNLOCK(fdp);
error = EOVERFLOW;
break;
}
- flp->l_start += fp->f_offset;
+ flp->l_start += foffset;
}
/*
* VOP_ADVLOCK() may block.
@@ -2907,7 +2910,7 @@
xf.xf_type = fp->f_type;
xf.xf_count = fp->f_count;
xf.xf_msgcount = 0;
- xf.xf_offset = fp->f_offset;
+ xf.xf_offset = foffset_get(fp);
xf.xf_flag = fp->f_flag;
error = SYSCTL_OUT(req, &xf, sizeof(xf));
if (error)
@@ -3112,7 +3115,7 @@
kif->kf_flags |= KF_FLAG_DIRECT;
if (fp->f_flag & FHASLOCK)
kif->kf_flags |= KF_FLAG_HASLOCK;
- kif->kf_offset = fp->f_offset;
+ kif->kf_offset = foffset_get(fp);
if (vp != NULL) {
vref(vp);
switch (vp->v_type) {
@@ -3456,7 +3459,7 @@
}
refcnt = fp->f_count;
fflags = fp->f_flag;
- offset = fp->f_offset;
+ offset = foffset_get(fp);
/*
* Create sysctl entry.
Modified: trunk/sys/kern/vfs_syscalls.c
===================================================================
--- trunk/sys/kern/vfs_syscalls.c 2016-09-14 21:06:39 UTC (rev 7929)
+++ trunk/sys/kern/vfs_syscalls.c 2016-09-14 21:09:43 UTC (rev 7930)
@@ -1992,7 +1992,7 @@
struct file *fp;
struct vnode *vp;
struct vattr vattr;
- off_t offset, size;
+ off_t foffset, offset, size;
int error, noneg;
int vfslocked;
@@ -2004,6 +2004,7 @@
return (ESPIPE);
}
vp = fp->f_vnode;
+ foffset = foffset_lock(fp, 0);
vfslocked = VFS_LOCK_GIANT(vp->v_mount);
noneg = (vp->v_type != VCHR);
offset = uap->offset;
@@ -2010,12 +2011,12 @@
switch (uap->whence) {
case L_INCR:
if (noneg &&
- (fp->f_offset < 0 ||
- (offset > 0 && fp->f_offset > OFF_MAX - offset))) {
+ (foffset < 0 ||
+ (offset > 0 && foffset > OFF_MAX - offset))) {
error = EOVERFLOW;
break;
}
- offset += fp->f_offset;
+ offset += foffset;
break;
case L_XTND:
vn_lock(vp, LK_SHARED | LK_RETRY);
@@ -2055,12 +2056,12 @@
error = EINVAL;
if (error != 0)
goto drop;
- fp->f_offset = offset;
VFS_KNOTE_UNLOCKED(vp, 0);
- *(off_t *)(td->td_retval) = fp->f_offset;
+ *(off_t *)(td->td_retval) = offset;
drop:
fdrop(fp, td);
VFS_UNLOCK_GIANT(vfslocked);
+ foffset_unlock(fp, offset, error != 0 ? FOF_NOUPDATE : 0);
return (error);
}
@@ -3994,6 +3995,7 @@
caddr_t dirbuf;
int error, eofflag, readcnt, vfslocked;
long loff;
+ off_t foffset;
/* XXX arbitrary sanity limit on `count'. */
if (uap->count > 64 * 1024)
@@ -4006,10 +4008,12 @@
return (EBADF);
}
vp = fp->f_vnode;
+ foffset = foffset_lock(fp, 0);
unionread:
vfslocked = VFS_LOCK_GIANT(vp->v_mount);
if (vp->v_type != VDIR) {
VFS_UNLOCK_GIANT(vfslocked);
+ foffset_unlock(fp, foffset, 0);
fdrop(fp, td);
return (EINVAL);
}
@@ -4022,12 +4026,13 @@
auio.uio_td = td;
auio.uio_resid = uap->count;
vn_lock(vp, LK_SHARED | LK_RETRY);
- loff = auio.uio_offset = fp->f_offset;
+ loff = auio.uio_offset = foffset;
#ifdef MAC
error = mac_vnode_check_readdir(td->td_ucred, vp);
if (error) {
VOP_UNLOCK(vp, 0);
VFS_UNLOCK_GIANT(vfslocked);
+ foffset_unlock(fp, foffset, FOF_NOUPDATE);
fdrop(fp, td);
return (error);
}
@@ -4036,7 +4041,7 @@
if (vp->v_mount->mnt_maxsymlinklen <= 0) {
error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
NULL, NULL);
- fp->f_offset = auio.uio_offset;
+ foffset = auio.uio_offset;
} else
# endif
{
@@ -4048,7 +4053,7 @@
kiov.iov_base = dirbuf;
error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
NULL, NULL);
- fp->f_offset = kuio.uio_offset;
+ foffset = kuio.uio_offset;
if (error == 0) {
readcnt = uap->count - kuio.uio_resid;
edp = (struct dirent *)&dirbuf[readcnt];
@@ -4086,6 +4091,7 @@
if (error) {
VOP_UNLOCK(vp, 0);
VFS_UNLOCK_GIANT(vfslocked);
+ foffset_unlock(fp, foffset, 0);
fdrop(fp, td);
return (error);
}
@@ -4097,7 +4103,7 @@
VREF(vp);
fp->f_vnode = vp;
fp->f_data = vp;
- fp->f_offset = 0;
+ foffset = 0;
vput(tvp);
VFS_UNLOCK_GIANT(vfslocked);
goto unionread;
@@ -4104,6 +4110,7 @@
}
VOP_UNLOCK(vp, 0);
VFS_UNLOCK_GIANT(vfslocked);
+ foffset_unlock(fp, foffset, 0);
fdrop(fp, td);
td->td_retval[0] = uap->count - auio.uio_resid;
if (error == 0)
@@ -4155,6 +4162,7 @@
int vfslocked;
long loff;
int error, eofflag;
+ off_t foffset;
AUDIT_ARG_FD(fd);
auio.uio_resid = count;
@@ -4168,6 +4176,7 @@
return (EBADF);
}
vp = fp->f_vnode;
+ foffset = foffset_lock(fp, 0);
unionread:
vfslocked = VFS_LOCK_GIANT(vp->v_mount);
if (vp->v_type != VDIR) {
@@ -4184,7 +4193,7 @@
auio.uio_td = td;
vn_lock(vp, LK_SHARED | LK_RETRY);
AUDIT_ARG_VNODE1(vp);
- loff = auio.uio_offset = fp->f_offset;
+ loff = auio.uio_offset = foffset;
#ifdef MAC
error = mac_vnode_check_readdir(td->td_ucred, vp);
if (error == 0)
@@ -4191,7 +4200,7 @@
#endif
error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, NULL,
NULL);
- fp->f_offset = auio.uio_offset;
+ foffset = auio.uio_offset;
if (error) {
VOP_UNLOCK(vp, 0);
VFS_UNLOCK_GIANT(vfslocked);
@@ -4205,7 +4214,7 @@
VREF(vp);
fp->f_vnode = vp;
fp->f_data = vp;
- fp->f_offset = 0;
+ foffset = 0;
vput(tvp);
VFS_UNLOCK_GIANT(vfslocked);
goto unionread;
@@ -4215,6 +4224,7 @@
*basep = loff;
td->td_retval[0] = count - auio.uio_resid;
fail:
+ foffset_unlock(fp, foffset, 0);
fdrop(fp, td);
return (error);
}
Modified: trunk/sys/kern/vfs_vnops.c
===================================================================
--- trunk/sys/kern/vfs_vnops.c 2016-09-14 21:06:39 UTC (rev 7929)
+++ trunk/sys/kern/vfs_vnops.c 2016-09-14 21:09:43 UTC (rev 7930)
@@ -512,30 +512,91 @@
return (error);
}
-static void
-foffset_lock(struct file *fp, struct uio *uio, int flags)
+off_t
+foffset_lock(struct file *fp, int flags)
{
struct mtx *mtxp;
+ off_t res;
- if ((flags & FOF_OFFSET) != 0)
- return;
+ 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.
* It is now protected by the FOFFSET_LOCKED flag.
*/
mtxp = mtx_pool_find(mtxpool_sleep, fp);
mtx_lock(mtxp);
- while (fp->f_vnread_flags & FOFFSET_LOCKED) {
- fp->f_vnread_flags |= FOFFSET_LOCK_WAITING;
- msleep(&fp->f_vnread_flags, mtxp, PUSER -1,
- "vnread offlock", 0);
+ 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;
}
- fp->f_vnread_flags |= FOFFSET_LOCKED;
- uio->uio_offset = fp->f_offset;
+ 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"));
+
+#if OFF_MAX <= LONG_MAX
+ if ((flags & FOF_NOLOCK) != 0) {
+ if ((flags & FOF_NOUPDATE) == 0)
+ fp->f_offset = val;
+ if ((flags & FOF_NEXTOFF) != 0)
+ fp->f_nextoff = val;
+ return;
+ }
+#endif
+
+ 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);
+}
+
+void
+foffset_lock_uio(struct file *fp, struct uio *uio, int flags)
+{
+
+ if ((flags & FOF_OFFSET) == 0)
+ uio->uio_offset = foffset_lock(fp, flags);
+}
+
+void
+foffset_unlock_uio(struct file *fp, struct uio *uio, int flags)
+{
+
+ if ((flags & FOF_OFFSET) == 0)
+ foffset_unlock(fp, uio->uio_offset, flags);
+}
+
static int
get_advice(struct file *fp, struct uio *uio)
{
@@ -555,23 +616,6 @@
return (ret);
}
-static void
-foffset_unlock(struct file *fp, struct uio *uio, int flags)
-{
- struct mtx *mtxp;
-
- if ((flags & FOF_OFFSET) != 0)
- return;
-
- fp->f_offset = uio->uio_offset;
- mtxp = mtx_pool_find(mtxpool_sleep, fp);
- mtx_lock(mtxp);
- if (fp->f_vnread_flags & FOFFSET_LOCK_WAITING)
- wakeup(&fp->f_vnread_flags);
- fp->f_vnread_flags = 0;
- mtx_unlock(mtxp);
-}
-
/*
* File table vnode read routine.
*/
@@ -850,7 +894,7 @@
else
doio = vn_write;
vp = fp->f_vnode;
- foffset_lock(fp, uio, flags);
+ foffset_lock_uio(fp, uio, flags);
if (uio->uio_segflg != UIO_USERSPACE || vp->v_type != VREG ||
((mp = vp->v_mount) != NULL &&
@@ -967,7 +1011,7 @@
vn_rangelock_unlock(vp, rl_cookie);
free(uio_clone, M_IOV);
out_last:
- foffset_unlock(fp, uio, flags);
+ foffset_unlock_uio(fp, uio, flags);
return (error);
}
Modified: trunk/sys/sys/file.h
===================================================================
--- trunk/sys/sys/file.h 2016-09-14 21:06:39 UTC (rev 7929)
+++ trunk/sys/sys/file.h 2016-09-14 21:09:43 UTC (rev 7930)
@@ -72,10 +72,25 @@
struct file;
struct ucred;
+#define FOF_OFFSET 0x01 /* Use the offset in uio argument */
+#define FOF_NOLOCK 0x02 /* Do not take FOFFSET_LOCK */
+#define FOF_NEXTOFF 0x04 /* Also update f_nextoff */
+#define FOF_NOUPDATE 0x10 /* Do not update f_offset */
+off_t foffset_lock(struct file *fp, int flags);
+void foffset_lock_uio(struct file *fp, struct uio *uio, int flags);
+void foffset_unlock(struct file *fp, off_t val, int flags);
+void foffset_unlock_uio(struct file *fp, struct uio *uio, int flags);
+
+static inline off_t
+foffset_get(struct file *fp)
+{
+
+ return (foffset_lock(fp, FOF_NOLOCK));
+}
+
typedef int fo_rdwr_t(struct file *fp, struct uio *uio,
struct ucred *active_cred, int flags,
struct thread *td);
-#define FOF_OFFSET 1 /* Use the offset in uio argument */
typedef int fo_truncate_t(struct file *fp, off_t length,
struct ucred *active_cred, struct thread *td);
typedef int fo_ioctl_t(struct file *fp, u_long com, void *data,
Modified: trunk/sys/ufs/ffs/ffs_alloc.c
===================================================================
--- trunk/sys/ufs/ffs/ffs_alloc.c 2016-09-14 21:06:39 UTC (rev 7929)
+++ trunk/sys/ufs/ffs/ffs_alloc.c 2016-09-14 21:09:43 UTC (rev 7930)
@@ -2871,10 +2871,9 @@
if (ip->i_devvp != devvp)
return (EINVAL);
fs = ip->i_fs;
+ foffset_lock_uio(fp, uio, flags);
vfslocked = VFS_LOCK_GIANT(ip->i_vnode->v_mount);
vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
- if ((flags & FOF_OFFSET) == 0)
- uio->uio_offset = fp->f_offset;
#ifdef DEBUG
if (fsckcmds) {
printf("%s: buffered write for block %jd\n",
@@ -2899,11 +2898,9 @@
goto out;
}
error = bwrite(bp);
- if ((flags & FOF_OFFSET) == 0)
- fp->f_offset = uio->uio_offset;
- fp->f_nextoff = uio->uio_offset;
out:
VOP_UNLOCK(devvp, 0);
VFS_UNLOCK_GIANT(vfslocked);
+ foffset_unlock_uio(fp, uio, flags | FOF_NEXTOFF);
return (error);
}
More information about the Midnightbsd-cvs
mailing list