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