linux/fs/ceph/export.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <linux/ceph/ceph_debug.h>
   3
   4#include <linux/exportfs.h>
   5#include <linux/slab.h>
   6#include <asm/unaligned.h>
   7
   8#include "super.h"
   9#include "mds_client.h"
  10
  11/*
  12 * Basic fh
  13 */
  14struct ceph_nfs_fh {
  15        u64 ino;
  16} __attribute__ ((packed));
  17
  18/*
  19 * Larger fh that includes parent ino.
  20 */
  21struct ceph_nfs_confh {
  22        u64 ino, parent_ino;
  23} __attribute__ ((packed));
  24
  25static int ceph_encode_fh(struct inode *inode, u32 *rawfh, int *max_len,
  26                          struct inode *parent_inode)
  27{
  28        int type;
  29        struct ceph_nfs_fh *fh = (void *)rawfh;
  30        struct ceph_nfs_confh *cfh = (void *)rawfh;
  31        int connected_handle_length = sizeof(*cfh)/4;
  32        int handle_length = sizeof(*fh)/4;
  33
  34        /* don't re-export snaps */
  35        if (ceph_snap(inode) != CEPH_NOSNAP)
  36                return -EINVAL;
  37
  38        if (parent_inode && (*max_len < connected_handle_length)) {
  39                *max_len = connected_handle_length;
  40                return FILEID_INVALID;
  41        } else if (*max_len < handle_length) {
  42                *max_len = handle_length;
  43                return FILEID_INVALID;
  44        }
  45
  46        if (parent_inode) {
  47                dout("encode_fh %llx with parent %llx\n",
  48                     ceph_ino(inode), ceph_ino(parent_inode));
  49                cfh->ino = ceph_ino(inode);
  50                cfh->parent_ino = ceph_ino(parent_inode);
  51                *max_len = connected_handle_length;
  52                type = FILEID_INO32_GEN_PARENT;
  53        } else {
  54                dout("encode_fh %llx\n", ceph_ino(inode));
  55                fh->ino = ceph_ino(inode);
  56                *max_len = handle_length;
  57                type = FILEID_INO32_GEN;
  58        }
  59        return type;
  60}
  61
  62static struct dentry *__fh_to_dentry(struct super_block *sb, u64 ino)
  63{
  64        struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
  65        struct inode *inode;
  66        struct ceph_vino vino;
  67        int err;
  68
  69        vino.ino = ino;
  70        vino.snap = CEPH_NOSNAP;
  71        inode = ceph_find_inode(sb, vino);
  72        if (!inode) {
  73                struct ceph_mds_request *req;
  74                int mask;
  75
  76                req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPINO,
  77                                               USE_ANY_MDS);
  78                if (IS_ERR(req))
  79                        return ERR_CAST(req);
  80
  81                mask = CEPH_STAT_CAP_INODE;
  82                if (ceph_security_xattr_wanted(d_inode(sb->s_root)))
  83                        mask |= CEPH_CAP_XATTR_SHARED;
  84                req->r_args.getattr.mask = cpu_to_le32(mask);
  85
  86                req->r_ino1 = vino;
  87                req->r_num_caps = 1;
  88                err = ceph_mdsc_do_request(mdsc, NULL, req);
  89                inode = req->r_target_inode;
  90                if (inode)
  91                        ihold(inode);
  92                ceph_mdsc_put_request(req);
  93                if (!inode)
  94                        return ERR_PTR(-ESTALE);
  95                if (inode->i_nlink == 0) {
  96                        iput(inode);
  97                        return ERR_PTR(-ESTALE);
  98                }
  99        }
 100
 101        return d_obtain_alias(inode);
 102}
 103
 104/*
 105 * convert regular fh to dentry
 106 */
 107static struct dentry *ceph_fh_to_dentry(struct super_block *sb,
 108                                        struct fid *fid,
 109                                        int fh_len, int fh_type)
 110{
 111        struct ceph_nfs_fh *fh = (void *)fid->raw;
 112
 113        if (fh_type != FILEID_INO32_GEN  &&
 114            fh_type != FILEID_INO32_GEN_PARENT)
 115                return NULL;
 116        if (fh_len < sizeof(*fh) / 4)
 117                return NULL;
 118
 119        dout("fh_to_dentry %llx\n", fh->ino);
 120        return __fh_to_dentry(sb, fh->ino);
 121}
 122
 123static struct dentry *__get_parent(struct super_block *sb,
 124                                   struct dentry *child, u64 ino)
 125{
 126        struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
 127        struct ceph_mds_request *req;
 128        struct inode *inode;
 129        int mask;
 130        int err;
 131
 132        req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPPARENT,
 133                                       USE_ANY_MDS);
 134        if (IS_ERR(req))
 135                return ERR_CAST(req);
 136
 137        if (child) {
 138                req->r_inode = d_inode(child);
 139                ihold(d_inode(child));
 140        } else {
 141                req->r_ino1 = (struct ceph_vino) {
 142                        .ino = ino,
 143                        .snap = CEPH_NOSNAP,
 144                };
 145        }
 146
 147        mask = CEPH_STAT_CAP_INODE;
 148        if (ceph_security_xattr_wanted(d_inode(sb->s_root)))
 149                mask |= CEPH_CAP_XATTR_SHARED;
 150        req->r_args.getattr.mask = cpu_to_le32(mask);
 151
 152        req->r_num_caps = 1;
 153        err = ceph_mdsc_do_request(mdsc, NULL, req);
 154        inode = req->r_target_inode;
 155        if (inode)
 156                ihold(inode);
 157        ceph_mdsc_put_request(req);
 158        if (!inode)
 159                return ERR_PTR(-ENOENT);
 160
 161        return d_obtain_alias(inode);
 162}
 163
 164static struct dentry *ceph_get_parent(struct dentry *child)
 165{
 166        /* don't re-export snaps */
 167        if (ceph_snap(d_inode(child)) != CEPH_NOSNAP)
 168                return ERR_PTR(-EINVAL);
 169
 170        dout("get_parent %p ino %llx.%llx\n",
 171             child, ceph_vinop(d_inode(child)));
 172        return __get_parent(child->d_sb, child, 0);
 173}
 174
 175/*
 176 * convert regular fh to parent
 177 */
 178static struct dentry *ceph_fh_to_parent(struct super_block *sb,
 179                                        struct fid *fid,
 180                                        int fh_len, int fh_type)
 181{
 182        struct ceph_nfs_confh *cfh = (void *)fid->raw;
 183        struct dentry *dentry;
 184
 185        if (fh_type != FILEID_INO32_GEN_PARENT)
 186                return NULL;
 187        if (fh_len < sizeof(*cfh) / 4)
 188                return NULL;
 189
 190        dout("fh_to_parent %llx\n", cfh->parent_ino);
 191        dentry = __get_parent(sb, NULL, cfh->ino);
 192        if (unlikely(dentry == ERR_PTR(-ENOENT)))
 193                dentry = __fh_to_dentry(sb, cfh->parent_ino);
 194        return dentry;
 195}
 196
 197static int ceph_get_name(struct dentry *parent, char *name,
 198                         struct dentry *child)
 199{
 200        struct ceph_mds_client *mdsc;
 201        struct ceph_mds_request *req;
 202        int err;
 203
 204        mdsc = ceph_inode_to_client(d_inode(child))->mdsc;
 205        req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPNAME,
 206                                       USE_ANY_MDS);
 207        if (IS_ERR(req))
 208                return PTR_ERR(req);
 209
 210        inode_lock(d_inode(parent));
 211
 212        req->r_inode = d_inode(child);
 213        ihold(d_inode(child));
 214        req->r_ino2 = ceph_vino(d_inode(parent));
 215        req->r_parent = d_inode(parent);
 216        set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags);
 217        req->r_num_caps = 2;
 218        err = ceph_mdsc_do_request(mdsc, NULL, req);
 219
 220        inode_unlock(d_inode(parent));
 221
 222        if (!err) {
 223                struct ceph_mds_reply_info_parsed *rinfo = &req->r_reply_info;
 224                memcpy(name, rinfo->dname, rinfo->dname_len);
 225                name[rinfo->dname_len] = 0;
 226                dout("get_name %p ino %llx.%llx name %s\n",
 227                     child, ceph_vinop(d_inode(child)), name);
 228        } else {
 229                dout("get_name %p ino %llx.%llx err %d\n",
 230                     child, ceph_vinop(d_inode(child)), err);
 231        }
 232
 233        ceph_mdsc_put_request(req);
 234        return err;
 235}
 236
 237const struct export_operations ceph_export_ops = {
 238        .encode_fh = ceph_encode_fh,
 239        .fh_to_dentry = ceph_fh_to_dentry,
 240        .fh_to_parent = ceph_fh_to_parent,
 241        .get_parent = ceph_get_parent,
 242        .get_name = ceph_get_name,
 243};
 244