summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Brauner <brauner@kernel.org>2025-04-17 11:03:52 +0200
committerChristian Brauner <brauner@kernel.org>2025-04-21 10:27:59 +0200
commitc4044870ae2cb28d11ea771db165edb9e1a60702 (patch)
treebb3e1417fd6fbfeb255e93faa29784efdff821fe
parent79beea2db0431536d79fc5d321225fb42f955466 (diff)
parent4ef4ac360101f8bb11b6486ce60cd60ca015be8c (diff)
Merge patch series "two nits for path lookup"
Mateusz Guzik <mjguzik@gmail.com> says: Since path looku is being looked at, two extra nits from me: 1. some trivial jump avoidance in inode_permission() 2. but more importantly avoiding a memory access which is most likely a cache miss when descending into devcgroup_inode_permission() the file seems to have no maintainer fwiw anyhow I'm confident the way forward is to add IOP_FAST_MAY_EXEC (or similar) to elide inode_permission() in the common case to begin with. There are quite a few branches which straight up don't need execute. On top of that btrfs has a permission hook only to check for MAY_WRITE, which in case of path lookup is not set. With the above flag the call will be avoided. * patches from https://lore.kernel.org/20250416221626.2710239-1-mjguzik@gmail.com: device_cgroup: avoid access to ->i_rdev in the common case in devcgroup_inode_permission() fs: touch up predicts in inode_permission() Link: https://lore.kernel.org/20250416221626.2710239-1-mjguzik@gmail.com Signed-off-by: Christian Brauner <brauner@kernel.org>
-rw-r--r--fs/namei.c10
-rw-r--r--include/linux/device_cgroup.h7
2 files changed, 9 insertions, 8 deletions
diff --git a/fs/namei.c b/fs/namei.c
index b9cc03faa033..b051211f064c 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -571,14 +571,14 @@ int inode_permission(struct mnt_idmap *idmap,
int retval;
retval = sb_permission(inode->i_sb, inode, mask);
- if (retval)
+ if (unlikely(retval))
return retval;
if (unlikely(mask & MAY_WRITE)) {
/*
* Nobody gets write access to an immutable file.
*/
- if (IS_IMMUTABLE(inode))
+ if (unlikely(IS_IMMUTABLE(inode)))
return -EPERM;
/*
@@ -586,16 +586,16 @@ int inode_permission(struct mnt_idmap *idmap,
* written back improperly if their true value is unknown
* to the vfs.
*/
- if (HAS_UNMAPPED_ID(idmap, inode))
+ if (unlikely(HAS_UNMAPPED_ID(idmap, inode)))
return -EACCES;
}
retval = do_inode_permission(idmap, inode, mask);
- if (retval)
+ if (unlikely(retval))
return retval;
retval = devcgroup_inode_permission(inode, mask);
- if (retval)
+ if (unlikely(retval))
return retval;
return security_inode_permission(inode, mask);
diff --git a/include/linux/device_cgroup.h b/include/linux/device_cgroup.h
index d02f32b7514e..0864773a57e8 100644
--- a/include/linux/device_cgroup.h
+++ b/include/linux/device_cgroup.h
@@ -18,15 +18,16 @@ static inline int devcgroup_inode_permission(struct inode *inode, int mask)
{
short type, access = 0;
+ if (likely(!S_ISBLK(inode->i_mode) && !S_ISCHR(inode->i_mode)))
+ return 0;
+
if (likely(!inode->i_rdev))
return 0;
if (S_ISBLK(inode->i_mode))
type = DEVCG_DEV_BLOCK;
- else if (S_ISCHR(inode->i_mode))
+ else /* S_ISCHR by the test above */
type = DEVCG_DEV_CHAR;
- else
- return 0;
if (mask & MAY_WRITE)
access |= DEVCG_ACC_WRITE;