mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
Allow VOP_ALLOCATE to be iterative, and have kern_posix_fallocate(9)
drive looping and potentially yielding. Requested by: kib
This commit is contained in:
parent
51268821a9
commit
1ce4508f6d
3 changed files with 61 additions and 48 deletions
|
|
@ -865,25 +865,25 @@ vop_stdallocate(struct vop_allocate_args *ap)
|
|||
struct iovec aiov;
|
||||
struct vattr vattr, *vap;
|
||||
struct uio auio;
|
||||
off_t len, cur, offset;
|
||||
off_t fsize, len, cur, offset;
|
||||
uint8_t *buf;
|
||||
struct thread *td;
|
||||
struct vnode *vp;
|
||||
size_t iosize;
|
||||
int error, locked;
|
||||
int error;
|
||||
|
||||
buf = NULL;
|
||||
error = 0;
|
||||
locked = 1;
|
||||
td = curthread;
|
||||
vap = &vattr;
|
||||
vp = ap->a_vp;
|
||||
len = ap->a_len;
|
||||
offset = ap->a_offset;
|
||||
len = *ap->a_len;
|
||||
offset = *ap->a_offset;
|
||||
|
||||
error = VOP_GETATTR(vp, vap, td->td_ucred);
|
||||
if (error != 0)
|
||||
goto out;
|
||||
fsize = vap->va_size;
|
||||
iosize = vap->va_blocksize;
|
||||
if (iosize == 0)
|
||||
iosize = BLKDEV_IOSIZE;
|
||||
|
|
@ -908,27 +908,22 @@ vop_stdallocate(struct vop_allocate_args *ap)
|
|||
} else
|
||||
#endif
|
||||
if (offset + len > vap->va_size) {
|
||||
/*
|
||||
* Test offset + len against the filesystem's maxfilesize.
|
||||
*/
|
||||
VATTR_NULL(vap);
|
||||
vap->va_size = offset + len;
|
||||
error = VOP_SETATTR(vp, vap, td->td_ucred);
|
||||
if (error != 0)
|
||||
goto out;
|
||||
VATTR_NULL(vap);
|
||||
vap->va_size = fsize;
|
||||
error = VOP_SETATTR(vp, vap, td->td_ucred);
|
||||
if (error != 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (len > 0) {
|
||||
if (should_yield()) {
|
||||
VOP_UNLOCK(vp, 0);
|
||||
locked = 0;
|
||||
kern_yield(-1);
|
||||
error = vn_lock(vp, LK_EXCLUSIVE);
|
||||
if (error != 0)
|
||||
break;
|
||||
locked = 1;
|
||||
error = VOP_GETATTR(vp, vap, td->td_ucred);
|
||||
if (error != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
/*
|
||||
* Read and write back anything below the nominal file
|
||||
* size. There's currently no way outside the filesystem
|
||||
|
|
@ -939,7 +934,7 @@ vop_stdallocate(struct vop_allocate_args *ap)
|
|||
cur -= (offset % iosize);
|
||||
if (cur > len)
|
||||
cur = len;
|
||||
if (offset < vap->va_size) {
|
||||
if (offset < fsize) {
|
||||
aiov.iov_base = buf;
|
||||
aiov.iov_len = cur;
|
||||
auio.uio_iov = &aiov;
|
||||
|
|
@ -976,12 +971,15 @@ vop_stdallocate(struct vop_allocate_args *ap)
|
|||
|
||||
len -= cur;
|
||||
offset += cur;
|
||||
if (len == 0)
|
||||
break;
|
||||
if (should_yield())
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
KASSERT(locked || error != 0, ("How'd I get unlocked with no error?"));
|
||||
if (locked && error != 0)
|
||||
VOP_UNLOCK(vp, 0);
|
||||
*ap->a_len = len;
|
||||
*ap->a_offset = offset;
|
||||
free(buf, M_TEMP);
|
||||
return (error);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4678,12 +4678,11 @@ kern_posix_fallocate(struct thread *td, int fd, off_t offset, off_t len)
|
|||
struct file *fp;
|
||||
struct mount *mp;
|
||||
struct vnode *vp;
|
||||
int error, vfslocked, vnlocked;
|
||||
off_t olen, ooffset;
|
||||
int error, vfslocked;
|
||||
|
||||
fp = NULL;
|
||||
mp = NULL;
|
||||
vfslocked = 0;
|
||||
vnlocked = 0;
|
||||
error = fget(td, fd, &fp);
|
||||
if (error != 0)
|
||||
goto out;
|
||||
|
|
@ -4718,28 +4717,44 @@ kern_posix_fallocate(struct thread *td, int fd, off_t offset, off_t len)
|
|||
goto out;
|
||||
}
|
||||
|
||||
bwillwrite();
|
||||
vfslocked = VFS_LOCK_GIANT(vp->v_mount);
|
||||
error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
|
||||
if (error != 0)
|
||||
goto out;
|
||||
error = vn_lock(vp, LK_EXCLUSIVE);
|
||||
if (error != 0)
|
||||
goto out;
|
||||
vnlocked = 1;
|
||||
/* Allocating blocks may take a long time, so iterate. */
|
||||
for (;;) {
|
||||
olen = len;
|
||||
ooffset = offset;
|
||||
|
||||
bwillwrite();
|
||||
vfslocked = VFS_LOCK_GIANT(vp->v_mount);
|
||||
mp = NULL;
|
||||
error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
|
||||
if (error != 0) {
|
||||
VFS_UNLOCK_GIANT(vfslocked);
|
||||
break;
|
||||
}
|
||||
error = vn_lock(vp, LK_EXCLUSIVE);
|
||||
if (error != 0) {
|
||||
vn_finished_write(mp);
|
||||
VFS_UNLOCK_GIANT(vfslocked);
|
||||
break;
|
||||
}
|
||||
#ifdef MAC
|
||||
error = mac_vnode_check_write(td->td_ucred, fp->f_cred, vp);
|
||||
if (error != 0)
|
||||
goto out;
|
||||
error = mac_vnode_check_write(td->td_ucred, fp->f_cred, vp);
|
||||
if (error == 0)
|
||||
#endif
|
||||
error = VOP_ALLOCATE(vp, offset, len);
|
||||
if (error != 0)
|
||||
vnlocked = 0;
|
||||
out:
|
||||
if (vnlocked)
|
||||
error = VOP_ALLOCATE(vp, &offset, &len);
|
||||
VOP_UNLOCK(vp, 0);
|
||||
vn_finished_write(mp);
|
||||
VFS_UNLOCK_GIANT(vfslocked);
|
||||
vn_finished_write(mp);
|
||||
VFS_UNLOCK_GIANT(vfslocked);
|
||||
|
||||
if (olen + ooffset != offset + len) {
|
||||
panic("offset + len changed from %jx/%jx to %jx/%jx",
|
||||
ooffset, olen, offset, len);
|
||||
}
|
||||
if (error != 0 || len == 0)
|
||||
break;
|
||||
KASSERT(olen > len, ("Iteration did not make progress?"));
|
||||
maybe_yield();
|
||||
}
|
||||
out:
|
||||
if (fp != NULL)
|
||||
fdrop(fp, td);
|
||||
return (error);
|
||||
|
|
|
|||
|
|
@ -621,10 +621,10 @@ vop_vptocnp {
|
|||
};
|
||||
|
||||
|
||||
%% allocate vp E E U
|
||||
%% allocate vp E E E
|
||||
|
||||
vop_allocate {
|
||||
IN struct vnode *vp;
|
||||
IN off_t offset;
|
||||
IN off_t len;
|
||||
IN off_t *offset;
|
||||
IN off_t *len;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue