From 24261fc23db950951760d00c188ba63cc756b932 Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Fri, 8 Mar 2013 16:30:03 +0100 Subject: cifs: delay super block destruction until all cifsFileInfo objects are gone cifsFileInfo objects hold references to dentries and it is possible that these will still be around in workqueues when VFS decides to kill super block during unmount. This results in panics like this one: BUG: Dentry ffff88001f5e76c0{i=66b4a,n=1M-2} still in use (1) [unmount of cifs cifs] ------------[ cut here ]------------ kernel BUG at fs/dcache.c:943! [..] Process umount (pid: 1781, threadinfo ffff88003d6e8000, task ffff880035eeaec0) [..] Call Trace: [] shrink_dcache_for_umount+0x33/0x60 [] generic_shutdown_super+0x2c/0xe0 [] kill_anon_super+0x16/0x30 [] cifs_kill_sb+0x1a/0x30 [cifs] [] deactivate_locked_super+0x57/0x80 [] deactivate_super+0x4e/0x70 [] mntput_no_expire+0xd7/0x130 [] sys_umount+0x9c/0x3c0 [] system_call_fastpath+0x16/0x1b Fix this by making each cifsFileInfo object hold a reference to cifs super block, which implicitly keeps VFS super block around as well. Signed-off-by: Mateusz Guzik Reviewed-by: Jeff Layton Cc: Reported-and-Tested-by: Ben Greear Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'fs/cifs/cifsfs.c') diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 1a052c0eee8e..054b90b682a7 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -91,6 +91,30 @@ struct workqueue_struct *cifsiod_wq; __u8 cifs_client_guid[SMB2_CLIENT_GUID_SIZE]; #endif +/* + * Bumps refcount for cifs super block. + * Note that it should be only called if a referece to VFS super block is + * already held, e.g. in open-type syscalls context. Otherwise it can race with + * atomic_dec_and_test in deactivate_locked_super. + */ +void +cifs_sb_active(struct super_block *sb) +{ + struct cifs_sb_info *server = CIFS_SB(sb); + + if (atomic_inc_return(&server->active) == 1) + atomic_inc(&sb->s_active); +} + +void +cifs_sb_deactive(struct super_block *sb) +{ + struct cifs_sb_info *server = CIFS_SB(sb); + + if (atomic_dec_and_test(&server->active)) + deactivate_super(sb); +} + static int cifs_read_super(struct super_block *sb) { -- cgit v1.2.1