diff options
author | kib <kib@FreeBSD.org> | 2012-06-21 09:19:41 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2012-06-21 09:19:41 +0000 |
commit | df9f3d2faa1df2bb13d274183876fe227e259a65 (patch) | |
tree | f333c89c12a01492f7498427b3750b2549eacc1b /contrib/gcc | |
parent | 2a52af28e66573a140482815c762bae088491ab9 (diff) | |
download | FreeBSD-src-df9f3d2faa1df2bb13d274183876fe227e259a65.zip FreeBSD-src-df9f3d2faa1df2bb13d274183876fe227e259a65.tar.gz |
Fix locking for f_offset, vn_read() and vn_write() cases only, for now.
It seems that intended locking protocol for struct file f_offset field
was as follows: f_offset should always be changed under the vnode lock
(except fcntl(2) and lseek(2) did not followed the rules). Since
read(2) uses shared vnode lock, FOFFSET_LOCKED block is additionally
taken to serialize shared vnode lock owners.
This was broken first by enabling shared lock on writes, then by
fadvise changes, which moved f_offset assigned from under vnode lock,
and last by vn_io_fault() doing chunked i/o. More, due to uio_offset
not yet valid in vn_io_fault(), the range lock for reads was taken on
the wrong region.
Change the locking for f_offset to always use FOFFSET_LOCKED block,
which is placed before rangelocks in the lock order.
Extract foffset_lock() and foffset_unlock() functions which implements
FOFFSET_LOCKED lock, and consistently lock f_offset with it in the
vn_io_fault() both for reads and writes, even if MNTK_NO_IOPF flag is
not set for the vnode mount. Indicate that f_offset is already valid
for vn_read() and vn_write() calls from vn_io_fault() with FOF_OFFSET
flag, and assert that all callers of vn_read() and vn_write() follow
this protocol.
Extract get_advice() function to calculate the POSIX_FADV_XXX value
for the i/o region, and use it were appropriate.
Reviewed by: jhb
Tested by: pho
MFC after: 2 weeks
Diffstat (limited to 'contrib/gcc')
0 files changed, 0 insertions, 0 deletions