blob: e0fa66ac8b9faa612969e0463ade52bc4b60d341 [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Yehuda Sadeh3d14c5d2010-04-06 15:14:15 -07002#include <linux/ceph/ceph_debug.h>
Sage Weila8e63b72009-10-06 11:31:13 -07003
4#include <linux/exportfs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +09005#include <linux/slab.h>
Sage Weila8e63b72009-10-06 11:31:13 -07006#include <asm/unaligned.h>
7
8#include "super.h"
Yehuda Sadeh3d14c5d2010-04-06 15:14:15 -07009#include "mds_client.h"
Sage Weila8e63b72009-10-06 11:31:13 -070010
11/*
Sage Weila8e63b72009-10-06 11:31:13 -070012 * Basic fh
13 */
14struct ceph_nfs_fh {
15 u64 ino;
16} __attribute__ ((packed));
17
18/*
Yan, Zheng4f32b422014-03-01 18:05:41 +080019 * Larger fh that includes parent ino.
Sage Weila8e63b72009-10-06 11:31:13 -070020 */
21struct ceph_nfs_confh {
22 u64 ino, parent_ino;
Sage Weila8e63b72009-10-06 11:31:13 -070023} __attribute__ ((packed));
24
Yan, Zheng570df4e2017-11-15 17:39:40 +080025/*
26 * fh for snapped inode
27 */
28struct ceph_nfs_snapfh {
29 u64 ino;
30 u64 snapid;
31 u64 parent_ino;
32 u32 hash;
33} __attribute__ ((packed));
34
35static int ceph_encode_snapfh(struct inode *inode, u32 *rawfh, int *max_len,
36 struct inode *parent_inode)
37{
Krzysztof Wilczynski536cc332019-08-31 23:57:12 +020038 static const int snap_handle_length =
Yan, Zheng570df4e2017-11-15 17:39:40 +080039 sizeof(struct ceph_nfs_snapfh) >> 2;
40 struct ceph_nfs_snapfh *sfh = (void *)rawfh;
41 u64 snapid = ceph_snap(inode);
42 int ret;
43 bool no_parent = true;
44
45 if (*max_len < snap_handle_length) {
46 *max_len = snap_handle_length;
47 ret = FILEID_INVALID;
48 goto out;
49 }
50
51 ret = -EINVAL;
52 if (snapid != CEPH_SNAPDIR) {
53 struct inode *dir;
54 struct dentry *dentry = d_find_alias(inode);
55 if (!dentry)
56 goto out;
57
58 rcu_read_lock();
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);
63 no_parent = false;
64 }
65 rcu_read_unlock();
66 dput(dentry);
67 }
68
69 if (no_parent) {
70 if (!S_ISDIR(inode->i_mode))
71 goto out;
72 sfh->parent_ino = sfh->ino;
73 sfh->hash = 0;
74 }
75 sfh->ino = ceph_ino(inode);
76 sfh->snapid = snapid;
77
78 *max_len = snap_handle_length;
79 ret = FILEID_BTRFS_WITH_PARENT;
80out:
81 dout("encode_snapfh %llx.%llx ret=%d\n", ceph_vinop(inode), ret);
82 return ret;
83}
84
Sage Weilc8628682012-04-05 12:07:36 -070085static int ceph_encode_fh(struct inode *inode, u32 *rawfh, int *max_len,
86 struct inode *parent_inode)
Sage Weila8e63b72009-10-06 11:31:13 -070087{
Krzysztof Wilczynski536cc332019-08-31 23:57:12 +020088 static const int handle_length =
Yan, Zheng570df4e2017-11-15 17:39:40 +080089 sizeof(struct ceph_nfs_fh) >> 2;
Krzysztof Wilczynski536cc332019-08-31 23:57:12 +020090 static const int connected_handle_length =
Yan, Zheng570df4e2017-11-15 17:39:40 +080091 sizeof(struct ceph_nfs_confh) >> 2;
Aneesh Kumar K.V92923dc2010-10-05 16:03:41 +053092 int type;
Sage Weila8e63b72009-10-06 11:31:13 -070093
Sage Weila8e63b72009-10-06 11:31:13 -070094 if (ceph_snap(inode) != CEPH_NOSNAP)
Yan, Zheng570df4e2017-11-15 17:39:40 +080095 return ceph_encode_snapfh(inode, rawfh, max_len, parent_inode);
Sage Weila8e63b72009-10-06 11:31:13 -070096
Yan, Zheng4f32b422014-03-01 18:05:41 +080097 if (parent_inode && (*max_len < connected_handle_length)) {
Aneesh Kumar K.V92923dc2010-10-05 16:03:41 +053098 *max_len = connected_handle_length;
Yan, Zheng4f32b422014-03-01 18:05:41 +080099 return FILEID_INVALID;
100 } else if (*max_len < handle_length) {
Aneesh Kumar K.Vbba0cd02010-10-05 16:03:42 +0530101 *max_len = handle_length;
Yan, Zheng4f32b422014-03-01 18:05:41 +0800102 return FILEID_INVALID;
Sage Weila8e63b72009-10-06 11:31:13 -0700103 }
Yan, Zheng4f32b422014-03-01 18:05:41 +0800104
105 if (parent_inode) {
Yan, Zheng570df4e2017-11-15 17:39:40 +0800106 struct ceph_nfs_confh *cfh = (void *)rawfh;
Yan, Zheng4f32b422014-03-01 18:05:41 +0800107 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;
113 } else {
Yan, Zheng570df4e2017-11-15 17:39:40 +0800114 struct ceph_nfs_fh *fh = (void *)rawfh;
Yan, Zheng4f32b422014-03-01 18:05:41 +0800115 dout("encode_fh %llx\n", ceph_ino(inode));
116 fh->ino = ceph_ino(inode);
117 *max_len = handle_length;
118 type = FILEID_INO32_GEN;
119 }
Sage Weila8e63b72009-10-06 11:31:13 -0700120 return type;
121}
122
Yan, Zheng570df4e2017-11-15 17:39:40 +0800123static struct inode *__lookup_inode(struct super_block *sb, u64 ino)
Sage Weila8e63b72009-10-06 11:31:13 -0700124{
Sage Weil3c454cf2011-04-06 09:31:40 -0700125 struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
Sage Weila8e63b72009-10-06 11:31:13 -0700126 struct inode *inode;
Sage Weila8e63b72009-10-06 11:31:13 -0700127 struct ceph_vino vino;
128 int err;
129
Yan, Zheng4f32b422014-03-01 18:05:41 +0800130 vino.ino = ino;
Sage Weila8e63b72009-10-06 11:31:13 -0700131 vino.snap = CEPH_NOSNAP;
Jeff Laytond4f6b312021-04-01 13:55:11 -0400132
133 if (ceph_vino_is_reserved(vino))
134 return ERR_PTR(-ESTALE);
135
Sage Weila8e63b72009-10-06 11:31:13 -0700136 inode = ceph_find_inode(sb, vino);
Sage Weil3c454cf2011-04-06 09:31:40 -0700137 if (!inode) {
138 struct ceph_mds_request *req;
Yan, Zheng315f2402016-03-07 10:34:50 +0800139 int mask;
Sage Weil3c454cf2011-04-06 09:31:40 -0700140
141 req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPINO,
142 USE_ANY_MDS);
143 if (IS_ERR(req))
144 return ERR_CAST(req);
145
Yan, Zheng315f2402016-03-07 10:34:50 +0800146 mask = CEPH_STAT_CAP_INODE;
147 if (ceph_security_xattr_wanted(d_inode(sb->s_root)))
148 mask |= CEPH_CAP_XATTR_SHARED;
Yan, Zheng570df4e2017-11-15 17:39:40 +0800149 req->r_args.lookupino.mask = cpu_to_le32(mask);
Yan, Zheng315f2402016-03-07 10:34:50 +0800150
Sage Weil3c454cf2011-04-06 09:31:40 -0700151 req->r_ino1 = vino;
152 req->r_num_caps = 1;
153 err = ceph_mdsc_do_request(mdsc, NULL, req);
Sage Weil45e3d3e2011-04-06 09:35:00 -0700154 inode = req->r_target_inode;
155 if (inode)
Sage Weil70b666c2011-05-27 09:24:26 -0700156 ihold(inode);
Sage Weil3c454cf2011-04-06 09:31:40 -0700157 ceph_mdsc_put_request(req);
Sage Weil3c454cf2011-04-06 09:31:40 -0700158 if (!inode)
Luis Henriques38862742019-03-21 10:20:09 +0000159 return err < 0 ? ERR_PTR(err) : ERR_PTR(-ESTALE);
Jeff Layton5d6451b2021-08-31 13:39:13 -0400160 } else {
161 if (ceph_inode_is_shutdown(inode)) {
162 iput(inode);
163 return ERR_PTR(-ESTALE);
164 }
Sage Weil3c454cf2011-04-06 09:31:40 -0700165 }
Yan, Zheng570df4e2017-11-15 17:39:40 +0800166 return inode;
167}
Sage Weila8e63b72009-10-06 11:31:13 -0700168
Yan, Zheng570df4e2017-11-15 17:39:40 +0800169struct inode *ceph_lookup_inode(struct super_block *sb, u64 ino)
170{
171 struct inode *inode = __lookup_inode(sb, ino);
172 if (IS_ERR(inode))
173 return inode;
174 if (inode->i_nlink == 0) {
175 iput(inode);
176 return ERR_PTR(-ESTALE);
177 }
Luis Henriques38862742019-03-21 10:20:09 +0000178 return inode;
179}
180
181static struct dentry *__fh_to_dentry(struct super_block *sb, u64 ino)
182{
Yan, Zheng570df4e2017-11-15 17:39:40 +0800183 struct inode *inode = __lookup_inode(sb, ino);
Luis Henriques878dabb2020-05-18 18:47:26 +0100184 int err;
185
Luis Henriques38862742019-03-21 10:20:09 +0000186 if (IS_ERR(inode))
187 return ERR_CAST(inode);
Luis Henriques878dabb2020-05-18 18:47:26 +0100188 /* We need LINK caps to reliably check i_nlink */
189 err = ceph_do_getattr(inode, CEPH_CAP_LINK_SHARED, false);
Jeff Layton1775c7d2021-03-26 09:21:53 -0400190 if (err) {
191 iput(inode);
Luis Henriques878dabb2020-05-18 18:47:26 +0100192 return ERR_PTR(err);
Jeff Layton1775c7d2021-03-26 09:21:53 -0400193 }
Luis Henriques878dabb2020-05-18 18:47:26 +0100194 /* -ESTALE if inode as been unlinked and no file is open */
195 if ((inode->i_nlink == 0) && (atomic_read(&inode->i_count) == 1)) {
Yan, Zheng570df4e2017-11-15 17:39:40 +0800196 iput(inode);
197 return ERR_PTR(-ESTALE);
198 }
Al Viroad5cb122016-10-28 22:05:13 -0400199 return d_obtain_alias(inode);
Sage Weila8e63b72009-10-06 11:31:13 -0700200}
201
Yan, Zheng570df4e2017-11-15 17:39:40 +0800202static struct dentry *__snapfh_to_dentry(struct super_block *sb,
203 struct ceph_nfs_snapfh *sfh,
204 bool want_parent)
205{
206 struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
207 struct ceph_mds_request *req;
208 struct inode *inode;
209 struct ceph_vino vino;
210 int mask;
211 int err;
212 bool unlinked = false;
213
214 if (want_parent) {
215 vino.ino = sfh->parent_ino;
216 if (sfh->snapid == CEPH_SNAPDIR)
217 vino.snap = CEPH_NOSNAP;
218 else if (sfh->ino == sfh->parent_ino)
219 vino.snap = CEPH_SNAPDIR;
220 else
221 vino.snap = sfh->snapid;
222 } else {
223 vino.ino = sfh->ino;
224 vino.snap = sfh->snapid;
225 }
Jeff Laytond4f6b312021-04-01 13:55:11 -0400226
227 if (ceph_vino_is_reserved(vino))
228 return ERR_PTR(-ESTALE);
229
Yan, Zheng570df4e2017-11-15 17:39:40 +0800230 inode = ceph_find_inode(sb, vino);
Jeff Layton5d6451b2021-08-31 13:39:13 -0400231 if (inode) {
232 if (ceph_inode_is_shutdown(inode)) {
233 iput(inode);
234 return ERR_PTR(-ESTALE);
235 }
Yan, Zheng570df4e2017-11-15 17:39:40 +0800236 return d_obtain_alias(inode);
Jeff Layton5d6451b2021-08-31 13:39:13 -0400237 }
Yan, Zheng570df4e2017-11-15 17:39:40 +0800238
239 req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPINO,
240 USE_ANY_MDS);
241 if (IS_ERR(req))
242 return ERR_CAST(req);
243
244 mask = CEPH_STAT_CAP_INODE;
245 if (ceph_security_xattr_wanted(d_inode(sb->s_root)))
246 mask |= CEPH_CAP_XATTR_SHARED;
247 req->r_args.lookupino.mask = cpu_to_le32(mask);
248 if (vino.snap < CEPH_NOSNAP) {
249 req->r_args.lookupino.snapid = cpu_to_le64(vino.snap);
250 if (!want_parent && sfh->ino != sfh->parent_ino) {
251 req->r_args.lookupino.parent =
252 cpu_to_le64(sfh->parent_ino);
253 req->r_args.lookupino.hash =
254 cpu_to_le32(sfh->hash);
255 }
256 }
257
258 req->r_ino1 = vino;
259 req->r_num_caps = 1;
260 err = ceph_mdsc_do_request(mdsc, NULL, req);
261 inode = req->r_target_inode;
262 if (inode) {
263 if (vino.snap == CEPH_SNAPDIR) {
264 if (inode->i_nlink == 0)
265 unlinked = true;
266 inode = ceph_get_snapdir(inode);
267 } else if (ceph_snap(inode) == vino.snap) {
268 ihold(inode);
269 } else {
270 /* mds does not support lookup snapped inode */
Jeff Layton3e10a152021-02-25 15:04:15 -0500271 inode = ERR_PTR(-EOPNOTSUPP);
Yan, Zheng570df4e2017-11-15 17:39:40 +0800272 }
Jeff Layton3e10a152021-02-25 15:04:15 -0500273 } else {
274 inode = ERR_PTR(-ESTALE);
Yan, Zheng570df4e2017-11-15 17:39:40 +0800275 }
276 ceph_mdsc_put_request(req);
277
278 if (want_parent) {
279 dout("snapfh_to_parent %llx.%llx\n err=%d\n",
280 vino.ino, vino.snap, err);
281 } else {
282 dout("snapfh_to_dentry %llx.%llx parent %llx hash %x err=%d",
283 vino.ino, vino.snap, sfh->parent_ino, sfh->hash, err);
284 }
Jeff Layton3e10a152021-02-25 15:04:15 -0500285 if (IS_ERR(inode))
286 return ERR_CAST(inode);
Yan, Zheng570df4e2017-11-15 17:39:40 +0800287 /* see comments in ceph_get_parent() */
288 return unlinked ? d_obtain_root(inode) : d_obtain_alias(inode);
289}
290
Sage Weila8e63b72009-10-06 11:31:13 -0700291/*
Yan, Zheng4f32b422014-03-01 18:05:41 +0800292 * convert regular fh to dentry
Sage Weila8e63b72009-10-06 11:31:13 -0700293 */
Yan, Zheng4f32b422014-03-01 18:05:41 +0800294static struct dentry *ceph_fh_to_dentry(struct super_block *sb,
295 struct fid *fid,
Sage Weila8e63b72009-10-06 11:31:13 -0700296 int fh_len, int fh_type)
297{
Yan, Zheng4f32b422014-03-01 18:05:41 +0800298 struct ceph_nfs_fh *fh = (void *)fid->raw;
299
Yan, Zheng570df4e2017-11-15 17:39:40 +0800300 if (fh_type == FILEID_BTRFS_WITH_PARENT) {
301 struct ceph_nfs_snapfh *sfh = (void *)fid->raw;
302 return __snapfh_to_dentry(sb, sfh, false);
303 }
304
Yan, Zheng4f32b422014-03-01 18:05:41 +0800305 if (fh_type != FILEID_INO32_GEN &&
306 fh_type != FILEID_INO32_GEN_PARENT)
307 return NULL;
308 if (fh_len < sizeof(*fh) / 4)
309 return NULL;
310
311 dout("fh_to_dentry %llx\n", fh->ino);
312 return __fh_to_dentry(sb, fh->ino);
Sage Weila8e63b72009-10-06 11:31:13 -0700313}
314
Yan, Zheng9017c2e2014-03-01 22:11:45 +0800315static struct dentry *__get_parent(struct super_block *sb,
316 struct dentry *child, u64 ino)
317{
318 struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
319 struct ceph_mds_request *req;
320 struct inode *inode;
Yan, Zheng315f2402016-03-07 10:34:50 +0800321 int mask;
Yan, Zheng9017c2e2014-03-01 22:11:45 +0800322 int err;
323
324 req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPPARENT,
325 USE_ANY_MDS);
326 if (IS_ERR(req))
327 return ERR_CAST(req);
328
329 if (child) {
David Howells2b0143b2015-03-17 22:25:59 +0000330 req->r_inode = d_inode(child);
331 ihold(d_inode(child));
Yan, Zheng9017c2e2014-03-01 22:11:45 +0800332 } else {
333 req->r_ino1 = (struct ceph_vino) {
334 .ino = ino,
335 .snap = CEPH_NOSNAP,
336 };
337 }
Yan, Zheng315f2402016-03-07 10:34:50 +0800338
339 mask = CEPH_STAT_CAP_INODE;
340 if (ceph_security_xattr_wanted(d_inode(sb->s_root)))
341 mask |= CEPH_CAP_XATTR_SHARED;
342 req->r_args.getattr.mask = cpu_to_le32(mask);
343
Yan, Zheng9017c2e2014-03-01 22:11:45 +0800344 req->r_num_caps = 1;
345 err = ceph_mdsc_do_request(mdsc, NULL, req);
Qiujun Huangc6d50292020-03-06 09:34:20 +0800346 if (err) {
347 ceph_mdsc_put_request(req);
348 return ERR_PTR(err);
349 }
350
Yan, Zheng9017c2e2014-03-01 22:11:45 +0800351 inode = req->r_target_inode;
352 if (inode)
353 ihold(inode);
354 ceph_mdsc_put_request(req);
355 if (!inode)
356 return ERR_PTR(-ENOENT);
357
Al Viroad5cb122016-10-28 22:05:13 -0400358 return d_obtain_alias(inode);
Yan, Zheng9017c2e2014-03-01 22:11:45 +0800359}
360
Fengguang Wue84be112014-04-09 14:11:31 +0800361static struct dentry *ceph_get_parent(struct dentry *child)
Yan, Zheng9017c2e2014-03-01 22:11:45 +0800362{
Yan, Zheng570df4e2017-11-15 17:39:40 +0800363 struct inode *inode = d_inode(child);
364 struct dentry *dn;
Yan, Zheng9017c2e2014-03-01 22:11:45 +0800365
Yan, Zheng570df4e2017-11-15 17:39:40 +0800366 if (ceph_snap(inode) != CEPH_NOSNAP) {
367 struct inode* dir;
368 bool unlinked = false;
369 /* do not support non-directory */
370 if (!d_is_dir(child)) {
371 dn = ERR_PTR(-EINVAL);
372 goto out;
373 }
374 dir = __lookup_inode(inode->i_sb, ceph_ino(inode));
375 if (IS_ERR(dir)) {
376 dn = ERR_CAST(dir);
377 goto out;
378 }
379 /* There can be multiple paths to access snapped inode.
380 * For simplicity, treat snapdir of head inode as parent */
381 if (ceph_snap(inode) != CEPH_SNAPDIR) {
382 struct inode *snapdir = ceph_get_snapdir(dir);
383 if (dir->i_nlink == 0)
384 unlinked = true;
385 iput(dir);
386 if (IS_ERR(snapdir)) {
387 dn = ERR_CAST(snapdir);
388 goto out;
389 }
390 dir = snapdir;
391 }
392 /* If directory has already been deleted, futher get_parent
393 * will fail. Do not mark snapdir dentry as disconnected,
394 * this prevent exportfs from doing futher get_parent. */
395 if (unlinked)
396 dn = d_obtain_root(dir);
397 else
398 dn = d_obtain_alias(dir);
399 } else {
400 dn = __get_parent(child->d_sb, child, 0);
401 }
402out:
403 dout("get_parent %p ino %llx.%llx err=%ld\n",
Hariprasad Kelam03af4392019-05-25 14:45:59 +0530404 child, ceph_vinop(inode), (long)PTR_ERR_OR_ZERO(dn));
Yan, Zheng570df4e2017-11-15 17:39:40 +0800405 return dn;
Yan, Zheng9017c2e2014-03-01 22:11:45 +0800406}
407
Sage Weila8e63b72009-10-06 11:31:13 -0700408/*
Yan, Zheng8996f4f2014-03-01 23:09:05 +0800409 * convert regular fh to parent
Sage Weila8e63b72009-10-06 11:31:13 -0700410 */
411static struct dentry *ceph_fh_to_parent(struct super_block *sb,
Yan, Zheng8996f4f2014-03-01 23:09:05 +0800412 struct fid *fid,
Sage Weila8e63b72009-10-06 11:31:13 -0700413 int fh_len, int fh_type)
414{
415 struct ceph_nfs_confh *cfh = (void *)fid->raw;
Sage Weila8e63b72009-10-06 11:31:13 -0700416 struct dentry *dentry;
Sage Weila8e63b72009-10-06 11:31:13 -0700417
Yan, Zheng570df4e2017-11-15 17:39:40 +0800418 if (fh_type == FILEID_BTRFS_WITH_PARENT) {
419 struct ceph_nfs_snapfh *sfh = (void *)fid->raw;
420 return __snapfh_to_dentry(sb, sfh, true);
421 }
422
Yan, Zheng8996f4f2014-03-01 23:09:05 +0800423 if (fh_type != FILEID_INO32_GEN_PARENT)
424 return NULL;
Hugh Dickins35c2a7f2012-10-07 20:32:51 -0700425 if (fh_len < sizeof(*cfh) / 4)
Yan, Zheng8996f4f2014-03-01 23:09:05 +0800426 return NULL;
Sage Weila8e63b72009-10-06 11:31:13 -0700427
Yan, Zheng8996f4f2014-03-01 23:09:05 +0800428 dout("fh_to_parent %llx\n", cfh->parent_ino);
429 dentry = __get_parent(sb, NULL, cfh->ino);
Al Virob42b90d2016-06-24 23:49:03 -0400430 if (unlikely(dentry == ERR_PTR(-ENOENT)))
Yan, Zheng8996f4f2014-03-01 23:09:05 +0800431 dentry = __fh_to_dentry(sb, cfh->parent_ino);
Sage Weila8e63b72009-10-06 11:31:13 -0700432 return dentry;
433}
434
Yan, Zheng570df4e2017-11-15 17:39:40 +0800435static int __get_snap_name(struct dentry *parent, char *name,
436 struct dentry *child)
437{
438 struct inode *inode = d_inode(child);
439 struct inode *dir = d_inode(parent);
440 struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
441 struct ceph_mds_request *req = NULL;
442 char *last_name = NULL;
443 unsigned next_offset = 2;
444 int err = -EINVAL;
445
446 if (ceph_ino(inode) != ceph_ino(dir))
447 goto out;
448 if (ceph_snap(inode) == CEPH_SNAPDIR) {
449 if (ceph_snap(dir) == CEPH_NOSNAP) {
450 strcpy(name, fsc->mount_options->snapdir_name);
451 err = 0;
452 }
453 goto out;
454 }
455 if (ceph_snap(dir) != CEPH_SNAPDIR)
456 goto out;
457
458 while (1) {
459 struct ceph_mds_reply_info_parsed *rinfo;
460 struct ceph_mds_reply_dir_entry *rde;
461 int i;
462
463 req = ceph_mdsc_create_request(fsc->mdsc, CEPH_MDS_OP_LSSNAP,
464 USE_AUTH_MDS);
465 if (IS_ERR(req)) {
466 err = PTR_ERR(req);
467 req = NULL;
468 goto out;
469 }
470 err = ceph_alloc_readdir_reply_buffer(req, inode);
471 if (err)
472 goto out;
473
474 req->r_direct_mode = USE_AUTH_MDS;
475 req->r_readdir_offset = next_offset;
476 req->r_args.readdir.flags =
477 cpu_to_le16(CEPH_READDIR_REPLY_BITFLAGS);
478 if (last_name) {
479 req->r_path2 = last_name;
480 last_name = NULL;
481 }
482
483 req->r_inode = dir;
484 ihold(dir);
485 req->r_dentry = dget(parent);
486
487 inode_lock(dir);
488 err = ceph_mdsc_do_request(fsc->mdsc, NULL, req);
489 inode_unlock(dir);
490
491 if (err < 0)
492 goto out;
493
Ilya Dryomov0ed26f32019-07-29 11:33:08 +0200494 rinfo = &req->r_reply_info;
495 for (i = 0; i < rinfo->dir_nr; i++) {
496 rde = rinfo->dir_entries + i;
497 BUG_ON(!rde->inode.in);
498 if (ceph_snap(inode) ==
499 le64_to_cpu(rde->inode.in->snapid)) {
500 memcpy(name, rde->name, rde->name_len);
501 name[rde->name_len] = '\0';
502 err = 0;
503 goto out;
504 }
505 }
Yan, Zheng570df4e2017-11-15 17:39:40 +0800506
Ilya Dryomov0ed26f32019-07-29 11:33:08 +0200507 if (rinfo->dir_end)
508 break;
Yan, Zheng570df4e2017-11-15 17:39:40 +0800509
Ilya Dryomov0ed26f32019-07-29 11:33:08 +0200510 BUG_ON(rinfo->dir_nr <= 0);
511 rde = rinfo->dir_entries + (rinfo->dir_nr - 1);
512 next_offset += rinfo->dir_nr;
513 last_name = kstrndup(rde->name, rde->name_len, GFP_KERNEL);
514 if (!last_name) {
515 err = -ENOMEM;
516 goto out;
517 }
Yan, Zheng570df4e2017-11-15 17:39:40 +0800518
Ilya Dryomov0ed26f32019-07-29 11:33:08 +0200519 ceph_mdsc_put_request(req);
520 req = NULL;
Yan, Zheng570df4e2017-11-15 17:39:40 +0800521 }
522 err = -ENOENT;
523out:
524 if (req)
525 ceph_mdsc_put_request(req);
526 kfree(last_name);
527 dout("get_snap_name %p ino %llx.%llx err=%d\n",
528 child, ceph_vinop(inode), err);
529 return err;
530}
531
Yan, Zheng19913b42014-03-06 16:40:32 +0800532static int ceph_get_name(struct dentry *parent, char *name,
533 struct dentry *child)
534{
535 struct ceph_mds_client *mdsc;
536 struct ceph_mds_request *req;
Yan, Zheng570df4e2017-11-15 17:39:40 +0800537 struct inode *inode = d_inode(child);
Yan, Zheng19913b42014-03-06 16:40:32 +0800538 int err;
539
Yan, Zheng570df4e2017-11-15 17:39:40 +0800540 if (ceph_snap(inode) != CEPH_NOSNAP)
541 return __get_snap_name(parent, name, child);
542
543 mdsc = ceph_inode_to_client(inode)->mdsc;
Yan, Zheng19913b42014-03-06 16:40:32 +0800544 req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPNAME,
545 USE_ANY_MDS);
546 if (IS_ERR(req))
547 return PTR_ERR(req);
548
Al Viro59551022016-01-22 15:40:57 -0500549 inode_lock(d_inode(parent));
Yan, Zheng19913b42014-03-06 16:40:32 +0800550
Yan, Zheng570df4e2017-11-15 17:39:40 +0800551 req->r_inode = inode;
552 ihold(inode);
David Howells2b0143b2015-03-17 22:25:59 +0000553 req->r_ino2 = ceph_vino(d_inode(parent));
Jeff Layton3dd69aa2017-01-31 10:28:26 -0500554 req->r_parent = d_inode(parent);
Jeff Layton4c183472021-06-18 13:05:06 -0400555 ihold(req->r_parent);
Jeff Layton3dd69aa2017-01-31 10:28:26 -0500556 set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags);
Yan, Zheng19913b42014-03-06 16:40:32 +0800557 req->r_num_caps = 2;
558 err = ceph_mdsc_do_request(mdsc, NULL, req);
559
Al Viro59551022016-01-22 15:40:57 -0500560 inode_unlock(d_inode(parent));
Yan, Zheng19913b42014-03-06 16:40:32 +0800561
562 if (!err) {
563 struct ceph_mds_reply_info_parsed *rinfo = &req->r_reply_info;
564 memcpy(name, rinfo->dname, rinfo->dname_len);
565 name[rinfo->dname_len] = 0;
566 dout("get_name %p ino %llx.%llx name %s\n",
Yan, Zheng570df4e2017-11-15 17:39:40 +0800567 child, ceph_vinop(inode), name);
Yan, Zheng19913b42014-03-06 16:40:32 +0800568 } else {
569 dout("get_name %p ino %llx.%llx err %d\n",
Yan, Zheng570df4e2017-11-15 17:39:40 +0800570 child, ceph_vinop(inode), err);
Yan, Zheng19913b42014-03-06 16:40:32 +0800571 }
572
573 ceph_mdsc_put_request(req);
574 return err;
575}
576
Sage Weila8e63b72009-10-06 11:31:13 -0700577const struct export_operations ceph_export_ops = {
578 .encode_fh = ceph_encode_fh,
Sage Weila8e63b72009-10-06 11:31:13 -0700579 .fh_to_dentry = ceph_fh_to_dentry,
580 .fh_to_parent = ceph_fh_to_parent,
Yan, Zheng9017c2e2014-03-01 22:11:45 +0800581 .get_parent = ceph_get_parent,
Yan, Zheng19913b42014-03-06 16:40:32 +0800582 .get_name = ceph_get_name,
Sage Weila8e63b72009-10-06 11:31:13 -0700583};