Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 924

kernel-2.6.18-238.el5.src.rpm

From: Eric Sandeen <sandeen@redhat.com>
Date: Thu, 26 Mar 2009 10:33:46 -0500
Subject: [fs] d_add_ci helper
Message-id: 49CBA05A.9060500@redhat.com
O-Subject: [PATCH 4/10 V2] d_add_ci helper
Bugzilla: 470845
RH-Acked-by: Josef Bacik <josef@redhat.com>

Update: add fsnotify_d_instantiate call as swhiteho pointed out
is missing vs upstream, due to 360da90029196c9449bc61e5a07ce8404e4cba57

This is for bug 470845 - [RHEL 5] [RFE] {RHEL 5.4?} XFS support

Backport of:

commit 9403540c0653122ca34884a180439ddbfcbcb524
Author: Barry Naujok <bnaujok@sgi.com>
Date:   Wed May 21 16:50:46 2008 +1000

    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>

and:

commit e45b590b976465c258f3e2a6cc84573fc19e16d3
Author: Christoph Hellwig <hch@lst.de>
Date: Thu, 7 Aug 2008 21:49:07 +0000 (+0200)

    [PATCH] change d_add_ci argument ordering

    As pointed out during review d_add_ci argument order should match d_add,
    so switch the dentry and inode arguments.

    Signed-off-by: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

and add call to fsnotify_d_instantiate() added in:

commit 360da90029196c9449bc61e5a07ce8404e4cba57
Author: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Date:   Thu Oct 16 07:50:28 2008 +0900

    [PATCH vfs-2.6 3/6] vfs: add __d_instantiate() helper

    This adds __d_instantiate() for users which is already taking
    dcache_lock, and replace with it.

    The part of d_add_ci() isn't equivalent. But it should be needed
    fsnotify_d_instantiate() actually, because the path is to add the
    inode to negative dentry.  fsnotify_d_instantiate() should be called
    after change from negative to positive.

    Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

diff --git a/fs/dcache.c b/fs/dcache.c
index 7032e27..3aec28c 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1163,6 +1163,108 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
 	return new;
 }
 
+/**
+ * d_add_ci - lookup or allocate new dentry with case-exact name
+ * @inode:  the inode case-insensitive lookup has found
+ * @dentry: the negative dentry that was passed to the parent's lookup func
+ * @name:   the case-exact name to be associated with the returned dentry
+ *
+ * This is to avoid filling the dcache with case-insensitive names to the
+ * same inode, only the actual correct case is stored in the dcache for
+ * case-insensitive filesystems.
+ *
+ * For a case-insensitive lookup match and if the the case-exact dentry
+ * already exists in in the dcache, use it and return it.
+ *
+ * If no entry exists with the exact case name, allocate new dentry with
+ * the exact case, and return the spliced entry.
+ */
+struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode,
+			struct qstr *name)
+{
+	int error;
+	struct dentry *found;
+	struct dentry *new;
+
+	/* Does a dentry matching the name exist already? */
+	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);
+			return found;
+		}
+		return new;
+	}
+	/* Matching dentry exists, check if it is negative. */
+	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.
+	 */
+	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.
+		 */
+		list_add(&found->d_alias, &inode->i_dentry);
+		found->d_inode = inode;
+		fsnotify_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.
+	 */
+	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:
+	iput(inode);
+	return ERR_PTR(error);
+}
 
 /**
  * d_lookup - search for a dentry
@@ -2151,6 +2253,7 @@ EXPORT_SYMBOL(d_path);
 EXPORT_SYMBOL(d_prune_aliases);
 EXPORT_SYMBOL(d_rehash);
 EXPORT_SYMBOL(d_splice_alias);
+EXPORT_SYMBOL(d_add_ci);
 EXPORT_SYMBOL(d_validate);
 EXPORT_SYMBOL(dget_locked);
 EXPORT_SYMBOL(dput);
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 4b46f00..f8e03cc 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -230,6 +230,7 @@ extern void d_delete(struct dentry *);
 extern struct dentry * d_alloc(struct dentry *, const struct qstr *);
 extern struct dentry * d_alloc_anon(struct inode *);
 extern struct dentry * d_splice_alias(struct inode *, struct dentry *);
+extern struct dentry * d_add_ci(struct dentry *, struct inode *, struct qstr *);
 extern void shrink_dcache_sb(struct super_block *);
 extern void shrink_dcache_parent(struct dentry *);
 extern void shrink_dcache_for_umount(struct super_block *);