nfsd4: kill unnecessary check in preprocess_stateid_op
[safe/jmp/linux-2.6] / fs / open.c
index e12f170..b70e766 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -244,21 +244,21 @@ static long do_sys_truncate(const char __user * path, loff_t length)
        if (!S_ISREG(inode->i_mode))
                goto dput_and_out;
 
-       error = vfs_permission(&nd, MAY_WRITE);
+       error = mnt_want_write(nd.path.mnt);
        if (error)
                goto dput_and_out;
 
-       error = -EROFS;
-       if (IS_RDONLY(inode))
-               goto dput_and_out;
+       error = vfs_permission(&nd, MAY_WRITE);
+       if (error)
+               goto mnt_drop_write_and_out;
 
        error = -EPERM;
        if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
-               goto dput_and_out;
+               goto mnt_drop_write_and_out;
 
        error = get_write_access(inode);
        if (error)
-               goto dput_and_out;
+               goto mnt_drop_write_and_out;
 
        /*
         * Make sure that there are no leases.  get_write_access() protects
@@ -276,6 +276,8 @@ static long do_sys_truncate(const char __user * path, loff_t length)
 
 put_write_and_out:
        put_write_access(inode);
+mnt_drop_write_and_out:
+       mnt_drop_write(nd.path.mnt);
 dput_and_out:
        path_put(&nd.path);
 out:
@@ -457,8 +459,17 @@ asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
        if(res || !(mode & S_IWOTH) ||
           special_file(nd.path.dentry->d_inode->i_mode))
                goto out_path_release;
-
-       if(IS_RDONLY(nd.path.dentry->d_inode))
+       /*
+        * This is a rare case where using __mnt_is_readonly()
+        * is OK without a mnt_want/drop_write() pair.  Since
+        * no actual write to the fs is performed here, we do
+        * not need to telegraph to that to anyone.
+        *
+        * By doing this, we accept that this access is
+        * inherently racy and know that the fs may change
+        * state before we even see this result.
+        */
+       if (__mnt_is_readonly(nd.path.mnt))
                res = -EROFS;
 
 out_path_release:
@@ -567,12 +578,12 @@ asmlinkage long sys_fchmod(unsigned int fd, mode_t mode)
 
        audit_inode(NULL, dentry);
 
-       err = -EROFS;
-       if (IS_RDONLY(inode))
+       err = mnt_want_write(file->f_path.mnt);
+       if (err)
                goto out_putf;
        err = -EPERM;
        if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
-               goto out_putf;
+               goto out_drop_write;
        mutex_lock(&inode->i_mutex);
        if (mode == (mode_t) -1)
                mode = inode->i_mode;
@@ -581,6 +592,8 @@ asmlinkage long sys_fchmod(unsigned int fd, mode_t mode)
        err = notify_change(dentry, &newattrs);
        mutex_unlock(&inode->i_mutex);
 
+out_drop_write:
+       mnt_drop_write(file->f_path.mnt);
 out_putf:
        fput(file);
 out:
@@ -600,13 +613,13 @@ asmlinkage long sys_fchmodat(int dfd, const char __user *filename,
                goto out;
        inode = nd.path.dentry->d_inode;
 
-       error = -EROFS;
-       if (IS_RDONLY(inode))
+       error = mnt_want_write(nd.path.mnt);
+       if (error)
                goto dput_and_out;
 
        error = -EPERM;
        if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
-               goto dput_and_out;
+               goto out_drop_write;
 
        mutex_lock(&inode->i_mutex);
        if (mode == (mode_t) -1)
@@ -616,6 +629,8 @@ asmlinkage long sys_fchmodat(int dfd, const char __user *filename,
        error = notify_change(nd.path.dentry, &newattrs);
        mutex_unlock(&inode->i_mutex);
 
+out_drop_write:
+       mnt_drop_write(nd.path.mnt);
 dput_and_out:
        path_put(&nd.path);
 out:
@@ -638,9 +653,6 @@ static int chown_common(struct dentry * dentry, uid_t user, gid_t group)
                printk(KERN_ERR "chown_common: NULL inode\n");
                goto out;
        }
-       error = -EROFS;
-       if (IS_RDONLY(inode))
-               goto out;
        error = -EPERM;
        if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
                goto out;
@@ -671,7 +683,12 @@ asmlinkage long sys_chown(const char __user * filename, uid_t user, gid_t group)
        error = user_path_walk(filename, &nd);
        if (error)
                goto out;
+       error = mnt_want_write(nd.path.mnt);
+       if (error)
+               goto out_release;
        error = chown_common(nd.path.dentry, user, group);
+       mnt_drop_write(nd.path.mnt);
+out_release:
        path_put(&nd.path);
 out:
        return error;
@@ -691,7 +708,12 @@ asmlinkage long sys_fchownat(int dfd, const char __user *filename, uid_t user,
        error = __user_walk_fd(dfd, filename, follow, &nd);
        if (error)
                goto out;
+       error = mnt_want_write(nd.path.mnt);
+       if (error)
+               goto out_release;
        error = chown_common(nd.path.dentry, user, group);
+       mnt_drop_write(nd.path.mnt);
+out_release:
        path_put(&nd.path);
 out:
        return error;
@@ -705,7 +727,12 @@ asmlinkage long sys_lchown(const char __user * filename, uid_t user, gid_t group
        error = user_path_walk_link(filename, &nd);
        if (error)
                goto out;
+       error = mnt_want_write(nd.path.mnt);
+       if (error)
+               goto out_release;
        error = chown_common(nd.path.dentry, user, group);
+       mnt_drop_write(nd.path.mnt);
+out_release:
        path_put(&nd.path);
 out:
        return error;
@@ -722,9 +749,14 @@ asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group)
        if (!file)
                goto out;
 
+       error = mnt_want_write(file->f_path.mnt);
+       if (error)
+               goto out_fput;
        dentry = file->f_path.dentry;
        audit_inode(NULL, dentry);
        error = chown_common(dentry, user, group);
+       mnt_drop_write(file->f_path.mnt);
+out_fput:
        fput(file);
 out:
        return error;
@@ -774,6 +806,8 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
                error = __get_file_write_access(inode, mnt);
                if (error)
                        goto cleanup_file;
+               if (!special_file(inode->i_mode))
+                       file_take_write(f);
        }
 
        f->f_mapping = inode->i_mapping;
@@ -815,8 +849,16 @@ cleanup_all:
        fops_put(f->f_op);
        if (f->f_mode & FMODE_WRITE) {
                put_write_access(inode);
-               if (!special_file(inode->i_mode))
+               if (!special_file(inode->i_mode)) {
+                       /*
+                        * We don't consider this a real
+                        * mnt_want/drop_write() pair
+                        * because it all happenend right
+                        * here, so just reset the state.
+                        */
+                       file_reset_write(f);
                        mnt_drop_write(mnt);
+               }
        }
        file_kill(f);
        f->f_path.dentry = NULL;