]> www.infradead.org Git - users/willy/pagecache.git/commitdiff
dissolve external_name.u into separate members
authorAl Viro <viro@zeniv.linux.org.uk>
Tue, 10 Dec 2024 01:03:33 +0000 (20:03 -0500)
committerAl Viro <viro@zeniv.linux.org.uk>
Tue, 28 Jan 2025 00:17:22 +0000 (19:17 -0500)
... and document the constraints on the layout.  Kept separate from
the previous commit to keep the noise separate from actual changes.
The reason for explicit __aligned() on ->name[] rather than relying
upon the alignment of the previous field is that the previous iteration
of that commit tried to save 4 bytes on 64bit by eliminating a hole
in there, which broke the assumptions in dentry_string_cmp().
Better spell it out and avoid the temptation for the future...

Reviewed-by: Jeff Layton <jlayton@kernel.org>
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/dcache.c

index f387dc97df864d3e00d12680881c354d34063589..f8d6a25577360bc2d06e8a29ce293bd352a05124 100644 (file)
@@ -295,12 +295,16 @@ static inline int dentry_cmp(const struct dentry *dentry, const unsigned char *c
        return dentry_string_cmp(cs, ct, tcount);
 }
 
+/*
+ * long names are allocated separately from dentry and never modified.
+ * Refcounted, freeing is RCU-delayed.  See take_dentry_name_snapshot()
+ * for the reason why ->count and ->head can't be combined into a union.
+ * dentry_string_cmp() relies upon ->name[] being word-aligned.
+ */
 struct external_name {
-       struct {
-               atomic_t count;         // ->count and ->head can't be combined
-               struct rcu_head head;   // see take_dentry_name_snapshot()
-       } u;
-       unsigned char name[];
+       atomic_t count;
+       struct rcu_head head;
+       unsigned char name[] __aligned(sizeof(unsigned long));
 };
 
 static inline struct external_name *external_name(struct dentry *dentry)
@@ -344,7 +348,7 @@ retry:
                struct external_name *p;
                p = container_of(s, struct external_name, name[0]);
                // get a valid reference
-               if (unlikely(!atomic_inc_not_zero(&p->u.count)))
+               if (unlikely(!atomic_inc_not_zero(&p->count)))
                        goto retry;
                name->name.name = s;
        }
@@ -361,8 +365,8 @@ void release_dentry_name_snapshot(struct name_snapshot *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)))
-                       kfree_rcu(p, u.head);
+               if (unlikely(atomic_dec_and_test(&p->count)))
+                       kfree_rcu(p, head);
        }
 }
 EXPORT_SYMBOL(release_dentry_name_snapshot);
@@ -400,7 +404,7 @@ static void dentry_free(struct dentry *dentry)
        WARN_ON(!hlist_unhashed(&dentry->d_u.d_alias));
        if (unlikely(dname_external(dentry))) {
                struct external_name *p = external_name(dentry);
-               if (likely(atomic_dec_and_test(&p->u.count))) {
+               if (likely(atomic_dec_and_test(&p->count))) {
                        call_rcu(&dentry->d_u.d_rcu, __d_free_external);
                        return;
                }
@@ -1681,7 +1685,7 @@ static struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
                        kmem_cache_free(dentry_cache, dentry); 
                        return NULL;
                }
-               atomic_set(&p->u.count, 1);
+               atomic_set(&p->count, 1);
                dname = p->name;
        } else  {
                dname = dentry->d_shortname.string;
@@ -2774,15 +2778,15 @@ static void copy_name(struct dentry *dentry, struct dentry *target)
        if (unlikely(dname_external(dentry)))
                old_name = external_name(dentry);
        if (unlikely(dname_external(target))) {
-               atomic_inc(&external_name(target)->u.count);
+               atomic_inc(&external_name(target)->count);
                dentry->d_name = target->d_name;
        } else {
                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)))
-               kfree_rcu(old_name, u.head);
+       if (old_name && likely(atomic_dec_and_test(&old_name->count)))
+               kfree_rcu(old_name, head);
 }
 
 /*