]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] fix ->setattr ATTR_SIZE locking for nfsd
authorChristoph Hellwig <hch@lst.de>
Tue, 11 Jan 2005 11:18:47 +0000 (03:18 -0800)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Tue, 11 Jan 2005 11:18:47 +0000 (03:18 -0800)
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>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
fs/attr.c
fs/open.c

index 468f3396006d7edf5d98addbdd26744728d0c293..d8524fc01e109a2d4482524d8c73ef77b2150c47 100644 (file)
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -171,6 +171,9 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
        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, struct iattr * attr)
                                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)
index 95266c0bafb555f82f96402725c9f817b57c8e0b..03a7fbc84769633586178275d63d91ab6407bb9f 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -203,10 +203,9 @@ int do_truncate(struct dentry *dentry, loff_t length)
 
        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;
 }