[PATCH NOMERGE 03/13] vfs: Add support for positive dentries CI lookups in the dentry cache

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Negative dentries are still invalidated, triggering a lookup in the
disk.

Signed-off-by: Gabriel Krisman Bertazi <krisman@xxxxxxxxxxxxxxx>
---
 fs/dcache.c            | 43 +++++++++++++++++++++++++++++++++---------
 fs/namei.c             |  5 +++--
 include/linux/dcache.h |  8 ++++++--
 3 files changed, 43 insertions(+), 13 deletions(-)

diff --git a/fs/dcache.c b/fs/dcache.c
index 7c38f39958bc..4bd28d7caa53 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -2049,6 +2049,16 @@ struct dentry *d_obtain_root(struct inode *inode)
 }
 EXPORT_SYMBOL(d_obtain_root);
 
+static inline bool d_same_name_ci(const struct dentry *dentry,
+				  const struct dentry *parent,
+				  const struct qstr *name)
+{
+	return parent->d_op->d_compare_ci(dentry,
+					  dentry->d_name.len,
+					  dentry->d_name.name,
+					  name) == 0;
+}
+
 /**
  * d_add_ci - lookup or allocate new dentry with case-exact name
  * @inode:  the inode case-insensitive lookup has found
@@ -2122,6 +2132,7 @@ static inline bool d_same_name(const struct dentry *dentry,
  * @parent: parent dentry
  * @name: qstr of name we wish to find
  * @seqp: returns d_seq value at the point where the dentry was found
+ * @ci_lookup: Whether d_lookup_rcu should do a CI lookup
  * Returns: dentry, or NULL
  *
  * __d_lookup_rcu is the dcache lookup function for rcu-walk name
@@ -2148,7 +2159,7 @@ static inline bool d_same_name(const struct dentry *dentry,
  */
 struct dentry *__d_lookup_rcu(const struct dentry *parent,
 				const struct qstr *name,
-				unsigned *seqp)
+				unsigned *seqp, int ci_lookup)
 {
 	u64 hashlen = name->hash_len;
 	const unsigned char *str = name->name;
@@ -2215,9 +2226,16 @@ struct dentry *__d_lookup_rcu(const struct dentry *parent,
 				cpu_relax();
 				goto seqretry;
 			}
-			if (parent->d_op->d_compare(dentry,
-						    tlen, tname, name) != 0)
-				continue;
+
+			if (ci_lookup) {
+				if (parent->d_op->d_compare_ci(dentry, tlen,
+							       tname, name) != 0)
+					continue;
+			} else {
+				if (parent->d_op->d_compare(dentry, tlen,
+							    tname, name) != 0)
+					continue;
+			}
 		} else {
 			if (dentry->d_name.hash_len != hashlen)
 				continue;
@@ -2248,7 +2266,7 @@ struct dentry *d_lookup(const struct dentry *parent, const struct qstr *name)
 
 	do {
 		seq = read_seqbegin(&rename_lock);
-		dentry = __d_lookup(parent, name);
+		dentry = __d_lookup(parent, name, 0);
 		if (dentry)
 			break;
 	} while (read_seqretry(&rename_lock, seq));
@@ -2260,6 +2278,7 @@ EXPORT_SYMBOL(d_lookup);
  * __d_lookup - search for a dentry (racy)
  * @parent: parent dentry
  * @name: qstr of name we wish to find
+ * @ci_lookup: Whether d_lookup_rcu should do a CI lookup
  * Returns: dentry, or NULL
  *
  * __d_lookup is like d_lookup, however it may (rarely) return a
@@ -2271,7 +2290,8 @@ EXPORT_SYMBOL(d_lookup);
  *
  * __d_lookup callers must be commented.
  */
-struct dentry *__d_lookup(const struct dentry *parent, const struct qstr *name)
+struct dentry *__d_lookup(const struct dentry *parent, const struct qstr *name,
+			  int ci_lookup)
 {
 	unsigned int hash = name->hash;
 	struct hlist_bl_head *b = d_hash(hash);
@@ -2312,8 +2332,13 @@ struct dentry *__d_lookup(const struct dentry *parent, const struct qstr *name)
 		if (d_unhashed(dentry))
 			goto next;
 
-		if (!d_same_name(dentry, parent, name))
-			goto next;
+		if (ci_lookup) {
+			if (!d_same_name_ci(dentry, parent, name))
+				goto next;
+		} else {
+			if (!d_same_name(dentry, parent, name))
+				goto next;
+		}
 
 		dentry->d_lockref.count++;
 		found = dentry;
@@ -2476,7 +2501,7 @@ struct dentry *d_alloc_parallel(struct dentry *parent,
 	rcu_read_lock();
 	seq = smp_load_acquire(&parent->d_inode->i_dir_seq) & ~1;
 	r_seq = read_seqbegin(&rename_lock);
-	dentry = __d_lookup_rcu(parent, name, &d_seq);
+	dentry = __d_lookup_rcu(parent, name, &d_seq, 0);
 	if (unlikely(dentry)) {
 		if (!lockref_get_not_dead(&dentry->d_lockref)) {
 			rcu_read_unlock();
diff --git a/fs/namei.c b/fs/namei.c
index 135a9a4e676b..1ebe5e775a9a 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1540,6 +1540,7 @@ static int lookup_fast(struct nameidata *nd,
 	struct dentry *dentry, *parent = nd->path.dentry;
 	int status = 1;
 	int err;
+	int ci_lookup = (nd->flags & LOOKUP_CASEFOLD);
 
 	/*
 	 * Rename seqlock is not required here because in the off chance
@@ -1549,7 +1550,7 @@ static int lookup_fast(struct nameidata *nd,
 	if (nd->flags & LOOKUP_RCU) {
 		unsigned seq;
 		bool negative;
-		dentry = __d_lookup_rcu(parent, &nd->last, &seq);
+		dentry = __d_lookup_rcu(parent, &nd->last, &seq, ci_lookup);
 		if (unlikely(!dentry)) {
 			if (unlazy_walk(nd))
 				return -ECHILD;
@@ -1595,7 +1596,7 @@ static int lookup_fast(struct nameidata *nd,
 			/* we'd been told to redo it in non-rcu mode */
 			status = d_revalidate(dentry, nd->flags);
 	} else {
-		dentry = __d_lookup(parent, &nd->last);
+		dentry = __d_lookup(parent, &nd->last, ci_lookup);
 		if (unlikely(!dentry))
 			return 0;
 		status = d_revalidate(dentry, nd->flags);
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 82a99d366aec..a4ce5ea207ad 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -139,6 +139,8 @@ struct dentry_operations {
 	int (*d_hash)(const struct dentry *, struct qstr *);
 	int (*d_compare)(const struct dentry *,
 			unsigned int, const char *, const struct qstr *);
+	int (*d_compare_ci)(const struct dentry *,
+			    unsigned int, const char *, const struct qstr *);
 	int (*d_delete)(const struct dentry *);
 	int (*d_init)(struct dentry *);
 	void (*d_release)(struct dentry *);
@@ -282,9 +284,11 @@ extern struct dentry *d_ancestor(struct dentry *, struct dentry *);
 /* appendix may either be NULL or be used for transname suffixes */
 extern struct dentry *d_lookup(const struct dentry *, const struct qstr *);
 extern struct dentry *d_hash_and_lookup(struct dentry *, struct qstr *);
-extern struct dentry *__d_lookup(const struct dentry *, const struct qstr *);
+extern struct dentry *__d_lookup(const struct dentry *, const struct qstr *,
+				 int ci_lookup);
 extern struct dentry *__d_lookup_rcu(const struct dentry *parent,
-				const struct qstr *name, unsigned *seq);
+				const struct qstr *name, unsigned *seq,
+				int ci_lookup);
 
 static inline unsigned d_count(const struct dentry *dentry)
 {
-- 
2.17.0




[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux