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:
parent
651045d6de
commit
037755fd15
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=270648
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user