
From: Christoph Hellwig <hch@lst.de>

Since the big direct I/O rework do_truncate takes i_alloc_sem before
calling into ->setattr.  Unfortunately the other callers of ->setattr with
ATTR_SIZE, most notably nfsd don't take it.

The (out of tree) XFS dmapi code relies wants to release i_alloc_sem and
thus gets into problems like

	http://oss.sgi.com/bugzilla/show_bug.cgi?id=365

This patch moves acquiring and releasing i_alloc_sem into notify_change()
to make the locking behaviour consistant.

Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/fs/attr.c |    7 +++++++
 25-akpm/fs/open.c |    3 +--
 2 files changed, 8 insertions(+), 2 deletions(-)

diff -puN fs/attr.c~fix-setattr-attr_size-locking-for-nfsd fs/attr.c
--- 25/fs/attr.c~fix-setattr-attr_size-locking-for-nfsd	Thu Jan  6 15:51:28 2005
+++ 25-akpm/fs/attr.c	Thu Jan  6 15:51:28 2005
@@ -171,6 +171,9 @@ int notify_change(struct dentry * dentry
 	if (!attr->ia_valid)
 		return 0;
 
+	if (ia_valid & ATTR_SIZE)
+		down_write(&dentry->d_inode->i_alloc_sem);
+
 	if (inode->i_op && inode->i_op->setattr) {
 		error = security_inode_setattr(dentry, attr);
 		if (!error)
@@ -187,6 +190,10 @@ int notify_change(struct dentry * dentry
 				error = inode_setattr(inode, attr);
 		}
 	}
+
+	if (ia_valid & ATTR_SIZE)
+		up_write(&dentry->d_inode->i_alloc_sem);
+
 	if (!error) {
 		unsigned long dn_mask = setattr_mask(ia_valid);
 		if (dn_mask)
diff -puN fs/open.c~fix-setattr-attr_size-locking-for-nfsd fs/open.c
--- 25/fs/open.c~fix-setattr-attr_size-locking-for-nfsd	Thu Jan  6 15:51:28 2005
+++ 25-akpm/fs/open.c	Thu Jan  6 15:51:28 2005
@@ -203,10 +203,9 @@ int do_truncate(struct dentry *dentry, l
 
 	newattrs.ia_size = length;
 	newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
+
 	down(&dentry->d_inode->i_sem);
-	down_write(&dentry->d_inode->i_alloc_sem);
 	err = notify_change(dentry, &newattrs);
-	up_write(&dentry->d_inode->i_alloc_sem);
 	up(&dentry->d_inode->i_sem);
 	return err;
 }
_
