diff options
author | mdf <mdf@FreeBSD.org> | 2011-04-19 16:36:24 +0000 |
---|---|---|
committer | mdf <mdf@FreeBSD.org> | 2011-04-19 16:36:24 +0000 |
commit | 597ae9f19b6fef74ff11610f93edbbe7203826bc (patch) | |
tree | 78d599ef539b474a5c063ebdaa0cbc1a6980fc47 /sys/kern/vfs_syscalls.c | |
parent | cc6bebd7b6fa6e0e167807baca1a190b89f16203 (diff) | |
download | FreeBSD-src-597ae9f19b6fef74ff11610f93edbbe7203826bc.zip FreeBSD-src-597ae9f19b6fef74ff11610f93edbbe7203826bc.tar.gz |
Allow VOP_ALLOCATE to be iterative, and have kern_posix_fallocate(9)
drive looping and potentially yielding.
Requested by: kib
Diffstat (limited to 'sys/kern/vfs_syscalls.c')
-rw-r--r-- | sys/kern/vfs_syscalls.c | 59 |
1 files changed, 37 insertions, 22 deletions
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index ae408ca..33f7c5b 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -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); |