Merge branch 'master'
[linux-block.git] / fs / gfs2 / ops_export.c
CommitLineData
b3b94faa
DT
1/*
2 * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
3 * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
4 *
5 * This copyrighted material is made available to anyone wishing to use,
6 * modify, copy, or redistribute it subject to the terms and conditions
7 * of the GNU General Public License v.2.
8 */
9
10#include <linux/sched.h>
11#include <linux/slab.h>
12#include <linux/spinlock.h>
13#include <linux/completion.h>
14#include <linux/buffer_head.h>
15#include <asm/semaphore.h>
16
17#include "gfs2.h"
18#include "dir.h"
19#include "glock.h"
20#include "glops.h"
21#include "inode.h"
22#include "ops_export.h"
23#include "rgrp.h"
24
25static struct dentry *gfs2_decode_fh(struct super_block *sb,
26 __u32 *fh,
27 int fh_len,
28 int fh_type,
29 int (*acceptable)(void *context,
30 struct dentry *dentry),
31 void *context)
32{
33 struct gfs2_inum this, parent;
34
b3b94faa
DT
35 if (fh_type != fh_len)
36 return NULL;
37
38 memset(&parent, 0, sizeof(struct gfs2_inum));
39
40 switch (fh_type) {
41 case 8:
42 parent.no_formal_ino = ((uint64_t)be32_to_cpu(fh[4])) << 32;
43 parent.no_formal_ino |= be32_to_cpu(fh[5]);
44 parent.no_addr = ((uint64_t)be32_to_cpu(fh[6])) << 32;
45 parent.no_addr |= be32_to_cpu(fh[7]);
46 case 4:
47 this.no_formal_ino = ((uint64_t)be32_to_cpu(fh[0])) << 32;
48 this.no_formal_ino |= be32_to_cpu(fh[1]);
49 this.no_addr = ((uint64_t)be32_to_cpu(fh[2])) << 32;
50 this.no_addr |= be32_to_cpu(fh[3]);
51 break;
52 default:
53 return NULL;
54 }
55
56 return gfs2_export_ops.find_exported_dentry(sb, &this, &parent,
57 acceptable, context);
58}
59
60static int gfs2_encode_fh(struct dentry *dentry, __u32 *fh, int *len,
61 int connectable)
62{
63 struct inode *inode = dentry->d_inode;
64 struct gfs2_inode *ip = get_v2ip(inode);
65 struct gfs2_sbd *sdp = ip->i_sbd;
66
b3b94faa
DT
67 if (*len < 4 || (connectable && *len < 8))
68 return 255;
69
70 fh[0] = ip->i_num.no_formal_ino >> 32;
71 fh[0] = cpu_to_be32(fh[0]);
72 fh[1] = ip->i_num.no_formal_ino & 0xFFFFFFFF;
73 fh[1] = cpu_to_be32(fh[1]);
74 fh[2] = ip->i_num.no_addr >> 32;
75 fh[2] = cpu_to_be32(fh[2]);
76 fh[3] = ip->i_num.no_addr & 0xFFFFFFFF;
77 fh[3] = cpu_to_be32(fh[3]);
78 *len = 4;
79
f42faf4f 80 if (!connectable || ip == get_v2ip(sdp->sd_root_dir))
b3b94faa
DT
81 return *len;
82
83 spin_lock(&dentry->d_lock);
84 inode = dentry->d_parent->d_inode;
85 ip = get_v2ip(inode);
86 gfs2_inode_hold(ip);
87 spin_unlock(&dentry->d_lock);
88
89 fh[4] = ip->i_num.no_formal_ino >> 32;
90 fh[4] = cpu_to_be32(fh[4]);
91 fh[5] = ip->i_num.no_formal_ino & 0xFFFFFFFF;
92 fh[5] = cpu_to_be32(fh[5]);
93 fh[6] = ip->i_num.no_addr >> 32;
94 fh[6] = cpu_to_be32(fh[6]);
95 fh[7] = ip->i_num.no_addr & 0xFFFFFFFF;
96 fh[7] = cpu_to_be32(fh[7]);
97 *len = 8;
98
99 gfs2_inode_put(ip);
100
101 return *len;
102}
103
104struct get_name_filldir {
105 struct gfs2_inum inum;
106 char *name;
107};
108
109static int get_name_filldir(void *opaque, const char *name, unsigned int length,
110 uint64_t offset, struct gfs2_inum *inum,
111 unsigned int type)
112{
113 struct get_name_filldir *gnfd = (struct get_name_filldir *)opaque;
114
115 if (!gfs2_inum_equal(inum, &gnfd->inum))
116 return 0;
117
118 memcpy(gnfd->name, name, length);
119 gnfd->name[length] = 0;
120
121 return 1;
122}
123
124static int gfs2_get_name(struct dentry *parent, char *name,
125 struct dentry *child)
126{
127 struct inode *dir = parent->d_inode;
128 struct inode *inode = child->d_inode;
129 struct gfs2_inode *dip, *ip;
130 struct get_name_filldir gnfd;
131 struct gfs2_holder gh;
132 uint64_t offset = 0;
133 int error;
134
135 if (!dir)
136 return -EINVAL;
137
b3b94faa
DT
138 if (!S_ISDIR(dir->i_mode) || !inode)
139 return -EINVAL;
140
141 dip = get_v2ip(dir);
142 ip = get_v2ip(inode);
143
144 *name = 0;
145 gnfd.inum = ip->i_num;
146 gnfd.name = name;
147
148 error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &gh);
149 if (error)
150 return error;
151
152 error = gfs2_dir_read(dip, &offset, &gnfd, get_name_filldir);
153
154 gfs2_glock_dq_uninit(&gh);
155
156 if (!error && !*name)
157 error = -ENOENT;
158
159 return error;
160}
161
162static struct dentry *gfs2_get_parent(struct dentry *child)
163{
b3b94faa 164 struct qstr dotdot = { .name = "..", .len = 2 };
b3b94faa
DT
165 struct inode *inode;
166 struct dentry *dentry;
167 int error;
168
7359a19c 169 error = gfs2_lookupi(child->d_inode, &dotdot, 1, &inode);
b3b94faa
DT
170 if (error)
171 return ERR_PTR(error);
172
b3b94faa
DT
173 dentry = d_alloc_anon(inode);
174 if (!dentry) {
175 iput(inode);
176 return ERR_PTR(-ENOMEM);
177 }
178
179 return dentry;
180}
181
182static struct dentry *gfs2_get_dentry(struct super_block *sb, void *inum_p)
183{
184 struct gfs2_sbd *sdp = get_v2sdp(sb);
185 struct gfs2_inum *inum = (struct gfs2_inum *)inum_p;
186 struct gfs2_holder i_gh, ri_gh, rgd_gh;
187 struct gfs2_rgrpd *rgd;
188 struct gfs2_inode *ip;
189 struct inode *inode;
190 struct dentry *dentry;
191 int error;
192
b3b94faa
DT
193 /* System files? */
194
195 inode = gfs2_iget(sb, inum);
196 if (inode) {
197 ip = get_v2ip(inode);
198 if (ip->i_num.no_formal_ino != inum->no_formal_ino) {
199 iput(inode);
200 return ERR_PTR(-ESTALE);
201 }
202 goto out_inode;
203 }
204
205 error = gfs2_glock_nq_num(sdp,
206 inum->no_addr, &gfs2_inode_glops,
207 LM_ST_SHARED, LM_FLAG_ANY | GL_LOCAL_EXCL,
208 &i_gh);
209 if (error)
210 return ERR_PTR(error);
211
212 error = gfs2_inode_get(i_gh.gh_gl, inum, NO_CREATE, &ip);
213 if (error)
214 goto fail;
215 if (ip)
216 goto out_ip;
217
218 error = gfs2_rindex_hold(sdp, &ri_gh);
219 if (error)
220 goto fail;
221
222 error = -EINVAL;
223 rgd = gfs2_blk2rgrpd(sdp, inum->no_addr);
224 if (!rgd)
225 goto fail_rindex;
226
227 error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_SHARED, 0, &rgd_gh);
228 if (error)
229 goto fail_rindex;
230
231 error = -ESTALE;
232 if (gfs2_get_block_type(rgd, inum->no_addr) != GFS2_BLKST_DINODE)
233 goto fail_rgd;
234
235 gfs2_glock_dq_uninit(&rgd_gh);
236 gfs2_glock_dq_uninit(&ri_gh);
237
238 error = gfs2_inode_get(i_gh.gh_gl, inum, CREATE, &ip);
239 if (error)
240 goto fail;
241
242 error = gfs2_inode_refresh(ip);
243 if (error) {
244 gfs2_inode_put(ip);
245 goto fail;
246 }
247
b3b94faa
DT
248 out_ip:
249 error = -EIO;
250 if (ip->i_di.di_flags & GFS2_DIF_SYSTEM) {
251 gfs2_inode_put(ip);
252 goto fail;
253 }
254
255 gfs2_glock_dq_uninit(&i_gh);
256
257 inode = gfs2_ip2v(ip);
258 gfs2_inode_put(ip);
259
260 if (!inode)
261 return ERR_PTR(-ENOMEM);
262
263 out_inode:
264 dentry = d_alloc_anon(inode);
265 if (!dentry) {
266 iput(inode);
267 return ERR_PTR(-ENOMEM);
268 }
269
270 return dentry;
271
272 fail_rgd:
273 gfs2_glock_dq_uninit(&rgd_gh);
274
275 fail_rindex:
276 gfs2_glock_dq_uninit(&ri_gh);
277
278 fail:
279 gfs2_glock_dq_uninit(&i_gh);
280 return ERR_PTR(error);
281}
282
283struct export_operations gfs2_export_ops = {
284 .decode_fh = gfs2_decode_fh,
285 .encode_fh = gfs2_encode_fh,
286 .get_name = gfs2_get_name,
287 .get_parent = gfs2_get_parent,
288 .get_dentry = gfs2_get_dentry,
289};
290