diff options
Diffstat (limited to 'fs/namei.c')
| -rw-r--r-- | fs/namei.c | 142 |
1 files changed, 85 insertions, 57 deletions
diff --git a/fs/namei.c b/fs/namei.c index 432d6bc6fab0..2892e68d3a86 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -372,6 +372,30 @@ void release_open_intent(struct nameidata *nd) | |||
| 372 | fput(nd->intent.open.file); | 372 | fput(nd->intent.open.file); |
| 373 | } | 373 | } |
| 374 | 374 | ||
| 375 | static inline struct dentry * | ||
| 376 | do_revalidate(struct dentry *dentry, struct nameidata *nd) | ||
| 377 | { | ||
| 378 | int status = dentry->d_op->d_revalidate(dentry, nd); | ||
| 379 | if (unlikely(status <= 0)) { | ||
| 380 | /* | ||
| 381 | * The dentry failed validation. | ||
| 382 | * If d_revalidate returned 0 attempt to invalidate | ||
| 383 | * the dentry otherwise d_revalidate is asking us | ||
| 384 | * to return a fail status. | ||
| 385 | */ | ||
| 386 | if (!status) { | ||
| 387 | if (!d_invalidate(dentry)) { | ||
| 388 | dput(dentry); | ||
| 389 | dentry = NULL; | ||
| 390 | } | ||
| 391 | } else { | ||
| 392 | dput(dentry); | ||
| 393 | dentry = ERR_PTR(status); | ||
| 394 | } | ||
| 395 | } | ||
| 396 | return dentry; | ||
| 397 | } | ||
| 398 | |||
| 375 | /* | 399 | /* |
| 376 | * Internal lookup() using the new generic dcache. | 400 | * Internal lookup() using the new generic dcache. |
| 377 | * SMP-safe | 401 | * SMP-safe |
| @@ -386,12 +410,9 @@ static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name, | |||
| 386 | if (!dentry) | 410 | if (!dentry) |
| 387 | dentry = d_lookup(parent, name); | 411 | dentry = d_lookup(parent, name); |
| 388 | 412 | ||
| 389 | if (dentry && dentry->d_op && dentry->d_op->d_revalidate) { | 413 | if (dentry && dentry->d_op && dentry->d_op->d_revalidate) |
| 390 | if (!dentry->d_op->d_revalidate(dentry, nd) && !d_invalidate(dentry)) { | 414 | dentry = do_revalidate(dentry, nd); |
| 391 | dput(dentry); | 415 | |
| 392 | dentry = NULL; | ||
| 393 | } | ||
| 394 | } | ||
| 395 | return dentry; | 416 | return dentry; |
| 396 | } | 417 | } |
| 397 | 418 | ||
| @@ -484,10 +505,9 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, s | |||
| 484 | */ | 505 | */ |
| 485 | mutex_unlock(&dir->i_mutex); | 506 | mutex_unlock(&dir->i_mutex); |
| 486 | if (result->d_op && result->d_op->d_revalidate) { | 507 | if (result->d_op && result->d_op->d_revalidate) { |
| 487 | if (!result->d_op->d_revalidate(result, nd) && !d_invalidate(result)) { | 508 | result = do_revalidate(result, nd); |
| 488 | dput(result); | 509 | if (!result) |
| 489 | result = ERR_PTR(-ENOENT); | 510 | result = ERR_PTR(-ENOENT); |
| 490 | } | ||
| 491 | } | 511 | } |
| 492 | return result; | 512 | return result; |
| 493 | } | 513 | } |
| @@ -498,18 +518,20 @@ static int __emul_lookup_dentry(const char *, struct nameidata *); | |||
| 498 | static __always_inline int | 518 | static __always_inline int |
| 499 | walk_init_root(const char *name, struct nameidata *nd) | 519 | walk_init_root(const char *name, struct nameidata *nd) |
| 500 | { | 520 | { |
| 501 | read_lock(¤t->fs->lock); | 521 | struct fs_struct *fs = current->fs; |
| 502 | if (current->fs->altroot && !(nd->flags & LOOKUP_NOALT)) { | 522 | |
| 503 | nd->mnt = mntget(current->fs->altrootmnt); | 523 | read_lock(&fs->lock); |
| 504 | nd->dentry = dget(current->fs->altroot); | 524 | if (fs->altroot && !(nd->flags & LOOKUP_NOALT)) { |
| 505 | read_unlock(¤t->fs->lock); | 525 | nd->mnt = mntget(fs->altrootmnt); |
| 526 | nd->dentry = dget(fs->altroot); | ||
| 527 | read_unlock(&fs->lock); | ||
| 506 | if (__emul_lookup_dentry(name,nd)) | 528 | if (__emul_lookup_dentry(name,nd)) |
| 507 | return 0; | 529 | return 0; |
| 508 | read_lock(¤t->fs->lock); | 530 | read_lock(&fs->lock); |
| 509 | } | 531 | } |
| 510 | nd->mnt = mntget(current->fs->rootmnt); | 532 | nd->mnt = mntget(fs->rootmnt); |
| 511 | nd->dentry = dget(current->fs->root); | 533 | nd->dentry = dget(fs->root); |
| 512 | read_unlock(¤t->fs->lock); | 534 | read_unlock(&fs->lock); |
| 513 | return 1; | 535 | return 1; |
| 514 | } | 536 | } |
| 515 | 537 | ||
| @@ -704,17 +726,19 @@ int follow_down(struct vfsmount **mnt, struct dentry **dentry) | |||
| 704 | 726 | ||
| 705 | static __always_inline void follow_dotdot(struct nameidata *nd) | 727 | static __always_inline void follow_dotdot(struct nameidata *nd) |
| 706 | { | 728 | { |
| 729 | struct fs_struct *fs = current->fs; | ||
| 730 | |||
| 707 | while(1) { | 731 | while(1) { |
| 708 | struct vfsmount *parent; | 732 | struct vfsmount *parent; |
| 709 | struct dentry *old = nd->dentry; | 733 | struct dentry *old = nd->dentry; |
| 710 | 734 | ||
| 711 | read_lock(¤t->fs->lock); | 735 | read_lock(&fs->lock); |
| 712 | if (nd->dentry == current->fs->root && | 736 | if (nd->dentry == fs->root && |
| 713 | nd->mnt == current->fs->rootmnt) { | 737 | nd->mnt == fs->rootmnt) { |
| 714 | read_unlock(¤t->fs->lock); | 738 | read_unlock(&fs->lock); |
| 715 | break; | 739 | break; |
| 716 | } | 740 | } |
| 717 | read_unlock(¤t->fs->lock); | 741 | read_unlock(&fs->lock); |
| 718 | spin_lock(&dcache_lock); | 742 | spin_lock(&dcache_lock); |
| 719 | if (nd->dentry != nd->mnt->mnt_root) { | 743 | if (nd->dentry != nd->mnt->mnt_root) { |
| 720 | nd->dentry = dget(nd->dentry->d_parent); | 744 | nd->dentry = dget(nd->dentry->d_parent); |
| @@ -767,12 +791,12 @@ need_lookup: | |||
| 767 | goto done; | 791 | goto done; |
| 768 | 792 | ||
| 769 | need_revalidate: | 793 | need_revalidate: |
| 770 | if (dentry->d_op->d_revalidate(dentry, nd)) | 794 | dentry = do_revalidate(dentry, nd); |
| 771 | goto done; | 795 | if (!dentry) |
| 772 | if (d_invalidate(dentry)) | 796 | goto need_lookup; |
| 773 | goto done; | 797 | if (IS_ERR(dentry)) |
| 774 | dput(dentry); | 798 | goto fail; |
| 775 | goto need_lookup; | 799 | goto done; |
| 776 | 800 | ||
| 777 | fail: | 801 | fail: |
| 778 | return PTR_ERR(dentry); | 802 | return PTR_ERR(dentry); |
| @@ -1022,15 +1046,17 @@ static int __emul_lookup_dentry(const char *name, struct nameidata *nd) | |||
| 1022 | struct vfsmount *old_mnt = nd->mnt; | 1046 | struct vfsmount *old_mnt = nd->mnt; |
| 1023 | struct qstr last = nd->last; | 1047 | struct qstr last = nd->last; |
| 1024 | int last_type = nd->last_type; | 1048 | int last_type = nd->last_type; |
| 1049 | struct fs_struct *fs = current->fs; | ||
| 1050 | |||
| 1025 | /* | 1051 | /* |
| 1026 | * NAME was not found in alternate root or it's a directory. Try to find | 1052 | * NAME was not found in alternate root or it's a directory. |
| 1027 | * it in the normal root: | 1053 | * Try to find it in the normal root: |
| 1028 | */ | 1054 | */ |
| 1029 | nd->last_type = LAST_ROOT; | 1055 | nd->last_type = LAST_ROOT; |
| 1030 | read_lock(¤t->fs->lock); | 1056 | read_lock(&fs->lock); |
| 1031 | nd->mnt = mntget(current->fs->rootmnt); | 1057 | nd->mnt = mntget(fs->rootmnt); |
| 1032 | nd->dentry = dget(current->fs->root); | 1058 | nd->dentry = dget(fs->root); |
| 1033 | read_unlock(¤t->fs->lock); | 1059 | read_unlock(&fs->lock); |
| 1034 | if (path_walk(name, nd) == 0) { | 1060 | if (path_walk(name, nd) == 0) { |
| 1035 | if (nd->dentry->d_inode) { | 1061 | if (nd->dentry->d_inode) { |
| 1036 | dput(old_dentry); | 1062 | dput(old_dentry); |
| @@ -1054,6 +1080,7 @@ void set_fs_altroot(void) | |||
| 1054 | struct vfsmount *mnt = NULL, *oldmnt; | 1080 | struct vfsmount *mnt = NULL, *oldmnt; |
| 1055 | struct dentry *dentry = NULL, *olddentry; | 1081 | struct dentry *dentry = NULL, *olddentry; |
| 1056 | int err; | 1082 | int err; |
| 1083 | struct fs_struct *fs = current->fs; | ||
| 1057 | 1084 | ||
| 1058 | if (!emul) | 1085 | if (!emul) |
| 1059 | goto set_it; | 1086 | goto set_it; |
| @@ -1063,12 +1090,12 @@ void set_fs_altroot(void) | |||
| 1063 | dentry = nd.dentry; | 1090 | dentry = nd.dentry; |
| 1064 | } | 1091 | } |
| 1065 | set_it: | 1092 | set_it: |
| 1066 | write_lock(¤t->fs->lock); | 1093 | write_lock(&fs->lock); |
| 1067 | oldmnt = current->fs->altrootmnt; | 1094 | oldmnt = fs->altrootmnt; |
| 1068 | olddentry = current->fs->altroot; | 1095 | olddentry = fs->altroot; |
| 1069 | current->fs->altrootmnt = mnt; | 1096 | fs->altrootmnt = mnt; |
| 1070 | current->fs->altroot = dentry; | 1097 | fs->altroot = dentry; |
| 1071 | write_unlock(¤t->fs->lock); | 1098 | write_unlock(&fs->lock); |
| 1072 | if (olddentry) { | 1099 | if (olddentry) { |
| 1073 | dput(olddentry); | 1100 | dput(olddentry); |
| 1074 | mntput(oldmnt); | 1101 | mntput(oldmnt); |
| @@ -1082,29 +1109,30 @@ static int fastcall do_path_lookup(int dfd, const char *name, | |||
| 1082 | int retval = 0; | 1109 | int retval = 0; |
| 1083 | int fput_needed; | 1110 | int fput_needed; |
| 1084 | struct file *file; | 1111 | struct file *file; |
| 1112 | struct fs_struct *fs = current->fs; | ||
| 1085 | 1113 | ||
| 1086 | nd->last_type = LAST_ROOT; /* if there are only slashes... */ | 1114 | nd->last_type = LAST_ROOT; /* if there are only slashes... */ |
| 1087 | nd->flags = flags; | 1115 | nd->flags = flags; |
| 1088 | nd->depth = 0; | 1116 | nd->depth = 0; |
| 1089 | 1117 | ||
| 1090 | if (*name=='/') { | 1118 | if (*name=='/') { |
| 1091 | read_lock(¤t->fs->lock); | 1119 | read_lock(&fs->lock); |
| 1092 | if (current->fs->altroot && !(nd->flags & LOOKUP_NOALT)) { | 1120 | if (fs->altroot && !(nd->flags & LOOKUP_NOALT)) { |
| 1093 | nd->mnt = mntget(current->fs->altrootmnt); | 1121 | nd->mnt = mntget(fs->altrootmnt); |
| 1094 | nd->dentry = dget(current->fs->altroot); | 1122 | nd->dentry = dget(fs->altroot); |
| 1095 | read_unlock(¤t->fs->lock); | 1123 | read_unlock(&fs->lock); |
| 1096 | if (__emul_lookup_dentry(name,nd)) | 1124 | if (__emul_lookup_dentry(name,nd)) |
| 1097 | goto out; /* found in altroot */ | 1125 | goto out; /* found in altroot */ |
| 1098 | read_lock(¤t->fs->lock); | 1126 | read_lock(&fs->lock); |
| 1099 | } | 1127 | } |
| 1100 | nd->mnt = mntget(current->fs->rootmnt); | 1128 | nd->mnt = mntget(fs->rootmnt); |
| 1101 | nd->dentry = dget(current->fs->root); | 1129 | nd->dentry = dget(fs->root); |
| 1102 | read_unlock(¤t->fs->lock); | 1130 | read_unlock(&fs->lock); |
| 1103 | } else if (dfd == AT_FDCWD) { | 1131 | } else if (dfd == AT_FDCWD) { |
| 1104 | read_lock(¤t->fs->lock); | 1132 | read_lock(&fs->lock); |
| 1105 | nd->mnt = mntget(current->fs->pwdmnt); | 1133 | nd->mnt = mntget(fs->pwdmnt); |
| 1106 | nd->dentry = dget(current->fs->pwd); | 1134 | nd->dentry = dget(fs->pwd); |
| 1107 | read_unlock(¤t->fs->lock); | 1135 | read_unlock(&fs->lock); |
| 1108 | } else { | 1136 | } else { |
| 1109 | struct dentry *dentry; | 1137 | struct dentry *dentry; |
| 1110 | 1138 | ||
| @@ -2370,7 +2398,8 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry, | |||
| 2370 | dput(new_dentry); | 2398 | dput(new_dentry); |
| 2371 | } | 2399 | } |
| 2372 | if (!error) | 2400 | if (!error) |
| 2373 | d_move(old_dentry,new_dentry); | 2401 | if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE)) |
| 2402 | d_move(old_dentry,new_dentry); | ||
| 2374 | return error; | 2403 | return error; |
| 2375 | } | 2404 | } |
| 2376 | 2405 | ||
| @@ -2393,8 +2422,7 @@ static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry, | |||
| 2393 | else | 2422 | else |
| 2394 | error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry); | 2423 | error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry); |
| 2395 | if (!error) { | 2424 | if (!error) { |
| 2396 | /* The following d_move() should become unconditional */ | 2425 | if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE)) |
| 2397 | if (!(old_dir->i_sb->s_type->fs_flags & FS_ODD_RENAME)) | ||
| 2398 | d_move(old_dentry, new_dentry); | 2426 | d_move(old_dentry, new_dentry); |
| 2399 | } | 2427 | } |
| 2400 | if (target) | 2428 | if (target) |
