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)

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/smbsrv/smb_locking_andx.c
          +++ new/usr/src/uts/common/fs/smbsrv/smb_locking_andx.c
↓ open down ↓ 13 lines elided ↑ open up ↑
  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  /*
  23   23   * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  24      - * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
       24 + * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
  25   25   */
  26   26  
  27   27  /*
  28   28   * SMB: locking_andx
  29   29   *
  30   30   * SMB_COM_LOCKING_ANDX allows both locking and/or unlocking of file range(s).
  31   31   *
  32   32   *  Client Request                     Description
  33   33   *  ================================== =================================
  34   34   *
↓ open down ↓ 170 lines elided ↑ open up ↑
 205  205   * ERRDOS/ERRbadfile
 206  206   * ERRDOS/ERRbadfid
 207  207   * ERRDOS/ERRlock
 208  208   * ERRDOS/ERRinvdevice
 209  209   * ERRSRV/ERRinvid
 210  210   * ERRSRV/ERRbaduid
 211  211   */
 212  212  
 213  213  #include <smbsrv/smb_kproto.h>
 214  214  
      215 +/*
      216 + * This is a somewhat arbitrary sanity limit on the length of the
      217 + * SMB2_LOCK_ELEMENT array.  It usually has length one or two.
      218 + */
      219 +int smb_lock_max_elem = 1024;
      220 +
 215  221  smb_sdrc_t
 216  222  smb_pre_locking_andx(smb_request_t *sr)
 217  223  {
 218      -        DTRACE_SMB_1(op__LockingX__start, smb_request_t *, sr);
      224 +        DTRACE_SMB_START(op__LockingX, smb_request_t *, sr);
 219  225          return (SDRC_SUCCESS);
 220  226  }
 221  227  
 222  228  void
 223  229  smb_post_locking_andx(smb_request_t *sr)
 224  230  {
 225      -        DTRACE_SMB_1(op__LockingX__done, smb_request_t *, sr);
      231 +        DTRACE_SMB_DONE(op__LockingX, smb_request_t *, sr);
 226  232  }
 227  233  
      234 +struct lreq {
      235 +        uint64_t off;
      236 +        uint64_t len;
      237 +        uint32_t pid;
      238 +        uint32_t _x;
      239 +};
      240 +
 228  241  smb_sdrc_t
 229  242  smb_com_locking_andx(smb_request_t *sr)
 230  243  {
 231  244          unsigned short  i;
 232  245          unsigned char   lock_type;      /* See lock_type table above */
 233  246          unsigned char   oplock_level;   /* The new oplock level */
 234  247          uint32_t        timeout;        /* Milliseconds to wait for lock */
 235  248          unsigned short  unlock_num;     /* # unlock range structs */
 236  249          unsigned short  lock_num;       /* # lock range structs */
 237      -        uint32_t        save_pid;       /* Process Id of owner */
 238      -        uint32_t        offset32, length32;
 239      -        uint64_t        offset64;
 240      -        uint64_t        length64;
 241  250          DWORD           result;
 242  251          int             rc;
 243  252          uint32_t        ltype;
      253 +        uint32_t        status;
 244  254          smb_ofile_t     *ofile;
 245  255          uint16_t        tmp_pid;        /* locking uses 16-bit pids */
 246      -        uint8_t         brk;
      256 +        uint32_t        lrv_tot;
      257 +        struct lreq     *lrv_ul;
      258 +        struct lreq     *lrv_lk;
      259 +        struct lreq     *lr;
 247  260  
 248  261          rc = smbsr_decode_vwv(sr, "4.wbblww", &sr->smb_fid, &lock_type,
 249  262              &oplock_level, &timeout, &unlock_num, &lock_num);
 250  263          if (rc != 0)
 251  264                  return (SDRC_ERROR);
 252  265  
 253  266          smbsr_lookup_file(sr);
 254  267          if (sr->fid_ofile == NULL) {
 255  268                  smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
 256  269                  return (SDRC_ERROR);
 257  270          }
 258  271          ofile = sr->fid_ofile;
 259  272          if (ofile->f_node == NULL) {
 260  273                  smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
 261  274                      ERRDOS, ERROR_INVALID_PARAMETER);
 262  275                  return (SDRC_ERROR);
 263  276          }
 264  277  
      278 +        if (unlock_num > smb_lock_max_elem ||
      279 +            lock_num > smb_lock_max_elem) {
      280 +                smbsr_error(sr, NT_STATUS_INSUFFICIENT_RESOURCES,
      281 +                    ERRDOS, ERROR_NO_SYSTEM_RESOURCES);
      282 +                return (SDRC_ERROR);
      283 +        }
      284 +
 265  285          if (lock_type & LOCKING_ANDX_SHARED_LOCK)
 266  286                  ltype = SMB_LOCK_TYPE_READONLY;
 267  287          else
 268  288                  ltype = SMB_LOCK_TYPE_READWRITE;
 269  289  
 270      -        save_pid = sr->smb_pid; /* Save the original pid */
 271      -
 272  290          if (lock_type & LOCKING_ANDX_OPLOCK_RELEASE) {
      291 +                uint32_t NewLevel;
 273  292                  if (oplock_level == 0)
 274      -                        brk = SMB_OPLOCK_BREAK_TO_NONE;
      293 +                        NewLevel = OPLOCK_LEVEL_NONE;
 275  294                  else
 276      -                        brk = SMB_OPLOCK_BREAK_TO_LEVEL_II;
 277      -                smb_oplock_ack(ofile->f_node, ofile, brk);
      295 +                        NewLevel = OPLOCK_LEVEL_TWO;
      296 +                status = smb_oplock_ack_break(sr, ofile, &NewLevel);
      297 +                if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
      298 +                        (void) smb_oplock_wait_break(ofile->f_node, 0);
      299 +                        status = 0;
      300 +                }
 278  301                  if (unlock_num == 0 && lock_num == 0)
 279  302                          return (SDRC_NO_REPLY);
 280  303          }
 281  304  
 282  305          /*
 283  306           * No support for changing locktype (although we could probably
 284  307           * implement this)
 285  308           */
 286  309          if (lock_type & LOCKING_ANDX_CHANGE_LOCK_TYPE) {
 287  310                  smbsr_error(sr, 0, ERRDOS,
 288  311                      ERROR_ATOMIC_LOCKS_NOT_SUPPORTED);
 289  312                  return (SDRC_ERROR);
 290  313          }
 291  314  
 292      -        /*
 293      -         * No support for cancel lock (smbtorture expects this)
 294      -         */
 295      -        if (lock_type & LOCKING_ANDX_CANCEL_LOCK) {
 296      -                smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
 297      -                    ERRDOS, ERROR_INVALID_PARAMETER);
 298      -                return (SDRC_ERROR);
 299      -        }
 300      -
 301  315          if (lock_type & LOCKING_ANDX_LARGE_FILES) {
 302  316                  /*
 303  317                   * negotiated protocol should be NT LM 0.12 or later
 304  318                   */
 305  319                  if (sr->session->dialect < NT_LM_0_12) {
 306  320                          smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
 307  321                              ERRDOS, ERROR_INVALID_PARAMETER);
 308  322                          return (SDRC_ERROR);
 309  323                  }
      324 +        }
 310  325  
 311      -                for (i = 0; i < unlock_num; i++) {
 312      -                        rc = smb_mbc_decodef(&sr->smb_data, "w2.QQ",
 313      -                            &tmp_pid, &offset64, &length64);
 314      -                        if (rc) {
 315      -                                /*
 316      -                                 * This is the error returned by Windows 2000
 317      -                                 * even when STATUS32 has been negotiated.
 318      -                                 */
 319      -                                smbsr_error(sr, 0, ERRSRV, ERRerror);
 320      -                                return (SDRC_ERROR);
 321      -                        }
 322      -                        sr->smb_pid = tmp_pid;  /* NB: 16-bit */
      326 +        /*
      327 +         * Parse the unlock, lock vectors.  Will parse all the
      328 +         * unlock + lock records into one array, and then use
      329 +         * pointers to the unlock and lock parts.
      330 +         */
      331 +        lrv_tot = unlock_num + lock_num;
      332 +        lrv_ul = smb_srm_zalloc(sr, lrv_tot * sizeof (*lrv_ul));
      333 +        lrv_lk = &lrv_ul[unlock_num];
 323  334  
 324      -                        result = smb_unlock_range(sr, sr->fid_ofile->f_node,
 325      -                            offset64, length64);
 326      -                        if (result != NT_STATUS_SUCCESS) {
 327      -                                smbsr_error(sr, NT_STATUS_RANGE_NOT_LOCKED,
 328      -                                    ERRDOS, ERROR_NOT_LOCKED);
 329      -                                return (SDRC_ERROR);
 330      -                        }
      335 +        for (i = 0; i < lrv_tot; i++) {
      336 +                lr = &lrv_ul[i];
      337 +                if (lock_type & LOCKING_ANDX_LARGE_FILES) {
      338 +                        rc = smb_mbc_decodef(&sr->smb_data, "w2.QQ",
      339 +                            &tmp_pid, &lr->off, &lr->len);
      340 +                } else {
      341 +                        uint32_t        offset32, length32;
      342 +                        rc = smb_mbc_decodef(&sr->smb_data, "wll",
      343 +                            &tmp_pid, &offset32, &length32);
      344 +                        lr->off = offset32;
      345 +                        lr->len = length32;
 331  346                  }
      347 +                lr->pid = tmp_pid;      /* 16-bit PID */
      348 +                if (rc) {
      349 +                        /*
      350 +                         * This is the error returned by Windows 2000
      351 +                         * even when STATUS32 has been negotiated.
      352 +                         */
      353 +                        smbsr_error(sr, 0, ERRSRV, ERRerror);
      354 +                        return (SDRC_ERROR);
      355 +                }
      356 +        }
 332  357  
 333      -                for (i = 0; i < lock_num; i++) {
 334      -                        rc = smb_mbc_decodef(&sr->smb_data, "w2.QQ",
 335      -                            &tmp_pid, &offset64, &length64);
 336      -                        if (rc) {
 337      -                                smbsr_error(sr, 0, ERRSRV, ERRerror);
 338      -                                return (SDRC_ERROR);
 339      -                        }
 340      -                        sr->smb_pid = tmp_pid;  /* NB: 16-bit */
      358 +        /*
      359 +         * Cancel waiting locks.  MS-CIFS says one place that
      360 +         * this cancels all waiting locks for this FID+PID,
      361 +         * but smbtorture insists this cancels just one.
      362 +         * Tests with Windows 7 confirms that.
      363 +         */
      364 +        if ((lock_type & LOCKING_ANDX_CANCEL_LOCK) != 0) {
      365 +                lr = lrv_lk;
 341  366  
 342      -                        result = smb_lock_range(sr, offset64, length64, timeout,
 343      -                            ltype);
 344      -                        if (result != NT_STATUS_SUCCESS) {
 345      -                                smb_lock_range_error(sr, result);
 346      -                                return (SDRC_ERROR);
 347      -                        }
      367 +                result = smb_lock_range_cancel(sr, lr->off, lr->len, lr->pid);
      368 +
      369 +                if (result != NT_STATUS_SUCCESS) {
      370 +                        smbsr_error(sr, 0, ERRDOS,
      371 +                            ERROR_CANCEL_VIOLATION);
      372 +                        return (SDRC_ERROR);
 348  373                  }
 349      -        } else {
 350      -                for (i = 0; i < unlock_num; i++) {
 351      -                        rc = smb_mbc_decodef(&sr->smb_data, "wll", &tmp_pid,
 352      -                            &offset32, &length32);
 353      -                        if (rc) {
 354      -                                smbsr_error(sr, 0, ERRSRV, ERRerror);
 355      -                                return (SDRC_ERROR);
 356      -                        }
 357      -                        sr->smb_pid = tmp_pid;  /* NB: 16-bit */
      374 +                goto out;
      375 +        }
 358  376  
 359      -                        result = smb_unlock_range(sr, sr->fid_ofile->f_node,
 360      -                            (uint64_t)offset32, (uint64_t)length32);
 361      -                        if (result != NT_STATUS_SUCCESS) {
 362      -                                smbsr_error(sr, NT_STATUS_RANGE_NOT_LOCKED,
 363      -                                    ERRDOS, ERROR_NOT_LOCKED);
 364      -                                return (SDRC_ERROR);
 365      -                        }
      377 +        /*
      378 +         * Normal unlock and lock list
      379 +         */
      380 +        for (i = 0; i < unlock_num; i++) {
      381 +                lr = &lrv_ul[i];
      382 +
      383 +                result = smb_unlock_range(sr, lr->off, lr->len, lr->pid);
      384 +                if (result != NT_STATUS_SUCCESS) {
      385 +                        smbsr_error(sr, NT_STATUS_RANGE_NOT_LOCKED,
      386 +                            ERRDOS, ERROR_NOT_LOCKED);
      387 +                        return (SDRC_ERROR);
 366  388                  }
      389 +        }
      390 +        for (i = 0; i < lock_num; i++) {
      391 +                lr = &lrv_lk[i];
 367  392  
 368      -                for (i = 0; i < lock_num; i++) {
 369      -                        rc = smb_mbc_decodef(&sr->smb_data, "wll", &tmp_pid,
 370      -                            &offset32, &length32);
 371      -                        if (rc) {
 372      -                                smbsr_error(sr, 0, ERRSRV, ERRerror);
 373      -                                return (SDRC_ERROR);
      393 +                result = smb_lock_range(sr, lr->off, lr->len, lr->pid,
      394 +                    ltype, timeout);
      395 +                if (result != NT_STATUS_SUCCESS) {
      396 +                        /*
      397 +                         * Oh... we have to rollback.
      398 +                         */
      399 +                        while (i > 0) {
      400 +                                --i;
      401 +                                lr = &lrv_lk[i];
      402 +                                (void) smb_unlock_range(sr,
      403 +                                    lr->off, lr->len, lr->pid);
 374  404                          }
 375      -                        sr->smb_pid = tmp_pid;  /* NB: 16-bit */
 376      -
 377      -                        result = smb_lock_range(sr, (uint64_t)offset32,
 378      -                            (uint64_t)length32, timeout, ltype);
 379      -                        if (result != NT_STATUS_SUCCESS) {
 380      -                                smb_lock_range_error(sr, result);
 381      -                                return (SDRC_ERROR);
 382      -                        }
      405 +                        smb_lock_range_error(sr, result);
      406 +                        return (SDRC_ERROR);
 383  407                  }
 384  408          }
 385  409  
 386      -        sr->smb_pid = save_pid;
 387      -        if (smbsr_encode_result(sr, 2, 0, "bb.ww", 2, sr->andx_com, 7, 0))
      410 +out:
      411 +        if (smbsr_encode_result(sr, 2, 0, "bb.ww",
      412 +            2, sr->andx_com, 0x27, 0) != 0)
 388  413                  return (SDRC_ERROR);
 389  414          return (SDRC_SUCCESS);
 390  415  }
 391  416  
 392  417  /*
 393  418   * Compose an SMB1 Oplock Break Notification packet, including
 394  419   * the SMB1 header and everything, in sr->reply.
 395  420   * The caller will send it and free the request.
 396  421   */
 397  422  void
 398      -smb1_oplock_break_notification(smb_request_t *sr, uint8_t brk)
      423 +smb1_oplock_break_notification(smb_request_t *sr, uint32_t NewLevel)
 399  424  {
 400  425          smb_ofile_t *ofile = sr->fid_ofile;
 401  426          uint16_t fid;
 402  427          uint8_t lock_type;
 403  428          uint8_t oplock_level;
 404  429  
 405      -        switch (brk) {
      430 +        /*
      431 +         * Convert internal level to SMB1
      432 +         */
      433 +        switch (NewLevel) {
 406  434          default:
 407  435                  ASSERT(0);
 408  436                  /* FALLTHROUGH */
 409      -        case SMB_OPLOCK_BREAK_TO_NONE:
      437 +        case OPLOCK_LEVEL_NONE:
 410  438                  oplock_level = 0;
 411  439                  break;
 412      -        case SMB_OPLOCK_BREAK_TO_LEVEL_II:
      440 +
      441 +        case OPLOCK_LEVEL_TWO:
 413  442                  oplock_level = 1;
 414  443                  break;
 415  444          }
 416  445  
 417  446          sr->smb_com = SMB_COM_LOCKING_ANDX;
 418  447          sr->smb_tid = ofile->f_tree->t_tid;
 419  448          sr->smb_pid = 0xFFFF;
 420  449          sr->smb_uid = 0;
 421  450          sr->smb_mid = 0xFFFF;
 422  451          fid = ofile->f_fid;
↓ open down ↓ 18 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX