kernel-hacking-2024-linux-s.../fs/cifs
Rabin Vincent 3998e6b87d CIFS: fix oplock break deadlocks
When the final cifsFileInfo_put() is called from cifsiod and an oplock
break work is queued, lockdep complains loudly:

 =============================================
 [ INFO: possible recursive locking detected ]
 4.11.0+ #21 Not tainted
 ---------------------------------------------
 kworker/0:2/78 is trying to acquire lock:
  ("cifsiod"){++++.+}, at: flush_work+0x215/0x350

 but task is already holding lock:
  ("cifsiod"){++++.+}, at: process_one_work+0x255/0x8e0

 other info that might help us debug this:
  Possible unsafe locking scenario:

        CPU0
        ----
   lock("cifsiod");
   lock("cifsiod");

  *** DEADLOCK ***

  May be due to missing lock nesting notation

 2 locks held by kworker/0:2/78:
  #0:  ("cifsiod"){++++.+}, at: process_one_work+0x255/0x8e0
  #1:  ((&wdata->work)){+.+...}, at: process_one_work+0x255/0x8e0

 stack backtrace:
 CPU: 0 PID: 78 Comm: kworker/0:2 Not tainted 4.11.0+ #21
 Workqueue: cifsiod cifs_writev_complete
 Call Trace:
  dump_stack+0x85/0xc2
  __lock_acquire+0x17dd/0x2260
  ? match_held_lock+0x20/0x2b0
  ? trace_hardirqs_off_caller+0x86/0x130
  ? mark_lock+0xa6/0x920
  lock_acquire+0xcc/0x260
  ? lock_acquire+0xcc/0x260
  ? flush_work+0x215/0x350
  flush_work+0x236/0x350
  ? flush_work+0x215/0x350
  ? destroy_worker+0x170/0x170
  __cancel_work_timer+0x17d/0x210
  ? ___preempt_schedule+0x16/0x18
  cancel_work_sync+0x10/0x20
  cifsFileInfo_put+0x338/0x7f0
  cifs_writedata_release+0x2a/0x40
  ? cifs_writedata_release+0x2a/0x40
  cifs_writev_complete+0x29d/0x850
  ? preempt_count_sub+0x18/0xd0
  process_one_work+0x304/0x8e0
  worker_thread+0x9b/0x6a0
  kthread+0x1b2/0x200
  ? process_one_work+0x8e0/0x8e0
  ? kthread_create_on_node+0x40/0x40
  ret_from_fork+0x31/0x40

This is a real warning.  Since the oplock is queued on the same
workqueue this can deadlock if there is only one worker thread active
for the workqueue (which will be the case during memory pressure when
the rescuer thread is handling it).

Furthermore, there is at least one other kind of hang possible due to
the oplock break handling if there is only worker.  (This can be
reproduced without introducing memory pressure by having passing 1 for
the max_active parameter of cifsiod.) cifs_oplock_break() can wait
indefintely in the filemap_fdatawait() while the cifs_writev_complete()
work is blocked:

 sysrq: SysRq : Show Blocked State
   task                        PC stack   pid father
 kworker/0:1     D    0    16      2 0x00000000
 Workqueue: cifsiod cifs_oplock_break
 Call Trace:
  __schedule+0x562/0xf40
  ? mark_held_locks+0x4a/0xb0
  schedule+0x57/0xe0
  io_schedule+0x21/0x50
  wait_on_page_bit+0x143/0x190
  ? add_to_page_cache_lru+0x150/0x150
  __filemap_fdatawait_range+0x134/0x190
  ? do_writepages+0x51/0x70
  filemap_fdatawait_range+0x14/0x30
  filemap_fdatawait+0x3b/0x40
  cifs_oplock_break+0x651/0x710
  ? preempt_count_sub+0x18/0xd0
  process_one_work+0x304/0x8e0
  worker_thread+0x9b/0x6a0
  kthread+0x1b2/0x200
  ? process_one_work+0x8e0/0x8e0
  ? kthread_create_on_node+0x40/0x40
  ret_from_fork+0x31/0x40
 dd              D    0   683    171 0x00000000
 Call Trace:
  __schedule+0x562/0xf40
  ? mark_held_locks+0x29/0xb0
  schedule+0x57/0xe0
  io_schedule+0x21/0x50
  wait_on_page_bit+0x143/0x190
  ? add_to_page_cache_lru+0x150/0x150
  __filemap_fdatawait_range+0x134/0x190
  ? do_writepages+0x51/0x70
  filemap_fdatawait_range+0x14/0x30
  filemap_fdatawait+0x3b/0x40
  filemap_write_and_wait+0x4e/0x70
  cifs_flush+0x6a/0xb0
  filp_close+0x52/0xa0
  __close_fd+0xdc/0x150
  SyS_close+0x33/0x60
  entry_SYSCALL_64_fastpath+0x1f/0xbe

 Showing all locks held in the system:
 2 locks held by kworker/0:1/16:
  #0:  ("cifsiod"){.+.+.+}, at: process_one_work+0x255/0x8e0
  #1:  ((&cfile->oplock_break)){+.+.+.}, at: process_one_work+0x255/0x8e0

 Showing busy workqueues and worker pools:
 workqueue cifsiod: flags=0xc
   pwq 0: cpus=0 node=0 flags=0x0 nice=0 active=1/1
     in-flight: 16:cifs_oplock_break
     delayed: cifs_writev_complete, cifs_echo_request
 pool 0: cpus=0 node=0 flags=0x0 nice=0 hung=0s workers=3 idle: 750 3

Fix these problems by creating a a new workqueue (with a rescuer) for
the oplock break work.

Signed-off-by: Rabin Vincent <rabinv@axis.com>
Signed-off-by: Steve French <smfrench@gmail.com>
CC: Stable <stable@vger.kernel.org>
2017-05-03 10:10:10 -05:00
..
asn1.c
cache.c
cifs_debug.c Replace <asm/uaccess.h> with <linux/uaccess.h> globally 2016-12-24 11:46:01 -08:00
cifs_debug.h
cifs_dfs_ref.c CIFS: add build_path_from_dentry_optional_prefix() 2017-03-01 22:26:10 -06:00
cifs_fs_sb.h cifs: Convert to separately allocated bdi 2017-04-20 12:09:55 -06:00
cifs_ioctl.h Enable previous version support 2016-10-13 19:48:11 -05:00
cifs_spnego.c
cifs_spnego.h
cifs_unicode.c
cifs_unicode.h CIFS: Fix sparse warnings 2017-03-02 23:11:54 -06:00
cifs_uniupr.h
cifsacl.c CIFS: Retrieve uid and gid from special sid if enabled 2016-10-14 14:22:16 -05:00
cifsacl.h
cifsencrypt.c CIFS: Encrypt SMB3 requests before sending 2017-02-01 16:46:36 -06:00
cifsfs.c CIFS: fix oplock break deadlocks 2017-05-03 10:10:10 -05:00
cifsfs.h Introduce cifs_copy_file_range() 2017-04-07 08:04:41 -05:00
cifsglob.h CIFS: fix oplock break deadlocks 2017-05-03 10:10:10 -05:00
cifspdu.h CIFS: move DFS response parsing out of SMB1 code 2017-03-01 22:26:10 -06:00
cifsproto.h CIFS: Add asynchronous context to support kernel AIO 2017-05-02 14:57:34 -05:00
cifssmb.c Set unicode flag on cifs echo request to avoid Mac error 2017-05-02 14:57:34 -05:00
connect.c cifs: fix IPv6 link local, with scope id, address parsing 2017-05-02 14:57:34 -05:00
dir.c CIFS: add build_path_from_dentry_optional_prefix() 2017-03-01 22:26:10 -06:00
dns_resolve.c
dns_resolve.h
export.c
file.c CIFS: Add asynchronous write support through kernel AIO 2017-05-02 14:57:34 -05:00
fscache.c
fscache.h
inode.c Merge branch 'rebased-statx' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs 2017-03-03 11:38:56 -08:00
ioctl.c cifs: fix CIFS_ENUMERATE_SNAPSHOTS oops 2017-05-03 09:59:20 -05:00
Kconfig CIFS: Encrypt SMB3 requests before sending 2017-02-01 16:46:36 -06:00
link.c cifs: use %16phN for formatting md5 sum 2016-12-15 00:21:37 -06:00
Makefile
misc.c CIFS: fix oplock break deadlocks 2017-05-03 10:10:10 -05:00
netmisc.c cifs: small underflow in cnvrtDosUnixTm() 2017-05-02 14:57:34 -05:00
nterr.c
nterr.h
ntlmssp.h
readdir.c cifs: initialize file_info_lock 2017-01-14 14:58:29 -06:00
rfc1002pdu.h
sess.c smb2: Enforce sec= mount option 2017-03-02 23:13:37 -06:00
smb1ops.c cifs: Do not send echoes before Negotiate is complete 2017-04-17 15:44:23 -05:00
smb2file.c CIFS: add use_ipc flag to SMB2_ioctl() 2017-03-01 22:26:11 -06:00
smb2glob.h CIFS: Separate SMB2 header structure 2017-02-01 16:46:34 -06:00
smb2inode.c Do not send SMB3 SET_INFO request if nothing is changing 2016-10-13 19:46:51 -05:00
smb2maperror.c CIFS: Separate SMB2 header structure 2017-02-01 16:46:34 -06:00
smb2misc.c CIFS: fix oplock break deadlocks 2017-05-03 10:10:10 -05:00
smb2ops.c cifs: fix leak in FSCTL_ENUM_SNAPS response handling 2017-05-03 09:54:12 -05:00
smb2pdu.c CIFS: Fix SMB3 mount without specifying a security mechanism 2017-04-13 10:03:26 -05:00
smb2pdu.h CIFS: implement get_dfs_refer for SMB2+ 2017-03-02 17:05:31 -06:00
smb2proto.h Handle mismatched open calls 2017-04-07 08:04:40 -05:00
smb2status.h
smb2transport.c cifs: don't check for failure from mempool_alloc() 2017-04-28 07:56:33 -05:00
smbencrypt.c cifs: Fix smbencrypt() to stop pointing a scatterlist at the stack 2016-12-14 01:44:16 -06:00
smberr.h
smbfsctl.h
transport.c cifs: don't check for failure from mempool_alloc() 2017-04-28 07:56:33 -05:00
winucase.c
xattr.c Add way to query creation time of file via cifs xattr 2016-10-12 12:08:31 -05:00