summaryrefslogtreecommitdiff
path: root/fs/dcache.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-03-27 16:23:12 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2009-03-27 16:23:12 -0700
commit3ae5080f4c2e293229508dabe7c8a90af4e4c460 (patch)
tree9cb11f26905a82b7fac9d3b8f9d61d58bc5c94b0 /fs/dcache.c
parent2c9e15a011c55ff96b2b8d2b126d1b9a96abba20 (diff)
parentaabb8fdb41128705fd1627f56fdd571e45fdbcdb (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: (37 commits) fs: avoid I_NEW inodes Merge code for single and multiple-instance mounts Remove get_init_pts_sb() Move common mknod_ptmx() calls into caller Parse mount options just once and copy them to super block Unroll essentials of do_remount_sb() into devpts vfs: simple_set_mnt() should return void fs: move bdev code out of buffer.c constify dentry_operations: rest constify dentry_operations: configfs constify dentry_operations: sysfs constify dentry_operations: JFS constify dentry_operations: OCFS2 constify dentry_operations: GFS2 constify dentry_operations: FAT constify dentry_operations: FUSE constify dentry_operations: procfs constify dentry_operations: ecryptfs constify dentry_operations: CIFS constify dentry_operations: AFS ...
Diffstat (limited to 'fs/dcache.c')
-rw-r--r--fs/dcache.c48
1 files changed, 18 insertions, 30 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index 07e2d4a44bd..90bbd7e1b11 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1247,15 +1247,18 @@ struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode,
struct dentry *found;
struct dentry *new;
- /* Does a dentry matching the name exist already? */
+ /*
+ * First check if a dentry matching the name already exists,
+ * if not go ahead and create it now.
+ */
found = d_hash_and_lookup(dentry->d_parent, name);
- /* If not, create it now and return */
if (!found) {
new = d_alloc(dentry->d_parent, name);
if (!new) {
error = -ENOMEM;
goto err_out;
}
+
found = d_splice_alias(inode, new);
if (found) {
dput(new);
@@ -1263,61 +1266,46 @@ struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode,
}
return new;
}
- /* Matching dentry exists, check if it is negative. */
+
+ /*
+ * If a matching dentry exists, and it's not negative use it.
+ *
+ * Decrement the reference count to balance the iget() done
+ * earlier on.
+ */
if (found->d_inode) {
if (unlikely(found->d_inode != inode)) {
/* This can't happen because bad inodes are unhashed. */
BUG_ON(!is_bad_inode(inode));
BUG_ON(!is_bad_inode(found->d_inode));
}
- /*
- * Already have the inode and the dentry attached, decrement
- * the reference count to balance the iget() done
- * earlier on. We found the dentry using d_lookup() so it
- * cannot be disconnected and thus we do not need to worry
- * about any NFS/disconnectedness issues here.
- */
iput(inode);
return found;
}
+
/*
* Negative dentry: instantiate it unless the inode is a directory and
- * has a 'disconnected' dentry (i.e. IS_ROOT and DCACHE_DISCONNECTED),
- * in which case d_move() that in place of the found dentry.
+ * already has a dentry.
*/
- if (!S_ISDIR(inode->i_mode)) {
- /* Not a directory; everything is easy. */
- d_instantiate(found, inode);
- return found;
- }
spin_lock(&dcache_lock);
- if (list_empty(&inode->i_dentry)) {
- /*
- * Directory without a 'disconnected' dentry; we need to do
- * d_instantiate() by hand because it takes dcache_lock which
- * we already hold.
- */
+ if (!S_ISDIR(inode->i_mode) || list_empty(&inode->i_dentry)) {
__d_instantiate(found, inode);
spin_unlock(&dcache_lock);
security_d_instantiate(found, inode);
return found;
}
+
/*
- * Directory with a 'disconnected' dentry; get a reference to the
- * 'disconnected' dentry.
+ * In case a directory already has a (disconnected) entry grab a
+ * reference to it, move it in place and use it.
*/
new = list_entry(inode->i_dentry.next, struct dentry, d_alias);
dget_locked(new);
spin_unlock(&dcache_lock);
- /* Do security vodoo. */
security_d_instantiate(found, inode);
- /* Move new in place of found. */
d_move(new, found);
- /* Balance the iget() we did above. */
iput(inode);
- /* Throw away found. */
dput(found);
- /* Use new as the actual dentry. */
return new;
err_out: