@@ -6,10 +6,12 @@
* Tao Peng <bergwolf@primarydata.com>
*/
+#include <linux/dcache.h>
#include <linux/exportfs.h>
#include <linux/nfs.h>
#include <linux/nfs_fs.h>
+#include "internal.h"
#include "nfstrace.h"
#define NFSDBG_FACILITY NFSDBG_VFS
@@ -40,7 +42,54 @@ nfs_encode_fh(struct inode *inode, __u32 *p, int *max_len, struct inode *parent)
return *max_len;
}
+static struct dentry *
+nfs_fh_to_dentry(struct super_block *sb, struct fid *fid,
+ int fh_len, int fh_type)
+{
+ struct nfs4_label *label = NULL;
+ struct nfs_fattr *fattr = NULL;
+ struct nfs_fh *server_fh = (struct nfs_fh *)fid->raw;
+ const struct nfs_rpc_ops *rpc_ops;
+ struct dentry *dentry = NULL;
+ struct inode *inode;
+ int len = server_fh->size / 4 + 1;
+ int ret;
+
+ /* NULL translates to ESTALE */
+ if (fh_len < len || fh_type != len)
+ return NULL;
+
+ fattr = nfs_alloc_fattr();
+ if (fattr == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ label = nfs4_label_alloc(NFS_SB(sb), GFP_KERNEL);
+ if (IS_ERR(label)) {
+ ret = PTR_ERR(label);
+ goto out;
+ }
+
+ rpc_ops = NFS_SB(sb)->nfs_client->rpc_ops;
+ ret = rpc_ops->getattr(NFS_SB(sb), server_fh, fattr, label);
+ if (ret) {
+ dprintk("%s: getattr failed %d\n", __func__, ret);
+ goto out;
+ }
+
+ inode = nfs_fhget(sb, server_fh, fattr, label);
+ dentry = d_obtain_alias(inode);
+
+out:
+ nfs4_label_free(label);
+ nfs_free_fattr(fattr);
+
+ return ret ? ERR_PTR(ret) : dentry;
+}
+
const struct export_operations nfs_export_ops = {
.encode_fh = nfs_encode_fh,
+ .fh_to_dentry = nfs_fh_to_dentry,
.flags = EXPORT_OP_NOWCC|EXPORT_OP_NOSUBTREECHK|EXPORT_OP_CLOSE_BEFORE_UNLINK,
};