export.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include <linux/ceph/ceph_debug.h>
  3. #include <linux/exportfs.h>
  4. #include <linux/slab.h>
  5. #include <asm/unaligned.h>
  6. #include "super.h"
  7. #include "mds_client.h"
  8. /*
  9. * Basic fh
  10. */
  11. struct ceph_nfs_fh {
  12. u64 ino;
  13. } __attribute__ ((packed));
  14. /*
  15. * Larger fh that includes parent ino.
  16. */
  17. struct ceph_nfs_confh {
  18. u64 ino, parent_ino;
  19. } __attribute__ ((packed));
  20. /*
  21. * fh for snapped inode
  22. */
  23. struct ceph_nfs_snapfh {
  24. u64 ino;
  25. u64 snapid;
  26. u64 parent_ino;
  27. u32 hash;
  28. } __attribute__ ((packed));
  29. static int ceph_encode_snapfh(struct inode *inode, u32 *rawfh, int *max_len,
  30. struct inode *parent_inode)
  31. {
  32. static const int snap_handle_length =
  33. sizeof(struct ceph_nfs_snapfh) >> 2;
  34. struct ceph_nfs_snapfh *sfh = (void *)rawfh;
  35. u64 snapid = ceph_snap(inode);
  36. int ret;
  37. bool no_parent = true;
  38. if (*max_len < snap_handle_length) {
  39. *max_len = snap_handle_length;
  40. ret = FILEID_INVALID;
  41. goto out;
  42. }
  43. ret = -EINVAL;
  44. if (snapid != CEPH_SNAPDIR) {
  45. struct inode *dir;
  46. struct dentry *dentry = d_find_alias(inode);
  47. if (!dentry)
  48. goto out;
  49. rcu_read_lock();
  50. dir = d_inode_rcu(dentry->d_parent);
  51. if (ceph_snap(dir) != CEPH_SNAPDIR) {
  52. sfh->parent_ino = ceph_ino(dir);
  53. sfh->hash = ceph_dentry_hash(dir, dentry);
  54. no_parent = false;
  55. }
  56. rcu_read_unlock();
  57. dput(dentry);
  58. }
  59. if (no_parent) {
  60. if (!S_ISDIR(inode->i_mode))
  61. goto out;
  62. sfh->parent_ino = sfh->ino;
  63. sfh->hash = 0;
  64. }
  65. sfh->ino = ceph_ino(inode);
  66. sfh->snapid = snapid;
  67. *max_len = snap_handle_length;
  68. ret = FILEID_BTRFS_WITH_PARENT;
  69. out:
  70. dout("encode_snapfh %llx.%llx ret=%d\n", ceph_vinop(inode), ret);
  71. return ret;
  72. }
  73. static int ceph_encode_fh(struct inode *inode, u32 *rawfh, int *max_len,
  74. struct inode *parent_inode)
  75. {
  76. static const int handle_length =
  77. sizeof(struct ceph_nfs_fh) >> 2;
  78. static const int connected_handle_length =
  79. sizeof(struct ceph_nfs_confh) >> 2;
  80. int type;
  81. if (ceph_snap(inode) != CEPH_NOSNAP)
  82. return ceph_encode_snapfh(inode, rawfh, max_len, parent_inode);
  83. if (parent_inode && (*max_len < connected_handle_length)) {
  84. *max_len = connected_handle_length;
  85. return FILEID_INVALID;
  86. } else if (*max_len < handle_length) {
  87. *max_len = handle_length;
  88. return FILEID_INVALID;
  89. }
  90. if (parent_inode) {
  91. struct ceph_nfs_confh *cfh = (void *)rawfh;
  92. dout("encode_fh %llx with parent %llx\n",
  93. ceph_ino(inode), ceph_ino(parent_inode));
  94. cfh->ino = ceph_ino(inode);
  95. cfh->parent_ino = ceph_ino(parent_inode);
  96. *max_len = connected_handle_length;
  97. type = FILEID_INO32_GEN_PARENT;
  98. } else {
  99. struct ceph_nfs_fh *fh = (void *)rawfh;
  100. dout("encode_fh %llx\n", ceph_ino(inode));
  101. fh->ino = ceph_ino(inode);
  102. *max_len = handle_length;
  103. type = FILEID_INO32_GEN;
  104. }
  105. return type;
  106. }
  107. static struct inode *__lookup_inode(struct super_block *sb, u64 ino)
  108. {
  109. struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
  110. struct inode *inode;
  111. struct ceph_vino vino;
  112. int err;
  113. vino.ino = ino;
  114. vino.snap = CEPH_NOSNAP;
  115. if (ceph_vino_is_reserved(vino))
  116. return ERR_PTR(-ESTALE);
  117. inode = ceph_find_inode(sb, vino);
  118. if (!inode) {
  119. struct ceph_mds_request *req;
  120. int mask;
  121. req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPINO,
  122. USE_ANY_MDS);
  123. if (IS_ERR(req))
  124. return ERR_CAST(req);
  125. mask = CEPH_STAT_CAP_INODE;
  126. if (ceph_security_xattr_wanted(d_inode(sb->s_root)))
  127. mask |= CEPH_CAP_XATTR_SHARED;
  128. req->r_args.lookupino.mask = cpu_to_le32(mask);
  129. req->r_ino1 = vino;
  130. req->r_num_caps = 1;
  131. err = ceph_mdsc_do_request(mdsc, NULL, req);
  132. inode = req->r_target_inode;
  133. if (inode)
  134. ihold(inode);
  135. ceph_mdsc_put_request(req);
  136. if (!inode)
  137. return err < 0 ? ERR_PTR(err) : ERR_PTR(-ESTALE);
  138. }
  139. return inode;
  140. }
  141. struct inode *ceph_lookup_inode(struct super_block *sb, u64 ino)
  142. {
  143. struct inode *inode = __lookup_inode(sb, ino);
  144. if (IS_ERR(inode))
  145. return inode;
  146. if (inode->i_nlink == 0) {
  147. iput(inode);
  148. return ERR_PTR(-ESTALE);
  149. }
  150. return inode;
  151. }
  152. static struct dentry *__fh_to_dentry(struct super_block *sb, u64 ino)
  153. {
  154. struct inode *inode = __lookup_inode(sb, ino);
  155. int err;
  156. if (IS_ERR(inode))
  157. return ERR_CAST(inode);
  158. /* We need LINK caps to reliably check i_nlink */
  159. err = ceph_do_getattr(inode, CEPH_CAP_LINK_SHARED, false);
  160. if (err) {
  161. iput(inode);
  162. return ERR_PTR(err);
  163. }
  164. /* -ESTALE if inode as been unlinked and no file is open */
  165. if ((inode->i_nlink == 0) && (atomic_read(&inode->i_count) == 1)) {
  166. iput(inode);
  167. return ERR_PTR(-ESTALE);
  168. }
  169. return d_obtain_alias(inode);
  170. }
  171. static struct dentry *__snapfh_to_dentry(struct super_block *sb,
  172. struct ceph_nfs_snapfh *sfh,
  173. bool want_parent)
  174. {
  175. struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
  176. struct ceph_mds_request *req;
  177. struct inode *inode;
  178. struct ceph_vino vino;
  179. int mask;
  180. int err;
  181. bool unlinked = false;
  182. if (want_parent) {
  183. vino.ino = sfh->parent_ino;
  184. if (sfh->snapid == CEPH_SNAPDIR)
  185. vino.snap = CEPH_NOSNAP;
  186. else if (sfh->ino == sfh->parent_ino)
  187. vino.snap = CEPH_SNAPDIR;
  188. else
  189. vino.snap = sfh->snapid;
  190. } else {
  191. vino.ino = sfh->ino;
  192. vino.snap = sfh->snapid;
  193. }
  194. if (ceph_vino_is_reserved(vino))
  195. return ERR_PTR(-ESTALE);
  196. inode = ceph_find_inode(sb, vino);
  197. if (inode)
  198. return d_obtain_alias(inode);
  199. req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPINO,
  200. USE_ANY_MDS);
  201. if (IS_ERR(req))
  202. return ERR_CAST(req);
  203. mask = CEPH_STAT_CAP_INODE;
  204. if (ceph_security_xattr_wanted(d_inode(sb->s_root)))
  205. mask |= CEPH_CAP_XATTR_SHARED;
  206. req->r_args.lookupino.mask = cpu_to_le32(mask);
  207. if (vino.snap < CEPH_NOSNAP) {
  208. req->r_args.lookupino.snapid = cpu_to_le64(vino.snap);
  209. if (!want_parent && sfh->ino != sfh->parent_ino) {
  210. req->r_args.lookupino.parent =
  211. cpu_to_le64(sfh->parent_ino);
  212. req->r_args.lookupino.hash =
  213. cpu_to_le32(sfh->hash);
  214. }
  215. }
  216. req->r_ino1 = vino;
  217. req->r_num_caps = 1;
  218. err = ceph_mdsc_do_request(mdsc, NULL, req);
  219. inode = req->r_target_inode;
  220. if (inode) {
  221. if (vino.snap == CEPH_SNAPDIR) {
  222. if (inode->i_nlink == 0)
  223. unlinked = true;
  224. inode = ceph_get_snapdir(inode);
  225. } else if (ceph_snap(inode) == vino.snap) {
  226. ihold(inode);
  227. } else {
  228. /* mds does not support lookup snapped inode */
  229. err = -EOPNOTSUPP;
  230. inode = NULL;
  231. }
  232. }
  233. ceph_mdsc_put_request(req);
  234. if (want_parent) {
  235. dout("snapfh_to_parent %llx.%llx\n err=%d\n",
  236. vino.ino, vino.snap, err);
  237. } else {
  238. dout("snapfh_to_dentry %llx.%llx parent %llx hash %x err=%d",
  239. vino.ino, vino.snap, sfh->parent_ino, sfh->hash, err);
  240. }
  241. if (!inode)
  242. return ERR_PTR(-ESTALE);
  243. /* see comments in ceph_get_parent() */
  244. return unlinked ? d_obtain_root(inode) : d_obtain_alias(inode);
  245. }
  246. /*
  247. * convert regular fh to dentry
  248. */
  249. static struct dentry *ceph_fh_to_dentry(struct super_block *sb,
  250. struct fid *fid,
  251. int fh_len, int fh_type)
  252. {
  253. struct ceph_nfs_fh *fh = (void *)fid->raw;
  254. if (fh_type == FILEID_BTRFS_WITH_PARENT) {
  255. struct ceph_nfs_snapfh *sfh = (void *)fid->raw;
  256. return __snapfh_to_dentry(sb, sfh, false);
  257. }
  258. if (fh_type != FILEID_INO32_GEN &&
  259. fh_type != FILEID_INO32_GEN_PARENT)
  260. return NULL;
  261. if (fh_len < sizeof(*fh) / 4)
  262. return NULL;
  263. dout("fh_to_dentry %llx\n", fh->ino);
  264. return __fh_to_dentry(sb, fh->ino);
  265. }
  266. static struct dentry *__get_parent(struct super_block *sb,
  267. struct dentry *child, u64 ino)
  268. {
  269. struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
  270. struct ceph_mds_request *req;
  271. struct inode *inode;
  272. int mask;
  273. int err;
  274. req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPPARENT,
  275. USE_ANY_MDS);
  276. if (IS_ERR(req))
  277. return ERR_CAST(req);
  278. if (child) {
  279. req->r_inode = d_inode(child);
  280. ihold(d_inode(child));
  281. } else {
  282. req->r_ino1 = (struct ceph_vino) {
  283. .ino = ino,
  284. .snap = CEPH_NOSNAP,
  285. };
  286. }
  287. mask = CEPH_STAT_CAP_INODE;
  288. if (ceph_security_xattr_wanted(d_inode(sb->s_root)))
  289. mask |= CEPH_CAP_XATTR_SHARED;
  290. req->r_args.getattr.mask = cpu_to_le32(mask);
  291. req->r_num_caps = 1;
  292. err = ceph_mdsc_do_request(mdsc, NULL, req);
  293. if (err) {
  294. ceph_mdsc_put_request(req);
  295. return ERR_PTR(err);
  296. }
  297. inode = req->r_target_inode;
  298. if (inode)
  299. ihold(inode);
  300. ceph_mdsc_put_request(req);
  301. if (!inode)
  302. return ERR_PTR(-ENOENT);
  303. return d_obtain_alias(inode);
  304. }
  305. static struct dentry *ceph_get_parent(struct dentry *child)
  306. {
  307. struct inode *inode = d_inode(child);
  308. struct dentry *dn;
  309. if (ceph_snap(inode) != CEPH_NOSNAP) {
  310. struct inode* dir;
  311. bool unlinked = false;
  312. /* do not support non-directory */
  313. if (!d_is_dir(child)) {
  314. dn = ERR_PTR(-EINVAL);
  315. goto out;
  316. }
  317. dir = __lookup_inode(inode->i_sb, ceph_ino(inode));
  318. if (IS_ERR(dir)) {
  319. dn = ERR_CAST(dir);
  320. goto out;
  321. }
  322. /* There can be multiple paths to access snapped inode.
  323. * For simplicity, treat snapdir of head inode as parent */
  324. if (ceph_snap(inode) != CEPH_SNAPDIR) {
  325. struct inode *snapdir = ceph_get_snapdir(dir);
  326. if (dir->i_nlink == 0)
  327. unlinked = true;
  328. iput(dir);
  329. if (IS_ERR(snapdir)) {
  330. dn = ERR_CAST(snapdir);
  331. goto out;
  332. }
  333. dir = snapdir;
  334. }
  335. /* If directory has already been deleted, futher get_parent
  336. * will fail. Do not mark snapdir dentry as disconnected,
  337. * this prevent exportfs from doing futher get_parent. */
  338. if (unlinked)
  339. dn = d_obtain_root(dir);
  340. else
  341. dn = d_obtain_alias(dir);
  342. } else {
  343. dn = __get_parent(child->d_sb, child, 0);
  344. }
  345. out:
  346. dout("get_parent %p ino %llx.%llx err=%ld\n",
  347. child, ceph_vinop(inode), (long)PTR_ERR_OR_ZERO(dn));
  348. return dn;
  349. }
  350. /*
  351. * convert regular fh to parent
  352. */
  353. static struct dentry *ceph_fh_to_parent(struct super_block *sb,
  354. struct fid *fid,
  355. int fh_len, int fh_type)
  356. {
  357. struct ceph_nfs_confh *cfh = (void *)fid->raw;
  358. struct dentry *dentry;
  359. if (fh_type == FILEID_BTRFS_WITH_PARENT) {
  360. struct ceph_nfs_snapfh *sfh = (void *)fid->raw;
  361. return __snapfh_to_dentry(sb, sfh, true);
  362. }
  363. if (fh_type != FILEID_INO32_GEN_PARENT)
  364. return NULL;
  365. if (fh_len < sizeof(*cfh) / 4)
  366. return NULL;
  367. dout("fh_to_parent %llx\n", cfh->parent_ino);
  368. dentry = __get_parent(sb, NULL, cfh->ino);
  369. if (unlikely(dentry == ERR_PTR(-ENOENT)))
  370. dentry = __fh_to_dentry(sb, cfh->parent_ino);
  371. return dentry;
  372. }
  373. static int __get_snap_name(struct dentry *parent, char *name,
  374. struct dentry *child)
  375. {
  376. struct inode *inode = d_inode(child);
  377. struct inode *dir = d_inode(parent);
  378. struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
  379. struct ceph_mds_request *req = NULL;
  380. char *last_name = NULL;
  381. unsigned next_offset = 2;
  382. int err = -EINVAL;
  383. if (ceph_ino(inode) != ceph_ino(dir))
  384. goto out;
  385. if (ceph_snap(inode) == CEPH_SNAPDIR) {
  386. if (ceph_snap(dir) == CEPH_NOSNAP) {
  387. strcpy(name, fsc->mount_options->snapdir_name);
  388. err = 0;
  389. }
  390. goto out;
  391. }
  392. if (ceph_snap(dir) != CEPH_SNAPDIR)
  393. goto out;
  394. while (1) {
  395. struct ceph_mds_reply_info_parsed *rinfo;
  396. struct ceph_mds_reply_dir_entry *rde;
  397. int i;
  398. req = ceph_mdsc_create_request(fsc->mdsc, CEPH_MDS_OP_LSSNAP,
  399. USE_AUTH_MDS);
  400. if (IS_ERR(req)) {
  401. err = PTR_ERR(req);
  402. req = NULL;
  403. goto out;
  404. }
  405. err = ceph_alloc_readdir_reply_buffer(req, inode);
  406. if (err)
  407. goto out;
  408. req->r_direct_mode = USE_AUTH_MDS;
  409. req->r_readdir_offset = next_offset;
  410. req->r_args.readdir.flags =
  411. cpu_to_le16(CEPH_READDIR_REPLY_BITFLAGS);
  412. if (last_name) {
  413. req->r_path2 = last_name;
  414. last_name = NULL;
  415. }
  416. req->r_inode = dir;
  417. ihold(dir);
  418. req->r_dentry = dget(parent);
  419. inode_lock(dir);
  420. err = ceph_mdsc_do_request(fsc->mdsc, NULL, req);
  421. inode_unlock(dir);
  422. if (err < 0)
  423. goto out;
  424. rinfo = &req->r_reply_info;
  425. for (i = 0; i < rinfo->dir_nr; i++) {
  426. rde = rinfo->dir_entries + i;
  427. BUG_ON(!rde->inode.in);
  428. if (ceph_snap(inode) ==
  429. le64_to_cpu(rde->inode.in->snapid)) {
  430. memcpy(name, rde->name, rde->name_len);
  431. name[rde->name_len] = '\0';
  432. err = 0;
  433. goto out;
  434. }
  435. }
  436. if (rinfo->dir_end)
  437. break;
  438. BUG_ON(rinfo->dir_nr <= 0);
  439. rde = rinfo->dir_entries + (rinfo->dir_nr - 1);
  440. next_offset += rinfo->dir_nr;
  441. last_name = kstrndup(rde->name, rde->name_len, GFP_KERNEL);
  442. if (!last_name) {
  443. err = -ENOMEM;
  444. goto out;
  445. }
  446. ceph_mdsc_put_request(req);
  447. req = NULL;
  448. }
  449. err = -ENOENT;
  450. out:
  451. if (req)
  452. ceph_mdsc_put_request(req);
  453. kfree(last_name);
  454. dout("get_snap_name %p ino %llx.%llx err=%d\n",
  455. child, ceph_vinop(inode), err);
  456. return err;
  457. }
  458. static int ceph_get_name(struct dentry *parent, char *name,
  459. struct dentry *child)
  460. {
  461. struct ceph_mds_client *mdsc;
  462. struct ceph_mds_request *req;
  463. struct inode *inode = d_inode(child);
  464. int err;
  465. if (ceph_snap(inode) != CEPH_NOSNAP)
  466. return __get_snap_name(parent, name, child);
  467. mdsc = ceph_inode_to_client(inode)->mdsc;
  468. req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPNAME,
  469. USE_ANY_MDS);
  470. if (IS_ERR(req))
  471. return PTR_ERR(req);
  472. inode_lock(d_inode(parent));
  473. req->r_inode = inode;
  474. ihold(inode);
  475. req->r_ino2 = ceph_vino(d_inode(parent));
  476. req->r_parent = d_inode(parent);
  477. set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags);
  478. req->r_num_caps = 2;
  479. err = ceph_mdsc_do_request(mdsc, NULL, req);
  480. inode_unlock(d_inode(parent));
  481. if (!err) {
  482. struct ceph_mds_reply_info_parsed *rinfo = &req->r_reply_info;
  483. memcpy(name, rinfo->dname, rinfo->dname_len);
  484. name[rinfo->dname_len] = 0;
  485. dout("get_name %p ino %llx.%llx name %s\n",
  486. child, ceph_vinop(inode), name);
  487. } else {
  488. dout("get_name %p ino %llx.%llx err %d\n",
  489. child, ceph_vinop(inode), err);
  490. }
  491. ceph_mdsc_put_request(req);
  492. return err;
  493. }
  494. const struct export_operations ceph_export_ops = {
  495. .encode_fh = ceph_encode_fh,
  496. .fh_to_dentry = ceph_fh_to_dentry,
  497. .fh_to_parent = ceph_fh_to_parent,
  498. .get_parent = ceph_get_parent,
  499. .get_name = ceph_get_name,
  500. };