locks: break delegations on any attribute modification
[deliverable/linux.git] / fs / open.c
index fffbed40dbe9e24dc6129878cf65527e241d4d48..4b3e1edf2fe4d917e69e56b3e268e32f2ae7301a 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -57,7 +57,8 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
                newattrs.ia_valid |= ret | ATTR_FORCE;
 
        mutex_lock(&dentry->d_inode->i_mutex);
-       ret = notify_change(dentry, &newattrs);
+       /* Note any delegations or leases have already been broken: */
+       ret = notify_change(dentry, &newattrs, NULL);
        mutex_unlock(&dentry->d_inode->i_mutex);
        return ret;
 }
@@ -464,21 +465,28 @@ out:
 static int chmod_common(struct path *path, umode_t mode)
 {
        struct inode *inode = path->dentry->d_inode;
+       struct inode *delegated_inode = NULL;
        struct iattr newattrs;
        int error;
 
        error = mnt_want_write(path->mnt);
        if (error)
                return error;
+retry_deleg:
        mutex_lock(&inode->i_mutex);
        error = security_path_chmod(path, mode);
        if (error)
                goto out_unlock;
        newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
        newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
-       error = notify_change(path->dentry, &newattrs);
+       error = notify_change(path->dentry, &newattrs, &delegated_inode);
 out_unlock:
        mutex_unlock(&inode->i_mutex);
+       if (delegated_inode) {
+               error = break_deleg_wait(&delegated_inode);
+               if (!error)
+                       goto retry_deleg;
+       }
        mnt_drop_write(path->mnt);
        return error;
 }
@@ -522,6 +530,7 @@ SYSCALL_DEFINE2(chmod, const char __user *, filename, umode_t, mode)
 static int chown_common(struct path *path, uid_t user, gid_t group)
 {
        struct inode *inode = path->dentry->d_inode;
+       struct inode *delegated_inode = NULL;
        int error;
        struct iattr newattrs;
        kuid_t uid;
@@ -546,12 +555,17 @@ static int chown_common(struct path *path, uid_t user, gid_t group)
        if (!S_ISDIR(inode->i_mode))
                newattrs.ia_valid |=
                        ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV;
+retry_deleg:
        mutex_lock(&inode->i_mutex);
        error = security_path_chown(path, uid, gid);
        if (!error)
-               error = notify_change(path->dentry, &newattrs);
+               error = notify_change(path->dentry, &newattrs, &delegated_inode);
        mutex_unlock(&inode->i_mutex);
-
+       if (delegated_inode) {
+               error = break_deleg_wait(&delegated_inode);
+               if (!error)
+                       goto retry_deleg;
+       }
        return error;
 }
 
This page took 0.033521 seconds and 5 git commands to generate.