export.c 5.5 KB
Newer Older
1
#include <linux/ceph/ceph_debug.h>
S
Sage Weil 已提交
2 3

#include <linux/exportfs.h>
4
#include <linux/slab.h>
S
Sage Weil 已提交
5 6 7
#include <asm/unaligned.h>

#include "super.h"
8
#include "mds_client.h"
S
Sage Weil 已提交
9 10 11 12 13 14 15 16 17

/*
 * Basic fh
 */
struct ceph_nfs_fh {
	u64 ino;
} __attribute__ ((packed));

/*
Y
Yan, Zheng 已提交
18
 * Larger fh that includes parent ino.
S
Sage Weil 已提交
19 20 21 22 23
 */
struct ceph_nfs_confh {
	u64 ino, parent_ino;
} __attribute__ ((packed));

S
Sage Weil 已提交
24 25
static int ceph_encode_fh(struct inode *inode, u32 *rawfh, int *max_len,
			  struct inode *parent_inode)
S
Sage Weil 已提交
26
{
27
	int type;
S
Sage Weil 已提交
28 29
	struct ceph_nfs_fh *fh = (void *)rawfh;
	struct ceph_nfs_confh *cfh = (void *)rawfh;
30 31
	int connected_handle_length = sizeof(*cfh)/4;
	int handle_length = sizeof(*fh)/4;
S
Sage Weil 已提交
32 33 34 35 36

	/* don't re-export snaps */
	if (ceph_snap(inode) != CEPH_NOSNAP)
		return -EINVAL;

Y
Yan, Zheng 已提交
37 38 39 40 41 42 43
	if (parent_inode && (*max_len < connected_handle_length)) {
		*max_len = connected_handle_length;
		return FILEID_INVALID;
	} else if (*max_len < handle_length) {
		*max_len = handle_length;
		return FILEID_INVALID;
	}
44

Y
Yan, Zheng 已提交
45 46 47
	if (parent_inode) {
		dout("encode_fh %llx with parent %llx\n",
		     ceph_ino(inode), ceph_ino(parent_inode));
S
Sage Weil 已提交
48
		cfh->ino = ceph_ino(inode);
Y
Yan, Zheng 已提交
49
		cfh->parent_ino = ceph_ino(parent_inode);
50
		*max_len = connected_handle_length;
Y
Yan, Zheng 已提交
51
		type = FILEID_INO32_GEN_PARENT;
S
Sage Weil 已提交
52
	} else {
Y
Yan, Zheng 已提交
53 54
		dout("encode_fh %llx\n", ceph_ino(inode));
		fh->ino = ceph_ino(inode);
55
		*max_len = handle_length;
Y
Yan, Zheng 已提交
56
		type = FILEID_INO32_GEN;
S
Sage Weil 已提交
57 58 59 60
	}
	return type;
}

Y
Yan, Zheng 已提交
61
static struct dentry *__fh_to_dentry(struct super_block *sb, u64 ino)
S
Sage Weil 已提交
62
{
63
	struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
S
Sage Weil 已提交
64 65 66 67
	struct inode *inode;
	struct ceph_vino vino;
	int err;

Y
Yan, Zheng 已提交
68
	vino.ino = ino;
S
Sage Weil 已提交
69 70
	vino.snap = CEPH_NOSNAP;
	inode = ceph_find_inode(sb, vino);
71 72
	if (!inode) {
		struct ceph_mds_request *req;
Y
Yan, Zheng 已提交
73
		int mask;
74 75 76 77 78 79

		req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPINO,
					       USE_ANY_MDS);
		if (IS_ERR(req))
			return ERR_CAST(req);

Y
Yan, Zheng 已提交
80 81 82 83 84
		mask = CEPH_STAT_CAP_INODE;
		if (ceph_security_xattr_wanted(d_inode(sb->s_root)))
			mask |= CEPH_CAP_XATTR_SHARED;
		req->r_args.getattr.mask = cpu_to_le32(mask);

85 86 87
		req->r_ino1 = vino;
		req->r_num_caps = 1;
		err = ceph_mdsc_do_request(mdsc, NULL, req);
88 89
		inode = req->r_target_inode;
		if (inode)
90
			ihold(inode);
91 92 93 94
		ceph_mdsc_put_request(req);
		if (!inode)
			return ERR_PTR(-ESTALE);
	}
S
Sage Weil 已提交
95

A
Al Viro 已提交
96
	return d_obtain_alias(inode);
S
Sage Weil 已提交
97 98 99
}

/*
Y
Yan, Zheng 已提交
100
 * convert regular fh to dentry
S
Sage Weil 已提交
101
 */
Y
Yan, Zheng 已提交
102 103 104
static struct dentry *ceph_fh_to_dentry(struct super_block *sb,
					struct fid *fid,
					int fh_len, int fh_type)
S
Sage Weil 已提交
105
{
Y
Yan, Zheng 已提交
106
	struct ceph_nfs_fh *fh = (void *)fid->raw;
S
Sage Weil 已提交
107

Y
Yan, Zheng 已提交
108 109 110 111 112
	if (fh_type != FILEID_INO32_GEN  &&
	    fh_type != FILEID_INO32_GEN_PARENT)
		return NULL;
	if (fh_len < sizeof(*fh) / 4)
		return NULL;
S
Sage Weil 已提交
113

Y
Yan, Zheng 已提交
114 115
	dout("fh_to_dentry %llx\n", fh->ino);
	return __fh_to_dentry(sb, fh->ino);
S
Sage Weil 已提交
116 117
}

118 119 120 121 122 123
static struct dentry *__get_parent(struct super_block *sb,
				   struct dentry *child, u64 ino)
{
	struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
	struct ceph_mds_request *req;
	struct inode *inode;
Y
Yan, Zheng 已提交
124
	int mask;
125 126 127 128 129 130 131 132
	int err;

	req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPPARENT,
				       USE_ANY_MDS);
	if (IS_ERR(req))
		return ERR_CAST(req);

	if (child) {
133 134
		req->r_inode = d_inode(child);
		ihold(d_inode(child));
135 136 137 138 139 140
	} else {
		req->r_ino1 = (struct ceph_vino) {
			.ino = ino,
			.snap = CEPH_NOSNAP,
		};
	}
Y
Yan, Zheng 已提交
141 142 143 144 145 146

	mask = CEPH_STAT_CAP_INODE;
	if (ceph_security_xattr_wanted(d_inode(sb->s_root)))
		mask |= CEPH_CAP_XATTR_SHARED;
	req->r_args.getattr.mask = cpu_to_le32(mask);

147 148 149 150 151 152 153 154 155
	req->r_num_caps = 1;
	err = ceph_mdsc_do_request(mdsc, NULL, req);
	inode = req->r_target_inode;
	if (inode)
		ihold(inode);
	ceph_mdsc_put_request(req);
	if (!inode)
		return ERR_PTR(-ENOENT);

A
Al Viro 已提交
156
	return d_obtain_alias(inode);
157 158
}

159
static 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 164 165
		return ERR_PTR(-EINVAL);

	dout("get_parent %p ino %llx.%llx\n",
166
	     child, ceph_vinop(d_inode(child)));
167 168 169
	return __get_parent(child->d_sb, child, 0);
}

S
Sage Weil 已提交
170
/*
Y
Yan, Zheng 已提交
171
 * convert regular fh to parent
S
Sage Weil 已提交
172 173
 */
static struct dentry *ceph_fh_to_parent(struct super_block *sb,
Y
Yan, Zheng 已提交
174
					struct fid *fid,
S
Sage Weil 已提交
175 176 177 178 179
					int fh_len, int fh_type)
{
	struct ceph_nfs_confh *cfh = (void *)fid->raw;
	struct dentry *dentry;

Y
Yan, Zheng 已提交
180 181
	if (fh_type != FILEID_INO32_GEN_PARENT)
		return NULL;
182
	if (fh_len < sizeof(*cfh) / 4)
Y
Yan, Zheng 已提交
183
		return NULL;
S
Sage Weil 已提交
184

Y
Yan, Zheng 已提交
185 186
	dout("fh_to_parent %llx\n", cfh->parent_ino);
	dentry = __get_parent(sb, NULL, cfh->ino);
A
Al Viro 已提交
187
	if (unlikely(dentry == ERR_PTR(-ENOENT)))
Y
Yan, Zheng 已提交
188
		dentry = __fh_to_dentry(sb, cfh->parent_ino);
S
Sage Weil 已提交
189 190 191
	return dentry;
}

192 193 194 195 196 197 198
static int ceph_get_name(struct dentry *parent, char *name,
			 struct dentry *child)
{
	struct ceph_mds_client *mdsc;
	struct ceph_mds_request *req;
	int err;

199
	mdsc = ceph_inode_to_client(d_inode(child))->mdsc;
200 201 202 203 204
	req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPNAME,
				       USE_ANY_MDS);
	if (IS_ERR(req))
		return PTR_ERR(req);

A
Al Viro 已提交
205
	inode_lock(d_inode(parent));
206

207 208 209 210
	req->r_inode = d_inode(child);
	ihold(d_inode(child));
	req->r_ino2 = ceph_vino(d_inode(parent));
	req->r_locked_dir = d_inode(parent);
211 212 213
	req->r_num_caps = 2;
	err = ceph_mdsc_do_request(mdsc, NULL, req);

A
Al Viro 已提交
214
	inode_unlock(d_inode(parent));
215 216 217 218 219 220

	if (!err) {
		struct ceph_mds_reply_info_parsed *rinfo = &req->r_reply_info;
		memcpy(name, rinfo->dname, rinfo->dname_len);
		name[rinfo->dname_len] = 0;
		dout("get_name %p ino %llx.%llx name %s\n",
221
		     child, ceph_vinop(d_inode(child)), name);
222 223
	} else {
		dout("get_name %p ino %llx.%llx err %d\n",
224
		     child, ceph_vinop(d_inode(child)), err);
225 226 227 228 229 230
	}

	ceph_mdsc_put_request(req);
	return err;
}

S
Sage Weil 已提交
231 232 233 234
const struct export_operations ceph_export_ops = {
	.encode_fh = ceph_encode_fh,
	.fh_to_dentry = ceph_fh_to_dentry,
	.fh_to_parent = ceph_fh_to_parent,
235
	.get_parent = ceph_get_parent,
236
	.get_name = ceph_get_name,
S
Sage Weil 已提交
237
};