aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/smb2misc.c
diff options
context:
space:
mode:
authorPavel Shilovsky <pshilovsky@samba.org>2012-09-18 19:20:33 -0400
committerSteve French <smfrench@gmail.com>2012-09-24 22:46:30 -0400
commit983c88a497914d60c91f431b05a8449ddda19167 (patch)
tree6e8ce5d70c6a584472ed7414497d06c034eb0595 /fs/cifs/smb2misc.c
parent95a3f2f377735ed13e42d3b8039aa1d73af2c90e (diff)
CIFS: Add oplock break support for SMB2
Signed-off-by: Pavel Shilovsky <pshilovsky@samba.org> Signed-off-by: Steve French <smfrench@gmail.com>
Diffstat (limited to 'fs/cifs/smb2misc.c')
-rw-r--r--fs/cifs/smb2misc.c76
1 files changed, 74 insertions, 2 deletions
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c
index 78225f517a60..01479a3fee8d 100644
--- a/fs/cifs/smb2misc.c
+++ b/fs/cifs/smb2misc.c
@@ -142,8 +142,8 @@ smb2_check_message(char *buf, unsigned int length)
142 } 142 }
143 143
144 if (smb2_rsp_struct_sizes[command] != pdu->StructureSize2) { 144 if (smb2_rsp_struct_sizes[command] != pdu->StructureSize2) {
145 if (hdr->Status == 0 || 145 if (command != SMB2_OPLOCK_BREAK_HE && (hdr->Status == 0 ||
146 pdu->StructureSize2 != SMB2_ERROR_STRUCTURE_SIZE2) { 146 pdu->StructureSize2 != SMB2_ERROR_STRUCTURE_SIZE2)) {
147 /* error packets have 9 byte structure size */ 147 /* error packets have 9 byte structure size */
148 cERROR(1, "Illegal response size %u for command %d", 148 cERROR(1, "Illegal response size %u for command %d",
149 le16_to_cpu(pdu->StructureSize2), command); 149 le16_to_cpu(pdu->StructureSize2), command);
@@ -162,6 +162,9 @@ smb2_check_message(char *buf, unsigned int length)
162 if (4 + len != clc_len) { 162 if (4 + len != clc_len) {
163 cFYI(1, "Calculated size %u length %u mismatch mid %llu", 163 cFYI(1, "Calculated size %u length %u mismatch mid %llu",
164 clc_len, 4 + len, mid); 164 clc_len, 4 + len, mid);
165 /* Windows 7 server returns 24 bytes more */
166 if (clc_len + 20 == len && command == SMB2_OPLOCK_BREAK_HE)
167 return 0;
165 /* server can return one byte more */ 168 /* server can return one byte more */
166 if (clc_len == 4 + len + 1) 169 if (clc_len == 4 + len + 1)
167 return 0; 170 return 0;
@@ -356,3 +359,72 @@ cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb)
356 CIFS_MOUNT_MAP_SPECIAL_CHR); 359 CIFS_MOUNT_MAP_SPECIAL_CHR);
357 return to; 360 return to;
358} 361}
362
363bool
364smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
365{
366 struct smb2_oplock_break *rsp = (struct smb2_oplock_break *)buffer;
367 struct list_head *tmp, *tmp1, *tmp2;
368 struct cifs_ses *ses;
369 struct cifs_tcon *tcon;
370 struct cifsInodeInfo *cinode;
371 struct cifsFileInfo *cfile;
372
373 cFYI(1, "Checking for oplock break");
374
375 if (rsp->hdr.Command != SMB2_OPLOCK_BREAK)
376 return false;
377
378 if (le16_to_cpu(rsp->StructureSize) !=
379 smb2_rsp_struct_sizes[SMB2_OPLOCK_BREAK_HE]) {
380 return false;
381 }
382
383 cFYI(1, "oplock level 0x%d", rsp->OplockLevel);
384
385 /* look up tcon based on tid & uid */
386 spin_lock(&cifs_tcp_ses_lock);
387 list_for_each(tmp, &server->smb_ses_list) {
388 ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
389 list_for_each(tmp1, &ses->tcon_list) {
390 tcon = list_entry(tmp1, struct cifs_tcon, tcon_list);
391
392 cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks);
393 spin_lock(&cifs_file_list_lock);
394 list_for_each(tmp2, &tcon->openFileList) {
395 cfile = list_entry(tmp2, struct cifsFileInfo,
396 tlist);
397 if (rsp->PersistentFid !=
398 cfile->fid.persistent_fid ||
399 rsp->VolatileFid !=
400 cfile->fid.volatile_fid)
401 continue;
402
403 cFYI(1, "file id match, oplock break");
404 cinode = CIFS_I(cfile->dentry->d_inode);
405
406 if (!cinode->clientCanCacheAll &&
407 rsp->OplockLevel == SMB2_OPLOCK_LEVEL_NONE)
408 cfile->oplock_break_cancelled = true;
409 else
410 cfile->oplock_break_cancelled = false;
411
412 smb2_set_oplock_level(cinode,
413 rsp->OplockLevel ? SMB2_OPLOCK_LEVEL_II : 0);
414
415 queue_work(cifsiod_wq, &cfile->oplock_break);
416
417 spin_unlock(&cifs_file_list_lock);
418 spin_unlock(&cifs_tcp_ses_lock);
419 return true;
420 }
421 spin_unlock(&cifs_file_list_lock);
422 spin_unlock(&cifs_tcp_ses_lock);
423 cFYI(1, "No matching file for oplock break");
424 return true;
425 }
426 }
427 spin_unlock(&cifs_tcp_ses_lock);
428 cFYI(1, "Can not process oplock break for non-existent connection");
429 return false;
430}