aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2010-07-20 16:09:02 -0400
committerTejun Heo <tj@kernel.org>2010-07-22 16:59:15 -0400
commit9b646972467fb5fdc677f9e4251875db20bdbb64 (patch)
tree01d54cf7e0ee110bd8287c3360de0c3997e859ae
parentd098adfb7d281258173a43151483e52e21761021 (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>
-rw-r--r--fs/cifs/Kconfig1
-rw-r--r--fs/cifs/cifsfs.c5
-rw-r--r--fs/cifs/cifsglob.h8
-rw-r--r--fs/cifs/dir.c2
-rw-r--r--fs/cifs/file.c30
-rw-r--r--fs/cifs/misc.c20
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 */
732GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */ 732GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */
733GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/ 733GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/
734 734
735extern const struct slow_work_ops cifs_oplock_break_ops; 735void cifs_oplock_break(struct work_struct *work);
736void cifs_oplock_break_get(struct cifsFileInfo *cfile);
737void 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
2298static void 2298void cifs_oplock_break(struct work_struct *work)
2299cifs_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
2338static int 2347void cifs_oplock_break_get(struct cifsFileInfo *cfile)
2339cifs_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
2348static void 2353void cifs_oplock_break_put(struct cifsFileInfo *cfile)
2349cifs_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
2357const 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
2363const struct address_space_operations cifs_addr_ops = { 2359const 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;