public inbox for linux-fsdevel@vger.kernel.org
 help / color / mirror / Atom feed
From: Al Viro <viro@zeniv.linux.org.uk>
To: linux-fsdevel@vger.kernel.org
Cc: agruenba@redhat.com, amir73il@gmail.com, brauner@kernel.org,
	ceph-devel@vger.kernel.org, dhowells@redhat.com,
	hubcap@omnibond.com, jack@suse.cz, krisman@kernel.org,
	linux-nfs@vger.kernel.org, miklos@szeredi.hu,
	torvalds@linux-foundation.org
Subject: [PATCH 02/20] dcache: back inline names with a struct-wrapped array of unsigned long
Date: Fri, 10 Jan 2025 02:42:45 +0000	[thread overview]
Message-ID: <20250110024303.4157645-2-viro@zeniv.linux.org.uk> (raw)
In-Reply-To: <20250110024303.4157645-1-viro@zeniv.linux.org.uk>

... so that they can be copied with struct assignment (which generates
better code) and accessed word-by-word.

The type is union shortname_storage; it's a union of arrays of
unsigned char and unsigned long.

struct name_snapshot.inline_name turned into union shortname_storage;
users (all in fs/dcache.c) adjusted.

struct dentry.d_iname has some users outside of fs/dcache.c; to
reduce the amount of noise in commit, it is replaced with
union shortname_storage d_shortname and d_iname is turned into a macro
that expands to d_shortname.string (similar to d_lock handling, hopefully
temporary - most, if not all, users shouldn't be messing with it).)

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/dcache.c                                  | 43 +++++++++-----------
 include/linux/dcache.h                       | 10 ++++-
 tools/testing/selftests/bpf/progs/find_vma.c |  2 +-
 3 files changed, 28 insertions(+), 27 deletions(-)

diff --git a/fs/dcache.c b/fs/dcache.c
index ea0f0bea511b..52662a5d08e4 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -324,7 +324,7 @@ static void __d_free_external(struct rcu_head *head)
 
 static inline int dname_external(const struct dentry *dentry)
 {
-	return dentry->d_name.name != dentry->d_iname;
+	return dentry->d_name.name != dentry->d_shortname.string;
 }
 
 void take_dentry_name_snapshot(struct name_snapshot *name, struct dentry *dentry)
@@ -334,9 +334,8 @@ void take_dentry_name_snapshot(struct name_snapshot *name, struct dentry *dentry
 	if (unlikely(dname_external(dentry))) {
 		atomic_inc(&external_name(dentry)->u.count);
 	} else {
-		memcpy(name->inline_name, dentry->d_iname,
-		       dentry->d_name.len + 1);
-		name->name.name = name->inline_name;
+		name->inline_name = dentry->d_shortname;
+		name->name.name = name->inline_name.string;
 	}
 	spin_unlock(&dentry->d_lock);
 }
@@ -344,7 +343,7 @@ EXPORT_SYMBOL(take_dentry_name_snapshot);
 
 void release_dentry_name_snapshot(struct name_snapshot *name)
 {
-	if (unlikely(name->name.name != name->inline_name)) {
+	if (unlikely(name->name.name != name->inline_name.string)) {
 		struct external_name *p;
 		p = container_of(name->name.name, struct external_name, name[0]);
 		if (unlikely(atomic_dec_and_test(&p->u.count)))
@@ -1654,10 +1653,10 @@ static struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
 	 * will still always have a NUL at the end, even if we might
 	 * be overwriting an internal NUL character
 	 */
-	dentry->d_iname[DNAME_INLINE_LEN-1] = 0;
+	dentry->d_shortname.string[DNAME_INLINE_LEN-1] = 0;
 	if (unlikely(!name)) {
 		name = &slash_name;
-		dname = dentry->d_iname;
+		dname = dentry->d_shortname.string;
 	} else if (name->len > DNAME_INLINE_LEN-1) {
 		size_t size = offsetof(struct external_name, name[1]);
 		struct external_name *p = kmalloc(size + name->len,
@@ -1670,7 +1669,7 @@ static struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
 		atomic_set(&p->u.count, 1);
 		dname = p->name;
 	} else  {
-		dname = dentry->d_iname;
+		dname = dentry->d_shortname.string;
 	}	
 
 	dentry->d_name.len = name->len;
@@ -2729,10 +2728,9 @@ static void swap_names(struct dentry *dentry, struct dentry *target)
 			 * dentry:internal, target:external.  Steal target's
 			 * storage and make target internal.
 			 */
-			memcpy(target->d_iname, dentry->d_name.name,
-					dentry->d_name.len + 1);
 			dentry->d_name.name = target->d_name.name;
-			target->d_name.name = target->d_iname;
+			target->d_shortname = dentry->d_shortname;
+			target->d_name.name = target->d_shortname.string;
 		}
 	} else {
 		if (unlikely(dname_external(dentry))) {
@@ -2740,18 +2738,16 @@ static void swap_names(struct dentry *dentry, struct dentry *target)
 			 * dentry:external, target:internal.  Give dentry's
 			 * storage to target and make dentry internal
 			 */
-			memcpy(dentry->d_iname, target->d_name.name,
-					target->d_name.len + 1);
 			target->d_name.name = dentry->d_name.name;
-			dentry->d_name.name = dentry->d_iname;
+			dentry->d_shortname = target->d_shortname;
+			dentry->d_name.name = dentry->d_shortname.string;
 		} else {
 			/*
 			 * Both are internal.
 			 */
-			for (int i = 0; i < DNAME_INLINE_WORDS; i++) {
-				swap(((long *) &dentry->d_iname)[i],
-				     ((long *) &target->d_iname)[i]);
-			}
+			for (int i = 0; i < DNAME_INLINE_WORDS; i++)
+				swap(dentry->d_shortname.words[i],
+				     target->d_shortname.words[i]);
 		}
 	}
 	swap(dentry->d_name.hash_len, target->d_name.hash_len);
@@ -2766,9 +2762,8 @@ static void copy_name(struct dentry *dentry, struct dentry *target)
 		atomic_inc(&external_name(target)->u.count);
 		dentry->d_name = target->d_name;
 	} else {
-		memcpy(dentry->d_iname, target->d_name.name,
-				target->d_name.len + 1);
-		dentry->d_name.name = dentry->d_iname;
+		dentry->d_shortname = target->d_shortname;
+		dentry->d_name.name = dentry->d_shortname.string;
 		dentry->d_name.hash_len = target->d_name.hash_len;
 	}
 	if (old_name && likely(atomic_dec_and_test(&old_name->u.count)))
@@ -3101,12 +3096,12 @@ void d_mark_tmpfile(struct file *file, struct inode *inode)
 {
 	struct dentry *dentry = file->f_path.dentry;
 
-	BUG_ON(dentry->d_name.name != dentry->d_iname ||
+	BUG_ON(dname_external(dentry) ||
 		!hlist_unhashed(&dentry->d_u.d_alias) ||
 		!d_unlinked(dentry));
 	spin_lock(&dentry->d_parent->d_lock);
 	spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
-	dentry->d_name.len = sprintf(dentry->d_iname, "#%llu",
+	dentry->d_name.len = sprintf(dentry->d_shortname.string, "#%llu",
 				(unsigned long long)inode->i_ino);
 	spin_unlock(&dentry->d_lock);
 	spin_unlock(&dentry->d_parent->d_lock);
@@ -3194,7 +3189,7 @@ static void __init dcache_init(void)
 	 */
 	dentry_cache = KMEM_CACHE_USERCOPY(dentry,
 		SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|SLAB_ACCOUNT,
-		d_iname);
+		d_shortname.string);
 
 	/* Hash may have been set up in dcache_init_early */
 	if (!hashdist)
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 42dd89beaf4e..8bc567a35718 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -79,7 +79,13 @@ extern const struct qstr dotdot_name;
 
 #define DNAME_INLINE_LEN (DNAME_INLINE_WORDS*sizeof(unsigned long))
 
+union shortname_store {
+	unsigned char string[DNAME_INLINE_LEN];
+	unsigned long words[DNAME_INLINE_WORDS];
+};
+
 #define d_lock	d_lockref.lock
+#define d_iname d_shortname.string
 
 struct dentry {
 	/* RCU lookup touched fields */
@@ -90,7 +96,7 @@ struct dentry {
 	struct qstr d_name;
 	struct inode *d_inode;		/* Where the name belongs to - NULL is
 					 * negative */
-	unsigned char d_iname[DNAME_INLINE_LEN];	/* small names */
+	union shortname_store d_shortname;
 	/* --- cacheline 1 boundary (64 bytes) was 32 bytes ago --- */
 
 	/* Ref lookup also touches following */
@@ -591,7 +597,7 @@ static inline struct inode *d_real_inode(const struct dentry *dentry)
 
 struct name_snapshot {
 	struct qstr name;
-	unsigned char inline_name[DNAME_INLINE_LEN];
+	union shortname_store inline_name;
 };
 void take_dentry_name_snapshot(struct name_snapshot *, struct dentry *);
 void release_dentry_name_snapshot(struct name_snapshot *);
diff --git a/tools/testing/selftests/bpf/progs/find_vma.c b/tools/testing/selftests/bpf/progs/find_vma.c
index 38034fb82530..02b82774469c 100644
--- a/tools/testing/selftests/bpf/progs/find_vma.c
+++ b/tools/testing/selftests/bpf/progs/find_vma.c
@@ -25,7 +25,7 @@ static long check_vma(struct task_struct *task, struct vm_area_struct *vma,
 {
 	if (vma->vm_file)
 		bpf_probe_read_kernel_str(d_iname, DNAME_INLINE_LEN - 1,
-					  vma->vm_file->f_path.dentry->d_iname);
+					  vma->vm_file->f_path.dentry->d_shortname.string);
 
 	/* check for VM_EXEC */
 	if (vma->vm_flags & VM_EXEC)
-- 
2.39.5


  reply	other threads:[~2025-01-10  2:43 UTC|newest]

Thread overview: 96+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-01-10  2:38 [PATCHES][RFC][CFT] ->d_revalidate() calling conventions changes (->d_parent/->d_name stability problems) Al Viro
2025-01-10  2:42 ` [PATCH 01/20] make sure that DNAME_INLINE_LEN is a multiple of word size Al Viro
2025-01-10  2:42   ` Al Viro [this message]
2025-01-10  9:35     ` [PATCH 02/20] dcache: back inline names with a struct-wrapped array of unsigned long Jan Kara
2025-01-10 16:24       ` Al Viro
2025-01-10  2:42   ` [PATCH 03/20] make take_dentry_name_snapshot() lockless Al Viro
2025-01-10  9:45     ` Jan Kara
2025-01-10  2:42   ` [PATCH 04/20] dissolve external_name.u into separate members Al Viro
2025-01-10  7:34     ` David Howells
2025-01-10 16:46       ` Al Viro
2025-01-10  2:42   ` [PATCH 05/20] ext4 fast_commit: make use of name_snapshot primitives Al Viro
2025-01-10  9:15     ` Jan Kara
2025-01-10  2:42   ` [PATCH 06/20] generic_ci_d_compare(): use shortname_storage Al Viro
2025-01-10  2:42   ` [PATCH 07/20] Pass parent directory inode and expected name to ->d_revalidate() Al Viro
2025-01-10  2:42   ` [PATCH 08/20] afs_d_revalidate(): use stable name and parent inode passed by caller Al Viro
2025-01-10  2:42   ` [PATCH 09/20] ceph_d_revalidate(): use stable " Al Viro
2025-01-10 19:45     ` Viacheslav Dubeyko
2025-01-10  2:42   ` [PATCH 10/20] ceph_d_revalidate(): propagate stable name down into request enconding Al Viro
2025-01-10  2:42   ` [PATCH 11/20] fscrypt_d_revalidate(): use stable parent inode passed by caller Al Viro
2025-01-10  2:42   ` [PATCH 12/20] exfat_d_revalidate(): " Al Viro
2025-01-10  2:42   ` [PATCH 13/20] vfat_revalidate{,_ci}(): " Al Viro
2025-01-10  2:42   ` [PATCH 14/20] fuse_dentry_revalidate(): use stable parent inode and name " Al Viro
2025-01-10  2:42   ` [PATCH 15/20] gfs2_drevalidate(): " Al Viro
2025-01-10 19:20     ` Andreas Grünbacher
2025-01-10  2:42   ` [PATCH 16/20] nfs{,4}_lookup_validate(): use stable parent inode " Al Viro
2025-01-10  2:43   ` [PATCH 17/20] nfs: fix ->d_revalidate() UAF on ->d_name accesses Al Viro
2025-01-10  2:43   ` [PATCH 18/20] ocfs2_dentry_revalidate(): use stable parent inode and name passed by caller Al Viro
2025-01-10  9:54     ` Jan Kara
2025-01-10  2:43   ` [PATCH 19/20] orangefs_d_revalidate(): " Al Viro
2025-01-10  3:06     ` Linus Torvalds
2025-01-10  2:43   ` [PATCH 20/20] 9p: fix ->rename_sem exclusion Al Viro
2025-01-10  3:11     ` Linus Torvalds
2025-01-10  5:53       ` Al Viro
2025-01-10  9:21   ` [PATCH 01/20] make sure that DNAME_INLINE_LEN is a multiple of word size Jan Kara
2025-01-16  5:21 ` [PATCHES v2][RFC][CFT] ->d_revalidate() calling conventions changes (->d_parent/->d_name stability problems) Al Viro
2025-01-16  5:22   ` [PATCH v2 01/20] make sure that DNAME_INLINE_LEN is a multiple of word size Al Viro
2025-01-16  5:22     ` [PATCH v2 02/20] dcache: back inline names with a struct-wrapped array of unsigned long Al Viro
2025-01-16  5:23     ` [PATCH v2 03/20] make take_dentry_name_snapshot() lockless Al Viro
2025-01-16  5:23     ` [PATCH v2 04/20] dissolve external_name.u into separate members Al Viro
2025-01-16 10:06       ` Jan Kara
2025-01-16  5:23     ` [PATCH v2 05/20] ext4 fast_commit: make use of name_snapshot primitives Al Viro
2025-01-16  5:23     ` [PATCH v2 06/20] generic_ci_d_compare(): use shortname_storage Al Viro
2025-01-16 15:38       ` Gabriel Krisman Bertazi
2025-01-16 15:46         ` Al Viro
2025-01-16 15:53           ` Gabriel Krisman Bertazi
2025-01-16  5:23     ` [PATCH v2 07/20] Pass parent directory inode and expected name to ->d_revalidate() Al Viro
2025-01-16 15:15       ` Gabriel Krisman Bertazi
2025-01-17 18:55       ` Jeff Layton
2025-01-17 19:00         ` Al Viro
2025-01-16  5:23     ` [PATCH v2 08/20] afs_d_revalidate(): use stable name and parent inode passed by caller Al Viro
2025-01-22 20:27       ` David Howells
2025-01-22 21:01         ` Al Viro
2025-01-22 21:24           ` Al Viro
2025-01-22 21:55             ` David Howells
2025-01-16  5:23     ` [PATCH v2 09/20] ceph_d_revalidate(): use stable " Al Viro
2025-01-17 18:35       ` Jeff Layton
2025-01-16  5:23     ` [PATCH v2 10/20] ceph_d_revalidate(): propagate stable name down into request enconding Al Viro
2025-01-17 18:35       ` Jeff Layton
2025-01-16  5:23     ` [PATCH v2 11/20] fscrypt_d_revalidate(): use stable parent inode passed by caller Al Viro
2025-01-17 15:20       ` Jeff Layton
2025-01-16  5:23     ` [PATCH v2 12/20] exfat_d_revalidate(): " Al Viro
2025-01-16  5:23     ` [PATCH v2 13/20] vfat_revalidate{,_ci}(): " Al Viro
2025-01-17 15:22       ` Jeff Layton
2025-01-16  5:23     ` [PATCH v2 14/20] fuse_dentry_revalidate(): use stable parent inode and name " Al Viro
2025-01-17 15:18       ` Jeff Layton
2025-01-16  5:23     ` [PATCH v2 15/20] gfs2_drevalidate(): " Al Viro
2025-01-16  5:23     ` [PATCH v2 16/20] nfs{,4}_lookup_validate(): use stable parent inode " Al Viro
2025-01-17 14:05       ` Jeff Layton
2025-01-16  5:23     ` [PATCH v2 17/20] nfs: fix ->d_revalidate() UAF on ->d_name accesses Al Viro
2025-01-17 15:12       ` Jeff Layton
2025-01-16  5:23     ` [PATCH v2 18/20] ocfs2_dentry_revalidate(): use stable parent inode and name passed by caller Al Viro
2025-01-16  5:23     ` [PATCH v2 19/20] orangefs_d_revalidate(): " Al Viro
2025-01-16  5:23     ` [PATCH v2 20/20] 9p: fix ->rename_sem exclusion Al Viro
2025-01-23  1:45   ` [PATCHES v3][RFC][CFT] ->d_revalidate() calling conventions changes (->d_parent/->d_name stability problems) Al Viro
2025-01-23  1:46     ` [PATCH v3 01/20] make sure that DNAME_INLINE_LEN is a multiple of word size Al Viro
2025-01-23  1:46       ` [PATCH v3 02/20] dcache: back inline names with a struct-wrapped array of unsigned long Al Viro
2025-01-23  1:46       ` [PATCH v3 03/20] make take_dentry_name_snapshot() lockless Al Viro
2025-01-23  1:46       ` [PATCH v3 04/20] dissolve external_name.u into separate members Al Viro
2025-01-23  1:46       ` [PATCH v3 05/20] ext4 fast_commit: make use of name_snapshot primitives Al Viro
2025-01-23  1:46       ` [PATCH v3 06/20] generic_ci_d_compare(): use shortname_storage Al Viro
2025-01-23  1:46       ` [PATCH v3 07/20] Pass parent directory inode and expected name to ->d_revalidate() Al Viro
2025-01-23  1:46       ` [PATCH v3 08/20] afs_d_revalidate(): use stable name and parent inode passed by caller Al Viro
2025-01-23  1:46       ` [PATCH v3 09/20] ceph_d_revalidate(): use stable " Al Viro
2025-01-23  1:46       ` [PATCH v3 10/20] ceph_d_revalidate(): propagate stable name down into request encoding Al Viro
2025-01-23  1:46       ` [PATCH v3 11/20] fscrypt_d_revalidate(): use stable parent inode passed by caller Al Viro
2025-01-23  1:46       ` [PATCH v3 12/20] exfat_d_revalidate(): " Al Viro
2025-01-23  1:46       ` [PATCH v3 13/20] vfat_revalidate{,_ci}(): " Al Viro
2025-01-23  1:46       ` [PATCH v3 14/20] fuse_dentry_revalidate(): use stable parent inode and name " Al Viro
2025-01-23 10:51         ` Miklos Szeredi
2025-01-23  1:46       ` [PATCH v3 15/20] gfs2_drevalidate(): " Al Viro
2025-01-23  1:46       ` [PATCH v3 16/20] nfs{,4}_lookup_validate(): use stable parent inode " Al Viro
2025-01-23  1:46       ` [PATCH v3 17/20] nfs: fix ->d_revalidate() UAF on ->d_name accesses Al Viro
2025-01-23  1:46       ` [PATCH v3 18/20] ocfs2_dentry_revalidate(): use stable parent inode and name passed by caller Al Viro
2025-01-23  1:46       ` [PATCH v3 19/20] orangefs_d_revalidate(): " Al Viro
2025-01-25 16:25         ` Mike Marshall
2025-01-23  1:46       ` [PATCH v3 20/20] 9p: fix ->rename_sem exclusion Al Viro

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250110024303.4157645-2-viro@zeniv.linux.org.uk \
    --to=viro@zeniv.linux.org.uk \
    --cc=agruenba@redhat.com \
    --cc=amir73il@gmail.com \
    --cc=brauner@kernel.org \
    --cc=ceph-devel@vger.kernel.org \
    --cc=dhowells@redhat.com \
    --cc=hubcap@omnibond.com \
    --cc=jack@suse.cz \
    --cc=krisman@kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-nfs@vger.kernel.org \
    --cc=miklos@szeredi.hu \
    --cc=torvalds@linux-foundation.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox