Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Barry Naujok and committed by
Niv Sardi
9403540c 6a178100

+103
+102
fs/dcache.c
··· 1220 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 + */ 1239 + struct 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 + 1320 + err_out: 1321 + iput(inode); 1322 + return ERR_PTR(error); 1323 + } 1223 1324 1224 1325 /** 1225 1326 * d_lookup - search for a dentry ··· 2355 2254 EXPORT_SYMBOL(d_prune_aliases); 2356 2255 EXPORT_SYMBOL(d_rehash); 2357 2256 EXPORT_SYMBOL(d_splice_alias); 2257 + EXPORT_SYMBOL(d_add_ci); 2358 2258 EXPORT_SYMBOL(d_validate); 2359 2259 EXPORT_SYMBOL(dget_locked); 2360 2260 EXPORT_SYMBOL(dput);
+1
include/linux/dcache.h
··· 230 230 extern struct dentry * d_alloc(struct dentry *, const struct qstr *); 231 231 extern struct dentry * d_alloc_anon(struct inode *); 232 232 extern struct dentry * d_splice_alias(struct inode *, struct dentry *); 233 + extern struct dentry * d_add_ci(struct inode *, struct dentry *, struct qstr *); 233 234 extern void shrink_dcache_sb(struct super_block *); 234 235 extern void shrink_dcache_parent(struct dentry *); 235 236 extern void shrink_dcache_for_umount(struct super_block *);