always call inode_change_ok early in ->setattr
Christoph Hellwig [Fri, 4 Jun 2010 09:30:03 +0000 (11:30 +0200)]
Make sure we call inode_change_ok before doing any changes in ->setattr,
and make sure to call it even if our fs wants to ignore normal UNIX
permissions, but use the ATTR_FORCE to skip those.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

fs/cifs/inode.c
fs/fat/file.c
fs/fuse/dir.c
fs/logfs/file.c
fs/reiserfs/inode.c
mm/shmem.c

index 9c6a40f..b95f4a5 100644 (file)
@@ -1796,14 +1796,12 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
 
        xid = GetXid();
 
-       if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) {
-               /* check if we have permission to change attrs */
-               rc = inode_change_ok(inode, attrs);
-               if (rc < 0)
-                       goto out;
-               else
-                       rc = 0;
-       }
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
+               attrs->ia_valid |= ATTR_FORCE;
+
+       rc = inode_change_ok(inode, attrs);
+       if (rc < 0)
+               goto out;
 
        full_path = build_path_from_dentry(direntry);
        if (full_path == NULL) {
@@ -1934,14 +1932,13 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
        cFYI(1, "setattr on file %s attrs->iavalid 0x%x",
                 direntry->d_name.name, attrs->ia_valid);
 
-       if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) {
-               /* check if we have permission to change attrs */
-               rc = inode_change_ok(inode, attrs);
-               if (rc < 0) {
-                       FreeXid(xid);
-                       return rc;
-               } else
-                       rc = 0;
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
+               attrs->ia_valid |= ATTR_FORCE;
+
+       rc = inode_change_ok(inode, attrs);
+       if (rc < 0) {
+               FreeXid(xid);
+               return rc;
        }
 
        full_path = build_path_from_dentry(direntry);
index 20813d2..b2eedce 100644 (file)
@@ -387,21 +387,6 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)
        unsigned int ia_valid;
        int error;
 
-       /*
-        * Expand the file. Since inode_setattr() updates ->i_size
-        * before calling the ->truncate(), but FAT needs to fill the
-        * hole before it. XXX: this is no longer true with new truncate
-        * sequence.
-        */
-       if (attr->ia_valid & ATTR_SIZE) {
-               if (attr->ia_size > inode->i_size) {
-                       error = fat_cont_expand(inode, attr->ia_size);
-                       if (error || attr->ia_valid == ATTR_SIZE)
-                               goto out;
-                       attr->ia_valid &= ~ATTR_SIZE;
-               }
-       }
-
        /* Check for setting the inode time. */
        ia_valid = attr->ia_valid;
        if (ia_valid & TIMES_SET_FLAGS) {
@@ -417,6 +402,21 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)
                goto out;
        }
 
+       /*
+        * Expand the file. Since inode_setattr() updates ->i_size
+        * before calling the ->truncate(), but FAT needs to fill the
+        * hole before it. XXX: this is no longer true with new truncate
+        * sequence.
+        */
+       if (attr->ia_valid & ATTR_SIZE) {
+               if (attr->ia_size > inode->i_size) {
+                       error = fat_cont_expand(inode, attr->ia_size);
+                       if (error || attr->ia_valid == ATTR_SIZE)
+                               goto out;
+                       attr->ia_valid &= ~ATTR_SIZE;
+               }
+       }
+
        if (((attr->ia_valid & ATTR_UID) &&
             (attr->ia_uid != sbi->options.fs_uid)) ||
            ((attr->ia_valid & ATTR_GID) &&
index 3cdc5f7..43a9b37 100644 (file)
@@ -1270,11 +1270,12 @@ static int fuse_do_setattr(struct dentry *entry, struct iattr *attr,
        if (!fuse_allow_task(fc, current))
                return -EACCES;
 
-       if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
-               err = inode_change_ok(inode, attr);
-               if (err)
-                       return err;
-       }
+       if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS))
+               attr->ia_valid |= ATTR_FORCE;
+
+       err = inode_change_ok(inode, attr);
+       if (err)
+               return err;
 
        if ((attr->ia_valid & ATTR_OPEN) && fc->atomic_o_trunc)
                return 0;
index 23b4d03..4dd0f7c 100644 (file)
@@ -232,16 +232,16 @@ static int logfs_setattr(struct dentry *dentry, struct iattr *attr)
        struct inode *inode = dentry->d_inode;
        int err = 0;
 
+       err = inode_change_ok(inode, attr);
+       if (err)
+               return err;
+
        if (attr->ia_valid & ATTR_SIZE) {
                err = logfs_truncate(inode, attr->ia_size);
                if (err)
                        return err;
        }
 
-       err = inode_change_ok(inode, attr);
-       if (err)
-               return err;
-
        setattr_copy(inode, attr);
        mark_inode_dirty(inode);
        return 0;
index 2b8dc5c..46ba1cf 100644 (file)
@@ -3084,6 +3084,10 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr)
        int depth;
        int error;
 
+       error = inode_change_ok(inode, attr);
+       if (error)
+               return error;
+
        /* must be turned off for recursive notify_change calls */
        ia_valid = attr->ia_valid &= ~(ATTR_KILL_SUID|ATTR_KILL_SGID);
 
@@ -3133,10 +3137,6 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr)
                goto out;
        }
 
-       error = inode_change_ok(inode, attr);
-       if (error)
-               goto out;
-
        if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
            (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) {
                struct reiserfs_transaction_handle th;
index 3b58ad6..0a43505 100644 (file)
@@ -767,6 +767,10 @@ static int shmem_notify_change(struct dentry *dentry, struct iattr *attr)
        loff_t newsize = attr->ia_size;
        int error;
 
+       error = inode_change_ok(inode, attr);
+       if (error)
+               return error;
+
        if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE)
                                        && newsize != inode->i_size) {
                struct page *page = NULL;
@@ -809,11 +813,9 @@ static int shmem_notify_change(struct dentry *dentry, struct iattr *attr)
                shmem_truncate_range(inode, newsize, (loff_t)-1);
        }
 
-       error = inode_change_ok(inode, attr);
-       if (!error)
-               setattr_copy(inode, attr);
+       setattr_copy(inode, attr);
 #ifdef CONFIG_TMPFS_POSIX_ACL
-       if (!error && (attr->ia_valid & ATTR_MODE))
+       if (attr->ia_valid & ATTR_MODE)
                error = generic_acl_chmod(inode);
 #endif
        return error;