aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2009-09-21 06:47:50 -0400
committerSteve French <sfrench@us.ibm.com>2009-09-24 14:33:18 -0400
commit3bc303c254335dbd7c7012cc1760b12f1d5514d3 (patch)
tree7da17fbfd697216d9ed0ccd64ea9c03aaf3d52c1 /fs/cifs
parent48541bd3dd4739b4d574b44ea47660c88d833677 (diff)
cifs: convert oplock breaks to use slow_work facility (try #4)
This is the fourth respin of the patch to convert oplock breaks to use the slow_work facility. A customer of ours was testing a backport of one of the earlier patchsets, and hit a "Busy inodes after umount..." problem. An oplock break job had raced with a umount, and the superblock got torn down and its memory reused. When the oplock break job tried to dereference the inode->i_sb, the kernel oopsed. This patchset has the oplock break job hold an inode and vfsmount reference until the oplock break completes. With this, there should be no need to take a tcon reference (the vfsmount implicitly holds one already). Currently, when an oplock break comes in there's a chance that the oplock break job won't occur if the allocation of the oplock_q_entry fails. There are also some rather nasty races in the allocation and handling these structs. Rather than allocating oplock queue entries when an oplock break comes in, add a few extra fields to the cifsFileInfo struct. Get rid of the dedicated cifs_oplock_thread as well and queue the oplock break job to the slow_work thread pool. This approach also has the advantage that the oplock break jobs can potentially run in parallel rather than be serialized like they are today. Signed-off-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/Kconfig1
-rw-r--r--fs/cifs/cifsfs.c95
-rw-r--r--fs/cifs/cifsglob.h12
-rw-r--r--fs/cifs/cifsproto.h6
-rw-r--r--fs/cifs/cifssmb.c1
-rw-r--r--fs/cifs/connect.c1
-rw-r--r--fs/cifs/dir.c25
-rw-r--r--fs/cifs/file.c74
-rw-r--r--fs/cifs/misc.c29
-rw-r--r--fs/cifs/transport.c50
10 files changed, 119 insertions, 175 deletions
diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig
index 6994a0f54f02..80f352596807 100644
--- a/fs/cifs/Kconfig
+++ b/fs/cifs/Kconfig
@@ -2,6 +2,7 @@ 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
5 help 6 help
6 This is the client VFS module for the Common Internet File System 7 This is the client VFS module for the Common Internet File System
7 (CIFS) protocol which is the successor to the Server Message Block 8 (CIFS) protocol which is the successor to the Server Message Block
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 3610e9958b4c..89142b39fec1 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -64,9 +64,6 @@ unsigned int multiuser_mount = 0;
64unsigned int extended_security = CIFSSEC_DEF; 64unsigned int extended_security = CIFSSEC_DEF;
65/* unsigned int ntlmv2_support = 0; */ 65/* unsigned int ntlmv2_support = 0; */
66unsigned int sign_CIFS_PDUs = 1; 66unsigned int sign_CIFS_PDUs = 1;
67extern struct task_struct *oplockThread; /* remove sparse warning */
68struct task_struct *oplockThread = NULL;
69/* extern struct task_struct * dnotifyThread; remove sparse warning */
70static const struct super_operations cifs_super_ops; 67static const struct super_operations cifs_super_ops;
71unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE; 68unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE;
72module_param(CIFSMaxBufSize, int, 0); 69module_param(CIFSMaxBufSize, int, 0);
@@ -973,89 +970,12 @@ cifs_destroy_mids(void)
973 kmem_cache_destroy(cifs_oplock_cachep); 970 kmem_cache_destroy(cifs_oplock_cachep);
974} 971}
975 972
976static int cifs_oplock_thread(void *dummyarg)
977{
978 struct oplock_q_entry *oplock_item;
979 struct cifsTconInfo *pTcon;
980 struct inode *inode;
981 __u16 netfid;
982 int rc, waitrc = 0;
983
984 set_freezable();
985 do {
986 if (try_to_freeze())
987 continue;
988
989 spin_lock(&cifs_oplock_lock);
990 if (list_empty(&cifs_oplock_list)) {
991 spin_unlock(&cifs_oplock_lock);
992 set_current_state(TASK_INTERRUPTIBLE);
993 schedule_timeout(39*HZ);
994 } else {
995 oplock_item = list_entry(cifs_oplock_list.next,
996 struct oplock_q_entry, qhead);
997 cFYI(1, ("found oplock item to write out"));
998 pTcon = oplock_item->tcon;
999 inode = oplock_item->pinode;
1000 netfid = oplock_item->netfid;
1001 spin_unlock(&cifs_oplock_lock);
1002 DeleteOplockQEntry(oplock_item);
1003 /* can not grab inode sem here since it would
1004 deadlock when oplock received on delete
1005 since vfs_unlink holds the i_mutex across
1006 the call */
1007 /* mutex_lock(&inode->i_mutex);*/
1008 if (S_ISREG(inode->i_mode)) {
1009#ifdef CONFIG_CIFS_EXPERIMENTAL
1010 if (CIFS_I(inode)->clientCanCacheAll == 0)
1011 break_lease(inode, FMODE_READ);
1012 else if (CIFS_I(inode)->clientCanCacheRead == 0)
1013 break_lease(inode, FMODE_WRITE);
1014#endif
1015 rc = filemap_fdatawrite(inode->i_mapping);
1016 if (CIFS_I(inode)->clientCanCacheRead == 0) {
1017 waitrc = filemap_fdatawait(
1018 inode->i_mapping);
1019 invalidate_remote_inode(inode);
1020 }
1021 if (rc == 0)
1022 rc = waitrc;
1023 } else
1024 rc = 0;
1025 /* mutex_unlock(&inode->i_mutex);*/
1026 if (rc)
1027 CIFS_I(inode)->write_behind_rc = rc;
1028 cFYI(1, ("Oplock flush inode %p rc %d",
1029 inode, rc));
1030
1031 /* releasing stale oplock after recent reconnect
1032 of smb session using a now incorrect file
1033 handle is not a data integrity issue but do
1034 not bother sending an oplock release if session
1035 to server still is disconnected since oplock
1036 already released by the server in that case */
1037 if (!pTcon->need_reconnect) {
1038 rc = CIFSSMBLock(0, pTcon, netfid,
1039 0 /* len */ , 0 /* offset */, 0,
1040 0, LOCKING_ANDX_OPLOCK_RELEASE,
1041 false /* wait flag */);
1042 cFYI(1, ("Oplock release rc = %d", rc));
1043 }
1044 set_current_state(TASK_INTERRUPTIBLE);
1045 schedule_timeout(1); /* yield in case q were corrupt */
1046 }
1047 } while (!kthread_should_stop());
1048
1049 return 0;
1050}
1051
1052static int __init 973static int __init
1053init_cifs(void) 974init_cifs(void)
1054{ 975{
1055 int rc = 0; 976 int rc = 0;
1056 cifs_proc_init(); 977 cifs_proc_init();
1057 INIT_LIST_HEAD(&cifs_tcp_ses_list); 978 INIT_LIST_HEAD(&cifs_tcp_ses_list);
1058 INIT_LIST_HEAD(&cifs_oplock_list);
1059#ifdef CONFIG_CIFS_EXPERIMENTAL 979#ifdef CONFIG_CIFS_EXPERIMENTAL
1060 INIT_LIST_HEAD(&GlobalDnotifyReqList); 980 INIT_LIST_HEAD(&GlobalDnotifyReqList);
1061 INIT_LIST_HEAD(&GlobalDnotifyRsp_Q); 981 INIT_LIST_HEAD(&GlobalDnotifyRsp_Q);
@@ -1084,7 +1004,6 @@ init_cifs(void)
1084 rwlock_init(&GlobalSMBSeslock); 1004 rwlock_init(&GlobalSMBSeslock);
1085 rwlock_init(&cifs_tcp_ses_lock); 1005 rwlock_init(&cifs_tcp_ses_lock);
1086 spin_lock_init(&GlobalMid_Lock); 1006 spin_lock_init(&GlobalMid_Lock);
1087 spin_lock_init(&cifs_oplock_lock);
1088 1007
1089 if (cifs_max_pending < 2) { 1008 if (cifs_max_pending < 2) {
1090 cifs_max_pending = 2; 1009 cifs_max_pending = 2;
@@ -1119,18 +1038,15 @@ init_cifs(void)
1119 if (rc) 1038 if (rc)
1120 goto out_unregister_key_type; 1039 goto out_unregister_key_type;
1121#endif 1040#endif
1122 oplockThread = kthread_run(cifs_oplock_thread, NULL, "cifsoplockd"); 1041 rc = slow_work_register_user();
1123 if (IS_ERR(oplockThread)) { 1042 if (rc)
1124 rc = PTR_ERR(oplockThread); 1043 goto out_unregister_resolver_key;
1125 cERROR(1, ("error %d create oplock thread", rc));
1126 goto out_unregister_dfs_key_type;
1127 }
1128 1044
1129 return 0; 1045 return 0;
1130 1046
1131 out_unregister_dfs_key_type: 1047 out_unregister_resolver_key:
1132#ifdef CONFIG_CIFS_DFS_UPCALL
1133 unregister_key_type(&key_type_dns_resolver); 1048 unregister_key_type(&key_type_dns_resolver);
1049#ifdef CONFIG_CIFS_DFS_UPCALL
1134 out_unregister_key_type: 1050 out_unregister_key_type:
1135#endif 1051#endif
1136#ifdef CONFIG_CIFS_UPCALL 1052#ifdef CONFIG_CIFS_UPCALL
@@ -1165,7 +1081,6 @@ exit_cifs(void)
1165 cifs_destroy_inodecache(); 1081 cifs_destroy_inodecache();
1166 cifs_destroy_mids(); 1082 cifs_destroy_mids();
1167 cifs_destroy_request_bufs(); 1083 cifs_destroy_request_bufs();
1168 kthread_stop(oplockThread);
1169} 1084}
1170 1085
1171MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>"); 1086MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>");
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index c19419a38f62..5d0fde18039c 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -18,6 +18,7 @@
18 */ 18 */
19#include <linux/in.h> 19#include <linux/in.h>
20#include <linux/in6.h> 20#include <linux/in6.h>
21#include <linux/slow-work.h>
21#include "cifs_fs_sb.h" 22#include "cifs_fs_sb.h"
22#include "cifsacl.h" 23#include "cifsacl.h"
23/* 24/*
@@ -346,14 +347,16 @@ struct cifsFileInfo {
346 /* lock scope id (0 if none) */ 347 /* lock scope id (0 if none) */
347 struct file *pfile; /* needed for writepage */ 348 struct file *pfile; /* needed for writepage */
348 struct inode *pInode; /* needed for oplock break */ 349 struct inode *pInode; /* needed for oplock break */
350 struct vfsmount *mnt;
349 struct mutex lock_mutex; 351 struct mutex lock_mutex;
350 struct list_head llist; /* list of byte range locks we have. */ 352 struct list_head llist; /* list of byte range locks we have. */
351 bool closePend:1; /* file is marked to close */ 353 bool closePend:1; /* file is marked to close */
352 bool invalidHandle:1; /* file closed via session abend */ 354 bool invalidHandle:1; /* file closed via session abend */
353 bool messageMode:1; /* for pipes: message vs byte mode */ 355 bool oplock_break_cancelled:1;
354 atomic_t count; /* reference count */ 356 atomic_t count; /* reference count */
355 struct mutex fh_mutex; /* prevents reopen race after dead ses*/ 357 struct mutex fh_mutex; /* prevents reopen race after dead ses*/
356 struct cifs_search_info srch_inf; 358 struct cifs_search_info srch_inf;
359 struct slow_work oplock_break; /* slow_work job for oplock breaks */
357}; 360};
358 361
359/* Take a reference on the file private data */ 362/* Take a reference on the file private data */
@@ -670,12 +673,6 @@ GLOBAL_EXTERN rwlock_t cifs_tcp_ses_lock;
670 */ 673 */
671GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; 674GLOBAL_EXTERN rwlock_t GlobalSMBSeslock;
672 675
673/* Global list of oplocks */
674GLOBAL_EXTERN struct list_head cifs_oplock_list;
675
676/* Protects the cifs_oplock_list */
677GLOBAL_EXTERN spinlock_t cifs_oplock_lock;
678
679/* Outstanding dir notify requests */ 676/* Outstanding dir notify requests */
680GLOBAL_EXTERN struct list_head GlobalDnotifyReqList; 677GLOBAL_EXTERN struct list_head GlobalDnotifyReqList;
681/* DirNotify response queue */ 678/* DirNotify response queue */
@@ -726,3 +723,4 @@ GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */
726GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */ 723GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */
727GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/ 724GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/
728 725
726extern const struct slow_work_ops cifs_oplock_break_ops;
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index bf3ae881b2d5..733e71b57c7a 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -86,17 +86,13 @@ extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
86 const int stage, 86 const int stage,
87 const struct nls_table *nls_cp); 87 const struct nls_table *nls_cp);
88extern __u16 GetNextMid(struct TCP_Server_Info *server); 88extern __u16 GetNextMid(struct TCP_Server_Info *server);
89extern struct oplock_q_entry *AllocOplockQEntry(struct inode *, u16,
90 struct cifsTconInfo *);
91extern void DeleteOplockQEntry(struct oplock_q_entry *);
92extern void DeleteTconOplockQEntries(struct cifsTconInfo *);
93extern struct timespec cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601); 89extern struct timespec cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601);
94extern u64 cifs_UnixTimeToNT(struct timespec); 90extern u64 cifs_UnixTimeToNT(struct timespec);
95extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, 91extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time,
96 int offset); 92 int offset);
97 93
98extern int cifs_posix_open(char *full_path, struct inode **pinode, 94extern int cifs_posix_open(char *full_path, struct inode **pinode,
99 struct super_block *sb, int mode, int oflags, 95 struct vfsmount *mnt, int mode, int oflags,
100 __u32 *poplock, __u16 *pnetfid, int xid); 96 __u32 *poplock, __u16 *pnetfid, int xid);
101extern void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, 97extern void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr,
102 FILE_UNIX_BASIC_INFO *info, 98 FILE_UNIX_BASIC_INFO *info,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 301e307e1279..941441d3e386 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -94,6 +94,7 @@ static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
94 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) { 94 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
95 open_file = list_entry(tmp, struct cifsFileInfo, tlist); 95 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
96 open_file->invalidHandle = true; 96 open_file->invalidHandle = true;
97 open_file->oplock_break_cancelled = true;
97 } 98 }
98 write_unlock(&GlobalSMBSeslock); 99 write_unlock(&GlobalSMBSeslock);
99 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted 100 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index d49682433c20..43003e0bef18 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1670,7 +1670,6 @@ cifs_put_tcon(struct cifsTconInfo *tcon)
1670 CIFSSMBTDis(xid, tcon); 1670 CIFSSMBTDis(xid, tcon);
1671 _FreeXid(xid); 1671 _FreeXid(xid);
1672 1672
1673 DeleteTconOplockQEntries(tcon);
1674 tconInfoFree(tcon); 1673 tconInfoFree(tcon);
1675 cifs_put_smb_ses(ses); 1674 cifs_put_smb_ses(ses);
1676} 1675}
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 36435502b5e8..9a5df7a84698 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -24,6 +24,7 @@
24#include <linux/stat.h> 24#include <linux/stat.h>
25#include <linux/slab.h> 25#include <linux/slab.h>
26#include <linux/namei.h> 26#include <linux/namei.h>
27#include <linux/mount.h>
27#include "cifsfs.h" 28#include "cifsfs.h"
28#include "cifspdu.h" 29#include "cifspdu.h"
29#include "cifsglob.h" 30#include "cifsglob.h"
@@ -131,11 +132,12 @@ cifs_bp_rename_retry:
131 132
132static void 133static void
133cifs_fill_fileinfo(struct inode *newinode, __u16 fileHandle, 134cifs_fill_fileinfo(struct inode *newinode, __u16 fileHandle,
134 struct cifsTconInfo *tcon, bool write_only) 135 struct vfsmount *mnt, bool write_only)
135{ 136{
136 int oplock = 0; 137 int oplock = 0;
137 struct cifsFileInfo *pCifsFile; 138 struct cifsFileInfo *pCifsFile;
138 struct cifsInodeInfo *pCifsInode; 139 struct cifsInodeInfo *pCifsInode;
140 struct cifs_sb_info *cifs_sb = CIFS_SB(mnt->mnt_sb);
139 141
140 pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); 142 pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
141 143
@@ -148,17 +150,19 @@ cifs_fill_fileinfo(struct inode *newinode, __u16 fileHandle,
148 pCifsFile->netfid = fileHandle; 150 pCifsFile->netfid = fileHandle;
149 pCifsFile->pid = current->tgid; 151 pCifsFile->pid = current->tgid;
150 pCifsFile->pInode = igrab(newinode); 152 pCifsFile->pInode = igrab(newinode);
153 pCifsFile->mnt = mnt;
151 pCifsFile->invalidHandle = false; 154 pCifsFile->invalidHandle = false;
152 pCifsFile->closePend = false; 155 pCifsFile->closePend = false;
153 mutex_init(&pCifsFile->fh_mutex); 156 mutex_init(&pCifsFile->fh_mutex);
154 mutex_init(&pCifsFile->lock_mutex); 157 mutex_init(&pCifsFile->lock_mutex);
155 INIT_LIST_HEAD(&pCifsFile->llist); 158 INIT_LIST_HEAD(&pCifsFile->llist);
156 atomic_set(&pCifsFile->count, 1); 159 atomic_set(&pCifsFile->count, 1);
160 slow_work_init(&pCifsFile->oplock_break, &cifs_oplock_break_ops);
157 161
158 /* set the following in open now 162 /* set the following in open now
159 pCifsFile->pfile = file; */ 163 pCifsFile->pfile = file; */
160 write_lock(&GlobalSMBSeslock); 164 write_lock(&GlobalSMBSeslock);
161 list_add(&pCifsFile->tlist, &tcon->openFileList); 165 list_add(&pCifsFile->tlist, &cifs_sb->tcon->openFileList);
162 pCifsInode = CIFS_I(newinode); 166 pCifsInode = CIFS_I(newinode);
163 if (pCifsInode) { 167 if (pCifsInode) {
164 /* if readable file instance put first in list*/ 168 /* if readable file instance put first in list*/
@@ -179,14 +183,14 @@ cifs_fill_fileinfo(struct inode *newinode, __u16 fileHandle,
179} 183}
180 184
181int cifs_posix_open(char *full_path, struct inode **pinode, 185int cifs_posix_open(char *full_path, struct inode **pinode,
182 struct super_block *sb, int mode, int oflags, 186 struct vfsmount *mnt, int mode, int oflags,
183 __u32 *poplock, __u16 *pnetfid, int xid) 187 __u32 *poplock, __u16 *pnetfid, int xid)
184{ 188{
185 int rc; 189 int rc;
186 bool write_only = false; 190 bool write_only = false;
187 FILE_UNIX_BASIC_INFO *presp_data; 191 FILE_UNIX_BASIC_INFO *presp_data;
188 __u32 posix_flags = 0; 192 __u32 posix_flags = 0;
189 struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 193 struct cifs_sb_info *cifs_sb = CIFS_SB(mnt->mnt_sb);
190 struct cifs_fattr fattr; 194 struct cifs_fattr fattr;
191 195
192 cFYI(1, ("posix open %s", full_path)); 196 cFYI(1, ("posix open %s", full_path));
@@ -243,7 +247,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
243 247
244 /* get new inode and set it up */ 248 /* get new inode and set it up */
245 if (*pinode == NULL) { 249 if (*pinode == NULL) {
246 *pinode = cifs_iget(sb, &fattr); 250 *pinode = cifs_iget(mnt->mnt_sb, &fattr);
247 if (!*pinode) { 251 if (!*pinode) {
248 rc = -ENOMEM; 252 rc = -ENOMEM;
249 goto posix_open_ret; 253 goto posix_open_ret;
@@ -252,7 +256,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
252 cifs_fattr_to_inode(*pinode, &fattr); 256 cifs_fattr_to_inode(*pinode, &fattr);
253 } 257 }
254 258
255 cifs_fill_fileinfo(*pinode, *pnetfid, cifs_sb->tcon, write_only); 259 cifs_fill_fileinfo(*pinode, *pnetfid, mnt, write_only);
256 260
257posix_open_ret: 261posix_open_ret:
258 kfree(presp_data); 262 kfree(presp_data);
@@ -322,7 +326,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
322 if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) && 326 if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
323 (CIFS_UNIX_POSIX_PATH_OPS_CAP & 327 (CIFS_UNIX_POSIX_PATH_OPS_CAP &
324 le64_to_cpu(tcon->fsUnixInfo.Capability))) { 328 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
325 rc = cifs_posix_open(full_path, &newinode, inode->i_sb, 329 rc = cifs_posix_open(full_path, &newinode, nd->path.mnt,
326 mode, oflags, &oplock, &fileHandle, xid); 330 mode, oflags, &oplock, &fileHandle, xid);
327 /* EIO could indicate that (posix open) operation is not 331 /* EIO could indicate that (posix open) operation is not
328 supported, despite what server claimed in capability 332 supported, despite what server claimed in capability
@@ -469,8 +473,8 @@ cifs_create_set_dentry:
469 /* mknod case - do not leave file open */ 473 /* mknod case - do not leave file open */
470 CIFSSMBClose(xid, tcon, fileHandle); 474 CIFSSMBClose(xid, tcon, fileHandle);
471 } else if (!(posix_create) && (newinode)) { 475 } else if (!(posix_create) && (newinode)) {
472 cifs_fill_fileinfo(newinode, fileHandle, 476 cifs_fill_fileinfo(newinode, fileHandle, nd->path.mnt,
473 cifs_sb->tcon, write_only); 477 write_only);
474 } 478 }
475cifs_create_out: 479cifs_create_out:
476 kfree(buf); 480 kfree(buf);
@@ -682,8 +686,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
682 if (!(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) && 686 if (!(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) &&
683 (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open && 687 (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open &&
684 (nd->intent.open.flags & O_CREAT)) { 688 (nd->intent.open.flags & O_CREAT)) {
685 rc = cifs_posix_open(full_path, &newInode, 689 rc = cifs_posix_open(full_path, &newInode, nd->path.mnt,
686 parent_dir_inode->i_sb,
687 nd->intent.open.create_mode, 690 nd->intent.open.create_mode,
688 nd->intent.open.flags, &oplock, 691 nd->intent.open.flags, &oplock,
689 &fileHandle, xid); 692 &fileHandle, xid);
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index b976cea24102..90f61786f516 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -30,6 +30,7 @@
30#include <linux/writeback.h> 30#include <linux/writeback.h>
31#include <linux/task_io_accounting_ops.h> 31#include <linux/task_io_accounting_ops.h>
32#include <linux/delay.h> 32#include <linux/delay.h>
33#include <linux/mount.h>
33#include <asm/div64.h> 34#include <asm/div64.h>
34#include "cifsfs.h" 35#include "cifsfs.h"
35#include "cifspdu.h" 36#include "cifspdu.h"
@@ -51,11 +52,13 @@ static inline struct cifsFileInfo *cifs_init_private(
51 INIT_LIST_HEAD(&private_data->llist); 52 INIT_LIST_HEAD(&private_data->llist);
52 private_data->pfile = file; /* needed for writepage */ 53 private_data->pfile = file; /* needed for writepage */
53 private_data->pInode = igrab(inode); 54 private_data->pInode = igrab(inode);
55 private_data->mnt = file->f_path.mnt;
54 private_data->invalidHandle = false; 56 private_data->invalidHandle = false;
55 private_data->closePend = false; 57 private_data->closePend = false;
56 /* Initialize reference count to one. The private data is 58 /* Initialize reference count to one. The private data is
57 freed on the release of the last reference */ 59 freed on the release of the last reference */
58 atomic_set(&private_data->count, 1); 60 atomic_set(&private_data->count, 1);
61 slow_work_init(&private_data->oplock_break, &cifs_oplock_break_ops);
59 62
60 return private_data; 63 return private_data;
61} 64}
@@ -327,7 +330,7 @@ int cifs_open(struct inode *inode, struct file *file)
327 le64_to_cpu(tcon->fsUnixInfo.Capability))) { 330 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
328 int oflags = (int) cifs_posix_convert_flags(file->f_flags); 331 int oflags = (int) cifs_posix_convert_flags(file->f_flags);
329 /* can not refresh inode info since size could be stale */ 332 /* can not refresh inode info since size could be stale */
330 rc = cifs_posix_open(full_path, &inode, inode->i_sb, 333 rc = cifs_posix_open(full_path, &inode, file->f_path.mnt,
331 cifs_sb->mnt_file_mode /* ignored */, 334 cifs_sb->mnt_file_mode /* ignored */,
332 oflags, &oplock, &netfid, xid); 335 oflags, &oplock, &netfid, xid);
333 if (rc == 0) { 336 if (rc == 0) {
@@ -547,7 +550,7 @@ reopen_error_exit:
547 le64_to_cpu(tcon->fsUnixInfo.Capability))) { 550 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
548 int oflags = (int) cifs_posix_convert_flags(file->f_flags); 551 int oflags = (int) cifs_posix_convert_flags(file->f_flags);
549 /* can not refresh inode info since size could be stale */ 552 /* can not refresh inode info since size could be stale */
550 rc = cifs_posix_open(full_path, NULL, inode->i_sb, 553 rc = cifs_posix_open(full_path, NULL, file->f_path.mnt,
551 cifs_sb->mnt_file_mode /* ignored */, 554 cifs_sb->mnt_file_mode /* ignored */,
552 oflags, &oplock, &netfid, xid); 555 oflags, &oplock, &netfid, xid);
553 if (rc == 0) { 556 if (rc == 0) {
@@ -2312,6 +2315,73 @@ out:
2312 return rc; 2315 return rc;
2313} 2316}
2314 2317
2318static void
2319cifs_oplock_break(struct slow_work *work)
2320{
2321 struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
2322 oplock_break);
2323 struct inode *inode = cfile->pInode;
2324 struct cifsInodeInfo *cinode = CIFS_I(inode);
2325 struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->mnt->mnt_sb);
2326 int rc, waitrc = 0;
2327
2328 if (inode && S_ISREG(inode->i_mode)) {
2329#ifdef CONFIG_CIFS_EXPERIMENTAL
2330 if (cinode->clientCanCacheAll == 0)
2331 break_lease(inode, FMODE_READ);
2332 else if (cinode->clientCanCacheRead == 0)
2333 break_lease(inode, FMODE_WRITE);
2334#endif
2335 rc = filemap_fdatawrite(inode->i_mapping);
2336 if (cinode->clientCanCacheRead == 0) {
2337 waitrc = filemap_fdatawait(inode->i_mapping);
2338 invalidate_remote_inode(inode);
2339 }
2340 if (!rc)
2341 rc = waitrc;
2342 if (rc)
2343 cinode->write_behind_rc = rc;
2344 cFYI(1, ("Oplock flush inode %p rc %d", inode, rc));
2345 }
2346
2347 /*
2348 * releasing stale oplock after recent reconnect of smb session using
2349 * a now incorrect file handle is not a data integrity issue but do
2350 * not bother sending an oplock release if session to server still is
2351 * disconnected since oplock already released by the server
2352 */
2353 if (!cfile->closePend && !cfile->oplock_break_cancelled) {
2354 rc = CIFSSMBLock(0, cifs_sb->tcon, cfile->netfid, 0, 0, 0, 0,
2355 LOCKING_ANDX_OPLOCK_RELEASE, false);
2356 cFYI(1, ("Oplock release rc = %d", rc));
2357 }
2358}
2359
2360static int
2361cifs_oplock_break_get(struct slow_work *work)
2362{
2363 struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
2364 oplock_break);
2365 mntget(cfile->mnt);
2366 cifsFileInfo_get(cfile);
2367 return 0;
2368}
2369
2370static void
2371cifs_oplock_break_put(struct slow_work *work)
2372{
2373 struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
2374 oplock_break);
2375 mntput(cfile->mnt);
2376 cifsFileInfo_put(cfile);
2377}
2378
2379const struct slow_work_ops cifs_oplock_break_ops = {
2380 .get_ref = cifs_oplock_break_get,
2381 .put_ref = cifs_oplock_break_put,
2382 .execute = cifs_oplock_break,
2383};
2384
2315const struct address_space_operations cifs_addr_ops = { 2385const struct address_space_operations cifs_addr_ops = {
2316 .readpage = cifs_readpage, 2386 .readpage = cifs_readpage,
2317 .readpages = cifs_readpages, 2387 .readpages = cifs_readpages,
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 191e6220bc76..0241b25ac33f 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -32,7 +32,6 @@
32 32
33extern mempool_t *cifs_sm_req_poolp; 33extern mempool_t *cifs_sm_req_poolp;
34extern mempool_t *cifs_req_poolp; 34extern mempool_t *cifs_req_poolp;
35extern struct task_struct *oplockThread;
36 35
37/* The xid serves as a useful identifier for each incoming vfs request, 36/* The xid serves as a useful identifier for each incoming vfs request,
38 in a similar way to the mid which is useful to track each sent smb, 37 in a similar way to the mid which is useful to track each sent smb,
@@ -500,6 +499,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
500 struct cifsTconInfo *tcon; 499 struct cifsTconInfo *tcon;
501 struct cifsInodeInfo *pCifsInode; 500 struct cifsInodeInfo *pCifsInode;
502 struct cifsFileInfo *netfile; 501 struct cifsFileInfo *netfile;
502 int rc;
503 503
504 cFYI(1, ("Checking for oplock break or dnotify response")); 504 cFYI(1, ("Checking for oplock break or dnotify response"));
505 if ((pSMB->hdr.Command == SMB_COM_NT_TRANSACT) && 505 if ((pSMB->hdr.Command == SMB_COM_NT_TRANSACT) &&
@@ -569,19 +569,30 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
569 if (pSMB->Fid != netfile->netfid) 569 if (pSMB->Fid != netfile->netfid)
570 continue; 570 continue;
571 571
572 read_unlock(&GlobalSMBSeslock); 572 /*
573 read_unlock(&cifs_tcp_ses_lock); 573 * don't do anything if file is about to be
574 * closed anyway.
575 */
576 if (netfile->closePend) {
577 read_unlock(&GlobalSMBSeslock);
578 read_unlock(&cifs_tcp_ses_lock);
579 return true;
580 }
581
574 cFYI(1, ("file id match, oplock break")); 582 cFYI(1, ("file id match, oplock break"));
575 pCifsInode = CIFS_I(netfile->pInode); 583 pCifsInode = CIFS_I(netfile->pInode);
576 pCifsInode->clientCanCacheAll = false; 584 pCifsInode->clientCanCacheAll = false;
577 if (pSMB->OplockLevel == 0) 585 if (pSMB->OplockLevel == 0)
578 pCifsInode->clientCanCacheRead = false; 586 pCifsInode->clientCanCacheRead = false;
579 AllocOplockQEntry(netfile->pInode, 587 rc = slow_work_enqueue(&netfile->oplock_break);
580 netfile->netfid, tcon); 588 if (rc) {
581 cFYI(1, ("about to wake up oplock thread")); 589 cERROR(1, ("failed to enqueue oplock "
582 if (oplockThread) 590 "break: %d\n", rc));
583 wake_up_process(oplockThread); 591 } else {
584 592 netfile->oplock_break_cancelled = false;
593 }
594 read_unlock(&GlobalSMBSeslock);
595 read_unlock(&cifs_tcp_ses_lock);
585 return true; 596 return true;
586 } 597 }
587 read_unlock(&GlobalSMBSeslock); 598 read_unlock(&GlobalSMBSeslock);
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 1da4ab250eae..07b8e71544ee 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -103,56 +103,6 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
103 mempool_free(midEntry, cifs_mid_poolp); 103 mempool_free(midEntry, cifs_mid_poolp);
104} 104}
105 105
106struct oplock_q_entry *
107AllocOplockQEntry(struct inode *pinode, __u16 fid, struct cifsTconInfo *tcon)
108{
109 struct oplock_q_entry *temp;
110 if ((pinode == NULL) || (tcon == NULL)) {
111 cERROR(1, ("Null parms passed to AllocOplockQEntry"));
112 return NULL;
113 }
114 temp = (struct oplock_q_entry *) kmem_cache_alloc(cifs_oplock_cachep,
115 GFP_KERNEL);
116 if (temp == NULL)
117 return temp;
118 else {
119 temp->pinode = pinode;
120 temp->tcon = tcon;
121 temp->netfid = fid;
122 spin_lock(&cifs_oplock_lock);
123 list_add_tail(&temp->qhead, &cifs_oplock_list);
124 spin_unlock(&cifs_oplock_lock);
125 }
126 return temp;
127}
128
129void DeleteOplockQEntry(struct oplock_q_entry *oplockEntry)
130{
131 spin_lock(&cifs_oplock_lock);
132 /* should we check if list empty first? */
133 list_del(&oplockEntry->qhead);
134 spin_unlock(&cifs_oplock_lock);
135 kmem_cache_free(cifs_oplock_cachep, oplockEntry);
136}
137
138
139void DeleteTconOplockQEntries(struct cifsTconInfo *tcon)
140{
141 struct oplock_q_entry *temp;
142
143 if (tcon == NULL)
144 return;
145
146 spin_lock(&cifs_oplock_lock);
147 list_for_each_entry(temp, &cifs_oplock_list, qhead) {
148 if ((temp->tcon) && (temp->tcon == tcon)) {
149 list_del(&temp->qhead);
150 kmem_cache_free(cifs_oplock_cachep, temp);
151 }
152 }
153 spin_unlock(&cifs_oplock_lock);
154}
155
156static int 106static int
157smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec) 107smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
158{ 108{