diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/cifs/cifsglob.h | 1 | ||||
-rw-r--r-- | fs/cifs/file.c | 55 | ||||
-rw-r--r-- | fs/cifs/smb1ops.c | 1 | ||||
-rw-r--r-- | fs/cifs/smb2ops.c | 2 |
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 | ||
241 | static bool | ||
242 | cifs_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 | |||
241 | struct cifsFileInfo * | 258 | struct cifsFileInfo * |
242 | cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, | 259 | cifs_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 | ||
713 | struct smb_version_values smb21_values = { | 714 | struct 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 | ||
730 | struct smb_version_values smb30_values = { | 732 | struct smb_version_values smb30_values = { |