patch-2.3.24 linux/fs/nfsd/vfs.c

Next file: linux/fs/romfs/inode.c
Previous file: linux/fs/nfsd/nfssvc.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.23/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c
@@ -234,6 +234,7 @@
 	int		ftype = 0;
 	int		imode;
 	int		err;
+	kernel_cap_t	saved_cap = 0;
 
 	if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE))
 		accmode |= MAY_WRITE;
@@ -242,7 +243,7 @@
 
 	/* Get inode */
 	err = fh_verify(rqstp, fhp, ftype, accmode);
-	if (err)
+	if (err || !iap->ia_valid)
 		goto out;
 
 	dentry = fhp->fh_dentry;
@@ -252,7 +253,7 @@
 	if (err)
 		goto out_nfserr;
 
-	/* The size case is special... */
+	/* The size case is special. It changes the file as well as the attributes.  */
 	if (iap->ia_valid & ATTR_SIZE) {
 if (!S_ISREG(inode->i_mode))
 printk("nfsd_setattr: size change??\n");
@@ -264,15 +265,14 @@
 		err = get_write_access(inode);
 		if (err)
 			goto out_nfserr;
-		/* N.B. Should we update the inode cache here? */
-		inode->i_size = iap->ia_size;
-		if (inode->i_op && inode->i_op->truncate)
-			inode->i_op->truncate(inode);
-		mark_inode_dirty(inode);
-		put_write_access(inode);
-		iap->ia_valid &= ~ATTR_SIZE;
-		iap->ia_valid |= ATTR_MTIME;
-		iap->ia_mtime = CURRENT_TIME;
+
+		err = locks_verify_area(FLOCK_VERIFY_WRITE, inode, NULL,
+				  iap->ia_size<inode->i_size ? iap->ia_size : inode->i_size,
+				  abs(inode->i_size - iap->ia_size));
+
+		if (err)
+			goto out_nfserr;
+		DQUOT_INIT(inode);
 	}
 
 	imode = inode->i_mode;
@@ -294,23 +294,32 @@
 	}
 
 	/* Change the attributes. */
-	if (iap->ia_valid) {
-		kernel_cap_t	saved_cap = 0;
 
-		iap->ia_valid |= ATTR_CTIME;
-		iap->ia_ctime = CURRENT_TIME;
-		if (current->fsuid != 0) {
-			saved_cap = current->cap_effective;
-			cap_clear(current->cap_effective);
-		}
+
+	iap->ia_valid |= ATTR_CTIME;
+	if (current->fsuid != 0) {
+		saved_cap = current->cap_effective;
+		cap_clear(current->cap_effective);
+	}
+	if (iap->ia_valid & ATTR_SIZE) {
+		fh_lock(fhp);
 		err = notify_change(dentry, iap);
-		if (current->fsuid != 0)
-			current->cap_effective = saved_cap;
-		if (err)
-			goto out_nfserr;
-		if (EX_ISSYNC(fhp->fh_export))
-			write_inode_now(inode);
+		if (!err) {
+			vmtruncate(inode,iap->ia_size);		
+			if (inode->i_op && inode->i_op->truncate)
+				inode->i_op->truncate(inode);
+		}
+		fh_unlock(fhp);
+		put_write_access(inode);
 	}
+	else
+		err = notify_change(dentry, iap);
+	if (current->fsuid != 0)
+		current->cap_effective = saved_cap;
+	if (err)
+		goto out_nfserr;
+	if (EX_ISSYNC(fhp->fh_export))
+		write_inode_now(inode);
 	err = 0;
 out:
 	return err;
@@ -401,7 +410,6 @@
 		filp->f_op->release(inode, filp);
 	if (filp->f_mode & FMODE_WRITE) {
 		put_write_access(inode);
-		DQUOT_DROP(inode);
 	}
 }
 
@@ -548,7 +556,6 @@
 	if ((stable || (stable = EX_ISSYNC(exp))) && !EX_WGATHER(exp))
 		file.f_flags |= O_SYNC;
 
-	fh_lock(fhp);			/* lock inode */
 	file.f_pos = offset;		/* set write offset */
 
 	/* Write the data. */
@@ -580,8 +587,6 @@
 			current->cap_effective = saved_cap;
 	}
 
-	fh_unlock(fhp);			/* unlock inode */
-
 	if (err >= 0 && stable) {
 		static unsigned long	last_ino = 0;
 		static kdev_t		last_dev = NODEV;
@@ -651,9 +656,13 @@
 	err = nfserr_perm;
 	if (!flen)
 		goto out;
-	err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE);
-	if (err)
-		goto out;
+
+	/* from mkdir it won't be verified, from create it will	 */
+	if (!fhp->fh_dverified) {
+		err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE);
+		if (err)
+			goto out;
+	}
 
 	dentry = fhp->fh_dentry;
 	dirp = dentry->d_inode;
@@ -731,7 +740,6 @@
 	 */
 	DQUOT_INIT(dirp);
 	err = opfunc(dirp, dchild, iap->ia_mode, rdev);
-	DQUOT_DROP(dirp);
 	if (err < 0)
 		goto out_nfserr;
 
@@ -786,6 +794,11 @@
 	err = get_write_access(inode);
 	if (err)
 		goto out_nfserr;
+	err = locks_verify_area(FLOCK_VERIFY_WRITE, inode, NULL,
+				  size<inode->i_size ? size : inode->i_size,
+				  abs(inode->i_size - size));
+	if (err)
+		goto out_nfserr;
 
 	/* Things look sane, lock and do it. */
 	fh_lock(fhp);
@@ -797,15 +810,14 @@
 		cap_clear(current->cap_effective);
 	}
 	err = notify_change(dentry, &newattrs);
-	if (current->fsuid != 0)
-		current->cap_effective = saved_cap;
 	if (!err) {
 		vmtruncate(inode, size);
 		if (inode->i_op && inode->i_op->truncate)
 			inode->i_op->truncate(inode);
 	}
+	if (current->fsuid != 0)
+		current->cap_effective = saved_cap;
 	put_write_access(inode);
-	DQUOT_DROP(inode);
 	fh_unlock(fhp);
 out_nfserr:
 	if (err)
@@ -902,7 +914,6 @@
 	if (!dnew->d_inode) {
 		DQUOT_INIT(dirp);
 		err = dirp->i_op->symlink(dirp, dnew, path);
-		DQUOT_DROP(dirp);
 		if (!err) {
 			if (EX_ISSYNC(fhp->fh_export))
 				write_inode_now(dirp);
@@ -981,7 +992,6 @@
 
 	DQUOT_INIT(dirp);
 	err = dirp->i_op->link(dold, dirp, dnew);
-	DQUOT_DROP(dirp);
 	if (!err) {
 		if (EX_ISSYNC(ffhp->fh_export)) {
 			write_inode_now(dirp);
@@ -1105,8 +1115,6 @@
 		}
 	} else
 		dprintk("nfsd: Caught race in nfsd_rename");
-	DQUOT_DROP(fdir);
-	DQUOT_DROP(tdir);
 
 	nfsd_double_up(&tdir->i_sem, &fdir->i_sem);
 	dput(ndentry);
@@ -1157,7 +1165,6 @@
 		goto out;
 	}
 
-	expire_by_dentry(rdentry);
 
 	if (type != S_IFDIR) {
 		/* It's UNLINK */
@@ -1168,7 +1175,6 @@
 
 		err = vfs_unlink(dirp, rdentry);
 
-		DQUOT_DROP(dirp);
 		fh_unlock(fhp);
 
 		dput(rdentry);
@@ -1188,7 +1194,6 @@
 			err = vfs_rmdir(dirp, rdentry);
 
 		rdentry->d_count--;
-		DQUOT_DROP(dirp);
 		if (!fhp->fh_post_version)
 			fhp->fh_post_version = dirp->i_version;
 		fhp->fh_locked = 0;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)