Commit 38feb080 authored by Mateusz Guzik's avatar Mateusz Guzik Committed by Greg Kroah-Hartman

cifs: delay super block destruction until all cifsFileInfo objects are gone

commit 24261fc2 upstream.

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:
 [<ffffffff811b44f3>] shrink_dcache_for_umount+0x33/0x60
 [<ffffffff8119f7fc>] generic_shutdown_super+0x2c/0xe0
 [<ffffffff8119f946>] kill_anon_super+0x16/0x30
 [<ffffffffa036623a>] cifs_kill_sb+0x1a/0x30 [cifs]
 [<ffffffff8119fcc7>] deactivate_locked_super+0x57/0x80
 [<ffffffff811a085e>] deactivate_super+0x4e/0x70
 [<ffffffff811bb417>] mntput_no_expire+0xd7/0x130
 [<ffffffff811bc30c>] sys_umount+0x9c/0x3c0
 [<ffffffff81657c19>] 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: default avatarMateusz Guzik <mguzik@redhat.com>
Reviewed-by: default avatarJeff Layton <jlayton@redhat.com>
Reported-and-Tested-by: default avatarBen Greear <greearb@candelatech.com>
Signed-off-by: default avatarSteve French <sfrench@us.ibm.com>
[bwh: Backported to 3.2: adjust context]
Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
[xr: Backported to 3.4: adjust context]
Signed-off-by: default avatarRui Xiang <rui.xiang@huawei.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 9b67aeff
...@@ -87,6 +87,30 @@ extern mempool_t *cifs_mid_poolp; ...@@ -87,6 +87,30 @@ extern mempool_t *cifs_mid_poolp;
struct workqueue_struct *cifsiod_wq; struct workqueue_struct *cifsiod_wq;
/*
* 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 static int
cifs_read_super(struct super_block *sb) cifs_read_super(struct super_block *sb)
{ {
......
...@@ -41,6 +41,10 @@ extern struct file_system_type cifs_fs_type; ...@@ -41,6 +41,10 @@ extern struct file_system_type cifs_fs_type;
extern const struct address_space_operations cifs_addr_ops; extern const struct address_space_operations cifs_addr_ops;
extern const struct address_space_operations cifs_addr_ops_smallbuf; extern const struct address_space_operations cifs_addr_ops_smallbuf;
/* Functions related to super block operations */
extern void cifs_sb_active(struct super_block *sb);
extern void cifs_sb_deactive(struct super_block *sb);
/* Functions related to inodes */ /* Functions related to inodes */
extern const struct inode_operations cifs_dir_inode_ops; extern const struct inode_operations cifs_dir_inode_ops;
extern struct inode *cifs_root_iget(struct super_block *); extern struct inode *cifs_root_iget(struct super_block *);
......
...@@ -265,6 +265,8 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file, ...@@ -265,6 +265,8 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file,
mutex_init(&pCifsFile->fh_mutex); mutex_init(&pCifsFile->fh_mutex);
INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break); INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break);
cifs_sb_active(inode->i_sb);
spin_lock(&cifs_file_list_lock); spin_lock(&cifs_file_list_lock);
list_add(&pCifsFile->tlist, &(tlink_tcon(tlink)->openFileList)); list_add(&pCifsFile->tlist, &(tlink_tcon(tlink)->openFileList));
/* if readable file instance put first in list*/ /* if readable file instance put first in list*/
...@@ -293,7 +295,8 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file) ...@@ -293,7 +295,8 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
struct inode *inode = cifs_file->dentry->d_inode; struct inode *inode = cifs_file->dentry->d_inode;
struct cifs_tcon *tcon = tlink_tcon(cifs_file->tlink); struct cifs_tcon *tcon = tlink_tcon(cifs_file->tlink);
struct cifsInodeInfo *cifsi = CIFS_I(inode); struct cifsInodeInfo *cifsi = CIFS_I(inode);
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct super_block *sb = inode->i_sb;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifsLockInfo *li, *tmp; struct cifsLockInfo *li, *tmp;
spin_lock(&cifs_file_list_lock); spin_lock(&cifs_file_list_lock);
...@@ -345,6 +348,7 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file) ...@@ -345,6 +348,7 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
cifs_put_tlink(cifs_file->tlink); cifs_put_tlink(cifs_file->tlink);
dput(cifs_file->dentry); dput(cifs_file->dentry);
cifs_sb_deactive(sb);
kfree(cifs_file); kfree(cifs_file);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment