|
@@ -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;
|
|
|
}
|
|
|
|