Print this page
NEX-5665 SMB2 oplock leases
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-5665 SMB2 oplock leases
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-1643 dtrace provider for smbsrv
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
NEX-6041 Should pass the smbtorture lock tests
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
NEX-1192 add context options to xpg4 grep (nits)
NEX-1192 add context options to xpg4 grep
SUP-867 panic in smb_com_locking_andx
SMB-11 SMB2 message parse & dispatch
SMB-12 SMB2 Negotiate Protocol
SMB-13 SMB2 Session Setup
SMB-14 SMB2 Logoff
SMB-15 SMB2 Tree Connect
SMB-16 SMB2 Tree Disconnect
SMB-17 SMB2 Create
SMB-18 SMB2 Close
SMB-19 SMB2 Flush
SMB-20 SMB2 Read
SMB-21 SMB2 Write
SMB-22 SMB2 Lock/Unlock
SMB-23 SMB2 Ioctl
SMB-24 SMB2 Cancel
SMB-25 SMB2 Echo
SMB-26 SMB2 Query Dir
SMB-27 SMB2 Change Notify
SMB-28 SMB2 Query Info
SMB-29 SMB2 Set Info
SMB-30 SMB2 Oplocks
SMB-53 SMB2 Create Context options
(SMB2 code review cleanup 1, 2, 3)

*** 19,29 **** * CDDL HEADER END */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. ! * Copyright 2014 Nexenta Systems, Inc. All rights reserved. */ /* * SMB: locking_andx * --- 19,29 ---- * CDDL HEADER END */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. ! * Copyright 2017 Nexenta Systems, Inc. All rights reserved. */ /* * SMB: locking_andx *
*** 210,251 **** * ERRSRV/ERRbaduid */ #include <smbsrv/smb_kproto.h> smb_sdrc_t smb_pre_locking_andx(smb_request_t *sr) { ! DTRACE_SMB_1(op__LockingX__start, smb_request_t *, sr); return (SDRC_SUCCESS); } void smb_post_locking_andx(smb_request_t *sr) { ! DTRACE_SMB_1(op__LockingX__done, smb_request_t *, sr); } smb_sdrc_t smb_com_locking_andx(smb_request_t *sr) { unsigned short i; unsigned char lock_type; /* See lock_type table above */ unsigned char oplock_level; /* The new oplock level */ uint32_t timeout; /* Milliseconds to wait for lock */ unsigned short unlock_num; /* # unlock range structs */ unsigned short lock_num; /* # lock range structs */ - uint32_t save_pid; /* Process Id of owner */ - uint32_t offset32, length32; - uint64_t offset64; - uint64_t length64; DWORD result; int rc; uint32_t ltype; smb_ofile_t *ofile; uint16_t tmp_pid; /* locking uses 16-bit pids */ ! uint8_t brk; rc = smbsr_decode_vwv(sr, "4.wbblww", &sr->smb_fid, &lock_type, &oplock_level, &timeout, &unlock_num, &lock_num); if (rc != 0) return (SDRC_ERROR); --- 210,264 ---- * ERRSRV/ERRbaduid */ #include <smbsrv/smb_kproto.h> + /* + * This is a somewhat arbitrary sanity limit on the length of the + * SMB2_LOCK_ELEMENT array. It usually has length one or two. + */ + int smb_lock_max_elem = 1024; + smb_sdrc_t smb_pre_locking_andx(smb_request_t *sr) { ! DTRACE_SMB_START(op__LockingX, smb_request_t *, sr); return (SDRC_SUCCESS); } void smb_post_locking_andx(smb_request_t *sr) { ! DTRACE_SMB_DONE(op__LockingX, smb_request_t *, sr); } + struct lreq { + uint64_t off; + uint64_t len; + uint32_t pid; + uint32_t _x; + }; + smb_sdrc_t smb_com_locking_andx(smb_request_t *sr) { unsigned short i; unsigned char lock_type; /* See lock_type table above */ unsigned char oplock_level; /* The new oplock level */ uint32_t timeout; /* Milliseconds to wait for lock */ unsigned short unlock_num; /* # unlock range structs */ unsigned short lock_num; /* # lock range structs */ DWORD result; int rc; uint32_t ltype; + uint32_t status; smb_ofile_t *ofile; uint16_t tmp_pid; /* locking uses 16-bit pids */ ! uint32_t lrv_tot; ! struct lreq *lrv_ul; ! struct lreq *lrv_lk; ! struct lreq *lr; rc = smbsr_decode_vwv(sr, "4.wbblww", &sr->smb_fid, &lock_type, &oplock_level, &timeout, &unlock_num, &lock_num); if (rc != 0) return (SDRC_ERROR);
*** 260,282 **** smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, ERRDOS, ERROR_INVALID_PARAMETER); return (SDRC_ERROR); } if (lock_type & LOCKING_ANDX_SHARED_LOCK) ltype = SMB_LOCK_TYPE_READONLY; else ltype = SMB_LOCK_TYPE_READWRITE; - save_pid = sr->smb_pid; /* Save the original pid */ - if (lock_type & LOCKING_ANDX_OPLOCK_RELEASE) { if (oplock_level == 0) ! brk = SMB_OPLOCK_BREAK_TO_NONE; else ! brk = SMB_OPLOCK_BREAK_TO_LEVEL_II; ! smb_oplock_ack(ofile->f_node, ofile, brk); if (unlock_num == 0 && lock_num == 0) return (SDRC_NO_REPLY); } /* --- 273,305 ---- smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, ERRDOS, ERROR_INVALID_PARAMETER); return (SDRC_ERROR); } + if (unlock_num > smb_lock_max_elem || + lock_num > smb_lock_max_elem) { + smbsr_error(sr, NT_STATUS_INSUFFICIENT_RESOURCES, + ERRDOS, ERROR_NO_SYSTEM_RESOURCES); + return (SDRC_ERROR); + } + if (lock_type & LOCKING_ANDX_SHARED_LOCK) ltype = SMB_LOCK_TYPE_READONLY; else ltype = SMB_LOCK_TYPE_READWRITE; if (lock_type & LOCKING_ANDX_OPLOCK_RELEASE) { + uint32_t NewLevel; if (oplock_level == 0) ! NewLevel = OPLOCK_LEVEL_NONE; else ! NewLevel = OPLOCK_LEVEL_TWO; ! status = smb_oplock_ack_break(sr, ofile, &NewLevel); ! if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { ! (void) smb_oplock_wait_break(ofile->f_node, 0); ! status = 0; ! } if (unlock_num == 0 && lock_num == 0) return (SDRC_NO_REPLY); } /*
*** 287,392 **** smbsr_error(sr, 0, ERRDOS, ERROR_ATOMIC_LOCKS_NOT_SUPPORTED); return (SDRC_ERROR); } - /* - * No support for cancel lock (smbtorture expects this) - */ - if (lock_type & LOCKING_ANDX_CANCEL_LOCK) { - smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, - ERRDOS, ERROR_INVALID_PARAMETER); - return (SDRC_ERROR); - } - if (lock_type & LOCKING_ANDX_LARGE_FILES) { /* * negotiated protocol should be NT LM 0.12 or later */ if (sr->session->dialect < NT_LM_0_12) { smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, ERRDOS, ERROR_INVALID_PARAMETER); return (SDRC_ERROR); } ! for (i = 0; i < unlock_num; i++) { rc = smb_mbc_decodef(&sr->smb_data, "w2.QQ", ! &tmp_pid, &offset64, &length64); if (rc) { /* * This is the error returned by Windows 2000 * even when STATUS32 has been negotiated. */ smbsr_error(sr, 0, ERRSRV, ERRerror); return (SDRC_ERROR); } - sr->smb_pid = tmp_pid; /* NB: 16-bit */ - - result = smb_unlock_range(sr, sr->fid_ofile->f_node, - offset64, length64); - if (result != NT_STATUS_SUCCESS) { - smbsr_error(sr, NT_STATUS_RANGE_NOT_LOCKED, - ERRDOS, ERROR_NOT_LOCKED); - return (SDRC_ERROR); } - } ! for (i = 0; i < lock_num; i++) { ! rc = smb_mbc_decodef(&sr->smb_data, "w2.QQ", ! &tmp_pid, &offset64, &length64); ! if (rc) { ! smbsr_error(sr, 0, ERRSRV, ERRerror); ! return (SDRC_ERROR); ! } ! sr->smb_pid = tmp_pid; /* NB: 16-bit */ ! result = smb_lock_range(sr, offset64, length64, timeout, ! ltype); if (result != NT_STATUS_SUCCESS) { ! smb_lock_range_error(sr, result); return (SDRC_ERROR); } } ! } else { for (i = 0; i < unlock_num; i++) { ! rc = smb_mbc_decodef(&sr->smb_data, "wll", &tmp_pid, ! &offset32, &length32); ! if (rc) { ! smbsr_error(sr, 0, ERRSRV, ERRerror); ! return (SDRC_ERROR); ! } ! sr->smb_pid = tmp_pid; /* NB: 16-bit */ ! result = smb_unlock_range(sr, sr->fid_ofile->f_node, ! (uint64_t)offset32, (uint64_t)length32); if (result != NT_STATUS_SUCCESS) { smbsr_error(sr, NT_STATUS_RANGE_NOT_LOCKED, ERRDOS, ERROR_NOT_LOCKED); return (SDRC_ERROR); } } - for (i = 0; i < lock_num; i++) { ! rc = smb_mbc_decodef(&sr->smb_data, "wll", &tmp_pid, ! &offset32, &length32); ! if (rc) { ! smbsr_error(sr, 0, ERRSRV, ERRerror); ! return (SDRC_ERROR); ! } ! sr->smb_pid = tmp_pid; /* NB: 16-bit */ ! result = smb_lock_range(sr, (uint64_t)offset32, ! (uint64_t)length32, timeout, ltype); if (result != NT_STATUS_SUCCESS) { smb_lock_range_error(sr, result); return (SDRC_ERROR); } } - } ! sr->smb_pid = save_pid; ! if (smbsr_encode_result(sr, 2, 0, "bb.ww", 2, sr->andx_com, 7, 0)) return (SDRC_ERROR); return (SDRC_SUCCESS); } /* --- 310,417 ---- smbsr_error(sr, 0, ERRDOS, ERROR_ATOMIC_LOCKS_NOT_SUPPORTED); return (SDRC_ERROR); } if (lock_type & LOCKING_ANDX_LARGE_FILES) { /* * negotiated protocol should be NT LM 0.12 or later */ if (sr->session->dialect < NT_LM_0_12) { smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, ERRDOS, ERROR_INVALID_PARAMETER); return (SDRC_ERROR); } + } ! /* ! * Parse the unlock, lock vectors. Will parse all the ! * unlock + lock records into one array, and then use ! * pointers to the unlock and lock parts. ! */ ! lrv_tot = unlock_num + lock_num; ! lrv_ul = smb_srm_zalloc(sr, lrv_tot * sizeof (*lrv_ul)); ! lrv_lk = &lrv_ul[unlock_num]; ! ! for (i = 0; i < lrv_tot; i++) { ! lr = &lrv_ul[i]; ! if (lock_type & LOCKING_ANDX_LARGE_FILES) { rc = smb_mbc_decodef(&sr->smb_data, "w2.QQ", ! &tmp_pid, &lr->off, &lr->len); ! } else { ! uint32_t offset32, length32; ! rc = smb_mbc_decodef(&sr->smb_data, "wll", ! &tmp_pid, &offset32, &length32); ! lr->off = offset32; ! lr->len = length32; ! } ! lr->pid = tmp_pid; /* 16-bit PID */ if (rc) { /* * This is the error returned by Windows 2000 * even when STATUS32 has been negotiated. */ smbsr_error(sr, 0, ERRSRV, ERRerror); return (SDRC_ERROR); } } ! /* ! * Cancel waiting locks. MS-CIFS says one place that ! * this cancels all waiting locks for this FID+PID, ! * but smbtorture insists this cancels just one. ! * Tests with Windows 7 confirms that. ! */ ! if ((lock_type & LOCKING_ANDX_CANCEL_LOCK) != 0) { ! lr = lrv_lk; ! result = smb_lock_range_cancel(sr, lr->off, lr->len, lr->pid); ! if (result != NT_STATUS_SUCCESS) { ! smbsr_error(sr, 0, ERRDOS, ! ERROR_CANCEL_VIOLATION); return (SDRC_ERROR); } + goto out; } ! ! /* ! * Normal unlock and lock list ! */ for (i = 0; i < unlock_num; i++) { ! lr = &lrv_ul[i]; ! result = smb_unlock_range(sr, lr->off, lr->len, lr->pid); if (result != NT_STATUS_SUCCESS) { smbsr_error(sr, NT_STATUS_RANGE_NOT_LOCKED, ERRDOS, ERROR_NOT_LOCKED); return (SDRC_ERROR); } } for (i = 0; i < lock_num; i++) { ! lr = &lrv_lk[i]; ! result = smb_lock_range(sr, lr->off, lr->len, lr->pid, ! ltype, timeout); if (result != NT_STATUS_SUCCESS) { + /* + * Oh... we have to rollback. + */ + while (i > 0) { + --i; + lr = &lrv_lk[i]; + (void) smb_unlock_range(sr, + lr->off, lr->len, lr->pid); + } smb_lock_range_error(sr, result); return (SDRC_ERROR); } } ! out: ! if (smbsr_encode_result(sr, 2, 0, "bb.ww", ! 2, sr->andx_com, 0x27, 0) != 0) return (SDRC_ERROR); return (SDRC_SUCCESS); } /*
*** 393,417 **** * Compose an SMB1 Oplock Break Notification packet, including * the SMB1 header and everything, in sr->reply. * The caller will send it and free the request. */ void ! smb1_oplock_break_notification(smb_request_t *sr, uint8_t brk) { smb_ofile_t *ofile = sr->fid_ofile; uint16_t fid; uint8_t lock_type; uint8_t oplock_level; ! switch (brk) { default: ASSERT(0); /* FALLTHROUGH */ ! case SMB_OPLOCK_BREAK_TO_NONE: oplock_level = 0; break; ! case SMB_OPLOCK_BREAK_TO_LEVEL_II: oplock_level = 1; break; } sr->smb_com = SMB_COM_LOCKING_ANDX; --- 418,446 ---- * Compose an SMB1 Oplock Break Notification packet, including * the SMB1 header and everything, in sr->reply. * The caller will send it and free the request. */ void ! smb1_oplock_break_notification(smb_request_t *sr, uint32_t NewLevel) { smb_ofile_t *ofile = sr->fid_ofile; uint16_t fid; uint8_t lock_type; uint8_t oplock_level; ! /* ! * Convert internal level to SMB1 ! */ ! switch (NewLevel) { default: ASSERT(0); /* FALLTHROUGH */ ! case OPLOCK_LEVEL_NONE: oplock_level = 0; break; ! ! case OPLOCK_LEVEL_TWO: oplock_level = 1; break; } sr->smb_com = SMB_COM_LOCKING_ANDX;