From: Christoph Hellwig 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 --- 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; } _