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);
183 /* -ESTALE if inode as been unlinked and no file is open */
184 if ((inode
->i_nlink
== 0) && (atomic_read(&inode
->i_count
) == 1)) {
186 return ERR_PTR(-ESTALE
);
188 return d_obtain_alias(inode
);
191 static struct dentry
*__snapfh_to_dentry(struct super_block
*sb
,
192 struct ceph_nfs_snapfh
*sfh
,
195 struct ceph_mds_client
*mdsc
= ceph_sb_to_client(sb
)->mdsc
;
196 struct ceph_mds_request
*req
;
198 struct ceph_vino vino
;
201 bool unlinked
= false;
204 vino
.ino
= sfh
->parent_ino
;
205 if (sfh
->snapid
== CEPH_SNAPDIR
)
206 vino
.snap
= CEPH_NOSNAP
;
207 else if (sfh
->ino
== sfh
->parent_ino
)
208 vino
.snap
= CEPH_SNAPDIR
;
210 vino
.snap
= sfh
->snapid
;
213 vino
.snap
= sfh
->snapid
;
215 inode
= ceph_find_inode(sb
, vino
);
217 return d_obtain_alias(inode
);
219 req
= ceph_mdsc_create_request(mdsc
, CEPH_MDS_OP_LOOKUPINO
,
222 return ERR_CAST(req
);
224 mask
= CEPH_STAT_CAP_INODE
;
225 if (ceph_security_xattr_wanted(d_inode(sb
->s_root
)))
226 mask
|= CEPH_CAP_XATTR_SHARED
;
227 req
->r_args
.lookupino
.mask
= cpu_to_le32(mask
);
228 if (vino
.snap
< CEPH_NOSNAP
) {
229 req
->r_args
.lookupino
.snapid
= cpu_to_le64(vino
.snap
);
230 if (!want_parent
&& sfh
->ino
!= sfh
->parent_ino
) {
231 req
->r_args
.lookupino
.parent
=
232 cpu_to_le64(sfh
->parent_ino
);
233 req
->r_args
.lookupino
.hash
=
234 cpu_to_le32(sfh
->hash
);
240 err
= ceph_mdsc_do_request(mdsc
, NULL
, req
);
241 inode
= req
->r_target_inode
;
243 if (vino
.snap
== CEPH_SNAPDIR
) {
244 if (inode
->i_nlink
== 0)
246 inode
= ceph_get_snapdir(inode
);
247 } else if (ceph_snap(inode
) == vino
.snap
) {
250 /* mds does not support lookup snapped inode */
255 ceph_mdsc_put_request(req
);
258 dout("snapfh_to_parent %llx.%llx\n err=%d\n",
259 vino
.ino
, vino
.snap
, err
);
261 dout("snapfh_to_dentry %llx.%llx parent %llx hash %x err=%d",
262 vino
.ino
, vino
.snap
, sfh
->parent_ino
, sfh
->hash
, err
);
265 return ERR_PTR(-ESTALE
);
266 /* see comments in ceph_get_parent() */
267 return unlinked
? d_obtain_root(inode
) : d_obtain_alias(inode
);
271 * convert regular fh to dentry
273 static struct dentry
*ceph_fh_to_dentry(struct super_block
*sb
,
275 int fh_len
, int fh_type
)
277 struct ceph_nfs_fh
*fh
= (void *)fid
->raw
;
279 if (fh_type
== FILEID_BTRFS_WITH_PARENT
) {
280 struct ceph_nfs_snapfh
*sfh
= (void *)fid
->raw
;
281 return __snapfh_to_dentry(sb
, sfh
, false);
284 if (fh_type
!= FILEID_INO32_GEN
&&
285 fh_type
!= FILEID_INO32_GEN_PARENT
)
287 if (fh_len
< sizeof(*fh
) / 4)
290 dout("fh_to_dentry %llx\n", fh
->ino
);
291 return __fh_to_dentry(sb
, fh
->ino
);
294 static struct dentry
*__get_parent(struct super_block
*sb
,
295 struct dentry
*child
, u64 ino
)
297 struct ceph_mds_client
*mdsc
= ceph_sb_to_client(sb
)->mdsc
;
298 struct ceph_mds_request
*req
;
303 req
= ceph_mdsc_create_request(mdsc
, CEPH_MDS_OP_LOOKUPPARENT
,
306 return ERR_CAST(req
);
309 req
->r_inode
= d_inode(child
);
310 ihold(d_inode(child
));
312 req
->r_ino1
= (struct ceph_vino
) {
318 mask
= CEPH_STAT_CAP_INODE
;
319 if (ceph_security_xattr_wanted(d_inode(sb
->s_root
)))
320 mask
|= CEPH_CAP_XATTR_SHARED
;
321 req
->r_args
.getattr
.mask
= cpu_to_le32(mask
);
324 err
= ceph_mdsc_do_request(mdsc
, NULL
, req
);
326 ceph_mdsc_put_request(req
);
330 inode
= req
->r_target_inode
;
333 ceph_mdsc_put_request(req
);
335 return ERR_PTR(-ENOENT
);
337 return d_obtain_alias(inode
);
340 static struct dentry
*ceph_get_parent(struct dentry
*child
)
342 struct inode
*inode
= d_inode(child
);
345 if (ceph_snap(inode
) != CEPH_NOSNAP
) {
347 bool unlinked
= false;
348 /* do not support non-directory */
349 if (!d_is_dir(child
)) {
350 dn
= ERR_PTR(-EINVAL
);
353 dir
= __lookup_inode(inode
->i_sb
, ceph_ino(inode
));
358 /* There can be multiple paths to access snapped inode.
359 * For simplicity, treat snapdir of head inode as parent */
360 if (ceph_snap(inode
) != CEPH_SNAPDIR
) {
361 struct inode
*snapdir
= ceph_get_snapdir(dir
);
362 if (dir
->i_nlink
== 0)
365 if (IS_ERR(snapdir
)) {
366 dn
= ERR_CAST(snapdir
);
371 /* If directory has already been deleted, futher get_parent
372 * will fail. Do not mark snapdir dentry as disconnected,
373 * this prevent exportfs from doing futher get_parent. */
375 dn
= d_obtain_root(dir
);
377 dn
= d_obtain_alias(dir
);
379 dn
= __get_parent(child
->d_sb
, child
, 0);
382 dout("get_parent %p ino %llx.%llx err=%ld\n",
383 child
, ceph_vinop(inode
), (long)PTR_ERR_OR_ZERO(dn
));
388 * convert regular fh to parent
390 static struct dentry
*ceph_fh_to_parent(struct super_block
*sb
,
392 int fh_len
, int fh_type
)
394 struct ceph_nfs_confh
*cfh
= (void *)fid
->raw
;
395 struct dentry
*dentry
;
397 if (fh_type
== FILEID_BTRFS_WITH_PARENT
) {
398 struct ceph_nfs_snapfh
*sfh
= (void *)fid
->raw
;
399 return __snapfh_to_dentry(sb
, sfh
, true);
402 if (fh_type
!= FILEID_INO32_GEN_PARENT
)
404 if (fh_len
< sizeof(*cfh
) / 4)
407 dout("fh_to_parent %llx\n", cfh
->parent_ino
);
408 dentry
= __get_parent(sb
, NULL
, cfh
->ino
);
409 if (unlikely(dentry
== ERR_PTR(-ENOENT
)))
410 dentry
= __fh_to_dentry(sb
, cfh
->parent_ino
);
414 static int __get_snap_name(struct dentry
*parent
, char *name
,
415 struct dentry
*child
)
417 struct inode
*inode
= d_inode(child
);
418 struct inode
*dir
= d_inode(parent
);
419 struct ceph_fs_client
*fsc
= ceph_inode_to_client(inode
);
420 struct ceph_mds_request
*req
= NULL
;
421 char *last_name
= NULL
;
422 unsigned next_offset
= 2;
425 if (ceph_ino(inode
) != ceph_ino(dir
))
427 if (ceph_snap(inode
) == CEPH_SNAPDIR
) {
428 if (ceph_snap(dir
) == CEPH_NOSNAP
) {
429 strcpy(name
, fsc
->mount_options
->snapdir_name
);
434 if (ceph_snap(dir
) != CEPH_SNAPDIR
)
438 struct ceph_mds_reply_info_parsed
*rinfo
;
439 struct ceph_mds_reply_dir_entry
*rde
;
442 req
= ceph_mdsc_create_request(fsc
->mdsc
, CEPH_MDS_OP_LSSNAP
,
449 err
= ceph_alloc_readdir_reply_buffer(req
, inode
);
453 req
->r_direct_mode
= USE_AUTH_MDS
;
454 req
->r_readdir_offset
= next_offset
;
455 req
->r_args
.readdir
.flags
=
456 cpu_to_le16(CEPH_READDIR_REPLY_BITFLAGS
);
458 req
->r_path2
= last_name
;
464 req
->r_dentry
= dget(parent
);
467 err
= ceph_mdsc_do_request(fsc
->mdsc
, NULL
, req
);
473 rinfo
= &req
->r_reply_info
;
474 for (i
= 0; i
< rinfo
->dir_nr
; i
++) {
475 rde
= rinfo
->dir_entries
+ i
;
476 BUG_ON(!rde
->inode
.in
);
477 if (ceph_snap(inode
) ==
478 le64_to_cpu(rde
->inode
.in
->snapid
)) {
479 memcpy(name
, rde
->name
, rde
->name_len
);
480 name
[rde
->name_len
] = '\0';
489 BUG_ON(rinfo
->dir_nr
<= 0);
490 rde
= rinfo
->dir_entries
+ (rinfo
->dir_nr
- 1);
491 next_offset
+= rinfo
->dir_nr
;
492 last_name
= kstrndup(rde
->name
, rde
->name_len
, GFP_KERNEL
);
498 ceph_mdsc_put_request(req
);
504 ceph_mdsc_put_request(req
);
506 dout("get_snap_name %p ino %llx.%llx err=%d\n",
507 child
, ceph_vinop(inode
), err
);
511 static int ceph_get_name(struct dentry
*parent
, char *name
,
512 struct dentry
*child
)
514 struct ceph_mds_client
*mdsc
;
515 struct ceph_mds_request
*req
;
516 struct inode
*inode
= d_inode(child
);
519 if (ceph_snap(inode
) != CEPH_NOSNAP
)
520 return __get_snap_name(parent
, name
, child
);
522 mdsc
= ceph_inode_to_client(inode
)->mdsc
;
523 req
= ceph_mdsc_create_request(mdsc
, CEPH_MDS_OP_LOOKUPNAME
,
528 inode_lock(d_inode(parent
));
530 req
->r_inode
= inode
;
532 req
->r_ino2
= ceph_vino(d_inode(parent
));
533 req
->r_parent
= d_inode(parent
);
534 set_bit(CEPH_MDS_R_PARENT_LOCKED
, &req
->r_req_flags
);
536 err
= ceph_mdsc_do_request(mdsc
, NULL
, req
);
538 inode_unlock(d_inode(parent
));
541 struct ceph_mds_reply_info_parsed
*rinfo
= &req
->r_reply_info
;
542 memcpy(name
, rinfo
->dname
, rinfo
->dname_len
);
543 name
[rinfo
->dname_len
] = 0;
544 dout("get_name %p ino %llx.%llx name %s\n",
545 child
, ceph_vinop(inode
), name
);
547 dout("get_name %p ino %llx.%llx err %d\n",
548 child
, ceph_vinop(inode
), err
);
551 ceph_mdsc_put_request(req
);
555 const struct export_operations ceph_export_ops
= {
556 .encode_fh
= ceph_encode_fh
,
557 .fh_to_dentry
= ceph_fh_to_dentry
,
558 .fh_to_parent
= ceph_fh_to_parent
,
559 .get_parent
= ceph_get_parent
,
560 .get_name
= ceph_get_name
,