Linux Audio

Check our new training course

Loading...
v3.15
  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 dentry *dentry;
 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
 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		req->r_ino1 = vino;
 81		req->r_num_caps = 1;
 82		err = ceph_mdsc_do_request(mdsc, NULL, req);
 83		inode = req->r_target_inode;
 84		if (inode)
 85			ihold(inode);
 86		ceph_mdsc_put_request(req);
 87		if (!inode)
 88			return ERR_PTR(-ESTALE);
 89	}
 90
 91	dentry = d_obtain_alias(inode);
 92	if (IS_ERR(dentry)) {
 
 
 93		iput(inode);
 94		return dentry;
 95	}
 96	err = ceph_init_dentry(dentry);
 97	if (err < 0) {
 98		dput(dentry);
 99		return ERR_PTR(err);
100	}
101	dout("__fh_to_dentry %llx %p dentry %p\n", ino, inode, dentry);
102	return dentry;
103}
104
105/*
106 * convert regular fh to dentry
107 */
108static struct dentry *ceph_fh_to_dentry(struct super_block *sb,
109					struct fid *fid,
110					int fh_len, int fh_type)
111{
112	struct ceph_nfs_fh *fh = (void *)fid->raw;
113
114	if (fh_type != FILEID_INO32_GEN  &&
115	    fh_type != FILEID_INO32_GEN_PARENT)
116		return NULL;
117	if (fh_len < sizeof(*fh) / 4)
118		return NULL;
119
120	dout("fh_to_dentry %llx\n", fh->ino);
121	return __fh_to_dentry(sb, fh->ino);
122}
123
124static struct dentry *__get_parent(struct super_block *sb,
125				   struct dentry *child, u64 ino)
126{
127	struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
128	struct ceph_mds_request *req;
129	struct inode *inode;
130	struct dentry *dentry;
 
131	int err;
132
133	req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPPARENT,
134				       USE_ANY_MDS);
135	if (IS_ERR(req))
136		return ERR_CAST(req);
137
138	if (child) {
139		req->r_inode = child->d_inode;
140		ihold(child->d_inode);
141	} else {
142		req->r_ino1 = (struct ceph_vino) {
143			.ino = ino,
144			.snap = CEPH_NOSNAP,
145		};
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	dentry = d_obtain_alias(inode);
157	if (IS_ERR(dentry)) {
 
 
158		iput(inode);
159		return dentry;
160	}
161	err = ceph_init_dentry(dentry);
162	if (err < 0) {
163		dput(dentry);
164		return ERR_PTR(err);
165	}
166	dout("__get_parent ino %llx parent %p ino %llx.%llx\n",
167	     child ? ceph_ino(child->d_inode) : ino,
168	     dentry, ceph_vinop(inode));
169	return dentry;
170}
171
172struct dentry *ceph_get_parent(struct dentry *child)
 
173{
174	/* don't re-export snaps */
175	if (ceph_snap(child->d_inode) != CEPH_NOSNAP)
176		return ERR_PTR(-EINVAL);
177
178	dout("get_parent %p ino %llx.%llx\n",
179	     child, ceph_vinop(child->d_inode));
180	return __get_parent(child->d_sb, child, 0);
181}
182
183/*
184 * convert regular fh to parent
 
 
 
185 */
186static struct dentry *ceph_fh_to_parent(struct super_block *sb,
187					struct fid *fid,
188					int fh_len, int fh_type)
189{
190	struct ceph_nfs_confh *cfh = (void *)fid->raw;
 
 
191	struct dentry *dentry;
 
192
193	if (fh_type != FILEID_INO32_GEN_PARENT)
194		return NULL;
195	if (fh_len < sizeof(*cfh) / 4)
196		return NULL;
197
198	dout("fh_to_parent %llx\n", cfh->parent_ino);
199	dentry = __get_parent(sb, NULL, cfh->ino);
200	if (IS_ERR(dentry) && PTR_ERR(dentry) == -ENOENT)
201		dentry = __fh_to_dentry(sb, cfh->parent_ino);
202	return dentry;
203}
204
205static int ceph_get_name(struct dentry *parent, char *name,
206			 struct dentry *child)
207{
208	struct ceph_mds_client *mdsc;
209	struct ceph_mds_request *req;
210	int err;
211
212	mdsc = ceph_inode_to_client(child->d_inode)->mdsc;
213	req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPNAME,
214				       USE_ANY_MDS);
215	if (IS_ERR(req))
216		return PTR_ERR(req);
217
218	mutex_lock(&parent->d_inode->i_mutex);
219
220	req->r_inode = child->d_inode;
221	ihold(child->d_inode);
222	req->r_ino2 = ceph_vino(parent->d_inode);
223	req->r_locked_dir = parent->d_inode;
224	req->r_num_caps = 2;
225	err = ceph_mdsc_do_request(mdsc, NULL, req);
226
227	mutex_unlock(&parent->d_inode->i_mutex);
228
229	if (!err) {
230		struct ceph_mds_reply_info_parsed *rinfo = &req->r_reply_info;
231		memcpy(name, rinfo->dname, rinfo->dname_len);
232		name[rinfo->dname_len] = 0;
233		dout("get_name %p ino %llx.%llx name %s\n",
234		     child, ceph_vinop(child->d_inode), name);
235	} else {
236		dout("get_name %p ino %llx.%llx err %d\n",
237		     child, ceph_vinop(child->d_inode), err);
238	}
239
240	ceph_mdsc_put_request(req);
241	return err;
 
 
 
 
 
 
 
 
 
 
 
 
242}
243
244const struct export_operations ceph_export_ops = {
245	.encode_fh = ceph_encode_fh,
246	.fh_to_dentry = ceph_fh_to_dentry,
247	.fh_to_parent = ceph_fh_to_parent,
248	.get_parent = ceph_get_parent,
249	.get_name = ceph_get_name,
250};
v3.1
  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
 43static int ceph_encode_fh(struct dentry *dentry, u32 *rawfh, int *max_len,
 44			  int connectable)
 45{
 46	int type;
 47	struct ceph_nfs_fh *fh = (void *)rawfh;
 48	struct ceph_nfs_confh *cfh = (void *)rawfh;
 49	struct dentry *parent;
 50	struct inode *inode = dentry->d_inode;
 51	int connected_handle_length = sizeof(*cfh)/4;
 52	int handle_length = sizeof(*fh)/4;
 53
 54	/* don't re-export snaps */
 55	if (ceph_snap(inode) != CEPH_NOSNAP)
 56		return -EINVAL;
 57
 58	spin_lock(&dentry->d_lock);
 59	parent = dget(dentry->d_parent);
 60	spin_unlock(&dentry->d_lock);
 61
 62	if (*max_len >= connected_handle_length) {
 63		dout("encode_fh %p connectable\n", dentry);
 64		cfh->ino = ceph_ino(dentry->d_inode);
 65		cfh->parent_ino = ceph_ino(parent->d_inode);
 66		cfh->parent_name_hash = ceph_dentry_hash(parent->d_inode,
 67							 dentry);
 68		*max_len = connected_handle_length;
 69		type = 2;
 70	} else if (*max_len >= handle_length) {
 71		if (connectable) {
 72			*max_len = connected_handle_length;
 73			type = 255;
 74		} else {
 75			dout("encode_fh %p\n", dentry);
 76			fh->ino = ceph_ino(dentry->d_inode);
 77			*max_len = handle_length;
 78			type = 1;
 79		}
 
 
 80	} else {
 
 
 81		*max_len = handle_length;
 82		type = 255;
 83	}
 84	dput(parent);
 85	return type;
 86}
 87
 88/*
 89 * convert regular fh to dentry
 90 *
 91 * FIXME: we should try harder by querying the mds for the ino.
 92 */
 93static struct dentry *__fh_to_dentry(struct super_block *sb,
 94				     struct ceph_nfs_fh *fh)
 95{
 96	struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
 97	struct inode *inode;
 98	struct dentry *dentry;
 99	struct ceph_vino vino;
100	int err;
101
102	dout("__fh_to_dentry %llx\n", fh->ino);
103	vino.ino = fh->ino;
104	vino.snap = CEPH_NOSNAP;
105	inode = ceph_find_inode(sb, vino);
106	if (!inode) {
107		struct ceph_mds_request *req;
108
109		req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPINO,
110					       USE_ANY_MDS);
111		if (IS_ERR(req))
112			return ERR_CAST(req);
113
114		req->r_ino1 = vino;
115		req->r_num_caps = 1;
116		err = ceph_mdsc_do_request(mdsc, NULL, req);
117		inode = req->r_target_inode;
118		if (inode)
119			ihold(inode);
120		ceph_mdsc_put_request(req);
121		if (!inode)
122			return ERR_PTR(-ESTALE);
123	}
124
125	dentry = d_obtain_alias(inode);
126	if (IS_ERR(dentry)) {
127		pr_err("fh_to_dentry %llx -- inode %p but ENOMEM\n",
128		       fh->ino, inode);
129		iput(inode);
130		return dentry;
131	}
132	err = ceph_init_dentry(dentry);
133	if (err < 0) {
134		iput(inode);
135		return ERR_PTR(err);
136	}
137	dout("__fh_to_dentry %llx %p dentry %p\n", fh->ino, inode, dentry);
138	return dentry;
139}
140
141/*
142 * convert connectable fh to dentry
143 */
144static struct dentry *__cfh_to_dentry(struct super_block *sb,
145				      struct ceph_nfs_confh *cfh)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
146{
147	struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
 
148	struct inode *inode;
149	struct dentry *dentry;
150	struct ceph_vino vino;
151	int err;
152
153	dout("__cfh_to_dentry %llx (%llx/%x)\n",
154	     cfh->ino, cfh->parent_ino, cfh->parent_name_hash);
155
156	vino.ino = cfh->ino;
157	vino.snap = CEPH_NOSNAP;
158	inode = ceph_find_inode(sb, vino);
159	if (!inode) {
160		struct ceph_mds_request *req;
161
162		req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPHASH,
163					       USE_ANY_MDS);
164		if (IS_ERR(req))
165			return ERR_CAST(req);
166
167		req->r_ino1 = vino;
168		req->r_ino2.ino = cfh->parent_ino;
169		req->r_ino2.snap = CEPH_NOSNAP;
170		req->r_path2 = kmalloc(16, GFP_NOFS);
171		snprintf(req->r_path2, 16, "%d", cfh->parent_name_hash);
172		req->r_num_caps = 1;
173		err = ceph_mdsc_do_request(mdsc, NULL, req);
174		inode = req->r_target_inode;
175		if (inode)
176			ihold(inode);
177		ceph_mdsc_put_request(req);
178		if (!inode)
179			return ERR_PTR(err ? err : -ESTALE);
180	}
181
182	dentry = d_obtain_alias(inode);
183	if (IS_ERR(dentry)) {
184		pr_err("cfh_to_dentry %llx -- inode %p but ENOMEM\n",
185		       cfh->ino, inode);
186		iput(inode);
187		return dentry;
188	}
189	err = ceph_init_dentry(dentry);
190	if (err < 0) {
191		iput(inode);
192		return ERR_PTR(err);
193	}
194	dout("__cfh_to_dentry %llx %p dentry %p\n", cfh->ino, inode, dentry);
 
 
195	return dentry;
196}
197
198static struct dentry *ceph_fh_to_dentry(struct super_block *sb, struct fid *fid,
199					int fh_len, int fh_type)
200{
201	if (fh_type == 1)
202		return __fh_to_dentry(sb, (struct ceph_nfs_fh *)fid->raw);
203	else
204		return __cfh_to_dentry(sb, (struct ceph_nfs_confh *)fid->raw);
 
 
 
205}
206
207/*
208 * get parent, if possible.
209 *
210 * FIXME: we could do better by querying the mds to discover the
211 * parent.
212 */
213static struct dentry *ceph_fh_to_parent(struct super_block *sb,
214					 struct fid *fid,
215					int fh_len, int fh_type)
216{
217	struct ceph_nfs_confh *cfh = (void *)fid->raw;
218	struct ceph_vino vino;
219	struct inode *inode;
220	struct dentry *dentry;
221	int err;
222
223	if (fh_type == 1)
224		return ERR_PTR(-ESTALE);
 
 
 
 
 
 
 
 
 
225
226	pr_debug("fh_to_parent %llx/%d\n", cfh->parent_ino,
227		 cfh->parent_name_hash);
 
 
 
 
228
229	vino.ino = cfh->ino;
230	vino.snap = CEPH_NOSNAP;
231	inode = ceph_find_inode(sb, vino);
232	if (!inode)
233		return ERR_PTR(-ESTALE);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
234
235	dentry = d_obtain_alias(inode);
236	if (IS_ERR(dentry)) {
237		pr_err("fh_to_parent %llx -- inode %p but ENOMEM\n",
238		       cfh->ino, inode);
239		iput(inode);
240		return dentry;
241	}
242	err = ceph_init_dentry(dentry);
243	if (err < 0) {
244		iput(inode);
245		return ERR_PTR(err);
246	}
247	dout("fh_to_parent %llx %p dentry %p\n", cfh->ino, inode, dentry);
248	return dentry;
249}
250
251const struct export_operations ceph_export_ops = {
252	.encode_fh = ceph_encode_fh,
253	.fh_to_dentry = ceph_fh_to_dentry,
254	.fh_to_parent = ceph_fh_to_parent,
 
 
255};