root/fs/nfs/export.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nfs_exp_embedfh
  2. nfs_encode_fh
  3. nfs_fh_to_dentry
  4. nfs_get_parent

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Copyright (c) 2015, Primary Data, Inc. All rights reserved.
   4  *
   5  * Tao Peng <bergwolf@primarydata.com>
   6  */
   7 #include <linux/dcache.h>
   8 #include <linux/exportfs.h>
   9 #include <linux/nfs.h>
  10 #include <linux/nfs_fs.h>
  11 
  12 #include "internal.h"
  13 #include "nfstrace.h"
  14 
  15 #define NFSDBG_FACILITY         NFSDBG_VFS
  16 
  17 enum {
  18         FILEID_HIGH_OFF = 0,    /* inode fileid high */
  19         FILEID_LOW_OFF,         /* inode fileid low */
  20         FILE_I_TYPE_OFF,        /* inode type */
  21         EMBED_FH_OFF            /* embeded server fh */
  22 };
  23 
  24 
  25 static struct nfs_fh *nfs_exp_embedfh(__u32 *p)
  26 {
  27         return (struct nfs_fh *)(p + EMBED_FH_OFF);
  28 }
  29 
  30 /*
  31  * Let's break subtree checking for now... otherwise we'll have to embed parent fh
  32  * but there might not be enough space.
  33  */
  34 static int
  35 nfs_encode_fh(struct inode *inode, __u32 *p, int *max_len, struct inode *parent)
  36 {
  37         struct nfs_fh *server_fh = NFS_FH(inode);
  38         struct nfs_fh *clnt_fh = nfs_exp_embedfh(p);
  39         size_t fh_size = offsetof(struct nfs_fh, data) + server_fh->size;
  40         int len = EMBED_FH_OFF + XDR_QUADLEN(fh_size);
  41 
  42         dprintk("%s: max fh len %d inode %p parent %p",
  43                 __func__, *max_len, inode, parent);
  44 
  45         if (*max_len < len || IS_AUTOMOUNT(inode)) {
  46                 dprintk("%s: fh len %d too small, required %d\n",
  47                         __func__, *max_len, len);
  48                 *max_len = len;
  49                 return FILEID_INVALID;
  50         }
  51 
  52         p[FILEID_HIGH_OFF] = NFS_FILEID(inode) >> 32;
  53         p[FILEID_LOW_OFF] = NFS_FILEID(inode);
  54         p[FILE_I_TYPE_OFF] = inode->i_mode & S_IFMT;
  55         p[len - 1] = 0; /* Padding */
  56         nfs_copy_fh(clnt_fh, server_fh);
  57         *max_len = len;
  58         dprintk("%s: result fh fileid %llu mode %u size %d\n",
  59                 __func__, NFS_FILEID(inode), inode->i_mode, *max_len);
  60         return *max_len;
  61 }
  62 
  63 static struct dentry *
  64 nfs_fh_to_dentry(struct super_block *sb, struct fid *fid,
  65                  int fh_len, int fh_type)
  66 {
  67         struct nfs4_label *label = NULL;
  68         struct nfs_fattr *fattr = NULL;
  69         struct nfs_fh *server_fh = nfs_exp_embedfh(fid->raw);
  70         size_t fh_size = offsetof(struct nfs_fh, data) + server_fh->size;
  71         const struct nfs_rpc_ops *rpc_ops;
  72         struct dentry *dentry;
  73         struct inode *inode;
  74         int len = EMBED_FH_OFF + XDR_QUADLEN(fh_size);
  75         u32 *p = fid->raw;
  76         int ret;
  77 
  78         /* NULL translates to ESTALE */
  79         if (fh_len < len || fh_type != len)
  80                 return NULL;
  81 
  82         fattr = nfs_alloc_fattr();
  83         if (fattr == NULL) {
  84                 dentry = ERR_PTR(-ENOMEM);
  85                 goto out;
  86         }
  87 
  88         fattr->fileid = ((u64)p[FILEID_HIGH_OFF] << 32) + p[FILEID_LOW_OFF];
  89         fattr->mode = p[FILE_I_TYPE_OFF];
  90         fattr->valid |= NFS_ATTR_FATTR_FILEID | NFS_ATTR_FATTR_TYPE;
  91 
  92         dprintk("%s: fileid %llu mode %d\n", __func__, fattr->fileid, fattr->mode);
  93 
  94         inode = nfs_ilookup(sb, fattr, server_fh);
  95         if (inode)
  96                 goto out_found;
  97 
  98         label = nfs4_label_alloc(NFS_SB(sb), GFP_KERNEL);
  99         if (IS_ERR(label)) {
 100                 dentry = ERR_CAST(label);
 101                 goto out_free_fattr;
 102         }
 103 
 104         rpc_ops = NFS_SB(sb)->nfs_client->rpc_ops;
 105         ret = rpc_ops->getattr(NFS_SB(sb), server_fh, fattr, label, NULL);
 106         if (ret) {
 107                 dprintk("%s: getattr failed %d\n", __func__, ret);
 108                 dentry = ERR_PTR(ret);
 109                 goto out_free_label;
 110         }
 111 
 112         inode = nfs_fhget(sb, server_fh, fattr, label);
 113 
 114 out_found:
 115         dentry = d_obtain_alias(inode);
 116 
 117 out_free_label:
 118         nfs4_label_free(label);
 119 out_free_fattr:
 120         nfs_free_fattr(fattr);
 121 out:
 122         return dentry;
 123 }
 124 
 125 static struct dentry *
 126 nfs_get_parent(struct dentry *dentry)
 127 {
 128         int ret;
 129         struct inode *inode = d_inode(dentry), *pinode;
 130         struct super_block *sb = inode->i_sb;
 131         struct nfs_server *server = NFS_SB(sb);
 132         struct nfs_fattr *fattr = NULL;
 133         struct nfs4_label *label = NULL;
 134         struct dentry *parent;
 135         struct nfs_rpc_ops const *ops = server->nfs_client->rpc_ops;
 136         struct nfs_fh fh;
 137 
 138         if (!ops->lookupp)
 139                 return ERR_PTR(-EACCES);
 140 
 141         fattr = nfs_alloc_fattr();
 142         if (fattr == NULL) {
 143                 parent = ERR_PTR(-ENOMEM);
 144                 goto out;
 145         }
 146 
 147         label = nfs4_label_alloc(server, GFP_KERNEL);
 148         if (IS_ERR(label)) {
 149                 parent = ERR_CAST(label);
 150                 goto out_free_fattr;
 151         }
 152 
 153         ret = ops->lookupp(inode, &fh, fattr, label);
 154         if (ret) {
 155                 parent = ERR_PTR(ret);
 156                 goto out_free_label;
 157         }
 158 
 159         pinode = nfs_fhget(sb, &fh, fattr, label);
 160         parent = d_obtain_alias(pinode);
 161 out_free_label:
 162         nfs4_label_free(label);
 163 out_free_fattr:
 164         nfs_free_fattr(fattr);
 165 out:
 166         return parent;
 167 }
 168 
 169 const struct export_operations nfs_export_ops = {
 170         .encode_fh = nfs_encode_fh,
 171         .fh_to_dentry = nfs_fh_to_dentry,
 172         .get_parent = nfs_get_parent,
 173 };

/* [<][>][^][v][top][bottom][index][help] */