Merge branch 'dmaengine' of git://git.linaro.org/people/rmk/linux-arm
[cascardo/linux.git] / fs / nfs / dir.c
index f430057..627f108 100644 (file)
@@ -17,6 +17,7 @@
  *  6 Jun 1999 Cache readdir lookups in the page cache. -DaveM
  */
 
+#include <linux/module.h>
 #include <linux/time.h>
 #include <linux/errno.h>
 #include <linux/stat.h>
 static int nfs_opendir(struct inode *, struct file *);
 static int nfs_closedir(struct inode *, struct file *);
 static int nfs_readdir(struct file *, void *, filldir_t);
-static struct dentry *nfs_lookup(struct inode *, struct dentry *, struct nameidata *);
-static int nfs_create(struct inode *, struct dentry *, umode_t, struct nameidata *);
-static int nfs_mkdir(struct inode *, struct dentry *, umode_t);
-static int nfs_rmdir(struct inode *, struct dentry *);
-static int nfs_unlink(struct inode *, struct dentry *);
-static int nfs_symlink(struct inode *, struct dentry *, const char *);
-static int nfs_link(struct dentry *, struct inode *, struct dentry *);
-static int nfs_mknod(struct inode *, struct dentry *, umode_t, dev_t);
-static int nfs_rename(struct inode *, struct dentry *,
-                     struct inode *, struct dentry *);
 static int nfs_fsync_dir(struct file *, loff_t, loff_t, int);
 static loff_t nfs_llseek_dir(struct file *, loff_t, int);
 static void nfs_readdir_clear_array(struct page*);
@@ -69,71 +60,10 @@ const struct file_operations nfs_dir_operations = {
        .fsync          = nfs_fsync_dir,
 };
 
-const struct inode_operations nfs_dir_inode_operations = {
-       .create         = nfs_create,
-       .lookup         = nfs_lookup,
-       .link           = nfs_link,
-       .unlink         = nfs_unlink,
-       .symlink        = nfs_symlink,
-       .mkdir          = nfs_mkdir,
-       .rmdir          = nfs_rmdir,
-       .mknod          = nfs_mknod,
-       .rename         = nfs_rename,
-       .permission     = nfs_permission,
-       .getattr        = nfs_getattr,
-       .setattr        = nfs_setattr,
-};
-
 const struct address_space_operations nfs_dir_aops = {
        .freepage = nfs_readdir_clear_array,
 };
 
-#ifdef CONFIG_NFS_V3
-const struct inode_operations nfs3_dir_inode_operations = {
-       .create         = nfs_create,
-       .lookup         = nfs_lookup,
-       .link           = nfs_link,
-       .unlink         = nfs_unlink,
-       .symlink        = nfs_symlink,
-       .mkdir          = nfs_mkdir,
-       .rmdir          = nfs_rmdir,
-       .mknod          = nfs_mknod,
-       .rename         = nfs_rename,
-       .permission     = nfs_permission,
-       .getattr        = nfs_getattr,
-       .setattr        = nfs_setattr,
-       .listxattr      = nfs3_listxattr,
-       .getxattr       = nfs3_getxattr,
-       .setxattr       = nfs3_setxattr,
-       .removexattr    = nfs3_removexattr,
-};
-#endif  /* CONFIG_NFS_V3 */
-
-#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);
-const struct inode_operations nfs4_dir_inode_operations = {
-       .create         = nfs_open_create,
-       .lookup         = nfs_atomic_lookup,
-       .link           = nfs_link,
-       .unlink         = nfs_unlink,
-       .symlink        = nfs_symlink,
-       .mkdir          = nfs_mkdir,
-       .rmdir          = nfs_rmdir,
-       .mknod          = nfs_mknod,
-       .rename         = nfs_rename,
-       .permission     = nfs_permission,
-       .getattr        = nfs_getattr,
-       .setattr        = nfs_setattr,
-       .getxattr       = generic_getxattr,
-       .setxattr       = generic_setxattr,
-       .listxattr      = generic_listxattr,
-       .removexattr    = generic_removexattr,
-};
-
-#endif /* CONFIG_NFS_V4 */
-
 static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct inode *dir, struct rpc_cred *cred)
 {
        struct nfs_open_dir_context *ctx;
@@ -1006,6 +936,7 @@ void nfs_force_lookup_revalidate(struct inode *dir)
 {
        NFS_I(dir)->cache_change_attribute++;
 }
+EXPORT_SYMBOL_GPL(nfs_force_lookup_revalidate);
 
 /*
  * A check for whether or not the parent directory has changed.
@@ -1028,28 +959,15 @@ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry)
        return 1;
 }
 
-/*
- * Return the intent data that applies to this particular path component
- *
- * Note that the current set of intents only apply to the very last
- * component of the path and none of them is set before that last
- * component.
- */
-static inline unsigned int nfs_lookup_check_intent(struct nameidata *nd,
-                                               unsigned int mask)
-{
-       return nd->flags & mask;
-}
-
 /*
  * Use intent information to check whether or not we're going to do
  * an O_EXCL create using this path component.
  */
-static int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd)
+static int nfs_is_exclusive_create(struct inode *dir, unsigned int flags)
 {
        if (NFS_PROTO(dir)->version == 2)
                return 0;
-       return nd && nfs_lookup_check_intent(nd, LOOKUP_EXCL);
+       return flags & LOOKUP_EXCL;
 }
 
 /*
@@ -1061,25 +979,20 @@ static int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd)
  *
  */
 static inline
-int nfs_lookup_verify_inode(struct inode *inode, struct nameidata *nd)
+int nfs_lookup_verify_inode(struct inode *inode, unsigned int flags)
 {
        struct nfs_server *server = NFS_SERVER(inode);
 
        if (IS_AUTOMOUNT(inode))
                return 0;
-       if (nd != NULL) {
-               /* VFS wants an on-the-wire revalidation */
-               if (nd->flags & LOOKUP_REVAL)
-                       goto out_force;
-               /* This is an open(2) */
-               if (nfs_lookup_check_intent(nd, LOOKUP_OPEN) != 0 &&
-                               !(server->flags & NFS_MOUNT_NOCTO) &&
-                               (S_ISREG(inode->i_mode) ||
-                                S_ISDIR(inode->i_mode)))
-                       goto out_force;
-               return 0;
-       }
-       return nfs_revalidate_inode(server, inode);
+       /* VFS wants an on-the-wire revalidation */
+       if (flags & LOOKUP_REVAL)
+               goto out_force;
+       /* This is an open(2) */
+       if ((flags & LOOKUP_OPEN) && !(server->flags & NFS_MOUNT_NOCTO) &&
+           (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)))
+               goto out_force;
+       return 0;
 out_force:
        return __nfs_revalidate_inode(server, inode);
 }
@@ -1093,10 +1006,10 @@ out_force:
  */
 static inline
 int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry,
-                      struct nameidata *nd)
+                      unsigned int flags)
 {
        /* Don't revalidate a negative dentry if we're creating a new file */
-       if (nd != NULL && nfs_lookup_check_intent(nd, LOOKUP_CREATE) != 0)
+       if (flags & LOOKUP_CREATE)
                return 0;
        if (NFS_SERVER(dir)->flags & NFS_MOUNT_LOOKUP_CACHE_NONEG)
                return 1;
@@ -1114,7 +1027,7 @@ int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry,
  * If the parent directory is seen to have changed, we throw out the
  * cached dentry and do a new lookup.
  */
-static int nfs_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
+static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
 {
        struct inode *dir;
        struct inode *inode;
@@ -1123,7 +1036,7 @@ static int nfs_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
        struct nfs_fattr *fattr = NULL;
        int error;
 
-       if (nd->flags & LOOKUP_RCU)
+       if (flags & LOOKUP_RCU)
                return -ECHILD;
 
        parent = dget_parent(dentry);
@@ -1132,7 +1045,7 @@ static int nfs_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
        inode = dentry->d_inode;
 
        if (!inode) {
-               if (nfs_neg_need_reval(dir, dentry, nd))
+               if (nfs_neg_need_reval(dir, dentry, flags))
                        goto out_bad;
                goto out_valid_noent;
        }
@@ -1144,12 +1057,12 @@ static int nfs_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
                goto out_bad;
        }
 
-       if (nfs_have_delegation(inode, FMODE_READ))
+       if (NFS_PROTO(dir)->have_delegation(inode, FMODE_READ))
                goto out_set_verifier;
 
        /* Force a full look up iff the parent directory has changed */
-       if (!nfs_is_exclusive_create(dir, nd) && nfs_check_verifier(dir, dentry)) {
-               if (nfs_lookup_verify_inode(inode, nd))
+       if (!nfs_is_exclusive_create(dir, flags) && nfs_check_verifier(dir, dentry)) {
+               if (nfs_lookup_verify_inode(inode, flags))
                        goto out_zap_parent;
                goto out_valid;
        }
@@ -1285,8 +1198,9 @@ const struct dentry_operations nfs_dentry_operations = {
        .d_automount    = nfs_d_automount,
        .d_release      = nfs_d_release,
 };
+EXPORT_SYMBOL_GPL(nfs_dentry_operations);
 
-static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
+struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags)
 {
        struct dentry *res;
        struct dentry *parent;
@@ -1307,7 +1221,7 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
         * If we're doing an exclusive create, optimize away the lookup
         * but don't hash the dentry.
         */
-       if (nfs_is_exclusive_create(dir, nd)) {
+       if (nfs_is_exclusive_create(dir, flags)) {
                d_instantiate(dentry, NULL);
                res = NULL;
                goto out;
@@ -1352,9 +1266,10 @@ out:
        nfs_free_fhandle(fhandle);
        return res;
 }
+EXPORT_SYMBOL_GPL(nfs_lookup);
 
-#ifdef CONFIG_NFS_V4
-static int nfs4_lookup_revalidate(struct dentry *, struct nameidata *);
+#if IS_ENABLED(CONFIG_NFS_V4)
+static int nfs4_lookup_revalidate(struct dentry *, unsigned int);
 
 const struct dentry_operations nfs4_dentry_operations = {
        .d_revalidate   = nfs4_lookup_revalidate,
@@ -1363,24 +1278,7 @@ const struct dentry_operations nfs4_dentry_operations = {
        .d_automount    = nfs_d_automount,
        .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;
-}
+EXPORT_SYMBOL_GPL(nfs4_dentry_operations);
 
 static fmode_t flags_to_mode(int flags)
 {
@@ -1403,136 +1301,144 @@ 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 file *file, 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);
+
+       err = finish_open(file, dentry, do_open, opened);
+       if (err)
+               goto out;
+       nfs_file_set_open_context(file, ctx);
+
 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)
+int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
+                   struct file *file, 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, file, open_flags, opened);
+
+       dput(res);
+out:
+       return err;
+
 no_open:
-       return nfs_lookup(dir, dentry, nd);
+       res = nfs_lookup(dir, dentry, 0);
+       err = PTR_ERR(res);
+       if (IS_ERR(res))
+               goto out;
+
+       return finish_no_open(file, res);
 }
+EXPORT_SYMBOL_GPL(nfs_atomic_open);
 
-static int nfs4_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
+static int nfs4_lookup_revalidate(struct dentry *dentry, unsigned int flags)
 {
        struct dentry *parent = NULL;
        struct inode *inode;
        struct inode *dir;
-       int openflags, ret = 0;
+       int ret = 0;
 
-       if (nd->flags & LOOKUP_RCU)
+       if (flags & LOOKUP_RCU)
                return -ECHILD;
 
-       inode = dentry->d_inode;
-       if (!is_atomic_open(nd) || d_mountpoint(dentry))
+       if (!(flags & LOOKUP_OPEN) || (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;
 
@@ -1540,7 +1446,7 @@ static int nfs4_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
         * optimize away revalidation of negative dentries.
         */
        if (inode == NULL) {
-               if (!nfs_neg_need_reval(dir, dentry, nd))
+               if (!nfs_neg_need_reval(dir, dentry, flags))
                        ret = 1;
                goto out;
        }
@@ -1548,9 +1454,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 (flags & LOOKUP_EXCL)
                goto no_open_dput;
 
        /* Let f_op->open() actually open (and revalidate) the file */
@@ -1563,48 +1468,7 @@ out:
 no_open_dput:
        dput(parent);
 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;
+       return nfs_lookup_revalidate(dentry, flags);
 }
 
 #endif /* CONFIG_NFSV4 */
@@ -1650,6 +1514,7 @@ out_error:
        dput(parent);
        return error;
 }
+EXPORT_SYMBOL_GPL(nfs_instantiate);
 
 /*
  * Following a failed create operation, we drop the dentry rather
@@ -1657,12 +1522,12 @@ out_error:
  * that the operation succeeded on the server, but an error in the
  * reply path made it appear to have failed.
  */
-static int nfs_create(struct inode *dir, struct dentry *dentry,
-               umode_t mode, struct nameidata *nd)
+int nfs_create(struct inode *dir, struct dentry *dentry,
+               umode_t mode, bool excl)
 {
        struct iattr attr;
+       int open_flags = excl ? O_CREAT | O_EXCL : O_CREAT;
        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);
@@ -1670,10 +1535,7 @@ 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;
-
-       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;
@@ -1681,11 +1543,12 @@ out_err:
        d_drop(dentry);
        return error;
 }
+EXPORT_SYMBOL_GPL(nfs_create);
 
 /*
  * See comments for nfs_proc_create regarding failed operations.
  */
-static int
+int
 nfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev)
 {
        struct iattr attr;
@@ -1708,11 +1571,12 @@ out_err:
        d_drop(dentry);
        return status;
 }
+EXPORT_SYMBOL_GPL(nfs_mknod);
 
 /*
  * See comments for nfs_proc_create regarding failed operations.
  */
-static int nfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
+int nfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 {
        struct iattr attr;
        int error;
@@ -1731,6 +1595,7 @@ out_err:
        d_drop(dentry);
        return error;
 }
+EXPORT_SYMBOL_GPL(nfs_mkdir);
 
 static void nfs_dentry_handle_enoent(struct dentry *dentry)
 {
@@ -1738,7 +1603,7 @@ static void nfs_dentry_handle_enoent(struct dentry *dentry)
                d_delete(dentry);
 }
 
-static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
+int nfs_rmdir(struct inode *dir, struct dentry *dentry)
 {
        int error;
 
@@ -1754,6 +1619,7 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
 
        return error;
 }
+EXPORT_SYMBOL_GPL(nfs_rmdir);
 
 /*
  * Remove a file after making sure there are no pending writes,
@@ -1778,7 +1644,7 @@ static int nfs_safe_remove(struct dentry *dentry)
        }
 
        if (inode != NULL) {
-               nfs_inode_return_delegation(inode);
+               NFS_PROTO(inode)->return_delegation(inode);
                error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
                /* The VFS may want to delete this inode */
                if (error == 0)
@@ -1797,7 +1663,7 @@ out:
  *
  *  If sillyrename() returns 0, we do nothing, otherwise we unlink.
  */
-static int nfs_unlink(struct inode *dir, struct dentry *dentry)
+int nfs_unlink(struct inode *dir, struct dentry *dentry)
 {
        int error;
        int need_rehash = 0;
@@ -1825,6 +1691,7 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry)
                d_rehash(dentry);
        return error;
 }
+EXPORT_SYMBOL_GPL(nfs_unlink);
 
 /*
  * To create a symbolic link, most file systems instantiate a new inode,
@@ -1841,7 +1708,7 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry)
  * now have a new file handle and can instantiate an in-core NFS inode
  * and move the raw page into its mapping.
  */
-static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
+int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
 {
        struct pagevec lru_pvec;
        struct page *page;
@@ -1895,8 +1762,9 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(nfs_symlink);
 
-static int 
+int
 nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
 {
        struct inode *inode = old_dentry->d_inode;
@@ -1906,7 +1774,7 @@ nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
                old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
                dentry->d_parent->d_name.name, dentry->d_name.name);
 
-       nfs_inode_return_delegation(inode);
+       NFS_PROTO(inode)->return_delegation(inode);
 
        d_drop(dentry);
        error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name);
@@ -1916,6 +1784,7 @@ nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
        }
        return error;
 }
+EXPORT_SYMBOL_GPL(nfs_link);
 
 /*
  * RENAME
@@ -1941,7 +1810,7 @@ nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
  * If these conditions are met, we can drop the dentries before doing
  * the rename.
  */
-static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                      struct inode *new_dir, struct dentry *new_dentry)
 {
        struct inode *old_inode = old_dentry->d_inode;
@@ -1990,9 +1859,9 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                }
        }
 
-       nfs_inode_return_delegation(old_inode);
+       NFS_PROTO(old_inode)->return_delegation(old_inode);
        if (new_inode != NULL)
-               nfs_inode_return_delegation(new_inode);
+               NFS_PROTO(new_inode)->return_delegation(new_inode);
 
        error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name,
                                           new_dir, &new_dentry->d_name);
@@ -2014,6 +1883,7 @@ out:
                dput(dentry);
        return error;
 }
+EXPORT_SYMBOL_GPL(nfs_rename);
 
 static DEFINE_SPINLOCK(nfs_access_lru_lock);
 static LIST_HEAD(nfs_access_lru_list);
@@ -2114,6 +1984,7 @@ void nfs_access_zap_cache(struct inode *inode)
        spin_unlock(&nfs_access_lru_lock);
        nfs_access_free_list(&head);
 }
+EXPORT_SYMBOL_GPL(nfs_access_zap_cache);
 
 static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, struct rpc_cred *cred)
 {
@@ -2274,6 +2145,7 @@ int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags)
 {
        return nfs_do_access(inode, cred, nfs_open_permission_mask(openflags));
 }
+EXPORT_SYMBOL_GPL(nfs_may_open);
 
 int nfs_permission(struct inode *inode, int mask)
 {
@@ -2333,6 +2205,7 @@ out_notsup:
                res = generic_permission(inode, mask);
        goto out;
 }
+EXPORT_SYMBOL_GPL(nfs_permission);
 
 /*
  * Local variables: