]> bbs.cooldavid.org Git - net-next-2.6.git/blame - fs/ceph/export.c
ceph: Fix return value of encode_fh function
[net-next-2.6.git] / fs / ceph / export.c
CommitLineData
a8e63b7d
SW
1#include "ceph_debug.h"
2
3#include <linux/exportfs.h>
5a0e3ad6 4#include <linux/slab.h>
a8e63b7d
SW
5#include <asm/unaligned.h>
6
7#include "super.h"
8
9/*
10 * NFS export support
11 *
12 * NFS re-export of a ceph mount is, at present, only semireliable.
13 * The basic issue is that the Ceph architectures doesn't lend itself
14 * well to generating filehandles that will remain valid forever.
15 *
16 * So, we do our best. If you're lucky, your inode will be in the
17 * client's cache. If it's not, and you have a connectable fh, then
18 * the MDS server may be able to find it for you. Otherwise, you get
19 * ESTALE.
20 *
21 * There are ways to this more reliable, but in the non-connectable fh
22 * case, we won't every work perfectly, and in the connectable case,
23 * some changes are needed on the MDS side to work better.
24 */
25
26/*
27 * Basic fh
28 */
29struct ceph_nfs_fh {
30 u64 ino;
31} __attribute__ ((packed));
32
33/*
34 * Larger 'connectable' fh that includes parent ino and name hash.
35 * Use this whenever possible, as it works more reliably.
36 */
37struct ceph_nfs_confh {
38 u64 ino, parent_ino;
39 u32 parent_name_hash;
40} __attribute__ ((packed));
41
42static int ceph_encode_fh(struct dentry *dentry, u32 *rawfh, int *max_len,
43 int connectable)
44{
92923dcb 45 int type;
a8e63b7d
SW
46 struct ceph_nfs_fh *fh = (void *)rawfh;
47 struct ceph_nfs_confh *cfh = (void *)rawfh;
48 struct dentry *parent = dentry->d_parent;
49 struct inode *inode = dentry->d_inode;
92923dcb
AK
50 int connected_handle_length = sizeof(*cfh)/4;
51 int handle_length = sizeof(*fh)/4;
a8e63b7d
SW
52
53 /* don't re-export snaps */
54 if (ceph_snap(inode) != CEPH_NOSNAP)
55 return -EINVAL;
56
92923dcb 57 if (*max_len >= connected_handle_length) {
a8e63b7d
SW
58 dout("encode_fh %p connectable\n", dentry);
59 cfh->ino = ceph_ino(dentry->d_inode);
60 cfh->parent_ino = ceph_ino(parent->d_inode);
61 cfh->parent_name_hash = parent->d_name.hash;
92923dcb 62 *max_len = connected_handle_length;
a8e63b7d 63 type = 2;
92923dcb 64 } else if (*max_len >= handle_length) {
a8e63b7d 65 if (connectable)
92923dcb 66 return 255;
a8e63b7d
SW
67 dout("encode_fh %p\n", dentry);
68 fh->ino = ceph_ino(dentry->d_inode);
92923dcb 69 *max_len = handle_length;
a8e63b7d
SW
70 type = 1;
71 } else {
92923dcb 72 return 255;
a8e63b7d
SW
73 }
74 return type;
75}
76
77/*
78 * convert regular fh to dentry
79 *
80 * FIXME: we should try harder by querying the mds for the ino.
81 */
82static struct dentry *__fh_to_dentry(struct super_block *sb,
83 struct ceph_nfs_fh *fh)
84{
85 struct inode *inode;
86 struct dentry *dentry;
87 struct ceph_vino vino;
88 int err;
89
90 dout("__fh_to_dentry %llx\n", fh->ino);
91 vino.ino = fh->ino;
92 vino.snap = CEPH_NOSNAP;
93 inode = ceph_find_inode(sb, vino);
94 if (!inode)
95 return ERR_PTR(-ESTALE);
96
97 dentry = d_obtain_alias(inode);
0d509c94 98 if (IS_ERR(dentry)) {
a8e63b7d
SW
99 pr_err("fh_to_dentry %llx -- inode %p but ENOMEM\n",
100 fh->ino, inode);
101 iput(inode);
0d509c94 102 return dentry;
a8e63b7d
SW
103 }
104 err = ceph_init_dentry(dentry);
105
106 if (err < 0) {
107 iput(inode);
108 return ERR_PTR(err);
109 }
110 dout("__fh_to_dentry %llx %p dentry %p\n", fh->ino, inode, dentry);
111 return dentry;
112}
113
114/*
115 * convert connectable fh to dentry
116 */
117static struct dentry *__cfh_to_dentry(struct super_block *sb,
118 struct ceph_nfs_confh *cfh)
119{
640ef79d 120 struct ceph_mds_client *mdsc = &ceph_sb_to_client(sb)->mdsc;
a8e63b7d
SW
121 struct inode *inode;
122 struct dentry *dentry;
123 struct ceph_vino vino;
124 int err;
125
126 dout("__cfh_to_dentry %llx (%llx/%x)\n",
127 cfh->ino, cfh->parent_ino, cfh->parent_name_hash);
128
129 vino.ino = cfh->ino;
130 vino.snap = CEPH_NOSNAP;
131 inode = ceph_find_inode(sb, vino);
132 if (!inode) {
133 struct ceph_mds_request *req;
134
135 req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPHASH,
136 USE_ANY_MDS);
137 if (IS_ERR(req))
7e34bc52 138 return ERR_CAST(req);
a8e63b7d
SW
139
140 req->r_ino1 = vino;
141 req->r_ino2.ino = cfh->parent_ino;
142 req->r_ino2.snap = CEPH_NOSNAP;
143 req->r_path2 = kmalloc(16, GFP_NOFS);
144 snprintf(req->r_path2, 16, "%d", cfh->parent_name_hash);
145 req->r_num_caps = 1;
146 err = ceph_mdsc_do_request(mdsc, NULL, req);
147 ceph_mdsc_put_request(req);
148 inode = ceph_find_inode(sb, vino);
149 if (!inode)
150 return ERR_PTR(err ? err : -ESTALE);
151 }
152
153 dentry = d_obtain_alias(inode);
0d509c94 154 if (IS_ERR(dentry)) {
a8e63b7d
SW
155 pr_err("cfh_to_dentry %llx -- inode %p but ENOMEM\n",
156 cfh->ino, inode);
157 iput(inode);
0d509c94 158 return dentry;
a8e63b7d
SW
159 }
160 err = ceph_init_dentry(dentry);
161 if (err < 0) {
162 iput(inode);
163 return ERR_PTR(err);
164 }
165 dout("__cfh_to_dentry %llx %p dentry %p\n", cfh->ino, inode, dentry);
166 return dentry;
167}
168
169static struct dentry *ceph_fh_to_dentry(struct super_block *sb, struct fid *fid,
170 int fh_len, int fh_type)
171{
172 if (fh_type == 1)
173 return __fh_to_dentry(sb, (struct ceph_nfs_fh *)fid->raw);
174 else
175 return __cfh_to_dentry(sb, (struct ceph_nfs_confh *)fid->raw);
176}
177
178/*
179 * get parent, if possible.
180 *
181 * FIXME: we could do better by querying the mds to discover the
182 * parent.
183 */
184static struct dentry *ceph_fh_to_parent(struct super_block *sb,
185 struct fid *fid,
186 int fh_len, int fh_type)
187{
188 struct ceph_nfs_confh *cfh = (void *)fid->raw;
189 struct ceph_vino vino;
190 struct inode *inode;
191 struct dentry *dentry;
192 int err;
193
194 if (fh_type == 1)
195 return ERR_PTR(-ESTALE);
196
197 pr_debug("fh_to_parent %llx/%d\n", cfh->parent_ino,
198 cfh->parent_name_hash);
199
200 vino.ino = cfh->ino;
201 vino.snap = CEPH_NOSNAP;
202 inode = ceph_find_inode(sb, vino);
203 if (!inode)
204 return ERR_PTR(-ESTALE);
205
206 dentry = d_obtain_alias(inode);
0d509c94 207 if (IS_ERR(dentry)) {
a8e63b7d
SW
208 pr_err("fh_to_parent %llx -- inode %p but ENOMEM\n",
209 cfh->ino, inode);
210 iput(inode);
0d509c94 211 return dentry;
a8e63b7d
SW
212 }
213 err = ceph_init_dentry(dentry);
214 if (err < 0) {
215 iput(inode);
216 return ERR_PTR(err);
217 }
218 dout("fh_to_parent %llx %p dentry %p\n", cfh->ino, inode, dentry);
219 return dentry;
220}
221
222const struct export_operations ceph_export_ops = {
223 .encode_fh = ceph_encode_fh,
224 .fh_to_dentry = ceph_fh_to_dentry,
225 .fh_to_parent = ceph_fh_to_parent,
226};