Commit 8dce684c authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Linus Torvalds

[PATCH] fix ->setattr ATTR_SIZE locking for nfsd

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: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent d7300467
...@@ -171,6 +171,9 @@ int notify_change(struct dentry * dentry, struct iattr * attr) ...@@ -171,6 +171,9 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
if (!attr->ia_valid) if (!attr->ia_valid)
return 0; return 0;
if (ia_valid & ATTR_SIZE)
down_write(&dentry->d_inode->i_alloc_sem);
if (inode->i_op && inode->i_op->setattr) { if (inode->i_op && inode->i_op->setattr) {
error = security_inode_setattr(dentry, attr); error = security_inode_setattr(dentry, attr);
if (!error) if (!error)
...@@ -187,6 +190,10 @@ int notify_change(struct dentry * dentry, struct iattr * attr) ...@@ -187,6 +190,10 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
error = inode_setattr(inode, attr); error = inode_setattr(inode, attr);
} }
} }
if (ia_valid & ATTR_SIZE)
up_write(&dentry->d_inode->i_alloc_sem);
if (!error) { if (!error) {
unsigned long dn_mask = setattr_mask(ia_valid); unsigned long dn_mask = setattr_mask(ia_valid);
if (dn_mask) if (dn_mask)
......
...@@ -203,10 +203,9 @@ int do_truncate(struct dentry *dentry, loff_t length) ...@@ -203,10 +203,9 @@ int do_truncate(struct dentry *dentry, loff_t length)
newattrs.ia_size = length; newattrs.ia_size = length;
newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
down(&dentry->d_inode->i_sem); down(&dentry->d_inode->i_sem);
down_write(&dentry->d_inode->i_alloc_sem);
err = notify_change(dentry, &newattrs); err = notify_change(dentry, &newattrs);
up_write(&dentry->d_inode->i_alloc_sem);
up(&dentry->d_inode->i_sem); up(&dentry->d_inode->i_sem);
return err; return err;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment