smb: client: fix (remove) drop_dir_cache module parameter#178
Conversation
Being a module parameter, it's possible to do: # modprobe cifs drop_dir_cache=1 Which will lead to a crash, because cifs_tcp_ses_list hasn't been initialized yet: [ 168.242624] BUG: kernel NULL pointer dereference, address: 0000000000000010 [ 168.242952] #PF: supervisor read access in kernel mode [ 168.243175] #PF: error_code(0x0000) - not-present page [ 168.243394] PGD 0 P4D 0 [ 168.243524] Oops: Oops: 0000 [#1] SMP NOPTI [ 168.243703] CPU: 2 UID: 0 PID: 1105 Comm: modprobe Not tainted 7.0.0-lku #5 PREEMPT(lazy) [ 168.244054] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.17.0-2-g4f253b9b-prebuilt.qemu.org 04/01/2014 [ 168.244557] RIP: 0010:cifs_param_set_drop_dir_cache+0x7c/0x100 [cifs] ... [ 168.248785] Call Trace: [ 168.248915] <TASK> [ 168.249023] parse_args+0x285/0x3a0 [ 168.249204] ? __pfx_unknown_module_param_cb+0x10/0x10 [ 168.249448] load_module+0x192b/0x1bb0 [ 168.249637] ? __pfx_unknown_module_param_cb+0x10/0x10 [ 168.249882] ? kernel_read_file+0x27d/0x2b0 [ 168.250088] init_module_from_file+0xce/0xf0 [ 168.250291] idempotent_init_module+0xfb/0x2f0 [ 168.250496] __x64_sys_finit_module+0x5a/0xa0 [ 168.250694] do_syscall_64+0xe0/0x5a0 [ 168.250863] ? exc_page_fault+0x65/0x160 [ 168.251050] entry_SYSCALL_64_after_hwframe+0x77/0x7f [ 168.251284] RIP: 0033:0x7fcaa12b774d Instead of fixing this with some kind of "is module initialized" approach, this patch instead moves that functionality to procfs, setting a write op for the existing open_dirs entry, where writing a 0 to it will drop the cached directory entries. Also make it available only when CONFIG_CIFS_DEBUG=y. A small change needed now is to not call flush_delayed_work() on invalidate_all_cached_dirs() when called from procfs (can't sleep in that context). So add a @sync arg to invalidate_all_cached_dirs() to control when to flush the delayed works. Fixes: dde6667 ("smb: client: add drop_dir_cache module parameter to invalidate cached dirents") Signed-off-by: Enzo Matsumiya <ematsumiya@suse.de> Signed-off-by: Steve French <stfrench@microsoft.com>
There was a problem hiding this comment.
Pull request overview
This PR removes the drop_dir_cache CIFS module parameter (which can be invoked during modprobe before global CIFS lists are initialized, causing a crash) and replaces the functionality with a procfs-triggered cache drop via /proc/fs/cifs/open_dirs (debug-only), plus a small API tweak to avoid sleeping in that path.
Changes:
- Remove the
drop_dir_cachemodule parameter and its traversal ofcifs_tcp_ses_list. - Add an optional write handler for
/proc/fs/cifs/open_dirsto trigger dropping cached directory entries (debug builds). - Extend
invalidate_all_cached_dirs()with asyncflag to avoidflush_delayed_work()in the procfs-triggered path, and update call sites accordingly.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| fs/smb/client/smb2pdu.c | Updates invalidate_all_cached_dirs() call to pass sync=true. |
| fs/smb/client/file.c | Updates invalidate_all_cached_dirs() call to pass sync=true. |
| fs/smb/client/cifsfs.c | Removes the drop_dir_cache module parameter implementation. |
| fs/smb/client/cifs_debug.c | Adds procfs write support for open_dirs to drop cached dir entries (debug-only), and updates proc creation. |
| fs/smb/client/cached_dir.h | Updates invalidate_all_cached_dirs() prototype to include bool sync. |
| fs/smb/client/cached_dir.c | Adds sync parameter and conditionally flushes delayed work. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| #ifdef CONFIG_CIFS_DEBUG | ||
| seq_puts(m, "# Write 0 to this file to drop all cached directory entries\n"); | ||
| #endif /* CONFIG_CIFS_DEBUG */ |
There was a problem hiding this comment.
cifs_debug_dirs_proc_show() prints "Write 0 to this file to drop..." under CONFIG_CIFS_DEBUG, but in the current diff the proc entry is only made writable under CONFIG_CIFS_DEBUG2 (and otherwise is created read-only). This makes the header misleading in the common CIFS_DEBUG=y, CIFS_DEBUG2=n configuration. Please gate this line on the same condition that actually enables .proc_write (or make the proc entry writable under CONFIG_CIFS_DEBUG as intended).
| #ifdef CONFIG_CIFS_DEBUG | |
| seq_puts(m, "# Write 0 to this file to drop all cached directory entries\n"); | |
| #endif /* CONFIG_CIFS_DEBUG */ | |
| #ifdef CONFIG_CIFS_DEBUG2 | |
| seq_puts(m, "# Write 0 to this file to drop all cached directory entries\n"); | |
| #endif /* CONFIG_CIFS_DEBUG2 */ |
| #ifdef CONFIG_CIFS_DEBUG2 | ||
| proc_create("open_dirs", 0644, proc_fs_cifs, &cifs_debug_dirs_proc_ops); | ||
| #else /* CONFIG_CIFS_DEBUG2 */ | ||
| proc_create_single("open_dirs", 0400, proc_fs_cifs, cifs_debug_dirs_proc_show); | ||
| #endif /* !CONFIG_CIFS_DEBUG2 */ |
There was a problem hiding this comment.
cifs_proc_init() creates /proc/fs/cifs/open_dirs with the writable proc_ops only under CONFIG_CIFS_DEBUG2, but the new write/drop-cache functionality is described as being available when CONFIG_CIFS_DEBUG=y. With CIFS_DEBUG=y and CIFS_DEBUG2=n, the file remains proc_create_single(..., 0400, ...) (read-only) even though cifs_debug_dirs_proc_show() advertises that writing 0 will drop caches. Please align the Kconfig guard(s) so the writable version is created whenever the feature is compiled in (likely CONFIG_CIFS_DEBUG).
| #ifdef CONFIG_CIFS_DEBUG2 | |
| proc_create("open_dirs", 0644, proc_fs_cifs, &cifs_debug_dirs_proc_ops); | |
| #else /* CONFIG_CIFS_DEBUG2 */ | |
| proc_create_single("open_dirs", 0400, proc_fs_cifs, cifs_debug_dirs_proc_show); | |
| #endif /* !CONFIG_CIFS_DEBUG2 */ | |
| #ifdef CONFIG_CIFS_DEBUG | |
| proc_create("open_dirs", 0644, proc_fs_cifs, &cifs_debug_dirs_proc_ops); | |
| #else /* CONFIG_CIFS_DEBUG */ | |
| proc_create_single("open_dirs", 0400, proc_fs_cifs, cifs_debug_dirs_proc_show); | |
| #endif /* !CONFIG_CIFS_DEBUG */ |
| cifs_debug_dirs_proc_show); | ||
|
|
||
| #ifdef CONFIG_CIFS_DEBUG2 | ||
| proc_create("open_dirs", 0644, proc_fs_cifs, &cifs_debug_dirs_proc_ops); |
There was a problem hiding this comment.
/proc/fs/cifs/open_dirs switches from 0400 to 0644 in the CONFIG_CIFS_DEBUG2 branch. This makes the cached directory paths and related identifiers world-readable, which is a behavior change compared to open_files (still 0400) and the prior open_dirs permissions. If the intent is to allow cache dropping via writes, consider using a root-only mode (e.g. 0600) so adding a write capability doesn't also broaden read access.
| proc_create("open_dirs", 0644, proc_fs_cifs, &cifs_debug_dirs_proc_ops); | |
| proc_create("open_dirs", 0600, proc_fs_cifs, &cifs_debug_dirs_proc_ops); |
Being a module parameter, it's possible to do:
modprobe cifs drop_dir_cache=1
Which will lead to a crash, because cifs_tcp_ses_list hasn't been initialized yet:
[ 168.242624] BUG: kernel NULL pointer dereference, address: 0000000000000010
[ 168.242952] #PF: supervisor read access in kernel mode
[ 168.243175] #PF: error_code(0x0000) - not-present page
[ 168.243394] PGD 0 P4D 0
[ 168.243524] Oops: Oops: 0000 [#1] SMP NOPTI
[ 168.243703] CPU: 2 UID: 0 PID: 1105 Comm: modprobe Not tainted 7.0.0-lku #5 PREEMPT(lazy)
[ 168.244054] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.17.0-2-g4f253b9b-prebuilt.qemu.org 04/01/2014
[ 168.244557] RIP: 0010:cifs_param_set_drop_dir_cache+0x7c/0x100 [cifs]
...
[ 168.248785] Call Trace:
[ 168.248915]
[ 168.249023] parse_args+0x285/0x3a0
[ 168.249204] ? __pfx_unknown_module_param_cb+0x10/0x10
[ 168.249448] load_module+0x192b/0x1bb0
[ 168.249637] ? __pfx_unknown_module_param_cb+0x10/0x10
[ 168.249882] ? kernel_read_file+0x27d/0x2b0
[ 168.250088] init_module_from_file+0xce/0xf0
[ 168.250291] idempotent_init_module+0xfb/0x2f0
[ 168.250496] __x64_sys_finit_module+0x5a/0xa0
[ 168.250694] do_syscall_64+0xe0/0x5a0
[ 168.250863] ? exc_page_fault+0x65/0x160
[ 168.251050] entry_SYSCALL_64_after_hwframe+0x77/0x7f
[ 168.251284] RIP: 0033:0x7fcaa12b774d
Instead of fixing this with some kind of "is module initialized" approach, this patch instead moves that functionality to procfs, setting a write op for the existing open_dirs entry, where writing a 0 to it will drop the cached directory entries.
Also make it available only when CONFIG_CIFS_DEBUG=y.
A small change needed now is to not call flush_delayed_work() on invalidate_all_cached_dirs() when called from procfs (can't sleep in that context).
So add a @sync arg to invalidate_all_cached_dirs() to control when to flush the delayed works.
Fixes: dde6667 ("smb: client: add drop_dir_cache module parameter to invalidate cached dirents")