aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBarry Naujok <bnaujok@sgi.com>2008-05-21 02:50:46 -0400
committerNiv Sardi <xaiki@debian.org>2008-07-28 02:58:39 -0400
commit9403540c0653122ca34884a180439ddbfcbcb524 (patch)
tree40b5fb192900c61a1c91be6ae8ea7432b61f18aa
parent6a178100abf01282eb697ab62b6086b2886dfc00 (diff)
dcache: Add case-insensitive support d_ci_add() routine
This add a dcache entry to the dcache for lookup, but changing the name that is associated with the entry rather than the one passed in to the lookup routine. First, it sees if the case-exact match already exists in the dcache and uses it if one exists. Otherwise, it allocates a new node with the new name and splices it into the dcache. Original code from ntfs_lookup in fs/ntfs/namei.c by Anton Altaparmakov. Signed-off-by: Barry Naujok <bnaujok@sgi.com> Signed-off-by: Anton Altaparmakov <aia21@cantab.net> Acked-by: Christoph Hellwig <hch@infradead.org>
-rw-r--r--fs/dcache.c102
-rw-r--r--include/linux/dcache.h1
2 files changed, 103 insertions, 0 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index f2584d22cb45..101663d15e9f 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1220,6 +1220,107 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
1220 return new; 1220 return new;
1221} 1221}
1222 1222
1223/**
1224 * d_add_ci - lookup or allocate new dentry with case-exact name
1225 * @inode: the inode case-insensitive lookup has found
1226 * @dentry: the negative dentry that was passed to the parent's lookup func
1227 * @name: the case-exact name to be associated with the returned dentry
1228 *
1229 * This is to avoid filling the dcache with case-insensitive names to the
1230 * same inode, only the actual correct case is stored in the dcache for
1231 * case-insensitive filesystems.
1232 *
1233 * For a case-insensitive lookup match and if the the case-exact dentry
1234 * already exists in in the dcache, use it and return it.
1235 *
1236 * If no entry exists with the exact case name, allocate new dentry with
1237 * the exact case, and return the spliced entry.
1238 */
1239struct dentry *d_add_ci(struct inode *inode, struct dentry *dentry,
1240 struct qstr *name)
1241{
1242 int error;
1243 struct dentry *found;
1244 struct dentry *new;
1245
1246 /* Does a dentry matching the name exist already? */
1247 found = d_hash_and_lookup(dentry->d_parent, name);
1248 /* If not, create it now and return */
1249 if (!found) {
1250 new = d_alloc(dentry->d_parent, name);
1251 if (!new) {
1252 error = -ENOMEM;
1253 goto err_out;
1254 }
1255 found = d_splice_alias(inode, new);
1256 if (found) {
1257 dput(new);
1258 return found;
1259 }
1260 return new;
1261 }
1262 /* Matching dentry exists, check if it is negative. */
1263 if (found->d_inode) {
1264 if (unlikely(found->d_inode != inode)) {
1265 /* This can't happen because bad inodes are unhashed. */
1266 BUG_ON(!is_bad_inode(inode));
1267 BUG_ON(!is_bad_inode(found->d_inode));
1268 }
1269 /*
1270 * Already have the inode and the dentry attached, decrement
1271 * the reference count to balance the iget() done
1272 * earlier on. We found the dentry using d_lookup() so it
1273 * cannot be disconnected and thus we do not need to worry
1274 * about any NFS/disconnectedness issues here.
1275 */
1276 iput(inode);
1277 return found;
1278 }
1279 /*
1280 * Negative dentry: instantiate it unless the inode is a directory and
1281 * has a 'disconnected' dentry (i.e. IS_ROOT and DCACHE_DISCONNECTED),
1282 * in which case d_move() that in place of the found dentry.
1283 */
1284 if (!S_ISDIR(inode->i_mode)) {
1285 /* Not a directory; everything is easy. */
1286 d_instantiate(found, inode);
1287 return found;
1288 }
1289 spin_lock(&dcache_lock);
1290 if (list_empty(&inode->i_dentry)) {
1291 /*
1292 * Directory without a 'disconnected' dentry; we need to do
1293 * d_instantiate() by hand because it takes dcache_lock which
1294 * we already hold.
1295 */
1296 list_add(&found->d_alias, &inode->i_dentry);
1297 found->d_inode = inode;
1298 spin_unlock(&dcache_lock);
1299 security_d_instantiate(found, inode);
1300 return found;
1301 }
1302 /*
1303 * Directory with a 'disconnected' dentry; get a reference to the
1304 * 'disconnected' dentry.
1305 */
1306 new = list_entry(inode->i_dentry.next, struct dentry, d_alias);
1307 dget_locked(new);
1308 spin_unlock(&dcache_lock);
1309 /* Do security vodoo. */
1310 security_d_instantiate(found, inode);
1311 /* Move new in place of found. */
1312 d_move(new, found);
1313 /* Balance the iget() we did above. */
1314 iput(inode);
1315 /* Throw away found. */
1316 dput(found);
1317 /* Use new as the actual dentry. */
1318 return new;
1319
1320err_out:
1321 iput(inode);
1322 return ERR_PTR(error);
1323}
1223 1324
1224/** 1325/**
1225 * d_lookup - search for a dentry 1326 * d_lookup - search for a dentry
@@ -2254,6 +2355,7 @@ EXPORT_SYMBOL(d_path);
2254EXPORT_SYMBOL(d_prune_aliases); 2355EXPORT_SYMBOL(d_prune_aliases);
2255EXPORT_SYMBOL(d_rehash); 2356EXPORT_SYMBOL(d_rehash);
2256EXPORT_SYMBOL(d_splice_alias); 2357EXPORT_SYMBOL(d_splice_alias);
2358EXPORT_SYMBOL(d_add_ci);
2257EXPORT_SYMBOL(d_validate); 2359EXPORT_SYMBOL(d_validate);
2258EXPORT_SYMBOL(dget_locked); 2360EXPORT_SYMBOL(dget_locked);
2259EXPORT_SYMBOL(dput); 2361EXPORT_SYMBOL(dput);
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 98202c672fde..07aa198f19ed 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -230,6 +230,7 @@ extern void d_delete(struct dentry *);
230extern struct dentry * d_alloc(struct dentry *, const struct qstr *); 230extern struct dentry * d_alloc(struct dentry *, const struct qstr *);
231extern struct dentry * d_alloc_anon(struct inode *); 231extern struct dentry * d_alloc_anon(struct inode *);
232extern struct dentry * d_splice_alias(struct inode *, struct dentry *); 232extern struct dentry * d_splice_alias(struct inode *, struct dentry *);
233extern struct dentry * d_add_ci(struct inode *, struct dentry *, struct qstr *);
233extern void shrink_dcache_sb(struct super_block *); 234extern void shrink_dcache_sb(struct super_block *);
234extern void shrink_dcache_parent(struct dentry *); 235extern void shrink_dcache_parent(struct dentry *);
235extern void shrink_dcache_for_umount(struct super_block *); 236extern void shrink_dcache_for_umount(struct super_block *);