Commit 9b646972467fb5fdc677f9e4251875db20bdbb64
1 parent
d098adfb7d
Exists in
master
and in
4 other branches
cifs: use workqueue instead of slow-work
Workqueue can now handle high concurrency. Use system_nrt_wq instead of slow-work. * Updated is_valid_oplock_break() to not call cifs_oplock_break_put() as advised by Steve French. It might cause deadlock. Instead, reference is increased after queueing succeeded and cifs_oplock_break() briefly grabs GlobalSMBSeslock before putting the cfile to make sure it doesn't put before the matching get is finished. * Anton Blanchard reported that cifs conversion was using now gone system_single_wq. Use system_nrt_wq which provides non-reentrance guarantee which is enough and much better. Signed-off-by: Tejun Heo <tj@kernel.org> Acked-by: Steve French <sfrench@samba.org> Cc: Anton Blanchard <anton@samba.org>
Showing 6 changed files with 31 additions and 35 deletions Side-by-side Diff
fs/cifs/Kconfig
... | ... | @@ -2,7 +2,6 @@ |
2 | 2 | tristate "CIFS support (advanced network filesystem, SMBFS successor)" |
3 | 3 | depends on INET |
4 | 4 | select NLS |
5 | - select SLOW_WORK | |
6 | 5 | help |
7 | 6 | This is the client VFS module for the Common Internet File System |
8 | 7 | (CIFS) protocol which is the successor to the Server Message Block |
fs/cifs/cifsfs.c
... | ... | @@ -917,15 +917,10 @@ |
917 | 917 | if (rc) |
918 | 918 | goto out_unregister_key_type; |
919 | 919 | #endif |
920 | - rc = slow_work_register_user(THIS_MODULE); | |
921 | - if (rc) | |
922 | - goto out_unregister_resolver_key; | |
923 | 920 | |
924 | 921 | return 0; |
925 | 922 | |
926 | - out_unregister_resolver_key: | |
927 | 923 | #ifdef CONFIG_CIFS_DFS_UPCALL |
928 | - unregister_key_type(&key_type_dns_resolver); | |
929 | 924 | out_unregister_key_type: |
930 | 925 | #endif |
931 | 926 | #ifdef CONFIG_CIFS_UPCALL |
fs/cifs/cifsglob.h
... | ... | @@ -19,7 +19,7 @@ |
19 | 19 | #include <linux/in.h> |
20 | 20 | #include <linux/in6.h> |
21 | 21 | #include <linux/slab.h> |
22 | -#include <linux/slow-work.h> | |
22 | +#include <linux/workqueue.h> | |
23 | 23 | #include "cifs_fs_sb.h" |
24 | 24 | #include "cifsacl.h" |
25 | 25 | /* |
... | ... | @@ -363,7 +363,7 @@ |
363 | 363 | atomic_t count; /* reference count */ |
364 | 364 | struct mutex fh_mutex; /* prevents reopen race after dead ses*/ |
365 | 365 | struct cifs_search_info srch_inf; |
366 | - struct slow_work oplock_break; /* slow_work job for oplock breaks */ | |
366 | + struct work_struct oplock_break; /* work for oplock breaks */ | |
367 | 367 | }; |
368 | 368 | |
369 | 369 | /* Take a reference on the file private data */ |
... | ... | @@ -732,5 +732,7 @@ |
732 | 732 | GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */ |
733 | 733 | GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/ |
734 | 734 | |
735 | -extern const struct slow_work_ops cifs_oplock_break_ops; | |
735 | +void cifs_oplock_break(struct work_struct *work); | |
736 | +void cifs_oplock_break_get(struct cifsFileInfo *cfile); | |
737 | +void cifs_oplock_break_put(struct cifsFileInfo *cfile); |
fs/cifs/dir.c
... | ... | @@ -162,7 +162,7 @@ |
162 | 162 | mutex_init(&pCifsFile->lock_mutex); |
163 | 163 | INIT_LIST_HEAD(&pCifsFile->llist); |
164 | 164 | atomic_set(&pCifsFile->count, 1); |
165 | - slow_work_init(&pCifsFile->oplock_break, &cifs_oplock_break_ops); | |
165 | + INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break); | |
166 | 166 | |
167 | 167 | write_lock(&GlobalSMBSeslock); |
168 | 168 | list_add(&pCifsFile->tlist, &cifs_sb->tcon->openFileList); |
fs/cifs/file.c
... | ... | @@ -2295,8 +2295,7 @@ |
2295 | 2295 | return rc; |
2296 | 2296 | } |
2297 | 2297 | |
2298 | -static void | |
2299 | -cifs_oplock_break(struct slow_work *work) | |
2298 | +void cifs_oplock_break(struct work_struct *work) | |
2300 | 2299 | { |
2301 | 2300 | struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, |
2302 | 2301 | oplock_break); |
2303 | 2302 | |
2304 | 2303 | |
2305 | 2304 | |
2306 | 2305 | |
2307 | 2306 | |
2308 | 2307 | |
... | ... | @@ -2333,32 +2332,29 @@ |
2333 | 2332 | LOCKING_ANDX_OPLOCK_RELEASE, false); |
2334 | 2333 | cFYI(1, "Oplock release rc = %d", rc); |
2335 | 2334 | } |
2335 | + | |
2336 | + /* | |
2337 | + * We might have kicked in before is_valid_oplock_break() | |
2338 | + * finished grabbing reference for us. Make sure it's done by | |
2339 | + * waiting for GlobalSMSSeslock. | |
2340 | + */ | |
2341 | + write_lock(&GlobalSMBSeslock); | |
2342 | + write_unlock(&GlobalSMBSeslock); | |
2343 | + | |
2344 | + cifs_oplock_break_put(cfile); | |
2336 | 2345 | } |
2337 | 2346 | |
2338 | -static int | |
2339 | -cifs_oplock_break_get(struct slow_work *work) | |
2347 | +void cifs_oplock_break_get(struct cifsFileInfo *cfile) | |
2340 | 2348 | { |
2341 | - struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, | |
2342 | - oplock_break); | |
2343 | 2349 | mntget(cfile->mnt); |
2344 | 2350 | cifsFileInfo_get(cfile); |
2345 | - return 0; | |
2346 | 2351 | } |
2347 | 2352 | |
2348 | -static void | |
2349 | -cifs_oplock_break_put(struct slow_work *work) | |
2353 | +void cifs_oplock_break_put(struct cifsFileInfo *cfile) | |
2350 | 2354 | { |
2351 | - struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, | |
2352 | - oplock_break); | |
2353 | 2355 | mntput(cfile->mnt); |
2354 | 2356 | cifsFileInfo_put(cfile); |
2355 | 2357 | } |
2356 | - | |
2357 | -const struct slow_work_ops cifs_oplock_break_ops = { | |
2358 | - .get_ref = cifs_oplock_break_get, | |
2359 | - .put_ref = cifs_oplock_break_put, | |
2360 | - .execute = cifs_oplock_break, | |
2361 | -}; | |
2362 | 2358 | |
2363 | 2359 | const struct address_space_operations cifs_addr_ops = { |
2364 | 2360 | .readpage = cifs_readpage, |
fs/cifs/misc.c
... | ... | @@ -498,7 +498,6 @@ |
498 | 498 | struct cifsTconInfo *tcon; |
499 | 499 | struct cifsInodeInfo *pCifsInode; |
500 | 500 | struct cifsFileInfo *netfile; |
501 | - int rc; | |
502 | 501 | |
503 | 502 | cFYI(1, "Checking for oplock break or dnotify response"); |
504 | 503 | if ((pSMB->hdr.Command == SMB_COM_NT_TRANSACT) && |
... | ... | @@ -583,13 +582,18 @@ |
583 | 582 | pCifsInode->clientCanCacheAll = false; |
584 | 583 | if (pSMB->OplockLevel == 0) |
585 | 584 | pCifsInode->clientCanCacheRead = false; |
586 | - rc = slow_work_enqueue(&netfile->oplock_break); | |
587 | - if (rc) { | |
588 | - cERROR(1, "failed to enqueue oplock " | |
589 | - "break: %d\n", rc); | |
590 | - } else { | |
591 | - netfile->oplock_break_cancelled = false; | |
592 | - } | |
585 | + | |
586 | + /* | |
587 | + * cifs_oplock_break_put() can't be called | |
588 | + * from here. Get reference after queueing | |
589 | + * succeeded. cifs_oplock_break() will | |
590 | + * synchronize using GlobalSMSSeslock. | |
591 | + */ | |
592 | + if (queue_work(system_nrt_wq, | |
593 | + &netfile->oplock_break)) | |
594 | + cifs_oplock_break_get(netfile); | |
595 | + netfile->oplock_break_cancelled = false; | |
596 | + | |
593 | 597 | read_unlock(&GlobalSMBSeslock); |
594 | 598 | read_unlock(&cifs_tcp_ses_lock); |
595 | 599 | return true; |