summaryrefslogtreecommitdiffstats
path: root/sys/kern/vfs_syscalls.c
diff options
context:
space:
mode:
authormdf <mdf@FreeBSD.org>2011-04-19 16:36:24 +0000
committermdf <mdf@FreeBSD.org>2011-04-19 16:36:24 +0000
commit597ae9f19b6fef74ff11610f93edbbe7203826bc (patch)
tree78d599ef539b474a5c063ebdaa0cbc1a6980fc47 /sys/kern/vfs_syscalls.c
parentcc6bebd7b6fa6e0e167807baca1a190b89f16203 (diff)
downloadFreeBSD-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.c59
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);
OpenPOWER on IntegriCloud