Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 19 Apr 2011 16:36:25 +0000 (UTC)
From:      Matthew D Fleming <mdf@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r220846 - head/sys/kern
Message-ID:  <201104191636.p3JGaPdW014233@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mdf
Date: Tue Apr 19 16:36:24 2011
New Revision: 220846
URL: http://svn.freebsd.org/changeset/base/220846

Log:
  Allow VOP_ALLOCATE to be iterative, and have kern_posix_fallocate(9)
  drive looping and potentially yielding.
  
  Requested by:	kib

Modified:
  head/sys/kern/vfs_default.c
  head/sys/kern/vfs_syscalls.c
  head/sys/kern/vnode_if.src

Modified: head/sys/kern/vfs_default.c
==============================================================================
--- head/sys/kern/vfs_default.c	Tue Apr 19 16:33:08 2011	(r220845)
+++ head/sys/kern/vfs_default.c	Tue Apr 19 16:36:24 2011	(r220846)
@@ -865,25 +865,25 @@ vop_stdallocate(struct vop_allocate_args
 	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
 	} 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
 			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
 
 		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);
 }

Modified: head/sys/kern/vfs_syscalls.c
==============================================================================
--- head/sys/kern/vfs_syscalls.c	Tue Apr 19 16:33:08 2011	(r220845)
+++ head/sys/kern/vfs_syscalls.c	Tue Apr 19 16:36:24 2011	(r220846)
@@ -4678,12 +4678,11 @@ kern_posix_fallocate(struct thread *td, 
 	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, 
 		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);

Modified: head/sys/kern/vnode_if.src
==============================================================================
--- head/sys/kern/vnode_if.src	Tue Apr 19 16:33:08 2011	(r220845)
+++ head/sys/kern/vnode_if.src	Tue Apr 19 16:36:24 2011	(r220846)
@@ -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;
 };



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201104191636.p3JGaPdW014233>