diff options
| -rw-r--r-- | fs/fat/namei_vfat.c | 124 |
1 files changed, 80 insertions, 44 deletions
diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c index 419deabfb9b..d585398f9f6 100644 --- a/fs/fat/namei_vfat.c +++ b/fs/fat/namei_vfat.c | |||
| @@ -24,27 +24,67 @@ | |||
| 24 | #include <linux/namei.h> | 24 | #include <linux/namei.h> |
| 25 | #include "fat.h" | 25 | #include "fat.h" |
| 26 | 26 | ||
| 27 | static int vfat_revalidate(struct dentry *dentry, struct nameidata *nd) | 27 | /* |
| 28 | * If new entry was created in the parent, it could create the 8.3 | ||
| 29 | * alias (the shortname of logname). So, the parent may have the | ||
| 30 | * negative-dentry which matches the created 8.3 alias. | ||
| 31 | * | ||
| 32 | * If it happened, the negative dentry isn't actually negative | ||
| 33 | * anymore. So, drop it. | ||
| 34 | */ | ||
| 35 | static int vfat_revalidate_shortname(struct dentry *dentry) | ||
| 28 | { | 36 | { |
| 29 | int ret = 1; | 37 | int ret = 1; |
| 30 | 38 | spin_lock(&dentry->d_lock); | |
| 31 | if (!dentry->d_inode && | 39 | if (dentry->d_time != dentry->d_parent->d_inode->i_version) |
| 32 | nd && !(nd->flags & LOOKUP_CONTINUE) && (nd->flags & LOOKUP_CREATE)) | ||
| 33 | /* | ||
| 34 | * negative dentry is dropped, in order to make sure | ||
| 35 | * to use the name which a user desires if this is | ||
| 36 | * create path. | ||
| 37 | */ | ||
| 38 | ret = 0; | 40 | ret = 0; |
| 39 | else { | 41 | spin_unlock(&dentry->d_lock); |
| 40 | spin_lock(&dentry->d_lock); | ||
| 41 | if (dentry->d_time != dentry->d_parent->d_inode->i_version) | ||
| 42 | ret = 0; | ||
| 43 | spin_unlock(&dentry->d_lock); | ||
| 44 | } | ||
| 45 | return ret; | 42 | return ret; |
| 46 | } | 43 | } |
| 47 | 44 | ||
| 45 | static int vfat_revalidate(struct dentry *dentry, struct nameidata *nd) | ||
| 46 | { | ||
| 47 | /* This is not negative dentry. Always valid. */ | ||
| 48 | if (dentry->d_inode) | ||
| 49 | return 1; | ||
| 50 | return vfat_revalidate_shortname(dentry); | ||
| 51 | } | ||
| 52 | |||
| 53 | static int vfat_revalidate_ci(struct dentry *dentry, struct nameidata *nd) | ||
| 54 | { | ||
| 55 | /* | ||
| 56 | * This is not negative dentry. Always valid. | ||
| 57 | * | ||
| 58 | * Note, rename() to existing directory entry will have ->d_inode, | ||
| 59 | * and will use existing name which isn't specified name by user. | ||
| 60 | * | ||
| 61 | * We may be able to drop this positive dentry here. But dropping | ||
| 62 | * positive dentry isn't good idea. So it's unsupported like | ||
| 63 | * rename("filename", "FILENAME") for now. | ||
| 64 | */ | ||
| 65 | if (dentry->d_inode) | ||
| 66 | return 1; | ||
| 67 | |||
| 68 | /* | ||
| 69 | * This may be nfsd (or something), anyway, we can't see the | ||
| 70 | * intent of this. So, since this can be for creation, drop it. | ||
| 71 | */ | ||
| 72 | if (!nd) | ||
| 73 | return 0; | ||
| 74 | |||
| 75 | /* | ||
| 76 | * Drop the negative dentry, in order to make sure to use the | ||
| 77 | * case sensitive name which is specified by user if this is | ||
| 78 | * for creation. | ||
| 79 | */ | ||
| 80 | if (!(nd->flags & (LOOKUP_CONTINUE | LOOKUP_PARENT))) { | ||
| 81 | if (nd->flags & LOOKUP_CREATE) | ||
| 82 | return 0; | ||
| 83 | } | ||
| 84 | |||
| 85 | return vfat_revalidate_shortname(dentry); | ||
| 86 | } | ||
| 87 | |||
| 48 | /* returns the length of a struct qstr, ignoring trailing dots */ | 88 | /* returns the length of a struct qstr, ignoring trailing dots */ |
| 49 | static unsigned int vfat_striptail_len(struct qstr *qstr) | 89 | static unsigned int vfat_striptail_len(struct qstr *qstr) |
| 50 | { | 90 | { |
| @@ -126,25 +166,16 @@ static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b) | |||
| 126 | return 1; | 166 | return 1; |
| 127 | } | 167 | } |
| 128 | 168 | ||
| 129 | static struct dentry_operations vfat_dentry_ops[4] = { | 169 | static struct dentry_operations vfat_ci_dentry_ops = { |
| 130 | { | 170 | .d_revalidate = vfat_revalidate_ci, |
| 131 | .d_hash = vfat_hashi, | 171 | .d_hash = vfat_hashi, |
| 132 | .d_compare = vfat_cmpi, | 172 | .d_compare = vfat_cmpi, |
| 133 | }, | 173 | }; |
| 134 | { | 174 | |
| 135 | .d_revalidate = vfat_revalidate, | 175 | static struct dentry_operations vfat_dentry_ops = { |
| 136 | .d_hash = vfat_hashi, | 176 | .d_revalidate = vfat_revalidate, |
| 137 | .d_compare = vfat_cmpi, | 177 | .d_hash = vfat_hash, |
| 138 | }, | 178 | .d_compare = vfat_cmp, |
| 139 | { | ||
| 140 | .d_hash = vfat_hash, | ||
| 141 | .d_compare = vfat_cmp, | ||
| 142 | }, | ||
| 143 | { | ||
| 144 | .d_revalidate = vfat_revalidate, | ||
| 145 | .d_hash = vfat_hash, | ||
| 146 | .d_compare = vfat_cmp, | ||
| 147 | } | ||
| 148 | }; | 179 | }; |
| 149 | 180 | ||
| 150 | /* Characters that are undesirable in an MS-DOS file name */ | 181 | /* Characters that are undesirable in an MS-DOS file name */ |
| @@ -685,29 +716,35 @@ static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry, | |||
| 685 | struct fat_slot_info sinfo; | 716 | struct fat_slot_info sinfo; |
| 686 | struct inode *inode; | 717 | struct inode *inode; |
| 687 | struct dentry *alias; | 718 | struct dentry *alias; |
| 688 | int err, table; | 719 | int err; |
| 689 | 720 | ||
| 690 | lock_super(sb); | 721 | lock_super(sb); |
| 691 | table = (MSDOS_SB(sb)->options.name_check == 's') ? 2 : 0; | ||
| 692 | dentry->d_op = &vfat_dentry_ops[table]; | ||
| 693 | 722 | ||
| 694 | err = vfat_find(dir, &dentry->d_name, &sinfo); | 723 | err = vfat_find(dir, &dentry->d_name, &sinfo); |
| 695 | if (err) { | 724 | if (err) { |
| 696 | if (err == -ENOENT) { | 725 | if (err == -ENOENT) { |
| 697 | table++; | ||
| 698 | inode = NULL; | 726 | inode = NULL; |
| 699 | goto out; | 727 | goto out; |
| 700 | } | 728 | } |
| 701 | goto error; | 729 | goto error; |
| 702 | } | 730 | } |
| 731 | |||
| 703 | inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos); | 732 | inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos); |
| 704 | brelse(sinfo.bh); | 733 | brelse(sinfo.bh); |
| 705 | if (IS_ERR(inode)) { | 734 | if (IS_ERR(inode)) { |
| 706 | err = PTR_ERR(inode); | 735 | err = PTR_ERR(inode); |
| 707 | goto error; | 736 | goto error; |
| 708 | } | 737 | } |
| 738 | |||
| 709 | alias = d_find_alias(inode); | 739 | alias = d_find_alias(inode); |
| 710 | if (alias) { | 740 | if (alias && !(alias->d_flags & DCACHE_DISCONNECTED)) { |
| 741 | /* | ||
| 742 | * This inode has non DCACHE_DISCONNECTED dentry. This | ||
| 743 | * means, the user did ->lookup() by an another name | ||
| 744 | * (longname vs 8.3 alias of it) in past. | ||
| 745 | * | ||
| 746 | * Switch to new one for reason of locality if possible. | ||
| 747 | */ | ||
| 711 | if (d_invalidate(alias) == 0) | 748 | if (d_invalidate(alias) == 0) |
| 712 | dput(alias); | 749 | dput(alias); |
| 713 | else { | 750 | else { |
| @@ -715,15 +752,14 @@ static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry, | |||
| 715 | unlock_super(sb); | 752 | unlock_super(sb); |
| 716 | return alias; | 753 | return alias; |
| 717 | } | 754 | } |
| 718 | |||
| 719 | } | 755 | } |
| 720 | out: | 756 | out: |
| 721 | unlock_super(sb); | 757 | unlock_super(sb); |
| 722 | dentry->d_op = &vfat_dentry_ops[table]; | 758 | dentry->d_op = sb->s_root->d_op; |
| 723 | dentry->d_time = dentry->d_parent->d_inode->i_version; | 759 | dentry->d_time = dentry->d_parent->d_inode->i_version; |
| 724 | dentry = d_splice_alias(inode, dentry); | 760 | dentry = d_splice_alias(inode, dentry); |
| 725 | if (dentry) { | 761 | if (dentry) { |
| 726 | dentry->d_op = &vfat_dentry_ops[table]; | 762 | dentry->d_op = sb->s_root->d_op; |
| 727 | dentry->d_time = dentry->d_parent->d_inode->i_version; | 763 | dentry->d_time = dentry->d_parent->d_inode->i_version; |
| 728 | } | 764 | } |
| 729 | return dentry; | 765 | return dentry; |
| @@ -1022,9 +1058,9 @@ static int vfat_fill_super(struct super_block *sb, void *data, int silent) | |||
| 1022 | return res; | 1058 | return res; |
| 1023 | 1059 | ||
| 1024 | if (MSDOS_SB(sb)->options.name_check != 's') | 1060 | if (MSDOS_SB(sb)->options.name_check != 's') |
| 1025 | sb->s_root->d_op = &vfat_dentry_ops[0]; | 1061 | sb->s_root->d_op = &vfat_ci_dentry_ops; |
| 1026 | else | 1062 | else |
| 1027 | sb->s_root->d_op = &vfat_dentry_ops[2]; | 1063 | sb->s_root->d_op = &vfat_dentry_ops; |
| 1028 | 1064 | ||
| 1029 | return 0; | 1065 | return 0; |
| 1030 | } | 1066 | } |
