Print this page
NEX-15578 SMB2 durable handle redesign
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@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-15578 SMB2 durable handle redesign
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@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-8841 SMB2 lock request fails
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@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-5555 smb locks don't need l_uid or l_session_kid
Reviewed by: Gordon Ross <gwr@nexenta.com>
NEX-4391 improve smb cancel support
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
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)
SMB-50 User-mode SMB server
 Includes work by these authors:
 Thomas Keiser <thomas.keiser@nexenta.com>
 Albert Lee <trisk@nexenta.com>
SMB-65 SMB server in non-global zones (use zone_kcred())
SUP-599 smb_oplock_acquire thread deadlock

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/smbsrv/smb_lock.c
          +++ new/usr/src/uts/common/fs/smbsrv/smb_lock.c
↓ open down ↓ 12 lines elided ↑ open up ↑
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  23      - * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
       23 + * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
  24   24   */
  25   25  
  26   26  /*
  27   27   * This module provides range lock functionality for CIFS/SMB clients.
  28   28   * Lock range service functions process SMB lock and and unlock
  29   29   * requests for a file by applying lock rules and marks file range
  30   30   * as locked if the lock is successful otherwise return proper
  31   31   * error code.
  32   32   */
  33   33  
  34   34  #include <smbsrv/smb_kproto.h>
  35   35  #include <smbsrv/smb_fsops.h>
  36   36  #include <sys/nbmlock.h>
  37   37  #include <sys/param.h>
  38   38  
  39   39  extern caller_context_t smb_ct;
  40   40  
       41 +#ifdef  DEBUG
       42 +int smb_lock_debug = 0;
       43 +static void smb_lock_dump1(smb_lock_t *);
       44 +static void smb_lock_dumplist(smb_llist_t *);
       45 +static void smb_lock_dumpnode(smb_node_t *);
       46 +#endif
       47 +
  41   48  static void smb_lock_posix_unlock(smb_node_t *, smb_lock_t *, cred_t *);
  42   49  static boolean_t smb_is_range_unlocked(uint64_t, uint64_t, uint32_t,
  43   50      smb_llist_t *, uint64_t *);
  44   51  static int smb_lock_range_overlap(smb_lock_t *, uint64_t, uint64_t);
  45      -static uint32_t smb_lock_range_lckrules(smb_request_t *, smb_ofile_t *,
  46      -    smb_node_t *, smb_lock_t *, smb_lock_t **);
  47      -static clock_t smb_lock_wait(smb_request_t *, smb_lock_t *, smb_lock_t *);
  48      -static uint32_t smb_lock_range_ulckrules(smb_request_t *, smb_node_t *,
  49      -    uint64_t, uint64_t, smb_lock_t **nodelock);
       52 +static uint32_t smb_lock_range_lckrules(smb_ofile_t *, smb_lock_t *,
       53 +    smb_lock_t **);
       54 +static uint32_t smb_lock_wait(smb_request_t *, smb_lock_t *, smb_lock_t *);
       55 +static uint32_t smb_lock_range_ulckrules(smb_ofile_t *,
       56 +    uint64_t, uint64_t, uint32_t, smb_lock_t **);
  50   57  static smb_lock_t *smb_lock_create(smb_request_t *, uint64_t, uint64_t,
  51      -    uint32_t, uint32_t);
       58 +    uint32_t, uint32_t, uint32_t);
  52   59  static void smb_lock_destroy(smb_lock_t *);
  53   60  static void smb_lock_free(smb_lock_t *);
  54   61  
  55   62  /*
  56   63   * Return the number of range locks on the specified ofile.
  57   64   */
  58   65  uint32_t
  59   66  smb_lock_get_lock_count(smb_node_t *node, smb_ofile_t *of)
  60   67  {
  61   68          smb_lock_t      *lock;
↓ open down ↓ 21 lines elided ↑ open up ↑
  83   90   * smb_unlock_range
  84   91   *
  85   92   * locates lock range performed for corresponding to unlock request.
  86   93   *
  87   94   * NT_STATUS_SUCCESS - Lock range performed successfully.
  88   95   * !NT_STATUS_SUCCESS - Error in unlock range operation.
  89   96   */
  90   97  uint32_t
  91   98  smb_unlock_range(
  92   99      smb_request_t       *sr,
  93      -    smb_node_t          *node,
  94  100      uint64_t            start,
  95      -    uint64_t            length)
      101 +    uint64_t            length,
      102 +    uint32_t            pid)
  96  103  {
      104 +        smb_ofile_t     *file = sr->fid_ofile;
      105 +        smb_node_t      *node = file->f_node;
  97  106          smb_lock_t      *lock = NULL;
  98  107          uint32_t        status;
  99  108  
      109 +        if (length > 1 &&
      110 +            (start + length) < start)
      111 +                return (NT_STATUS_INVALID_LOCK_RANGE);
      112 +
      113 +#ifdef  DEBUG
      114 +        if (smb_lock_debug) {
      115 +                cmn_err(CE_CONT, "smb_unlock_range "
      116 +                    "off=0x%llx, len=0x%llx, f=%p, pid=%d\n",
      117 +                    (long long)start, (long long)length,
      118 +                    (void *)sr->fid_ofile, pid);
      119 +        }
      120 +#endif
      121 +
 100  122          /* Apply unlocking rules */
 101  123          smb_llist_enter(&node->n_lock_list, RW_WRITER);
 102      -        status = smb_lock_range_ulckrules(sr, node, start, length, &lock);
      124 +        status = smb_lock_range_ulckrules(file, start, length, pid, &lock);
 103  125          if (status != NT_STATUS_SUCCESS) {
 104  126                  /*
 105  127                   * If lock range is not matching in the list
 106  128                   * return error.
 107  129                   */
 108  130                  ASSERT(lock == NULL);
 109      -                smb_llist_exit(&node->n_lock_list);
 110      -                return (status);
 111  131          }
      132 +        if (lock != NULL) {
      133 +                smb_llist_remove(&node->n_lock_list, lock);
      134 +                smb_lock_posix_unlock(node, lock, sr->user_cr);
      135 +        }
 112  136  
 113      -        smb_llist_remove(&node->n_lock_list, lock);
 114      -        smb_lock_posix_unlock(node, lock, sr->user_cr);
      137 +#ifdef  DEBUG
      138 +        if (smb_lock_debug && lock == NULL) {
      139 +                cmn_err(CE_CONT, "unlock failed, 0x%x\n", status);
      140 +                smb_lock_dumpnode(node);
      141 +        }
      142 +#endif
      143 +
 115  144          smb_llist_exit(&node->n_lock_list);
 116      -        smb_lock_destroy(lock);
 117  145  
      146 +        if (lock != NULL)
      147 +                smb_lock_destroy(lock);
      148 +
 118  149          return (status);
 119  150  }
 120  151  
 121  152  /*
 122  153   * smb_lock_range
 123  154   *
 124  155   * Checks for integrity of file lock operation for the given range of file data.
 125  156   * This is performed by applying lock rules with all the elements of the node
 126  157   * lock list.
 127  158   *
↓ open down ↓ 5 lines elided ↑ open up ↑
 133  164   * without returning.
 134  165   *
 135  166   * NT_STATUS_SUCCESS - Lock range performed successfully.
 136  167   * !NT_STATUS_SUCCESS - Error in lock range operation.
 137  168   */
 138  169  uint32_t
 139  170  smb_lock_range(
 140  171      smb_request_t       *sr,
 141  172      uint64_t            start,
 142  173      uint64_t            length,
 143      -    uint32_t            timeout,
 144      -    uint32_t            locktype)
      174 +    uint32_t            pid,
      175 +    uint32_t            locktype,
      176 +    uint32_t            timeout)
 145  177  {
 146  178          smb_ofile_t     *file = sr->fid_ofile;
 147  179          smb_node_t      *node = file->f_node;
 148  180          smb_lock_t      *lock;
 149      -        smb_lock_t      *clock = NULL;
 150      -        uint32_t        result = NT_STATUS_SUCCESS;
      181 +        smb_lock_t      *conflict = NULL;
      182 +        uint32_t        result;
      183 +        int             rc;
 151  184          boolean_t       lock_has_timeout =
 152  185              (timeout != 0 && timeout != UINT_MAX);
 153  186  
 154      -        lock = smb_lock_create(sr, start, length, locktype, timeout);
      187 +        if (length > 1 &&
      188 +            (start + length) < start)
      189 +                return (NT_STATUS_INVALID_LOCK_RANGE);
 155  190  
      191 +#ifdef  DEBUG
      192 +        if (smb_lock_debug) {
      193 +                cmn_err(CE_CONT, "smb_lock_range "
      194 +                    "off=0x%llx, len=0x%llx, "
      195 +                    "f=%p, pid=%d, typ=%d, tmo=%d\n",
      196 +                    (long long)start, (long long)length,
      197 +                    (void *)sr->fid_ofile, pid, locktype, timeout);
      198 +        }
      199 +#endif
      200 +
      201 +        lock = smb_lock_create(sr, start, length, pid, locktype, timeout);
      202 +
 156  203          smb_llist_enter(&node->n_lock_list, RW_WRITER);
 157  204          for (;;) {
 158      -                clock_t rc;
 159  205  
 160  206                  /* Apply locking rules */
 161      -                result = smb_lock_range_lckrules(sr, file, node, lock, &clock);
 162      -
 163      -                if ((result == NT_STATUS_CANCELLED) ||
 164      -                    (result == NT_STATUS_SUCCESS) ||
 165      -                    (result == NT_STATUS_RANGE_NOT_LOCKED)) {
 166      -                        ASSERT(clock == NULL);
      207 +                result = smb_lock_range_lckrules(file, lock, &conflict);
      208 +                switch (result) {
      209 +                case NT_STATUS_LOCK_NOT_GRANTED: /* conflict! */
      210 +                        /* may need to wait */
 167  211                          break;
 168      -                } else if (timeout == 0) {
 169      -                        break;
      212 +                case NT_STATUS_SUCCESS:
      213 +                case NT_STATUS_FILE_CLOSED:
      214 +                        goto break_loop;
      215 +                default:
      216 +                        cmn_err(CE_CONT, "smb_lock_range1, status 0x%x\n",
      217 +                            result);
      218 +                        goto break_loop;
 170  219                  }
      220 +                if (timeout == 0)
      221 +                        goto break_loop;
 171  222  
 172      -                ASSERT(result == NT_STATUS_LOCK_NOT_GRANTED);
 173      -                ASSERT(clock);
 174  223                  /*
 175  224                   * Call smb_lock_wait holding write lock for
 176  225                   * node lock list.  smb_lock_wait will release
 177      -                 * this lock if it blocks.
      226 +                 * the node list lock if it blocks, so after
      227 +                 * the call, (*conflict) may no longer exist.
 178  228                   */
 179      -                ASSERT(node == clock->l_file->f_node);
 180      -
 181      -                rc = smb_lock_wait(sr, lock, clock);
 182      -                if (rc == 0) {
 183      -                        result = NT_STATUS_CANCELLED;
      229 +                result = smb_lock_wait(sr, lock, conflict);
      230 +                conflict = NULL;
      231 +                switch (result) {
      232 +                case NT_STATUS_SUCCESS:
      233 +                        /* conflict gone, try again */
 184  234                          break;
 185      -                }
 186      -                if (rc == -1)
      235 +                case NT_STATUS_TIMEOUT:
      236 +                        /* try just once more */
 187  237                          timeout = 0;
 188      -
 189      -                clock = NULL;
      238 +                        break;
      239 +                case NT_STATUS_CANCELLED:
      240 +                case NT_STATUS_FILE_CLOSED:
      241 +                        goto break_loop;
      242 +                default:
      243 +                        cmn_err(CE_CONT, "smb_lock_range2, status 0x%x\n",
      244 +                            result);
      245 +                        goto break_loop;
      246 +                }
 190  247          }
 191  248  
      249 +break_loop:
 192  250          lock->l_blocked_by = NULL;
 193  251  
 194  252          if (result != NT_STATUS_SUCCESS) {
      253 +                if (result == NT_STATUS_FILE_CLOSED)
      254 +                        result = NT_STATUS_RANGE_NOT_LOCKED;
      255 +
 195  256                  /*
 196  257                   * Under certain conditions NT_STATUS_FILE_LOCK_CONFLICT
 197  258                   * should be returned instead of NT_STATUS_LOCK_NOT_GRANTED.
 198  259                   * All of this appears to be specific to SMB1
 199  260                   */
 200  261                  if (sr->session->dialect <= NT_LM_0_12 &&
 201  262                      result == NT_STATUS_LOCK_NOT_GRANTED) {
 202  263                          /*
 203  264                           * Locks with timeouts always return
 204  265                           * NT_STATUS_FILE_LOCK_CONFLICT
↓ open down ↓ 29 lines elided ↑ open up ↑
 234  295                  file->f_llf_pos = lock->l_start;
 235  296                  file->f_flags |= SMB_OFLAGS_LLF_POS_VALID;
 236  297                  mutex_exit(&file->f_mutex);
 237  298  
 238  299                  smb_lock_free(lock);
 239  300          } else {
 240  301                  /*
 241  302                   * don't insert into the CIFS lock list unless the
 242  303                   * posix lock worked
 243  304                   */
 244      -                if (smb_fsop_frlock(node, lock, B_FALSE, sr->user_cr))
      305 +                rc = smb_fsop_frlock(node, lock, B_FALSE, sr->user_cr);
      306 +                if (rc != 0) {
      307 +#ifdef  DEBUG
      308 +                        if (smb_lock_debug)
      309 +                                cmn_err(CE_CONT, "fop_frlock, err=%d\n", rc);
      310 +#endif
 245  311                          result = NT_STATUS_FILE_LOCK_CONFLICT;
 246      -                else
 247      -                        smb_llist_insert_tail(&node->n_lock_list, lock);
      312 +                } else {
      313 +                        /*
      314 +                         * We want unlock to find exclusive locks before
      315 +                         * shared locks, so insert those at the head.
      316 +                         */
      317 +                        if (lock->l_type == SMB_LOCK_TYPE_READWRITE)
      318 +                                smb_llist_insert_head(&node->n_lock_list, lock);
      319 +                        else
      320 +                                smb_llist_insert_tail(&node->n_lock_list, lock);
      321 +                }
 248  322          }
      323 +
      324 +#ifdef  DEBUG
      325 +        if (smb_lock_debug && result != 0) {
      326 +                cmn_err(CE_CONT, "lock failed, 0x%x\n", result);
      327 +                smb_lock_dumpnode(node);
      328 +        }
      329 +#endif
      330 +
 249  331          smb_llist_exit(&node->n_lock_list);
 250  332  
 251      -        if (result == NT_STATUS_SUCCESS)
 252      -                smb_oplock_break_levelII(node);
      333 +        if (result == NT_STATUS_SUCCESS) {
      334 +                /* This revokes read cache delegations. */
      335 +                (void) smb_oplock_break_WRITE(node, file);
      336 +        }
 253  337  
 254  338          return (result);
 255  339  }
 256  340  
 257      -
 258  341  /*
 259  342   * smb_lock_range_access
 260  343   *
 261  344   * scans node lock list
 262  345   * to check if there is any overlapping lock. Overlapping
 263  346   * lock is allowed only under same session and client pid.
 264  347   *
 265  348   * Return values
 266  349   *      NT_STATUS_SUCCESS               lock access granted.
 267  350   *      NT_STATUS_FILE_LOCK_CONFLICT    access denied due to lock conflict.
 268  351   */
 269  352  int
 270  353  smb_lock_range_access(
 271  354      smb_request_t       *sr,
 272  355      smb_node_t          *node,
 273  356      uint64_t            start,
 274      -    uint64_t            length,  /* zero means to EoF */
      357 +    uint64_t            length,
 275  358      boolean_t           will_write)
 276  359  {
 277  360          smb_lock_t      *lock;
 278  361          smb_llist_t     *llist;
      362 +        uint32_t        lk_pid = 0;
 279  363          int             status = NT_STATUS_SUCCESS;
 280  364  
      365 +        if (length == 0)
      366 +                return (status);
      367 +
      368 +        /*
      369 +         * What PID to use for lock conflict checks?
      370 +         * SMB2 locking ignores PIDs (have lk_pid=0)
      371 +         * SMB1 uses low 16 bits of sr->smb_pid
      372 +         */
      373 +        if (sr->session->dialect < SMB_VERS_2_BASE)
      374 +                lk_pid = sr->smb_pid & 0xFFFF;
      375 +
 281  376          llist = &node->n_lock_list;
 282  377          smb_llist_enter(llist, RW_READER);
 283  378          /* Search for any applicable lock */
 284  379          for (lock = smb_llist_head(llist);
 285  380              lock != NULL;
 286  381              lock = smb_llist_next(llist, lock)) {
 287  382  
 288  383                  if (!smb_lock_range_overlap(lock, start, length))
 289  384                          /* Lock does not overlap */
 290  385                          continue;
 291  386  
 292  387                  if (lock->l_type == SMB_LOCK_TYPE_READONLY && !will_write)
 293  388                          continue;
 294  389  
 295  390                  if (lock->l_type == SMB_LOCK_TYPE_READWRITE &&
 296      -                    lock->l_session_kid == sr->session->s_kid &&
 297      -                    lock->l_pid == sr->smb_pid)
      391 +                    lock->l_file == sr->fid_ofile &&
      392 +                    lock->l_pid == lk_pid)
 298  393                          continue;
 299  394  
      395 +#ifdef  DEBUG
      396 +                if (smb_lock_debug) {
      397 +                        cmn_err(CE_CONT, "smb_lock_range_access conflict: "
      398 +                            "off=0x%llx, len=0x%llx, "
      399 +                            "f=%p, pid=%d, typ=%d\n",
      400 +                            (long long)lock->l_start,
      401 +                            (long long)lock->l_length,
      402 +                            (void *)lock->l_file,
      403 +                            lock->l_pid, lock->l_type);
      404 +                }
      405 +#endif
 300  406                  status = NT_STATUS_FILE_LOCK_CONFLICT;
 301  407                  break;
 302  408          }
 303  409          smb_llist_exit(llist);
 304  410          return (status);
 305  411  }
 306  412  
      413 +/*
      414 + * The ofile is being closed.  Wake any waiting locks and
      415 + * clear any granted locks.
      416 + */
 307  417  void
 308  418  smb_node_destroy_lock_by_ofile(smb_node_t *node, smb_ofile_t *file)
 309  419  {
      420 +        cred_t          *kcr = zone_kcred();
 310  421          smb_lock_t      *lock;
 311  422          smb_lock_t      *nxtl;
 312  423          list_t          destroy_list;
 313  424  
 314  425          SMB_NODE_VALID(node);
 315  426          ASSERT(node->n_refcnt);
 316  427  
 317  428          /*
      429 +         * Cancel any waiting locks for this ofile
      430 +         */
      431 +        smb_llist_enter(&node->n_wlock_list, RW_READER);
      432 +        for (lock = smb_llist_head(&node->n_wlock_list);
      433 +            lock != NULL;
      434 +            lock = smb_llist_next(&node->n_wlock_list, lock)) {
      435 +
      436 +                if (lock->l_file == file) {
      437 +                        mutex_enter(&lock->l_mutex);
      438 +                        lock->l_blocked_by = NULL;
      439 +                        lock->l_flags |= SMB_LOCK_FLAG_CLOSED;
      440 +                        cv_broadcast(&lock->l_cv);
      441 +                        mutex_exit(&lock->l_mutex);
      442 +                }
      443 +        }
      444 +        smb_llist_exit(&node->n_wlock_list);
      445 +
      446 +        /*
 318  447           * Move locks matching the specified file from the node->n_lock_list
 319  448           * to a temporary list (holding the lock the entire time) then
 320  449           * destroy all the matching locks.  We can't call smb_lock_destroy
 321  450           * while we are holding the lock for node->n_lock_list because we will
 322  451           * deadlock and we can't drop the lock because the list contents might
 323  452           * change (for example nxtl might get removed on another thread).
 324  453           */
 325  454          list_create(&destroy_list, sizeof (smb_lock_t),
 326  455              offsetof(smb_lock_t, l_lnd));
 327  456  
 328  457          smb_llist_enter(&node->n_lock_list, RW_WRITER);
 329  458          lock = smb_llist_head(&node->n_lock_list);
 330  459          while (lock) {
 331  460                  nxtl = smb_llist_next(&node->n_lock_list, lock);
 332  461                  if (lock->l_file == file) {
 333  462                          smb_llist_remove(&node->n_lock_list, lock);
 334      -                        smb_lock_posix_unlock(node, lock, file->f_user->u_cred);
      463 +                        smb_lock_posix_unlock(node, lock, kcr);
 335  464                          list_insert_tail(&destroy_list, lock);
 336  465                  }
 337  466                  lock = nxtl;
 338  467          }
 339  468          smb_llist_exit(&node->n_lock_list);
 340  469  
 341  470          lock = list_head(&destroy_list);
 342  471          while (lock) {
 343  472                  nxtl = list_next(&destroy_list, lock);
 344  473                  list_remove(&destroy_list, lock);
 345  474                  smb_lock_destroy(lock);
 346  475                  lock = nxtl;
 347  476          }
 348  477  
 349  478          list_destroy(&destroy_list);
 350  479  }
 351  480  
      481 +/*
      482 + * Cause a waiting lock to stop waiting and return an error.
      483 + * returns same status codes as unlock:
      484 + * NT_STATUS_SUCCESS, NT_STATUS_RANGE_NOT_LOCKED
      485 + */
      486 +uint32_t
      487 +smb_lock_range_cancel(smb_request_t *sr,
      488 +    uint64_t start, uint64_t length, uint32_t pid)
      489 +{
      490 +        smb_node_t *node;
      491 +        smb_lock_t *lock;
      492 +        uint32_t status = NT_STATUS_RANGE_NOT_LOCKED;
      493 +        int cnt = 0;
      494 +
      495 +        node = sr->fid_ofile->f_node;
      496 +
      497 +        smb_llist_enter(&node->n_wlock_list, RW_READER);
      498 +
      499 +#ifdef  DEBUG
      500 +        if (smb_lock_debug) {
      501 +                cmn_err(CE_CONT, "smb_lock_range_cancel:\n"
      502 +                    "\tstart=0x%llx, len=0x%llx, of=%p, pid=%d\n",
      503 +                    (long long)start, (long long)length,
      504 +                    (void *)sr->fid_ofile, pid);
      505 +        }
      506 +#endif
      507 +
      508 +        for (lock = smb_llist_head(&node->n_wlock_list);
      509 +            lock != NULL;
      510 +            lock = smb_llist_next(&node->n_wlock_list, lock)) {
      511 +
      512 +                if ((start == lock->l_start) &&
      513 +                    (length == lock->l_length) &&
      514 +                    lock->l_file == sr->fid_ofile &&
      515 +                    lock->l_pid == pid) {
      516 +
      517 +                        mutex_enter(&lock->l_mutex);
      518 +                        lock->l_blocked_by = NULL;
      519 +                        lock->l_flags |= SMB_LOCK_FLAG_CANCELLED;
      520 +                        cv_broadcast(&lock->l_cv);
      521 +                        mutex_exit(&lock->l_mutex);
      522 +                        status = NT_STATUS_SUCCESS;
      523 +                        cnt++;
      524 +                }
      525 +        }
      526 +
      527 +#ifdef  DEBUG
      528 +        if (smb_lock_debug && cnt != 1) {
      529 +                cmn_err(CE_CONT, "cancel found %d\n", cnt);
      530 +                smb_lock_dumpnode(node);
      531 +        }
      532 +#endif
      533 +
      534 +        smb_llist_exit(&node->n_wlock_list);
      535 +
      536 +        return (status);
      537 +}
      538 +
 352  539  void
 353  540  smb_lock_range_error(smb_request_t *sr, uint32_t status32)
 354  541  {
 355  542          uint16_t errcode;
 356  543  
 357      -        if (status32 == NT_STATUS_CANCELLED)
 358      -                errcode = ERROR_OPERATION_ABORTED;
 359      -        else
      544 +        if (status32 == NT_STATUS_CANCELLED) {
      545 +                status32 = NT_STATUS_FILE_LOCK_CONFLICT;
      546 +                errcode = ERROR_LOCK_VIOLATION;
      547 +        } else {
 360  548                  errcode = ERRlock;
      549 +        }
 361  550  
 362  551          smbsr_error(sr, status32, ERRDOS, errcode);
 363  552  }
 364  553  
 365  554  /*
 366  555   * An SMB variant of nbl_conflict().
 367  556   *
 368  557   * SMB prevents remove or rename when conflicting locks exist
 369  558   * (unlike NFS, which is why we can't just use nbl_conflict).
 370  559   *
↓ open down ↓ 136 lines elided ↑ open up ↑
 507  696  
 508  697  /*
 509  698   * smb_lock_range_lckrules
 510  699   *
 511  700   * Lock range rules:
 512  701   *      1. Overlapping read locks are allowed if the
 513  702   *         current locks in the region are only read locks
 514  703   *         irrespective of pid of smb client issuing lock request.
 515  704   *
 516  705   *      2. Read lock in the overlapped region of write lock
 517      - *         are allowed if the pervious lock is performed by the
      706 + *         are allowed if the previous lock is performed by the
 518  707   *         same pid and connection.
 519  708   *
 520  709   * return status:
 521      - *      NT_STATUS_SUCCESS - Input lock range adapts to lock rules.
      710 + *      NT_STATUS_SUCCESS - Input lock range conforms to lock rules.
 522  711   *      NT_STATUS_LOCK_NOT_GRANTED - Input lock conflicts lock rules.
 523      - *      NT_STATUS_CANCELLED - Error in processing lock rules
      712 + *      NT_STATUS_FILE_CLOSED
 524  713   */
 525  714  static uint32_t
 526  715  smb_lock_range_lckrules(
 527      -    smb_request_t       *sr,
 528  716      smb_ofile_t         *file,
 529      -    smb_node_t          *node,
 530      -    smb_lock_t          *dlock,
 531      -    smb_lock_t          **clockp)
      717 +    smb_lock_t          *dlock,         /* desired lock */
      718 +    smb_lock_t          **conflictp)
 532  719  {
      720 +        smb_node_t      *node = file->f_node;
 533  721          smb_lock_t      *lock;
 534  722          uint32_t        status = NT_STATUS_SUCCESS;
 535  723  
 536  724          /* Check if file is closed */
 537  725          if (!smb_ofile_is_open(file)) {
 538      -                return (NT_STATUS_RANGE_NOT_LOCKED);
      726 +                return (NT_STATUS_FILE_CLOSED);
 539  727          }
 540  728  
 541  729          /* Caller must hold lock for node->n_lock_list */
 542  730          for (lock = smb_llist_head(&node->n_lock_list);
 543  731              lock != NULL;
 544  732              lock = smb_llist_next(&node->n_lock_list, lock)) {
 545  733  
 546  734                  if (!smb_lock_range_overlap(lock, dlock->l_start,
 547  735                      dlock->l_length))
 548  736                          continue;
↓ open down ↓ 7 lines elided ↑ open up ↑
 556  744                      (dlock->l_type == SMB_LOCK_TYPE_READONLY)) {
 557  745                          continue;
 558  746                  }
 559  747  
 560  748                  /*
 561  749                   * When the read lock overlaps write lock, check if
 562  750                   * allowed.
 563  751                   */
 564  752                  if ((dlock->l_type == SMB_LOCK_TYPE_READONLY) &&
 565  753                      !(lock->l_type == SMB_LOCK_TYPE_READONLY)) {
 566      -                        if (lock->l_file == sr->fid_ofile &&
 567      -                            lock->l_session_kid == sr->session->s_kid &&
 568      -                            lock->l_pid == sr->smb_pid &&
 569      -                            lock->l_uid == sr->smb_uid) {
      754 +                        if (lock->l_file == dlock->l_file &&
      755 +                            lock->l_pid == dlock->l_pid) {
 570  756                                  continue;
 571  757                          }
 572  758                  }
 573  759  
 574  760                  /* Conflict in overlapping lock element */
 575      -                *clockp = lock;
      761 +                *conflictp = lock;
 576  762                  status = NT_STATUS_LOCK_NOT_GRANTED;
 577  763                  break;
 578  764          }
 579  765  
 580  766          return (status);
 581  767  }
 582  768  
 583  769  /*
      770 + * Cancel method for smb_lock_wait()
      771 + *
      772 + * This request is waiting on a lock.  Wakeup everything
      773 + * waiting on the lock so that the relevant thread regains
      774 + * control and notices that is has been cancelled.  The
      775 + * other lock request threads waiting on this lock will go
      776 + * back to sleep when they discover they are still blocked.
      777 + */
      778 +static void
      779 +smb_lock_cancel_sr(smb_request_t *sr)
      780 +{
      781 +        smb_lock_t *lock = sr->cancel_arg2;
      782 +
      783 +        ASSERT(lock->l_magic == SMB_LOCK_MAGIC);
      784 +        mutex_enter(&lock->l_mutex);
      785 +        lock->l_blocked_by = NULL;
      786 +        lock->l_flags |= SMB_LOCK_FLAG_CANCELLED;
      787 +        cv_broadcast(&lock->l_cv);
      788 +        mutex_exit(&lock->l_mutex);
      789 +}
      790 +
      791 +/*
 584  792   * smb_lock_wait
 585  793   *
 586  794   * Wait operation for smb overlapping lock to be released.  Caller must hold
 587  795   * write lock for node->n_lock_list so that the set of active locks can't
 588  796   * change unexpectedly.  The lock for node->n_lock_list  will be released
 589  797   * within this function during the sleep after the lock dependency has
 590  798   * been recorded.
 591  799   *
 592      - * return value
 593      - *
 594      - *      0       The request was canceled.
 595      - *      -1      The timeout was reached.
 596      - *      >0      Condition met.
      800 + * Returns NT_STATUS_SUCCESS when the lock can be granted,
      801 + * otherwise NT_STATUS_CANCELLED, etc.
 597  802   */
 598      -static clock_t
 599      -smb_lock_wait(smb_request_t *sr, smb_lock_t *b_lock, smb_lock_t *c_lock)
      803 +static uint32_t
      804 +smb_lock_wait(smb_request_t *sr, smb_lock_t *lock, smb_lock_t *conflict)
 600  805  {
 601      -        clock_t         rc = 0;
      806 +        smb_node_t      *node;
      807 +        clock_t         rc;
      808 +        uint32_t        status = NT_STATUS_SUCCESS;
 602  809  
 603      -        ASSERT(sr->sr_awaiting == NULL);
      810 +        node = lock->l_file->f_node;
      811 +        ASSERT(node == conflict->l_file->f_node);
 604  812  
 605      -        mutex_enter(&sr->sr_mutex);
      813 +        /*
      814 +         * Let the blocked lock (lock) l_blocked_by point to the
      815 +         * conflicting lock (conflict), and increment a count of
      816 +         * conflicts with the latter.  When the conflicting lock
      817 +         * is destroyed, we'll search the list of waiting locks
      818 +         * (on the node) and wake any with l_blocked_by ==
      819 +         * the formerly conflicting lock.
      820 +         */
      821 +        mutex_enter(&lock->l_mutex);
      822 +        lock->l_blocked_by = conflict;
      823 +        mutex_exit(&lock->l_mutex);
 606  824  
 607      -        switch (sr->sr_state) {
 608      -        case SMB_REQ_STATE_ACTIVE:
 609      -                /*
 610      -                 * Wait up till the timeout time keeping track of actual
 611      -                 * time waited for possible retry failure.
 612      -                 */
 613      -                sr->sr_state = SMB_REQ_STATE_WAITING_LOCK;
 614      -                sr->sr_awaiting = c_lock;
 615      -                mutex_exit(&sr->sr_mutex);
      825 +        mutex_enter(&conflict->l_mutex);
      826 +        conflict->l_conflicts++;
      827 +        mutex_exit(&conflict->l_mutex);
 616  828  
 617      -                mutex_enter(&c_lock->l_mutex);
 618      -                /*
 619      -                 * The conflict list (l_conflict_list) for a lock contains
 620      -                 * all the locks that are blocked by and in conflict with
 621      -                 * that lock.  Add the new lock to the conflict list for the
 622      -                 * active lock.
 623      -                 *
 624      -                 * l_conflict_list is currently a fancy way of representing
 625      -                 * the references/dependencies on a lock.  It could be
 626      -                 * replaced with a reference count but this approach
 627      -                 * has the advantage that MDB can display the lock
 628      -                 * dependencies at any point in time.  In the future
 629      -                 * we should be able to leverage the list to implement
 630      -                 * an asynchronous locking model.
 631      -                 *
 632      -                 * l_blocked_by is the reverse of the conflict list.  It
 633      -                 * points to the lock that the new lock conflicts with.
 634      -                 * As currently implemented this value is purely for
 635      -                 * debug purposes -- there are windows of time when
 636      -                 * l_blocked_by may be non-NULL even though there is no
 637      -                 * conflict list
 638      -                 */
 639      -                b_lock->l_blocked_by = c_lock;
 640      -                smb_slist_insert_tail(&c_lock->l_conflict_list, b_lock);
 641      -                smb_llist_exit(&c_lock->l_file->f_node->n_lock_list);
      829 +        /*
      830 +         * Put the blocked lock on the waiting list.
      831 +         */
      832 +        smb_llist_enter(&node->n_wlock_list, RW_WRITER);
      833 +        smb_llist_insert_tail(&node->n_wlock_list, lock);
      834 +        smb_llist_exit(&node->n_wlock_list);
 642  835  
 643      -                if (SMB_LOCK_INDEFINITE_WAIT(b_lock)) {
 644      -                        cv_wait(&c_lock->l_cv, &c_lock->l_mutex);
 645      -                } else {
 646      -                        rc = cv_timedwait(&c_lock->l_cv,
 647      -                            &c_lock->l_mutex, b_lock->l_end_time);
 648      -                }
      836 +#ifdef  DEBUG
      837 +        if (smb_lock_debug) {
      838 +                cmn_err(CE_CONT, "smb_lock_wait: lock=%p conflict=%p\n",
      839 +                    (void *)lock, (void *)conflict);
      840 +                smb_lock_dumpnode(node);
      841 +        }
      842 +#endif
 649  843  
 650      -                mutex_exit(&c_lock->l_mutex);
      844 +        /*
      845 +         * We come in with n_lock_list already held, and keep
      846 +         * that hold until we're done with conflict (are now).
      847 +         * Drop that now, and retake later.  Note that the lock
      848 +         * (*conflict) may go away once we exit this list.
      849 +         */
      850 +        smb_llist_exit(&node->n_lock_list);
      851 +        conflict = NULL;
 651  852  
 652      -                smb_llist_enter(&c_lock->l_file->f_node->n_lock_list,
 653      -                    RW_WRITER);
 654      -                smb_slist_remove(&c_lock->l_conflict_list, b_lock);
      853 +        /*
      854 +         * Before we actually start waiting, setup the hooks
      855 +         * smb_request_cancel uses to unblock this wait.
      856 +         */
      857 +        mutex_enter(&sr->sr_mutex);
      858 +        if (sr->sr_state == SMB_REQ_STATE_ACTIVE) {
      859 +                sr->sr_state = SMB_REQ_STATE_WAITING_LOCK;
      860 +                sr->cancel_method = smb_lock_cancel_sr;
      861 +                sr->cancel_arg2 = lock;
      862 +        } else {
      863 +                status = NT_STATUS_CANCELLED;
      864 +        }
      865 +        mutex_exit(&sr->sr_mutex);
 655  866  
 656      -                mutex_enter(&sr->sr_mutex);
 657      -                sr->sr_awaiting = NULL;
 658      -                if (sr->sr_state == SMB_REQ_STATE_CANCELED) {
 659      -                        rc = 0;
      867 +        /*
      868 +         * Now we're ready to actually wait for the conflicting
      869 +         * lock to be removed, or for the wait to be ended by
      870 +         * an external cancel, or a timeout.
      871 +         */
      872 +        mutex_enter(&lock->l_mutex);
      873 +        while (status == NT_STATUS_SUCCESS &&
      874 +            lock->l_blocked_by != NULL) {
      875 +                if (lock->l_flags & SMB_LOCK_FLAG_INDEFINITE) {
      876 +                        cv_wait(&lock->l_cv, &lock->l_mutex);
 660  877                  } else {
 661      -                        sr->sr_state = SMB_REQ_STATE_ACTIVE;
      878 +                        rc = cv_timedwait(&lock->l_cv,
      879 +                            &lock->l_mutex, lock->l_end_time);
      880 +                        if (rc < 0)
      881 +                                status = NT_STATUS_TIMEOUT;
 662  882                  }
      883 +        }
      884 +        if (status == NT_STATUS_SUCCESS) {
      885 +                if (lock->l_flags & SMB_LOCK_FLAG_CANCELLED)
      886 +                        status = NT_STATUS_CANCELLED;
      887 +                if (lock->l_flags & SMB_LOCK_FLAG_CLOSED)
      888 +                        status = NT_STATUS_FILE_CLOSED;
      889 +        }
      890 +        mutex_exit(&lock->l_mutex);
      891 +
      892 +        /*
      893 +         * Done waiting.  Cleanup cancel hooks and
      894 +         * finish SR state transitions.
      895 +         */
      896 +        mutex_enter(&sr->sr_mutex);
      897 +        sr->cancel_method = NULL;
      898 +        sr->cancel_arg2 = NULL;
      899 +
      900 +        switch (sr->sr_state) {
      901 +        case SMB_REQ_STATE_WAITING_LOCK:
      902 +                /* Normal wakeup.  Keep status from above. */
      903 +                sr->sr_state = SMB_REQ_STATE_ACTIVE;
 663  904                  break;
 664  905  
      906 +        case SMB_REQ_STATE_CANCEL_PENDING:
      907 +                /* Cancelled via smb_lock_cancel_sr */
      908 +                sr->sr_state = SMB_REQ_STATE_CANCELLED;
      909 +                /* FALLTHROUGH */
      910 +        case SMB_REQ_STATE_CANCELLED:
      911 +                if (status == NT_STATUS_SUCCESS)
      912 +                        status = NT_STATUS_CANCELLED;
      913 +                break;
      914 +
 665  915          default:
 666      -                ASSERT(sr->sr_state == SMB_REQ_STATE_CANCELED);
 667      -                rc = 0;
 668  916                  break;
 669  917          }
 670  918          mutex_exit(&sr->sr_mutex);
 671  919  
 672      -        return (rc);
      920 +        /* Return to the caller with n_lock_list held. */
      921 +        smb_llist_enter(&node->n_lock_list, RW_WRITER);
      922 +
      923 +        smb_llist_enter(&node->n_wlock_list, RW_WRITER);
      924 +        smb_llist_remove(&node->n_wlock_list, lock);
      925 +        smb_llist_exit(&node->n_wlock_list);
      926 +
      927 +        return (status);
 673  928  }
 674  929  
 675  930  /*
 676  931   * smb_lock_range_ulckrules
 677  932   *
 678  933   *      1. Unlock should be performed at exactly matching ends.
 679  934   *         This has been changed because overlapping ends is
 680  935   *         allowed and there is no other precise way of locating
 681  936   *         lock entity in node lock list.
 682  937   *
 683  938   *      2. Unlock is failed if there is no corresponding lock exists.
 684  939   *
 685  940   * Return values
 686  941   *
 687  942   *      NT_STATUS_SUCCESS               Unlock request matches lock record
 688      - *                                      pointed by 'nodelock' lock structure.
      943 + *                                      pointed by 'foundlock' lock structure.
 689  944   *
 690  945   *      NT_STATUS_RANGE_NOT_LOCKED      Unlock request doen't match any
 691  946   *                                      of lock record in node lock request or
 692  947   *                                      error in unlock range processing.
 693  948   */
 694  949  static uint32_t
 695  950  smb_lock_range_ulckrules(
 696      -    smb_request_t       *sr,
 697      -    smb_node_t          *node,
      951 +    smb_ofile_t         *file,
 698  952      uint64_t            start,
 699  953      uint64_t            length,
 700      -    smb_lock_t          **nodelock)
      954 +    uint32_t            pid,
      955 +    smb_lock_t          **foundlock)
 701  956  {
      957 +        smb_node_t      *node = file->f_node;
 702  958          smb_lock_t      *lock;
 703  959          uint32_t        status = NT_STATUS_RANGE_NOT_LOCKED;
 704  960  
 705  961          /* Caller must hold lock for node->n_lock_list */
 706  962          for (lock = smb_llist_head(&node->n_lock_list);
 707  963              lock != NULL;
 708  964              lock = smb_llist_next(&node->n_lock_list, lock)) {
 709  965  
 710  966                  if ((start == lock->l_start) &&
 711  967                      (length == lock->l_length) &&
 712      -                    lock->l_file == sr->fid_ofile &&
 713      -                    lock->l_session_kid == sr->session->s_kid &&
 714      -                    lock->l_pid == sr->smb_pid &&
 715      -                    lock->l_uid == sr->smb_uid) {
 716      -                        *nodelock = lock;
      968 +                    lock->l_file == file &&
      969 +                    lock->l_pid == pid) {
      970 +                        *foundlock = lock;
 717  971                          status = NT_STATUS_SUCCESS;
 718  972                          break;
 719  973                  }
 720  974          }
 721  975  
 722  976          return (status);
 723  977  }
 724  978  
 725  979  static smb_lock_t *
 726  980  smb_lock_create(
 727  981      smb_request_t *sr,
 728  982      uint64_t start,
 729  983      uint64_t length,
      984 +    uint32_t pid,
 730  985      uint32_t locktype,
 731  986      uint32_t timeout)
 732  987  {
 733  988          smb_lock_t *lock;
 734  989  
 735  990          ASSERT(locktype == SMB_LOCK_TYPE_READWRITE ||
 736  991              locktype == SMB_LOCK_TYPE_READONLY);
 737  992  
 738      -        lock = kmem_zalloc(sizeof (smb_lock_t), KM_SLEEP);
      993 +        lock = kmem_cache_alloc(smb_cache_lock, KM_SLEEP);
      994 +        bzero(lock, sizeof (*lock));
 739  995          lock->l_magic = SMB_LOCK_MAGIC;
 740      -        lock->l_sr = sr; /* Invalid after lock is active */
 741      -        lock->l_session_kid = sr->session->s_kid;
 742      -        lock->l_session = sr->session;
 743  996          lock->l_file = sr->fid_ofile;
 744      -        lock->l_uid = sr->smb_uid;
 745      -        lock->l_pid = sr->smb_pid;
      997 +        /* l_file == fid_ofile implies same connection (see ofile lookup) */
      998 +        lock->l_pid = pid;
 746  999          lock->l_type = locktype;
 747 1000          lock->l_start = start;
 748 1001          lock->l_length = length;
 749 1002          /*
 750 1003           * Calculate the absolute end time so that we can use it
 751 1004           * in cv_timedwait.
 752 1005           */
 753 1006          lock->l_end_time = ddi_get_lbolt() + MSEC_TO_TICK(timeout);
 754 1007          if (timeout == UINT_MAX)
 755 1008                  lock->l_flags |= SMB_LOCK_FLAG_INDEFINITE;
 756 1009  
 757 1010          mutex_init(&lock->l_mutex, NULL, MUTEX_DEFAULT, NULL);
 758 1011          cv_init(&lock->l_cv, NULL, CV_DEFAULT, NULL);
 759      -        smb_slist_constructor(&lock->l_conflict_list, sizeof (smb_lock_t),
 760      -            offsetof(smb_lock_t, l_conflict_lnd));
 761 1012  
 762 1013          return (lock);
 763 1014  }
 764 1015  
 765 1016  static void
 766 1017  smb_lock_free(smb_lock_t *lock)
 767 1018  {
 768      -        smb_slist_destructor(&lock->l_conflict_list);
     1019 +
     1020 +        lock->l_magic = 0;
 769 1021          cv_destroy(&lock->l_cv);
 770 1022          mutex_destroy(&lock->l_mutex);
 771 1023  
 772      -        kmem_free(lock, sizeof (smb_lock_t));
     1024 +        kmem_cache_free(smb_cache_lock, lock);
 773 1025  }
 774 1026  
 775 1027  /*
 776 1028   * smb_lock_destroy
 777 1029   *
 778 1030   * Caller must hold node->n_lock_list
 779 1031   */
 780 1032  static void
 781 1033  smb_lock_destroy(smb_lock_t *lock)
 782 1034  {
     1035 +        smb_lock_t *tl;
     1036 +        smb_node_t *node;
     1037 +        uint32_t ccnt;
     1038 +
 783 1039          /*
 784      -         * Caller must hold node->n_lock_list lock.
     1040 +         * Wake any waiting locks that were blocked by this.
     1041 +         * We want them to wake and continue in FIFO order,
     1042 +         * so enter/exit the llist every time...
 785 1043           */
 786 1044          mutex_enter(&lock->l_mutex);
 787      -        cv_broadcast(&lock->l_cv);
     1045 +        ccnt = lock->l_conflicts;
     1046 +        lock->l_conflicts = 0;
 788 1047          mutex_exit(&lock->l_mutex);
 789 1048  
 790      -        /*
 791      -         * The cv_broadcast above should wake up any locks that previous
 792      -         * had conflicts with this lock.  Wait for the locking threads
 793      -         * to remove their references to this lock.
 794      -         */
 795      -        smb_slist_wait_for_empty(&lock->l_conflict_list);
     1049 +        node = lock->l_file->f_node;
     1050 +        while (ccnt) {
 796 1051  
     1052 +                smb_llist_enter(&node->n_wlock_list, RW_READER);
     1053 +
     1054 +                for (tl = smb_llist_head(&node->n_wlock_list);
     1055 +                    tl != NULL;
     1056 +                    tl = smb_llist_next(&node->n_wlock_list, tl)) {
     1057 +                        mutex_enter(&tl->l_mutex);
     1058 +                        if (tl->l_blocked_by == lock) {
     1059 +                                tl->l_blocked_by = NULL;
     1060 +                                cv_broadcast(&tl->l_cv);
     1061 +                                mutex_exit(&tl->l_mutex);
     1062 +                                goto woke_one;
     1063 +                        }
     1064 +                        mutex_exit(&tl->l_mutex);
     1065 +                }
     1066 +                /* No more in the list blocked by this lock. */
     1067 +                ccnt = 0;
     1068 +        woke_one:
     1069 +                smb_llist_exit(&node->n_wlock_list);
     1070 +                if (ccnt) {
     1071 +                        /*
     1072 +                         * Let the thread we woke have a chance to run
     1073 +                         * before we wake competitors for their lock.
     1074 +                         */
     1075 +                        delay(MSEC_TO_TICK(1));
     1076 +                }
     1077 +        }
     1078 +
 797 1079          smb_lock_free(lock);
 798 1080  }
 799 1081  
 800 1082  /*
 801 1083   * smb_is_range_unlocked
 802 1084   *
 803 1085   * Checks if the current unlock byte range request overlaps another lock
 804 1086   * This function is used to determine where POSIX unlocks should be
 805 1087   * applied.
 806 1088   *
↓ open down ↓ 73 lines elided ↑ open up ↑
 880 1162                  lk = smb_llist_next(llist_head, lk);
 881 1163          }
 882 1164  
 883 1165          if (low_water_mark != MAXOFFSET_T) {
 884 1166                  *new_mark = low_water_mark;
 885 1167                  return (B_TRUE);
 886 1168          }
 887 1169          /* the range is completely unlocked */
 888 1170          return (B_TRUE);
 889 1171  }
     1172 +
     1173 +#ifdef  DEBUG
     1174 +static void
     1175 +smb_lock_dump1(smb_lock_t *lock)
     1176 +{
     1177 +        cmn_err(CE_CONT, "\t0x%p: 0x%llx, 0x%llx, %p, %d\n",
     1178 +            (void *)lock,
     1179 +            (long long)lock->l_start,
     1180 +            (long long)lock->l_length,
     1181 +            (void *)lock->l_file,
     1182 +            lock->l_pid);
     1183 +
     1184 +}
     1185 +
     1186 +static void
     1187 +smb_lock_dumplist(smb_llist_t *llist)
     1188 +{
     1189 +        smb_lock_t *lock;
     1190 +
     1191 +        for (lock = smb_llist_head(llist);
     1192 +            lock != NULL;
     1193 +            lock = smb_llist_next(llist, lock)) {
     1194 +                smb_lock_dump1(lock);
     1195 +        }
     1196 +}
     1197 +
     1198 +static void
     1199 +smb_lock_dumpnode(smb_node_t *node)
     1200 +{
     1201 +        cmn_err(CE_CONT, "Granted Locks on %p (%d)\n",
     1202 +            (void *)node, node->n_lock_list.ll_count);
     1203 +        smb_lock_dumplist(&node->n_lock_list);
     1204 +
     1205 +        cmn_err(CE_CONT, "Waiting Locks on %p (%d)\n",
     1206 +            (void *)node, node->n_wlock_list.ll_count);
     1207 +        smb_lock_dumplist(&node->n_wlock_list);
     1208 +}
     1209 +
     1210 +#endif
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX