1
#include <linux/ceph/ceph_debug.h>
3
#include <linux/exportfs.h>
4
#include <linux/slab.h>
5
#include <asm/unaligned.h>
8
#include "mds_client.h"
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.
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
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.
32
} __attribute__ ((packed));
35
* Larger 'connectable' fh that includes parent ino and name hash.
36
* Use this whenever possible, as it works more reliably.
38
struct ceph_nfs_confh {
41
} __attribute__ ((packed));
43
static int ceph_encode_fh(struct dentry *dentry, u32 *rawfh, int *max_len,
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;
54
/* don't re-export snaps */
55
if (ceph_snap(inode) != CEPH_NOSNAP)
58
spin_lock(&dentry->d_lock);
59
parent = dget(dentry->d_parent);
60
spin_unlock(&dentry->d_lock);
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,
68
*max_len = connected_handle_length;
70
} else if (*max_len >= handle_length) {
72
*max_len = connected_handle_length;
75
dout("encode_fh %p\n", dentry);
76
fh->ino = ceph_ino(dentry->d_inode);
77
*max_len = handle_length;
81
*max_len = handle_length;
89
* convert regular fh to dentry
91
* FIXME: we should try harder by querying the mds for the ino.
93
static struct dentry *__fh_to_dentry(struct super_block *sb,
94
struct ceph_nfs_fh *fh)
96
struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
98
struct dentry *dentry;
99
struct ceph_vino vino;
102
dout("__fh_to_dentry %llx\n", fh->ino);
104
vino.snap = CEPH_NOSNAP;
105
inode = ceph_find_inode(sb, vino);
107
struct ceph_mds_request *req;
109
req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPINO,
112
return ERR_CAST(req);
116
err = ceph_mdsc_do_request(mdsc, NULL, req);
117
inode = req->r_target_inode;
120
ceph_mdsc_put_request(req);
122
return ERR_PTR(-ESTALE);
125
dentry = d_obtain_alias(inode);
126
if (IS_ERR(dentry)) {
127
pr_err("fh_to_dentry %llx -- inode %p but ENOMEM\n",
132
err = ceph_init_dentry(dentry);
137
dout("__fh_to_dentry %llx %p dentry %p\n", fh->ino, inode, dentry);
142
* convert connectable fh to dentry
144
static struct dentry *__cfh_to_dentry(struct super_block *sb,
145
struct ceph_nfs_confh *cfh)
147
struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
149
struct dentry *dentry;
150
struct ceph_vino vino;
153
dout("__cfh_to_dentry %llx (%llx/%x)\n",
154
cfh->ino, cfh->parent_ino, cfh->parent_name_hash);
157
vino.snap = CEPH_NOSNAP;
158
inode = ceph_find_inode(sb, vino);
160
struct ceph_mds_request *req;
162
req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPHASH,
165
return ERR_CAST(req);
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);
173
err = ceph_mdsc_do_request(mdsc, NULL, req);
174
inode = req->r_target_inode;
177
ceph_mdsc_put_request(req);
179
return ERR_PTR(err ? err : -ESTALE);
182
dentry = d_obtain_alias(inode);
183
if (IS_ERR(dentry)) {
184
pr_err("cfh_to_dentry %llx -- inode %p but ENOMEM\n",
189
err = ceph_init_dentry(dentry);
194
dout("__cfh_to_dentry %llx %p dentry %p\n", cfh->ino, inode, dentry);
198
static struct dentry *ceph_fh_to_dentry(struct super_block *sb, struct fid *fid,
199
int fh_len, int fh_type)
202
return __fh_to_dentry(sb, (struct ceph_nfs_fh *)fid->raw);
204
return __cfh_to_dentry(sb, (struct ceph_nfs_confh *)fid->raw);
208
* get parent, if possible.
210
* FIXME: we could do better by querying the mds to discover the
213
static struct dentry *ceph_fh_to_parent(struct super_block *sb,
215
int fh_len, int fh_type)
217
struct ceph_nfs_confh *cfh = (void *)fid->raw;
218
struct ceph_vino vino;
220
struct dentry *dentry;
224
return ERR_PTR(-ESTALE);
226
pr_debug("fh_to_parent %llx/%d\n", cfh->parent_ino,
227
cfh->parent_name_hash);
230
vino.snap = CEPH_NOSNAP;
231
inode = ceph_find_inode(sb, vino);
233
return ERR_PTR(-ESTALE);
235
dentry = d_obtain_alias(inode);
236
if (IS_ERR(dentry)) {
237
pr_err("fh_to_parent %llx -- inode %p but ENOMEM\n",
242
err = ceph_init_dentry(dentry);
247
dout("fh_to_parent %llx %p dentry %p\n", cfh->ino, inode, dentry);
251
const 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,