1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
  14  */
  15 
  16 /*
  17  * Dispatch function for SMB2_OPLOCK_BREAK
  18  */
  19 
  20 #include <smbsrv/smb2_kproto.h>
  21 #include <smbsrv/smb_oplock.h>
  22 
  23 /* StructSize for the two "break" message formats. */
  24 #define SSZ_OPLOCK      24
  25 #define SSZ_LEASE_ACK   36
  26 #define SSZ_LEASE_BRK   44
  27 
  28 #define NODE_FLAGS_DELETING     (NODE_FLAGS_DELETE_ON_CLOSE |\
  29                                 NODE_FLAGS_DELETE_COMMITTED)
  30 
  31 static const char lease_zero[UUID_LEN] = { 0 };
  32 
  33 static kmem_cache_t     *smb_lease_cache = NULL;
  34 
  35 void
  36 smb2_lease_init()
  37 {
  38         if (smb_lease_cache != NULL)
  39                 return;
  40 
  41         smb_lease_cache = kmem_cache_create("smb_lease_cache",
  42             sizeof (smb_lease_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
  43 }
  44 
  45 void
  46 smb2_lease_fini()
  47 {
  48         if (smb_lease_cache != NULL) {
  49                 kmem_cache_destroy(smb_lease_cache);
  50                 smb_lease_cache = NULL;
  51         }
  52 }
  53 
  54 static void
  55 smb2_lease_hold(smb_lease_t *ls)
  56 {
  57         mutex_enter(&ls->ls_mutex);
  58         ls->ls_refcnt++;
  59         mutex_exit(&ls->ls_mutex);
  60 }
  61 
  62 void
  63 smb2_lease_rele(smb_lease_t *ls)
  64 {
  65         smb_llist_t *bucket;
  66 
  67         mutex_enter(&ls->ls_mutex);
  68         ls->ls_refcnt--;
  69         if (ls->ls_refcnt != 0) {
  70                 mutex_exit(&ls->ls_mutex);
  71                 return;
  72         }
  73         mutex_exit(&ls->ls_mutex);
  74 
  75         /*
  76          * Get the list lock, then re-check the refcnt
  77          * and if it's still zero, unlink & destroy.
  78          */
  79         bucket = ls->ls_bucket;
  80         smb_llist_enter(bucket, RW_WRITER);
  81 
  82         mutex_enter(&ls->ls_mutex);
  83         if (ls->ls_refcnt == 0)
  84                 smb_llist_remove(bucket, ls);
  85         mutex_exit(&ls->ls_mutex);
  86 
  87         if (ls->ls_refcnt == 0) {
  88                 mutex_destroy(&ls->ls_mutex);
  89                 kmem_cache_free(smb_lease_cache, ls);
  90         }
  91 
  92         smb_llist_exit(bucket);
  93 }
  94 
  95 /*
  96  * Compute a hash from a uuid
  97  * Based on mod_hash_bystr()
  98  */
  99 static uint_t
 100 smb_hash_uuid(const uint8_t *uuid)
 101 {
 102         char *k = (char *)uuid;
 103         uint_t hash = 0;
 104         uint_t g;
 105         int i;
 106 
 107         ASSERT(k);
 108         for (i = 0; i < UUID_LEN; i++) {
 109                 hash = (hash << 4) + k[i];
 110                 if ((g = (hash & 0xf0000000)) != 0) {
 111                         hash ^= (g >> 24);
 112                         hash ^= g;
 113                 }
 114         }
 115         return (hash);
 116 }
 117 
 118 /*
 119  * Add or update a lease table entry for a new ofile.
 120  * (in the per-session lease table)
 121  * See [MS-SMB2] 3.3.5.9.8
 122  * Handling the SMB2_CREATE_REQUEST_LEASE Create Context
 123  */
 124 uint32_t
 125 smb2_lease_create(smb_request_t *sr, uint8_t *clnt)
 126 {
 127         smb_arg_open_t *op = &sr->arg.open;
 128         uint8_t *key = op->lease_key;
 129         smb_ofile_t *of = sr->fid_ofile;
 130         smb_hash_t *ht = sr->sr_server->sv_lease_ht;
 131         smb_llist_t *bucket;
 132         smb_lease_t *lease;
 133         smb_lease_t *newlease;
 134         size_t hashkey;
 135         uint32_t status = NT_STATUS_INVALID_PARAMETER;
 136 
 137         if (bcmp(key, lease_zero, UUID_LEN) == 0)
 138                 return (status);
 139 
 140         /*
 141          * Find or create, and add a ref for the new ofile.
 142          */
 143         hashkey = smb_hash_uuid(key);
 144         hashkey &= (ht->num_buckets - 1);
 145         bucket = &ht->buckets[hashkey].b_list;
 146 
 147         newlease = kmem_cache_alloc(smb_lease_cache, KM_SLEEP);
 148         bzero(newlease, sizeof (smb_lease_t));
 149         mutex_init(&newlease->ls_mutex, NULL, MUTEX_DEFAULT, NULL);
 150         newlease->ls_bucket = bucket;
 151         newlease->ls_node = of->f_node;
 152         newlease->ls_refcnt = 1;
 153         newlease->ls_epoch = op->lease_epoch;
 154         newlease->ls_version = op->lease_version;
 155         bcopy(key, newlease->ls_key, UUID_LEN);
 156         bcopy(clnt, newlease->ls_clnt, UUID_LEN);
 157 
 158         smb_llist_enter(bucket, RW_WRITER);
 159         for (lease = smb_llist_head(bucket); lease != NULL;
 160             lease = smb_llist_next(bucket, lease)) {
 161                 /*
 162                  * Looking for this lease ID, on a node
 163                  * that's not being deleted.
 164                  */
 165                 if (bcmp(lease->ls_key, key, UUID_LEN) == 0 &&
 166                     bcmp(lease->ls_clnt, clnt, UUID_LEN) == 0 &&
 167                     (lease->ls_node->flags & NODE_FLAGS_DELETING) == 0)
 168                         break;
 169         }
 170         if (lease != NULL) {
 171                 /*
 172                  * Found existing lease.  Make sure it refers to
 173                  * the same node...
 174                  */
 175                 if (lease->ls_node == of->f_node) {
 176                         smb2_lease_hold(lease);
 177                 } else {
 178                         /* Same lease ID, different node! */
 179 #ifdef DEBUG
 180                         cmn_err(CE_NOTE, "new lease on node %p (%s) "
 181                             "conflicts with existing node %p (%s)",
 182                             (void *) of->f_node,
 183                             of->f_node->od_name,
 184                             (void *) lease->ls_node,
 185                             lease->ls_node->od_name);
 186 #endif
 187                         DTRACE_PROBE2(dup_lease, smb_request_t, sr,
 188                             smb_lease_t, lease);
 189                         lease = NULL; /* error */
 190                 }
 191         } else {
 192                 lease = newlease;
 193                 smb_llist_insert_head(bucket, lease);
 194                 newlease = NULL; /* don't free */
 195         }
 196         smb_llist_exit(bucket);
 197 
 198         if (newlease != NULL) {
 199                 mutex_destroy(&newlease->ls_mutex);
 200                 kmem_cache_free(smb_lease_cache, newlease);
 201         }
 202 
 203         if (lease != NULL) {
 204                 of->f_lease = lease;
 205                 status = NT_STATUS_SUCCESS;
 206         }
 207 
 208         return (status);
 209 }
 210 
 211 /*
 212  * Find the lease for a given: client_uuid, lease_key
 213  * Returns the lease with a new ref.
 214  */
 215 smb_lease_t *
 216 smb2_lease_lookup(smb_server_t *sv, uint8_t *clnt_uuid, uint8_t *lease_key)
 217 {
 218         smb_hash_t *ht = sv->sv_lease_ht;
 219         smb_llist_t *bucket;
 220         smb_lease_t *lease;
 221         size_t hashkey;
 222 
 223         hashkey = smb_hash_uuid(lease_key);
 224         hashkey &= (ht->num_buckets - 1);
 225         bucket = &ht->buckets[hashkey].b_list;
 226 
 227         smb_llist_enter(bucket, RW_READER);
 228         lease = smb_llist_head(bucket);
 229         while (lease != NULL) {
 230                 if (bcmp(lease->ls_key, lease_key, UUID_LEN) == 0 &&
 231                     bcmp(lease->ls_clnt, clnt_uuid, UUID_LEN) == 0) {
 232                         smb2_lease_hold(lease);
 233                         break;
 234                 }
 235                 lease = smb_llist_next(bucket, lease);
 236         }
 237         smb_llist_exit(bucket);
 238 
 239         return (lease);
 240 }
 241 
 242 /*
 243  * Find an smb_ofile_t in the current tree that shares the
 244  * specified lease and has some oplock breaking flags set.
 245  * If lease not found, NT_STATUS_OBJECT_NAME_NOT_FOUND.
 246  * If ofile not breaking NT_STATUS_UNSUCCESSFUL.
 247  * On success, ofile (held) in sr->fid_ofile.
 248  */
 249 static uint32_t
 250 find_breaking_ofile(smb_request_t *sr, uint8_t *lease_key)
 251 {
 252         smb_tree_t      *tree = sr->tid_tree;
 253         smb_lease_t     *lease;
 254         smb_llist_t     *of_list;
 255         smb_ofile_t     *o;
 256         uint32_t        status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
 257 
 258         SMB_TREE_VALID(tree);
 259         of_list = &tree->t_ofile_list;
 260 
 261         smb_llist_enter(of_list, RW_READER);
 262         for (o = smb_llist_head(of_list); o != NULL;
 263             o = smb_llist_next(of_list, o)) {
 264 
 265                 ASSERT(o->f_magic == SMB_OFILE_MAGIC);
 266                 ASSERT(o->f_tree == tree);
 267 
 268                 if ((lease = o->f_lease) == NULL)
 269                         continue; // no lease
 270 
 271                 if (bcmp(lease->ls_key, lease_key, UUID_LEN) != 0)
 272                         continue; // wrong lease
 273 
 274                 /*
 275                  * Now we know the lease exists, so if we don't
 276                  * find an ofile with breaking flags, return:
 277                  */
 278                 status = NT_STATUS_UNSUCCESSFUL;
 279 
 280                 if (o->f_oplock.og_breaking == 0)
 281                         continue; // not breaking
 282 
 283                 /* Found breaking ofile. */
 284                 if (smb_ofile_hold(o)) {
 285                         sr->fid_ofile = o;
 286                         status = NT_STATUS_SUCCESS;
 287                         break;
 288                 }
 289         }
 290         smb_llist_exit(of_list);
 291 
 292         return (status);
 293 }
 294 
 295 /*
 296  * This is called by smb2_oplock_break_ack when the struct size
 297  * indicates this is a lease break (SZ_LEASE).  See:
 298  * [MS-SMB2] 3.3.5.22.2 Processing a Lease Acknowledgment
 299  */
 300 smb_sdrc_t
 301 smb2_lease_break_ack(smb_request_t *sr)
 302 {
 303         smb_lease_t *lease;
 304         smb_ofile_t *ofile;
 305         uint8_t LeaseKey[UUID_LEN];
 306         uint32_t LeaseState;
 307         uint32_t LeaseBreakTo;
 308         uint32_t status;
 309         int rc = 0;
 310 
 311         if (sr->session->dialect < SMB_VERS_2_1)
 312                 return (SDRC_ERROR);
 313 
 314         /*
 315          * Decode an SMB2 Lease Acknowldgement
 316          * [MS-SMB2] 2.2.24.2
 317          * Note: Struct size decoded by caller.
 318          */
 319         rc = smb_mbc_decodef(
 320             &sr->smb_data, "6.#cl8.",
 321             /* reserved           6. */
 322             UUID_LEN,           /* # */
 323             LeaseKey,           /* c */
 324             &LeaseState);   /* l */
 325             /* duration           8. */
 326         if (rc != 0)
 327                 return (SDRC_ERROR);
 328 
 329         status = find_breaking_ofile(sr, LeaseKey);
 330 
 331         DTRACE_SMB2_START(op__OplockBreak, smb_request_t *, sr);
 332         if (status != 0)
 333                 goto errout;
 334 
 335         /* Success, so have sr->fid_ofile and lease */
 336         ofile = sr->fid_ofile;
 337         lease = ofile->f_lease;
 338 
 339         /*
 340          * Process the lease break ack.
 341          *
 342          * If the new LeaseState has any bits in excess of
 343          * the lease state we sent in the break, error...
 344          */
 345         LeaseBreakTo = (lease->ls_breaking >> BREAK_SHIFT) &
 346             OPLOCK_LEVEL_CACHE_MASK;
 347         if ((LeaseState & ~LeaseBreakTo) != 0) {
 348                 status = NT_STATUS_REQUEST_NOT_ACCEPTED;
 349                 goto errout;
 350         }
 351 
 352         ofile->f_oplock.og_breaking = 0;
 353         lease->ls_breaking = 0;
 354 
 355         LeaseState |= OPLOCK_LEVEL_GRANULAR;
 356         status = smb_oplock_ack_break(sr, ofile, &LeaseState);
 357         if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
 358                 (void) smb2sr_go_async(sr);
 359                 (void) smb_oplock_wait_break(ofile->f_node, 0);
 360                 status = NT_STATUS_SUCCESS;
 361         }
 362 
 363         ofile->f_oplock.og_state = LeaseState;
 364         lease->ls_state = LeaseState &
 365             OPLOCK_LEVEL_CACHE_MASK;
 366 
 367 errout:
 368         sr->smb2_status = status;
 369         DTRACE_SMB2_DONE(op__OplockBreak, smb_request_t *, sr);
 370         if (status) {
 371                 smb2sr_put_error(sr, status);
 372                 return (SDRC_SUCCESS);
 373         }
 374 
 375         /*
 376          * Encode an SMB2 Lease Ack. response
 377          * [MS-SMB2] 2.2.25.2
 378          */
 379         LeaseState &= OPLOCK_LEVEL_CACHE_MASK;
 380         (void) smb_mbc_encodef(
 381             &sr->reply, "w6.#cl8.",
 382             SSZ_LEASE_ACK,      /* w */
 383             /* reserved           6. */
 384             UUID_LEN,           /* # */
 385             LeaseKey,           /* c */
 386             LeaseState);        /* l */
 387             /* duration           8. */
 388 
 389         return (SDRC_SUCCESS);
 390 
 391 }
 392 
 393 /*
 394  * Compose an SMB2 Lease Break Notification packet, including
 395  * the SMB2 header and everything, in sr->reply.
 396  * The caller will send it and free the request.
 397  *
 398  * [MS-SMB2] 2.2.23.2 Lease Break Notification
 399  */
 400 void
 401 smb2_lease_break_notification(smb_request_t *sr, uint32_t NewLevel,
 402     boolean_t AckReq)
 403 {
 404         smb_ofile_t *ofile = sr->fid_ofile;
 405         smb_oplock_grant_t *og = &ofile->f_oplock;
 406         smb_lease_t *ls = ofile->f_lease;
 407         uint32_t oldcache;
 408         uint32_t newcache;
 409         uint16_t Epoch;
 410         uint16_t Flags;
 411 
 412         /*
 413          * Convert internal level to SMB2
 414          */
 415         oldcache = og->og_state & OPLOCK_LEVEL_CACHE_MASK;
 416         newcache = NewLevel & OPLOCK_LEVEL_CACHE_MASK;
 417         if (ls->ls_version < 2)
 418                 Epoch = 0;
 419         else
 420                 Epoch = ls->ls_epoch;
 421 
 422         /*
 423          * SMB2 Header
 424          */
 425         sr->smb2_cmd_code = SMB2_OPLOCK_BREAK;
 426         sr->smb2_hdr_flags = SMB2_FLAGS_SERVER_TO_REDIR;
 427         sr->smb_tid = 0;
 428         sr->smb_pid = 0;
 429         sr->smb2_ssnid = 0;
 430         sr->smb2_messageid = UINT64_MAX;
 431         (void) smb2_encode_header(sr, B_FALSE);
 432 
 433         /*
 434          * SMB2 Oplock Break, variable part
 435          *
 436          * [MS-SMB2] says the current lease state preceeds the
 437          * new lease state, but that looks like an error...
 438          */
 439         Flags = AckReq ? SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED : 0;
 440         (void) smb_mbc_encodef(
 441             &sr->reply, "wwl#cll4.4.4.",
 442             SSZ_LEASE_BRK,              /* w */
 443             Epoch,                      /* w */
 444             Flags,                      /* l */
 445             SMB_LEASE_KEY_SZ,           /* # */
 446             ls->ls_key,                      /* c */
 447             oldcache,           /* cur.st  l */
 448             newcache);          /* new.st  l */
 449             /* reserved (4.4.4.) */
 450 }
 451 
 452 /*
 453  * Client has an open handle and requests a lease.
 454  * Convert SMB2 lease request info in to internal form,
 455  * call common oplock code, convert result to SMB2.
 456  *
 457  * If necessary, "go async" here.
 458  */
 459 void
 460 smb2_lease_acquire(smb_request_t *sr)
 461 {
 462         smb_arg_open_t *op = &sr->arg.open;
 463         smb_ofile_t *ofile = sr->fid_ofile;
 464         smb_lease_t *lease = ofile->f_lease;
 465         uint32_t status = NT_STATUS_OPLOCK_NOT_GRANTED;
 466         uint32_t have, want; /* lease flags */
 467         boolean_t NewGrant = B_FALSE;
 468 
 469         /* Only disk trees get oplocks. */
 470         ASSERT((sr->tid_tree->t_res_type & STYPE_MASK) == STYPE_DISKTREE);
 471 
 472         /*
 473          * Only plain files (for now).
 474          * Later, test SMB2_CAP_DIRECTORY_LEASING
 475          */
 476         if (!smb_node_is_file(ofile->f_node)) {
 477                 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
 478                 return;
 479         }
 480 
 481         if (!smb_tree_has_feature(sr->tid_tree, SMB_TREE_OPLOCKS)) {
 482                 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
 483                 return;
 484         }
 485 
 486         /*
 487          * SMB2: Convert to internal form.
 488          * Caller should have setup the lease.
 489          */
 490         ASSERT(op->op_oplock_level == SMB2_OPLOCK_LEVEL_LEASE);
 491         ASSERT(lease != NULL);
 492         if (lease == NULL) {
 493                 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
 494                 return;
 495         }
 496         op->op_oplock_state = OPLOCK_LEVEL_GRANULAR |
 497             (op->lease_state & CACHE_RWH);
 498 
 499         /*
 500          * Tree options may force shared oplocks,
 501          * in which case we reduce the request.
 502          */
 503         if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_FORCE_L2_OPLOCK)) {
 504                 op->op_oplock_state &= ~WRITE_CACHING;
 505         }
 506 
 507         /*
 508          * Disallow downgrade
 509          *
 510          * Note that open with a lease is not allowed to turn off
 511          * any cache rights.  If the client tries to "downgrade",
 512          * any bits, just return the existing lease cache bits.
 513          */
 514         have = lease->ls_state & CACHE_RWH;
 515         want = op->op_oplock_state & CACHE_RWH;
 516         if ((have & ~want) != 0) {
 517                 op->op_oplock_state = have |
 518                     OPLOCK_LEVEL_GRANULAR;
 519                 goto done;
 520         }
 521 
 522         /*
 523          * Handle oplock requests in three parts:
 524          *      a: Requests with WRITE_CACHING
 525          *      b: Requests with HANDLE_CACHING
 526          *      c: Requests with READ_CACHING
 527          * reducing the request before b and c.
 528          *
 529          * In each: first check if the lease grants the
 530          * (possibly reduced) request, in which case we
 531          * leave the lease unchanged and return what's
 532          * granted by the lease.  Otherwise, try to get
 533          * the oplock, and if the succeeds, wait for any
 534          * breaks, update the lease, and return.
 535          */
 536 
 537         /*
 538          * Try exclusive (request is RW or RWH)
 539          */
 540         if ((op->op_oplock_state & WRITE_CACHING) != 0) {
 541                 want = op->op_oplock_state & CACHE_RWH;
 542                 if (have == want)
 543                         goto done;
 544 
 545                 status = smb_oplock_request(sr, ofile,
 546                     &op->op_oplock_state);
 547                 if (status == NT_STATUS_SUCCESS ||
 548                     status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
 549                         NewGrant = B_TRUE;
 550                         goto done;
 551                 }
 552 
 553                 /*
 554                  * We did not get the exclusive oplock.
 555                  *
 556                  * There are odd rules about lease upgrade.
 557                  * If the existing lease grants R and the
 558                  * client fails to upgrade it to "RWH"
 559                  * (presumably due to handle conflicts)
 560                  * then just return the existing lease,
 561                  * even though upgrade to RH would work.
 562                  */
 563                 if (have != 0) {
 564                         op->op_oplock_state = have |
 565                             OPLOCK_LEVEL_GRANULAR;
 566                         goto done;
 567                 }
 568 
 569                 /*
 570                  * Keep trying without write.
 571                  * Need to re-init op_oplock_state
 572                  */
 573                 op->op_oplock_state = OPLOCK_LEVEL_GRANULAR |
 574                     (op->lease_state & CACHE_RH);
 575         }
 576 
 577         /*
 578          * Try shared ("RH")
 579          */
 580         if ((op->op_oplock_state & HANDLE_CACHING) != 0) {
 581                 want = op->op_oplock_state & CACHE_RWH;
 582                 if (have == want)
 583                         goto done;
 584 
 585                 status = smb_oplock_request(sr, ofile,
 586                     &op->op_oplock_state);
 587                 if (status == NT_STATUS_SUCCESS ||
 588                     status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
 589                         NewGrant = B_TRUE;
 590                         goto done;
 591                 }
 592 
 593                 /*
 594                  * We did not get "RH", probably because
 595                  * ther were (old style) Level II oplocks.
 596                  * Continue, try for just read.
 597                  */
 598                 op->op_oplock_state = OPLOCK_LEVEL_GRANULAR |
 599                     (op->lease_state & CACHE_R);
 600         }
 601 
 602         /*
 603          * Try shared ("R")
 604          */
 605         if ((op->op_oplock_state & READ_CACHING) != 0) {
 606                 want = op->op_oplock_state & CACHE_RWH;
 607                 if (have == want)
 608                         goto done;
 609 
 610                 status = smb_oplock_request(sr, ofile,
 611                     &op->op_oplock_state);
 612                 if (status == NT_STATUS_SUCCESS ||
 613                     status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
 614                         NewGrant = B_TRUE;
 615                         goto done;
 616                 }
 617 
 618                 /*
 619                  * We did not get "R".
 620                  * Fall into "none".
 621                  */
 622         }
 623 
 624         /*
 625          * None of the above were able to get an oplock.
 626          * The lease has no caching rights, and we didn't
 627          * add any in this request.  Return it as-is.
 628          */
 629         op->op_oplock_state = OPLOCK_LEVEL_GRANULAR;
 630 
 631 done:
 632         if (NewGrant) {
 633                 /*
 634                  * After a new oplock grant, the status return
 635                  * may indicate we need to wait for breaks.
 636                  */
 637                 if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
 638                         (void) smb2sr_go_async(sr);
 639                         (void) smb_oplock_wait_break(ofile->f_node, 0);
 640                         status = NT_STATUS_SUCCESS;
 641                 }
 642                 ASSERT(status == NT_STATUS_SUCCESS);
 643 
 644                 /*
 645                  * Keep track of what we got (in ofile->f_oplock.og_state)
 646                  * so we'll know what we had when sending a break later.
 647                  * Also update the lease with the new oplock state.
 648                  * Also track which ofile on the lease owns the oplock.
 649                  * The og_dialect here is the oplock dialect, not the
 650                  * SMB dialect.  Leasing, so SMB 2.1 (or later).
 651                  */
 652                 ofile->f_oplock.og_dialect = SMB_VERS_2_1;
 653                 ofile->f_oplock.og_state = op->op_oplock_state;
 654                 mutex_enter(&lease->ls_mutex);
 655                 lease->ls_state = op->op_oplock_state & CACHE_RWH;
 656                 lease->ls_oplock_ofile = ofile;
 657                 lease->ls_epoch++;
 658                 mutex_exit(&lease->ls_mutex);
 659         }
 660 
 661         /*
 662          * Convert internal oplock state to SMB2
 663          */
 664         op->op_oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
 665         op->lease_state = lease->ls_state & CACHE_RWH;
 666         op->lease_flags = (lease->ls_breaking != 0) ?
 667             SMB2_LEASE_FLAG_BREAK_IN_PROGRESS : 0;
 668         op->lease_epoch = lease->ls_epoch;
 669         op->lease_version = lease->ls_version;
 670 }
 671 
 672 /*
 673  * This ofile has a lease and is about to close.
 674  * Called by smb_ofile_close when there's a lease.
 675  *
 676  * With leases, just one ofile on a lease owns the oplock.
 677  * If an ofile with a lease is closed and it's the one that
 678  * owns the oplock, try to move the oplock to another ofile
 679  * on the same lease.
 680  */
 681 void
 682 smb2_lease_ofile_close(smb_ofile_t *ofile)
 683 {
 684         smb_node_t *node = ofile->f_node;
 685         smb_lease_t *lease = ofile->f_lease;
 686         smb_ofile_t *o;
 687 
 688         /*
 689          * If this ofile was not the oplock owner for this lease,
 690          * we can leave things as they are.
 691          */
 692         if (lease->ls_oplock_ofile != ofile)
 693                 return;
 694 
 695         /*
 696          * Find another ofile to which we can move the oplock.
 697          * The ofile must be open and allow a new ref.
 698          */
 699         smb_llist_enter(&node->n_ofile_list, RW_READER);
 700         FOREACH_NODE_OFILE(node, o) {
 701                 if (o == ofile)
 702                         continue;
 703                 if (o->f_lease != lease)
 704                         continue;
 705                 /* If we can get a hold, use this ofile. */
 706                 if (smb_ofile_hold(o))
 707                         break;
 708         }
 709         if (o == NULL) {
 710                 /* Normal for last close on a lease. */
 711                 smb_llist_exit(&node->n_ofile_list);
 712                 return;
 713         }
 714         smb_oplock_move(node, ofile, o);
 715         lease->ls_oplock_ofile = o;
 716 
 717         smb_llist_exit(&node->n_ofile_list);
 718         smb_ofile_release(o);
 719 }