diff options
author | Konstantin Belousov <kib@FreeBSD.org> | 2012-07-02 21:01:03 +0000 |
---|---|---|
committer | Konstantin Belousov <kib@FreeBSD.org> | 2012-07-02 21:01:03 +0000 |
commit | c5c1199c83b05316971c0d32456d3383cacd9c98 (patch) | |
tree | 26c1ae1ac3dde3bf8b9b01fad04caad427a4ef48 /sys/kern/kern_descrip.c | |
parent | 9f1dae79da25d27d7b6a3085d491796ed0de30b3 (diff) | |
download | src-c5c1199c83b05316971c0d32456d3383cacd9c98.tar.gz src-c5c1199c83b05316971c0d32456d3383cacd9c98.zip |
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().
Ensure that on 32bit architectures f_offset, which is 64bit quantity,
always read and written under the mtxpool protection. This fixes
apparently easy to trigger race when parallel lseek()s or lseek() and
read/write could destroy file offset.
The already broken ABI emulations, including iBCS and SysV, are not
converted (yet).
Tested by: pho
No objections from: jhb
MFC after: 3 weeks
Notes
Notes:
svn path=/head/; revision=238029
Diffstat (limited to 'sys/kern/kern_descrip.c')
-rw-r--r-- | sys/kern/kern_descrip.c | 21 |
1 files changed, 12 insertions, 9 deletions
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index c2db4c0bbedd..d16746ad703e 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -465,6 +465,7 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) int vfslocked; u_int old, new; uint64_t bsize; + off_t foffset; vfslocked = 0; error = 0; @@ -606,14 +607,15 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) } 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; } /* @@ -727,15 +729,16 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) 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. @@ -2810,7 +2813,7 @@ sysctl_kern_file(SYSCTL_HANDLER_ARGS) 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) @@ -3015,7 +3018,7 @@ sysctl_kern_proc_ofiledesc(SYSCTL_HANDLER_ARGS) 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) { @@ -3359,7 +3362,7 @@ sysctl_kern_proc_filedesc(SYSCTL_HANDLER_ARGS) } refcnt = fp->f_count; fflags = fp->f_flag; - offset = fp->f_offset; + offset = foffset_get(fp); /* * Create sysctl entry. |