1*a90cf9f2SGordon Ross /* 2*a90cf9f2SGordon Ross * This file and its contents are supplied under the terms of the 3*a90cf9f2SGordon Ross * Common Development and Distribution License ("CDDL"), version 1.0. 4*a90cf9f2SGordon Ross * You may only use this file in accordance with the terms of version 5*a90cf9f2SGordon Ross * 1.0 of the CDDL. 6*a90cf9f2SGordon Ross * 7*a90cf9f2SGordon Ross * A full copy of the text of the CDDL should have accompanied this 8*a90cf9f2SGordon Ross * source. A copy of the CDDL is also available via the Internet at 9*a90cf9f2SGordon Ross * http://www.illumos.org/license/CDDL. 10*a90cf9f2SGordon Ross */ 11*a90cf9f2SGordon Ross 12*a90cf9f2SGordon Ross /* 13*a90cf9f2SGordon Ross * Copyright 2014 Nexenta Systems, Inc. All rights reserved. 14*a90cf9f2SGordon Ross */ 15*a90cf9f2SGordon Ross 16*a90cf9f2SGordon Ross /* 17*a90cf9f2SGordon Ross * Dispatch function for SMB2_LOCK 18*a90cf9f2SGordon Ross */ 19*a90cf9f2SGordon Ross 20*a90cf9f2SGordon Ross #include <smbsrv/smb2_kproto.h> 21*a90cf9f2SGordon Ross 22*a90cf9f2SGordon Ross struct SMB2_LOCK_ELEMENT { 23*a90cf9f2SGordon Ross uint64_t Offset; 24*a90cf9f2SGordon Ross uint64_t Length; 25*a90cf9f2SGordon Ross uint32_t Flags; 26*a90cf9f2SGordon Ross uint32_t reserved; 27*a90cf9f2SGordon Ross }; 28*a90cf9f2SGordon Ross 29*a90cf9f2SGordon Ross static smb_sdrc_t smb2_lock_async(smb_request_t *); 30*a90cf9f2SGordon Ross static uint32_t smb2_lock_exec(smb_request_t *, uint16_t); 31*a90cf9f2SGordon Ross static uint32_t smb2_lock_elem(smb_request_t *, struct SMB2_LOCK_ELEMENT *); 32*a90cf9f2SGordon Ross 33*a90cf9f2SGordon Ross /* 34*a90cf9f2SGordon Ross * This is a somewhat arbitrary sanity limit on the length of the 35*a90cf9f2SGordon Ross * SMB2_LOCK_ELEMENT array. It usually has length one or two. 36*a90cf9f2SGordon Ross */ 37*a90cf9f2SGordon Ross int smb2_lock_max_elem = 1024; 38*a90cf9f2SGordon Ross 39*a90cf9f2SGordon Ross smb_sdrc_t 40*a90cf9f2SGordon Ross smb2_lock(smb_request_t *sr) 41*a90cf9f2SGordon Ross { 42*a90cf9f2SGordon Ross struct SMB2_LOCK_ELEMENT elem; 43*a90cf9f2SGordon Ross smb2fid_t smb2fid; 44*a90cf9f2SGordon Ross uint32_t save_offset; 45*a90cf9f2SGordon Ross uint32_t LockSequence; 46*a90cf9f2SGordon Ross uint32_t status; 47*a90cf9f2SGordon Ross uint16_t StructSize; 48*a90cf9f2SGordon Ross uint16_t LockCount; 49*a90cf9f2SGordon Ross uint16_t i; 50*a90cf9f2SGordon Ross boolean_t MayBlock = B_FALSE; 51*a90cf9f2SGordon Ross int rc = 0; 52*a90cf9f2SGordon Ross 53*a90cf9f2SGordon Ross /* 54*a90cf9f2SGordon Ross * SMB2 Lock request 55*a90cf9f2SGordon Ross */ 56*a90cf9f2SGordon Ross rc = smb_mbc_decodef( 57*a90cf9f2SGordon Ross &sr->smb_data, "wwlqq", 58*a90cf9f2SGordon Ross &StructSize, /* w */ 59*a90cf9f2SGordon Ross &LockCount, /* w */ 60*a90cf9f2SGordon Ross &LockSequence, /* l */ 61*a90cf9f2SGordon Ross &smb2fid.persistent, /* q */ 62*a90cf9f2SGordon Ross &smb2fid.temporal); /* q */ 63*a90cf9f2SGordon Ross if (rc || StructSize != 48) 64*a90cf9f2SGordon Ross return (SDRC_ERROR); 65*a90cf9f2SGordon Ross 66*a90cf9f2SGordon Ross status = smb2sr_lookup_fid(sr, &smb2fid); 67*a90cf9f2SGordon Ross if (status) 68*a90cf9f2SGordon Ross goto errout; 69*a90cf9f2SGordon Ross if (sr->fid_ofile->f_node == NULL || LockCount == 0) { 70*a90cf9f2SGordon Ross status = NT_STATUS_INVALID_PARAMETER; 71*a90cf9f2SGordon Ross goto errout; 72*a90cf9f2SGordon Ross } 73*a90cf9f2SGordon Ross if (LockCount > smb2_lock_max_elem) { 74*a90cf9f2SGordon Ross status = NT_STATUS_INSUFFICIENT_RESOURCES; 75*a90cf9f2SGordon Ross goto errout; 76*a90cf9f2SGordon Ross } 77*a90cf9f2SGordon Ross 78*a90cf9f2SGordon Ross /* 79*a90cf9f2SGordon Ross * Process the array of SMB2_LOCK_ELEMENT structs 80*a90cf9f2SGordon Ross * We do this twice. (it's always a short list) 81*a90cf9f2SGordon Ross * The first time, just validate the flags, and check 82*a90cf9f2SGordon Ross * if any of the locking request might need to block. 83*a90cf9f2SGordon Ross * The second time (either here, or in the async 84*a90cf9f2SGordon Ross * handler function) process the locks for real. 85*a90cf9f2SGordon Ross */ 86*a90cf9f2SGordon Ross save_offset = sr->smb_data.chain_offset; 87*a90cf9f2SGordon Ross for (i = 0; i < LockCount; i++) { 88*a90cf9f2SGordon Ross rc = smb_mbc_decodef( 89*a90cf9f2SGordon Ross &sr->smb_data, "qqll", 90*a90cf9f2SGordon Ross &elem.Offset, /* q */ 91*a90cf9f2SGordon Ross &elem.Length, /* q */ 92*a90cf9f2SGordon Ross &elem.Flags, /* l */ 93*a90cf9f2SGordon Ross &elem.reserved); /* l */ 94*a90cf9f2SGordon Ross if (rc) { 95*a90cf9f2SGordon Ross status = NT_STATUS_INVALID_PARAMETER; 96*a90cf9f2SGordon Ross goto errout; 97*a90cf9f2SGordon Ross } 98*a90cf9f2SGordon Ross 99*a90cf9f2SGordon Ross /* 100*a90cf9f2SGordon Ross * Make sure the flags are valid; 101*a90cf9f2SGordon Ross * Find out if we might block. 102*a90cf9f2SGordon Ross */ 103*a90cf9f2SGordon Ross switch (elem.Flags) { 104*a90cf9f2SGordon Ross case SMB2_LOCKFLAG_SHARED_LOCK: 105*a90cf9f2SGordon Ross case SMB2_LOCKFLAG_EXCLUSIVE_LOCK: 106*a90cf9f2SGordon Ross MayBlock = B_TRUE; 107*a90cf9f2SGordon Ross break; 108*a90cf9f2SGordon Ross 109*a90cf9f2SGordon Ross /* BEGIN CSTYLED */ 110*a90cf9f2SGordon Ross case SMB2_LOCKFLAG_SHARED_LOCK | 111*a90cf9f2SGordon Ross SMB2_LOCKFLAG_FAIL_IMMEDIATELY: 112*a90cf9f2SGordon Ross case SMB2_LOCKFLAG_EXCLUSIVE_LOCK | 113*a90cf9f2SGordon Ross SMB2_LOCKFLAG_FAIL_IMMEDIATELY: 114*a90cf9f2SGordon Ross case SMB2_LOCKFLAG_UNLOCK: 115*a90cf9f2SGordon Ross /* END CSTYLED */ 116*a90cf9f2SGordon Ross break; 117*a90cf9f2SGordon Ross 118*a90cf9f2SGordon Ross default: 119*a90cf9f2SGordon Ross status = NT_STATUS_INVALID_PARAMETER; 120*a90cf9f2SGordon Ross goto errout; 121*a90cf9f2SGordon Ross } 122*a90cf9f2SGordon Ross } 123*a90cf9f2SGordon Ross 124*a90cf9f2SGordon Ross if (MayBlock) { 125*a90cf9f2SGordon Ross /* 126*a90cf9f2SGordon Ross * May need to block. "Go async". 127*a90cf9f2SGordon Ross */ 128*a90cf9f2SGordon Ross status = smb2sr_go_async(sr, smb2_lock_async); 129*a90cf9f2SGordon Ross goto errout; 130*a90cf9f2SGordon Ross } 131*a90cf9f2SGordon Ross 132*a90cf9f2SGordon Ross sr->smb_data.chain_offset = save_offset; 133*a90cf9f2SGordon Ross status = smb2_lock_exec(sr, LockCount); 134*a90cf9f2SGordon Ross if (status) 135*a90cf9f2SGordon Ross goto errout; 136*a90cf9f2SGordon Ross 137*a90cf9f2SGordon Ross /* 138*a90cf9f2SGordon Ross * SMB2 Lock reply (sync) 139*a90cf9f2SGordon Ross */ 140*a90cf9f2SGordon Ross StructSize = 4; 141*a90cf9f2SGordon Ross (void) smb_mbc_encodef( 142*a90cf9f2SGordon Ross &sr->reply, "w..", 143*a90cf9f2SGordon Ross StructSize); /* w */ 144*a90cf9f2SGordon Ross /* reserved .. */ 145*a90cf9f2SGordon Ross return (SDRC_SUCCESS); 146*a90cf9f2SGordon Ross 147*a90cf9f2SGordon Ross errout: 148*a90cf9f2SGordon Ross smb2sr_put_error(sr, status); 149*a90cf9f2SGordon Ross return (SDRC_SUCCESS); 150*a90cf9f2SGordon Ross } 151*a90cf9f2SGordon Ross 152*a90cf9f2SGordon Ross static smb_sdrc_t 153*a90cf9f2SGordon Ross smb2_lock_async(smb_request_t *sr) 154*a90cf9f2SGordon Ross { 155*a90cf9f2SGordon Ross smb2fid_t smb2fid; 156*a90cf9f2SGordon Ross uint32_t LockSequence; 157*a90cf9f2SGordon Ross uint32_t status; 158*a90cf9f2SGordon Ross uint16_t StructSize; 159*a90cf9f2SGordon Ross uint16_t LockCount; 160*a90cf9f2SGordon Ross int rc = 0; 161*a90cf9f2SGordon Ross 162*a90cf9f2SGordon Ross /* 163*a90cf9f2SGordon Ross * Decode the lock request again. It should all decode 164*a90cf9f2SGordon Ross * exactly the same as the first time we saw it. If not, 165*a90cf9f2SGordon Ross * report an "internal error". 166*a90cf9f2SGordon Ross */ 167*a90cf9f2SGordon Ross rc = smb_mbc_decodef( 168*a90cf9f2SGordon Ross &sr->smb_data, "wwlqq", 169*a90cf9f2SGordon Ross &StructSize, /* w */ 170*a90cf9f2SGordon Ross &LockCount, /* w */ 171*a90cf9f2SGordon Ross &LockSequence, /* l */ 172*a90cf9f2SGordon Ross &smb2fid.persistent, /* q */ 173*a90cf9f2SGordon Ross &smb2fid.temporal); /* q */ 174*a90cf9f2SGordon Ross if (rc || StructSize != 48) 175*a90cf9f2SGordon Ross return (SDRC_ERROR); 176*a90cf9f2SGordon Ross 177*a90cf9f2SGordon Ross status = smb2sr_lookup_fid(sr, &smb2fid); 178*a90cf9f2SGordon Ross if (status) 179*a90cf9f2SGordon Ross goto errout; 180*a90cf9f2SGordon Ross if (sr->fid_ofile->f_node == NULL || LockCount == 0) { 181*a90cf9f2SGordon Ross status = NT_STATUS_INTERNAL_ERROR; 182*a90cf9f2SGordon Ross goto errout; 183*a90cf9f2SGordon Ross } 184*a90cf9f2SGordon Ross 185*a90cf9f2SGordon Ross status = smb2_lock_exec(sr, LockCount); 186*a90cf9f2SGordon Ross if (status) 187*a90cf9f2SGordon Ross goto errout; 188*a90cf9f2SGordon Ross 189*a90cf9f2SGordon Ross /* 190*a90cf9f2SGordon Ross * SMB2 Lock reply (async) 191*a90cf9f2SGordon Ross */ 192*a90cf9f2SGordon Ross StructSize = 4; 193*a90cf9f2SGordon Ross (void) smb_mbc_encodef( 194*a90cf9f2SGordon Ross &sr->reply, "w..", 195*a90cf9f2SGordon Ross StructSize); /* w */ 196*a90cf9f2SGordon Ross /* reserved .. */ 197*a90cf9f2SGordon Ross return (SDRC_SUCCESS); 198*a90cf9f2SGordon Ross 199*a90cf9f2SGordon Ross errout: 200*a90cf9f2SGordon Ross smb2sr_put_error(sr, status); 201*a90cf9f2SGordon Ross return (SDRC_SUCCESS); 202*a90cf9f2SGordon Ross } 203*a90cf9f2SGordon Ross 204*a90cf9f2SGordon Ross /* 205*a90cf9f2SGordon Ross * Execute the vector of locks. This is the common function called by 206*a90cf9f2SGordon Ross * either the sync or async code paths. We've already decoded this 207*a90cf9f2SGordon Ross * request once when we get here, so if there are any decode errors 208*a90cf9f2SGordon Ross * then it's some kind of internal error. 209*a90cf9f2SGordon Ross */ 210*a90cf9f2SGordon Ross static uint32_t 211*a90cf9f2SGordon Ross smb2_lock_exec(smb_request_t *sr, uint16_t LockCount) 212*a90cf9f2SGordon Ross { 213*a90cf9f2SGordon Ross struct SMB2_LOCK_ELEMENT elem; 214*a90cf9f2SGordon Ross uint32_t status = 0; 215*a90cf9f2SGordon Ross uint16_t i; 216*a90cf9f2SGordon Ross int rc; 217*a90cf9f2SGordon Ross 218*a90cf9f2SGordon Ross /* 219*a90cf9f2SGordon Ross * On entry, out position in the input data should be 220*a90cf9f2SGordon Ross * after both the SMB2 header and the fixed part of 221*a90cf9f2SGordon Ross * the SMB Lock request header (24). 222*a90cf9f2SGordon Ross */ 223*a90cf9f2SGordon Ross ASSERT(sr->smb_data.chain_offset == 224*a90cf9f2SGordon Ross (sr->smb2_cmd_hdr + SMB2_HDR_SIZE + 24)); 225*a90cf9f2SGordon Ross 226*a90cf9f2SGordon Ross /* 227*a90cf9f2SGordon Ross * This is checked by our callers, but let's make sure. 228*a90cf9f2SGordon Ross */ 229*a90cf9f2SGordon Ross ASSERT(sr->fid_ofile->f_node != NULL); 230*a90cf9f2SGordon Ross 231*a90cf9f2SGordon Ross for (i = 0; i < LockCount; i++) { 232*a90cf9f2SGordon Ross rc = smb_mbc_decodef( 233*a90cf9f2SGordon Ross &sr->smb_data, "qqll", 234*a90cf9f2SGordon Ross &elem.Offset, /* q */ 235*a90cf9f2SGordon Ross &elem.Length, /* q */ 236*a90cf9f2SGordon Ross &elem.Flags, /* l */ 237*a90cf9f2SGordon Ross &elem.reserved); /* l */ 238*a90cf9f2SGordon Ross if (rc) { 239*a90cf9f2SGordon Ross status = NT_STATUS_INTERNAL_ERROR; 240*a90cf9f2SGordon Ross break; 241*a90cf9f2SGordon Ross } 242*a90cf9f2SGordon Ross status = smb2_lock_elem(sr, &elem); 243*a90cf9f2SGordon Ross if (status) 244*a90cf9f2SGordon Ross break; 245*a90cf9f2SGordon Ross } 246*a90cf9f2SGordon Ross return (status); 247*a90cf9f2SGordon Ross } 248*a90cf9f2SGordon Ross 249*a90cf9f2SGordon Ross static uint32_t 250*a90cf9f2SGordon Ross smb2_lock_elem(smb_request_t *sr, struct SMB2_LOCK_ELEMENT *elem) 251*a90cf9f2SGordon Ross { 252*a90cf9f2SGordon Ross smb_node_t *node = sr->fid_ofile->f_node; 253*a90cf9f2SGordon Ross uint32_t status; 254*a90cf9f2SGordon Ross uint32_t ltype; 255*a90cf9f2SGordon Ross uint32_t timeout = 0; 256*a90cf9f2SGordon Ross 257*a90cf9f2SGordon Ross switch (elem->Flags) { 258*a90cf9f2SGordon Ross case SMB2_LOCKFLAG_SHARED_LOCK: 259*a90cf9f2SGordon Ross timeout = UINT_MAX; 260*a90cf9f2SGordon Ross /* FALLTHROUGH */ 261*a90cf9f2SGordon Ross case SMB2_LOCKFLAG_SHARED_LOCK | SMB2_LOCKFLAG_FAIL_IMMEDIATELY: 262*a90cf9f2SGordon Ross ltype = SMB_LOCK_TYPE_READONLY; 263*a90cf9f2SGordon Ross status = smb_lock_range(sr, 264*a90cf9f2SGordon Ross elem->Offset, elem->Length, 265*a90cf9f2SGordon Ross timeout, ltype); 266*a90cf9f2SGordon Ross break; 267*a90cf9f2SGordon Ross 268*a90cf9f2SGordon Ross case SMB2_LOCKFLAG_EXCLUSIVE_LOCK: 269*a90cf9f2SGordon Ross timeout = UINT_MAX; 270*a90cf9f2SGordon Ross /* FALLTHROUGH */ 271*a90cf9f2SGordon Ross case SMB2_LOCKFLAG_EXCLUSIVE_LOCK | SMB2_LOCKFLAG_FAIL_IMMEDIATELY: 272*a90cf9f2SGordon Ross ltype = SMB_LOCK_TYPE_READWRITE; 273*a90cf9f2SGordon Ross status = smb_lock_range(sr, 274*a90cf9f2SGordon Ross elem->Offset, elem->Length, 275*a90cf9f2SGordon Ross timeout, ltype); 276*a90cf9f2SGordon Ross break; 277*a90cf9f2SGordon Ross 278*a90cf9f2SGordon Ross case SMB2_LOCKFLAG_UNLOCK: 279*a90cf9f2SGordon Ross status = smb_unlock_range(sr, node, 280*a90cf9f2SGordon Ross elem->Offset, elem->Length); 281*a90cf9f2SGordon Ross break; 282*a90cf9f2SGordon Ross 283*a90cf9f2SGordon Ross /* 284*a90cf9f2SGordon Ross * We've already checked the flags previously, so any 285*a90cf9f2SGordon Ross * surprises here are some kind of internal error. 286*a90cf9f2SGordon Ross */ 287*a90cf9f2SGordon Ross default: 288*a90cf9f2SGordon Ross status = NT_STATUS_INTERNAL_ERROR; 289*a90cf9f2SGordon Ross break; 290*a90cf9f2SGordon Ross } 291*a90cf9f2SGordon Ross 292*a90cf9f2SGordon Ross return (status); 293*a90cf9f2SGordon Ross } 294