aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/cifs/cifsglob.h1
-rw-r--r--fs/cifs/file.c55
-rw-r--r--fs/cifs/smb1ops.c1
-rw-r--r--fs/cifs/smb2ops.c2
4 files changed, 57 insertions, 2 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index dfab450a191..e6899cea1c3 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -386,6 +386,7 @@ struct smb_version_values {
386 unsigned int cap_unix; 386 unsigned int cap_unix;
387 unsigned int cap_nt_find; 387 unsigned int cap_nt_find;
388 unsigned int cap_large_files; 388 unsigned int cap_large_files;
389 unsigned int oplock_read;
389}; 390};
390 391
391#define HEADER_SIZE(server) (server->vals->header_size) 392#define HEADER_SIZE(server) (server->vals->header_size)
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 22c37254b64..8ea6ca50a66 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -238,6 +238,23 @@ out:
238 return rc; 238 return rc;
239} 239}
240 240
241static bool
242cifs_has_mand_locks(struct cifsInodeInfo *cinode)
243{
244 struct cifs_fid_locks *cur;
245 bool has_locks = false;
246
247 down_read(&cinode->lock_sem);
248 list_for_each_entry(cur, &cinode->llist, llist) {
249 if (!list_empty(&cur->locks)) {
250 has_locks = true;
251 break;
252 }
253 }
254 up_read(&cinode->lock_sem);
255 return has_locks;
256}
257
241struct cifsFileInfo * 258struct cifsFileInfo *
242cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, 259cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
243 struct tcon_link *tlink, __u32 oplock) 260 struct tcon_link *tlink, __u32 oplock)
@@ -248,6 +265,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
248 struct cifsFileInfo *cfile; 265 struct cifsFileInfo *cfile;
249 struct cifs_fid_locks *fdlocks; 266 struct cifs_fid_locks *fdlocks;
250 struct cifs_tcon *tcon = tlink_tcon(tlink); 267 struct cifs_tcon *tcon = tlink_tcon(tlink);
268 struct TCP_Server_Info *server = tcon->ses->server;
251 269
252 cfile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); 270 cfile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
253 if (cfile == NULL) 271 if (cfile == NULL)
@@ -276,12 +294,22 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
276 INIT_WORK(&cfile->oplock_break, cifs_oplock_break); 294 INIT_WORK(&cfile->oplock_break, cifs_oplock_break);
277 mutex_init(&cfile->fh_mutex); 295 mutex_init(&cfile->fh_mutex);
278 296
297 /*
298 * If the server returned a read oplock and we have mandatory brlocks,
299 * set oplock level to None.
300 */
301 if (oplock == server->vals->oplock_read &&
302 cifs_has_mand_locks(cinode)) {
303 cFYI(1, "Reset oplock val from read to None due to mand locks");
304 oplock = 0;
305 }
306
279 spin_lock(&cifs_file_list_lock); 307 spin_lock(&cifs_file_list_lock);
280 if (fid->pending_open->oplock != CIFS_OPLOCK_NO_CHANGE) 308 if (fid->pending_open->oplock != CIFS_OPLOCK_NO_CHANGE && oplock)
281 oplock = fid->pending_open->oplock; 309 oplock = fid->pending_open->oplock;
282 list_del(&fid->pending_open->olist); 310 list_del(&fid->pending_open->olist);
283 311
284 tlink_tcon(tlink)->ses->server->ops->set_fid(cfile, fid, oplock); 312 server->ops->set_fid(cfile, fid, oplock);
285 313
286 list_add(&cfile->tlist, &tcon->openFileList); 314 list_add(&cfile->tlist, &tcon->openFileList);
287 /* if readable file instance put first in list*/ 315 /* if readable file instance put first in list*/
@@ -1422,6 +1450,7 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type,
1422 struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data; 1450 struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data;
1423 struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); 1451 struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
1424 struct TCP_Server_Info *server = tcon->ses->server; 1452 struct TCP_Server_Info *server = tcon->ses->server;
1453 struct inode *inode = cfile->dentry->d_inode;
1425 1454
1426 if (posix_lck) { 1455 if (posix_lck) {
1427 int posix_lock_type; 1456 int posix_lock_type;
@@ -1459,6 +1488,21 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type,
1459 if (!rc) 1488 if (!rc)
1460 goto out; 1489 goto out;
1461 1490
1491 /*
1492 * Windows 7 server can delay breaking lease from read to None
1493 * if we set a byte-range lock on a file - break it explicitly
1494 * before sending the lock to the server to be sure the next
1495 * read won't conflict with non-overlapted locks due to
1496 * pagereading.
1497 */
1498 if (!CIFS_I(inode)->clientCanCacheAll &&
1499 CIFS_I(inode)->clientCanCacheRead) {
1500 cifs_invalidate_mapping(inode);
1501 cFYI(1, "Set no oplock for inode=%p due to mand locks",
1502 inode);
1503 CIFS_I(inode)->clientCanCacheRead = false;
1504 }
1505
1462 rc = server->ops->mand_lock(xid, cfile, flock->fl_start, length, 1506 rc = server->ops->mand_lock(xid, cfile, flock->fl_start, length,
1463 type, 1, 0, wait_flag); 1507 type, 1, 0, wait_flag);
1464 if (rc) { 1508 if (rc) {
@@ -3537,6 +3581,13 @@ void cifs_oplock_break(struct work_struct *work)
3537 struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); 3581 struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
3538 int rc = 0; 3582 int rc = 0;
3539 3583
3584 if (!cinode->clientCanCacheAll && cinode->clientCanCacheRead &&
3585 cifs_has_mand_locks(cinode)) {
3586 cFYI(1, "Reset oplock to None for inode=%p due to mand locks",
3587 inode);
3588 cinode->clientCanCacheRead = false;
3589 }
3590
3540 if (inode && S_ISREG(inode->i_mode)) { 3591 if (inode && S_ISREG(inode->i_mode)) {
3541 if (cinode->clientCanCacheRead) 3592 if (cinode->clientCanCacheRead)
3542 break_lease(inode, O_RDONLY); 3593 break_lease(inode, O_RDONLY);
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index dd79056c058..47bc5a87f94 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -959,4 +959,5 @@ struct smb_version_values smb1_values = {
959 .cap_unix = CAP_UNIX, 959 .cap_unix = CAP_UNIX,
960 .cap_nt_find = CAP_NT_SMBS | CAP_NT_FIND, 960 .cap_nt_find = CAP_NT_SMBS | CAP_NT_FIND,
961 .cap_large_files = CAP_LARGE_FILES, 961 .cap_large_files = CAP_LARGE_FILES,
962 .oplock_read = OPLOCK_READ,
962}; 963};
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index d79de7bc443..c9c7aa7ed96 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -708,6 +708,7 @@ struct smb_version_values smb20_values = {
708 .cap_unix = 0, 708 .cap_unix = 0,
709 .cap_nt_find = SMB2_NT_FIND, 709 .cap_nt_find = SMB2_NT_FIND,
710 .cap_large_files = SMB2_LARGE_FILES, 710 .cap_large_files = SMB2_LARGE_FILES,
711 .oplock_read = SMB2_OPLOCK_LEVEL_II,
711}; 712};
712 713
713struct smb_version_values smb21_values = { 714struct smb_version_values smb21_values = {
@@ -725,6 +726,7 @@ struct smb_version_values smb21_values = {
725 .cap_unix = 0, 726 .cap_unix = 0,
726 .cap_nt_find = SMB2_NT_FIND, 727 .cap_nt_find = SMB2_NT_FIND,
727 .cap_large_files = SMB2_LARGE_FILES, 728 .cap_large_files = SMB2_LARGE_FILES,
729 .oplock_read = SMB2_OPLOCK_LEVEL_II,
728}; 730};
729 731
730struct smb_version_values smb30_values = { 732struct smb_version_values smb30_values = {