include/asm-x86/local.h: checkpatch cleanups - formatting only
[sfrench/cifs-2.6.git] / fs / attr.c
index ae58bd3f875f9c92c9599bacebbab85ebdf2c800..966b73e25f82e06f69ad0eca22a3f6fe268c4cd0 100644 (file)
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -103,12 +103,11 @@ EXPORT_SYMBOL(inode_setattr);
 int notify_change(struct dentry * dentry, struct iattr * attr)
 {
        struct inode *inode = dentry->d_inode;
-       mode_t mode;
+       mode_t mode = inode->i_mode;
        int error;
        struct timespec now;
        unsigned int ia_valid = attr->ia_valid;
 
-       mode = inode->i_mode;
        now = current_fs_time(inode->i_sb);
 
        attr->ia_ctime = now;
@@ -125,18 +124,25 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
                if (error)
                        return error;
        }
+
+       /*
+        * We now pass ATTR_KILL_S*ID to the lower level setattr function so
+        * that the function has the ability to reinterpret a mode change
+        * that's due to these bits. This adds an implicit restriction that
+        * no function will ever call notify_change with both ATTR_MODE and
+        * ATTR_KILL_S*ID set.
+        */
+       if ((ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) &&
+           (ia_valid & ATTR_MODE))
+               BUG();
+
        if (ia_valid & ATTR_KILL_SUID) {
-               attr->ia_valid &= ~ATTR_KILL_SUID;
                if (mode & S_ISUID) {
-                       if (!(ia_valid & ATTR_MODE)) {
-                               ia_valid = attr->ia_valid |= ATTR_MODE;
-                               attr->ia_mode = inode->i_mode;
-                       }
-                       attr->ia_mode &= ~S_ISUID;
+                       ia_valid = attr->ia_valid |= ATTR_MODE;
+                       attr->ia_mode = (inode->i_mode & ~S_ISUID);
                }
        }
        if (ia_valid & ATTR_KILL_SGID) {
-               attr->ia_valid &= ~ ATTR_KILL_SGID;
                if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
                        if (!(ia_valid & ATTR_MODE)) {
                                ia_valid = attr->ia_valid |= ATTR_MODE;
@@ -145,7 +151,7 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
                        attr->ia_mode &= ~S_ISGID;
                }
        }
-       if (!attr->ia_valid)
+       if (!(attr->ia_valid & ~(ATTR_KILL_SUID | ATTR_KILL_SGID)))
                return 0;
 
        if (ia_valid & ATTR_SIZE)