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
);
178 return ERR_CAST(inode
);
179 /* We need LINK caps to reliably check i_nlink */
180 err
= ceph_do_getattr(inode
, CEPH_CAP_LINK_SHARED
, false);
185 /* -ESTALE if inode as been unlinked and no file is open */
186 if ((inode
->i_nlink
== 0) && (atomic_read(&inode
->i_count
) == 1)) {
188 return ERR_PTR(-ESTALE
);
190 return d_obtain_alias(inode
);
193 static struct dentry
*__snapfh_to_dentry(struct super_block
*sb
,
194 struct ceph_nfs_snapfh
*sfh
,
197 struct ceph_mds_client
*mdsc
= ceph_sb_to_client(sb
)->mdsc
;
198 struct ceph_mds_request
*req
;
200 struct ceph_vino vino
;
203 bool unlinked
= false;
206 vino
.ino
= sfh
->parent_ino
;
207 if (sfh
->snapid
== CEPH_SNAPDIR
)
208 vino
.snap
= CEPH_NOSNAP
;
209 else if (sfh
->ino
== sfh
->parent_ino
)
210 vino
.snap
= CEPH_SNAPDIR
;
212 vino
.snap
= sfh
->snapid
;
215 vino
.snap
= sfh
->snapid
;
217 inode
= ceph_find_inode(sb
, vino
);
219 return d_obtain_alias(inode
);
221 req
= ceph_mdsc_create_request(mdsc
, CEPH_MDS_OP_LOOKUPINO
,
224 return ERR_CAST(req
);
226 mask
= CEPH_STAT_CAP_INODE
;
227 if (ceph_security_xattr_wanted(d_inode(sb
->s_root
)))
228 mask
|= CEPH_CAP_XATTR_SHARED
;
229 req
->r_args
.lookupino
.mask
= cpu_to_le32(mask
);
230 if (vino
.snap
< CEPH_NOSNAP
) {
231 req
->r_args
.lookupino
.snapid
= cpu_to_le64(vino
.snap
);
232 if (!want_parent
&& sfh
->ino
!= sfh
->parent_ino
) {
233 req
->r_args
.lookupino
.parent
=
234 cpu_to_le64(sfh
->parent_ino
);
235 req
->r_args
.lookupino
.hash
=
236 cpu_to_le32(sfh
->hash
);
242 err
= ceph_mdsc_do_request(mdsc
, NULL
, req
);
243 inode
= req
->r_target_inode
;
245 if (vino
.snap
== CEPH_SNAPDIR
) {
246 if (inode
->i_nlink
== 0)
248 inode
= ceph_get_snapdir(inode
);
249 } else if (ceph_snap(inode
) == vino
.snap
) {
252 /* mds does not support lookup snapped inode */
257 ceph_mdsc_put_request(req
);
260 dout("snapfh_to_parent %llx.%llx\n err=%d\n",
261 vino
.ino
, vino
.snap
, err
);
263 dout("snapfh_to_dentry %llx.%llx parent %llx hash %x err=%d",
264 vino
.ino
, vino
.snap
, sfh
->parent_ino
, sfh
->hash
, err
);
267 return ERR_PTR(-ESTALE
);
268 /* see comments in ceph_get_parent() */
269 return unlinked
? d_obtain_root(inode
) : d_obtain_alias(inode
);
273 * convert regular fh to dentry
275 static struct dentry
*ceph_fh_to_dentry(struct super_block
*sb
,
277 int fh_len
, int fh_type
)
279 struct ceph_nfs_fh
*fh
= (void *)fid
->raw
;
281 if (fh_type
== FILEID_BTRFS_WITH_PARENT
) {
282 struct ceph_nfs_snapfh
*sfh
= (void *)fid
->raw
;
283 return __snapfh_to_dentry(sb
, sfh
, false);
286 if (fh_type
!= FILEID_INO32_GEN
&&
287 fh_type
!= FILEID_INO32_GEN_PARENT
)
289 if (fh_len
< sizeof(*fh
) / 4)
292 dout("fh_to_dentry %llx\n", fh
->ino
);
293 return __fh_to_dentry(sb
, fh
->ino
);
296 static struct dentry
*__get_parent(struct super_block
*sb
,
297 struct dentry
*child
, u64 ino
)
299 struct ceph_mds_client
*mdsc
= ceph_sb_to_client(sb
)->mdsc
;
300 struct ceph_mds_request
*req
;
305 req
= ceph_mdsc_create_request(mdsc
, CEPH_MDS_OP_LOOKUPPARENT
,
308 return ERR_CAST(req
);
311 req
->r_inode
= d_inode(child
);
312 ihold(d_inode(child
));
314 req
->r_ino1
= (struct ceph_vino
) {
320 mask
= CEPH_STAT_CAP_INODE
;
321 if (ceph_security_xattr_wanted(d_inode(sb
->s_root
)))
322 mask
|= CEPH_CAP_XATTR_SHARED
;
323 req
->r_args
.getattr
.mask
= cpu_to_le32(mask
);
326 err
= ceph_mdsc_do_request(mdsc
, NULL
, req
);
328 ceph_mdsc_put_request(req
);
332 inode
= req
->r_target_inode
;
335 ceph_mdsc_put_request(req
);
337 return ERR_PTR(-ENOENT
);
339 return d_obtain_alias(inode
);
342 static struct dentry
*ceph_get_parent(struct dentry
*child
)
344 struct inode
*inode
= d_inode(child
);
347 if (ceph_snap(inode
) != CEPH_NOSNAP
) {
349 bool unlinked
= false;
350 /* do not support non-directory */
351 if (!d_is_dir(child
)) {
352 dn
= ERR_PTR(-EINVAL
);
355 dir
= __lookup_inode(inode
->i_sb
, ceph_ino(inode
));
360 /* There can be multiple paths to access snapped inode.
361 * For simplicity, treat snapdir of head inode as parent */
362 if (ceph_snap(inode
) != CEPH_SNAPDIR
) {
363 struct inode
*snapdir
= ceph_get_snapdir(dir
);
364 if (dir
->i_nlink
== 0)
367 if (IS_ERR(snapdir
)) {
368 dn
= ERR_CAST(snapdir
);
373 /* If directory has already been deleted, futher get_parent
374 * will fail. Do not mark snapdir dentry as disconnected,
375 * this prevent exportfs from doing futher get_parent. */
377 dn
= d_obtain_root(dir
);
379 dn
= d_obtain_alias(dir
);
381 dn
= __get_parent(child
->d_sb
, child
, 0);
384 dout("get_parent %p ino %llx.%llx err=%ld\n",
385 child
, ceph_vinop(inode
), (long)PTR_ERR_OR_ZERO(dn
));
390 * convert regular fh to parent
392 static struct dentry
*ceph_fh_to_parent(struct super_block
*sb
,
394 int fh_len
, int fh_type
)
396 struct ceph_nfs_confh
*cfh
= (void *)fid
->raw
;
397 struct dentry
*dentry
;
399 if (fh_type
== FILEID_BTRFS_WITH_PARENT
) {
400 struct ceph_nfs_snapfh
*sfh
= (void *)fid
->raw
;
401 return __snapfh_to_dentry(sb
, sfh
, true);
404 if (fh_type
!= FILEID_INO32_GEN_PARENT
)
406 if (fh_len
< sizeof(*cfh
) / 4)
409 dout("fh_to_parent %llx\n", cfh
->parent_ino
);
410 dentry
= __get_parent(sb
, NULL
, cfh
->ino
);
411 if (unlikely(dentry
== ERR_PTR(-ENOENT
)))
412 dentry
= __fh_to_dentry(sb
, cfh
->parent_ino
);
416 static int __get_snap_name(struct dentry
*parent
, char *name
,
417 struct dentry
*child
)
419 struct inode
*inode
= d_inode(child
);
420 struct inode
*dir
= d_inode(parent
);
421 struct ceph_fs_client
*fsc
= ceph_inode_to_client(inode
);
422 struct ceph_mds_request
*req
= NULL
;
423 char *last_name
= NULL
;
424 unsigned next_offset
= 2;
427 if (ceph_ino(inode
) != ceph_ino(dir
))
429 if (ceph_snap(inode
) == CEPH_SNAPDIR
) {
430 if (ceph_snap(dir
) == CEPH_NOSNAP
) {
431 strcpy(name
, fsc
->mount_options
->snapdir_name
);
436 if (ceph_snap(dir
) != CEPH_SNAPDIR
)
440 struct ceph_mds_reply_info_parsed
*rinfo
;
441 struct ceph_mds_reply_dir_entry
*rde
;
444 req
= ceph_mdsc_create_request(fsc
->mdsc
, CEPH_MDS_OP_LSSNAP
,
451 err
= ceph_alloc_readdir_reply_buffer(req
, inode
);
455 req
->r_direct_mode
= USE_AUTH_MDS
;
456 req
->r_readdir_offset
= next_offset
;
457 req
->r_args
.readdir
.flags
=
458 cpu_to_le16(CEPH_READDIR_REPLY_BITFLAGS
);
460 req
->r_path2
= last_name
;
466 req
->r_dentry
= dget(parent
);
469 err
= ceph_mdsc_do_request(fsc
->mdsc
, NULL
, req
);
475 rinfo
= &req
->r_reply_info
;
476 for (i
= 0; i
< rinfo
->dir_nr
; i
++) {
477 rde
= rinfo
->dir_entries
+ i
;
478 BUG_ON(!rde
->inode
.in
);
479 if (ceph_snap(inode
) ==
480 le64_to_cpu(rde
->inode
.in
->snapid
)) {
481 memcpy(name
, rde
->name
, rde
->name_len
);
482 name
[rde
->name_len
] = '\0';
491 BUG_ON(rinfo
->dir_nr
<= 0);
492 rde
= rinfo
->dir_entries
+ (rinfo
->dir_nr
- 1);
493 next_offset
+= rinfo
->dir_nr
;
494 last_name
= kstrndup(rde
->name
, rde
->name_len
, GFP_KERNEL
);
500 ceph_mdsc_put_request(req
);
506 ceph_mdsc_put_request(req
);
508 dout("get_snap_name %p ino %llx.%llx err=%d\n",
509 child
, ceph_vinop(inode
), err
);
513 static int ceph_get_name(struct dentry
*parent
, char *name
,
514 struct dentry
*child
)
516 struct ceph_mds_client
*mdsc
;
517 struct ceph_mds_request
*req
;
518 struct inode
*inode
= d_inode(child
);
521 if (ceph_snap(inode
) != CEPH_NOSNAP
)
522 return __get_snap_name(parent
, name
, child
);
524 mdsc
= ceph_inode_to_client(inode
)->mdsc
;
525 req
= ceph_mdsc_create_request(mdsc
, CEPH_MDS_OP_LOOKUPNAME
,
530 inode_lock(d_inode(parent
));
532 req
->r_inode
= inode
;
534 req
->r_ino2
= ceph_vino(d_inode(parent
));
535 req
->r_parent
= d_inode(parent
);
536 set_bit(CEPH_MDS_R_PARENT_LOCKED
, &req
->r_req_flags
);
538 err
= ceph_mdsc_do_request(mdsc
, NULL
, req
);
540 inode_unlock(d_inode(parent
));
543 struct ceph_mds_reply_info_parsed
*rinfo
= &req
->r_reply_info
;
544 memcpy(name
, rinfo
->dname
, rinfo
->dname_len
);
545 name
[rinfo
->dname_len
] = 0;
546 dout("get_name %p ino %llx.%llx name %s\n",
547 child
, ceph_vinop(inode
), name
);
549 dout("get_name %p ino %llx.%llx err %d\n",
550 child
, ceph_vinop(inode
), err
);
553 ceph_mdsc_put_request(req
);
557 const struct export_operations ceph_export_ops
= {
558 .encode_fh
= ceph_encode_fh
,
559 .fh_to_dentry
= ceph_fh_to_dentry
,
560 .fh_to_parent
= ceph_fh_to_parent
,
561 .get_parent
= ceph_get_parent
,
562 .get_name
= ceph_get_name
,