* [PATCH] quota: initialize dquot cache before mounting rootfs
@ 2026-10-15 18:36 YouYou Yu
2026-10-19 10:44 ` Jan Kara
0 siblings, 1 reply; 3+ messages in thread
From: YouYou Yu @ 2026-10-15 18:36 UTC (permalink / raw)
To: Christian Brauner, Jan Kara
Cc: Alexander Viro, Lichen Liu, Dylan Johnson, linux-fsdevel,
linux-kernel, Gunnar Kudrjavets
Booting with CONFIG_TMPFS_QUOTA=y, an initramfs, no root= and
"initramfs_options=usrquota" panics at boot:
BUG: kernel NULL pointer dereference, address: 0000000000000000
RIP: 0010:dqget+0x1ac/0x490
Call Trace:
__dquot_initialize
dquot_initialize
shmem_get_inode
shmem_fill_super
...
mnt_init
vfs_caches_init
start_kernel
The rootfs is mounted from mnt_init(), but the dquot hash table and
cache are only set up later by dquot_init(), an fs_initcall. Creating
the root inode of a quota enabled rootfs thus dereferences the NULL
dquot_hash in dqget().
Rename dquot_init() to dquot_cache_init() and call it from
vfs_caches_init() before mnt_init(). The slab, percpu and early
workqueue code it relies on is available there, and the workqueue
rescuer and shrinker debugfs entries are set up later by their own
subsystems. Keep the sysctl registration in an fs_initcall, as done
for the dcache, inode and mount sysctls. This only moves existing
allocations earlier in boot.
Fixes: 278033a225e1 ("fs: Add 'initramfs_options' to set initramfs mount options")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Co-developed-by: Dylan Johnson <dgj@amazon.com>
Signed-off-by: Dylan Johnson <dgj@amazon.com>
Signed-off-by: YouYou Yu <youyouyu@amazon.com>
Reviewed-by: Gunnar Kudrjavets <gunnarku@amazon.com>
---
Notes:
Tested on v7.3-rc7, x86_64 QEMU/KVM, booting from an initramfs without root=:
- without this patch, initramfs_options=usrquota panics in dqget() as above
- with it, initramfs_options=usrquota,grpquota,usrquota_block_hardlimit=10M
boots, rootfs is mounted with quotas, and a non-root user is limited to
10M on rootfs
- /sys/kernel/slab/dquot, the quota_events_unbound rescuer, the fs/quota
sysctls and (with CONFIG_SHRINKER_DEBUG) the dquota-cache shrinker
debugfs entry are all created as expected
An LLM (Claude Opus 5.5) helped drafting this changelog.
I reviewed the change and ran the tests above.
fs/dcache.c | 2 ++
fs/quota/dquot.c | 10 ++++++----
include/linux/quotaops.h | 5 +++++
3 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/fs/dcache.c b/fs/dcache.c
index f44c7b39c3b..b208cbdda0f 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -32,6 +32,7 @@
#include <linux/bit_spinlock.h>
#include <linux/rculist_bl.h>
#include <linux/list_lru.h>
+#include <linux/quotaops.h>
#include "internal.h"
#include "mount.h"
@@ -3525,6 +3526,7 @@ void __init vfs_caches_init(void)
inode_init();
files_init();
files_maxfiles_init();
+ dquot_cache_init();
mnt_init();
bdev_cache_init();
chrdev_init();
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 1c78c695d0d..cd142c9cc7e 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -2942,7 +2942,7 @@ static const struct ctl_table fs_dqstats_table[] = {
},
};
-static int __init dquot_init(void)
+void __init dquot_cache_init(void)
{
int i, ret;
unsigned long nr_hash;
@@ -2950,8 +2950,6 @@ static int __init dquot_init(void)
printk(KERN_NOTICE "VFS: Disk quotas %s\n", __DQUOT_VERSION__);
- register_sysctl_init("fs/quota", fs_dqstats_table);
-
dquot_cachep = kmem_cache_create("dquot",
sizeof(struct dquot), sizeof(unsigned long) * 4,
(SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
@@ -2992,7 +2990,11 @@ static int __init dquot_init(void)
WQ_UNBOUND | WQ_MEM_RECLAIM, WQ_MAX_ACTIVE);
if (!quota_unbound_wq)
panic("Cannot create quota_unbound_wq\n");
+}
+static int __init init_fs_dquot_sysctls(void)
+{
+ register_sysctl_init("fs/quota", fs_dqstats_table);
return 0;
}
-fs_initcall(dquot_init);
+fs_initcall(init_fs_dquot_sysctls);
diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h
index f9c0f9d7c9d..bbe22c22439 100644
--- a/include/linux/quotaops.h
+++ b/include/linux/quotaops.h
@@ -40,6 +40,7 @@ void __quota_error(struct super_block *sb, const char *func,
/*
* declaration of quota_function calls in kernel.
*/
+void dquot_cache_init(void);
int dquot_initialize(struct inode *inode);
bool dquot_initialize_needed(struct inode *inode);
void dquot_drop(struct inode *inode);
@@ -206,6 +207,10 @@ static inline int sb_has_quota_active(struct super_block *sb, int type)
return 0;
}
+static inline void dquot_cache_init(void)
+{
+}
+
static inline int dquot_initialize(struct inode *inode)
{
return 0;
base-commit: 7c6f8a2841d4eeeceacf42689cd2717fe76d9f7c
--
2.47.3
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [PATCH] quota: initialize dquot cache before mounting rootfs
2026-10-15 18:36 [PATCH] quota: initialize dquot cache before mounting rootfs YouYou Yu
@ 2026-10-19 10:44 ` Jan Kara
2026-10-20 21:52 ` YouYou Yu
0 siblings, 1 reply; 3+ messages in thread
From: Jan Kara @ 2026-10-19 10:44 UTC (permalink / raw)
To: YouYou Yu
Cc: Christian Brauner, Jan Kara, Alexander Viro, Lichen Liu,
Dylan Johnson, linux-fsdevel, linux-kernel, Gunnar Kudrjavets
On Thu 15-10-26 18:36:08, YouYou Yu wrote:
> Booting with CONFIG_TMPFS_QUOTA=y, an initramfs, no root= and
> "initramfs_options=usrquota" panics at boot:
>
> BUG: kernel NULL pointer dereference, address: 0000000000000000
> RIP: 0010:dqget+0x1ac/0x490
> Call Trace:
> __dquot_initialize
> dquot_initialize
> shmem_get_inode
> shmem_fill_super
> ...
> mnt_init
> vfs_caches_init
> start_kernel
>
> The rootfs is mounted from mnt_init(), but the dquot hash table and
> cache are only set up later by dquot_init(), an fs_initcall. Creating
> the root inode of a quota enabled rootfs thus dereferences the NULL
> dquot_hash in dqget().
>
> Rename dquot_init() to dquot_cache_init() and call it from
> vfs_caches_init() before mnt_init(). The slab, percpu and early
> workqueue code it relies on is available there, and the workqueue
> rescuer and shrinker debugfs entries are set up later by their own
> subsystems. Keep the sysctl registration in an fs_initcall, as done
> for the dcache, inode and mount sysctls. This only moves existing
> allocations earlier in boot.
>
> Fixes: 278033a225e1 ("fs: Add 'initramfs_options' to set initramfs mount options")
> Cc: stable@vger.kernel.org
> Assisted-by: LLM
> Co-developed-by: Dylan Johnson <dgj@amazon.com>
> Signed-off-by: Dylan Johnson <dgj@amazon.com>
> Signed-off-by: YouYou Yu <youyouyu@amazon.com>
> Reviewed-by: Gunnar Kudrjavets <gunnarku@amazon.com>
Dunno, I'd say: "don't do it when it hurts"... I definitely don't think
anybody sane wants quotas on initramfs. Is this just a fuzzing result or
are you really interested in that functionality?
Instead of pulling quota into early boot I'd just refuse tmpfs mount in
this case (same result as original behavior but clearer error message :)).
Honza
> ---
>
> Notes:
> Tested on v7.3-rc7, x86_64 QEMU/KVM, booting from an initramfs without root=:
> - without this patch, initramfs_options=usrquota panics in dqget() as above
> - with it, initramfs_options=usrquota,grpquota,usrquota_block_hardlimit=10M
> boots, rootfs is mounted with quotas, and a non-root user is limited to
> 10M on rootfs
> - /sys/kernel/slab/dquot, the quota_events_unbound rescuer, the fs/quota
> sysctls and (with CONFIG_SHRINKER_DEBUG) the dquota-cache shrinker
> debugfs entry are all created as expected
>
> An LLM (Claude Opus 5.5) helped drafting this changelog.
> I reviewed the change and ran the tests above.
>
> fs/dcache.c | 2 ++
> fs/quota/dquot.c | 10 ++++++----
> include/linux/quotaops.h | 5 +++++
> 3 files changed, 13 insertions(+), 4 deletions(-)
>
> diff --git a/fs/dcache.c b/fs/dcache.c
> index f44c7b39c3b..b208cbdda0f 100644
> --- a/fs/dcache.c
> +++ b/fs/dcache.c
> @@ -32,6 +32,7 @@
> #include <linux/bit_spinlock.h>
> #include <linux/rculist_bl.h>
> #include <linux/list_lru.h>
> +#include <linux/quotaops.h>
> #include "internal.h"
> #include "mount.h"
>
> @@ -3525,6 +3526,7 @@ void __init vfs_caches_init(void)
> inode_init();
> files_init();
> files_maxfiles_init();
> + dquot_cache_init();
> mnt_init();
> bdev_cache_init();
> chrdev_init();
> diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
> index 1c78c695d0d..cd142c9cc7e 100644
> --- a/fs/quota/dquot.c
> +++ b/fs/quota/dquot.c
> @@ -2942,7 +2942,7 @@ static const struct ctl_table fs_dqstats_table[] = {
> },
> };
>
> -static int __init dquot_init(void)
> +void __init dquot_cache_init(void)
> {
> int i, ret;
> unsigned long nr_hash;
> @@ -2950,8 +2950,6 @@ static int __init dquot_init(void)
>
> printk(KERN_NOTICE "VFS: Disk quotas %s\n", __DQUOT_VERSION__);
>
> - register_sysctl_init("fs/quota", fs_dqstats_table);
> -
> dquot_cachep = kmem_cache_create("dquot",
> sizeof(struct dquot), sizeof(unsigned long) * 4,
> (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
> @@ -2992,7 +2990,11 @@ static int __init dquot_init(void)
> WQ_UNBOUND | WQ_MEM_RECLAIM, WQ_MAX_ACTIVE);
> if (!quota_unbound_wq)
> panic("Cannot create quota_unbound_wq\n");
> +}
>
> +static int __init init_fs_dquot_sysctls(void)
> +{
> + register_sysctl_init("fs/quota", fs_dqstats_table);
> return 0;
> }
> -fs_initcall(dquot_init);
> +fs_initcall(init_fs_dquot_sysctls);
> diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h
> index f9c0f9d7c9d..bbe22c22439 100644
> --- a/include/linux/quotaops.h
> +++ b/include/linux/quotaops.h
> @@ -40,6 +40,7 @@ void __quota_error(struct super_block *sb, const char *func,
> /*
> * declaration of quota_function calls in kernel.
> */
> +void dquot_cache_init(void);
> int dquot_initialize(struct inode *inode);
> bool dquot_initialize_needed(struct inode *inode);
> void dquot_drop(struct inode *inode);
> @@ -206,6 +207,10 @@ static inline int sb_has_quota_active(struct super_block *sb, int type)
> return 0;
> }
>
> +static inline void dquot_cache_init(void)
> +{
> +}
> +
> static inline int dquot_initialize(struct inode *inode)
> {
> return 0;
>
> base-commit: 7c6f8a2841d4eeeceacf42689cd2717fe76d9f7c
> --
> 2.47.3
>
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [PATCH] quota: initialize dquot cache before mounting rootfs
2026-10-19 10:44 ` Jan Kara
@ 2026-10-20 21:52 ` YouYou Yu
0 siblings, 0 replies; 3+ messages in thread
From: YouYou Yu @ 2026-10-20 21:52 UTC (permalink / raw)
To: jack
Cc: brauner, dgj, gunnarku, lichliu, linux-fsdevel, linux-kernel,
viro, youyouyu
Hi Jan,
Thanks for reviewing.
On Mon, 19 Oct 2026 12:44:49 +0200, Jan Kara wrote:
> I definitely don't think anybody sane wants quotas on initramfs. Is this
> just a fuzzing result or are you really interested in that functionality?
The truth is it's not a fuzzing result, we are really interested in it.
We run systems that extensively use rootfs and we want to limit per user
usage on it the same way tmpfs quotas allow on any other tmpfs mount.
> Instead of pulling quota into early boot I'd just refuse tmpfs mount in
> this case (same result as original behavior but clearer error message :)).
Refusing the mount would avoid the crash, but rootfs would then be
the only tmpfs instance where quotas can't be used, even though
initramfs_options= exists to pass mount options to it. That said, if
initializing this earlier is a concern, I'm happy to rework the patch
if you have a preferred approach.
Thanks,
YouYou
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-10-20 21:52 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-15 18:36 [PATCH] quota: initialize dquot cache before mounting rootfs YouYou Yu
2026-10-19 10:44 ` Jan Kara
2026-10-20 21:52 ` YouYou Yu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®