Line 0
Link Here
|
|
|
1 |
/* |
2 |
* linux/fs/supermount/namei.c |
3 |
* |
4 |
* Original version: |
5 |
* Copyright (C) 1995 |
6 |
* Stephen Tweedie (sct@dcs.ed.ac.uk) |
7 |
* |
8 |
* from |
9 |
* |
10 |
* linux/fs/minix/namei.c |
11 |
* Copyright (C) 1991, 1992 Linus Torvalds |
12 |
* |
13 |
* and |
14 |
* |
15 |
* linux/fs/ext2/namei.c |
16 |
* Copyright (C) 1992, 1993, 1994, 1995 Remy Card |
17 |
* |
18 |
* Rewriten for kernel 2.2 & 2.4. (C) 1999, 2000 Alexis Mikhailov |
19 |
* (alexis@abc.cap.ru) |
20 |
* Rewritten for kernel 2.4.21 (C) 2003 Andrey Borzenkov |
21 |
* (arvidjaar@mail.ru) |
22 |
* Rewritten for kernel 2.5.70 (C) 2003 Andrey Borzenkov |
23 |
* (arvidjaar@mail.ru) |
24 |
* |
25 |
* $Id: namei.c,v 1.21.2.11 2004/01/04 15:05:03 bor Exp $ |
26 |
*/ |
27 |
|
28 |
#define S_DBG_TRACE_CURRENT S_DBG_TRACE_NAMEI |
29 |
#include "supermount.h" |
30 |
|
31 |
/** |
32 |
* Attach super dentry to sub dentry |
33 |
* |
34 |
* @dentry: super dentry that is being created |
35 |
* @subd: subfs dentry that just has been found |
36 |
* |
37 |
* It checks whether subfs is still valid using @dentry->d_parent; |
38 |
* new supermount_dentry_info is created and set to point to @subd. |
39 |
* |
40 |
* It is possible that @subd actually has different name (ntfs, vfat or |
41 |
* in general any case-insensitive filesystems). Search @dentry->d_parent |
42 |
* for a child matching == @subd->d_name. If found, discard @dentry and child |
43 |
* (after some validity checks) is returned. Check that child actually points |
44 |
* to @subd |
45 |
* |
46 |
* d_lookup relies on the fact that hash is properly initialized in |
47 |
* @subd->d_name and that superfs is using the same compare method as subfs. |
48 |
* |
49 |
* About ref counting. @subd is dput in supermount_lookup. I.e. in case of |
50 |
* error or if we find out it is already connected to superfs the excessive |
51 |
* counter gets decremented. @dentry is finally dput in caller of ->lookup |
52 |
* if ->lookup returns something != 0. |
53 |
*/ |
54 |
|
55 |
static struct dentry * |
56 |
prepare_dentry(struct dentry *dentry, struct dentry *subd) |
57 |
{ |
58 |
struct super_block *sb = dentry->d_sb; |
59 |
struct dentry *rc; |
60 |
|
61 |
ENTER(sb, "dentry=%s subd=%s", dentry->d_name.name, subd->d_name.name); |
62 |
|
63 |
subfs_lock(sb); |
64 |
|
65 |
SUPERMOUNT_BUG_LOCKED_ON(sb, !subd); |
66 |
SUPERMOUNT_BUG_LOCKED_ON(sb, dentry->d_fsdata); |
67 |
|
68 |
rc = ERR_PTR(-ENOMEDIUM); |
69 |
if (!subfs_is_mounted(sb)) |
70 |
goto out; |
71 |
|
72 |
rc = ERR_PTR(-ESTALE); |
73 |
if (is_dentry_obsolete(dentry->d_parent)) |
74 |
goto out; |
75 |
|
76 |
rc = d_lookup(dentry->d_parent, &subd->d_name); |
77 |
if (IS_ERR(rc)) |
78 |
goto out; |
79 |
|
80 |
if (rc) { |
81 |
SUPERMOUNT_BUG_LOCKED_ON(sb, !rc->d_fsdata); |
82 |
SUPERMOUNT_BUG_LOCKED_ON(sb, |
83 |
((struct supermount_dentry_info *)rc->d_fsdata)->dentry != subd); |
84 |
} else { |
85 |
/* |
86 |
* this is theoretically possible. We cannot garantee full |
87 |
* coherency between subfs and superfs cache; i.e. entry |
88 |
* may have been left in one cache but removed from another |
89 |
*/ |
90 |
rc = ERR_PTR(-ENOMEM); |
91 |
if (init_dentry_info(dentry)) |
92 |
goto out; |
93 |
attach_subfs_dentry(dentry, subd); |
94 |
d_add(dentry, 0); |
95 |
rc = 0; |
96 |
} |
97 |
|
98 |
out: |
99 |
subfs_unlock(sb); |
100 |
|
101 |
LEAVE(sb, "dentry=%p subd=%p rc=%p", dentry, subd, rc); |
102 |
|
103 |
return rc; |
104 |
/* |
105 |
* subdent is implicitly freed on return if we skip dget here |
106 |
*/ |
107 |
} |
108 |
|
109 |
|
110 |
/** |
111 |
* Attach superfs inode to subfs inode |
112 |
* |
113 |
* @dentry: superfs dentry |
114 |
* @subd: subfs dentry |
115 |
* |
116 |
* This is expected to be called only in cointext that requires |
117 |
* negative dentry. |
118 |
* |
119 |
* FIXME |
120 |
* Holding sbi->sem during iget4 creates deadlock with write_inode - |
121 |
* write_inode sets I_LOCK abd calls supermount_write_inode at the |
122 |
* same moment as iget4 sleeps waiting for I_LOCK to be cleared. So |
123 |
* it first acquires inode and then checks if subfs is still valid. |
124 |
*/ |
125 |
|
126 |
static int |
127 |
prepare_inode(struct dentry *dentry, struct dentry *subd) |
128 |
{ |
129 |
struct super_block *sb = dentry->d_sb; |
130 |
struct inode *inode = dentry->d_inode; |
131 |
struct inode *subi = subd->d_inode; |
132 |
int rc; |
133 |
|
134 |
ENTER(sb, "dentry=%s", dentry->d_name.name); |
135 |
|
136 |
SUPERMOUNT_BUG_ON(inode); |
137 |
SUPERMOUNT_BUG_ON(!subi); |
138 |
|
139 |
rc = -ENOMEM; |
140 |
inode = iget_locked(sb, subi->i_ino); |
141 |
if (!inode) |
142 |
goto out; |
143 |
else if (inode->i_state & I_NEW) |
144 |
unlock_new_inode(inode); |
145 |
|
146 |
rc = 0; |
147 |
|
148 |
subfs_lock(sb); |
149 |
if (!subfs_is_mounted(sb)) |
150 |
rc = -ENOMEDIUM; |
151 |
else if (is_dentry_obsolete(dentry)) |
152 |
rc = -ESTALE; |
153 |
else { |
154 |
attach_subfs_inode(inode, subi); |
155 |
d_instantiate(dentry, inode); |
156 |
} |
157 |
subfs_unlock(sb); |
158 |
|
159 |
if (rc) |
160 |
iput(inode); |
161 |
|
162 |
out: |
163 |
LEAVE(sb, "dentry=%s inode=%p rc=%d", dentry->d_name.name, inode, rc); |
164 |
|
165 |
return rc; |
166 |
} |
167 |
|
168 |
struct inode * |
169 |
get_subfs_inode(struct inode *inode) |
170 |
{ |
171 |
struct super_block *sb = inode->i_sb; |
172 |
struct inode *err; |
173 |
struct supermount_inode_info *sii = supermount_i(inode); |
174 |
|
175 |
ENTER(sb, "inode=%p", inode); |
176 |
|
177 |
subfs_lock(sb); |
178 |
|
179 |
err = ERR_PTR(-ENOMEDIUM); |
180 |
if (!subfs_is_mounted(sb)) |
181 |
goto out; |
182 |
|
183 |
err = ERR_PTR(-ESTALE); |
184 |
if (is_inode_obsolete(inode)) |
185 |
goto out; |
186 |
|
187 |
err = igrab(sii->inode); |
188 |
SUPERMOUNT_BUG_LOCKED_ON(sb, !err); |
189 |
|
190 |
out: |
191 |
subfs_unlock(sb); |
192 |
|
193 |
LEAVE(sb, "inode=%p subi=%p", inode, err); |
194 |
|
195 |
return err; |
196 |
} |
197 |
|
198 |
/* inode methods */ |
199 |
|
200 |
static int |
201 |
supermount_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) |
202 |
{ |
203 |
struct super_block *sb = dir->i_sb; |
204 |
struct dentry *subdent; |
205 |
struct inode *subdir; |
206 |
int rc; |
207 |
struct vfsmount *mnt; |
208 |
|
209 |
ENTER(sb, "dir=%p dentry=%s", dir, dentry->d_name.name); |
210 |
|
211 |
mnt = subfs_go_online(sb); |
212 |
rc = PTR_ERR(mnt); |
213 |
if (IS_ERR(mnt)) |
214 |
goto out; |
215 |
|
216 |
subdir = get_subfs_inode(dir); |
217 |
rc = PTR_ERR(subdir); |
218 |
if (IS_ERR(subdir)) |
219 |
goto go_offline; |
220 |
|
221 |
rc = -EACCES; |
222 |
if (!subdir->i_op || !subdir->i_op->create) |
223 |
goto put_subdir; |
224 |
|
225 |
subdent = get_subfs_dentry(dentry); |
226 |
rc = PTR_ERR(subdent); |
227 |
if (IS_ERR(subdent)) |
228 |
goto put_subdir; |
229 |
|
230 |
rc = subfs_get_access(dir, 1); |
231 |
if (rc) |
232 |
goto put_subdent; |
233 |
|
234 |
/* FIXME build proper nd struct */ |
235 |
rc = subdir->i_op->create(subdir, subdent, mode, nd); |
236 |
subfs_put_access(dir, 1); |
237 |
if (rc) |
238 |
goto put_subdent; |
239 |
|
240 |
rc = prepare_inode(dentry, subdent); |
241 |
if (rc) |
242 |
goto put_subdent; |
243 |
|
244 |
dir->i_mtime = subdir->i_mtime; |
245 |
dir->i_ctime = subdir->i_ctime; |
246 |
dir->i_nlink = subdir->i_nlink; |
247 |
dir->i_size = subdir->i_size; |
248 |
dir->i_blocks = subdir->i_blocks; |
249 |
|
250 |
put_subdent: |
251 |
dput(subdent); |
252 |
put_subdir: |
253 |
iput(subdir); |
254 |
go_offline: |
255 |
subfs_go_offline(sb, mnt); |
256 |
out: |
257 |
LEAVE(sb, "dir=%p dentry=%s rc=%d", dir, dentry->d_name.name, rc); |
258 |
|
259 |
return rc; |
260 |
} |
261 |
|
262 |
/** |
263 |
* Search directory for a matching name |
264 |
* |
265 |
* @dir: directory that is being searched |
266 |
* @dentry: name to search for (in dentry->d_name) |
267 |
* |
268 |
* This is (currently :) the only method where we do not call subfs |
269 |
* directly. The reason is coherency between subfs and superfs dentry |
270 |
* caches. It is impossible to ensure it without modifying the very |
271 |
* guts of fs/dcache.c; so we check cache before doing actual lookup. |
272 |
* lookup_one_len just avoids duplicating of code. |
273 |
* |
274 |
* Supermount is in exclusive control of subfs so it is garanteed that |
275 |
* dentry cannot magically appear in the middle of lookup. |
276 |
* |
277 |
* There are filesystems that support multiple forms of file name, like |
278 |
* case-insensitive or short-long names on NTFS. In this case cache lookup |
279 |
* fails but filesystem may return dentry for different name. In this case |
280 |
* we check if dentry with matching name exists in parent and reuse it. |
281 |
*/ |
282 |
static struct dentry * |
283 |
supermount_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) |
284 |
{ |
285 |
struct super_block *sb = dir->i_sb; |
286 |
struct dentry *rc, *subdent, *subparent; |
287 |
struct inode *subdir; |
288 |
struct vfsmount *mnt; |
289 |
int ret; |
290 |
|
291 |
ENTER(sb, "dir=%p dentry=%s", dir, dentry->d_name.name); |
292 |
|
293 |
mnt = subfs_go_online(sb); |
294 |
rc = (struct dentry *)mnt; |
295 |
if (IS_ERR(mnt)) |
296 |
goto out; |
297 |
|
298 |
subdir = get_subfs_inode(dir); |
299 |
rc = (struct dentry *)subdir; |
300 |
if (IS_ERR(subdir)) |
301 |
goto go_offline; |
302 |
|
303 |
subparent = get_subfs_dentry(dentry->d_parent); |
304 |
rc = subparent; |
305 |
if (IS_ERR(subparent)) |
306 |
goto put_subdir; |
307 |
|
308 |
ret = subfs_get_access(dir, 0); |
309 |
rc = ERR_PTR(ret); |
310 |
if (ret) |
311 |
goto put_subparent; |
312 |
|
313 |
SUPERMOUNT_BUG_ON(subparent->d_inode != subdir); |
314 |
|
315 |
/* FIXME usually lookup_one_len is called under i_sem */ |
316 |
/* FIXME what to do with nd? */ |
317 |
subdent = lookup_one_len(dentry->d_name.name, subparent, |
318 |
dentry->d_name.len); |
319 |
|
320 |
subfs_put_access(dir, 0); |
321 |
rc = subdent; |
322 |
if (IS_ERR(rc)) |
323 |
goto put_subparent; |
324 |
|
325 |
rc = prepare_dentry(dentry, subdent); |
326 |
if (IS_ERR(rc)) |
327 |
goto put_subdent; |
328 |
|
329 |
if (!rc && subdent->d_inode) { |
330 |
ret = prepare_inode(dentry, subdent); |
331 |
if (ret < 0) |
332 |
rc = ERR_PTR(ret); |
333 |
} |
334 |
|
335 |
put_subdent: |
336 |
dput(subdent); |
337 |
put_subparent: |
338 |
dput(subparent); |
339 |
put_subdir: |
340 |
iput(subdir); |
341 |
go_offline: |
342 |
subfs_go_offline(sb, mnt); |
343 |
out: |
344 |
LEAVE(sb, "dir=%p dentry=%s rc=%p", dir, dentry->d_name.name, rc); |
345 |
|
346 |
return rc; |
347 |
} |
348 |
|
349 |
static int |
350 |
supermount_link(struct dentry *old_dentry, struct inode *dir, |
351 |
struct dentry *new_dentry) |
352 |
{ |
353 |
struct super_block *sb = dir->i_sb; |
354 |
struct dentry *old_subdent, *new_subdent; |
355 |
struct inode *subdir; |
356 |
int rc; |
357 |
struct vfsmount *mnt; |
358 |
|
359 |
ENTER(sb, "from=%s dir=%p to=%s", old_dentry->d_name.name, dir, new_dentry->d_name.name); |
360 |
|
361 |
SUPERMOUNT_BUG_ON(new_dentry->d_inode); |
362 |
|
363 |
mnt = subfs_go_online(sb); |
364 |
rc = PTR_ERR(mnt); |
365 |
if (IS_ERR(mnt)) |
366 |
goto out; |
367 |
|
368 |
subdir = get_subfs_inode(dir); |
369 |
rc = PTR_ERR(subdir); |
370 |
if (IS_ERR(subdir)) |
371 |
goto go_offline; |
372 |
|
373 |
rc = -EPERM; |
374 |
if (!subdir->i_op || !subdir->i_op->link) |
375 |
goto put_subdir; |
376 |
|
377 |
old_subdent = get_subfs_dentry(old_dentry); |
378 |
rc = PTR_ERR(old_subdent); |
379 |
if (IS_ERR(old_subdent)) |
380 |
goto put_subdir; |
381 |
|
382 |
new_subdent = get_subfs_dentry(new_dentry); |
383 |
rc = PTR_ERR(new_subdent); |
384 |
if (IS_ERR(new_subdent)) |
385 |
goto put_old_subdent; |
386 |
|
387 |
rc = subfs_get_access(dir, 1); |
388 |
if (rc) |
389 |
goto put_new_subdent; |
390 |
|
391 |
rc = subdir->i_op->link(old_subdent, subdir, new_subdent); |
392 |
subfs_put_access(dir, 1); |
393 |
if (rc) |
394 |
goto put_new_subdent; |
395 |
|
396 |
rc = prepare_inode(new_dentry, new_subdent); |
397 |
if (rc) |
398 |
goto put_new_subdent; |
399 |
|
400 |
dir->i_mtime = subdir->i_mtime; |
401 |
dir->i_ctime = subdir->i_ctime; |
402 |
dir->i_nlink = subdir->i_nlink; |
403 |
dir->i_size = subdir->i_size; |
404 |
dir->i_blocks = subdir->i_blocks; |
405 |
|
406 |
put_new_subdent: |
407 |
dput(new_subdent); |
408 |
put_old_subdent: |
409 |
dput(old_subdent); |
410 |
put_subdir: |
411 |
iput(subdir); |
412 |
go_offline: |
413 |
subfs_go_offline(sb, mnt); |
414 |
out: |
415 |
LEAVE(sb, "from=%s dir=%p to=%s rc=%d", old_dentry->d_name.name, dir, new_dentry->d_name.name, rc); |
416 |
|
417 |
return rc; |
418 |
} |
419 |
|
420 |
static int |
421 |
supermount_unlink(struct inode *dir, struct dentry *dentry) |
422 |
{ |
423 |
struct super_block *sb = dir->i_sb; |
424 |
struct dentry *subdent; |
425 |
struct inode *subdir; |
426 |
int rc; |
427 |
struct vfsmount *mnt; |
428 |
|
429 |
ENTER(sb, "dir=%p dentry=%s", dir, dentry->d_name.name); |
430 |
|
431 |
mnt = subfs_go_online(sb); |
432 |
rc = PTR_ERR(mnt); |
433 |
if (IS_ERR(mnt)) |
434 |
goto out; |
435 |
|
436 |
subdir = get_subfs_inode(dir); |
437 |
rc = PTR_ERR(subdir); |
438 |
if (IS_ERR(subdir)) |
439 |
goto go_offline; |
440 |
|
441 |
rc = -EPERM; |
442 |
if (!subdir->i_op || !subdir->i_op->unlink) |
443 |
goto put_subdir; |
444 |
|
445 |
subdent = get_subfs_dentry(dentry); |
446 |
rc = PTR_ERR(subdent); |
447 |
if (IS_ERR(subdent)) |
448 |
goto put_subdir; |
449 |
|
450 |
/* |
451 |
* below is not a typo. We have to mark _deleted_ inode |
452 |
* for possible later delete in clear_inode |
453 |
*/ |
454 |
rc = subfs_get_access(dentry->d_inode, 1); |
455 |
if (rc) |
456 |
goto put_subdent; |
457 |
|
458 |
rc = subdir->i_op->unlink(subdir, subdent); |
459 |
if (rc) |
460 |
goto put_write_access; |
461 |
|
462 |
dir->i_mtime = subdir->i_mtime; |
463 |
dir->i_ctime = subdir->i_ctime; |
464 |
dir->i_nlink = subdir->i_nlink; |
465 |
dir->i_size = subdir->i_size; |
466 |
dir->i_blocks = subdir->i_blocks; |
467 |
|
468 |
dentry->d_inode->i_nlink = subdent->d_inode->i_nlink; |
469 |
dentry->d_inode->i_ctime = subdent->d_inode->i_ctime; |
470 |
|
471 |
put_write_access: |
472 |
/* |
473 |
* we can't put write access if there are pending deletes |
474 |
* so we leave it on and let it be put in clear_inode for |
475 |
* i_nlink == 0 |
476 |
* |
477 |
* While i_nlink is believed to be atomic here i_count not, |
478 |
* so we cannot check && i_count == 0. It is expected that |
479 |
* deleted files are kept open only rarely. |
480 |
*/ |
481 |
if (dentry->d_inode->i_nlink) |
482 |
subfs_put_access(dentry->d_inode, 1); |
483 |
put_subdent: |
484 |
dput(subdent); |
485 |
put_subdir: |
486 |
iput(subdir); |
487 |
go_offline: |
488 |
subfs_go_offline(sb, mnt); |
489 |
out: |
490 |
LEAVE(sb, "dir=%p dentry=%s rc=%d", dir, dentry->d_name.name, rc); |
491 |
|
492 |
return rc; |
493 |
} |
494 |
|
495 |
static int |
496 |
supermount_symlink(struct inode *dir, struct dentry *dentry, |
497 |
const char *symname) |
498 |
{ |
499 |
struct super_block *sb = dir->i_sb; |
500 |
struct dentry *subdent; |
501 |
struct inode *subdir; |
502 |
int rc; |
503 |
struct vfsmount *mnt; |
504 |
|
505 |
ENTER(sb, "dir=%p dentry=%s", dir, dentry->d_name.name); |
506 |
|
507 |
mnt = subfs_go_online(sb); |
508 |
rc = PTR_ERR(mnt); |
509 |
if (IS_ERR(mnt)) |
510 |
goto out; |
511 |
|
512 |
subdir = get_subfs_inode(dir); |
513 |
rc = PTR_ERR(subdir); |
514 |
if (IS_ERR(subdir)) |
515 |
goto go_offline; |
516 |
|
517 |
rc = -EPERM; |
518 |
if (!subdir->i_op || !subdir->i_op->symlink) |
519 |
goto put_subdir; |
520 |
|
521 |
subdent = get_subfs_dentry(dentry); |
522 |
rc = PTR_ERR(subdent); |
523 |
if (IS_ERR(subdent)) |
524 |
goto put_subdir; |
525 |
|
526 |
rc = subfs_get_access(dir, 1); |
527 |
if (rc) |
528 |
goto put_subdent; |
529 |
|
530 |
rc = subdir->i_op->symlink(subdir, subdent, symname); |
531 |
subfs_put_access(dir, 1); |
532 |
if (rc) |
533 |
goto put_subdent; |
534 |
|
535 |
rc = prepare_inode(dentry, subdent); |
536 |
if (rc) |
537 |
goto put_subdent; |
538 |
|
539 |
dir->i_mtime = subdir->i_mtime; |
540 |
dir->i_ctime = subdir->i_ctime; |
541 |
dir->i_nlink = subdir->i_nlink; |
542 |
dir->i_size = subdir->i_size; |
543 |
dir->i_blocks = subdir->i_blocks; |
544 |
|
545 |
put_subdent: |
546 |
dput(subdent); |
547 |
put_subdir: |
548 |
iput(subdir); |
549 |
go_offline: |
550 |
subfs_go_offline(sb, mnt); |
551 |
out: |
552 |
LEAVE(sb, "dir=%p dentry=%s rc=%d", dir, dentry->d_name.name, rc); |
553 |
|
554 |
return rc; |
555 |
} |
556 |
|
557 |
static int |
558 |
supermount_mkdir(struct inode *dir, struct dentry *dentry, int mode) |
559 |
{ |
560 |
struct super_block *sb = dir->i_sb; |
561 |
struct dentry *subdent; |
562 |
struct inode *subdir; |
563 |
int rc; |
564 |
struct vfsmount *mnt; |
565 |
|
566 |
ENTER(sb, "dir=%p dentry=%s", dir, dentry->d_name.name); |
567 |
|
568 |
mnt = subfs_go_online(sb); |
569 |
rc = PTR_ERR(mnt); |
570 |
if (IS_ERR(mnt)) |
571 |
goto out; |
572 |
|
573 |
subdir = get_subfs_inode(dir); |
574 |
rc = PTR_ERR(subdir); |
575 |
if (IS_ERR(subdir)) |
576 |
goto go_offline; |
577 |
|
578 |
rc = -EPERM; |
579 |
if (!subdir->i_op || !subdir->i_op->mkdir) |
580 |
goto put_subdir; |
581 |
|
582 |
subdent = get_subfs_dentry(dentry); |
583 |
rc = PTR_ERR(subdent); |
584 |
if (IS_ERR(subdent)) |
585 |
goto put_subdir; |
586 |
|
587 |
rc = subfs_get_access(dir, 1); |
588 |
if (rc) |
589 |
goto put_subdent; |
590 |
|
591 |
rc = subdir->i_op->mkdir(subdir, subdent, mode); |
592 |
subfs_put_access(dir, 1); |
593 |
if (rc) |
594 |
goto put_subdent; |
595 |
|
596 |
rc = prepare_inode(dentry, subdent); |
597 |
if (rc) |
598 |
goto put_subdent; |
599 |
|
600 |
dir->i_mtime = subdir->i_mtime; |
601 |
dir->i_ctime = subdir->i_ctime; |
602 |
dir->i_nlink = subdir->i_nlink; |
603 |
dir->i_size = subdir->i_size; |
604 |
dir->i_blocks = subdir->i_blocks; |
605 |
|
606 |
put_subdent: |
607 |
dput(subdent); |
608 |
put_subdir: |
609 |
iput(subdir); |
610 |
go_offline: |
611 |
subfs_go_offline(sb, mnt); |
612 |
out: |
613 |
LEAVE(sb, "dir=%p dentry=%s rc=%d", dir, dentry->d_name.name, rc); |
614 |
|
615 |
return rc; |
616 |
} |
617 |
|
618 |
static int |
619 |
supermount_rmdir(struct inode *dir, struct dentry *dentry) |
620 |
{ |
621 |
struct super_block *sb = dir->i_sb; |
622 |
struct dentry *subdent; |
623 |
struct inode *subdir; |
624 |
int rc; |
625 |
struct vfsmount *mnt; |
626 |
|
627 |
ENTER(sb, "dir=%p dentry=%s", dir, dentry->d_name.name); |
628 |
|
629 |
mnt = subfs_go_online(sb); |
630 |
rc = PTR_ERR(mnt); |
631 |
if (IS_ERR(mnt)) |
632 |
goto out; |
633 |
|
634 |
subdir = get_subfs_inode(dir); |
635 |
rc = PTR_ERR(subdir); |
636 |
if (IS_ERR(subdir)) |
637 |
goto go_offline; |
638 |
|
639 |
rc = -EPERM; |
640 |
if (!subdir->i_op || !subdir->i_op->rmdir) |
641 |
goto put_subdir; |
642 |
|
643 |
subdent = get_subfs_dentry(dentry); |
644 |
rc = PTR_ERR(subdent); |
645 |
if (IS_ERR(subdent)) |
646 |
goto put_subdir; |
647 |
|
648 |
/* cf. supermount_unlink */ |
649 |
rc = subfs_get_access(dentry->d_inode, 1); |
650 |
if (rc) |
651 |
goto put_subdent; |
652 |
|
653 |
rc = subdir->i_op->rmdir(subdir, subdent); |
654 |
if (rc) |
655 |
goto put_write_access; |
656 |
|
657 |
dir->i_mtime = subdir->i_mtime; |
658 |
dir->i_ctime = subdir->i_ctime; |
659 |
dir->i_nlink = subdir->i_nlink; |
660 |
dir->i_size = subdir->i_size; |
661 |
dir->i_blocks = subdir->i_blocks; |
662 |
|
663 |
/* hmm ... hard links to directories are not allowed, are they? */ |
664 |
dentry->d_inode->i_nlink = subdent->d_inode->i_nlink; |
665 |
dentry->d_inode->i_ctime = subdent->d_inode->i_ctime; |
666 |
|
667 |
put_write_access: |
668 |
/* cf. supermount_unlink */ |
669 |
if (dentry->d_inode->i_nlink) |
670 |
subfs_put_access(dentry->d_inode, 1); |
671 |
put_subdent: |
672 |
dput(subdent); |
673 |
put_subdir: |
674 |
iput(subdir); |
675 |
go_offline: |
676 |
subfs_go_offline(sb, mnt); |
677 |
out: |
678 |
LEAVE(sb, "dir=%p dentry=%s rc=%d", dir, dentry->d_name.name, rc); |
679 |
|
680 |
return rc; |
681 |
} |
682 |
|
683 |
static int |
684 |
supermount_mknod(struct inode *dir, struct dentry *dentry, int |
685 |
mode, dev_t dev) |
686 |
{ |
687 |
struct super_block *sb = dir->i_sb; |
688 |
struct dentry *subdent; |
689 |
struct inode *subdir; |
690 |
int rc; |
691 |
struct vfsmount *mnt; |
692 |
|
693 |
ENTER(sb, "dir=%p dentry=%s", dir, dentry->d_name.name); |
694 |
|
695 |
mnt = subfs_go_online(sb); |
696 |
rc = PTR_ERR(mnt); |
697 |
if (IS_ERR(mnt)) |
698 |
goto out; |
699 |
|
700 |
subdir = get_subfs_inode(dir); |
701 |
rc = PTR_ERR(subdir); |
702 |
if (IS_ERR(subdir)) |
703 |
goto go_offline; |
704 |
|
705 |
rc = -EPERM; |
706 |
if (!subdir->i_op || !subdir->i_op->mknod) |
707 |
goto put_subdir; |
708 |
|
709 |
subdent = get_subfs_dentry(dentry); |
710 |
rc = PTR_ERR(subdent); |
711 |
if (IS_ERR(subdent)) |
712 |
goto put_subdir; |
713 |
|
714 |
rc = subfs_get_access(dir, 1); |
715 |
if (rc) |
716 |
goto put_subdent; |
717 |
|
718 |
rc = subdir->i_op->mknod(subdir, subdent, mode, dev); |
719 |
subfs_put_access(dir, 1); |
720 |
if (rc) |
721 |
goto put_subdent; |
722 |
|
723 |
rc = prepare_inode(dentry, subdent); |
724 |
if (rc) |
725 |
goto put_subdent; |
726 |
|
727 |
dir->i_mtime = subdir->i_mtime; |
728 |
dir->i_ctime = subdir->i_ctime; |
729 |
dir->i_nlink = subdir->i_nlink; |
730 |
dir->i_size = subdir->i_size; |
731 |
dir->i_blocks = subdir->i_blocks; |
732 |
|
733 |
put_subdent: |
734 |
dput(subdent); |
735 |
put_subdir: |
736 |
iput(subdir); |
737 |
go_offline: |
738 |
subfs_go_offline(sb, mnt); |
739 |
out: |
740 |
LEAVE(sb, "dir=%p dentry=%s rc=%d", dir, dentry->d_name.name, rc); |
741 |
|
742 |
return rc; |
743 |
} |
744 |
|
745 |
static int |
746 |
supermount_rename(struct inode *olddir, struct dentry *olddentry, |
747 |
struct inode *newdir, struct dentry *newdentry) |
748 |
{ |
749 |
struct super_block *sb = olddir->i_sb; |
750 |
struct dentry *oldsubdent, *newsubdent; |
751 |
struct inode *oldsubdir, *newsubdir; |
752 |
int rc; |
753 |
struct vfsmount *mnt; |
754 |
|
755 |
ENTER(sb, "olddir=%p olddentry=%s newdir=%p newdentry=%s", olddir, olddentry->d_name.name, newdir, newdentry->d_name.name); |
756 |
|
757 |
mnt = subfs_go_online(sb); |
758 |
rc = PTR_ERR(mnt); |
759 |
if (IS_ERR(mnt)) |
760 |
goto out; |
761 |
|
762 |
oldsubdir = get_subfs_inode(olddir); |
763 |
rc = PTR_ERR(oldsubdir); |
764 |
if (IS_ERR(oldsubdir)) |
765 |
goto go_offline; |
766 |
|
767 |
rc = -EPERM; |
768 |
if (!oldsubdir->i_op || !oldsubdir->i_op->rename) |
769 |
goto put_old_subdir; |
770 |
|
771 |
oldsubdent = get_subfs_dentry(olddentry); |
772 |
rc = PTR_ERR(oldsubdent); |
773 |
if (IS_ERR(oldsubdent)) |
774 |
goto put_old_subdir; |
775 |
|
776 |
newsubdir = get_subfs_inode(newdir); |
777 |
rc = PTR_ERR(newsubdir); |
778 |
if (IS_ERR(newsubdir)) |
779 |
goto put_old_subdent; |
780 |
|
781 |
newsubdent = get_subfs_dentry(newdentry); |
782 |
rc = PTR_ERR(newsubdent); |
783 |
if (IS_ERR(newsubdent)) |
784 |
goto put_new_subdir; |
785 |
|
786 |
/* |
787 |
* If new file exists it will be implcitly unlinked so |
788 |
* behave like in unlink case. |
789 |
* If it does not exist we have two write accesses - for |
790 |
* both old and new directory, I guess it does not matter |
791 |
* which one is used in this case |
792 |
*/ |
793 |
if (newdentry->d_inode) |
794 |
rc = subfs_get_access(newdentry->d_inode, 1); |
795 |
else |
796 |
rc = subfs_get_access(olddir, 1); |
797 |
if (rc) |
798 |
goto put_new_subdent; |
799 |
|
800 |
rc = oldsubdir->i_op->rename(oldsubdir, oldsubdent, |
801 |
newsubdir, newsubdent); |
802 |
if (rc) |
803 |
goto put_write_access; |
804 |
|
805 |
/* |
806 |
* this is strictly speaking conditional on FS_RENAME_DOES_D_MOVE |
807 |
* flag, but as of this writing this flag is set only |
808 |
* for NFS or intermezzo and it hopefully goes away sometimes ... |
809 |
* |
810 |
* Supermount patch adds code to do_kern_mount that checks |
811 |
* for this flag and refuses mounting |
812 |
*/ |
813 |
d_move(oldsubdent, newsubdent); |
814 |
|
815 |
olddir->i_mtime = oldsubdir->i_mtime; |
816 |
olddir->i_ctime = oldsubdir->i_ctime; |
817 |
olddir->i_nlink = oldsubdir->i_nlink; |
818 |
olddir->i_size = oldsubdir->i_size; |
819 |
olddir->i_blocks = oldsubdir->i_blocks; |
820 |
|
821 |
newdir->i_mtime = newsubdir->i_mtime; |
822 |
newdir->i_ctime = newsubdir->i_ctime; |
823 |
newdir->i_nlink = newsubdir->i_nlink; |
824 |
newdir->i_size = newsubdir->i_size; |
825 |
newdir->i_blocks = newsubdir->i_blocks; |
826 |
|
827 |
olddentry->d_inode->i_nlink = oldsubdent->d_inode->i_nlink; |
828 |
olddentry->d_inode->i_ctime = oldsubdent->d_inode->i_ctime; |
829 |
|
830 |
if (newdentry->d_inode) { |
831 |
newdentry->d_inode->i_nlink = newsubdent->d_inode->i_nlink; |
832 |
newdentry->d_inode->i_ctime = newsubdent->d_inode->i_ctime; |
833 |
} |
834 |
|
835 |
put_write_access: |
836 |
if (newdentry->d_inode) { |
837 |
/* cf. supermount_unlink */ |
838 |
if (newdentry->d_inode->i_nlink) |
839 |
subfs_put_access(newdentry->d_inode, 1); |
840 |
} else |
841 |
subfs_put_access(olddir, 1); |
842 |
put_new_subdent: |
843 |
dput(newsubdent); |
844 |
put_new_subdir: |
845 |
iput(newsubdir); |
846 |
put_old_subdent: |
847 |
dput(oldsubdent); |
848 |
put_old_subdir: |
849 |
iput(oldsubdir); |
850 |
go_offline: |
851 |
subfs_go_offline(sb, mnt); |
852 |
out: |
853 |
LEAVE(sb, "olddentry=%s newdentry=%s rc=%d", olddentry->d_name.name, newdentry->d_name.name, rc); |
854 |
|
855 |
return rc; |
856 |
} |
857 |
|
858 |
static int |
859 |
supermount_readlink(struct dentry *dentry, char *buffer , int buflen) |
860 |
{ |
861 |
struct super_block *sb = dentry->d_sb; |
862 |
struct inode *inode = dentry->d_inode; |
863 |
struct dentry *subdent; |
864 |
int write_on = NEED_WRITE_ATIME(inode); |
865 |
int rc; |
866 |
struct vfsmount *mnt; |
867 |
|
868 |
ENTER(sb, "dentry=%s", dentry->d_name.name); |
869 |
|
870 |
mnt = subfs_go_online(sb); |
871 |
rc = PTR_ERR(mnt); |
872 |
if (IS_ERR(mnt)) |
873 |
goto out; |
874 |
|
875 |
subdent = get_subfs_dentry(dentry); |
876 |
rc = PTR_ERR(subdent); |
877 |
if (IS_ERR(subdent)) |
878 |
goto go_offline; |
879 |
|
880 |
rc = -EINVAL; |
881 |
if (!subdent->d_inode->i_op || !subdent->d_inode->i_op->readlink) |
882 |
goto put_subdent; |
883 |
|
884 |
rc = subfs_get_access(inode, write_on); |
885 |
if (rc) |
886 |
goto put_subdent; |
887 |
|
888 |
//update_atime(subdent->d_inode); |
889 |
touch_atime(mnt,subdent); |
890 |
rc = subdent->d_inode->i_op->readlink(subdent, buffer, buflen); |
891 |
subfs_put_access(inode, write_on); |
892 |
inode->i_atime = subdent->d_inode->i_atime; |
893 |
|
894 |
put_subdent: |
895 |
dput(subdent); |
896 |
go_offline: |
897 |
subfs_go_offline(sb, mnt); |
898 |
out: |
899 |
LEAVE(sb, "dentry=%s rc=%d", dentry->d_name.name, rc); |
900 |
|
901 |
return rc; |
902 |
} |
903 |
|
904 |
static int |
905 |
supermount_follow_link(struct dentry *dentry, struct nameidata *nd) |
906 |
{ |
907 |
struct super_block *sb = dentry->d_sb; |
908 |
struct inode *inode = dentry->d_inode; |
909 |
struct dentry *subdent; |
910 |
int write_on = NEED_WRITE_ATIME(inode); |
911 |
int rc; |
912 |
struct vfsmount *mnt; |
913 |
|
914 |
ENTER(sb, "dentry=%s", dentry->d_name.name); |
915 |
|
916 |
mnt = subfs_go_online(sb); |
917 |
rc = PTR_ERR(mnt); |
918 |
if (IS_ERR(mnt)) |
919 |
goto out; |
920 |
|
921 |
subdent = get_subfs_dentry(dentry); |
922 |
rc = PTR_ERR(subdent); |
923 |
if (IS_ERR(subdent)) |
924 |
goto go_offline; |
925 |
|
926 |
rc = subfs_get_access(inode, write_on); |
927 |
if (rc) |
928 |
goto put_subdent; |
929 |
|
930 |
//update_atime(subdent->d_inode); |
931 |
touch_atime(mnt,subdent); |
932 |
/* FIXME do we need proper subfs nd here? */ |
933 |
rc = subdent->d_inode->i_op->follow_link(subdent, nd); |
934 |
subfs_put_access(inode, write_on); |
935 |
inode->i_atime = subdent->d_inode->i_atime; |
936 |
|
937 |
put_subdent: |
938 |
dput(subdent); |
939 |
go_offline: |
940 |
subfs_go_offline(sb, mnt); |
941 |
out: |
942 |
LEAVE(sb, "dentry=%s rc=%d", dentry->d_name.name, rc); |
943 |
|
944 |
return rc; |
945 |
} |
946 |
|
947 |
static int |
948 |
supermount_permission(struct inode *inode, int mask, struct nameidata *nd) |
949 |
{ |
950 |
struct super_block *sb = inode->i_sb; |
951 |
struct inode *subi; |
952 |
int rc; |
953 |
int write_on = !IS_RDONLY(inode) && (mask & MAY_WRITE); |
954 |
struct vfsmount *mnt; |
955 |
int fake_permissions = 1; |
956 |
|
957 |
ENTER(sb, "inode=%p", inode); |
958 |
|
959 |
mnt = subfs_go_online(sb); |
960 |
rc = PTR_ERR(mnt); |
961 |
if (IS_ERR(mnt)) |
962 |
goto out; |
963 |
|
964 |
subi = get_subfs_inode(inode); |
965 |
rc = PTR_ERR(subi); |
966 |
if (IS_ERR(subi)) |
967 |
goto go_offline; |
968 |
|
969 |
rc = subfs_get_access(inode, write_on); |
970 |
if (rc) |
971 |
goto put_subi; |
972 |
|
973 |
fake_permissions = 0; |
974 |
/* FIXME do we need proper subfs nd here */ |
975 |
if (subi->i_op && subi->i_op->permission) |
976 |
rc = subi->i_op->permission(subi, mask, nd); |
977 |
else |
978 |
rc = generic_permission(subi, mask, NULL); |
979 |
|
980 |
subfs_put_access(inode, write_on); |
981 |
|
982 |
put_subi: |
983 |
iput(subi); |
984 |
go_offline: |
985 |
subfs_go_offline(sb, mnt); |
986 |
out: |
987 |
if (fake_permissions && inode == sb->s_root->d_inode) { |
988 |
/* cf. file.c:supermount_open() */ |
989 |
rc = generic_permission(inode, mask, NULL); |
990 |
} |
991 |
|
992 |
LEAVE(sb, "inode=%p rc=%d fake=%d", inode, rc, fake_permissions); |
993 |
|
994 |
return rc; |
995 |
} |
996 |
|
997 |
static int |
998 |
supermount_setattr(struct dentry *dentry, struct iattr *attr) |
999 |
{ |
1000 |
struct super_block *sb = dentry->d_sb; |
1001 |
struct inode *subi; |
1002 |
struct dentry *subdent; |
1003 |
int rc; |
1004 |
struct vfsmount *mnt; |
1005 |
|
1006 |
ENTER(sb, "dentry=%s", dentry->d_name.name); |
1007 |
|
1008 |
mnt = subfs_go_online(sb); |
1009 |
rc = PTR_ERR(mnt); |
1010 |
if (IS_ERR(mnt)) |
1011 |
goto out; |
1012 |
|
1013 |
subdent = get_subfs_dentry(dentry); |
1014 |
rc = PTR_ERR(subdent); |
1015 |
if (IS_ERR(subdent)) |
1016 |
goto go_offline; |
1017 |
|
1018 |
rc = subfs_get_access(dentry->d_inode, 1); |
1019 |
if (rc) |
1020 |
goto put_subdent; |
1021 |
|
1022 |
subi = subdent->d_inode; |
1023 |
if (subi->i_op && subi->i_op->setattr) |
1024 |
rc = subi->i_op->setattr(subdent, attr); |
1025 |
else { |
1026 |
rc = inode_change_ok(subi, attr); |
1027 |
/* |
1028 |
* FIXME |
1029 |
* What to do with quota? |
1030 |
*/ |
1031 |
if (!rc) |
1032 |
rc = inode_setattr(subi, attr); |
1033 |
} |
1034 |
subfs_put_access(dentry->d_inode, 1); |
1035 |
if (rc) |
1036 |
goto put_subdent; |
1037 |
|
1038 |
/* |
1039 |
* If it worked, then we need to mark the modification |
1040 |
* to the subfs, and we also need to propogate the |
1041 |
* change up to the shadowing inode. |
1042 |
*/ |
1043 |
attr->ia_mode = subi->i_mode; |
1044 |
attr->ia_uid = subi->i_uid; |
1045 |
attr->ia_gid = subi->i_gid; |
1046 |
attr->ia_size = subi->i_size; |
1047 |
attr->ia_atime = subi->i_atime; |
1048 |
attr->ia_mtime = subi->i_mtime; |
1049 |
attr->ia_ctime = subi->i_ctime; |
1050 |
attr->ia_valid = |
1051 |
ATTR_UID | ATTR_GID | ATTR_MODE | ATTR_SIZE | |
1052 |
ATTR_ATIME | ATTR_MTIME | ATTR_CTIME; |
1053 |
inode_setattr(dentry->d_inode, attr); |
1054 |
|
1055 |
put_subdent: |
1056 |
dput(subdent); |
1057 |
go_offline: |
1058 |
subfs_go_offline(sb, mnt); |
1059 |
out: |
1060 |
LEAVE(sb, "dentry=%s rc=%d", dentry->d_name.name, rc); |
1061 |
|
1062 |
return rc; |
1063 |
} |
1064 |
|
1065 |
static int |
1066 |
supermount_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) |
1067 |
{ |
1068 |
struct super_block *sb = dentry->d_sb; |
1069 |
struct vfsmount *submnt; |
1070 |
struct dentry *subdent = 0; |
1071 |
int rc; |
1072 |
|
1073 |
ENTER(sb, "dentry=%s", dentry->d_name.name); |
1074 |
|
1075 |
/* |
1076 |
* do not use subfs_go_online - it will result in ls /mnt |
1077 |
* attempting to mount all supermounted directories |
1078 |
*/ |
1079 |
submnt = subfs_prevent_umount(sb); |
1080 |
if (submnt) |
1081 |
subdent = get_subfs_dentry(dentry); |
1082 |
|
1083 |
/* |
1084 |
* do not fail stat for stale files - it is needed to |
1085 |
* make sure fuser -m /mnt/cdrom lists all processes still |
1086 |
* having any (obsolete) file open |
1087 |
*/ |
1088 |
if (submnt && subdent && !IS_ERR(subdent)) { |
1089 |
rc = vfs_getattr(submnt, subdent, stat); |
1090 |
stat->dev = sb->s_dev; |
1091 |
} else { |
1092 |
subfs_lock(sb); |
1093 |
generic_fillattr(dentry->d_inode, stat); |
1094 |
subfs_unlock(sb); |
1095 |
rc = 0; |
1096 |
} |
1097 |
|
1098 |
if (subdent && !IS_ERR(subdent)) |
1099 |
dput(subdent); |
1100 |
if (submnt) |
1101 |
subfs_allow_umount(sb, submnt); |
1102 |
|
1103 |
LEAVE(sb, "dentry=%s rc=%d", dentry->d_name.name, rc); |
1104 |
|
1105 |
return rc; |
1106 |
} |
1107 |
|
1108 |
/* |
1109 |
* directories can handle most operations... supermount/namei.c just |
1110 |
* passes them through to the underlying subfs, except for lookup(). |
1111 |
*/ |
1112 |
|
1113 |
/* truncate: is not necesary, handled with setattr |
1114 |
* revalidate: only needed by nfs |
1115 |
* ->getattr: FIXME is not appeared to be used anywhere in kernel; so I am |
1116 |
* not sure how to implement it or what to return |
1117 |
* FIXME: implement accl functions |
1118 |
*/ |
1119 |
|
1120 |
struct inode_operations supermount_dir_iops = { |
1121 |
.create = supermount_create, |
1122 |
.lookup = supermount_lookup, |
1123 |
.link = supermount_link, |
1124 |
.unlink = supermount_unlink, |
1125 |
.symlink = supermount_symlink, |
1126 |
.mkdir = supermount_mkdir, |
1127 |
.rmdir = supermount_rmdir, |
1128 |
.mknod = supermount_mknod, |
1129 |
.rename = supermount_rename, |
1130 |
.permission = supermount_permission, |
1131 |
.setattr = supermount_setattr, |
1132 |
.getattr = supermount_getattr, |
1133 |
}; |
1134 |
|
1135 |
struct inode_operations supermount_symlink_iops = { |
1136 |
.readlink = supermount_readlink, |
1137 |
.follow_link = supermount_follow_link, |
1138 |
.setattr = supermount_setattr, |
1139 |
.getattr = supermount_getattr, |
1140 |
}; |
1141 |
|
1142 |
struct inode_operations supermount_file_iops = { |
1143 |
.setattr = supermount_setattr, |
1144 |
.getattr = supermount_getattr, |
1145 |
}; |