1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/ceph/ceph_debug.h>
4 #include <linux/exportfs.h>
5 #include <linux/slab.h>
6 #include <asm/unaligned.h>
9 #include "mds_client.h"
16 } __attribute__ ((packed
));
19 * Larger fh that includes parent ino.
21 struct ceph_nfs_confh
{
23 } __attribute__ ((packed
));
26 * fh for snapped inode
28 struct ceph_nfs_snapfh
{
33 } __attribute__ ((packed
));
35 static int ceph_encode_snapfh(struct inode
*inode
, u32
*rawfh
, int *max_len
,
36 struct inode
*parent_inode
)
38 static const int snap_handle_length
=
39 sizeof(struct ceph_nfs_snapfh
) >> 2;
40 struct ceph_nfs_snapfh
*sfh
= (void *)rawfh
;
41 u64 snapid
= ceph_snap(inode
);
43 bool no_parent
= true;
45 if (*max_len
< snap_handle_length
) {
46 *max_len
= snap_handle_length
;
52 if (snapid
!= CEPH_SNAPDIR
) {
54 struct dentry
*dentry
= d_find_alias(inode
);
59 dir
= d_inode_rcu(dentry
->d_parent
);
60 if (ceph_snap(dir
) != CEPH_SNAPDIR
) {
61 sfh
->parent_ino
= ceph_ino(dir
);
62 sfh
->hash
= ceph_dentry_hash(dir
, dentry
);
70 if (!S_ISDIR(inode
->i_mode
))
72 sfh
->parent_ino
= sfh
->ino
;
75 sfh
->ino
= ceph_ino(inode
);
78 *max_len
= snap_handle_length
;
79 ret
= FILEID_BTRFS_WITH_PARENT
;
81 dout("encode_snapfh %llx.%llx ret=%d\n", ceph_vinop(inode
), ret
);
85 static int ceph_encode_fh(struct inode
*inode
, u32
*rawfh
, int *max_len
,
86 struct inode
*parent_inode
)
88 static const int handle_length
=
89 sizeof(struct ceph_nfs_fh
) >> 2;
90 static const int connected_handle_length
=
91 sizeof(struct ceph_nfs_confh
) >> 2;
94 if (ceph_snap(inode
) != CEPH_NOSNAP
)
95 return ceph_encode_snapfh(inode
, rawfh
, max_len
, parent_inode
);
97 if (parent_inode
&& (*max_len
< connected_handle_length
)) {
98 *max_len
= connected_handle_length
;
99 return FILEID_INVALID
;
100 } else if (*max_len
< handle_length
) {
101 *max_len
= handle_length
;
102 return FILEID_INVALID
;
106 struct ceph_nfs_confh
*cfh
= (void *)rawfh
;
107 dout("encode_fh %llx with parent %llx\n",
108 ceph_ino(inode
), ceph_ino(parent_inode
));
109 cfh
->ino
= ceph_ino(inode
);
110 cfh
->parent_ino
= ceph_ino(parent_inode
);
111 *max_len
= connected_handle_length
;
112 type
= FILEID_INO32_GEN_PARENT
;
114 struct ceph_nfs_fh
*fh
= (void *)rawfh
;
115 dout("encode_fh %llx\n", ceph_ino(inode
));
116 fh
->ino
= ceph_ino(inode
);
117 *max_len
= handle_length
;
118 type
= FILEID_INO32_GEN
;
123 static struct inode
*__lookup_inode(struct super_block
*sb
, u64 ino
)
125 struct ceph_mds_client
*mdsc
= ceph_sb_to_client(sb
)->mdsc
;
127 struct ceph_vino vino
;
131 vino
.snap
= CEPH_NOSNAP
;
132 inode
= ceph_find_inode(sb
, vino
);
134 struct ceph_mds_request
*req
;
137 req
= ceph_mdsc_create_request(mdsc
, CEPH_MDS_OP_LOOKUPINO
,
140 return ERR_CAST(req
);
142 mask
= CEPH_STAT_CAP_INODE
;
143 if (ceph_security_xattr_wanted(d_inode(sb
->s_root
)))
144 mask
|= CEPH_CAP_XATTR_SHARED
;
145 req
->r_args
.lookupino
.mask
= cpu_to_le32(mask
);
149 err
= ceph_mdsc_do_request(mdsc
, NULL
, req
);
150 inode
= req
->r_target_inode
;
153 ceph_mdsc_put_request(req
);
155 return err
< 0 ? ERR_PTR(err
) : ERR_PTR(-ESTALE
);
160 struct inode
*ceph_lookup_inode(struct super_block
*sb
, u64 ino
)
162 struct inode
*inode
= __lookup_inode(sb
, ino
);
165 if (inode
->i_nlink
== 0) {
167 return ERR_PTR(-ESTALE
);
172 static struct dentry
*__fh_to_dentry(struct super_block
*sb
, u64 ino
)
174 struct inode
*inode
= __lookup_inode(sb
, ino
);
176 return ERR_CAST(inode
);
177 if (inode
->i_nlink
== 0) {
179 return ERR_PTR(-ESTALE
);
181 return d_obtain_alias(inode
);
184 static struct dentry
*__snapfh_to_dentry(struct super_block
*sb
,
185 struct ceph_nfs_snapfh
*sfh
,
188 struct ceph_mds_client
*mdsc
= ceph_sb_to_client(sb
)->mdsc
;
189 struct ceph_mds_request
*req
;
191 struct ceph_vino vino
;
194 bool unlinked
= false;
197 vino
.ino
= sfh
->parent_ino
;
198 if (sfh
->snapid
== CEPH_SNAPDIR
)
199 vino
.snap
= CEPH_NOSNAP
;
200 else if (sfh
->ino
== sfh
->parent_ino
)
201 vino
.snap
= CEPH_SNAPDIR
;
203 vino
.snap
= sfh
->snapid
;
206 vino
.snap
= sfh
->snapid
;
208 inode
= ceph_find_inode(sb
, vino
);
210 return d_obtain_alias(inode
);
212 req
= ceph_mdsc_create_request(mdsc
, CEPH_MDS_OP_LOOKUPINO
,
215 return ERR_CAST(req
);
217 mask
= CEPH_STAT_CAP_INODE
;
218 if (ceph_security_xattr_wanted(d_inode(sb
->s_root
)))
219 mask
|= CEPH_CAP_XATTR_SHARED
;
220 req
->r_args
.lookupino
.mask
= cpu_to_le32(mask
);
221 if (vino
.snap
< CEPH_NOSNAP
) {
222 req
->r_args
.lookupino
.snapid
= cpu_to_le64(vino
.snap
);
223 if (!want_parent
&& sfh
->ino
!= sfh
->parent_ino
) {
224 req
->r_args
.lookupino
.parent
=
225 cpu_to_le64(sfh
->parent_ino
);
226 req
->r_args
.lookupino
.hash
=
227 cpu_to_le32(sfh
->hash
);
233 err
= ceph_mdsc_do_request(mdsc
, NULL
, req
);
234 inode
= req
->r_target_inode
;
236 if (vino
.snap
== CEPH_SNAPDIR
) {
237 if (inode
->i_nlink
== 0)
239 inode
= ceph_get_snapdir(inode
);
240 } else if (ceph_snap(inode
) == vino
.snap
) {
243 /* mds does not support lookup snapped inode */
248 ceph_mdsc_put_request(req
);
251 dout("snapfh_to_parent %llx.%llx\n err=%d\n",
252 vino
.ino
, vino
.snap
, err
);
254 dout("snapfh_to_dentry %llx.%llx parent %llx hash %x err=%d",
255 vino
.ino
, vino
.snap
, sfh
->parent_ino
, sfh
->hash
, err
);
258 return ERR_PTR(-ESTALE
);
259 /* see comments in ceph_get_parent() */
260 return unlinked
? d_obtain_root(inode
) : d_obtain_alias(inode
);
264 * convert regular fh to dentry
266 static struct dentry
*ceph_fh_to_dentry(struct super_block
*sb
,
268 int fh_len
, int fh_type
)
270 struct ceph_nfs_fh
*fh
= (void *)fid
->raw
;
272 if (fh_type
== FILEID_BTRFS_WITH_PARENT
) {
273 struct ceph_nfs_snapfh
*sfh
= (void *)fid
->raw
;
274 return __snapfh_to_dentry(sb
, sfh
, false);
277 if (fh_type
!= FILEID_INO32_GEN
&&
278 fh_type
!= FILEID_INO32_GEN_PARENT
)
280 if (fh_len
< sizeof(*fh
) / 4)
283 dout("fh_to_dentry %llx\n", fh
->ino
);
284 return __fh_to_dentry(sb
, fh
->ino
);
287 static struct dentry
*__get_parent(struct super_block
*sb
,
288 struct dentry
*child
, u64 ino
)
290 struct ceph_mds_client
*mdsc
= ceph_sb_to_client(sb
)->mdsc
;
291 struct ceph_mds_request
*req
;
296 req
= ceph_mdsc_create_request(mdsc
, CEPH_MDS_OP_LOOKUPPARENT
,
299 return ERR_CAST(req
);
302 req
->r_inode
= d_inode(child
);
303 ihold(d_inode(child
));
305 req
->r_ino1
= (struct ceph_vino
) {
311 mask
= CEPH_STAT_CAP_INODE
;
312 if (ceph_security_xattr_wanted(d_inode(sb
->s_root
)))
313 mask
|= CEPH_CAP_XATTR_SHARED
;
314 req
->r_args
.getattr
.mask
= cpu_to_le32(mask
);
317 err
= ceph_mdsc_do_request(mdsc
, NULL
, req
);
319 ceph_mdsc_put_request(req
);
323 inode
= req
->r_target_inode
;
326 ceph_mdsc_put_request(req
);
328 return ERR_PTR(-ENOENT
);
330 return d_obtain_alias(inode
);
333 static struct dentry
*ceph_get_parent(struct dentry
*child
)
335 struct inode
*inode
= d_inode(child
);
338 if (ceph_snap(inode
) != CEPH_NOSNAP
) {
340 bool unlinked
= false;
341 /* do not support non-directory */
342 if (!d_is_dir(child
)) {
343 dn
= ERR_PTR(-EINVAL
);
346 dir
= __lookup_inode(inode
->i_sb
, ceph_ino(inode
));
351 /* There can be multiple paths to access snapped inode.
352 * For simplicity, treat snapdir of head inode as parent */
353 if (ceph_snap(inode
) != CEPH_SNAPDIR
) {
354 struct inode
*snapdir
= ceph_get_snapdir(dir
);
355 if (dir
->i_nlink
== 0)
358 if (IS_ERR(snapdir
)) {
359 dn
= ERR_CAST(snapdir
);
364 /* If directory has already been deleted, futher get_parent
365 * will fail. Do not mark snapdir dentry as disconnected,
366 * this prevent exportfs from doing futher get_parent. */
368 dn
= d_obtain_root(dir
);
370 dn
= d_obtain_alias(dir
);
372 dn
= __get_parent(child
->d_sb
, child
, 0);
375 dout("get_parent %p ino %llx.%llx err=%ld\n",
376 child
, ceph_vinop(inode
), (long)PTR_ERR_OR_ZERO(dn
));
381 * convert regular fh to parent
383 static struct dentry
*ceph_fh_to_parent(struct super_block
*sb
,
385 int fh_len
, int fh_type
)
387 struct ceph_nfs_confh
*cfh
= (void *)fid
->raw
;
388 struct dentry
*dentry
;
390 if (fh_type
== FILEID_BTRFS_WITH_PARENT
) {
391 struct ceph_nfs_snapfh
*sfh
= (void *)fid
->raw
;
392 return __snapfh_to_dentry(sb
, sfh
, true);
395 if (fh_type
!= FILEID_INO32_GEN_PARENT
)
397 if (fh_len
< sizeof(*cfh
) / 4)
400 dout("fh_to_parent %llx\n", cfh
->parent_ino
);
401 dentry
= __get_parent(sb
, NULL
, cfh
->ino
);
402 if (unlikely(dentry
== ERR_PTR(-ENOENT
)))
403 dentry
= __fh_to_dentry(sb
, cfh
->parent_ino
);
407 static int __get_snap_name(struct dentry
*parent
, char *name
,
408 struct dentry
*child
)
410 struct inode
*inode
= d_inode(child
);
411 struct inode
*dir
= d_inode(parent
);
412 struct ceph_fs_client
*fsc
= ceph_inode_to_client(inode
);
413 struct ceph_mds_request
*req
= NULL
;
414 char *last_name
= NULL
;
415 unsigned next_offset
= 2;
418 if (ceph_ino(inode
) != ceph_ino(dir
))
420 if (ceph_snap(inode
) == CEPH_SNAPDIR
) {
421 if (ceph_snap(dir
) == CEPH_NOSNAP
) {
422 strcpy(name
, fsc
->mount_options
->snapdir_name
);
427 if (ceph_snap(dir
) != CEPH_SNAPDIR
)
431 struct ceph_mds_reply_info_parsed
*rinfo
;
432 struct ceph_mds_reply_dir_entry
*rde
;
435 req
= ceph_mdsc_create_request(fsc
->mdsc
, CEPH_MDS_OP_LSSNAP
,
442 err
= ceph_alloc_readdir_reply_buffer(req
, inode
);
446 req
->r_direct_mode
= USE_AUTH_MDS
;
447 req
->r_readdir_offset
= next_offset
;
448 req
->r_args
.readdir
.flags
=
449 cpu_to_le16(CEPH_READDIR_REPLY_BITFLAGS
);
451 req
->r_path2
= last_name
;
457 req
->r_dentry
= dget(parent
);
460 err
= ceph_mdsc_do_request(fsc
->mdsc
, NULL
, req
);
466 rinfo
= &req
->r_reply_info
;
467 for (i
= 0; i
< rinfo
->dir_nr
; i
++) {
468 rde
= rinfo
->dir_entries
+ i
;
469 BUG_ON(!rde
->inode
.in
);
470 if (ceph_snap(inode
) ==
471 le64_to_cpu(rde
->inode
.in
->snapid
)) {
472 memcpy(name
, rde
->name
, rde
->name_len
);
473 name
[rde
->name_len
] = '\0';
482 BUG_ON(rinfo
->dir_nr
<= 0);
483 rde
= rinfo
->dir_entries
+ (rinfo
->dir_nr
- 1);
484 next_offset
+= rinfo
->dir_nr
;
485 last_name
= kstrndup(rde
->name
, rde
->name_len
, GFP_KERNEL
);
491 ceph_mdsc_put_request(req
);
497 ceph_mdsc_put_request(req
);
499 dout("get_snap_name %p ino %llx.%llx err=%d\n",
500 child
, ceph_vinop(inode
), err
);
504 static int ceph_get_name(struct dentry
*parent
, char *name
,
505 struct dentry
*child
)
507 struct ceph_mds_client
*mdsc
;
508 struct ceph_mds_request
*req
;
509 struct inode
*inode
= d_inode(child
);
512 if (ceph_snap(inode
) != CEPH_NOSNAP
)
513 return __get_snap_name(parent
, name
, child
);
515 mdsc
= ceph_inode_to_client(inode
)->mdsc
;
516 req
= ceph_mdsc_create_request(mdsc
, CEPH_MDS_OP_LOOKUPNAME
,
521 inode_lock(d_inode(parent
));
523 req
->r_inode
= inode
;
525 req
->r_ino2
= ceph_vino(d_inode(parent
));
526 req
->r_parent
= d_inode(parent
);
527 set_bit(CEPH_MDS_R_PARENT_LOCKED
, &req
->r_req_flags
);
529 err
= ceph_mdsc_do_request(mdsc
, NULL
, req
);
531 inode_unlock(d_inode(parent
));
534 struct ceph_mds_reply_info_parsed
*rinfo
= &req
->r_reply_info
;
535 memcpy(name
, rinfo
->dname
, rinfo
->dname_len
);
536 name
[rinfo
->dname_len
] = 0;
537 dout("get_name %p ino %llx.%llx name %s\n",
538 child
, ceph_vinop(inode
), name
);
540 dout("get_name %p ino %llx.%llx err %d\n",
541 child
, ceph_vinop(inode
), err
);
544 ceph_mdsc_put_request(req
);
548 const struct export_operations ceph_export_ops
= {
549 .encode_fh
= ceph_encode_fh
,
550 .fh_to_dentry
= ceph_fh_to_dentry
,
551 .fh_to_parent
= ceph_fh_to_parent
,
552 .get_parent
= ceph_get_parent
,
553 .get_name
= ceph_get_name
,