diff options
author | David Woodhouse <dwmw2@infradead.org> | 2007-07-23 05:20:10 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@infradead.org> | 2007-07-23 05:20:10 -0400 |
commit | 39fe5434cb9de5da40510028b17b96bc4eb312b3 (patch) | |
tree | 7a02a317b9ad57da51ca99887c119e779ccf3f13 /fs/exportfs/expfs.c | |
parent | 0fc72b81d3111d114ab378935b1cf07680ca1289 (diff) | |
parent | f695baf2df9e0413d3521661070103711545207a (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'fs/exportfs/expfs.c')
-rw-r--r-- | fs/exportfs/expfs.c | 439 |
1 files changed, 220 insertions, 219 deletions
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c index e98f6cd7200c..8adb32a9387a 100644 --- a/fs/exportfs/expfs.c +++ b/fs/exportfs/expfs.c | |||
@@ -1,15 +1,45 @@ | |||
1 | 1 | ||
2 | #include <linux/exportfs.h> | ||
2 | #include <linux/fs.h> | 3 | #include <linux/fs.h> |
3 | #include <linux/file.h> | 4 | #include <linux/file.h> |
4 | #include <linux/module.h> | 5 | #include <linux/module.h> |
6 | #include <linux/mount.h> | ||
5 | #include <linux/namei.h> | 7 | #include <linux/namei.h> |
6 | 8 | ||
7 | struct export_operations export_op_default; | 9 | #define dprintk(fmt, args...) do{}while(0) |
8 | 10 | ||
9 | #define CALL(ops,fun) ((ops->fun)?(ops->fun):export_op_default.fun) | ||
10 | 11 | ||
11 | #define dprintk(fmt, args...) do{}while(0) | 12 | static int get_name(struct dentry *dentry, char *name, |
13 | struct dentry *child); | ||
14 | |||
15 | |||
16 | static struct dentry *exportfs_get_dentry(struct super_block *sb, void *obj) | ||
17 | { | ||
18 | struct dentry *result = ERR_PTR(-ESTALE); | ||
19 | |||
20 | if (sb->s_export_op->get_dentry) { | ||
21 | result = sb->s_export_op->get_dentry(sb, obj); | ||
22 | if (!result) | ||
23 | result = ERR_PTR(-ESTALE); | ||
24 | } | ||
25 | |||
26 | return result; | ||
27 | } | ||
28 | |||
29 | static int exportfs_get_name(struct dentry *dir, char *name, | ||
30 | struct dentry *child) | ||
31 | { | ||
32 | struct export_operations *nop = dir->d_sb->s_export_op; | ||
12 | 33 | ||
34 | if (nop->get_name) | ||
35 | return nop->get_name(dir, name, child); | ||
36 | else | ||
37 | return get_name(dir, name, child); | ||
38 | } | ||
39 | |||
40 | /* | ||
41 | * Check if the dentry or any of it's aliases is acceptable. | ||
42 | */ | ||
13 | static struct dentry * | 43 | static struct dentry * |
14 | find_acceptable_alias(struct dentry *result, | 44 | find_acceptable_alias(struct dentry *result, |
15 | int (*acceptable)(void *context, struct dentry *dentry), | 45 | int (*acceptable)(void *context, struct dentry *dentry), |
@@ -17,6 +47,9 @@ find_acceptable_alias(struct dentry *result, | |||
17 | { | 47 | { |
18 | struct dentry *dentry, *toput = NULL; | 48 | struct dentry *dentry, *toput = NULL; |
19 | 49 | ||
50 | if (acceptable(context, result)) | ||
51 | return result; | ||
52 | |||
20 | spin_lock(&dcache_lock); | 53 | spin_lock(&dcache_lock); |
21 | list_for_each_entry(dentry, &result->d_inode->i_dentry, d_alias) { | 54 | list_for_each_entry(dentry, &result->d_inode->i_dentry, d_alias) { |
22 | dget_locked(dentry); | 55 | dget_locked(dentry); |
@@ -37,130 +70,50 @@ find_acceptable_alias(struct dentry *result, | |||
37 | return NULL; | 70 | return NULL; |
38 | } | 71 | } |
39 | 72 | ||
40 | /** | 73 | /* |
41 | * find_exported_dentry - helper routine to implement export_operations->decode_fh | 74 | * Find root of a disconnected subtree and return a reference to it. |
42 | * @sb: The &super_block identifying the filesystem | ||
43 | * @obj: An opaque identifier of the object to be found - passed to | ||
44 | * get_inode | ||
45 | * @parent: An optional opqaue identifier of the parent of the object. | ||
46 | * @acceptable: A function used to test possible &dentries to see if they are | ||
47 | * acceptable | ||
48 | * @context: A parameter to @acceptable so that it knows on what basis to | ||
49 | * judge. | ||
50 | * | ||
51 | * find_exported_dentry is the central helper routine to enable file systems | ||
52 | * to provide the decode_fh() export_operation. It's main task is to take | ||
53 | * an &inode, find or create an appropriate &dentry structure, and possibly | ||
54 | * splice this into the dcache in the correct place. | ||
55 | * | ||
56 | * The decode_fh() operation provided by the filesystem should call | ||
57 | * find_exported_dentry() with the same parameters that it received except | ||
58 | * that instead of the file handle fragment, pointers to opaque identifiers | ||
59 | * for the object and optionally its parent are passed. The default decode_fh | ||
60 | * routine passes one pointer to the start of the filehandle fragment, and | ||
61 | * one 8 bytes into the fragment. It is expected that most filesystems will | ||
62 | * take this approach, though the offset to the parent identifier may well be | ||
63 | * different. | ||
64 | * | ||
65 | * find_exported_dentry() will call get_dentry to get an dentry pointer from | ||
66 | * the file system. If any &dentry in the d_alias list is acceptable, it will | ||
67 | * be returned. Otherwise find_exported_dentry() will attempt to splice a new | ||
68 | * &dentry into the dcache using get_name() and get_parent() to find the | ||
69 | * appropriate place. | ||
70 | */ | 75 | */ |
71 | 76 | static struct dentry * | |
72 | struct dentry * | 77 | find_disconnected_root(struct dentry *dentry) |
73 | find_exported_dentry(struct super_block *sb, void *obj, void *parent, | ||
74 | int (*acceptable)(void *context, struct dentry *de), | ||
75 | void *context) | ||
76 | { | 78 | { |
77 | struct dentry *result = NULL; | 79 | dget(dentry); |
78 | struct dentry *target_dir; | 80 | spin_lock(&dentry->d_lock); |
79 | int err; | 81 | while (!IS_ROOT(dentry) && |
80 | struct export_operations *nops = sb->s_export_op; | 82 | (dentry->d_parent->d_flags & DCACHE_DISCONNECTED)) { |
81 | struct dentry *alias; | 83 | struct dentry *parent = dentry->d_parent; |
82 | int noprogress; | 84 | dget(parent); |
83 | char nbuf[NAME_MAX+1]; | 85 | spin_unlock(&dentry->d_lock); |
84 | 86 | dput(dentry); | |
85 | /* | 87 | dentry = parent; |
86 | * Attempt to find the inode. | 88 | spin_lock(&dentry->d_lock); |
87 | */ | ||
88 | result = CALL(sb->s_export_op,get_dentry)(sb,obj); | ||
89 | err = -ESTALE; | ||
90 | if (result == NULL) | ||
91 | goto err_out; | ||
92 | if (IS_ERR(result)) { | ||
93 | err = PTR_ERR(result); | ||
94 | goto err_out; | ||
95 | } | 89 | } |
96 | if (S_ISDIR(result->d_inode->i_mode) && | 90 | spin_unlock(&dentry->d_lock); |
97 | (result->d_flags & DCACHE_DISCONNECTED)) { | 91 | return dentry; |
98 | /* it is an unconnected directory, we must connect it */ | 92 | } |
99 | ; | ||
100 | } else { | ||
101 | if (acceptable(context, result)) | ||
102 | return result; | ||
103 | if (S_ISDIR(result->d_inode->i_mode)) { | ||
104 | err = -EACCES; | ||
105 | goto err_result; | ||
106 | } | ||
107 | 93 | ||
108 | alias = find_acceptable_alias(result, acceptable, context); | ||
109 | if (alias) | ||
110 | return alias; | ||
111 | } | ||
112 | |||
113 | /* It's a directory, or we are required to confirm the file's | ||
114 | * location in the tree based on the parent information | ||
115 | */ | ||
116 | dprintk("find_exported_dentry: need to look harder for %s/%d\n",sb->s_id,*(int*)obj); | ||
117 | if (S_ISDIR(result->d_inode->i_mode)) | ||
118 | target_dir = dget(result); | ||
119 | else { | ||
120 | if (parent == NULL) | ||
121 | goto err_result; | ||
122 | 94 | ||
123 | target_dir = CALL(sb->s_export_op,get_dentry)(sb,parent); | 95 | /* |
124 | if (IS_ERR(target_dir)) | 96 | * Make sure target_dir is fully connected to the dentry tree. |
125 | err = PTR_ERR(target_dir); | 97 | * |
126 | if (target_dir == NULL || IS_ERR(target_dir)) | 98 | * It may already be, as the flag isn't always updated when connection happens. |
127 | goto err_result; | 99 | */ |
128 | } | 100 | static int |
129 | /* | 101 | reconnect_path(struct super_block *sb, struct dentry *target_dir) |
130 | * Now we need to make sure that target_dir is properly connected. | 102 | { |
131 | * It may already be, as the flag isn't always updated when connection | 103 | char nbuf[NAME_MAX+1]; |
132 | * happens. | 104 | int noprogress = 0; |
133 | * So, we walk up parent links until we find a connected directory, | 105 | int err = -ESTALE; |
134 | * or we run out of directories. Then we find the parent, find | ||
135 | * the name of the child in that parent, and do a lookup. | ||
136 | * This should connect the child into the parent | ||
137 | * We then repeat. | ||
138 | */ | ||
139 | 106 | ||
140 | /* it is possible that a confused file system might not let us complete | 107 | /* |
108 | * It is possible that a confused file system might not let us complete | ||
141 | * the path to the root. For example, if get_parent returns a directory | 109 | * the path to the root. For example, if get_parent returns a directory |
142 | * in which we cannot find a name for the child. While this implies a | 110 | * in which we cannot find a name for the child. While this implies a |
143 | * very sick filesystem we don't want it to cause knfsd to spin. Hence | 111 | * very sick filesystem we don't want it to cause knfsd to spin. Hence |
144 | * the noprogress counter. If we go through the loop 10 times (2 is | 112 | * the noprogress counter. If we go through the loop 10 times (2 is |
145 | * probably enough) without getting anywhere, we just give up | 113 | * probably enough) without getting anywhere, we just give up |
146 | */ | 114 | */ |
147 | noprogress= 0; | ||
148 | while (target_dir->d_flags & DCACHE_DISCONNECTED && noprogress++ < 10) { | 115 | while (target_dir->d_flags & DCACHE_DISCONNECTED && noprogress++ < 10) { |
149 | struct dentry *pd = target_dir; | 116 | struct dentry *pd = find_disconnected_root(target_dir); |
150 | |||
151 | dget(pd); | ||
152 | spin_lock(&pd->d_lock); | ||
153 | while (!IS_ROOT(pd) && | ||
154 | (pd->d_parent->d_flags&DCACHE_DISCONNECTED)) { | ||
155 | struct dentry *parent = pd->d_parent; | ||
156 | |||
157 | dget(parent); | ||
158 | spin_unlock(&pd->d_lock); | ||
159 | dput(pd); | ||
160 | pd = parent; | ||
161 | spin_lock(&pd->d_lock); | ||
162 | } | ||
163 | spin_unlock(&pd->d_lock); | ||
164 | 117 | ||
165 | if (!IS_ROOT(pd)) { | 118 | if (!IS_ROOT(pd)) { |
166 | /* must have found a connected parent - great */ | 119 | /* must have found a connected parent - great */ |
@@ -175,29 +128,40 @@ find_exported_dentry(struct super_block *sb, void *obj, void *parent, | |||
175 | spin_unlock(&pd->d_lock); | 128 | spin_unlock(&pd->d_lock); |
176 | noprogress = 0; | 129 | noprogress = 0; |
177 | } else { | 130 | } else { |
178 | /* we have hit the top of a disconnected path. Try | 131 | /* |
179 | * to find parent and connect | 132 | * We have hit the top of a disconnected path, try to |
180 | * note: racing with some other process renaming a | 133 | * find parent and connect. |
181 | * directory isn't much of a problem here. If someone | 134 | * |
182 | * renames the directory, it will end up properly | 135 | * Racing with some other process renaming a directory |
183 | * connected, which is what we want | 136 | * isn't much of a problem here. If someone renames |
137 | * the directory, it will end up properly connected, | ||
138 | * which is what we want | ||
139 | * | ||
140 | * Getting the parent can't be supported generically, | ||
141 | * the locking is too icky. | ||
142 | * | ||
143 | * Instead we just return EACCES. If server reboots | ||
144 | * or inodes get flushed, you lose | ||
184 | */ | 145 | */ |
185 | struct dentry *ppd; | 146 | struct dentry *ppd = ERR_PTR(-EACCES); |
186 | struct dentry *npd; | 147 | struct dentry *npd; |
187 | 148 | ||
188 | mutex_lock(&pd->d_inode->i_mutex); | 149 | mutex_lock(&pd->d_inode->i_mutex); |
189 | ppd = CALL(nops,get_parent)(pd); | 150 | if (sb->s_export_op->get_parent) |
151 | ppd = sb->s_export_op->get_parent(pd); | ||
190 | mutex_unlock(&pd->d_inode->i_mutex); | 152 | mutex_unlock(&pd->d_inode->i_mutex); |
191 | 153 | ||
192 | if (IS_ERR(ppd)) { | 154 | if (IS_ERR(ppd)) { |
193 | err = PTR_ERR(ppd); | 155 | err = PTR_ERR(ppd); |
194 | dprintk("find_exported_dentry: get_parent of %ld failed, err %d\n", | 156 | dprintk("%s: get_parent of %ld failed, err %d\n", |
195 | pd->d_inode->i_ino, err); | 157 | __FUNCTION__, pd->d_inode->i_ino, err); |
196 | dput(pd); | 158 | dput(pd); |
197 | break; | 159 | break; |
198 | } | 160 | } |
199 | dprintk("find_exported_dentry: find name of %lu in %lu\n", pd->d_inode->i_ino, ppd->d_inode->i_ino); | 161 | |
200 | err = CALL(nops,get_name)(ppd, nbuf, pd); | 162 | dprintk("%s: find name of %lu in %lu\n", __FUNCTION__, |
163 | pd->d_inode->i_ino, ppd->d_inode->i_ino); | ||
164 | err = exportfs_get_name(ppd, nbuf, pd); | ||
201 | if (err) { | 165 | if (err) { |
202 | dput(ppd); | 166 | dput(ppd); |
203 | dput(pd); | 167 | dput(pd); |
@@ -208,13 +172,14 @@ find_exported_dentry(struct super_block *sb, void *obj, void *parent, | |||
208 | continue; | 172 | continue; |
209 | break; | 173 | break; |
210 | } | 174 | } |
211 | dprintk("find_exported_dentry: found name: %s\n", nbuf); | 175 | dprintk("%s: found name: %s\n", __FUNCTION__, nbuf); |
212 | mutex_lock(&ppd->d_inode->i_mutex); | 176 | mutex_lock(&ppd->d_inode->i_mutex); |
213 | npd = lookup_one_len(nbuf, ppd, strlen(nbuf)); | 177 | npd = lookup_one_len(nbuf, ppd, strlen(nbuf)); |
214 | mutex_unlock(&ppd->d_inode->i_mutex); | 178 | mutex_unlock(&ppd->d_inode->i_mutex); |
215 | if (IS_ERR(npd)) { | 179 | if (IS_ERR(npd)) { |
216 | err = PTR_ERR(npd); | 180 | err = PTR_ERR(npd); |
217 | dprintk("find_exported_dentry: lookup failed: %d\n", err); | 181 | dprintk("%s: lookup failed: %d\n", |
182 | __FUNCTION__, err); | ||
218 | dput(ppd); | 183 | dput(ppd); |
219 | dput(pd); | 184 | dput(pd); |
220 | break; | 185 | break; |
@@ -227,7 +192,7 @@ find_exported_dentry(struct super_block *sb, void *obj, void *parent, | |||
227 | if (npd == pd) | 192 | if (npd == pd) |
228 | noprogress = 0; | 193 | noprogress = 0; |
229 | else | 194 | else |
230 | printk("find_exported_dentry: npd != pd\n"); | 195 | printk("%s: npd != pd\n", __FUNCTION__); |
231 | dput(npd); | 196 | dput(npd); |
232 | dput(ppd); | 197 | dput(ppd); |
233 | if (IS_ROOT(pd)) { | 198 | if (IS_ROOT(pd)) { |
@@ -243,15 +208,101 @@ find_exported_dentry(struct super_block *sb, void *obj, void *parent, | |||
243 | /* something went wrong - oh-well */ | 208 | /* something went wrong - oh-well */ |
244 | if (!err) | 209 | if (!err) |
245 | err = -ESTALE; | 210 | err = -ESTALE; |
246 | goto err_target; | 211 | return err; |
247 | } | 212 | } |
248 | /* if we weren't after a directory, have one more step to go */ | 213 | |
249 | if (result != target_dir) { | 214 | return 0; |
250 | struct dentry *nresult; | 215 | } |
251 | err = CALL(nops,get_name)(target_dir, nbuf, result); | 216 | |
217 | /** | ||
218 | * find_exported_dentry - helper routine to implement export_operations->decode_fh | ||
219 | * @sb: The &super_block identifying the filesystem | ||
220 | * @obj: An opaque identifier of the object to be found - passed to | ||
221 | * get_inode | ||
222 | * @parent: An optional opqaue identifier of the parent of the object. | ||
223 | * @acceptable: A function used to test possible &dentries to see if they are | ||
224 | * acceptable | ||
225 | * @context: A parameter to @acceptable so that it knows on what basis to | ||
226 | * judge. | ||
227 | * | ||
228 | * find_exported_dentry is the central helper routine to enable file systems | ||
229 | * to provide the decode_fh() export_operation. It's main task is to take | ||
230 | * an &inode, find or create an appropriate &dentry structure, and possibly | ||
231 | * splice this into the dcache in the correct place. | ||
232 | * | ||
233 | * The decode_fh() operation provided by the filesystem should call | ||
234 | * find_exported_dentry() with the same parameters that it received except | ||
235 | * that instead of the file handle fragment, pointers to opaque identifiers | ||
236 | * for the object and optionally its parent are passed. The default decode_fh | ||
237 | * routine passes one pointer to the start of the filehandle fragment, and | ||
238 | * one 8 bytes into the fragment. It is expected that most filesystems will | ||
239 | * take this approach, though the offset to the parent identifier may well be | ||
240 | * different. | ||
241 | * | ||
242 | * find_exported_dentry() will call get_dentry to get an dentry pointer from | ||
243 | * the file system. If any &dentry in the d_alias list is acceptable, it will | ||
244 | * be returned. Otherwise find_exported_dentry() will attempt to splice a new | ||
245 | * &dentry into the dcache using get_name() and get_parent() to find the | ||
246 | * appropriate place. | ||
247 | */ | ||
248 | |||
249 | struct dentry * | ||
250 | find_exported_dentry(struct super_block *sb, void *obj, void *parent, | ||
251 | int (*acceptable)(void *context, struct dentry *de), | ||
252 | void *context) | ||
253 | { | ||
254 | struct dentry *result, *alias; | ||
255 | int err = -ESTALE; | ||
256 | |||
257 | /* | ||
258 | * Attempt to find the inode. | ||
259 | */ | ||
260 | result = exportfs_get_dentry(sb, obj); | ||
261 | if (IS_ERR(result)) | ||
262 | return result; | ||
263 | |||
264 | if (S_ISDIR(result->d_inode->i_mode)) { | ||
265 | if (!(result->d_flags & DCACHE_DISCONNECTED)) { | ||
266 | if (acceptable(context, result)) | ||
267 | return result; | ||
268 | err = -EACCES; | ||
269 | goto err_result; | ||
270 | } | ||
271 | |||
272 | err = reconnect_path(sb, result); | ||
273 | if (err) | ||
274 | goto err_result; | ||
275 | } else { | ||
276 | struct dentry *target_dir, *nresult; | ||
277 | char nbuf[NAME_MAX+1]; | ||
278 | |||
279 | alias = find_acceptable_alias(result, acceptable, context); | ||
280 | if (alias) | ||
281 | return alias; | ||
282 | |||
283 | if (parent == NULL) | ||
284 | goto err_result; | ||
285 | |||
286 | target_dir = exportfs_get_dentry(sb,parent); | ||
287 | if (IS_ERR(target_dir)) { | ||
288 | err = PTR_ERR(target_dir); | ||
289 | goto err_result; | ||
290 | } | ||
291 | |||
292 | err = reconnect_path(sb, target_dir); | ||
293 | if (err) { | ||
294 | dput(target_dir); | ||
295 | goto err_result; | ||
296 | } | ||
297 | |||
298 | /* | ||
299 | * As we weren't after a directory, have one more step to go. | ||
300 | */ | ||
301 | err = exportfs_get_name(target_dir, nbuf, result); | ||
252 | if (!err) { | 302 | if (!err) { |
253 | mutex_lock(&target_dir->d_inode->i_mutex); | 303 | mutex_lock(&target_dir->d_inode->i_mutex); |
254 | nresult = lookup_one_len(nbuf, target_dir, strlen(nbuf)); | 304 | nresult = lookup_one_len(nbuf, target_dir, |
305 | strlen(nbuf)); | ||
255 | mutex_unlock(&target_dir->d_inode->i_mutex); | 306 | mutex_unlock(&target_dir->d_inode->i_mutex); |
256 | if (!IS_ERR(nresult)) { | 307 | if (!IS_ERR(nresult)) { |
257 | if (nresult->d_inode) { | 308 | if (nresult->d_inode) { |
@@ -261,11 +312,8 @@ find_exported_dentry(struct super_block *sb, void *obj, void *parent, | |||
261 | dput(nresult); | 312 | dput(nresult); |
262 | } | 313 | } |
263 | } | 314 | } |
315 | dput(target_dir); | ||
264 | } | 316 | } |
265 | dput(target_dir); | ||
266 | /* now result is properly connected, it is our best bet */ | ||
267 | if (acceptable(context, result)) | ||
268 | return result; | ||
269 | 317 | ||
270 | alias = find_acceptable_alias(result, acceptable, context); | 318 | alias = find_acceptable_alias(result, acceptable, context); |
271 | if (alias) | 319 | if (alias) |
@@ -275,32 +323,16 @@ find_exported_dentry(struct super_block *sb, void *obj, void *parent, | |||
275 | dput(result); | 323 | dput(result); |
276 | /* It might be justifiable to return ESTALE here, | 324 | /* It might be justifiable to return ESTALE here, |
277 | * but the filehandle at-least looks reasonable good | 325 | * but the filehandle at-least looks reasonable good |
278 | * and it just be a permission problem, so returning | 326 | * and it may just be a permission problem, so returning |
279 | * -EACCESS is safer | 327 | * -EACCESS is safer |
280 | */ | 328 | */ |
281 | return ERR_PTR(-EACCES); | 329 | return ERR_PTR(-EACCES); |
282 | 330 | ||
283 | err_target: | ||
284 | dput(target_dir); | ||
285 | err_result: | 331 | err_result: |
286 | dput(result); | 332 | dput(result); |
287 | err_out: | ||
288 | return ERR_PTR(err); | 333 | return ERR_PTR(err); |
289 | } | 334 | } |
290 | 335 | ||
291 | |||
292 | |||
293 | static struct dentry *get_parent(struct dentry *child) | ||
294 | { | ||
295 | /* get_parent cannot be supported generically, the locking | ||
296 | * is too icky. | ||
297 | * instead, we just return EACCES. If server reboots or inodes | ||
298 | * get flushed, you lose | ||
299 | */ | ||
300 | return ERR_PTR(-EACCES); | ||
301 | } | ||
302 | |||
303 | |||
304 | struct getdents_callback { | 336 | struct getdents_callback { |
305 | char *name; /* name that was found. It already points to a | 337 | char *name; /* name that was found. It already points to a |
306 | buffer NAME_MAX+1 is size */ | 338 | buffer NAME_MAX+1 is size */ |
@@ -390,61 +422,6 @@ out: | |||
390 | return error; | 422 | return error; |
391 | } | 423 | } |
392 | 424 | ||
393 | |||
394 | static struct dentry *export_iget(struct super_block *sb, unsigned long ino, __u32 generation) | ||
395 | { | ||
396 | |||
397 | /* iget isn't really right if the inode is currently unallocated!! | ||
398 | * This should really all be done inside each filesystem | ||
399 | * | ||
400 | * ext2fs' read_inode has been strengthed to return a bad_inode if | ||
401 | * the inode had been deleted. | ||
402 | * | ||
403 | * Currently we don't know the generation for parent directory, so | ||
404 | * a generation of 0 means "accept any" | ||
405 | */ | ||
406 | struct inode *inode; | ||
407 | struct dentry *result; | ||
408 | if (ino == 0) | ||
409 | return ERR_PTR(-ESTALE); | ||
410 | inode = iget(sb, ino); | ||
411 | if (inode == NULL) | ||
412 | return ERR_PTR(-ENOMEM); | ||
413 | if (is_bad_inode(inode) | ||
414 | || (generation && inode->i_generation != generation) | ||
415 | ) { | ||
416 | /* we didn't find the right inode.. */ | ||
417 | dprintk("fh_verify: Inode %lu, Bad count: %d %d or version %u %u\n", | ||
418 | inode->i_ino, | ||
419 | inode->i_nlink, atomic_read(&inode->i_count), | ||
420 | inode->i_generation, | ||
421 | generation); | ||
422 | |||
423 | iput(inode); | ||
424 | return ERR_PTR(-ESTALE); | ||
425 | } | ||
426 | /* now to find a dentry. | ||
427 | * If possible, get a well-connected one | ||
428 | */ | ||
429 | result = d_alloc_anon(inode); | ||
430 | if (!result) { | ||
431 | iput(inode); | ||
432 | return ERR_PTR(-ENOMEM); | ||
433 | } | ||
434 | return result; | ||
435 | } | ||
436 | |||
437 | |||
438 | static struct dentry *get_object(struct super_block *sb, void *vobjp) | ||
439 | { | ||
440 | __u32 *objp = vobjp; | ||
441 | unsigned long ino = objp[0]; | ||
442 | __u32 generation = objp[1]; | ||
443 | |||
444 | return export_iget(sb, ino, generation); | ||
445 | } | ||
446 | |||
447 | |||
448 | /** | 425 | /** |
449 | * export_encode_fh - default export_operations->encode_fh function | 426 | * export_encode_fh - default export_operations->encode_fh function |
450 | * @dentry: the dentry to encode | 427 | * @dentry: the dentry to encode |
@@ -517,16 +494,40 @@ static struct dentry *export_decode_fh(struct super_block *sb, __u32 *fh, int fh | |||
517 | acceptable, context); | 494 | acceptable, context); |
518 | } | 495 | } |
519 | 496 | ||
520 | struct export_operations export_op_default = { | 497 | int exportfs_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len, |
521 | .decode_fh = export_decode_fh, | 498 | int connectable) |
522 | .encode_fh = export_encode_fh, | 499 | { |
500 | struct export_operations *nop = dentry->d_sb->s_export_op; | ||
501 | int error; | ||
502 | |||
503 | if (nop->encode_fh) | ||
504 | error = nop->encode_fh(dentry, fh, max_len, connectable); | ||
505 | else | ||
506 | error = export_encode_fh(dentry, fh, max_len, connectable); | ||
523 | 507 | ||
524 | .get_name = get_name, | 508 | return error; |
525 | .get_parent = get_parent, | 509 | } |
526 | .get_dentry = get_object, | 510 | EXPORT_SYMBOL_GPL(exportfs_encode_fh); |
527 | }; | 511 | |
512 | struct dentry *exportfs_decode_fh(struct vfsmount *mnt, __u32 *fh, int fh_len, | ||
513 | int fileid_type, int (*acceptable)(void *, struct dentry *), | ||
514 | void *context) | ||
515 | { | ||
516 | struct export_operations *nop = mnt->mnt_sb->s_export_op; | ||
517 | struct dentry *result; | ||
518 | |||
519 | if (nop->decode_fh) { | ||
520 | result = nop->decode_fh(mnt->mnt_sb, fh, fh_len, fileid_type, | ||
521 | acceptable, context); | ||
522 | } else { | ||
523 | result = export_decode_fh(mnt->mnt_sb, fh, fh_len, fileid_type, | ||
524 | acceptable, context); | ||
525 | } | ||
526 | |||
527 | return result; | ||
528 | } | ||
529 | EXPORT_SYMBOL_GPL(exportfs_decode_fh); | ||
528 | 530 | ||
529 | EXPORT_SYMBOL(export_op_default); | ||
530 | EXPORT_SYMBOL(find_exported_dentry); | 531 | EXPORT_SYMBOL(find_exported_dentry); |
531 | 532 | ||
532 | MODULE_LICENSE("GPL"); | 533 | MODULE_LICENSE("GPL"); |