|
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 |
}; |