From 46ae620b364db83b3db79508364303d4b01780b3 Mon Sep 17 00:00:00 2001
From: Jeff Layton <jlayton@redhat.com>
Date: Wed, 9 Sep 2009 11:44:16 -0400
Subject: [PATCH 5/4] cifs: convert oplock_break job to slow_work
Seems like a good candidate for this.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/cifs/Kconfig | 1 +
fs/cifs/cifsfs.c | 6 ++++++
fs/cifs/cifsglob.h | 4 +++-
fs/cifs/cifsproto.h | 1 -
fs/cifs/dir.c | 3 ++-
fs/cifs/file.c | 27 ++++++++++++++++++++++++---
fs/cifs/misc.c | 13 +++++++++----
7 files changed, 45 insertions(+), 10 deletions(-)
@@ -2,6 +2,7 @@ config CIFS
tristate "CIFS support (advanced network filesystem, SMBFS successor)"
depends on INET
select NLS
+ select SLOW_WORK
help
This is the client VFS module for the Common Internet File System
(CIFS) protocol which is the successor to the Server Message Block
@@ -1038,8 +1038,14 @@ init_cifs(void)
if (rc)
goto out_unregister_key_type;
#endif
+ rc = slow_work_register_user();
+ if (rc)
+ goto out_unregister_resolver_key;
+
return 0;
+ out_unregister_resolver_key:
+ unregister_key_type(&key_type_dns_resolver);
#ifdef CONFIG_CIFS_DFS_UPCALL
out_unregister_key_type:
#endif
@@ -18,6 +18,7 @@
*/
#include <linux/in.h>
#include <linux/in6.h>
+#include <linux/slow-work.h>
#include "cifs_fs_sb.h"
#include "cifsacl.h"
/*
@@ -355,7 +356,7 @@ struct cifsFileInfo {
atomic_t count; /* reference count */
struct mutex fh_mutex; /* prevents reopen race after dead ses*/
struct cifs_search_info srch_inf;
- struct work_struct oplock_break; /* workqueue job for oplock breaks */
+ struct slow_work oplock_break; /* slow_work job for oplock breaks */
};
/* Take a reference on the file private data */
@@ -722,3 +723,4 @@ GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */
GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */
GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/
+extern const struct slow_work_ops cifs_oplock_break_ops;
@@ -88,7 +88,6 @@ extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
extern __u16 GetNextMid(struct TCP_Server_Info *server);
extern struct timespec cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601);
extern u64 cifs_UnixTimeToNT(struct timespec);
-extern void cifs_oplock_break(struct work_struct *work);
extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time,
int offset);
@@ -31,6 +31,7 @@
#include "cifs_debug.h"
#include "cifs_fs_sb.h"
+
static void
renew_parental_timestamps(struct dentry *direntry)
{
@@ -155,7 +156,7 @@ cifs_fill_fileinfo(struct inode *newinode, __u16 fileHandle,
mutex_init(&pCifsFile->lock_mutex);
INIT_LIST_HEAD(&pCifsFile->llist);
atomic_set(&pCifsFile->count, 1);
- INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break);
+ slow_work_init(&pCifsFile->oplock_break, &cifs_oplock_break_ops);
/* set the following in open now
pCifsFile->pfile = file; */
@@ -57,7 +57,7 @@ static inline struct cifsFileInfo *cifs_init_private(
/* Initialize reference count to one. The private data is
freed on the release of the last reference */
atomic_set(&private_data->count, 1);
- INIT_WORK(&private_data->oplock_break, cifs_oplock_break);
+ slow_work_init(&private_data->oplock_break, &cifs_oplock_break_ops);
return private_data;
}
@@ -2311,8 +2311,8 @@ out:
return rc;
}
-void
-cifs_oplock_break(struct work_struct *work)
+static void
+cifs_oplock_break(struct slow_work *work)
{
struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
oplock_break);
@@ -2350,10 +2350,31 @@ cifs_oplock_break(struct work_struct *work)
LOCKING_ANDX_OPLOCK_RELEASE, false);
cFYI(1, ("Oplock release rc = %d", rc));
}
+}
+static int
+cifs_oplock_break_get(struct slow_work *work)
+{
+ struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
+ oplock_break);
+ cifsFileInfo_get(cfile);
+ return 0;
+}
+
+static void
+cifs_oplock_break_put(struct slow_work *work)
+{
+ struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
+ oplock_break);
cifsFileInfo_put(cfile);
}
+const struct slow_work_ops cifs_oplock_break_ops = {
+ .get_ref = cifs_oplock_break_get,
+ .put_ref = cifs_oplock_break_put,
+ .execute = cifs_oplock_break,
+};
+
const struct address_space_operations cifs_addr_ops = {
.readpage = cifs_readpage,
.readpages = cifs_readpages,
@@ -499,6 +499,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
struct cifsTconInfo *tcon;
struct cifsInodeInfo *pCifsInode;
struct cifsFileInfo *netfile;
+ int rc;
cFYI(1, ("Checking for oplock break or dnotify response"));
if ((pSMB->hdr.Command == SMB_COM_NT_TRANSACT) &&
@@ -578,16 +579,20 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
return true;
}
- cifsFileInfo_get(netfile);
- read_unlock(&GlobalSMBSeslock);
- read_unlock(&cifs_tcp_ses_lock);
cFYI(1, ("file id match, oplock break"));
pCifsInode = CIFS_I(netfile->pInode);
pCifsInode->clientCanCacheAll = false;
if (pSMB->OplockLevel == 0)
pCifsInode->clientCanCacheRead = false;
- if (schedule_work(&netfile->oplock_break))
+ rc = slow_work_enqueue(&netfile->oplock_break);
+ if (rc) {
+ cERROR(1, ("failed to enqueue oplock "
+ "break: %d\n", rc));
+ } else {
netfile->oplock_break_cancelled = false;
+ }
+ read_unlock(&GlobalSMBSeslock);
+ read_unlock(&cifs_tcp_ses_lock);
return true;
}
read_unlock(&GlobalSMBSeslock);
--
1.6.0.6