Blame view
fs/ceph/export.c
5.78 KB
3d14c5d2b
|
1 |
#include <linux/ceph/ceph_debug.h> |
a8e63b7d5
|
2 3 |
#include <linux/exportfs.h> |
5a0e3ad6a
|
4 |
#include <linux/slab.h> |
a8e63b7d5
|
5 6 7 |
#include <asm/unaligned.h> #include "super.h" |
3d14c5d2b
|
8 |
#include "mds_client.h" |
a8e63b7d5
|
9 10 |
/* |
a8e63b7d5
|
11 12 13 14 15 16 17 |
* Basic fh */ struct ceph_nfs_fh { u64 ino; } __attribute__ ((packed)); /* |
4f32b42dc
|
18 |
* Larger fh that includes parent ino. |
a8e63b7d5
|
19 20 21 |
*/ struct ceph_nfs_confh { u64 ino, parent_ino; |
a8e63b7d5
|
22 |
} __attribute__ ((packed)); |
c862868bb
|
23 24 |
static int ceph_encode_fh(struct inode *inode, u32 *rawfh, int *max_len, struct inode *parent_inode) |
a8e63b7d5
|
25 |
{ |
92923dcbf
|
26 |
int type; |
a8e63b7d5
|
27 28 |
struct ceph_nfs_fh *fh = (void *)rawfh; struct ceph_nfs_confh *cfh = (void *)rawfh; |
92923dcbf
|
29 30 |
int connected_handle_length = sizeof(*cfh)/4; int handle_length = sizeof(*fh)/4; |
a8e63b7d5
|
31 32 33 34 |
/* don't re-export snaps */ if (ceph_snap(inode) != CEPH_NOSNAP) return -EINVAL; |
4f32b42dc
|
35 36 37 38 39 40 41 |
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; } |
f6af75dac
|
42 |
|
4f32b42dc
|
43 44 45 46 |
if (parent_inode) { dout("encode_fh %llx with parent %llx ", ceph_ino(inode), ceph_ino(parent_inode)); |
c862868bb
|
47 |
cfh->ino = ceph_ino(inode); |
4f32b42dc
|
48 |
cfh->parent_ino = ceph_ino(parent_inode); |
92923dcbf
|
49 |
*max_len = connected_handle_length; |
4f32b42dc
|
50 |
type = FILEID_INO32_GEN_PARENT; |
a8e63b7d5
|
51 |
} else { |
4f32b42dc
|
52 53 54 |
dout("encode_fh %llx ", ceph_ino(inode)); fh->ino = ceph_ino(inode); |
bba0cd0e3
|
55 |
*max_len = handle_length; |
4f32b42dc
|
56 |
type = FILEID_INO32_GEN; |
a8e63b7d5
|
57 58 59 |
} return type; } |
4f32b42dc
|
60 |
static struct dentry *__fh_to_dentry(struct super_block *sb, u64 ino) |
a8e63b7d5
|
61 |
{ |
3c454cf21
|
62 |
struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc; |
a8e63b7d5
|
63 64 65 66 |
struct inode *inode; struct dentry *dentry; struct ceph_vino vino; int err; |
4f32b42dc
|
67 |
vino.ino = ino; |
a8e63b7d5
|
68 69 |
vino.snap = CEPH_NOSNAP; inode = ceph_find_inode(sb, vino); |
3c454cf21
|
70 71 72 73 74 75 76 77 78 79 80 |
if (!inode) { struct ceph_mds_request *req; req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPINO, USE_ANY_MDS); if (IS_ERR(req)) return ERR_CAST(req); req->r_ino1 = vino; req->r_num_caps = 1; err = ceph_mdsc_do_request(mdsc, NULL, req); |
45e3d3eeb
|
81 82 |
inode = req->r_target_inode; if (inode) |
70b666c3b
|
83 |
ihold(inode); |
3c454cf21
|
84 |
ceph_mdsc_put_request(req); |
3c454cf21
|
85 86 87 |
if (!inode) return ERR_PTR(-ESTALE); } |
a8e63b7d5
|
88 89 |
dentry = d_obtain_alias(inode); |
0d509c949
|
90 |
if (IS_ERR(dentry)) { |
a8e63b7d5
|
91 |
iput(inode); |
0d509c949
|
92 |
return dentry; |
a8e63b7d5
|
93 94 |
} err = ceph_init_dentry(dentry); |
a8e63b7d5
|
95 |
if (err < 0) { |
4f32b42dc
|
96 |
dput(dentry); |
a8e63b7d5
|
97 98 |
return ERR_PTR(err); } |
4f32b42dc
|
99 100 |
dout("__fh_to_dentry %llx %p dentry %p ", ino, inode, dentry); |
a8e63b7d5
|
101 102 103 104 |
return dentry; } /* |
4f32b42dc
|
105 |
* convert regular fh to dentry |
a8e63b7d5
|
106 |
*/ |
4f32b42dc
|
107 108 109 |
static struct dentry *ceph_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, int fh_type) |
a8e63b7d5
|
110 |
{ |
4f32b42dc
|
111 |
struct ceph_nfs_fh *fh = (void *)fid->raw; |
a8e63b7d5
|
112 |
|
4f32b42dc
|
113 114 115 116 117 |
if (fh_type != FILEID_INO32_GEN && fh_type != FILEID_INO32_GEN_PARENT) return NULL; if (fh_len < sizeof(*fh) / 4) return NULL; |
a8e63b7d5
|
118 |
|
4f32b42dc
|
119 120 121 |
dout("fh_to_dentry %llx ", fh->ino); return __fh_to_dentry(sb, fh->ino); |
a8e63b7d5
|
122 |
} |
9017c2ec7
|
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
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; struct dentry *dentry; 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) { |
2b0143b5c
|
138 139 |
req->r_inode = d_inode(child); ihold(d_inode(child)); |
9017c2ec7
|
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
} else { req->r_ino1 = (struct ceph_vino) { .ino = ino, .snap = CEPH_NOSNAP, }; } 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); dentry = d_obtain_alias(inode); if (IS_ERR(dentry)) { iput(inode); return dentry; } err = ceph_init_dentry(dentry); if (err < 0) { dput(dentry); return ERR_PTR(err); } dout("__get_parent ino %llx parent %p ino %llx.%llx ", |
2b0143b5c
|
167 |
child ? ceph_ino(d_inode(child)) : ino, |
9017c2ec7
|
168 169 170 |
dentry, ceph_vinop(inode)); return dentry; } |
e84be11c5
|
171 |
static struct dentry *ceph_get_parent(struct dentry *child) |
9017c2ec7
|
172 173 |
{ /* don't re-export snaps */ |
2b0143b5c
|
174 |
if (ceph_snap(d_inode(child)) != CEPH_NOSNAP) |
9017c2ec7
|
175 176 177 178 |
return ERR_PTR(-EINVAL); dout("get_parent %p ino %llx.%llx ", |
2b0143b5c
|
179 |
child, ceph_vinop(d_inode(child))); |
9017c2ec7
|
180 181 |
return __get_parent(child->d_sb, child, 0); } |
a8e63b7d5
|
182 |
/* |
8996f4f23
|
183 |
* convert regular fh to parent |
a8e63b7d5
|
184 185 |
*/ static struct dentry *ceph_fh_to_parent(struct super_block *sb, |
8996f4f23
|
186 |
struct fid *fid, |
a8e63b7d5
|
187 188 189 |
int fh_len, int fh_type) { struct ceph_nfs_confh *cfh = (void *)fid->raw; |
a8e63b7d5
|
190 |
struct dentry *dentry; |
a8e63b7d5
|
191 |
|
8996f4f23
|
192 193 |
if (fh_type != FILEID_INO32_GEN_PARENT) return NULL; |
35c2a7f49
|
194 |
if (fh_len < sizeof(*cfh) / 4) |
8996f4f23
|
195 |
return NULL; |
a8e63b7d5
|
196 |
|
8996f4f23
|
197 198 199 200 201 |
dout("fh_to_parent %llx ", cfh->parent_ino); dentry = __get_parent(sb, NULL, cfh->ino); if (IS_ERR(dentry) && PTR_ERR(dentry) == -ENOENT) dentry = __fh_to_dentry(sb, cfh->parent_ino); |
a8e63b7d5
|
202 203 |
return dentry; } |
19913b4ea
|
204 205 206 207 208 209 |
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; |
2b0143b5c
|
210 |
mdsc = ceph_inode_to_client(d_inode(child))->mdsc; |
19913b4ea
|
211 212 213 214 |
req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPNAME, USE_ANY_MDS); if (IS_ERR(req)) return PTR_ERR(req); |
5955102c9
|
215 |
inode_lock(d_inode(parent)); |
19913b4ea
|
216 |
|
2b0143b5c
|
217 218 219 220 |
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); |
19913b4ea
|
221 222 |
req->r_num_caps = 2; err = ceph_mdsc_do_request(mdsc, NULL, req); |
5955102c9
|
223 |
inode_unlock(d_inode(parent)); |
19913b4ea
|
224 225 226 227 228 229 230 |
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 ", |
2b0143b5c
|
231 |
child, ceph_vinop(d_inode(child)), name); |
19913b4ea
|
232 233 234 |
} else { dout("get_name %p ino %llx.%llx err %d ", |
2b0143b5c
|
235 |
child, ceph_vinop(d_inode(child)), err); |
19913b4ea
|
236 237 238 239 240 |
} ceph_mdsc_put_request(req); return err; } |
a8e63b7d5
|
241 242 243 244 |
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, |
9017c2ec7
|
245 |
.get_parent = ceph_get_parent, |
19913b4ea
|
246 |
.get_name = ceph_get_name, |
a8e63b7d5
|
247 |
}; |