linux/fs/ceph/export.c
<<
>>
Prefs
   1#include <linux/ceph/ceph_debug.h>
   2
   3#include <linux/exportfs.h>
   4#include <linux/slab.h>
   5#include <asm/unaligned.h>
   6
   7#include "super.h"
   8#include "mds_client.h"
   9
  10/*
  11 * NFS export support
  12 *
  13 * NFS re-export of a ceph mount is, at present, only semireliable.
  14 * The basic issue is that the Ceph architectures doesn't lend itself
  15 * well to generating filehandles that will remain valid forever.
  16 *
  17 * So, we do our best.  If you're lucky, your inode will be in the
  18 * client's cache.  If it's not, and you have a connectable fh, then
  19 * the MDS server may be able to find it for you.  Otherwise, you get
  20 * ESTALE.
  21 *
  22 * There are ways to this more reliable, but in the non-connectable fh
  23 * case, we won't every work perfectly, and in the connectable case,
  24 * some changes are needed on the MDS side to work better.
  25 */
  26
  27/*
  28 * Basic fh
  29 */
  30struct ceph_nfs_fh {
  31        u64 ino;
  32} __attribute__ ((packed));
  33
  34/*
  35 * Larger 'connectable' fh that includes parent ino and name hash.
  36 * Use this whenever possible, as it works more reliably.
  37 */
  38struct ceph_nfs_confh {
  39        u64 ino, parent_ino;
  40        u32 parent_name_hash;
  41} __attribute__ ((packed));
  42
  43/*
  44 * The presence of @parent_inode here tells us whether NFS wants a
  45 * connectable file handle.  However, we want to make a connectionable
  46 * file handle unconditionally so that the MDS gets as much of a hint
  47 * as possible.  That means we only use @parent_dentry to indicate
  48 * whether nfsd wants a connectable fh, and whether we should indicate
  49 * failure from a too-small @max_len.
  50 */
  51static int ceph_encode_fh(struct inode *inode, u32 *rawfh, int *max_len,
  52                          struct inode *parent_inode)
  53{
  54        int type;
  55        struct ceph_nfs_fh *fh = (void *)rawfh;
  56        struct ceph_nfs_confh *cfh = (void *)rawfh;
  57        int connected_handle_length = sizeof(*cfh)/4;
  58        int handle_length = sizeof(*fh)/4;
  59        struct dentry *dentry = d_find_alias(inode);
  60        struct dentry *parent;
  61
  62        /* don't re-export snaps */
  63        if (ceph_snap(inode) != CEPH_NOSNAP)
  64                return -EINVAL;
  65
  66        /* if we found an alias, generate a connectable fh */
  67        if (*max_len >= connected_handle_length && dentry) {
  68                dout("encode_fh %p connectable\n", dentry);
  69                spin_lock(&dentry->d_lock);
  70                parent = dentry->d_parent;
  71                cfh->ino = ceph_ino(inode);
  72                cfh->parent_ino = ceph_ino(parent->d_inode);
  73                cfh->parent_name_hash = ceph_dentry_hash(parent->d_inode,
  74                                                         dentry);
  75                *max_len = connected_handle_length;
  76                type = 2;
  77                spin_unlock(&dentry->d_lock);
  78        } else if (*max_len >= handle_length) {
  79                if (parent_inode) {
  80                        /* nfsd wants connectable */
  81                        *max_len = connected_handle_length;
  82                        type = 255;
  83                } else {
  84                        dout("encode_fh %p\n", dentry);
  85                        fh->ino = ceph_ino(inode);
  86                        *max_len = handle_length;
  87                        type = 1;
  88                }
  89        } else {
  90                *max_len = handle_length;
  91                type = 255;
  92        }
  93        return type;
  94}
  95
  96/*
  97 * convert regular fh to dentry
  98 *
  99 * FIXME: we should try harder by querying the mds for the ino.
 100 */
 101static struct dentry *__fh_to_dentry(struct super_block *sb,
 102                                     struct ceph_nfs_fh *fh)
 103{
 104        struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
 105        struct inode *inode;
 106        struct dentry *dentry;
 107        struct ceph_vino vino;
 108        int err;
 109
 110        dout("__fh_to_dentry %llx\n", fh->ino);
 111        vino.ino = fh->ino;
 112        vino.snap = CEPH_NOSNAP;
 113        inode = ceph_find_inode(sb, vino);
 114        if (!inode) {
 115                struct ceph_mds_request *req;
 116
 117                req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPINO,
 118                                               USE_ANY_MDS);
 119                if (IS_ERR(req))
 120                        return ERR_CAST(req);
 121
 122                req->r_ino1 = vino;
 123                req->r_num_caps = 1;
 124                err = ceph_mdsc_do_request(mdsc, NULL, req);
 125                inode = req->r_target_inode;
 126                if (inode)
 127                        ihold(inode);
 128                ceph_mdsc_put_request(req);
 129                if (!inode)
 130                        return ERR_PTR(-ESTALE);
 131        }
 132
 133        dentry = d_obtain_alias(inode);
 134        if (IS_ERR(dentry)) {
 135                pr_err("fh_to_dentry %llx -- inode %p but ENOMEM\n",
 136                       fh->ino, inode);
 137                iput(inode);
 138                return dentry;
 139        }
 140        err = ceph_init_dentry(dentry);
 141        if (err < 0) {
 142                iput(inode);
 143                return ERR_PTR(err);
 144        }
 145        dout("__fh_to_dentry %llx %p dentry %p\n", fh->ino, inode, dentry);
 146        return dentry;
 147}
 148
 149/*
 150 * convert connectable fh to dentry
 151 */
 152static struct dentry *__cfh_to_dentry(struct super_block *sb,
 153                                      struct ceph_nfs_confh *cfh)
 154{
 155        struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
 156        struct inode *inode;
 157        struct dentry *dentry;
 158        struct ceph_vino vino;
 159        int err;
 160
 161        dout("__cfh_to_dentry %llx (%llx/%x)\n",
 162             cfh->ino, cfh->parent_ino, cfh->parent_name_hash);
 163
 164        vino.ino = cfh->ino;
 165        vino.snap = CEPH_NOSNAP;
 166        inode = ceph_find_inode(sb, vino);
 167        if (!inode) {
 168                struct ceph_mds_request *req;
 169
 170                req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPHASH,
 171                                               USE_ANY_MDS);
 172                if (IS_ERR(req))
 173                        return ERR_CAST(req);
 174
 175                req->r_ino1 = vino;
 176                req->r_ino2.ino = cfh->parent_ino;
 177                req->r_ino2.snap = CEPH_NOSNAP;
 178                req->r_path2 = kmalloc(16, GFP_NOFS);
 179                snprintf(req->r_path2, 16, "%d", cfh->parent_name_hash);
 180                req->r_num_caps = 1;
 181                err = ceph_mdsc_do_request(mdsc, NULL, req);
 182                inode = req->r_target_inode;
 183                if (inode)
 184                        ihold(inode);
 185                ceph_mdsc_put_request(req);
 186                if (!inode)
 187                        return ERR_PTR(err ? err : -ESTALE);
 188        }
 189
 190        dentry = d_obtain_alias(inode);
 191        if (IS_ERR(dentry)) {
 192                pr_err("cfh_to_dentry %llx -- inode %p but ENOMEM\n",
 193                       cfh->ino, inode);
 194                iput(inode);
 195                return dentry;
 196        }
 197        err = ceph_init_dentry(dentry);
 198        if (err < 0) {
 199                iput(inode);
 200                return ERR_PTR(err);
 201        }
 202        dout("__cfh_to_dentry %llx %p dentry %p\n", cfh->ino, inode, dentry);
 203        return dentry;
 204}
 205
 206static struct dentry *ceph_fh_to_dentry(struct super_block *sb, struct fid *fid,
 207                                        int fh_len, int fh_type)
 208{
 209        if (fh_type == 1)
 210                return __fh_to_dentry(sb, (struct ceph_nfs_fh *)fid->raw);
 211        else
 212                return __cfh_to_dentry(sb, (struct ceph_nfs_confh *)fid->raw);
 213}
 214
 215/*
 216 * get parent, if possible.
 217 *
 218 * FIXME: we could do better by querying the mds to discover the
 219 * parent.
 220 */
 221static struct dentry *ceph_fh_to_parent(struct super_block *sb,
 222                                         struct fid *fid,
 223                                        int fh_len, int fh_type)
 224{
 225        struct ceph_nfs_confh *cfh = (void *)fid->raw;
 226        struct ceph_vino vino;
 227        struct inode *inode;
 228        struct dentry *dentry;
 229        int err;
 230
 231        if (fh_type == 1)
 232                return ERR_PTR(-ESTALE);
 233
 234        pr_debug("fh_to_parent %llx/%d\n", cfh->parent_ino,
 235                 cfh->parent_name_hash);
 236
 237        vino.ino = cfh->ino;
 238        vino.snap = CEPH_NOSNAP;
 239        inode = ceph_find_inode(sb, vino);
 240        if (!inode)
 241                return ERR_PTR(-ESTALE);
 242
 243        dentry = d_obtain_alias(inode);
 244        if (IS_ERR(dentry)) {
 245                pr_err("fh_to_parent %llx -- inode %p but ENOMEM\n",
 246                       cfh->ino, inode);
 247                iput(inode);
 248                return dentry;
 249        }
 250        err = ceph_init_dentry(dentry);
 251        if (err < 0) {
 252                iput(inode);
 253                return ERR_PTR(err);
 254        }
 255        dout("fh_to_parent %llx %p dentry %p\n", cfh->ino, inode, dentry);
 256        return dentry;
 257}
 258
 259const struct export_operations ceph_export_ops = {
 260        .encode_fh = ceph_encode_fh,
 261        .fh_to_dentry = ceph_fh_to_dentry,
 262        .fh_to_parent = ceph_fh_to_parent,
 263};
 264
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.