Linux Audio

Check our new training course

Loading...
v5.4
  1// SPDX-License-Identifier: GPL-2.0
  2#include <linux/ceph/ceph_debug.h>
  3
  4#include <linux/exportfs.h>
  5#include <linux/slab.h>
  6#include <asm/unaligned.h>
  7
  8#include "super.h"
  9#include "mds_client.h"
 10
 11/*
 12 * Basic fh
 13 */
 14struct ceph_nfs_fh {
 15	u64 ino;
 16} __attribute__ ((packed));
 17
 18/*
 19 * Larger fh that includes parent ino.
 20 */
 21struct ceph_nfs_confh {
 22	u64 ino, parent_ino;
 23} __attribute__ ((packed));
 24
 25/*
 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{
 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);
 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
 85static int ceph_encode_fh(struct inode *inode, u32 *rawfh, int *max_len,
 86			  struct inode *parent_inode)
 87{
 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;
 92	int type;
 
 
 
 
 93
 
 94	if (ceph_snap(inode) != CEPH_NOSNAP)
 95		return ceph_encode_snapfh(inode, rawfh, max_len, parent_inode);
 96
 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;
103	}
104
105	if (parent_inode) {
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;
113	} else {
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;
119	}
120	return type;
121}
122
123static struct inode *__lookup_inode(struct super_block *sb, u64 ino)
124{
125	struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
126	struct inode *inode;
127	struct ceph_vino vino;
128	int err;
129
130	vino.ino = ino;
131	vino.snap = CEPH_NOSNAP;
132	inode = ceph_find_inode(sb, vino);
133	if (!inode) {
134		struct ceph_mds_request *req;
135		int mask;
136
137		req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPINO,
138					       USE_ANY_MDS);
139		if (IS_ERR(req))
140			return ERR_CAST(req);
141
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);
146
147		req->r_ino1 = vino;
148		req->r_num_caps = 1;
149		err = ceph_mdsc_do_request(mdsc, NULL, req);
150		inode = req->r_target_inode;
151		if (inode)
152			ihold(inode);
153		ceph_mdsc_put_request(req);
154		if (!inode)
155			return err < 0 ? ERR_PTR(err) : ERR_PTR(-ESTALE);
156	}
157	return inode;
158}
159
160struct inode *ceph_lookup_inode(struct super_block *sb, u64 ino)
161{
162	struct inode *inode = __lookup_inode(sb, ino);
163	if (IS_ERR(inode))
164		return inode;
165	if (inode->i_nlink == 0) {
166		iput(inode);
167		return ERR_PTR(-ESTALE);
168	}
169	return inode;
170}
171
172static struct dentry *__fh_to_dentry(struct super_block *sb, u64 ino)
173{
174	struct inode *inode = __lookup_inode(sb, ino);
175	if (IS_ERR(inode))
176		return ERR_CAST(inode);
177	if (inode->i_nlink == 0) {
178		iput(inode);
179		return ERR_PTR(-ESTALE);
180	}
181	return d_obtain_alias(inode);
182}
183
184static struct dentry *__snapfh_to_dentry(struct super_block *sb,
185					  struct ceph_nfs_snapfh *sfh,
186					  bool want_parent)
187{
188	struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
189	struct ceph_mds_request *req;
190	struct inode *inode;
191	struct ceph_vino vino;
192	int mask;
193	int err;
194	bool unlinked = false;
195
196	if (want_parent) {
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;
202		else
203			vino.snap = sfh->snapid;
204	} else {
205		vino.ino = sfh->ino;
206		vino.snap = sfh->snapid;
207	}
208	inode = ceph_find_inode(sb, vino);
209	if (inode)
210		return d_obtain_alias(inode);
211
212	req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPINO,
213				       USE_ANY_MDS);
214	if (IS_ERR(req))
215		return ERR_CAST(req);
216
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);
228		}
229	}
230
231	req->r_ino1 = vino;
232	req->r_num_caps = 1;
233	err = ceph_mdsc_do_request(mdsc, NULL, req);
234	inode = req->r_target_inode;
235	if (inode) {
236		if (vino.snap == CEPH_SNAPDIR) {
237			if (inode->i_nlink == 0)
238				unlinked = true;
239			inode = ceph_get_snapdir(inode);
240		} else if (ceph_snap(inode) == vino.snap) {
241			ihold(inode);
242		} else {
243			/* mds does not support lookup snapped inode */
244			err = -EOPNOTSUPP;
245			inode = NULL;
246		}
247	}
248	ceph_mdsc_put_request(req);
249
250	if (want_parent) {
251		dout("snapfh_to_parent %llx.%llx\n err=%d\n",
252		     vino.ino, vino.snap, err);
253	} else {
254		dout("snapfh_to_dentry %llx.%llx parent %llx hash %x err=%d",
255		      vino.ino, vino.snap, sfh->parent_ino, sfh->hash, err);
256	}
257	if (!inode)
258		return ERR_PTR(-ESTALE);
259	/* see comments in ceph_get_parent() */
260	return unlinked ? d_obtain_root(inode) : d_obtain_alias(inode);
261}
262
263/*
264 * convert regular fh to dentry
265 */
266static struct dentry *ceph_fh_to_dentry(struct super_block *sb,
267					struct fid *fid,
268					int fh_len, int fh_type)
269{
270	struct ceph_nfs_fh *fh = (void *)fid->raw;
271
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);
275	}
276
277	if (fh_type != FILEID_INO32_GEN  &&
278	    fh_type != FILEID_INO32_GEN_PARENT)
279		return NULL;
280	if (fh_len < sizeof(*fh) / 4)
281		return NULL;
282
283	dout("fh_to_dentry %llx\n", fh->ino);
284	return __fh_to_dentry(sb, fh->ino);
285}
286
287static struct dentry *__get_parent(struct super_block *sb,
288				   struct dentry *child, u64 ino)
289{
290	struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
291	struct ceph_mds_request *req;
292	struct inode *inode;
293	int mask;
294	int err;
295
296	req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPPARENT,
297				       USE_ANY_MDS);
298	if (IS_ERR(req))
299		return ERR_CAST(req);
300
301	if (child) {
302		req->r_inode = d_inode(child);
303		ihold(d_inode(child));
304	} else {
305		req->r_ino1 = (struct ceph_vino) {
306			.ino = ino,
307			.snap = CEPH_NOSNAP,
308		};
309	}
310
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);
315
316	req->r_num_caps = 1;
317	err = ceph_mdsc_do_request(mdsc, NULL, req);
318	inode = req->r_target_inode;
319	if (inode)
320		ihold(inode);
321	ceph_mdsc_put_request(req);
322	if (!inode)
323		return ERR_PTR(-ENOENT);
324
325	return d_obtain_alias(inode);
326}
327
328static struct dentry *ceph_get_parent(struct dentry *child)
329{
330	struct inode *inode = d_inode(child);
331	struct dentry *dn;
332
333	if (ceph_snap(inode) != CEPH_NOSNAP) {
334		struct inode* dir;
335		bool unlinked = false;
336		/* do not support non-directory */
337		if (!d_is_dir(child)) {
338			dn = ERR_PTR(-EINVAL);
339			goto out;
340		}
341		dir = __lookup_inode(inode->i_sb, ceph_ino(inode));
342		if (IS_ERR(dir)) {
343			dn = ERR_CAST(dir);
344			goto out;
345		}
346		/* There can be multiple paths to access snapped inode.
347		 * For simplicity, treat snapdir of head inode as parent */
348		if (ceph_snap(inode) != CEPH_SNAPDIR) {
349			struct inode *snapdir = ceph_get_snapdir(dir);
350			if (dir->i_nlink == 0)
351				unlinked = true;
352			iput(dir);
353			if (IS_ERR(snapdir)) {
354				dn = ERR_CAST(snapdir);
355				goto out;
356			}
357			dir = snapdir;
358		}
359		/* If directory has already been deleted, futher get_parent
360		 * will fail. Do not mark snapdir dentry as disconnected,
361		 * this prevent exportfs from doing futher get_parent. */
362		if (unlinked)
363			dn = d_obtain_root(dir);
364		else
365			dn = d_obtain_alias(dir);
366	} else {
367		dn = __get_parent(child->d_sb, child, 0);
368	}
369out:
370	dout("get_parent %p ino %llx.%llx err=%ld\n",
371	     child, ceph_vinop(inode), (long)PTR_ERR_OR_ZERO(dn));
372	return dn;
373}
374
375/*
376 * convert regular fh to parent
377 */
378static struct dentry *ceph_fh_to_parent(struct super_block *sb,
379					struct fid *fid,
380					int fh_len, int fh_type)
381{
382	struct ceph_nfs_confh *cfh = (void *)fid->raw;
383	struct dentry *dentry;
384
385	if (fh_type == FILEID_BTRFS_WITH_PARENT) {
386		struct ceph_nfs_snapfh *sfh = (void *)fid->raw;
387		return __snapfh_to_dentry(sb, sfh, true);
388	}
389
390	if (fh_type != FILEID_INO32_GEN_PARENT)
391		return NULL;
392	if (fh_len < sizeof(*cfh) / 4)
393		return NULL;
394
395	dout("fh_to_parent %llx\n", cfh->parent_ino);
396	dentry = __get_parent(sb, NULL, cfh->ino);
397	if (unlikely(dentry == ERR_PTR(-ENOENT)))
398		dentry = __fh_to_dentry(sb, cfh->parent_ino);
399	return dentry;
400}
401
402static int __get_snap_name(struct dentry *parent, char *name,
403			   struct dentry *child)
404{
405	struct inode *inode = d_inode(child);
406	struct inode *dir = d_inode(parent);
407	struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
408	struct ceph_mds_request *req = NULL;
409	char *last_name = NULL;
410	unsigned next_offset = 2;
411	int err = -EINVAL;
412
413	if (ceph_ino(inode) != ceph_ino(dir))
414		goto out;
415	if (ceph_snap(inode) == CEPH_SNAPDIR) {
416		if (ceph_snap(dir) == CEPH_NOSNAP) {
417			strcpy(name, fsc->mount_options->snapdir_name);
418			err = 0;
419		}
420		goto out;
421	}
422	if (ceph_snap(dir) != CEPH_SNAPDIR)
423		goto out;
424
425	while (1) {
426		struct ceph_mds_reply_info_parsed *rinfo;
427		struct ceph_mds_reply_dir_entry *rde;
428		int i;
429
430		req = ceph_mdsc_create_request(fsc->mdsc, CEPH_MDS_OP_LSSNAP,
431					       USE_AUTH_MDS);
432		if (IS_ERR(req)) {
433			err = PTR_ERR(req);
434			req = NULL;
435			goto out;
436		}
437		err = ceph_alloc_readdir_reply_buffer(req, inode);
438		if (err)
439			goto out;
440
441		req->r_direct_mode = USE_AUTH_MDS;
442		req->r_readdir_offset = next_offset;
443		req->r_args.readdir.flags =
444				cpu_to_le16(CEPH_READDIR_REPLY_BITFLAGS);
445		if (last_name) {
446			req->r_path2 = last_name;
447			last_name = NULL;
448		}
449
450		req->r_inode = dir;
451		ihold(dir);
452		req->r_dentry = dget(parent);
453
454		inode_lock(dir);
455		err = ceph_mdsc_do_request(fsc->mdsc, NULL, req);
456		inode_unlock(dir);
457
458		if (err < 0)
459			goto out;
460
461		rinfo = &req->r_reply_info;
462		for (i = 0; i < rinfo->dir_nr; i++) {
463			rde = rinfo->dir_entries + i;
464			BUG_ON(!rde->inode.in);
465			if (ceph_snap(inode) ==
466			    le64_to_cpu(rde->inode.in->snapid)) {
467				memcpy(name, rde->name, rde->name_len);
468				name[rde->name_len] = '\0';
469				err = 0;
470				goto out;
471			}
472		}
473
474		if (rinfo->dir_end)
475			break;
476
477		BUG_ON(rinfo->dir_nr <= 0);
478		rde = rinfo->dir_entries + (rinfo->dir_nr - 1);
479		next_offset += rinfo->dir_nr;
480		last_name = kstrndup(rde->name, rde->name_len, GFP_KERNEL);
481		if (!last_name) {
482			err = -ENOMEM;
483			goto out;
484		}
485
486		ceph_mdsc_put_request(req);
487		req = NULL;
488	}
489	err = -ENOENT;
490out:
491	if (req)
492		ceph_mdsc_put_request(req);
493	kfree(last_name);
494	dout("get_snap_name %p ino %llx.%llx err=%d\n",
495	     child, ceph_vinop(inode), err);
496	return err;
497}
498
499static int ceph_get_name(struct dentry *parent, char *name,
500			 struct dentry *child)
501{
502	struct ceph_mds_client *mdsc;
503	struct ceph_mds_request *req;
504	struct inode *inode = d_inode(child);
505	int err;
506
507	if (ceph_snap(inode) != CEPH_NOSNAP)
508		return __get_snap_name(parent, name, child);
509
510	mdsc = ceph_inode_to_client(inode)->mdsc;
511	req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPNAME,
512				       USE_ANY_MDS);
513	if (IS_ERR(req))
514		return PTR_ERR(req);
515
516	inode_lock(d_inode(parent));
517
518	req->r_inode = inode;
519	ihold(inode);
520	req->r_ino2 = ceph_vino(d_inode(parent));
521	req->r_parent = d_inode(parent);
522	set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags);
523	req->r_num_caps = 2;
524	err = ceph_mdsc_do_request(mdsc, NULL, req);
525
526	inode_unlock(d_inode(parent));
527
528	if (!err) {
529		struct ceph_mds_reply_info_parsed *rinfo = &req->r_reply_info;
530		memcpy(name, rinfo->dname, rinfo->dname_len);
531		name[rinfo->dname_len] = 0;
532		dout("get_name %p ino %llx.%llx name %s\n",
533		     child, ceph_vinop(inode), name);
534	} else {
535		dout("get_name %p ino %llx.%llx err %d\n",
536		     child, ceph_vinop(inode), err);
537	}
538
539	ceph_mdsc_put_request(req);
540	return err;
541}
542
543const struct export_operations ceph_export_ops = {
544	.encode_fh = ceph_encode_fh,
545	.fh_to_dentry = ceph_fh_to_dentry,
546	.fh_to_parent = ceph_fh_to_parent,
547	.get_parent = ceph_get_parent,
548	.get_name = ceph_get_name,
549};
v4.10.11
 
  1#include <linux/ceph/ceph_debug.h>
  2
  3#include <linux/exportfs.h>
  4#include <linux/slab.h>
  5#include <asm/unaligned.h>
  6
  7#include "super.h"
  8#include "mds_client.h"
  9
 10/*
 11 * Basic fh
 12 */
 13struct ceph_nfs_fh {
 14	u64 ino;
 15} __attribute__ ((packed));
 16
 17/*
 18 * Larger fh that includes parent ino.
 19 */
 20struct ceph_nfs_confh {
 21	u64 ino, parent_ino;
 22} __attribute__ ((packed));
 23
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 24static int ceph_encode_fh(struct inode *inode, u32 *rawfh, int *max_len,
 25			  struct inode *parent_inode)
 26{
 
 
 
 
 27	int type;
 28	struct ceph_nfs_fh *fh = (void *)rawfh;
 29	struct ceph_nfs_confh *cfh = (void *)rawfh;
 30	int connected_handle_length = sizeof(*cfh)/4;
 31	int handle_length = sizeof(*fh)/4;
 32
 33	/* don't re-export snaps */
 34	if (ceph_snap(inode) != CEPH_NOSNAP)
 35		return -EINVAL;
 36
 37	if (parent_inode && (*max_len < connected_handle_length)) {
 38		*max_len = connected_handle_length;
 39		return FILEID_INVALID;
 40	} else if (*max_len < handle_length) {
 41		*max_len = handle_length;
 42		return FILEID_INVALID;
 43	}
 44
 45	if (parent_inode) {
 
 46		dout("encode_fh %llx with parent %llx\n",
 47		     ceph_ino(inode), ceph_ino(parent_inode));
 48		cfh->ino = ceph_ino(inode);
 49		cfh->parent_ino = ceph_ino(parent_inode);
 50		*max_len = connected_handle_length;
 51		type = FILEID_INO32_GEN_PARENT;
 52	} else {
 
 53		dout("encode_fh %llx\n", ceph_ino(inode));
 54		fh->ino = ceph_ino(inode);
 55		*max_len = handle_length;
 56		type = FILEID_INO32_GEN;
 57	}
 58	return type;
 59}
 60
 61static struct dentry *__fh_to_dentry(struct super_block *sb, u64 ino)
 62{
 63	struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
 64	struct inode *inode;
 65	struct ceph_vino vino;
 66	int err;
 67
 68	vino.ino = ino;
 69	vino.snap = CEPH_NOSNAP;
 70	inode = ceph_find_inode(sb, vino);
 71	if (!inode) {
 72		struct ceph_mds_request *req;
 73		int mask;
 74
 75		req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPINO,
 76					       USE_ANY_MDS);
 77		if (IS_ERR(req))
 78			return ERR_CAST(req);
 79
 80		mask = CEPH_STAT_CAP_INODE;
 81		if (ceph_security_xattr_wanted(d_inode(sb->s_root)))
 82			mask |= CEPH_CAP_XATTR_SHARED;
 83		req->r_args.getattr.mask = cpu_to_le32(mask);
 84
 85		req->r_ino1 = vino;
 86		req->r_num_caps = 1;
 87		err = ceph_mdsc_do_request(mdsc, NULL, req);
 88		inode = req->r_target_inode;
 89		if (inode)
 90			ihold(inode);
 91		ceph_mdsc_put_request(req);
 92		if (!inode)
 93			return ERR_PTR(-ESTALE);
 
 
 
 
 
 
 
 
 
 
 
 
 94	}
 
 
 95
 
 
 
 
 
 
 
 
 
 96	return d_obtain_alias(inode);
 97}
 98
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 99/*
100 * convert regular fh to dentry
101 */
102static struct dentry *ceph_fh_to_dentry(struct super_block *sb,
103					struct fid *fid,
104					int fh_len, int fh_type)
105{
106	struct ceph_nfs_fh *fh = (void *)fid->raw;
107
 
 
 
 
 
108	if (fh_type != FILEID_INO32_GEN  &&
109	    fh_type != FILEID_INO32_GEN_PARENT)
110		return NULL;
111	if (fh_len < sizeof(*fh) / 4)
112		return NULL;
113
114	dout("fh_to_dentry %llx\n", fh->ino);
115	return __fh_to_dentry(sb, fh->ino);
116}
117
118static struct dentry *__get_parent(struct super_block *sb,
119				   struct dentry *child, u64 ino)
120{
121	struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
122	struct ceph_mds_request *req;
123	struct inode *inode;
124	int mask;
125	int err;
126
127	req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPPARENT,
128				       USE_ANY_MDS);
129	if (IS_ERR(req))
130		return ERR_CAST(req);
131
132	if (child) {
133		req->r_inode = d_inode(child);
134		ihold(d_inode(child));
135	} else {
136		req->r_ino1 = (struct ceph_vino) {
137			.ino = ino,
138			.snap = CEPH_NOSNAP,
139		};
140	}
141
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.getattr.mask = cpu_to_le32(mask);
146
147	req->r_num_caps = 1;
148	err = ceph_mdsc_do_request(mdsc, NULL, req);
149	inode = req->r_target_inode;
150	if (inode)
151		ihold(inode);
152	ceph_mdsc_put_request(req);
153	if (!inode)
154		return ERR_PTR(-ENOENT);
155
156	return d_obtain_alias(inode);
157}
158
159static struct dentry *ceph_get_parent(struct dentry *child)
160{
161	/* don't re-export snaps */
162	if (ceph_snap(d_inode(child)) != CEPH_NOSNAP)
163		return ERR_PTR(-EINVAL);
164
165	dout("get_parent %p ino %llx.%llx\n",
166	     child, ceph_vinop(d_inode(child)));
167	return __get_parent(child->d_sb, child, 0);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168}
169
170/*
171 * convert regular fh to parent
172 */
173static struct dentry *ceph_fh_to_parent(struct super_block *sb,
174					struct fid *fid,
175					int fh_len, int fh_type)
176{
177	struct ceph_nfs_confh *cfh = (void *)fid->raw;
178	struct dentry *dentry;
179
 
 
 
 
 
180	if (fh_type != FILEID_INO32_GEN_PARENT)
181		return NULL;
182	if (fh_len < sizeof(*cfh) / 4)
183		return NULL;
184
185	dout("fh_to_parent %llx\n", cfh->parent_ino);
186	dentry = __get_parent(sb, NULL, cfh->ino);
187	if (unlikely(dentry == ERR_PTR(-ENOENT)))
188		dentry = __fh_to_dentry(sb, cfh->parent_ino);
189	return dentry;
190}
191
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
192static int ceph_get_name(struct dentry *parent, char *name,
193			 struct dentry *child)
194{
195	struct ceph_mds_client *mdsc;
196	struct ceph_mds_request *req;
 
197	int err;
198
199	mdsc = ceph_inode_to_client(d_inode(child))->mdsc;
 
 
 
200	req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPNAME,
201				       USE_ANY_MDS);
202	if (IS_ERR(req))
203		return PTR_ERR(req);
204
205	inode_lock(d_inode(parent));
206
207	req->r_inode = d_inode(child);
208	ihold(d_inode(child));
209	req->r_ino2 = ceph_vino(d_inode(parent));
210	req->r_locked_dir = d_inode(parent);
 
211	req->r_num_caps = 2;
212	err = ceph_mdsc_do_request(mdsc, NULL, req);
213
214	inode_unlock(d_inode(parent));
215
216	if (!err) {
217		struct ceph_mds_reply_info_parsed *rinfo = &req->r_reply_info;
218		memcpy(name, rinfo->dname, rinfo->dname_len);
219		name[rinfo->dname_len] = 0;
220		dout("get_name %p ino %llx.%llx name %s\n",
221		     child, ceph_vinop(d_inode(child)), name);
222	} else {
223		dout("get_name %p ino %llx.%llx err %d\n",
224		     child, ceph_vinop(d_inode(child)), err);
225	}
226
227	ceph_mdsc_put_request(req);
228	return err;
229}
230
231const struct export_operations ceph_export_ops = {
232	.encode_fh = ceph_encode_fh,
233	.fh_to_dentry = ceph_fh_to_dentry,
234	.fh_to_parent = ceph_fh_to_parent,
235	.get_parent = ceph_get_parent,
236	.get_name = ceph_get_name,
237};