diff options
author | Tejun Heo <tj@kernel.org> | 2010-07-20 16:09:02 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2010-07-22 16:59:15 -0400 |
commit | 9b646972467fb5fdc677f9e4251875db20bdbb64 (patch) | |
tree | 01d54cf7e0ee110bd8287c3360de0c3997e859ae /fs | |
parent | d098adfb7d281258173a43151483e52e21761021 (diff) |
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>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/cifs/Kconfig | 1 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 5 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 8 | ||||
-rw-r--r-- | fs/cifs/dir.c | 2 | ||||
-rw-r--r-- | fs/cifs/file.c | 30 | ||||
-rw-r--r-- | fs/cifs/misc.c | 20 |
6 files changed, 31 insertions, 35 deletions
diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index 80f352596807..6994a0f54f02 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig | |||
@@ -2,7 +2,6 @@ config CIFS | |||
2 | tristate "CIFS support (advanced network filesystem, SMBFS successor)" | 2 | tristate "CIFS support (advanced network filesystem, SMBFS successor)" |
3 | depends on INET | 3 | depends on INET |
4 | select NLS | 4 | select NLS |
5 | select SLOW_WORK | ||
6 | help | 5 | help |
7 | This is the client VFS module for the Common Internet File System | 6 | This is the client VFS module for the Common Internet File System |
8 | (CIFS) protocol which is the successor to the Server Message Block | 7 | (CIFS) protocol which is the successor to the Server Message Block |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 78c02eb4cb1f..4c075177c8b6 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -917,15 +917,10 @@ init_cifs(void) | |||
917 | if (rc) | 917 | if (rc) |
918 | goto out_unregister_key_type; | 918 | goto out_unregister_key_type; |
919 | #endif | 919 | #endif |
920 | rc = slow_work_register_user(THIS_MODULE); | ||
921 | if (rc) | ||
922 | goto out_unregister_resolver_key; | ||
923 | 920 | ||
924 | return 0; | 921 | return 0; |
925 | 922 | ||
926 | out_unregister_resolver_key: | ||
927 | #ifdef CONFIG_CIFS_DFS_UPCALL | 923 | #ifdef CONFIG_CIFS_DFS_UPCALL |
928 | unregister_key_type(&key_type_dns_resolver); | ||
929 | out_unregister_key_type: | 924 | out_unregister_key_type: |
930 | #endif | 925 | #endif |
931 | #ifdef CONFIG_CIFS_UPCALL | 926 | #ifdef CONFIG_CIFS_UPCALL |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index a88479ceaad5..f5a1f9bb3a9f 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -19,7 +19,7 @@ | |||
19 | #include <linux/in.h> | 19 | #include <linux/in.h> |
20 | #include <linux/in6.h> | 20 | #include <linux/in6.h> |
21 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
22 | #include <linux/slow-work.h> | 22 | #include <linux/workqueue.h> |
23 | #include "cifs_fs_sb.h" | 23 | #include "cifs_fs_sb.h" |
24 | #include "cifsacl.h" | 24 | #include "cifsacl.h" |
25 | /* | 25 | /* |
@@ -363,7 +363,7 @@ struct cifsFileInfo { | |||
363 | atomic_t count; /* reference count */ | 363 | atomic_t count; /* reference count */ |
364 | struct mutex fh_mutex; /* prevents reopen race after dead ses*/ | 364 | struct mutex fh_mutex; /* prevents reopen race after dead ses*/ |
365 | struct cifs_search_info srch_inf; | 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 | /* Take a reference on the file private data */ | 369 | /* Take a reference on the file private data */ |
@@ -732,4 +732,6 @@ GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */ | |||
732 | GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */ | 732 | GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */ |
733 | GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/ | 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); | ||
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 391816b461ca..b066e73c4153 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -162,7 +162,7 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, | |||
162 | mutex_init(&pCifsFile->lock_mutex); | 162 | mutex_init(&pCifsFile->lock_mutex); |
163 | INIT_LIST_HEAD(&pCifsFile->llist); | 163 | INIT_LIST_HEAD(&pCifsFile->llist); |
164 | atomic_set(&pCifsFile->count, 1); | 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 | write_lock(&GlobalSMBSeslock); | 167 | write_lock(&GlobalSMBSeslock); |
168 | list_add(&pCifsFile->tlist, &cifs_sb->tcon->openFileList); | 168 | list_add(&pCifsFile->tlist, &cifs_sb->tcon->openFileList); |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 75541af4b3db..e767bfa7978b 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -2295,8 +2295,7 @@ out: | |||
2295 | return rc; | 2295 | return rc; |
2296 | } | 2296 | } |
2297 | 2297 | ||
2298 | static void | 2298 | void cifs_oplock_break(struct work_struct *work) |
2299 | cifs_oplock_break(struct slow_work *work) | ||
2300 | { | 2299 | { |
2301 | struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, | 2300 | struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, |
2302 | oplock_break); | 2301 | oplock_break); |
@@ -2333,33 +2332,30 @@ cifs_oplock_break(struct slow_work *work) | |||
2333 | LOCKING_ANDX_OPLOCK_RELEASE, false); | 2332 | LOCKING_ANDX_OPLOCK_RELEASE, false); |
2334 | cFYI(1, "Oplock release rc = %d", rc); | 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 | 2347 | void cifs_oplock_break_get(struct cifsFileInfo *cfile) |
2339 | cifs_oplock_break_get(struct slow_work *work) | ||
2340 | { | 2348 | { |
2341 | struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, | ||
2342 | oplock_break); | ||
2343 | mntget(cfile->mnt); | 2349 | mntget(cfile->mnt); |
2344 | cifsFileInfo_get(cfile); | 2350 | cifsFileInfo_get(cfile); |
2345 | return 0; | ||
2346 | } | 2351 | } |
2347 | 2352 | ||
2348 | static void | 2353 | void cifs_oplock_break_put(struct cifsFileInfo *cfile) |
2349 | cifs_oplock_break_put(struct slow_work *work) | ||
2350 | { | 2354 | { |
2351 | struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, | ||
2352 | oplock_break); | ||
2353 | mntput(cfile->mnt); | 2355 | mntput(cfile->mnt); |
2354 | cifsFileInfo_put(cfile); | 2356 | cifsFileInfo_put(cfile); |
2355 | } | 2357 | } |
2356 | 2358 | ||
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 | |||
2363 | const struct address_space_operations cifs_addr_ops = { | 2359 | const struct address_space_operations cifs_addr_ops = { |
2364 | .readpage = cifs_readpage, | 2360 | .readpage = cifs_readpage, |
2365 | .readpages = cifs_readpages, | 2361 | .readpages = cifs_readpages, |
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 1394aa37f26c..3ccadc1326d6 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
@@ -498,7 +498,6 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) | |||
498 | struct cifsTconInfo *tcon; | 498 | struct cifsTconInfo *tcon; |
499 | struct cifsInodeInfo *pCifsInode; | 499 | struct cifsInodeInfo *pCifsInode; |
500 | struct cifsFileInfo *netfile; | 500 | struct cifsFileInfo *netfile; |
501 | int rc; | ||
502 | 501 | ||
503 | cFYI(1, "Checking for oplock break or dnotify response"); | 502 | cFYI(1, "Checking for oplock break or dnotify response"); |
504 | if ((pSMB->hdr.Command == SMB_COM_NT_TRANSACT) && | 503 | if ((pSMB->hdr.Command == SMB_COM_NT_TRANSACT) && |
@@ -583,13 +582,18 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) | |||
583 | pCifsInode->clientCanCacheAll = false; | 582 | pCifsInode->clientCanCacheAll = false; |
584 | if (pSMB->OplockLevel == 0) | 583 | if (pSMB->OplockLevel == 0) |
585 | pCifsInode->clientCanCacheRead = false; | 584 | pCifsInode->clientCanCacheRead = false; |
586 | rc = slow_work_enqueue(&netfile->oplock_break); | 585 | |
587 | if (rc) { | 586 | /* |
588 | cERROR(1, "failed to enqueue oplock " | 587 | * cifs_oplock_break_put() can't be called |
589 | "break: %d\n", rc); | 588 | * from here. Get reference after queueing |
590 | } else { | 589 | * succeeded. cifs_oplock_break() will |
591 | netfile->oplock_break_cancelled = false; | 590 | * synchronize using GlobalSMSSeslock. |
592 | } | 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 | read_unlock(&GlobalSMBSeslock); | 597 | read_unlock(&GlobalSMBSeslock); |
594 | read_unlock(&cifs_tcp_ses_lock); | 598 | read_unlock(&cifs_tcp_ses_lock); |
595 | return true; | 599 | return true; |