xfs: add xfs_trim_extent
[cascardo/linux.git] / fs / attr.c
index 5c45909..c902b3d 100644 (file)
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -47,7 +47,7 @@ int setattr_prepare(struct dentry *dentry, struct iattr *attr)
 
        /* If force is set do it anyway. */
        if (ia_valid & ATTR_FORCE)
-               return 0;
+               goto kill_priv;
 
        /* Make sure a caller can chown. */
        if ((ia_valid & ATTR_UID) &&
@@ -80,6 +80,16 @@ int setattr_prepare(struct dentry *dentry, struct iattr *attr)
                        return -EPERM;
        }
 
+kill_priv:
+       /* User has permission for the change */
+       if (ia_valid & ATTR_KILL_PRIV) {
+               int error;
+
+               error = security_inode_killpriv(dentry);
+               if (error)
+                       return error;
+       }
+
        return 0;
 }
 EXPORT_SYMBOL(setattr_prepare);
@@ -205,6 +215,21 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
                        return -EPERM;
        }
 
+       /*
+        * If utimes(2) and friends are called with times == NULL (or both
+        * times are UTIME_NOW), then we need to check for write permission
+        */
+       if (ia_valid & ATTR_TOUCH) {
+               if (IS_IMMUTABLE(inode))
+                       return -EPERM;
+
+               if (!inode_owner_or_capable(inode)) {
+                       error = inode_permission(inode, MAY_WRITE);
+                       if (error)
+                               return error;
+               }
+       }
+
        if ((ia_valid & ATTR_MODE)) {
                umode_t amode = attr->ia_mode;
                /* Flag setting protected by i_mutex */
@@ -212,7 +237,7 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
                        inode->i_flags &= ~S_NOSEC;
        }
 
-       now = current_fs_time(inode->i_sb);
+       now = current_time(inode);
 
        attr->ia_ctime = now;
        if (!(ia_valid & ATTR_ATIME_SET))
@@ -220,13 +245,11 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
        if (!(ia_valid & ATTR_MTIME_SET))
                attr->ia_mtime = now;
        if (ia_valid & ATTR_KILL_PRIV) {
-               attr->ia_valid &= ~ATTR_KILL_PRIV;
-               ia_valid &= ~ATTR_KILL_PRIV;
                error = security_inode_need_killpriv(dentry);
-               if (error > 0)
-                       error = security_inode_killpriv(dentry);
-               if (error)
+               if (error < 0)
                        return error;
+               if (error == 0)
+                       ia_valid = attr->ia_valid &= ~ATTR_KILL_PRIV;
        }
 
        /*