@@ -238,6 +238,23 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
238
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
258
struct cifsFileInfo *
242
259
cifs_new_fileinfo (struct cifs_fid * fid , struct file * file ,
243
260
struct tcon_link * tlink , __u32 oplock )
@@ -248,6 +265,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
248
265
struct cifsFileInfo * cfile ;
249
266
struct cifs_fid_locks * fdlocks ;
250
267
struct cifs_tcon * tcon = tlink_tcon (tlink );
268
+ struct TCP_Server_Info * server = tcon -> ses -> server ;
251
269
252
270
cfile = kzalloc (sizeof (struct cifsFileInfo ), GFP_KERNEL );
253
271
if (cfile == NULL )
@@ -276,12 +294,22 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
276
294
INIT_WORK (& cfile -> oplock_break , cifs_oplock_break );
277
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
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
309
oplock = fid -> pending_open -> oplock ;
282
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
314
list_add (& cfile -> tlist , & tcon -> openFileList );
287
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
1450
struct cifsFileInfo * cfile = (struct cifsFileInfo * )file -> private_data ;
1423
1451
struct cifs_tcon * tcon = tlink_tcon (cfile -> tlink );
1424
1452
struct TCP_Server_Info * server = tcon -> ses -> server ;
1453
+ struct inode * inode = cfile -> dentry -> d_inode ;
1425
1454
1426
1455
if (posix_lck ) {
1427
1456
int posix_lock_type ;
@@ -1459,6 +1488,21 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type,
1459
1488
if (!rc )
1460
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
1506
rc = server -> ops -> mand_lock (xid , cfile , flock -> fl_start , length ,
1463
1507
type , 1 , 0 , wait_flag );
1464
1508
if (rc ) {
@@ -3537,6 +3581,13 @@ void cifs_oplock_break(struct work_struct *work)
3537
3581
struct cifs_tcon * tcon = tlink_tcon (cfile -> tlink );
3538
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
3591
if (inode && S_ISREG (inode -> i_mode )) {
3541
3592
if (cinode -> clientCanCacheRead )
3542
3593
break_lease (inode , O_RDONLY );
0 commit comments