io_uring: fix race condition in task_work add and clear
[linux-2.6-microblaze.git] / fs / open.c
index ca54447..e53af13 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -35,8 +35,8 @@
 
 #include "internal.h"
 
-int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
-       struct file *filp)
+int do_truncate(struct user_namespace *mnt_userns, struct dentry *dentry,
+               loff_t length, unsigned int time_attrs, struct file *filp)
 {
        int ret;
        struct iattr newattrs;
@@ -61,13 +61,14 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
 
        inode_lock(dentry->d_inode);
        /* Note any delegations or leases have already been broken: */
-       ret = notify_change(dentry, &newattrs, NULL);
+       ret = notify_change(mnt_userns, dentry, &newattrs, NULL);
        inode_unlock(dentry->d_inode);
        return ret;
 }
 
 long vfs_truncate(const struct path *path, loff_t length)
 {
+       struct user_namespace *mnt_userns;
        struct inode *inode;
        long error;
 
@@ -83,7 +84,8 @@ long vfs_truncate(const struct path *path, loff_t length)
        if (error)
                goto out;
 
-       error = inode_permission(inode, MAY_WRITE);
+       mnt_userns = mnt_user_ns(path->mnt);
+       error = inode_permission(mnt_userns, inode, MAY_WRITE);
        if (error)
                goto mnt_drop_write_and_out;
 
@@ -107,7 +109,7 @@ long vfs_truncate(const struct path *path, loff_t length)
        if (!error)
                error = security_path_truncate(path);
        if (!error)
-               error = do_truncate(path->dentry, length, 0, NULL);
+               error = do_truncate(mnt_userns, path->dentry, length, 0, NULL);
 
 put_write_and_out:
        put_write_access(inode);
@@ -186,13 +188,13 @@ long do_sys_ftruncate(unsigned int fd, loff_t length, int small)
        /* Check IS_APPEND on real upper inode */
        if (IS_APPEND(file_inode(f.file)))
                goto out_putf;
-
        sb_start_write(inode->i_sb);
        error = locks_verify_truncate(inode, f.file, length);
        if (!error)
                error = security_path_truncate(&f.file->f_path);
        if (!error)
-               error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, f.file);
+               error = do_truncate(file_mnt_user_ns(f.file), dentry, length,
+                                   ATTR_MTIME | ATTR_CTIME, f.file);
        sb_end_write(inode->i_sb);
 out_putf:
        fdput(f);
@@ -436,7 +438,7 @@ retry:
                        goto out_path_release;
        }
 
-       res = inode_permission(inode, mode | MAY_ACCESS);
+       res = inode_permission(mnt_user_ns(path.mnt), inode, mode | MAY_ACCESS);
        /* SuS v2 requires we report a read only fs too */
        if (res || !(mode & S_IWOTH) || special_file(inode->i_mode))
                goto out_path_release;
@@ -492,7 +494,7 @@ retry:
        if (error)
                goto out;
 
-       error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
+       error = path_permission(&path, MAY_EXEC | MAY_CHDIR);
        if (error)
                goto dput_and_out;
 
@@ -521,7 +523,7 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd)
        if (!d_can_lookup(f.file->f_path.dentry))
                goto out_putf;
 
-       error = inode_permission(file_inode(f.file), MAY_EXEC | MAY_CHDIR);
+       error = file_permission(f.file, MAY_EXEC | MAY_CHDIR);
        if (!error)
                set_fs_pwd(current->fs, &f.file->f_path);
 out_putf:
@@ -540,7 +542,7 @@ retry:
        if (error)
                goto out;
 
-       error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
+       error = path_permission(&path, MAY_EXEC | MAY_CHDIR);
        if (error)
                goto dput_and_out;
 
@@ -580,7 +582,8 @@ retry_deleg:
                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, &delegated_inode);
+       error = notify_change(mnt_user_ns(path->mnt), path->dentry,
+                             &newattrs, &delegated_inode);
 out_unlock:
        inode_unlock(inode);
        if (delegated_inode) {
@@ -641,6 +644,7 @@ SYSCALL_DEFINE2(chmod, const char __user *, filename, umode_t, mode)
 
 int chown_common(const struct path *path, uid_t user, gid_t group)
 {
+       struct user_namespace *mnt_userns;
        struct inode *inode = path->dentry->d_inode;
        struct inode *delegated_inode = NULL;
        int error;
@@ -651,6 +655,10 @@ int chown_common(const struct path *path, uid_t user, gid_t group)
        uid = make_kuid(current_user_ns(), user);
        gid = make_kgid(current_user_ns(), group);
 
+       mnt_userns = mnt_user_ns(path->mnt);
+       uid = kuid_from_mnt(mnt_userns, uid);
+       gid = kgid_from_mnt(mnt_userns, gid);
+
 retry_deleg:
        newattrs.ia_valid =  ATTR_CTIME;
        if (user != (uid_t) -1) {
@@ -671,7 +679,8 @@ retry_deleg:
        inode_lock(inode);
        error = security_path_chown(path, uid, gid);
        if (!error)
-               error = notify_change(path->dentry, &newattrs, &delegated_inode);
+               error = notify_change(mnt_userns, path->dentry, &newattrs,
+                                     &delegated_inode);
        inode_unlock(inode);
        if (delegated_inode) {
                error = break_deleg_wait(&delegated_inode);