make ->atomic_open() return int
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / fs / nfs / dir.c
index f430057ff3b397c2fe1f523bf5fcea4135276f8c..b56f4b36ed415650c4b6a26d85aba45a16a36f28 100644 (file)
@@ -111,11 +111,13 @@ const struct inode_operations nfs3_dir_inode_operations = {
 
 #ifdef CONFIG_NFS_V4
 
-static struct dentry *nfs_atomic_lookup(struct inode *, struct dentry *, struct nameidata *);
-static int nfs_open_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd);
+static int nfs_atomic_open(struct inode *, struct dentry *,
+                          struct opendata *, unsigned, umode_t,
+                          int *);
 const struct inode_operations nfs4_dir_inode_operations = {
-       .create         = nfs_open_create,
-       .lookup         = nfs_atomic_lookup,
+       .create         = nfs_create,
+       .lookup         = nfs_lookup,
+       .atomic_open    = nfs_atomic_open,
        .link           = nfs_link,
        .unlink         = nfs_unlink,
        .symlink        = nfs_symlink,
@@ -1364,24 +1366,6 @@ const struct dentry_operations nfs4_dentry_operations = {
        .d_release      = nfs_d_release,
 };
 
-/*
- * Use intent information to determine whether we need to substitute
- * the NFSv4-style stateful OPEN for the LOOKUP call
- */
-static int is_atomic_open(struct nameidata *nd)
-{
-       if (nd == NULL || nfs_lookup_check_intent(nd, LOOKUP_OPEN) == 0)
-               return 0;
-       /* NFS does not (yet) have a stateful open for directories */
-       if (nd->flags & LOOKUP_DIRECTORY)
-               return 0;
-       /* Are we trying to write to a read only partition? */
-       if (__mnt_is_readonly(nd->path.mnt) &&
-           (nd->intent.open.flags & (O_CREAT|O_TRUNC|O_ACCMODE)))
-               return 0;
-       return 1;
-}
-
 static fmode_t flags_to_mode(int flags)
 {
        fmode_t res = (__force fmode_t)flags & FMODE_EXEC;
@@ -1403,120 +1387,130 @@ static int do_open(struct inode *inode, struct file *filp)
        return 0;
 }
 
-static int nfs_intent_set_file(struct nameidata *nd, struct nfs_open_context *ctx)
+static int nfs_finish_open(struct nfs_open_context *ctx,
+                          struct dentry *dentry,
+                          struct opendata *od, unsigned open_flags,
+                          int *opened)
 {
        struct file *filp;
-       int ret = 0;
+       int err;
+
+       if (ctx->dentry != dentry) {
+               dput(ctx->dentry);
+               ctx->dentry = dget(dentry);
+       }
 
        /* If the open_intent is for execute, we have an extra check to make */
        if (ctx->mode & FMODE_EXEC) {
-               ret = nfs_may_open(ctx->dentry->d_inode,
-                               ctx->cred,
-                               nd->intent.open.flags);
-               if (ret < 0)
+               err = nfs_may_open(dentry->d_inode, ctx->cred, open_flags);
+               if (err < 0)
                        goto out;
        }
-       filp = lookup_instantiate_filp(nd, ctx->dentry, do_open);
-       if (IS_ERR(filp))
-               ret = PTR_ERR(filp);
-       else
-               nfs_file_set_open_context(filp, ctx);
+
+       filp = finish_open(od, dentry, do_open, opened);
+       if (IS_ERR(filp)) {
+               err = PTR_ERR(filp);
+               goto out;
+       }
+       nfs_file_set_open_context(filp, ctx);
+       err = 0;
+
 out:
        put_nfs_open_context(ctx);
-       return ret;
+       return err;
 }
 
-static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+static int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
+                           struct opendata *od, unsigned open_flags,
+                           umode_t mode, int *opened)
 {
        struct nfs_open_context *ctx;
-       struct iattr attr;
-       struct dentry *res = NULL;
+       struct dentry *res;
+       struct iattr attr = { .ia_valid = ATTR_OPEN };
        struct inode *inode;
-       int open_flags;
        int err;
 
-       dfprintk(VFS, "NFS: atomic_lookup(%s/%ld), %s\n",
+       /* Expect a negative dentry */
+       BUG_ON(dentry->d_inode);
+
+       dfprintk(VFS, "NFS: atomic_open(%s/%ld), %s\n",
                        dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
 
-       /* Check that we are indeed trying to open this file */
-       if (!is_atomic_open(nd))
+       /* NFS only supports OPEN on regular files */
+       if ((open_flags & O_DIRECTORY)) {
+               if (!d_unhashed(dentry)) {
+                       /*
+                        * Hashed negative dentry with O_DIRECTORY: dentry was
+                        * revalidated and is fine, no need to perform lookup
+                        * again
+                        */
+                       return -ENOENT;
+               }
                goto no_open;
-
-       if (dentry->d_name.len > NFS_SERVER(dir)->namelen) {
-               res = ERR_PTR(-ENAMETOOLONG);
-               goto out;
-       }
-
-       /* Let vfs_create() deal with O_EXCL. Instantiate, but don't hash
-        * the dentry. */
-       if (nd->flags & LOOKUP_EXCL) {
-               d_instantiate(dentry, NULL);
-               goto out;
        }
 
-       open_flags = nd->intent.open.flags;
-       attr.ia_valid = ATTR_OPEN;
-
-       ctx = create_nfs_open_context(dentry, open_flags);
-       res = ERR_CAST(ctx);
-       if (IS_ERR(ctx))
-               goto out;
+       if (dentry->d_name.len > NFS_SERVER(dir)->namelen)
+               return -ENAMETOOLONG;
 
-       if (nd->flags & LOOKUP_CREATE) {
-               attr.ia_mode = nd->intent.open.create_mode;
+       if (open_flags & O_CREAT) {
                attr.ia_valid |= ATTR_MODE;
-               attr.ia_mode &= ~current_umask();
-       } else
-               open_flags &= ~(O_EXCL | O_CREAT);
-
+               attr.ia_mode = mode & ~current_umask();
+       }
        if (open_flags & O_TRUNC) {
                attr.ia_valid |= ATTR_SIZE;
                attr.ia_size = 0;
        }
 
-       /* Open the file on the server */
+       ctx = create_nfs_open_context(dentry, open_flags);
+       err = PTR_ERR(ctx);
+       if (IS_ERR(ctx))
+               goto out;
+
        nfs_block_sillyrename(dentry->d_parent);
        inode = NFS_PROTO(dir)->open_context(dir, ctx, open_flags, &attr);
+       d_drop(dentry);
        if (IS_ERR(inode)) {
                nfs_unblock_sillyrename(dentry->d_parent);
                put_nfs_open_context(ctx);
-               switch (PTR_ERR(inode)) {
-                       /* Make a negative dentry */
-                       case -ENOENT:
-                               d_add(dentry, NULL);
-                               res = NULL;
-                               goto out;
-                       /* This turned out not to be a regular file */
-                       case -EISDIR:
-                       case -ENOTDIR:
+               err = PTR_ERR(inode);
+               switch (err) {
+               case -ENOENT:
+                       d_add(dentry, NULL);
+                       break;
+               case -EISDIR:
+               case -ENOTDIR:
+                       goto no_open;
+               case -ELOOP:
+                       if (!(open_flags & O_NOFOLLOW))
                                goto no_open;
-                       case -ELOOP:
-                               if (!(nd->intent.open.flags & O_NOFOLLOW))
-                                       goto no_open;
+                       break;
                        /* case -EINVAL: */
-                       default:
-                               res = ERR_CAST(inode);
-                               goto out;
+               default:
+                       break;
                }
+               goto out;
        }
        res = d_add_unique(dentry, inode);
-       nfs_unblock_sillyrename(dentry->d_parent);
-       if (res != NULL) {
-               dput(ctx->dentry);
-               ctx->dentry = dget(res);
+       if (res != NULL)
                dentry = res;
-       }
-       err = nfs_intent_set_file(nd, ctx);
-       if (err < 0) {
-               if (res != NULL)
-                       dput(res);
-               return ERR_PTR(err);
-       }
-out:
+
+       nfs_unblock_sillyrename(dentry->d_parent);
        nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
-       return res;
+
+       err = nfs_finish_open(ctx, dentry, od, open_flags, opened);
+
+       dput(res);
+out:
+       return err;
+
 no_open:
-       return nfs_lookup(dir, dentry, nd);
+       res = nfs_lookup(dir, dentry, NULL);
+       err = PTR_ERR(res);
+       if (IS_ERR(res))
+               goto out;
+
+       finish_no_open(od, res);
+       return 1;
 }
 
 static int nfs4_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
@@ -1524,15 +1518,17 @@ static int nfs4_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
        struct dentry *parent = NULL;
        struct inode *inode;
        struct inode *dir;
-       int openflags, ret = 0;
+       int ret = 0;
 
        if (nd->flags & LOOKUP_RCU)
                return -ECHILD;
 
-       inode = dentry->d_inode;
-       if (!is_atomic_open(nd) || d_mountpoint(dentry))
+       if (!(nd->flags & LOOKUP_OPEN) || (nd->flags & LOOKUP_DIRECTORY))
+               goto no_open;
+       if (d_mountpoint(dentry))
                goto no_open;
 
+       inode = dentry->d_inode;
        parent = dget_parent(dentry);
        dir = parent->d_inode;
 
@@ -1548,9 +1544,8 @@ static int nfs4_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
        /* NFS only supports OPEN on regular files */
        if (!S_ISREG(inode->i_mode))
                goto no_open_dput;
-       openflags = nd->intent.open.flags;
        /* We cannot do exclusive creation on a positive dentry */
-       if ((openflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL))
+       if (nd && nd->flags & LOOKUP_EXCL)
                goto no_open_dput;
 
        /* Let f_op->open() actually open (and revalidate) the file */
@@ -1566,47 +1561,6 @@ no_open:
        return nfs_lookup_revalidate(dentry, nd);
 }
 
-static int nfs_open_create(struct inode *dir, struct dentry *dentry,
-               umode_t mode, struct nameidata *nd)
-{
-       struct nfs_open_context *ctx = NULL;
-       struct iattr attr;
-       int error;
-       int open_flags = O_CREAT|O_EXCL;
-
-       dfprintk(VFS, "NFS: create(%s/%ld), %s\n",
-                       dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
-
-       attr.ia_mode = mode;
-       attr.ia_valid = ATTR_MODE;
-
-       if (nd)
-               open_flags = nd->intent.open.flags;
-
-       ctx = create_nfs_open_context(dentry, open_flags);
-       error = PTR_ERR(ctx);
-       if (IS_ERR(ctx))
-               goto out_err_drop;
-
-       error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, ctx);
-       if (error != 0)
-               goto out_put_ctx;
-       if (nd) {
-               error = nfs_intent_set_file(nd, ctx);
-               if (error < 0)
-                       goto out_err;
-       } else {
-               put_nfs_open_context(ctx);
-       }
-       return 0;
-out_put_ctx:
-       put_nfs_open_context(ctx);
-out_err_drop:
-       d_drop(dentry);
-out_err:
-       return error;
-}
-
 #endif /* CONFIG_NFSV4 */
 
 /*
@@ -1670,10 +1624,10 @@ static int nfs_create(struct inode *dir, struct dentry *dentry,
        attr.ia_mode = mode;
        attr.ia_valid = ATTR_MODE;
 
-       if (nd)
-               open_flags = nd->intent.open.flags;
+       if (nd && !(nd->flags & LOOKUP_EXCL))
+               open_flags = O_CREAT;
 
-       error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, NULL);
+       error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags);
        if (error != 0)
                goto out_err;
        return 0;