1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-11 09:50:12 +00:00

Fix up races with f_seqcount handling.

It was possible that the kernel would overwrite user-supplied hint.

Abuse vnode lock for this purpose.

In collaboration with: kib
MFC after:	1 week
This commit is contained in:
Mateusz Guzik 2014-08-26 08:17:22 +00:00
parent 651045d6de
commit 037755fd15
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=270648
3 changed files with 21 additions and 22 deletions

View File

@ -476,7 +476,6 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
struct vnode *vp;
cap_rights_t rights;
int error, flg, tmp;
u_int old, new;
uint64_t bsize;
off_t foffset;
@ -760,26 +759,24 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
error = EBADF;
break;
}
if (arg >= 0) {
vp = fp->f_vnode;
error = vn_lock(vp, LK_SHARED);
if (error != 0) {
fdrop(fp, td);
break;
}
bsize = fp->f_vnode->v_mount->mnt_stat.f_iosize;
VOP_UNLOCK(vp, 0);
fp->f_seqcount = (arg + bsize - 1) / bsize;
do {
new = old = fp->f_flag;
new |= FRDAHEAD;
} while (!atomic_cmpset_rel_int(&fp->f_flag, old, new));
} else {
do {
new = old = fp->f_flag;
new &= ~FRDAHEAD;
} while (!atomic_cmpset_rel_int(&fp->f_flag, old, new));
vp = fp->f_vnode;
/*
* Exclusive lock synchronizes against f_seqcount reads and
* writes in sequential_heuristic().
*/
error = vn_lock(vp, LK_EXCLUSIVE);
if (error != 0) {
fdrop(fp, td);
break;
}
if (arg >= 0) {
bsize = fp->f_vnode->v_mount->mnt_stat.f_iosize;
fp->f_seqcount = (arg + bsize - 1) / bsize;
atomic_set_int(&fp->f_flag, FRDAHEAD);
} else {
atomic_clear_int(&fp->f_flag, FRDAHEAD);
}
VOP_UNLOCK(vp, 0);
fdrop(fp, td);
break;

View File

@ -438,7 +438,8 @@ static int
sequential_heuristic(struct uio *uio, struct file *fp)
{
if (atomic_load_acq_int(&(fp->f_flag)) & FRDAHEAD)
ASSERT_VOP_LOCKED(fp->f_vnode, __func__);
if (fp->f_flag & FRDAHEAD)
return (fp->f_seqcount << IO_SEQSHIFT);
/*

View File

@ -143,6 +143,7 @@ struct fileops {
*
* Below is the list of locks that protects members in struct file.
*
* (a) f_vnode lock required (shared allows both reads and writes)
* (f) protected with mtx_lock(mtx_pool_find(fp))
* (d) cdevpriv_mtx
* none not locked
@ -168,7 +169,7 @@ struct file {
/*
* DTYPE_VNODE specific fields.
*/
int f_seqcount; /* Count of sequential accesses. */
int f_seqcount; /* (a) Count of sequential accesses. */
off_t f_nextoff; /* next expected read/write offset. */
union {
struct cdev_privdata *fvn_cdevpriv;