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-15069 smtorture smb2.create.blob is failed
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-15069 smtorture smb2.create.blob is failed
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-1643 dtrace provider for smbsrv
Reviewed by: Evan Layton <evan.layton@nexenta.com>
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())
SMB-63 taskq_create_proc ... TQ_DYNAMIC puts tasks in p0
re #11974 CIFS Share - Tree connect fails from Windows 7 Clients
SUP-599 smb_oplock_acquire thread deadlock
re #7815 SMB server delivers old modification time...
re #6854 FindFirstFile,FindFirstFileEx,... are not working correctly on Nexenta CIFS-shares


   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
  25  */
  26 
  27 #include <sys/sunddi.h>
  28 #include <sys/nbmlock.h>
  29 
  30 #include <smbsrv/smb_kproto.h>
  31 #include <smbsrv/smb_fsops.h>
  32 #include <smbsrv/smbinfo.h>
  33 
  34 static int smb_delete_check_path(smb_request_t *);
  35 static int smb_delete_single_file(smb_request_t *, smb_error_t *);
  36 static int smb_delete_multiple_files(smb_request_t *, smb_error_t *);
  37 static int smb_delete_find_fname(smb_request_t *, smb_odir_t *, char *, int);
  38 static int smb_delete_check_dosattr(smb_request_t *, smb_error_t *);
  39 static int smb_delete_remove_file(smb_request_t *, smb_error_t *);
  40 
  41 static void smb_delete_error(smb_error_t *, uint32_t, uint16_t, uint16_t);
  42 
  43 /*
  44  * smb_com_delete


  87  * ERRDOS/ERRbadfile
  88  * ERRDOS/ERRnoaccess
  89  * ERRDOS/ERRbadshare   # returned by NT for files that are already open
  90  * ERRHRD/ERRnowrite
  91  * ERRSRV/ERRaccess
  92  * ERRSRV/ERRinvdevice
  93  * ERRSRV/ERRinvid
  94  * ERRSRV/ERRbaduid
  95  */
  96 smb_sdrc_t
  97 smb_pre_delete(smb_request_t *sr)
  98 {
  99         int rc;
 100         smb_fqi_t *fqi;
 101 
 102         fqi = &sr->arg.dirop.fqi;
 103 
 104         if ((rc = smbsr_decode_vwv(sr, "w", &fqi->fq_sattr)) == 0)
 105                 rc = smbsr_decode_data(sr, "%S", sr, &fqi->fq_path.pn_path);
 106 
 107         DTRACE_SMB_2(op__Delete__start, smb_request_t *, sr, smb_fqi_t *, fqi);
 108 
 109         return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 110 }
 111 
 112 void
 113 smb_post_delete(smb_request_t *sr)
 114 {
 115         DTRACE_SMB_1(op__Delete__done, smb_request_t *, sr);
 116 }
 117 
 118 /*
 119  * smb_com_delete
 120  *
 121  * 1. intialize, pre-process and validate pathname
 122  *
 123  * 2. process the path to get directory node & last_comp,
 124  *    store these in fqi
 125  *    - If smb_pathname_reduce cannot find the specified path,
 126  *      the error (ENOTDIR) is translated to NT_STATUS_OBJECT_PATH_NOT_FOUND
 127  *      if the target is a single file (no wildcards).  If there are
 128  *      wildcards in the last_comp, NT_STATUS_OBJECT_NAME_NOT_FOUND is
 129  *      used instead.
 130  *    - If the directory node is the mount point and the last component
 131  *      is ".." NT_STATUS_OBJECT_PATH_SYNTAX_BAD is returned.
 132  *
 133  * 3. check access permissions
 134  *
 135  * 4. invoke the appropriate deletion routine to find and remove


 453  * after checking for sharing violations.  Attempting to delete a
 454  * locked file will result in sharing violation, which is the same
 455  * thing that will happen if you try to delete a non-locked open file.
 456  *
 457  * Note that windows 2000 rejects lock requests on open files that
 458  * have been opened with metadata open modes.  The error is
 459  * STATUS_ACCESS_DENIED.
 460  *
 461  * NT does not always close a file immediately, which can cause the
 462  * share and access checking to fail (the node refcnt is greater
 463  * than one), and the file doesn't get deleted. Breaking the oplock
 464  * before share and lock checking gives the client a chance to
 465  * close the file.
 466  *
 467  * Returns: 0 - success
 468  *         -1 - error, err populated with error details
 469  */
 470 static int
 471 smb_delete_remove_file(smb_request_t *sr, smb_error_t *err)
 472 {
 473         int rc, count;
 474         uint32_t status;
 475         smb_fqi_t *fqi;
 476         smb_node_t *node;
 477         uint32_t flags = 0;
 478 
 479         fqi = &sr->arg.dirop.fqi;
 480         node = fqi->fq_fnode;
 481 
 482         /*
 483          * Break BATCH oplock before ofile checks. If a client
 484          * has a file open, this will force a flush or close,
 485          * which may affect the outcome of any share checking.
 486          */
 487         (void) smb_oplock_break(sr, node,
 488             SMB_OPLOCK_BREAK_TO_LEVEL_II | SMB_OPLOCK_BREAK_BATCH);







 489 
 490         /*
 491          * Wait (a little) for the oplock break to be
 492          * responded to by clients closing handles.
 493          * Hold node->n_lock as reader to keep new
 494          * ofiles from showing up after we check.
 495          */
 496         smb_node_rdlock(node);
 497         for (count = 0; count <= 12; count++) {
 498                 status = smb_node_delete_check(node);
 499                 if (status != NT_STATUS_SHARING_VIOLATION)
 500                         break;
 501                 smb_node_unlock(node);
 502                 delay(MSEC_TO_TICK(100));
 503                 smb_node_rdlock(node);
 504         }
 505         if (status != NT_STATUS_SUCCESS) {

 506                 smb_delete_error(err, NT_STATUS_SHARING_VIOLATION,
 507                     ERRDOS, ERROR_SHARING_VIOLATION);
 508                 smb_node_unlock(node);
 509                 return (-1);
 510         }
 511 
 512         /*
 513          * Note, the combination of these two:
 514          *      smb_node_rdlock(node);
 515          *      nbl_start_crit(node->vp, RW_READER);
 516          * is equivalent to this call:
 517          *      smb_node_start_crit(node, RW_READER)
 518          *
 519          * Cleanup after this point should use:
 520          *      smb_node_end_crit(node)
 521          */
 522         nbl_start_crit(node->vp, RW_READER);
 523 
 524         /*
 525          * This checks nbl_share_conflict, nbl_lock_conflict
 526          */
 527         status = smb_nbl_conflict(node, 0, UINT64_MAX, NBL_REMOVE);
 528         if (status == NT_STATUS_SHARING_VIOLATION) {
 529                 smb_node_end_crit(node);
 530                 smb_delete_error(err, NT_STATUS_SHARING_VIOLATION,
 531                     ERRDOS, ERROR_SHARING_VIOLATION);
 532                 return (-1);
 533         }
 534         if (status != NT_STATUS_SUCCESS) {
 535                 smb_node_end_crit(node);
 536                 smb_delete_error(err, NT_STATUS_ACCESS_DENIED,
 537                     ERRDOS, ERROR_ACCESS_DENIED);
 538                 return (-1);
 539         }
 540 
 541         if (SMB_TREE_SUPPORTS_CATIA(sr))
 542                 flags |= SMB_CATIA;
 543 
 544         rc = smb_fsop_remove(sr, sr->user_cr, node->n_dnode,
 545             node->od_name, flags);
 546         if (rc != 0) {
 547                 if (rc == ENOENT)
 548                         smb_delete_error(err, NT_STATUS_OBJECT_NAME_NOT_FOUND,
 549                             ERRDOS, ERROR_FILE_NOT_FOUND);
 550                 else
 551                         smbsr_map_errno(rc, err);
 552 
 553                 smb_node_end_crit(node);
 554                 return (-1);
 555         }
 556 
 557         smb_node_end_crit(node);
 558         return (0);
 559 }
 560 
 561 
 562 /*
 563  * smb_delete_check_path
 564  *
 565  * smb_pathname_validate() should already have been used to
 566  * perform initial validation on the pathname. Additional
 567  * request specific validation of the filename is performed
 568  * here.
 569  *
 570  * - pn->pn_fname is NULL should result in NT_STATUS_FILE_IS_A_DIRECTORY
 571  *
 572  * - Any wildcard filename that resolves to '.' should result in
 573  *   NT_STATUS_OBJECT_NAME_INVALID if the search attributes include
 574  *   FILE_ATTRIBUTE_DIRECTORY
 575  *
 576  * Returns:
 577  *   0: path is valid.
 578  *  -1: path is invalid. Sets error information in sr.




   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
  25  */
  26 
  27 #include <sys/sunddi.h>
  28 #include <sys/nbmlock.h>
  29 
  30 #include <smbsrv/smb_kproto.h>
  31 #include <smbsrv/smb_fsops.h>
  32 #include <smbsrv/smbinfo.h>
  33 
  34 static int smb_delete_check_path(smb_request_t *);
  35 static int smb_delete_single_file(smb_request_t *, smb_error_t *);
  36 static int smb_delete_multiple_files(smb_request_t *, smb_error_t *);
  37 static int smb_delete_find_fname(smb_request_t *, smb_odir_t *, char *, int);
  38 static int smb_delete_check_dosattr(smb_request_t *, smb_error_t *);
  39 static int smb_delete_remove_file(smb_request_t *, smb_error_t *);
  40 
  41 static void smb_delete_error(smb_error_t *, uint32_t, uint16_t, uint16_t);
  42 
  43 /*
  44  * smb_com_delete


  87  * ERRDOS/ERRbadfile
  88  * ERRDOS/ERRnoaccess
  89  * ERRDOS/ERRbadshare   # returned by NT for files that are already open
  90  * ERRHRD/ERRnowrite
  91  * ERRSRV/ERRaccess
  92  * ERRSRV/ERRinvdevice
  93  * ERRSRV/ERRinvid
  94  * ERRSRV/ERRbaduid
  95  */
  96 smb_sdrc_t
  97 smb_pre_delete(smb_request_t *sr)
  98 {
  99         int rc;
 100         smb_fqi_t *fqi;
 101 
 102         fqi = &sr->arg.dirop.fqi;
 103 
 104         if ((rc = smbsr_decode_vwv(sr, "w", &fqi->fq_sattr)) == 0)
 105                 rc = smbsr_decode_data(sr, "%S", sr, &fqi->fq_path.pn_path);
 106 
 107         DTRACE_SMB_START(op__Delete, smb_request_t *, sr); /* arg.dirop */
 108 
 109         return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 110 }
 111 
 112 void
 113 smb_post_delete(smb_request_t *sr)
 114 {
 115         DTRACE_SMB_DONE(op__Delete, smb_request_t *, sr);
 116 }
 117 
 118 /*
 119  * smb_com_delete
 120  *
 121  * 1. intialize, pre-process and validate pathname
 122  *
 123  * 2. process the path to get directory node & last_comp,
 124  *    store these in fqi
 125  *    - If smb_pathname_reduce cannot find the specified path,
 126  *      the error (ENOTDIR) is translated to NT_STATUS_OBJECT_PATH_NOT_FOUND
 127  *      if the target is a single file (no wildcards).  If there are
 128  *      wildcards in the last_comp, NT_STATUS_OBJECT_NAME_NOT_FOUND is
 129  *      used instead.
 130  *    - If the directory node is the mount point and the last component
 131  *      is ".." NT_STATUS_OBJECT_PATH_SYNTAX_BAD is returned.
 132  *
 133  * 3. check access permissions
 134  *
 135  * 4. invoke the appropriate deletion routine to find and remove


 453  * after checking for sharing violations.  Attempting to delete a
 454  * locked file will result in sharing violation, which is the same
 455  * thing that will happen if you try to delete a non-locked open file.
 456  *
 457  * Note that windows 2000 rejects lock requests on open files that
 458  * have been opened with metadata open modes.  The error is
 459  * STATUS_ACCESS_DENIED.
 460  *
 461  * NT does not always close a file immediately, which can cause the
 462  * share and access checking to fail (the node refcnt is greater
 463  * than one), and the file doesn't get deleted. Breaking the oplock
 464  * before share and lock checking gives the client a chance to
 465  * close the file.
 466  *
 467  * Returns: 0 - success
 468  *         -1 - error, err populated with error details
 469  */
 470 static int
 471 smb_delete_remove_file(smb_request_t *sr, smb_error_t *err)
 472 {
 473         int rc;
 474         uint32_t status;
 475         smb_fqi_t *fqi;
 476         smb_node_t *node;
 477         uint32_t flags = 0;
 478 
 479         fqi = &sr->arg.dirop.fqi;
 480         node = fqi->fq_fnode;
 481 
 482         /*
 483          * Break BATCH oplock before ofile checks. If a client
 484          * has a file open, this will force a flush or close,
 485          * which may affect the outcome of any share checking.
 486          */
 487         status = smb_oplock_break_DELETE(node, NULL);
 488         if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
 489                 (void) smb_oplock_wait_break(node, 0);
 490                 status = 0;
 491         }
 492         if (status != 0) {
 493                 err->status = status;
 494                 return (-1);
 495         }
 496 






 497         smb_node_rdlock(node);

 498         status = smb_node_delete_check(node);






 499         if (status != NT_STATUS_SUCCESS) {
 500                 smb_node_unlock(node);
 501                 smb_delete_error(err, NT_STATUS_SHARING_VIOLATION,
 502                     ERRDOS, ERROR_SHARING_VIOLATION);

 503                 return (-1);
 504         }
 505 
 506         /*
 507          * Note, the combination of these two:
 508          *      smb_node_rdlock(node);
 509          *      nbl_start_crit(node->vp, RW_READER);
 510          * is equivalent to this call:
 511          *      smb_node_start_crit(node, RW_READER)
 512          *
 513          * Cleanup after this point should use:
 514          *      smb_node_end_crit(node)
 515          */
 516         nbl_start_crit(node->vp, RW_READER);
 517 
 518         /*
 519          * This checks nbl_share_conflict, nbl_lock_conflict
 520          */
 521         status = smb_nbl_conflict(node, 0, UINT64_MAX, NBL_REMOVE);
 522         if (status == NT_STATUS_SHARING_VIOLATION) {
 523                 smb_node_end_crit(node);
 524                 smb_delete_error(err, NT_STATUS_SHARING_VIOLATION,
 525                     ERRDOS, ERROR_SHARING_VIOLATION);
 526                 return (-1);
 527         }
 528         if (status != NT_STATUS_SUCCESS) {
 529                 smb_node_end_crit(node);
 530                 smb_delete_error(err, NT_STATUS_ACCESS_DENIED,
 531                     ERRDOS, ERROR_ACCESS_DENIED);
 532                 return (-1);
 533         }
 534 
 535         if (SMB_TREE_SUPPORTS_CATIA(sr))
 536                 flags |= SMB_CATIA;
 537 
 538         rc = smb_fsop_remove(sr, sr->user_cr, node->n_dnode,
 539             node->od_name, flags);
 540         if (rc != 0) {




 541                 smbsr_map_errno(rc, err);
 542                 rc = -1;


 543         }
 544 
 545         smb_node_end_crit(node);
 546         return (rc);
 547 }
 548 
 549 
 550 /*
 551  * smb_delete_check_path
 552  *
 553  * smb_pathname_validate() should already have been used to
 554  * perform initial validation on the pathname. Additional
 555  * request specific validation of the filename is performed
 556  * here.
 557  *
 558  * - pn->pn_fname is NULL should result in NT_STATUS_FILE_IS_A_DIRECTORY
 559  *
 560  * - Any wildcard filename that resolves to '.' should result in
 561  *   NT_STATUS_OBJECT_NAME_INVALID if the search attributes include
 562  *   FILE_ATTRIBUTE_DIRECTORY
 563  *
 564  * Returns:
 565  *   0: path is valid.
 566  *  -1: path is invalid. Sets error information in sr.