diff options
| author | Nick Piggin <npiggin@kernel.dk> | 2011-01-07 01:49:27 -0500 |
|---|---|---|
| committer | Nick Piggin <npiggin@kernel.dk> | 2011-01-07 01:50:19 -0500 |
| commit | 621e155a3591962420eacdd39f6f0aa29ceb221e (patch) | |
| tree | 387a9fb396f1bf24514b712c294182e36ba51076 /fs/fat | |
| parent | fb2d5b86aff355a27ebfc132d3c99f4a940cc3fe (diff) | |
fs: change d_compare for rcu-walk
Change d_compare so it may be called from lock-free RCU lookups. This
does put significant restrictions on what may be done from the callback,
however there don't seem to have been any problems with in-tree fses.
If some strange use case pops up that _really_ cannot cope with the
rcu-walk rules, we can just add new rcu-unaware callbacks, which would
cause name lookup to drop out of rcu-walk mode.
For in-tree filesystems, this is just a mechanical change.
Signed-off-by: Nick Piggin <npiggin@kernel.dk>
Diffstat (limited to 'fs/fat')
| -rw-r--r-- | fs/fat/namei_msdos.c | 14 | ||||
| -rw-r--r-- | fs/fat/namei_vfat.c | 33 |
2 files changed, 28 insertions, 19 deletions
diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c index 3345aabd1dd7..99d3c7ac973c 100644 --- a/fs/fat/namei_msdos.c +++ b/fs/fat/namei_msdos.c | |||
| @@ -164,16 +164,18 @@ static int msdos_hash(struct dentry *dentry, struct qstr *qstr) | |||
| 164 | * Compare two msdos names. If either of the names are invalid, | 164 | * Compare two msdos names. If either of the names are invalid, |
| 165 | * we fall back to doing the standard name comparison. | 165 | * we fall back to doing the standard name comparison. |
| 166 | */ | 166 | */ |
| 167 | static int msdos_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b) | 167 | static int msdos_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) | ||
| 168 | { | 170 | { |
| 169 | struct fat_mount_options *options = &MSDOS_SB(dentry->d_sb)->options; | 171 | struct fat_mount_options *options = &MSDOS_SB(parent->d_sb)->options; |
| 170 | unsigned char a_msdos_name[MSDOS_NAME], b_msdos_name[MSDOS_NAME]; | 172 | unsigned char a_msdos_name[MSDOS_NAME], b_msdos_name[MSDOS_NAME]; |
| 171 | int error; | 173 | int error; |
| 172 | 174 | ||
| 173 | error = msdos_format_name(a->name, a->len, a_msdos_name, options); | 175 | error = msdos_format_name(name->name, name->len, a_msdos_name, options); |
| 174 | if (error) | 176 | if (error) |
| 175 | goto old_compare; | 177 | goto old_compare; |
| 176 | error = msdos_format_name(b->name, b->len, b_msdos_name, options); | 178 | error = msdos_format_name(str, len, b_msdos_name, options); |
| 177 | if (error) | 179 | if (error) |
| 178 | goto old_compare; | 180 | goto old_compare; |
| 179 | error = memcmp(a_msdos_name, b_msdos_name, MSDOS_NAME); | 181 | error = memcmp(a_msdos_name, b_msdos_name, MSDOS_NAME); |
| @@ -182,8 +184,8 @@ out: | |||
| 182 | 184 | ||
| 183 | old_compare: | 185 | old_compare: |
| 184 | error = 1; | 186 | error = 1; |
| 185 | if (a->len == b->len) | 187 | if (name->len == len) |
| 186 | error = memcmp(a->name, b->name, a->len); | 188 | error = memcmp(name->name, str, len); |
| 187 | goto out; | 189 | goto out; |
| 188 | } | 190 | } |
| 189 | 191 | ||
diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c index b936703b8924..95e00ab84c3f 100644 --- a/fs/fat/namei_vfat.c +++ b/fs/fat/namei_vfat.c | |||
| @@ -85,15 +85,18 @@ static int vfat_revalidate_ci(struct dentry *dentry, struct nameidata *nd) | |||
| 85 | } | 85 | } |
| 86 | 86 | ||
| 87 | /* returns the length of a struct qstr, ignoring trailing dots */ | 87 | /* returns the length of a struct qstr, ignoring trailing dots */ |
| 88 | static unsigned int vfat_striptail_len(struct qstr *qstr) | 88 | static unsigned int __vfat_striptail_len(unsigned int len, const char *name) |
| 89 | { | 89 | { |
| 90 | unsigned int len = qstr->len; | 90 | while (len && name[len - 1] == '.') |
| 91 | |||
| 92 | while (len && qstr->name[len - 1] == '.') | ||
| 93 | len--; | 91 | len--; |
| 94 | return len; | 92 | return len; |
| 95 | } | 93 | } |
| 96 | 94 | ||
| 95 | static unsigned int vfat_striptail_len(const struct qstr *qstr) | ||
| 96 | { | ||
| 97 | return __vfat_striptail_len(qstr->len, qstr->name); | ||
| 98 | } | ||
| 99 | |||
| 97 | /* | 100 | /* |
| 98 | * Compute the hash for the vfat name corresponding to the dentry. | 101 | * 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 | 102 | * Note: if the name is invalid, we leave the hash code unchanged so |
| @@ -133,16 +136,18 @@ static int vfat_hashi(struct dentry *dentry, struct qstr *qstr) | |||
| 133 | /* | 136 | /* |
| 134 | * Case insensitive compare of two vfat names. | 137 | * Case insensitive compare of two vfat names. |
| 135 | */ | 138 | */ |
| 136 | static int vfat_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b) | 139 | static int vfat_cmpi(const struct dentry *parent, const struct inode *pinode, |
| 140 | const struct dentry *dentry, const struct inode *inode, | ||
| 141 | unsigned int len, const char *str, const struct qstr *name) | ||
| 137 | { | 142 | { |
| 138 | struct nls_table *t = MSDOS_SB(dentry->d_inode->i_sb)->nls_io; | 143 | struct nls_table *t = MSDOS_SB(parent->d_sb)->nls_io; |
| 139 | unsigned int alen, blen; | 144 | unsigned int alen, blen; |
| 140 | 145 | ||
| 141 | /* A filename cannot end in '.' or we treat it like it has none */ | 146 | /* A filename cannot end in '.' or we treat it like it has none */ |
| 142 | alen = vfat_striptail_len(a); | 147 | alen = vfat_striptail_len(name); |
| 143 | blen = vfat_striptail_len(b); | 148 | blen = __vfat_striptail_len(len, str); |
| 144 | if (alen == blen) { | 149 | if (alen == blen) { |
| 145 | if (nls_strnicmp(t, a->name, b->name, alen) == 0) | 150 | if (nls_strnicmp(t, name->name, str, alen) == 0) |
| 146 | return 0; | 151 | return 0; |
| 147 | } | 152 | } |
| 148 | return 1; | 153 | return 1; |
| @@ -151,15 +156,17 @@ static int vfat_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b) | |||
| 151 | /* | 156 | /* |
| 152 | * Case sensitive compare of two vfat names. | 157 | * Case sensitive compare of two vfat names. |
| 153 | */ | 158 | */ |
| 154 | static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b) | 159 | static int vfat_cmp(const struct dentry *parent, const struct inode *pinode, |
| 160 | const struct dentry *dentry, const struct inode *inode, | ||
| 161 | unsigned int len, const char *str, const struct qstr *name) | ||
| 155 | { | 162 | { |
| 156 | unsigned int alen, blen; | 163 | unsigned int alen, blen; |
| 157 | 164 | ||
| 158 | /* A filename cannot end in '.' or we treat it like it has none */ | 165 | /* A filename cannot end in '.' or we treat it like it has none */ |
| 159 | alen = vfat_striptail_len(a); | 166 | alen = vfat_striptail_len(name); |
| 160 | blen = vfat_striptail_len(b); | 167 | blen = __vfat_striptail_len(len, str); |
| 161 | if (alen == blen) { | 168 | if (alen == blen) { |
| 162 | if (strncmp(a->name, b->name, alen) == 0) | 169 | if (strncmp(name->name, str, alen) == 0) |
| 163 | return 0; | 170 | return 0; |
| 164 | } | 171 | } |
| 165 | return 1; | 172 | return 1; |
