[PATCH 1/2] VFS: Cut down inode->i_op->xyz accesses in path walking

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

 



From: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx>
Date: Fri, 22 Jul 2011 08:44:51 -0700
Subject: [PATCH 1/2] VFS: Cut down inode->i_op->xyz accesses in path walking

One of the biggest remaining unnecessary costs in path walking is the
pointer chasing in inode operations.  We already avoided the
dentry->d_op derferences with the DCACHE_OP_xyz flags, this just starts
doing the same thing for the i_op->xyz cases.

Signed-off-by: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx>
---
 fs/dcache.c            |    6 ++++++
 fs/namei.c             |   25 +++++++++++++------------
 include/linux/dcache.h |   12 +++++++++---
 3 files changed, 28 insertions(+), 15 deletions(-)

diff --git a/fs/dcache.c b/fs/dcache.c
index fbdcbca40725..2dacddb7b101 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1374,6 +1374,12 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode)
 		if (unlikely(IS_AUTOMOUNT(inode)))
 			dentry->d_flags |= DCACHE_NEED_AUTOMOUNT;
 		list_add(&dentry->d_alias, &inode->i_dentry);
+		if (unlikely(inode->i_op->lookup))
+			dentry->d_flags |= DCACHE_OP_LOOKUP;
+		if (unlikely(inode->i_op->permission))
+			dentry->d_flags |= DCACHE_OP_PERMISSION;
+		if (unlikely(inode->i_op->follow_link))
+			dentry->d_flags |= DCACHE_OP_FOLLOW_LINK;
 	}
 	dentry->d_inode = inode;
 	dentry_rcuwalk_barrier(dentry);
diff --git a/fs/namei.c b/fs/namei.c
index 14ab8d3f2f0c..02b680e0e816 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -577,12 +577,12 @@ static int complete_walk(struct nameidata *nd)
  * short-cut DAC fails, then call ->permission() to do more
  * complete permission check.
  */
-static inline int exec_permission(struct inode *inode, unsigned int flags)
+static inline int exec_permission(struct dentry *dentry, struct inode *inode, unsigned int flags)
 {
 	int ret;
 	struct user_namespace *ns = inode_userns(inode);
 
-	if (inode->i_op->permission) {
+	if (dentry->d_flags & DCACHE_OP_PERMISSION) {
 		ret = inode->i_op->permission(inode, MAY_EXEC, flags);
 	} else {
 		ret = acl_permission_check(inode, MAY_EXEC, flags,
@@ -1234,13 +1234,13 @@ retry:
 static inline int may_lookup(struct nameidata *nd)
 {
 	if (nd->flags & LOOKUP_RCU) {
-		int err = exec_permission(nd->inode, IPERM_FLAG_RCU);
+		int err = exec_permission(nd->path.dentry, nd->inode, IPERM_FLAG_RCU);
 		if (err != -ECHILD)
 			return err;
 		if (unlazy_walk(nd, NULL))
 			return -ECHILD;
 	}
-	return exec_permission(nd->inode, 0);
+	return exec_permission(nd->path.dentry, nd->inode, 0);
 }
 
 static inline int handle_dots(struct nameidata *nd, int type)
@@ -1290,7 +1290,7 @@ static inline int walk_component(struct nameidata *nd, struct path *path,
 		terminate_walk(nd);
 		return -ENOENT;
 	}
-	if (unlikely(inode->i_op->follow_link) && follow) {
+	if (unlikely(path->dentry->d_flags & DCACHE_OP_FOLLOW_LINK) && follow) {
 		if (nd->flags & LOOKUP_RCU) {
 			if (unlikely(unlazy_walk(nd, path->dentry))) {
 				terminate_walk(nd);
@@ -1425,7 +1425,7 @@ static int link_path_walk(const char *name, struct nameidata *nd)
 				return err;
 		}
 		err = -ENOTDIR; 
-		if (!nd->inode->i_op->lookup)
+		if (!(nd->path.dentry->d_flags & DCACHE_OP_LOOKUP))
 			break;
 		continue;
 		/* here ends the main loop */
@@ -1452,11 +1452,12 @@ static int path_init(int dfd, const char *name, unsigned int flags,
 	nd->flags = flags | LOOKUP_JUMPED;
 	nd->depth = 0;
 	if (flags & LOOKUP_ROOT) {
-		struct inode *inode = nd->root.dentry->d_inode;
+		struct dentry *dentry = nd->root.dentry;
+		struct inode *inode = dentry->d_inode;
 		if (*name) {
-			if (!inode->i_op->lookup)
+			if (!(dentry->d_flags & DCACHE_OP_LOOKUP))
 				return -ENOTDIR;
-			retval = inode_permission(inode, MAY_EXEC);
+			retval = exec_permission(dentry, inode, 0);
 			if (retval)
 				return retval;
 		}
@@ -1599,7 +1600,7 @@ static int path_lookupat(int dfd, const char *name,
 		err = complete_walk(nd);
 
 	if (!err && nd->flags & LOOKUP_DIRECTORY) {
-		if (!nd->inode->i_op->lookup) {
+		if (!(nd->path.dentry->d_flags & DCACHE_OP_LOOKUP)) {
 			path_put(&nd->path);
 			err = -ENOTDIR;
 		}
@@ -1672,7 +1673,7 @@ static struct dentry *__lookup_hash(struct qstr *name,
 	struct dentry *dentry;
 	int err;
 
-	err = exec_permission(inode, 0);
+	err = exec_permission(base, inode, 0);
 	if (err)
 		return ERR_PTR(err);
 
@@ -2099,7 +2100,7 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
 
 		error = -ENOTDIR;
 		if (nd->flags & LOOKUP_DIRECTORY) {
-			if (!nd->inode->i_op->lookup)
+			if (!(nd->path.dentry->d_flags & DCACHE_OP_LOOKUP))
 				goto exit;
 		}
 		audit_inode(pathname, nd->path.dentry);
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 19d90a55541d..8cd1a3d5b320 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -208,14 +208,20 @@ struct dentry_operations {
 #define DCACHE_CANT_MOUNT	0x0100
 #define DCACHE_GENOCIDE		0x0200
 
+/* Avoid 'dentry->d_op->op' dereference chain */
 #define DCACHE_OP_HASH		0x1000
 #define DCACHE_OP_COMPARE	0x2000
 #define DCACHE_OP_REVALIDATE	0x4000
 #define DCACHE_OP_DELETE	0x8000
 
-#define DCACHE_MOUNTED		0x10000	/* is a mountpoint */
-#define DCACHE_NEED_AUTOMOUNT	0x20000	/* handle automount on this dir */
-#define DCACHE_MANAGE_TRANSIT	0x40000	/* manage transit from this dirent */
+/* Avoid 'inode->i_op->op' dereference chain */
+#define DCACHE_OP_LOOKUP	0x10000
+#define DCACHE_OP_PERMISSION	0x20000
+#define DCACHE_OP_FOLLOW_LINK	0x40000
+
+#define DCACHE_MOUNTED		0x100000	/* is a mountpoint */
+#define DCACHE_NEED_AUTOMOUNT	0x200000	/* handle automount on this dir */
+#define DCACHE_MANAGE_TRANSIT	0x400000	/* manage transit from this dirent */
 #define DCACHE_MANAGED_DENTRY \
 	(DCACHE_MOUNTED|DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT)
 
-- 
1.7.6.233.gd79bc.dirty

--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[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