Linux Audio

Check our new training course

Loading...
v4.17
  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
 
 
 
 
 
 
 
 
 25static int ceph_encode_fh(struct inode *inode, u32 *rawfh, int *max_len,
 26			  struct inode *parent_inode)
 27{
 28	int type;
 29	struct ceph_nfs_fh *fh = (void *)rawfh;
 30	struct ceph_nfs_confh *cfh = (void *)rawfh;
 31	int connected_handle_length = sizeof(*cfh)/4;
 32	int handle_length = sizeof(*fh)/4;
 
 
 33
 34	/* don't re-export snaps */
 35	if (ceph_snap(inode) != CEPH_NOSNAP)
 36		return -EINVAL;
 37
 38	if (parent_inode && (*max_len < connected_handle_length)) {
 39		*max_len = connected_handle_length;
 40		return FILEID_INVALID;
 41	} else if (*max_len < handle_length) {
 42		*max_len = handle_length;
 43		return FILEID_INVALID;
 44	}
 45
 46	if (parent_inode) {
 47		dout("encode_fh %llx with parent %llx\n",
 48		     ceph_ino(inode), ceph_ino(parent_inode));
 49		cfh->ino = ceph_ino(inode);
 50		cfh->parent_ino = ceph_ino(parent_inode);
 
 
 51		*max_len = connected_handle_length;
 52		type = FILEID_INO32_GEN_PARENT;
 
 
 
 
 
 
 
 
 
 
 
 
 53	} else {
 54		dout("encode_fh %llx\n", ceph_ino(inode));
 55		fh->ino = ceph_ino(inode);
 56		*max_len = handle_length;
 57		type = FILEID_INO32_GEN;
 58	}
 59	return type;
 60}
 61
 62static struct dentry *__fh_to_dentry(struct super_block *sb, u64 ino)
 
 
 
 
 
 
 63{
 64	struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
 65	struct inode *inode;
 
 66	struct ceph_vino vino;
 67	int err;
 68
 69	vino.ino = ino;
 
 70	vino.snap = CEPH_NOSNAP;
 71	inode = ceph_find_inode(sb, vino);
 72	if (!inode) {
 73		struct ceph_mds_request *req;
 74		int mask;
 75
 76		req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPINO,
 77					       USE_ANY_MDS);
 78		if (IS_ERR(req))
 79			return ERR_CAST(req);
 80
 81		mask = CEPH_STAT_CAP_INODE;
 82		if (ceph_security_xattr_wanted(d_inode(sb->s_root)))
 83			mask |= CEPH_CAP_XATTR_SHARED;
 84		req->r_args.getattr.mask = cpu_to_le32(mask);
 85
 86		req->r_ino1 = vino;
 87		req->r_num_caps = 1;
 88		err = ceph_mdsc_do_request(mdsc, NULL, req);
 89		inode = req->r_target_inode;
 90		if (inode)
 91			ihold(inode);
 92		ceph_mdsc_put_request(req);
 93		if (!inode)
 94			return ERR_PTR(-ESTALE);
 95		if (inode->i_nlink == 0) {
 96			iput(inode);
 97			return ERR_PTR(-ESTALE);
 98		}
 99	}
100
101	return d_obtain_alias(inode);
 
 
 
 
 
 
 
 
 
 
 
 
 
102}
103
104/*
105 * convert regular fh to dentry
106 */
107static struct dentry *ceph_fh_to_dentry(struct super_block *sb,
108					struct fid *fid,
109					int fh_len, int fh_type)
110{
111	struct ceph_nfs_fh *fh = (void *)fid->raw;
112
113	if (fh_type != FILEID_INO32_GEN  &&
114	    fh_type != FILEID_INO32_GEN_PARENT)
115		return NULL;
116	if (fh_len < sizeof(*fh) / 4)
117		return NULL;
118
119	dout("fh_to_dentry %llx\n", fh->ino);
120	return __fh_to_dentry(sb, fh->ino);
121}
122
123static struct dentry *__get_parent(struct super_block *sb,
124				   struct dentry *child, u64 ino)
125{
126	struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
127	struct ceph_mds_request *req;
128	struct inode *inode;
129	int mask;
 
130	int err;
131
132	req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPPARENT,
133				       USE_ANY_MDS);
134	if (IS_ERR(req))
135		return ERR_CAST(req);
136
137	if (child) {
138		req->r_inode = d_inode(child);
139		ihold(d_inode(child));
140	} else {
141		req->r_ino1 = (struct ceph_vino) {
142			.ino = ino,
143			.snap = CEPH_NOSNAP,
144		};
145	}
146
147	mask = CEPH_STAT_CAP_INODE;
148	if (ceph_security_xattr_wanted(d_inode(sb->s_root)))
149		mask |= CEPH_CAP_XATTR_SHARED;
150	req->r_args.getattr.mask = cpu_to_le32(mask);
151
152	req->r_num_caps = 1;
153	err = ceph_mdsc_do_request(mdsc, NULL, req);
154	inode = req->r_target_inode;
155	if (inode)
156		ihold(inode);
157	ceph_mdsc_put_request(req);
158	if (!inode)
159		return ERR_PTR(-ENOENT);
160
161	return d_obtain_alias(inode);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162}
163
164static struct dentry *ceph_get_parent(struct dentry *child)
 
165{
166	/* don't re-export snaps */
167	if (ceph_snap(d_inode(child)) != CEPH_NOSNAP)
168		return ERR_PTR(-EINVAL);
169
170	dout("get_parent %p ino %llx.%llx\n",
171	     child, ceph_vinop(d_inode(child)));
172	return __get_parent(child->d_sb, child, 0);
173}
174
175/*
176 * convert regular fh to parent
 
 
 
177 */
178static struct dentry *ceph_fh_to_parent(struct super_block *sb,
179					struct fid *fid,
180					int fh_len, int fh_type)
181{
182	struct ceph_nfs_confh *cfh = (void *)fid->raw;
 
 
183	struct dentry *dentry;
 
184
185	if (fh_type != FILEID_INO32_GEN_PARENT)
186		return NULL;
187	if (fh_len < sizeof(*cfh) / 4)
188		return NULL;
189
190	dout("fh_to_parent %llx\n", cfh->parent_ino);
191	dentry = __get_parent(sb, NULL, cfh->ino);
192	if (unlikely(dentry == ERR_PTR(-ENOENT)))
193		dentry = __fh_to_dentry(sb, cfh->parent_ino);
194	return dentry;
195}
196
197static int ceph_get_name(struct dentry *parent, char *name,
198			 struct dentry *child)
199{
200	struct ceph_mds_client *mdsc;
201	struct ceph_mds_request *req;
202	int err;
203
204	mdsc = ceph_inode_to_client(d_inode(child))->mdsc;
205	req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPNAME,
206				       USE_ANY_MDS);
207	if (IS_ERR(req))
208		return PTR_ERR(req);
209
210	inode_lock(d_inode(parent));
211
212	req->r_inode = d_inode(child);
213	ihold(d_inode(child));
214	req->r_ino2 = ceph_vino(d_inode(parent));
215	req->r_parent = d_inode(parent);
216	set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags);
217	req->r_num_caps = 2;
218	err = ceph_mdsc_do_request(mdsc, NULL, req);
219
220	inode_unlock(d_inode(parent));
221
222	if (!err) {
223		struct ceph_mds_reply_info_parsed *rinfo = &req->r_reply_info;
224		memcpy(name, rinfo->dname, rinfo->dname_len);
225		name[rinfo->dname_len] = 0;
226		dout("get_name %p ino %llx.%llx name %s\n",
227		     child, ceph_vinop(d_inode(child)), name);
228	} else {
229		dout("get_name %p ino %llx.%llx err %d\n",
230		     child, ceph_vinop(d_inode(child)), err);
231	}
232
233	ceph_mdsc_put_request(req);
234	return err;
 
 
 
 
 
 
 
 
 
 
 
 
235}
236
237const struct export_operations ceph_export_ops = {
238	.encode_fh = ceph_encode_fh,
239	.fh_to_dentry = ceph_fh_to_dentry,
240	.fh_to_parent = ceph_fh_to_parent,
241	.get_parent = ceph_get_parent,
242	.get_name = ceph_get_name,
243};
v3.5.6
 
  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 * NFS export support
 12 *
 13 * NFS re-export of a ceph mount is, at present, only semireliable.
 14 * The basic issue is that the Ceph architectures doesn't lend itself
 15 * well to generating filehandles that will remain valid forever.
 16 *
 17 * So, we do our best.  If you're lucky, your inode will be in the
 18 * client's cache.  If it's not, and you have a connectable fh, then
 19 * the MDS server may be able to find it for you.  Otherwise, you get
 20 * ESTALE.
 21 *
 22 * There are ways to this more reliable, but in the non-connectable fh
 23 * case, we won't every work perfectly, and in the connectable case,
 24 * some changes are needed on the MDS side to work better.
 25 */
 26
 27/*
 28 * Basic fh
 29 */
 30struct ceph_nfs_fh {
 31	u64 ino;
 32} __attribute__ ((packed));
 33
 34/*
 35 * Larger 'connectable' fh that includes parent ino and name hash.
 36 * Use this whenever possible, as it works more reliably.
 37 */
 38struct ceph_nfs_confh {
 39	u64 ino, parent_ino;
 40	u32 parent_name_hash;
 41} __attribute__ ((packed));
 42
 43/*
 44 * The presence of @parent_inode here tells us whether NFS wants a
 45 * connectable file handle.  However, we want to make a connectionable
 46 * file handle unconditionally so that the MDS gets as much of a hint
 47 * as possible.  That means we only use @parent_dentry to indicate
 48 * whether nfsd wants a connectable fh, and whether we should indicate
 49 * failure from a too-small @max_len.
 50 */
 51static int ceph_encode_fh(struct inode *inode, u32 *rawfh, int *max_len,
 52			  struct inode *parent_inode)
 53{
 54	int type;
 55	struct ceph_nfs_fh *fh = (void *)rawfh;
 56	struct ceph_nfs_confh *cfh = (void *)rawfh;
 57	int connected_handle_length = sizeof(*cfh)/4;
 58	int handle_length = sizeof(*fh)/4;
 59	struct dentry *dentry = d_find_alias(inode);
 60	struct dentry *parent;
 61
 62	/* don't re-export snaps */
 63	if (ceph_snap(inode) != CEPH_NOSNAP)
 64		return -EINVAL;
 65
 66	/* if we found an alias, generate a connectable fh */
 67	if (*max_len >= connected_handle_length && dentry) {
 68		dout("encode_fh %p connectable\n", dentry);
 69		spin_lock(&dentry->d_lock);
 70		parent = dentry->d_parent;
 
 
 
 
 
 
 71		cfh->ino = ceph_ino(inode);
 72		cfh->parent_ino = ceph_ino(parent->d_inode);
 73		cfh->parent_name_hash = ceph_dentry_hash(parent->d_inode,
 74							 dentry);
 75		*max_len = connected_handle_length;
 76		type = 2;
 77		spin_unlock(&dentry->d_lock);
 78	} else if (*max_len >= handle_length) {
 79		if (parent_inode) {
 80			/* nfsd wants connectable */
 81			*max_len = connected_handle_length;
 82			type = 255;
 83		} else {
 84			dout("encode_fh %p\n", dentry);
 85			fh->ino = ceph_ino(inode);
 86			*max_len = handle_length;
 87			type = 1;
 88		}
 89	} else {
 
 
 90		*max_len = handle_length;
 91		type = 255;
 92	}
 93	return type;
 94}
 95
 96/*
 97 * convert regular fh to dentry
 98 *
 99 * FIXME: we should try harder by querying the mds for the ino.
100 */
101static struct dentry *__fh_to_dentry(struct super_block *sb,
102				     struct ceph_nfs_fh *fh)
103{
104	struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
105	struct inode *inode;
106	struct dentry *dentry;
107	struct ceph_vino vino;
108	int err;
109
110	dout("__fh_to_dentry %llx\n", fh->ino);
111	vino.ino = fh->ino;
112	vino.snap = CEPH_NOSNAP;
113	inode = ceph_find_inode(sb, vino);
114	if (!inode) {
115		struct ceph_mds_request *req;
 
116
117		req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPINO,
118					       USE_ANY_MDS);
119		if (IS_ERR(req))
120			return ERR_CAST(req);
121
 
 
 
 
 
122		req->r_ino1 = vino;
123		req->r_num_caps = 1;
124		err = ceph_mdsc_do_request(mdsc, NULL, req);
125		inode = req->r_target_inode;
126		if (inode)
127			ihold(inode);
128		ceph_mdsc_put_request(req);
129		if (!inode)
130			return ERR_PTR(-ESTALE);
 
 
 
 
131	}
132
133	dentry = d_obtain_alias(inode);
134	if (IS_ERR(dentry)) {
135		pr_err("fh_to_dentry %llx -- inode %p but ENOMEM\n",
136		       fh->ino, inode);
137		iput(inode);
138		return dentry;
139	}
140	err = ceph_init_dentry(dentry);
141	if (err < 0) {
142		iput(inode);
143		return ERR_PTR(err);
144	}
145	dout("__fh_to_dentry %llx %p dentry %p\n", fh->ino, inode, dentry);
146	return dentry;
147}
148
149/*
150 * convert connectable fh to dentry
151 */
152static struct dentry *__cfh_to_dentry(struct super_block *sb,
153				      struct ceph_nfs_confh *cfh)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154{
155	struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
 
156	struct inode *inode;
157	struct dentry *dentry;
158	struct ceph_vino vino;
159	int err;
160
161	dout("__cfh_to_dentry %llx (%llx/%x)\n",
162	     cfh->ino, cfh->parent_ino, cfh->parent_name_hash);
163
164	vino.ino = cfh->ino;
165	vino.snap = CEPH_NOSNAP;
166	inode = ceph_find_inode(sb, vino);
167	if (!inode) {
168		struct ceph_mds_request *req;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
170		req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPHASH,
171					       USE_ANY_MDS);
172		if (IS_ERR(req))
173			return ERR_CAST(req);
174
175		req->r_ino1 = vino;
176		req->r_ino2.ino = cfh->parent_ino;
177		req->r_ino2.snap = CEPH_NOSNAP;
178		req->r_path2 = kmalloc(16, GFP_NOFS);
179		snprintf(req->r_path2, 16, "%d", cfh->parent_name_hash);
180		req->r_num_caps = 1;
181		err = ceph_mdsc_do_request(mdsc, NULL, req);
182		inode = req->r_target_inode;
183		if (inode)
184			ihold(inode);
185		ceph_mdsc_put_request(req);
186		if (!inode)
187			return ERR_PTR(err ? err : -ESTALE);
188	}
189
190	dentry = d_obtain_alias(inode);
191	if (IS_ERR(dentry)) {
192		pr_err("cfh_to_dentry %llx -- inode %p but ENOMEM\n",
193		       cfh->ino, inode);
194		iput(inode);
195		return dentry;
196	}
197	err = ceph_init_dentry(dentry);
198	if (err < 0) {
199		iput(inode);
200		return ERR_PTR(err);
201	}
202	dout("__cfh_to_dentry %llx %p dentry %p\n", cfh->ino, inode, dentry);
203	return dentry;
204}
205
206static struct dentry *ceph_fh_to_dentry(struct super_block *sb, struct fid *fid,
207					int fh_len, int fh_type)
208{
209	if (fh_type == 1)
210		return __fh_to_dentry(sb, (struct ceph_nfs_fh *)fid->raw);
211	else
212		return __cfh_to_dentry(sb, (struct ceph_nfs_confh *)fid->raw);
 
 
 
213}
214
215/*
216 * get parent, if possible.
217 *
218 * FIXME: we could do better by querying the mds to discover the
219 * parent.
220 */
221static struct dentry *ceph_fh_to_parent(struct super_block *sb,
222					 struct fid *fid,
223					int fh_len, int fh_type)
224{
225	struct ceph_nfs_confh *cfh = (void *)fid->raw;
226	struct ceph_vino vino;
227	struct inode *inode;
228	struct dentry *dentry;
229	int err;
230
231	if (fh_type == 1)
232		return ERR_PTR(-ESTALE);
 
 
 
 
 
 
 
 
 
233
234	pr_debug("fh_to_parent %llx/%d\n", cfh->parent_ino,
235		 cfh->parent_name_hash);
 
 
 
 
236
237	vino.ino = cfh->ino;
238	vino.snap = CEPH_NOSNAP;
239	inode = ceph_find_inode(sb, vino);
240	if (!inode)
241		return ERR_PTR(-ESTALE);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
242
243	dentry = d_obtain_alias(inode);
244	if (IS_ERR(dentry)) {
245		pr_err("fh_to_parent %llx -- inode %p but ENOMEM\n",
246		       cfh->ino, inode);
247		iput(inode);
248		return dentry;
249	}
250	err = ceph_init_dentry(dentry);
251	if (err < 0) {
252		iput(inode);
253		return ERR_PTR(err);
254	}
255	dout("fh_to_parent %llx %p dentry %p\n", cfh->ino, inode, dentry);
256	return dentry;
257}
258
259const struct export_operations ceph_export_ops = {
260	.encode_fh = ceph_encode_fh,
261	.fh_to_dentry = ceph_fh_to_dentry,
262	.fh_to_parent = ceph_fh_to_parent,
 
 
263};