0001
0002 #include <linux/ceph/ceph_debug.h>
0003
0004 #include <linux/exportfs.h>
0005 #include <linux/slab.h>
0006 #include <asm/unaligned.h>
0007
0008 #include "super.h"
0009 #include "mds_client.h"
0010
0011
0012
0013
0014 struct ceph_nfs_fh {
0015 u64 ino;
0016 } __attribute__ ((packed));
0017
0018
0019
0020
0021 struct ceph_nfs_confh {
0022 u64 ino, parent_ino;
0023 } __attribute__ ((packed));
0024
0025
0026
0027
0028 struct ceph_nfs_snapfh {
0029 u64 ino;
0030 u64 snapid;
0031 u64 parent_ino;
0032 u32 hash;
0033 } __attribute__ ((packed));
0034
0035 static int ceph_encode_snapfh(struct inode *inode, u32 *rawfh, int *max_len,
0036 struct inode *parent_inode)
0037 {
0038 static const int snap_handle_length =
0039 sizeof(struct ceph_nfs_snapfh) >> 2;
0040 struct ceph_nfs_snapfh *sfh = (void *)rawfh;
0041 u64 snapid = ceph_snap(inode);
0042 int ret;
0043 bool no_parent = true;
0044
0045 if (*max_len < snap_handle_length) {
0046 *max_len = snap_handle_length;
0047 ret = FILEID_INVALID;
0048 goto out;
0049 }
0050
0051 ret = -EINVAL;
0052 if (snapid != CEPH_SNAPDIR) {
0053 struct inode *dir;
0054 struct dentry *dentry = d_find_alias(inode);
0055 if (!dentry)
0056 goto out;
0057
0058 rcu_read_lock();
0059 dir = d_inode_rcu(dentry->d_parent);
0060 if (ceph_snap(dir) != CEPH_SNAPDIR) {
0061 sfh->parent_ino = ceph_ino(dir);
0062 sfh->hash = ceph_dentry_hash(dir, dentry);
0063 no_parent = false;
0064 }
0065 rcu_read_unlock();
0066 dput(dentry);
0067 }
0068
0069 if (no_parent) {
0070 if (!S_ISDIR(inode->i_mode))
0071 goto out;
0072 sfh->parent_ino = sfh->ino;
0073 sfh->hash = 0;
0074 }
0075 sfh->ino = ceph_ino(inode);
0076 sfh->snapid = snapid;
0077
0078 *max_len = snap_handle_length;
0079 ret = FILEID_BTRFS_WITH_PARENT;
0080 out:
0081 dout("encode_snapfh %llx.%llx ret=%d\n", ceph_vinop(inode), ret);
0082 return ret;
0083 }
0084
0085 static int ceph_encode_fh(struct inode *inode, u32 *rawfh, int *max_len,
0086 struct inode *parent_inode)
0087 {
0088 static const int handle_length =
0089 sizeof(struct ceph_nfs_fh) >> 2;
0090 static const int connected_handle_length =
0091 sizeof(struct ceph_nfs_confh) >> 2;
0092 int type;
0093
0094 if (ceph_snap(inode) != CEPH_NOSNAP)
0095 return ceph_encode_snapfh(inode, rawfh, max_len, parent_inode);
0096
0097 if (parent_inode && (*max_len < connected_handle_length)) {
0098 *max_len = connected_handle_length;
0099 return FILEID_INVALID;
0100 } else if (*max_len < handle_length) {
0101 *max_len = handle_length;
0102 return FILEID_INVALID;
0103 }
0104
0105 if (parent_inode) {
0106 struct ceph_nfs_confh *cfh = (void *)rawfh;
0107 dout("encode_fh %llx with parent %llx\n",
0108 ceph_ino(inode), ceph_ino(parent_inode));
0109 cfh->ino = ceph_ino(inode);
0110 cfh->parent_ino = ceph_ino(parent_inode);
0111 *max_len = connected_handle_length;
0112 type = FILEID_INO32_GEN_PARENT;
0113 } else {
0114 struct ceph_nfs_fh *fh = (void *)rawfh;
0115 dout("encode_fh %llx\n", ceph_ino(inode));
0116 fh->ino = ceph_ino(inode);
0117 *max_len = handle_length;
0118 type = FILEID_INO32_GEN;
0119 }
0120 return type;
0121 }
0122
0123 static struct inode *__lookup_inode(struct super_block *sb, u64 ino)
0124 {
0125 struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
0126 struct inode *inode;
0127 struct ceph_vino vino;
0128 int err;
0129
0130 vino.ino = ino;
0131 vino.snap = CEPH_NOSNAP;
0132
0133 if (ceph_vino_is_reserved(vino))
0134 return ERR_PTR(-ESTALE);
0135
0136 inode = ceph_find_inode(sb, vino);
0137 if (!inode) {
0138 struct ceph_mds_request *req;
0139 int mask;
0140
0141 req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPINO,
0142 USE_ANY_MDS);
0143 if (IS_ERR(req))
0144 return ERR_CAST(req);
0145
0146 mask = CEPH_STAT_CAP_INODE;
0147 if (ceph_security_xattr_wanted(d_inode(sb->s_root)))
0148 mask |= CEPH_CAP_XATTR_SHARED;
0149 req->r_args.lookupino.mask = cpu_to_le32(mask);
0150
0151 req->r_ino1 = vino;
0152 req->r_num_caps = 1;
0153 err = ceph_mdsc_do_request(mdsc, NULL, req);
0154 inode = req->r_target_inode;
0155 if (inode)
0156 ihold(inode);
0157 ceph_mdsc_put_request(req);
0158 if (!inode)
0159 return err < 0 ? ERR_PTR(err) : ERR_PTR(-ESTALE);
0160 } else {
0161 if (ceph_inode_is_shutdown(inode)) {
0162 iput(inode);
0163 return ERR_PTR(-ESTALE);
0164 }
0165 }
0166 return inode;
0167 }
0168
0169 struct inode *ceph_lookup_inode(struct super_block *sb, u64 ino)
0170 {
0171 struct inode *inode = __lookup_inode(sb, ino);
0172 if (IS_ERR(inode))
0173 return inode;
0174 if (inode->i_nlink == 0) {
0175 iput(inode);
0176 return ERR_PTR(-ESTALE);
0177 }
0178 return inode;
0179 }
0180
0181 static struct dentry *__fh_to_dentry(struct super_block *sb, u64 ino)
0182 {
0183 struct inode *inode = __lookup_inode(sb, ino);
0184 int err;
0185
0186 if (IS_ERR(inode))
0187 return ERR_CAST(inode);
0188
0189 err = ceph_do_getattr(inode, CEPH_CAP_LINK_SHARED, false);
0190 if (err) {
0191 iput(inode);
0192 return ERR_PTR(err);
0193 }
0194
0195 if ((inode->i_nlink == 0) && (atomic_read(&inode->i_count) == 1)) {
0196 iput(inode);
0197 return ERR_PTR(-ESTALE);
0198 }
0199 return d_obtain_alias(inode);
0200 }
0201
0202 static struct dentry *__snapfh_to_dentry(struct super_block *sb,
0203 struct ceph_nfs_snapfh *sfh,
0204 bool want_parent)
0205 {
0206 struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
0207 struct ceph_mds_request *req;
0208 struct inode *inode;
0209 struct ceph_vino vino;
0210 int mask;
0211 int err;
0212 bool unlinked = false;
0213
0214 if (want_parent) {
0215 vino.ino = sfh->parent_ino;
0216 if (sfh->snapid == CEPH_SNAPDIR)
0217 vino.snap = CEPH_NOSNAP;
0218 else if (sfh->ino == sfh->parent_ino)
0219 vino.snap = CEPH_SNAPDIR;
0220 else
0221 vino.snap = sfh->snapid;
0222 } else {
0223 vino.ino = sfh->ino;
0224 vino.snap = sfh->snapid;
0225 }
0226
0227 if (ceph_vino_is_reserved(vino))
0228 return ERR_PTR(-ESTALE);
0229
0230 inode = ceph_find_inode(sb, vino);
0231 if (inode) {
0232 if (ceph_inode_is_shutdown(inode)) {
0233 iput(inode);
0234 return ERR_PTR(-ESTALE);
0235 }
0236 return d_obtain_alias(inode);
0237 }
0238
0239 req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPINO,
0240 USE_ANY_MDS);
0241 if (IS_ERR(req))
0242 return ERR_CAST(req);
0243
0244 mask = CEPH_STAT_CAP_INODE;
0245 if (ceph_security_xattr_wanted(d_inode(sb->s_root)))
0246 mask |= CEPH_CAP_XATTR_SHARED;
0247 req->r_args.lookupino.mask = cpu_to_le32(mask);
0248 if (vino.snap < CEPH_NOSNAP) {
0249 req->r_args.lookupino.snapid = cpu_to_le64(vino.snap);
0250 if (!want_parent && sfh->ino != sfh->parent_ino) {
0251 req->r_args.lookupino.parent =
0252 cpu_to_le64(sfh->parent_ino);
0253 req->r_args.lookupino.hash =
0254 cpu_to_le32(sfh->hash);
0255 }
0256 }
0257
0258 req->r_ino1 = vino;
0259 req->r_num_caps = 1;
0260 err = ceph_mdsc_do_request(mdsc, NULL, req);
0261 inode = req->r_target_inode;
0262 if (inode) {
0263 if (vino.snap == CEPH_SNAPDIR) {
0264 if (inode->i_nlink == 0)
0265 unlinked = true;
0266 inode = ceph_get_snapdir(inode);
0267 } else if (ceph_snap(inode) == vino.snap) {
0268 ihold(inode);
0269 } else {
0270
0271 inode = ERR_PTR(-EOPNOTSUPP);
0272 }
0273 } else {
0274 inode = ERR_PTR(-ESTALE);
0275 }
0276 ceph_mdsc_put_request(req);
0277
0278 if (want_parent) {
0279 dout("snapfh_to_parent %llx.%llx\n err=%d\n",
0280 vino.ino, vino.snap, err);
0281 } else {
0282 dout("snapfh_to_dentry %llx.%llx parent %llx hash %x err=%d",
0283 vino.ino, vino.snap, sfh->parent_ino, sfh->hash, err);
0284 }
0285 if (IS_ERR(inode))
0286 return ERR_CAST(inode);
0287
0288 return unlinked ? d_obtain_root(inode) : d_obtain_alias(inode);
0289 }
0290
0291
0292
0293
0294 static struct dentry *ceph_fh_to_dentry(struct super_block *sb,
0295 struct fid *fid,
0296 int fh_len, int fh_type)
0297 {
0298 struct ceph_nfs_fh *fh = (void *)fid->raw;
0299
0300 if (fh_type == FILEID_BTRFS_WITH_PARENT) {
0301 struct ceph_nfs_snapfh *sfh = (void *)fid->raw;
0302 return __snapfh_to_dentry(sb, sfh, false);
0303 }
0304
0305 if (fh_type != FILEID_INO32_GEN &&
0306 fh_type != FILEID_INO32_GEN_PARENT)
0307 return NULL;
0308 if (fh_len < sizeof(*fh) / 4)
0309 return NULL;
0310
0311 dout("fh_to_dentry %llx\n", fh->ino);
0312 return __fh_to_dentry(sb, fh->ino);
0313 }
0314
0315 static struct dentry *__get_parent(struct super_block *sb,
0316 struct dentry *child, u64 ino)
0317 {
0318 struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
0319 struct ceph_mds_request *req;
0320 struct inode *inode;
0321 int mask;
0322 int err;
0323
0324 req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPPARENT,
0325 USE_ANY_MDS);
0326 if (IS_ERR(req))
0327 return ERR_CAST(req);
0328
0329 if (child) {
0330 req->r_inode = d_inode(child);
0331 ihold(d_inode(child));
0332 } else {
0333 req->r_ino1 = (struct ceph_vino) {
0334 .ino = ino,
0335 .snap = CEPH_NOSNAP,
0336 };
0337 }
0338
0339 mask = CEPH_STAT_CAP_INODE;
0340 if (ceph_security_xattr_wanted(d_inode(sb->s_root)))
0341 mask |= CEPH_CAP_XATTR_SHARED;
0342 req->r_args.getattr.mask = cpu_to_le32(mask);
0343
0344 req->r_num_caps = 1;
0345 err = ceph_mdsc_do_request(mdsc, NULL, req);
0346 if (err) {
0347 ceph_mdsc_put_request(req);
0348 return ERR_PTR(err);
0349 }
0350
0351 inode = req->r_target_inode;
0352 if (inode)
0353 ihold(inode);
0354 ceph_mdsc_put_request(req);
0355 if (!inode)
0356 return ERR_PTR(-ENOENT);
0357
0358 return d_obtain_alias(inode);
0359 }
0360
0361 static struct dentry *ceph_get_parent(struct dentry *child)
0362 {
0363 struct inode *inode = d_inode(child);
0364 struct dentry *dn;
0365
0366 if (ceph_snap(inode) != CEPH_NOSNAP) {
0367 struct inode* dir;
0368 bool unlinked = false;
0369
0370 if (!d_is_dir(child)) {
0371 dn = ERR_PTR(-EINVAL);
0372 goto out;
0373 }
0374 dir = __lookup_inode(inode->i_sb, ceph_ino(inode));
0375 if (IS_ERR(dir)) {
0376 dn = ERR_CAST(dir);
0377 goto out;
0378 }
0379
0380
0381 if (ceph_snap(inode) != CEPH_SNAPDIR) {
0382 struct inode *snapdir = ceph_get_snapdir(dir);
0383 if (dir->i_nlink == 0)
0384 unlinked = true;
0385 iput(dir);
0386 if (IS_ERR(snapdir)) {
0387 dn = ERR_CAST(snapdir);
0388 goto out;
0389 }
0390 dir = snapdir;
0391 }
0392
0393
0394
0395 if (unlinked)
0396 dn = d_obtain_root(dir);
0397 else
0398 dn = d_obtain_alias(dir);
0399 } else {
0400 dn = __get_parent(child->d_sb, child, 0);
0401 }
0402 out:
0403 dout("get_parent %p ino %llx.%llx err=%ld\n",
0404 child, ceph_vinop(inode), (long)PTR_ERR_OR_ZERO(dn));
0405 return dn;
0406 }
0407
0408
0409
0410
0411 static struct dentry *ceph_fh_to_parent(struct super_block *sb,
0412 struct fid *fid,
0413 int fh_len, int fh_type)
0414 {
0415 struct ceph_nfs_confh *cfh = (void *)fid->raw;
0416 struct dentry *dentry;
0417
0418 if (fh_type == FILEID_BTRFS_WITH_PARENT) {
0419 struct ceph_nfs_snapfh *sfh = (void *)fid->raw;
0420 return __snapfh_to_dentry(sb, sfh, true);
0421 }
0422
0423 if (fh_type != FILEID_INO32_GEN_PARENT)
0424 return NULL;
0425 if (fh_len < sizeof(*cfh) / 4)
0426 return NULL;
0427
0428 dout("fh_to_parent %llx\n", cfh->parent_ino);
0429 dentry = __get_parent(sb, NULL, cfh->ino);
0430 if (unlikely(dentry == ERR_PTR(-ENOENT)))
0431 dentry = __fh_to_dentry(sb, cfh->parent_ino);
0432 return dentry;
0433 }
0434
0435 static int __get_snap_name(struct dentry *parent, char *name,
0436 struct dentry *child)
0437 {
0438 struct inode *inode = d_inode(child);
0439 struct inode *dir = d_inode(parent);
0440 struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
0441 struct ceph_mds_request *req = NULL;
0442 char *last_name = NULL;
0443 unsigned next_offset = 2;
0444 int err = -EINVAL;
0445
0446 if (ceph_ino(inode) != ceph_ino(dir))
0447 goto out;
0448 if (ceph_snap(inode) == CEPH_SNAPDIR) {
0449 if (ceph_snap(dir) == CEPH_NOSNAP) {
0450 strcpy(name, fsc->mount_options->snapdir_name);
0451 err = 0;
0452 }
0453 goto out;
0454 }
0455 if (ceph_snap(dir) != CEPH_SNAPDIR)
0456 goto out;
0457
0458 while (1) {
0459 struct ceph_mds_reply_info_parsed *rinfo;
0460 struct ceph_mds_reply_dir_entry *rde;
0461 int i;
0462
0463 req = ceph_mdsc_create_request(fsc->mdsc, CEPH_MDS_OP_LSSNAP,
0464 USE_AUTH_MDS);
0465 if (IS_ERR(req)) {
0466 err = PTR_ERR(req);
0467 req = NULL;
0468 goto out;
0469 }
0470 err = ceph_alloc_readdir_reply_buffer(req, inode);
0471 if (err)
0472 goto out;
0473
0474 req->r_direct_mode = USE_AUTH_MDS;
0475 req->r_readdir_offset = next_offset;
0476 req->r_args.readdir.flags =
0477 cpu_to_le16(CEPH_READDIR_REPLY_BITFLAGS);
0478 if (last_name) {
0479 req->r_path2 = last_name;
0480 last_name = NULL;
0481 }
0482
0483 req->r_inode = dir;
0484 ihold(dir);
0485 req->r_dentry = dget(parent);
0486
0487 inode_lock(dir);
0488 err = ceph_mdsc_do_request(fsc->mdsc, NULL, req);
0489 inode_unlock(dir);
0490
0491 if (err < 0)
0492 goto out;
0493
0494 rinfo = &req->r_reply_info;
0495 for (i = 0; i < rinfo->dir_nr; i++) {
0496 rde = rinfo->dir_entries + i;
0497 BUG_ON(!rde->inode.in);
0498 if (ceph_snap(inode) ==
0499 le64_to_cpu(rde->inode.in->snapid)) {
0500 memcpy(name, rde->name, rde->name_len);
0501 name[rde->name_len] = '\0';
0502 err = 0;
0503 goto out;
0504 }
0505 }
0506
0507 if (rinfo->dir_end)
0508 break;
0509
0510 BUG_ON(rinfo->dir_nr <= 0);
0511 rde = rinfo->dir_entries + (rinfo->dir_nr - 1);
0512 next_offset += rinfo->dir_nr;
0513 last_name = kstrndup(rde->name, rde->name_len, GFP_KERNEL);
0514 if (!last_name) {
0515 err = -ENOMEM;
0516 goto out;
0517 }
0518
0519 ceph_mdsc_put_request(req);
0520 req = NULL;
0521 }
0522 err = -ENOENT;
0523 out:
0524 if (req)
0525 ceph_mdsc_put_request(req);
0526 kfree(last_name);
0527 dout("get_snap_name %p ino %llx.%llx err=%d\n",
0528 child, ceph_vinop(inode), err);
0529 return err;
0530 }
0531
0532 static int ceph_get_name(struct dentry *parent, char *name,
0533 struct dentry *child)
0534 {
0535 struct ceph_mds_client *mdsc;
0536 struct ceph_mds_request *req;
0537 struct inode *inode = d_inode(child);
0538 int err;
0539
0540 if (ceph_snap(inode) != CEPH_NOSNAP)
0541 return __get_snap_name(parent, name, child);
0542
0543 mdsc = ceph_inode_to_client(inode)->mdsc;
0544 req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPNAME,
0545 USE_ANY_MDS);
0546 if (IS_ERR(req))
0547 return PTR_ERR(req);
0548
0549 inode_lock(d_inode(parent));
0550
0551 req->r_inode = inode;
0552 ihold(inode);
0553 req->r_ino2 = ceph_vino(d_inode(parent));
0554 req->r_parent = d_inode(parent);
0555 ihold(req->r_parent);
0556 set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags);
0557 req->r_num_caps = 2;
0558 err = ceph_mdsc_do_request(mdsc, NULL, req);
0559
0560 inode_unlock(d_inode(parent));
0561
0562 if (!err) {
0563 struct ceph_mds_reply_info_parsed *rinfo = &req->r_reply_info;
0564 memcpy(name, rinfo->dname, rinfo->dname_len);
0565 name[rinfo->dname_len] = 0;
0566 dout("get_name %p ino %llx.%llx name %s\n",
0567 child, ceph_vinop(inode), name);
0568 } else {
0569 dout("get_name %p ino %llx.%llx err %d\n",
0570 child, ceph_vinop(inode), err);
0571 }
0572
0573 ceph_mdsc_put_request(req);
0574 return err;
0575 }
0576
0577 const struct export_operations ceph_export_ops = {
0578 .encode_fh = ceph_encode_fh,
0579 .fh_to_dentry = ceph_fh_to_dentry,
0580 .fh_to_parent = ceph_fh_to_parent,
0581 .get_parent = ceph_get_parent,
0582 .get_name = ceph_get_name,
0583 };