fs: report f_fsid from s_dev for "simple" filesystems
authorAmir Goldstein <amir73il@gmail.com>
Mon, 23 Oct 2023 14:30:49 +0000 (17:30 +0300)
committerChristian Brauner <brauner@kernel.org>
Sat, 28 Oct 2023 14:16:18 +0000 (16:16 +0200)
There are many "simple" filesystems (*) that report null f_fsid in
statfs(2).  Those "simple" filesystems report sb->s_dev as the st_dev
field of the stat syscalls for all inodes of the filesystem (**).

In order to enable fanotify reporting of events with fsid on those
"simple" filesystems, report the sb->s_dev number in f_fsid field of
statfs(2).

(*) For most of the "simple" filesystem refered to in this commit, the
->statfs() operation is simple_statfs(). Some of those fs assign the
simple_statfs() method directly in their ->s_op struct and some assign it
indirectly via a call to simple_fill_super() or to pseudo_fs_fill_super()
with either custom or "simple" s_op.
We also make the same change to efivarfs and hugetlbfs, although they do
not use simple_statfs(), because they use the simple_* inode opreations
(e.g. simple_lookup()).

(**) For most of the "simple" filesystems, the ->getattr() method is not
assigned, so stat() is implemented by generic_fillattr().  A few "simple"
filesystem use the simple_getattr() method which also calls
generic_fillattr() to fill most of the stat struct.

The two exceptions are procfs and 9p. procfs implements several different
->getattr() methods, but they all end up calling generic_fillattr() to
fill the st_dev field from sb->s_dev.

9p has more complicated ->getattr() methods, but they too, end up calling
generic_fillattr() to fill the st_dev field from sb->s_dev.

Note that 9p and kernfs also call simple_statfs() from custom ->statfs()
methods which already fill the f_fsid field, but v9fs_statfs() calls
simple_statfs() only in case f_fsid was not filled and kenrfs_statfs()
overwrites f_fsid after calling simple_statfs().

Link: https://lore.kernel.org/r/20230919094820.g5bwharbmy2dq46w@quack3/
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Link: https://lore.kernel.org/r/20231023143049.2944970-1-amir73il@gmail.com
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/efivarfs/super.c
fs/hugetlbfs/inode.c
fs/libfs.c

index 996271473609a0dbde8cd3db3eadb73e35d2510d..2933090ad11f2a8974a157824c41d4f44320b4f3 100644 (file)
@@ -30,6 +30,7 @@ static int efivarfs_statfs(struct dentry *dentry, struct kstatfs *buf)
                         EFI_VARIABLE_BOOTSERVICE_ACCESS |
                         EFI_VARIABLE_RUNTIME_ACCESS;
        u64 storage_space, remaining_space, max_variable_size;
+       u64 id = huge_encode_dev(dentry->d_sb->s_dev);
        efi_status_t status;
 
        /* Some UEFI firmware does not implement QueryVariableInfo() */
@@ -53,6 +54,7 @@ static int efivarfs_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_blocks   = storage_space;
        buf->f_bfree    = remaining_space;
        buf->f_type     = dentry->d_sb->s_magic;
+       buf->f_fsid     = u64_to_fsid(id);
 
        /*
         * In f_bavail we declare the free space that the kernel will allow writing
index 316c4cebd3f3de67e6aa049d7f6f51b17cd98d83..c003a27be6fe55d318940d1e24218b5dce2e029f 100644 (file)
@@ -1204,7 +1204,9 @@ static int hugetlbfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(dentry->d_sb);
        struct hstate *h = hstate_inode(d_inode(dentry));
+       u64 id = huge_encode_dev(dentry->d_sb->s_dev);
 
+       buf->f_fsid = u64_to_fsid(id);
        buf->f_type = HUGETLBFS_MAGIC;
        buf->f_bsize = huge_page_size(h);
        if (sbinfo) {
index 37f2d34ee090bd1230426045d8565bf72a82579b..8117b24b929dbdd7fcf14329daaa53bf08b7bae7 100644 (file)
@@ -41,6 +41,9 @@ EXPORT_SYMBOL(simple_getattr);
 
 int simple_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
+       u64 id = huge_encode_dev(dentry->d_sb->s_dev);
+
+       buf->f_fsid = u64_to_fsid(id);
        buf->f_type = dentry->d_sb->s_magic;
        buf->f_bsize = PAGE_SIZE;
        buf->f_namelen = NAME_MAX;