export.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  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. static int ceph_encode_fh(struct inode *inode, u32 *rawfh, int *max_len,
  21. struct inode *parent_inode)
  22. {
  23. int type;
  24. struct ceph_nfs_fh *fh = (void *)rawfh;
  25. struct ceph_nfs_confh *cfh = (void *)rawfh;
  26. int connected_handle_length = sizeof(*cfh)/4;
  27. int handle_length = sizeof(*fh)/4;
  28. /* don't re-export snaps */
  29. if (ceph_snap(inode) != CEPH_NOSNAP)
  30. return -EINVAL;
  31. if (parent_inode && (*max_len < connected_handle_length)) {
  32. *max_len = connected_handle_length;
  33. return FILEID_INVALID;
  34. } else if (*max_len < handle_length) {
  35. *max_len = handle_length;
  36. return FILEID_INVALID;
  37. }
  38. if (parent_inode) {
  39. dout("encode_fh %llx with parent %llx\n",
  40. ceph_ino(inode), ceph_ino(parent_inode));
  41. cfh->ino = ceph_ino(inode);
  42. cfh->parent_ino = ceph_ino(parent_inode);
  43. *max_len = connected_handle_length;
  44. type = FILEID_INO32_GEN_PARENT;
  45. } else {
  46. dout("encode_fh %llx\n", ceph_ino(inode));
  47. fh->ino = ceph_ino(inode);
  48. *max_len = handle_length;
  49. type = FILEID_INO32_GEN;
  50. }
  51. return type;
  52. }
  53. static struct dentry *__fh_to_dentry(struct super_block *sb, u64 ino)
  54. {
  55. struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
  56. struct inode *inode;
  57. struct ceph_vino vino;
  58. int err;
  59. vino.ino = ino;
  60. vino.snap = CEPH_NOSNAP;
  61. inode = ceph_find_inode(sb, vino);
  62. if (!inode) {
  63. struct ceph_mds_request *req;
  64. int mask;
  65. req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPINO,
  66. USE_ANY_MDS);
  67. if (IS_ERR(req))
  68. return ERR_CAST(req);
  69. mask = CEPH_STAT_CAP_INODE;
  70. if (ceph_security_xattr_wanted(d_inode(sb->s_root)))
  71. mask |= CEPH_CAP_XATTR_SHARED;
  72. req->r_args.getattr.mask = cpu_to_le32(mask);
  73. req->r_ino1 = vino;
  74. req->r_num_caps = 1;
  75. err = ceph_mdsc_do_request(mdsc, NULL, req);
  76. inode = req->r_target_inode;
  77. if (inode)
  78. ihold(inode);
  79. ceph_mdsc_put_request(req);
  80. if (!inode)
  81. return ERR_PTR(-ESTALE);
  82. if (inode->i_nlink == 0) {
  83. iput(inode);
  84. return ERR_PTR(-ESTALE);
  85. }
  86. }
  87. return d_obtain_alias(inode);
  88. }
  89. /*
  90. * convert regular fh to dentry
  91. */
  92. static struct dentry *ceph_fh_to_dentry(struct super_block *sb,
  93. struct fid *fid,
  94. int fh_len, int fh_type)
  95. {
  96. struct ceph_nfs_fh *fh = (void *)fid->raw;
  97. if (fh_type != FILEID_INO32_GEN &&
  98. fh_type != FILEID_INO32_GEN_PARENT)
  99. return NULL;
  100. if (fh_len < sizeof(*fh) / 4)
  101. return NULL;
  102. dout("fh_to_dentry %llx\n", fh->ino);
  103. return __fh_to_dentry(sb, fh->ino);
  104. }
  105. static struct dentry *__get_parent(struct super_block *sb,
  106. struct dentry *child, u64 ino)
  107. {
  108. struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
  109. struct ceph_mds_request *req;
  110. struct inode *inode;
  111. int mask;
  112. int err;
  113. req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPPARENT,
  114. USE_ANY_MDS);
  115. if (IS_ERR(req))
  116. return ERR_CAST(req);
  117. if (child) {
  118. req->r_inode = d_inode(child);
  119. ihold(d_inode(child));
  120. } else {
  121. req->r_ino1 = (struct ceph_vino) {
  122. .ino = ino,
  123. .snap = CEPH_NOSNAP,
  124. };
  125. }
  126. mask = CEPH_STAT_CAP_INODE;
  127. if (ceph_security_xattr_wanted(d_inode(sb->s_root)))
  128. mask |= CEPH_CAP_XATTR_SHARED;
  129. req->r_args.getattr.mask = cpu_to_le32(mask);
  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_PTR(-ENOENT);
  138. return d_obtain_alias(inode);
  139. }
  140. static struct dentry *ceph_get_parent(struct dentry *child)
  141. {
  142. /* don't re-export snaps */
  143. if (ceph_snap(d_inode(child)) != CEPH_NOSNAP)
  144. return ERR_PTR(-EINVAL);
  145. dout("get_parent %p ino %llx.%llx\n",
  146. child, ceph_vinop(d_inode(child)));
  147. return __get_parent(child->d_sb, child, 0);
  148. }
  149. /*
  150. * convert regular fh to parent
  151. */
  152. static struct dentry *ceph_fh_to_parent(struct super_block *sb,
  153. struct fid *fid,
  154. int fh_len, int fh_type)
  155. {
  156. struct ceph_nfs_confh *cfh = (void *)fid->raw;
  157. struct dentry *dentry;
  158. if (fh_type != FILEID_INO32_GEN_PARENT)
  159. return NULL;
  160. if (fh_len < sizeof(*cfh) / 4)
  161. return NULL;
  162. dout("fh_to_parent %llx\n", cfh->parent_ino);
  163. dentry = __get_parent(sb, NULL, cfh->ino);
  164. if (unlikely(dentry == ERR_PTR(-ENOENT)))
  165. dentry = __fh_to_dentry(sb, cfh->parent_ino);
  166. return dentry;
  167. }
  168. static int ceph_get_name(struct dentry *parent, char *name,
  169. struct dentry *child)
  170. {
  171. struct ceph_mds_client *mdsc;
  172. struct ceph_mds_request *req;
  173. int err;
  174. mdsc = ceph_inode_to_client(d_inode(child))->mdsc;
  175. req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPNAME,
  176. USE_ANY_MDS);
  177. if (IS_ERR(req))
  178. return PTR_ERR(req);
  179. inode_lock(d_inode(parent));
  180. req->r_inode = d_inode(child);
  181. ihold(d_inode(child));
  182. req->r_ino2 = ceph_vino(d_inode(parent));
  183. req->r_parent = d_inode(parent);
  184. set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags);
  185. req->r_num_caps = 2;
  186. err = ceph_mdsc_do_request(mdsc, NULL, req);
  187. inode_unlock(d_inode(parent));
  188. if (!err) {
  189. struct ceph_mds_reply_info_parsed *rinfo = &req->r_reply_info;
  190. memcpy(name, rinfo->dname, rinfo->dname_len);
  191. name[rinfo->dname_len] = 0;
  192. dout("get_name %p ino %llx.%llx name %s\n",
  193. child, ceph_vinop(d_inode(child)), name);
  194. } else {
  195. dout("get_name %p ino %llx.%llx err %d\n",
  196. child, ceph_vinop(d_inode(child)), err);
  197. }
  198. ceph_mdsc_put_request(req);
  199. return err;
  200. }
  201. const struct export_operations ceph_export_ops = {
  202. .encode_fh = ceph_encode_fh,
  203. .fh_to_dentry = ceph_fh_to_dentry,
  204. .fh_to_parent = ceph_fh_to_parent,
  205. .get_parent = ceph_get_parent,
  206. .get_name = ceph_get_name,
  207. };