]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Rework file system group lookups 38340/head
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Fri, 25 Jul 2025 15:08:56 +0000 (17:08 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Sun, 27 Jul 2025 11:14:05 +0000 (13:14 +0200)
We want to check if the magic we got from statfs() is one of the magics listed
for one of the file systems in the given group. To do this, we'd iteratate over
the file system names, convert each name to an array of magics, and compare
those to the one we got. We were using gperf-generated lookup table for this,
so the string lookups were quick, but still this seems unnecessarily complex.
Let's just generate a simple lookup function, because we can:

$ src/basic/filesystem-sets.py fs-in-group
bool fs_in_group(const struct statfs *st, FilesystemGroups fs_group) {
        switch (fs_group) {
        case FILESYSTEM_SET_BASIC_API:
                return F_TYPE_EQUAL(st->f_type, CGROUP2_SUPER_MAGIC)
                    || F_TYPE_EQUAL(st->f_type, CGROUP_SUPER_MAGIC)
                    || F_TYPE_EQUAL(st->f_type, DEVPTS_SUPER_MAGIC)
                    || F_TYPE_EQUAL(st->f_type, MQUEUE_MAGIC)
                    || F_TYPE_EQUAL(st->f_type, PROC_SUPER_MAGIC)
                    || F_TYPE_EQUAL(st->f_type, SYSFS_MAGIC)
                    || F_TYPE_EQUAL(st->f_type, TMPFS_MAGIC);
        case FILESYSTEM_SET_ANONYMOUS:
                return F_TYPE_EQUAL(st->f_type, ANON_INODE_FS_MAGIC)
                    || F_TYPE_EQUAL(st->f_type, PIPEFS_MAGIC)
                    || F_TYPE_EQUAL(st->f_type, SOCKFS_MAGIC);
...

We flatten the nested lookup of group=>fs=>magic into a single level.
The compiler can work its magic here to make the lookup quick.

src/basic/filesystem-sets.py
src/basic/filesystems.c
src/basic/meson.build

index d374ac41ffe75e6eb7a54eccc7adbf8a7e789d90..7cf73aaefb881b3c82522e4080bcb40148e4a4ae 100755 (executable)
@@ -297,6 +297,23 @@ const char* fs_type_to_string(statfs_f_type_t magic) {
         return NULL;
 }""")
 
+def generate_fs_in_group():
+    print('bool fs_in_group(const struct statfs *st, FilesystemGroups fs_group) {')
+    print('        switch (fs_group) {')
+
+    for name, _, *filesystems in FILESYSTEM_SETS:
+        magics = sorted(set(sum((NAME_TO_MAGIC[fs] for fs in filesystems),
+                                start=[])))
+        enum = 'FILESYSTEM_SET_' + name[1:].upper().replace('-', '_')
+        print(f'        case {enum}:')
+        opts = '\n                    || '.join(f'F_TYPE_EQUAL(st->f_type, {magic})'
+                                                for magic in magics)
+        print(f'                return {opts};')
+
+    print('        default: assert_not_reached();')
+    print('        }')
+    print('}')
+
 def generate_filesystem_sets():
     print('const FilesystemSet filesystem_sets[_FILESYSTEM_SET_MAX] = {')
 
@@ -346,6 +363,8 @@ if __name__ == '__main__':
             generate_fs_type_to_string()
         elif arg == 'filesystem-sets':
             generate_filesystem_sets()
+        elif arg == 'fs-in-group':
+            generate_fs_in_group()
         elif arg == 'check':
             check()
         else:
index 2bbab151bb3ab00b25322cba7e9ad2c468cc3348..cd2789e32944fd364505502f8cfc0c034fd04626 100644 (file)
@@ -19,26 +19,6 @@ int fs_type_from_string(const char *name, const statfs_f_type_t **ret) {
         return 0;
 }
 
-bool fs_in_group(const struct statfs *s, FilesystemGroups fs_group) {
-        int r;
-
-        NULSTR_FOREACH(fs, filesystem_sets[fs_group].value) {
-                const statfs_f_type_t *magic;
-
-                r = fs_type_from_string(fs, &magic);
-                if (r >= 0)
-                        for (size_t i = 0; i < FILESYSTEM_MAGIC_MAX; i++) {
-                                if (magic[i] == 0)
-                                        break;
-
-                                if (is_fs_type(s, magic[i]))
-                                        return true;
-                        }
-        }
-
-        return false;
-}
-
 const FilesystemSet* filesystem_set_find(const char *name) {
         if (isempty(name) || name[0] != '@')
                 return NULL;
index 6589ce29955e5651142d72c86ecc8d42f40b7329..79af468381fc2e6e531fa5ddd072150ed72f68bc 100644 (file)
@@ -173,7 +173,8 @@ filesystem_sets_c = custom_target(
         output : 'filesystem-sets.c',
         command : [filesystem_sets_py,
                    'fs-type-to-string',
-                   'filesystem-sets'],
+                   'filesystem-sets',
+                   'fs-in-group'],
         capture : true)
 
 filesystems_gperf_gperf = custom_target(