diff options
Diffstat (limited to 'fs/fat')
-rw-r--r-- | fs/fat/inode.c | 13 | ||||
-rw-r--r-- | fs/fat/namei_msdos.c | 23 | ||||
-rw-r--r-- | fs/fat/namei_vfat.c | 55 |
3 files changed, 58 insertions, 33 deletions
diff --git a/fs/fat/inode.c b/fs/fat/inode.c index ad6998a92c30..206351af7c58 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c | |||
@@ -514,11 +514,18 @@ static struct inode *fat_alloc_inode(struct super_block *sb) | |||
514 | return &ei->vfs_inode; | 514 | return &ei->vfs_inode; |
515 | } | 515 | } |
516 | 516 | ||
517 | static void fat_destroy_inode(struct inode *inode) | 517 | static void fat_i_callback(struct rcu_head *head) |
518 | { | 518 | { |
519 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
520 | INIT_LIST_HEAD(&inode->i_dentry); | ||
519 | kmem_cache_free(fat_inode_cachep, MSDOS_I(inode)); | 521 | kmem_cache_free(fat_inode_cachep, MSDOS_I(inode)); |
520 | } | 522 | } |
521 | 523 | ||
524 | static void fat_destroy_inode(struct inode *inode) | ||
525 | { | ||
526 | call_rcu(&inode->i_rcu, fat_i_callback); | ||
527 | } | ||
528 | |||
522 | static void init_once(void *foo) | 529 | static void init_once(void *foo) |
523 | { | 530 | { |
524 | struct msdos_inode_info *ei = (struct msdos_inode_info *)foo; | 531 | struct msdos_inode_info *ei = (struct msdos_inode_info *)foo; |
@@ -743,7 +750,7 @@ static struct dentry *fat_fh_to_dentry(struct super_block *sb, | |||
743 | */ | 750 | */ |
744 | result = d_obtain_alias(inode); | 751 | result = d_obtain_alias(inode); |
745 | if (!IS_ERR(result)) | 752 | if (!IS_ERR(result)) |
746 | result->d_op = sb->s_root->d_op; | 753 | d_set_d_op(result, sb->s_root->d_op); |
747 | return result; | 754 | return result; |
748 | } | 755 | } |
749 | 756 | ||
@@ -793,7 +800,7 @@ static struct dentry *fat_get_parent(struct dentry *child) | |||
793 | 800 | ||
794 | parent = d_obtain_alias(inode); | 801 | parent = d_obtain_alias(inode); |
795 | if (!IS_ERR(parent)) | 802 | if (!IS_ERR(parent)) |
796 | parent->d_op = sb->s_root->d_op; | 803 | d_set_d_op(parent, sb->s_root->d_op); |
797 | out: | 804 | out: |
798 | unlock_super(sb); | 805 | unlock_super(sb); |
799 | 806 | ||
diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c index 3345aabd1dd7..35ffe43afa4b 100644 --- a/fs/fat/namei_msdos.c +++ b/fs/fat/namei_msdos.c | |||
@@ -148,7 +148,8 @@ static int msdos_find(struct inode *dir, const unsigned char *name, int len, | |||
148 | * that the existing dentry can be used. The msdos fs routines will | 148 | * that the existing dentry can be used. The msdos fs routines will |
149 | * return ENOENT or EINVAL as appropriate. | 149 | * return ENOENT or EINVAL as appropriate. |
150 | */ | 150 | */ |
151 | static int msdos_hash(struct dentry *dentry, struct qstr *qstr) | 151 | static int msdos_hash(const struct dentry *dentry, const struct inode *inode, |
152 | struct qstr *qstr) | ||
152 | { | 153 | { |
153 | struct fat_mount_options *options = &MSDOS_SB(dentry->d_sb)->options; | 154 | struct fat_mount_options *options = &MSDOS_SB(dentry->d_sb)->options; |
154 | unsigned char msdos_name[MSDOS_NAME]; | 155 | unsigned char msdos_name[MSDOS_NAME]; |
@@ -164,16 +165,18 @@ static int msdos_hash(struct dentry *dentry, struct qstr *qstr) | |||
164 | * Compare two msdos names. If either of the names are invalid, | 165 | * Compare two msdos names. If either of the names are invalid, |
165 | * we fall back to doing the standard name comparison. | 166 | * we fall back to doing the standard name comparison. |
166 | */ | 167 | */ |
167 | static int msdos_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b) | 168 | static int msdos_cmp(const struct dentry *parent, const struct inode *pinode, |
169 | const struct dentry *dentry, const struct inode *inode, | ||
170 | unsigned int len, const char *str, const struct qstr *name) | ||
168 | { | 171 | { |
169 | struct fat_mount_options *options = &MSDOS_SB(dentry->d_sb)->options; | 172 | struct fat_mount_options *options = &MSDOS_SB(parent->d_sb)->options; |
170 | unsigned char a_msdos_name[MSDOS_NAME], b_msdos_name[MSDOS_NAME]; | 173 | unsigned char a_msdos_name[MSDOS_NAME], b_msdos_name[MSDOS_NAME]; |
171 | int error; | 174 | int error; |
172 | 175 | ||
173 | error = msdos_format_name(a->name, a->len, a_msdos_name, options); | 176 | error = msdos_format_name(name->name, name->len, a_msdos_name, options); |
174 | if (error) | 177 | if (error) |
175 | goto old_compare; | 178 | goto old_compare; |
176 | error = msdos_format_name(b->name, b->len, b_msdos_name, options); | 179 | error = msdos_format_name(str, len, b_msdos_name, options); |
177 | if (error) | 180 | if (error) |
178 | goto old_compare; | 181 | goto old_compare; |
179 | error = memcmp(a_msdos_name, b_msdos_name, MSDOS_NAME); | 182 | error = memcmp(a_msdos_name, b_msdos_name, MSDOS_NAME); |
@@ -182,8 +185,8 @@ out: | |||
182 | 185 | ||
183 | old_compare: | 186 | old_compare: |
184 | error = 1; | 187 | error = 1; |
185 | if (a->len == b->len) | 188 | if (name->len == len) |
186 | error = memcmp(a->name, b->name, a->len); | 189 | error = memcmp(name->name, str, len); |
187 | goto out; | 190 | goto out; |
188 | } | 191 | } |
189 | 192 | ||
@@ -224,10 +227,10 @@ static struct dentry *msdos_lookup(struct inode *dir, struct dentry *dentry, | |||
224 | } | 227 | } |
225 | out: | 228 | out: |
226 | unlock_super(sb); | 229 | unlock_super(sb); |
227 | dentry->d_op = &msdos_dentry_operations; | 230 | d_set_d_op(dentry, &msdos_dentry_operations); |
228 | dentry = d_splice_alias(inode, dentry); | 231 | dentry = d_splice_alias(inode, dentry); |
229 | if (dentry) | 232 | if (dentry) |
230 | dentry->d_op = &msdos_dentry_operations; | 233 | d_set_d_op(dentry, &msdos_dentry_operations); |
231 | return dentry; | 234 | return dentry; |
232 | 235 | ||
233 | error: | 236 | error: |
@@ -670,7 +673,7 @@ static int msdos_fill_super(struct super_block *sb, void *data, int silent) | |||
670 | } | 673 | } |
671 | 674 | ||
672 | sb->s_flags |= MS_NOATIME; | 675 | sb->s_flags |= MS_NOATIME; |
673 | sb->s_root->d_op = &msdos_dentry_operations; | 676 | d_set_d_op(sb->s_root, &msdos_dentry_operations); |
674 | unlock_super(sb); | 677 | unlock_super(sb); |
675 | return 0; | 678 | return 0; |
676 | } | 679 | } |
diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c index b936703b8924..e3ffc5e12332 100644 --- a/fs/fat/namei_vfat.c +++ b/fs/fat/namei_vfat.c | |||
@@ -43,6 +43,9 @@ static int vfat_revalidate_shortname(struct dentry *dentry) | |||
43 | 43 | ||
44 | static int vfat_revalidate(struct dentry *dentry, struct nameidata *nd) | 44 | static int vfat_revalidate(struct dentry *dentry, struct nameidata *nd) |
45 | { | 45 | { |
46 | if (nd->flags & LOOKUP_RCU) | ||
47 | return -ECHILD; | ||
48 | |||
46 | /* This is not negative dentry. Always valid. */ | 49 | /* This is not negative dentry. Always valid. */ |
47 | if (dentry->d_inode) | 50 | if (dentry->d_inode) |
48 | return 1; | 51 | return 1; |
@@ -51,6 +54,9 @@ static int vfat_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
51 | 54 | ||
52 | static int vfat_revalidate_ci(struct dentry *dentry, struct nameidata *nd) | 55 | static int vfat_revalidate_ci(struct dentry *dentry, struct nameidata *nd) |
53 | { | 56 | { |
57 | if (nd->flags & LOOKUP_RCU) | ||
58 | return -ECHILD; | ||
59 | |||
54 | /* | 60 | /* |
55 | * This is not negative dentry. Always valid. | 61 | * This is not negative dentry. Always valid. |
56 | * | 62 | * |
@@ -85,22 +91,26 @@ static int vfat_revalidate_ci(struct dentry *dentry, struct nameidata *nd) | |||
85 | } | 91 | } |
86 | 92 | ||
87 | /* returns the length of a struct qstr, ignoring trailing dots */ | 93 | /* returns the length of a struct qstr, ignoring trailing dots */ |
88 | static unsigned int vfat_striptail_len(struct qstr *qstr) | 94 | static unsigned int __vfat_striptail_len(unsigned int len, const char *name) |
89 | { | 95 | { |
90 | unsigned int len = qstr->len; | 96 | while (len && name[len - 1] == '.') |
91 | |||
92 | while (len && qstr->name[len - 1] == '.') | ||
93 | len--; | 97 | len--; |
94 | return len; | 98 | return len; |
95 | } | 99 | } |
96 | 100 | ||
101 | static unsigned int vfat_striptail_len(const struct qstr *qstr) | ||
102 | { | ||
103 | return __vfat_striptail_len(qstr->len, qstr->name); | ||
104 | } | ||
105 | |||
97 | /* | 106 | /* |
98 | * Compute the hash for the vfat name corresponding to the dentry. | 107 | * Compute the hash for the vfat name corresponding to the dentry. |
99 | * Note: if the name is invalid, we leave the hash code unchanged so | 108 | * Note: if the name is invalid, we leave the hash code unchanged so |
100 | * that the existing dentry can be used. The vfat fs routines will | 109 | * that the existing dentry can be used. The vfat fs routines will |
101 | * return ENOENT or EINVAL as appropriate. | 110 | * return ENOENT or EINVAL as appropriate. |
102 | */ | 111 | */ |
103 | static int vfat_hash(struct dentry *dentry, struct qstr *qstr) | 112 | static int vfat_hash(const struct dentry *dentry, const struct inode *inode, |
113 | struct qstr *qstr) | ||
104 | { | 114 | { |
105 | qstr->hash = full_name_hash(qstr->name, vfat_striptail_len(qstr)); | 115 | qstr->hash = full_name_hash(qstr->name, vfat_striptail_len(qstr)); |
106 | return 0; | 116 | return 0; |
@@ -112,9 +122,10 @@ static int vfat_hash(struct dentry *dentry, struct qstr *qstr) | |||
112 | * that the existing dentry can be used. The vfat fs routines will | 122 | * that the existing dentry can be used. The vfat fs routines will |
113 | * return ENOENT or EINVAL as appropriate. | 123 | * return ENOENT or EINVAL as appropriate. |
114 | */ | 124 | */ |
115 | static int vfat_hashi(struct dentry *dentry, struct qstr *qstr) | 125 | static int vfat_hashi(const struct dentry *dentry, const struct inode *inode, |
126 | struct qstr *qstr) | ||
116 | { | 127 | { |
117 | struct nls_table *t = MSDOS_SB(dentry->d_inode->i_sb)->nls_io; | 128 | struct nls_table *t = MSDOS_SB(dentry->d_sb)->nls_io; |
118 | const unsigned char *name; | 129 | const unsigned char *name; |
119 | unsigned int len; | 130 | unsigned int len; |
120 | unsigned long hash; | 131 | unsigned long hash; |
@@ -133,16 +144,18 @@ static int vfat_hashi(struct dentry *dentry, struct qstr *qstr) | |||
133 | /* | 144 | /* |
134 | * Case insensitive compare of two vfat names. | 145 | * Case insensitive compare of two vfat names. |
135 | */ | 146 | */ |
136 | static int vfat_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b) | 147 | static int vfat_cmpi(const struct dentry *parent, const struct inode *pinode, |
148 | const struct dentry *dentry, const struct inode *inode, | ||
149 | unsigned int len, const char *str, const struct qstr *name) | ||
137 | { | 150 | { |
138 | struct nls_table *t = MSDOS_SB(dentry->d_inode->i_sb)->nls_io; | 151 | struct nls_table *t = MSDOS_SB(parent->d_sb)->nls_io; |
139 | unsigned int alen, blen; | 152 | unsigned int alen, blen; |
140 | 153 | ||
141 | /* A filename cannot end in '.' or we treat it like it has none */ | 154 | /* A filename cannot end in '.' or we treat it like it has none */ |
142 | alen = vfat_striptail_len(a); | 155 | alen = vfat_striptail_len(name); |
143 | blen = vfat_striptail_len(b); | 156 | blen = __vfat_striptail_len(len, str); |
144 | if (alen == blen) { | 157 | if (alen == blen) { |
145 | if (nls_strnicmp(t, a->name, b->name, alen) == 0) | 158 | if (nls_strnicmp(t, name->name, str, alen) == 0) |
146 | return 0; | 159 | return 0; |
147 | } | 160 | } |
148 | return 1; | 161 | return 1; |
@@ -151,15 +164,17 @@ static int vfat_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b) | |||
151 | /* | 164 | /* |
152 | * Case sensitive compare of two vfat names. | 165 | * Case sensitive compare of two vfat names. |
153 | */ | 166 | */ |
154 | static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b) | 167 | static int vfat_cmp(const struct dentry *parent, const struct inode *pinode, |
168 | const struct dentry *dentry, const struct inode *inode, | ||
169 | unsigned int len, const char *str, const struct qstr *name) | ||
155 | { | 170 | { |
156 | unsigned int alen, blen; | 171 | unsigned int alen, blen; |
157 | 172 | ||
158 | /* A filename cannot end in '.' or we treat it like it has none */ | 173 | /* A filename cannot end in '.' or we treat it like it has none */ |
159 | alen = vfat_striptail_len(a); | 174 | alen = vfat_striptail_len(name); |
160 | blen = vfat_striptail_len(b); | 175 | blen = __vfat_striptail_len(len, str); |
161 | if (alen == blen) { | 176 | if (alen == blen) { |
162 | if (strncmp(a->name, b->name, alen) == 0) | 177 | if (strncmp(name->name, str, alen) == 0) |
163 | return 0; | 178 | return 0; |
164 | } | 179 | } |
165 | return 1; | 180 | return 1; |
@@ -757,11 +772,11 @@ static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry, | |||
757 | 772 | ||
758 | out: | 773 | out: |
759 | unlock_super(sb); | 774 | unlock_super(sb); |
760 | dentry->d_op = sb->s_root->d_op; | 775 | d_set_d_op(dentry, sb->s_root->d_op); |
761 | dentry->d_time = dentry->d_parent->d_inode->i_version; | 776 | dentry->d_time = dentry->d_parent->d_inode->i_version; |
762 | dentry = d_splice_alias(inode, dentry); | 777 | dentry = d_splice_alias(inode, dentry); |
763 | if (dentry) { | 778 | if (dentry) { |
764 | dentry->d_op = sb->s_root->d_op; | 779 | d_set_d_op(dentry, sb->s_root->d_op); |
765 | dentry->d_time = dentry->d_parent->d_inode->i_version; | 780 | dentry->d_time = dentry->d_parent->d_inode->i_version; |
766 | } | 781 | } |
767 | return dentry; | 782 | return dentry; |
@@ -1063,9 +1078,9 @@ static int vfat_fill_super(struct super_block *sb, void *data, int silent) | |||
1063 | } | 1078 | } |
1064 | 1079 | ||
1065 | if (MSDOS_SB(sb)->options.name_check != 's') | 1080 | if (MSDOS_SB(sb)->options.name_check != 's') |
1066 | sb->s_root->d_op = &vfat_ci_dentry_ops; | 1081 | d_set_d_op(sb->s_root, &vfat_ci_dentry_ops); |
1067 | else | 1082 | else |
1068 | sb->s_root->d_op = &vfat_dentry_ops; | 1083 | d_set_d_op(sb->s_root, &vfat_dentry_ops); |
1069 | 1084 | ||
1070 | unlock_super(sb); | 1085 | unlock_super(sb); |
1071 | return 0; | 1086 | return 0; |