Print this page
NEX-6402 SMB2 change notify response wrong when STATUS_NOTIFY_ENUM_DIR
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
NEX-6096 Enable compile warnings re. parentheses in smbsrv
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Jean McCormack <jean.mccormack@nexenta.com>
NEX-3906 Prefer that SMB change notify not tie up a worker thread
NEX-5278 SMB notify should buffer per file handle
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
NEX-4391 improve smb cancel support
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
NEX-2602 MacOS X Yosemite fails to authenticate
NEX-2107 SMB2 Notify Change fails to return for directory time change
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)


   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 /*
  28  * File Change Notification (FCN)
  29  * Common parts shared by SMB1 & SMB2
  30  */
  31 
  32 /*
  33  * This command notifies the client when the specified directory
  34  * has changed, and optionally returns the names of files and
  35  * directories that changed, and how they changed.  The caller
  36  * specifies a "Completion Filter" to select which kinds of
  37  * changes they want to know about.
  38  *
  39  * When a change that's in the CompletionFilter is made to the directory,
  40  * the command completes.  The names of the files that have changed since
  41  * the last time the command was issued are returned to the client.
  42  * If too many files have changed since the last time the command was
  43  * issued, then zero bytes are returned and an alternate status code
  44  * is returned in the Status field of the response.


  68  * entry in the list must be longword aligned, so NextEntryOffset must be a
  69  * multiple of four.
  70  *
  71  * typedef struct {
  72  *     ULONG NextEntryOffset;
  73  *     ULONG Action;
  74  *     ULONG FileNameLength;
  75  *     WCHAR FileName[1];
  76  * } FILE_NOTIFY_INFORMATION;
  77  *
  78  * Where Action describes what happened to the file named FileName:
  79  *
  80  * FILE_ACTION_ADDED            0x00000001
  81  * FILE_ACTION_REMOVED          0x00000002
  82  * FILE_ACTION_MODIFIED         0x00000003
  83  * FILE_ACTION_RENAMED_OLD_NAME 0x00000004
  84  * FILE_ACTION_RENAMED_NEW_NAME 0x00000005
  85  * FILE_ACTION_ADDED_STREAM     0x00000006
  86  * FILE_ACTION_REMOVED_STREAM   0x00000007
  87  * FILE_ACTION_MODIFIED_STREAM  0x00000008

































































  88  */
  89 
  90 #include <smbsrv/smb_kproto.h>
  91 #include <sys/sdt.h>
  92 
  93 static void smb_notify_sr(smb_request_t *, uint_t, const char *);
  94 static uint32_t smb_notify_encode_action(struct smb_request *,
  95         mbuf_chain_t *, uint32_t, char *);


  96 

















  97 uint32_t
  98 smb_notify_common(smb_request_t *sr, mbuf_chain_t *mbc,
  99         uint32_t CompletionFilter)
 100 {
 101         smb_notify_change_req_t *nc;
 102         smb_node_t      *node;

 103         uint32_t        status;
 104 
 105         if (sr->fid_ofile == NULL)
 106                 return (NT_STATUS_INVALID_HANDLE);
 107 
 108         node = sr->fid_ofile->f_node;
 109         if (node == NULL || !smb_node_is_dir(node)) {
 110                 /*
 111                  * Notify change is only valid on directories.
 112                  */






 113                 return (NT_STATUS_INVALID_PARAMETER);
 114         }
 115 


 116         /*
 117          * Prepare to receive event data.


 118          */
 119         nc = &sr->sr_ncr;
 120         nc->nc_flags = CompletionFilter;
 121         ASSERT(nc->nc_action == 0);
 122         ASSERT(nc->nc_fname == NULL);
 123         nc->nc_fname = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
 124 

 125         /*
 126          * Subscribe to events on this node.

 127          */
 128         smb_node_fcn_subscribe(node, sr);
 129 

 130         /*
 131          * Wait for subscribed events to arrive.
 132          * Expect SMB_REQ_STATE_EVENT_OCCURRED
 133          * or SMB_REQ_STATE_CANCELED when signaled.
 134          * Note it's possible (though rare) to already
 135          * have SMB_REQ_STATE_CANCELED here.
 136          */
 137         mutex_enter(&sr->sr_mutex);
 138         if (sr->sr_state == SMB_REQ_STATE_ACTIVE)
 139                 sr->sr_state = SMB_REQ_STATE_WAITING_EVENT;
 140         while (sr->sr_state == SMB_REQ_STATE_WAITING_EVENT) {
 141                 cv_wait(&nc->nc_cv, &sr->sr_mutex);

 142         }
 143         if (sr->sr_state == SMB_REQ_STATE_EVENT_OCCURRED)
 144                 sr->sr_state = SMB_REQ_STATE_ACTIVE;
 145         mutex_exit(&sr->sr_mutex);
 146 


 147         /*
 148          * Unsubscribe from events on this node.
 149          */
 150         smb_node_fcn_unsubscribe(node, sr);


 151 





















 152         /*
 153          * Why did we wake up?
 154          */














 155         switch (sr->sr_state) {
 156         case SMB_REQ_STATE_ACTIVE:









 157                 break;
 158         case SMB_REQ_STATE_CANCELED:

 159                 status = NT_STATUS_CANCELLED;
 160                 goto out;
 161         default:
 162                 status = NT_STATUS_INTERNAL_ERROR;
 163                 goto out;
 164         }

 165 
 166         /*
 167          * We have SMB_REQ_STATE_ACTIVE.
















 168          *
 169          * If we have event data, marshall it now, else just
 170          * say "many things changed". Note that when we get
 171          * action FILE_ACTION_SUBDIR_CHANGED, we don't have
 172          * any event details and only know that some subdir
 173          * changed, so just report "many things changed".

 174          */
 175         switch (nc->nc_action) {





 176 
 177         case FILE_ACTION_ADDED:
 178         case FILE_ACTION_REMOVED:
 179         case FILE_ACTION_MODIFIED:
 180         case FILE_ACTION_RENAMED_OLD_NAME:
 181         case FILE_ACTION_RENAMED_NEW_NAME:
 182         case FILE_ACTION_ADDED_STREAM:
 183         case FILE_ACTION_REMOVED_STREAM:
 184         case FILE_ACTION_MODIFIED_STREAM:







 185                 /*
 186                  * Build the reply
 187                  */
 188                 status = smb_notify_encode_action(sr, mbc,
 189                     nc->nc_action, nc->nc_fname);
 190                 break;
 191 
 192         case FILE_ACTION_SUBDIR_CHANGED:
 193                 status = NT_STATUS_NOTIFY_ENUM_DIR;




 194                 break;
 195 
 196         case FILE_ACTION_DELETE_PENDING:
 197                 status = NT_STATUS_DELETE_PENDING;
 198                 break;
 199 
 200         default:
 201                 ASSERT(0);
 202                 status = NT_STATUS_INTERNAL_ERROR;
 203                 break;
 204         }

 205 
 206 out:
 207         kmem_free(nc->nc_fname, MAXNAMELEN);
 208         nc->nc_fname = NULL;









 209         return (status);
 210 }
 211 
 212 /*
 213  * Encode a FILE_NOTIFY_INFORMATION struct.
 214  *
 215  * We only ever put one of these in a response, so this
 216  * does not bother handling appending additional ones.
 217  */
 218 static uint32_t
 219 smb_notify_encode_action(struct smb_request *sr, mbuf_chain_t *mbc,
 220         uint32_t action, char *fname)
 221 {
 222         uint32_t namelen;



 223 
 224         ASSERT(FILE_ACTION_ADDED <= action &&
 225             action <= FILE_ACTION_MODIFIED_STREAM);


 226 
 227         if (fname == NULL)
 228                 return (NT_STATUS_INTERNAL_ERROR);
 229         namelen = smb_wcequiv_strlen(fname);
 230         if (namelen == 0)
 231                 return (NT_STATUS_INTERNAL_ERROR);
 232 
 233         if (smb_mbc_encodef(mbc, "%lllU", sr,
 234             0, /* NextEntryOffset */
 235             action, namelen, fname))
 236                 return (NT_STATUS_NOTIFY_ENUM_DIR);















 237 
 238         return (0);
 239 }
 240 
 241 /*
 242  * smb_notify_file_closed
 243  *
 244  * Cancel any change-notify calls on this open file.

 245  */
 246 void
 247 smb_notify_file_closed(struct smb_ofile *of)
 248 {
 249         smb_session_t   *ses;
 250         smb_request_t   *sr;
 251         smb_slist_t     *list;
 252 
 253         SMB_OFILE_VALID(of);
 254         ses = of->f_session;
 255         SMB_SESSION_VALID(ses);
 256         list = &ses->s_req_list;







 257 
 258         smb_slist_enter(list);








 259 
 260         sr = smb_slist_head(list);
 261         while (sr) {
 262                 SMB_REQ_VALID(sr);
 263                 if (sr->sr_state == SMB_REQ_STATE_WAITING_EVENT &&
 264                     sr->fid_ofile == of) {
 265                         smb_request_cancel(sr);



 266                 }
 267                 sr = smb_slist_next(list, sr);

























 268         }
 269 
 270         smb_slist_exit(list);
 271 }
 272 










 273 
 274 /*
 275  * smb_notify_event
 276  *
 277  * Post an event to the watchers on a given node.
 278  *
 279  * This makes one exception for RENAME, where we expect a
 280  * pair of events for the {old,new} directory element names.
 281  * This only delivers an event for the "new" name.
 282  *
 283  * The event delivery mechanism does not implement delivery of
 284  * multiple events for one "NT Notify" call.  One could do that,
 285  * but modern clients don't actually use the event data.  They
 286  * set a max. received data size of zero, which means we discard
 287  * the data and send the special "lots changed" error instead.
 288  * Given that, there's not really any point in implementing the
 289  * delivery of multiple events.  In fact, we don't even need to
 290  * implement single event delivery, but do so for completeness,
 291  * for debug convenience, and to be nice to older clients that
 292  * may actually want some event data instead of the error.
 293  *
 294  * Given that we only deliver a single event for an "NT Notify"
 295  * caller, we want to deliver the "new" name event.  (The "old"
 296  * name event is less important, even ignored by some clients.)
 297  * Since we know these are delivered in pairs, we can simply
 298  * discard the "old" name event, knowing that the "new" name
 299  * event will be delivered immediately afterwards.
 300  *
 301  * So, why do event sources post the "old name" event at all?
 302  * (1) For debugging, so we see both {old,new} names here.
 303  * (2) If in the future someone decides to implement the
 304  * delivery of both {old,new} events, the changes can be
 305  * mostly isolated to this file.
 306  */
 307 void
 308 smb_notify_event(smb_node_t *node, uint_t action, const char *name)
 309 {
 310         smb_request_t   *sr;
 311         smb_node_fcn_t  *fcn;
 312 
 313         SMB_NODE_VALID(node);
 314         fcn = &node->n_fcn;
 315 
 316         if (action == FILE_ACTION_RENAMED_OLD_NAME)
 317                 return; /* see above */




 318 
 319         mutex_enter(&fcn->fcn_mutex);
 320 
 321         sr = list_head(&fcn->fcn_watchers);
 322         while (sr) {
 323                 smb_notify_sr(sr, action, name);
 324                 sr = list_next(&fcn->fcn_watchers, sr);
 325         }

 326 
 327         mutex_exit(&fcn->fcn_mutex);




















 328 }
 329 

 330 /*
 331  * What completion filter (masks) apply to each of the
 332  * FILE_ACTION_... events.
 333  */
 334 static const uint32_t
 335 smb_notify_action_mask[] = {
 336         0,  /* not used */
 337 
 338         /* FILE_ACTION_ADDED     */
 339         FILE_NOTIFY_CHANGE_NAME |
 340         FILE_NOTIFY_CHANGE_LAST_WRITE,
 341 
 342         /* FILE_ACTION_REMOVED   */
 343         FILE_NOTIFY_CHANGE_NAME |
 344         FILE_NOTIFY_CHANGE_LAST_WRITE,
 345 
 346         /* FILE_ACTION_MODIFIED  */
 347         FILE_NOTIFY_CHANGE_ATTRIBUTES |
 348         FILE_NOTIFY_CHANGE_SIZE |
 349         FILE_NOTIFY_CHANGE_LAST_WRITE |


 354 
 355         /* FILE_ACTION_RENAMED_OLD_NAME */
 356         FILE_NOTIFY_CHANGE_NAME |
 357         FILE_NOTIFY_CHANGE_LAST_WRITE,
 358 
 359         /* FILE_ACTION_RENAMED_NEW_NAME */
 360         FILE_NOTIFY_CHANGE_NAME |
 361         FILE_NOTIFY_CHANGE_LAST_WRITE,
 362 
 363         /* FILE_ACTION_ADDED_STREAM */
 364         FILE_NOTIFY_CHANGE_STREAM_NAME,
 365 
 366         /* FILE_ACTION_REMOVED_STREAM */
 367         FILE_NOTIFY_CHANGE_STREAM_NAME,
 368 
 369         /* FILE_ACTION_MODIFIED_STREAM */
 370         FILE_NOTIFY_CHANGE_STREAM_SIZE |
 371         FILE_NOTIFY_CHANGE_STREAM_WRITE,
 372 
 373         /* FILE_ACTION_SUBDIR_CHANGED */
 374         NODE_FLAGS_WATCH_TREE,
 375 
 376         /* FILE_ACTION_DELETE_PENDING */
 377         NODE_FLAGS_WATCH_TREE |
 378         FILE_NOTIFY_VALID_MASK,


 379 };
 380 static const int smb_notify_action_nelm =
 381         sizeof (smb_notify_action_mask) /
 382         sizeof (smb_notify_action_mask[0]);
 383 
 384 /*
 385  * smb_notify_sr
 386  *
 387  * Post an event to an smb request waiting on some node.
 388  *
 389  * Note that node->fcn.mutex is held.  This implies a
 390  * lock order: node->fcn.mutex, then sr_mutex
 391  */
 392 static void
 393 smb_notify_sr(smb_request_t *sr, uint_t action, const char *name)
 394 {
 395         smb_notify_change_req_t *ncr;
 396         uint32_t        mask;

 397 
 398         SMB_REQ_VALID(sr);
 399         ncr = &sr->sr_ncr;
 400 



 401         /*
 402          * Compute the completion filter mask bits for which
 403          * we will signal waiting notify requests.

 404          */



 405         VERIFY(action < smb_notify_action_nelm);
 406         mask = smb_notify_action_mask[action];


 407 
 408         mutex_enter(&sr->sr_mutex);
 409         if (sr->sr_state == SMB_REQ_STATE_WAITING_EVENT &&
 410             (ncr->nc_flags & mask) != 0) {
 411                 sr->sr_state = SMB_REQ_STATE_EVENT_OCCURRED;
 412                 /*
 413                  * Save event data in the sr_ncr field so the
 414                  * reply handler can return it.
 415                  */
 416                 ncr->nc_action = action;
 417                 if (name != NULL)
 418                         (void) strlcpy(ncr->nc_fname, name, MAXNAMELEN);
 419                 cv_signal(&ncr->nc_cv);



























 420         }
 421         mutex_exit(&sr->sr_mutex);









































































 422 }


   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 2016 Nexenta Systems, Inc.  All rights reserved.
  25  */
  26 
  27 /*
  28  * File Change Notification (FCN)
  29  * Common parts shared by SMB1 & SMB2
  30  */
  31 
  32 /*
  33  * This command notifies the client when the specified directory
  34  * has changed, and optionally returns the names of files and
  35  * directories that changed, and how they changed.  The caller
  36  * specifies a "Completion Filter" to select which kinds of
  37  * changes they want to know about.
  38  *
  39  * When a change that's in the CompletionFilter is made to the directory,
  40  * the command completes.  The names of the files that have changed since
  41  * the last time the command was issued are returned to the client.
  42  * If too many files have changed since the last time the command was
  43  * issued, then zero bytes are returned and an alternate status code
  44  * is returned in the Status field of the response.


  68  * entry in the list must be longword aligned, so NextEntryOffset must be a
  69  * multiple of four.
  70  *
  71  * typedef struct {
  72  *     ULONG NextEntryOffset;
  73  *     ULONG Action;
  74  *     ULONG FileNameLength;
  75  *     WCHAR FileName[1];
  76  * } FILE_NOTIFY_INFORMATION;
  77  *
  78  * Where Action describes what happened to the file named FileName:
  79  *
  80  * FILE_ACTION_ADDED            0x00000001
  81  * FILE_ACTION_REMOVED          0x00000002
  82  * FILE_ACTION_MODIFIED         0x00000003
  83  * FILE_ACTION_RENAMED_OLD_NAME 0x00000004
  84  * FILE_ACTION_RENAMED_NEW_NAME 0x00000005
  85  * FILE_ACTION_ADDED_STREAM     0x00000006
  86  * FILE_ACTION_REMOVED_STREAM   0x00000007
  87  * FILE_ACTION_MODIFIED_STREAM  0x00000008
  88  *
  89  * The internal interface between SMB1 and/or SMB2 protocol handlers
  90  * and this module has some sophistication to allow for:
  91  * (1) code sharing between SMB1 and SMB2(+)
  92  * (2) efficient handling of non-blocking scenarios
  93  * (3) long blocking calls without tying up a thread
  94  *
  95  * The interface has three calls (like a three act play)
  96  *
  97  * smb_notify_act1:
  98  *      Validate parameters, setup ofile buffer.
  99  *      If data already available, return it, all done.
 100  *      (In the "all done" case, skip act2 & act3.)
 101  *      If no data available, return a special error
 102  *      ("STATUS_PENDING") to tell the caller they must
 103  *      proceed with calls to act2 & act3.
 104  *
 105  * smb_notify_act2:
 106  *      Arrange wakeup after event delivery or cancellation.
 107  *      Return leaving the SR with no worker thread.
 108  *
 109  * smb_notify_act3:
 110  *      New taskq work thread runs this after the wakeup
 111  *      or cancellation arranged in act2 happens.  This
 112  *      returns the notification data and retires the SR.
 113  *
 114  * In the SMB2 notify handler, we call act1 during the initial
 115  * synchronous handling of the request.  If that returns anything
 116  * other than STATUS_PENDING, that request is fully complete.
 117  * If act1 returns STATUS_PENDING, SMB2 calls act2 as it's
 118  * "go async" handler, which arranges to call act3 later.
 119  *
 120  * In the SMB1 notify handler there is not separate sync. & async
 121  * handler so act1 and (if necessary) act2 are both called during
 122  * the initial handling of the request.
 123  *
 124  * About notify event buffering:
 125  *
 126  * An important (and poorly documented) feature of SMB notify is
 127  * that once a notify call has happened on a given directory handle,
 128  * the system CONTINUES to post events to the notify event buffer
 129  * for the handle, even when SMB notify calls are NOT running.
 130  * When the client next comes back with a notify call, we return
 131  * any events that were posted while they were "away".  This is
 132  * how clients track directory changes without missing events.
 133  *
 134  * About simultaneous notify calls:
 135  *
 136  * Note that SMB "notify" calls are destructive to events, much like
 137  * reading data from a pipe.  It therefore makes little sense to
 138  * allow multiple simultaneous callers.  However, we permit it
 139  * (like Windows does) as follows:  When multiple notify calls
 140  * are waiting for events, the next event wakes them all, and
 141  * only the last one out clears the event buffer.  They all get
 142  * whatever events are pending at the time they woke up.
 143  *
 144  * About NT_STATUS_NOTIFY_ENUM_DIR
 145  *
 146  * One more caution about NT_STATUS_NOTIFY_ENUM_DIR:  Some clients
 147  * are stupid about re-reading the directory almost continuously when
 148  * there are changes happening in the directory.  We want to bound
 149  * the rate of such directory re-reading, so before returning an
 150  * NT_STATUS_NOTIFY_ENUM_DIR, we delay just a little.  The length
 151  * of the delay can be adjusted via smb_notify_enum_dir_delay,
 152  * though it's not expected that should need to be changed.
 153  */
 154 
 155 #include <smbsrv/smb_kproto.h>
 156 #include <sys/sdt.h>
 157 
 158 /*
 159  * Length of the short delay we impose before returning
 160  * NT_STATUS_NOTIFY_ENUM_DIR (See above)
 161  */
 162 int smb_notify_enum_dir_delay = 100; /* mSec. */
 163 
 164 static uint32_t smb_notify_get_events(smb_request_t *);
 165 static void smb_notify_cancel(smb_request_t *);
 166 static void smb_notify_wakeup(smb_request_t *);
 167 static void smb_notify_dispatch2(smb_request_t *);
 168 static void smb_notify_encode_action(smb_ofile_t *,
 169         uint32_t, const char *);
 170 
 171 
 172 /*
 173  * smb_notify_act1()
 174  *
 175  * Check for events and consume, non-blocking.
 176  * Special return STATUS_PENDING means:
 177  * No events; caller must call "act2" next.
 178  *
 179  * See overall design notes, top of file.
 180  */
 181 uint32_t
 182 smb_notify_act1(smb_request_t *sr, uint32_t buflen, uint32_t filter)

 183 {
 184         smb_ofile_t     *of;
 185         smb_node_t      *node;
 186         smb_notify_t    *nc;
 187         uint32_t        status;
 188 





 189         /*
 190          * Validate parameters
 191          */
 192         if ((of = sr->fid_ofile) == NULL)
 193                 return (NT_STATUS_INVALID_HANDLE);
 194         nc = &of->f_notify;
 195         node = of->f_node;
 196         if (node == NULL || !smb_node_is_dir(node)) {
 197                 /* Notify change is only valid on directories. */
 198                 return (NT_STATUS_INVALID_PARAMETER);
 199         }
 200 
 201         mutex_enter(&of->f_mutex);
 202 
 203         /*
 204          * On the first FCN call with this ofile, subscribe to
 205          * events on the node.  The corresponding unsubscribe
 206          * happens in smb_ofile_delete().
 207          */
 208         if (nc->nc_subscribed == B_FALSE) {
 209                 nc->nc_subscribed = B_TRUE;
 210                 smb_node_fcn_subscribe(node);
 211                 /* In case this happened before we subscribed. */
 212                 if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
 213                         nc->nc_events |= FILE_NOTIFY_CHANGE_EV_DELETE;
 214                 }
 215                 /*
 216                  * Windows only lets you set these on the first call,
 217                  * so we may as well do the same.
 218                  */
 219                 nc->nc_buffer.max_bytes = buflen;
 220                 nc->nc_filter = filter;
 221         }
 222         /*
 223          * If we already have events, consume them.




 224          */
 225         sr->raw_data.max_bytes = buflen;
 226         if (nc->nc_events != 0) {
 227                 status = smb_notify_get_events(sr);
 228         } else {
 229                 /* Caller will come back for act2 */
 230                 status = NT_STATUS_PENDING;
 231         }



 232 
 233         mutex_exit(&of->f_mutex);
 234 
 235         /*
 236          * See: About NT_STATUS_NOTIFY_ENUM_DIR (above)
 237          */
 238         if (status == NT_STATUS_NOTIFY_ENUM_DIR &&
 239             smb_notify_enum_dir_delay > 0)
 240                 delay(MSEC_TO_TICK(smb_notify_enum_dir_delay));
 241 
 242         return (status);
 243 }
 244 
 245 /*
 246  * smb_notify_act2()
 247  *
 248  * Prepare to wait for events after act1 found that none were pending.
 249  * Assume the wait may be for a very long time.  (hours, days...)
 250  * Special return STATUS_PENDING means the SR will later be
 251  * scheduled again on a new worker thread, and this thread
 252  * MUST NOT touch it any longer (return SDRC_SR_KEPT).
 253  *
 254  * See overall design notes, top of file.
 255  */
 256 uint32_t
 257 smb_notify_act2(smb_request_t *sr)
 258 {
 259         smb_ofile_t     *of;
 260         smb_notify_t    *nc;
 261         uint32_t        status;
 262 
 263         /*
 264          * Sanity checks.
 265          */
 266         if ((of = sr->fid_ofile) == NULL)
 267                 return (NT_STATUS_INVALID_HANDLE);
 268         nc = &of->f_notify;
 269 
 270         mutex_enter(&of->f_mutex);
 271 
 272         /*
 273          * Prepare for a potentially long wait for events.
 274          * Normally transition from ACTIVE to WAITING_FCN1.
 275          *
 276          * Note we hold both of->f_mutex, sr->sr_mutex here,
 277          * taken in that order.
 278          */
 279         mutex_enter(&sr->sr_mutex);
 280         switch (sr->sr_state) {
 281         case SMB_REQ_STATE_ACTIVE:
 282                 /*
 283                  * This sr has no worker thread until smb_notify_act3
 284                  * or smb_notify_cancel (later, via taskq_dispatch).
 285                  */
 286                 sr->sr_state = SMB_REQ_STATE_WAITING_FCN1;
 287                 sr->cancel_method = smb_notify_cancel;
 288                 sr->sr_worker = NULL;
 289                 list_insert_tail(&nc->nc_waiters, sr);
 290                 status = NT_STATUS_PENDING;
 291                 break;
 292 
 293         case SMB_REQ_STATE_CANCELLED:
 294                 status = NT_STATUS_CANCELLED;
 295                 break;
 296         default:
 297                 status = NT_STATUS_INTERNAL_ERROR;
 298                 break;
 299         }
 300         mutex_exit(&sr->sr_mutex);
 301 
 302         /*
 303          * In case we missed any events before setting
 304          * state FCN1, schedule our own wakeup.
 305          */
 306         if (status == NT_STATUS_PENDING && nc->nc_events != 0) {
 307                 smb_notify_wakeup(sr);
 308         }
 309 
 310         mutex_exit(&of->f_mutex);
 311 
 312         /* Note: Never NT_STATUS_NOTIFY_ENUM_DIR here. */
 313         ASSERT(status != NT_STATUS_NOTIFY_ENUM_DIR);
 314 
 315         return (status);
 316 }
 317 
 318 /*
 319  * smb_notify_act3()
 320  *
 321  * This runs via the 2nd taskq_dispatch call, after we've either
 322  * seen a change notify event, or the request has been cancelled.
 323  * Complete it here.  This returns to SMB1 or SMB2 code to send
 324  * the response and free the request.
 325  *
 326  * See overall design notes, top of file.
 327  */
 328 uint32_t
 329 smb_notify_act3(smb_request_t *sr)
 330 {
 331         smb_ofile_t     *of;
 332         smb_notify_t    *nc;
 333         uint32_t        status;
 334 
 335         of = sr->fid_ofile;
 336         ASSERT(of != NULL);
 337         nc = &of->f_notify;
 338 
 339         mutex_enter(&of->f_mutex);
 340 
 341         mutex_enter(&sr->sr_mutex);
 342         ASSERT3P(sr->sr_worker, ==, NULL);
 343         sr->sr_worker = curthread;
 344         sr->cancel_method = NULL;
 345 
 346         list_remove(&nc->nc_waiters, sr);
 347 
 348         switch (sr->sr_state) {
 349         case SMB_REQ_STATE_WAITING_FCN2:
 350                 /*
 351                  * Got smb_notify_wakeup.
 352                  */
 353                 sr->sr_state = SMB_REQ_STATE_ACTIVE;
 354                 status = 0;
 355                 break;
 356 
 357         case SMB_REQ_STATE_CANCEL_PENDING:
 358                 /*
 359                  * Got smb_notify_cancel
 360                  */
 361                 sr->sr_state = SMB_REQ_STATE_CANCELLED;
 362                 status = NT_STATUS_CANCELLED;
 363                 break;





 364         default:

 365                 status = NT_STATUS_INTERNAL_ERROR;
 366                 break;
 367         }
 368         mutex_exit(&sr->sr_mutex);
 369 
 370         if (status == 0)
 371                 status = smb_notify_get_events(sr);
 372 
 373         mutex_exit(&of->f_mutex);
 374 
 375         /*
 376          * See: About NT_STATUS_NOTIFY_ENUM_DIR (above)
 377          */
 378         if (status == NT_STATUS_NOTIFY_ENUM_DIR &&
 379             smb_notify_enum_dir_delay > 0)
 380                 delay(MSEC_TO_TICK(smb_notify_enum_dir_delay));
 381 
 382         return (status);
 383 }
 384 






 385 static uint32_t
 386 smb_notify_get_events(smb_request_t *sr)

 387 {
 388         smb_ofile_t     *of;
 389         smb_notify_t    *nc;
 390         uint32_t        status;
 391         int             len;
 392 
 393         of = sr->fid_ofile;
 394         ASSERT(of != NULL);
 395         ASSERT(MUTEX_HELD(&of->f_mutex));
 396         nc = &of->f_notify;
 397 
 398         DTRACE_PROBE2(notify__get__events,
 399             smb_request_t, sr,
 400             uint32_t, nc->nc_events);


 401 
 402         /*
 403          * Special events which override other events
 404          */
 405         if (nc->nc_events & FILE_NOTIFY_CHANGE_EV_CLOSED) {
 406                 status = NT_STATUS_NOTIFY_CLEANUP;
 407                 goto out;
 408         }
 409         if (nc->nc_events & FILE_NOTIFY_CHANGE_EV_DELETE) {
 410                 status = NT_STATUS_DELETE_PENDING;
 411                 goto out;
 412         }
 413         if (nc->nc_events & FILE_NOTIFY_CHANGE_EV_SUBDIR) {
 414                 status = NT_STATUS_NOTIFY_ENUM_DIR;
 415                 goto out;
 416         }
 417         if (nc->nc_events & FILE_NOTIFY_CHANGE_EV_OVERFLOW) {
 418                 status = NT_STATUS_NOTIFY_ENUM_DIR;
 419                 goto out;
 420         }
 421 
 422         /*
 423          * Normal events (FILE_NOTIFY_VALID_MASK)



 424          *
 425          * At this point there should be some, or else
 426          * some sort of bug woke us up for nothing.
 427          */
 428         if ((nc->nc_events & FILE_NOTIFY_VALID_MASK) == 0) {
 429                 status = NT_STATUS_INTERNAL_ERROR;
 430                 goto out;
 431         }


 432 
 433         /*
 434          * Many Windows clients call change notify with a
 435          * zero-length buffer, expecting all events to be
 436          * reported as _ENUM_DIR.  Testing max_bytes here
 437          * because ROOM_FOR check below says "yes" if both
 438          * max_bytes and the amount we ask for are zero.
 439          */
 440         if (nc->nc_buffer.max_bytes <= 0) {
 441                 status = NT_STATUS_NOTIFY_ENUM_DIR;
 442                 goto out;
 443         }
 444 
 445         /*
 446          * Client gave us a non-zero output buffer, and
 447          * there was no overflow event (checked above)
 448          * so there should be some event data.
 449          */
 450         if ((len = nc->nc_buffer.chain_offset) <= 0) {
 451                 status = NT_STATUS_INTERNAL_ERROR;
 452                 goto out;
 453         }
 454 
 455         /*
 456          * If the current SR has a smaller output buffer
 457          * then what was setup by some previous notify,
 458          * we could have more data than will fit.
 459          */
 460         if (!MBC_ROOM_FOR(&sr->raw_data, len)) {
 461                 /* Would overflow caller's buffer. */
 462                 status = NT_STATUS_NOTIFY_ENUM_DIR;
 463                 goto out;
 464         }
 465 
 466         /*
 467          * Copy the event data to sr->raw_data.  In the copy,
 468          * zap the NextEntryOffset in the last entry, and
 469          * trim any extra bytes at the tail.
 470          */
 471         (void) smb_mbc_copy(&sr->raw_data, &nc->nc_buffer, 0, len);
 472         (void) smb_mbc_poke(&sr->raw_data, nc->nc_last_off, "l", 0);
 473         smb_mbuf_trim(sr->raw_data.chain, len);
 474         status = 0;
 475 
 476 out:
 477         /*
 478          * If there are no other SRs waiting on this ofile,
 479          * mark all events consumed, except for those that
 480          * remain until the ofile is closed.  That means
 481          * clear all bits EXCEPT: _EV_CLOSED, _EV_DELETE
 482          *
 483          * If there are other waiters (rare) all will get
 484          * the currently pending events, and then the
 485          * the last one out will clear the events.
 486          */
 487         if (list_is_empty(&nc->nc_waiters)) {
 488                 nc->nc_buffer.chain_offset = 0;
 489                 nc->nc_events &= (FILE_NOTIFY_CHANGE_EV_CLOSED |
 490                     FILE_NOTIFY_CHANGE_EV_DELETE);
 491         }
 492 
 493         return (status);
 494 }
 495 
 496 /*
 497  * Called by common code after a transition from
 498  * state WAITING_FCN1 to state CANCEL_PENDING.
 499  */
 500 static void
 501 smb_notify_cancel(smb_request_t *sr)
 502 {
 503         ASSERT3U(sr->sr_state, ==, SMB_REQ_STATE_CANCEL_PENDING);
 504         smb_notify_dispatch2(sr);
 505 }
 506 
 507 /*
 508  * Called after ofile event delivery to take a waiting smb request
 509  * from state FCN1 to state FCN2.  This may be called many times
 510  * (as events are delivered) but it must (exactly once) schedule
 511  * the taskq job to run smb_notify_act3().  Only the event that
 512  * takes us from state FCN1 to FCN2 schedules the taskq job.


























 513  */
 514 static void
 515 smb_notify_wakeup(smb_request_t *sr)
 516 {
 517         boolean_t do_disp = B_FALSE;

 518 
 519         SMB_REQ_VALID(sr);

 520 
 521         mutex_enter(&sr->sr_mutex);
 522         if (sr->sr_state == SMB_REQ_STATE_WAITING_FCN1) {
 523                 sr->sr_state = SMB_REQ_STATE_WAITING_FCN2;
 524                 do_disp = B_TRUE;
 525         }
 526         mutex_exit(&sr->sr_mutex);
 527 
 528         if (do_disp) {
 529                 smb_notify_dispatch2(sr);




 530         }
 531 }
 532 
 533 /*
 534  * smb_notify_dispatch2()
 535  * Schedule a 2nd taskq call to finish up a change notify request;
 536  * (smb_notify_act3) either completing it or cancelling it.
 537  */
 538 static void
 539 smb_notify_dispatch2(smb_request_t *sr)
 540 {
 541         void (*tq_func)(void *);
 542 
 543         /*
 544          * Both of these call smb_notify_act3(), returning
 545          * to version-specific code to send the response.
 546          */
 547         if (sr->session->dialect >= SMB_VERS_2_BASE)
 548                 tq_func = smb2_change_notify_finish;
 549         else
 550                 tq_func = smb_nt_transact_notify_finish;
 551 
 552         (void) taskq_dispatch(sr->sr_server->sv_worker_pool,
 553             tq_func, sr, TQ_SLEEP);
 554 }
 555 
 556 
 557 /*
 558  * What completion filter (masks) apply to each of the
 559  * FILE_ACTION_... events.
 560  */
 561 static const uint32_t
 562 smb_notify_action_mask[] = {
 563         0,  /* not used */
 564 
 565         /* FILE_ACTION_ADDED     */
 566         FILE_NOTIFY_CHANGE_NAME |
 567         FILE_NOTIFY_CHANGE_LAST_WRITE,
 568 
 569         /* FILE_ACTION_REMOVED   */
 570         FILE_NOTIFY_CHANGE_NAME |
 571         FILE_NOTIFY_CHANGE_LAST_WRITE,
 572 
 573         /* FILE_ACTION_MODIFIED  */
 574         FILE_NOTIFY_CHANGE_ATTRIBUTES |
 575         FILE_NOTIFY_CHANGE_SIZE |
 576         FILE_NOTIFY_CHANGE_LAST_WRITE |


 581 
 582         /* FILE_ACTION_RENAMED_OLD_NAME */
 583         FILE_NOTIFY_CHANGE_NAME |
 584         FILE_NOTIFY_CHANGE_LAST_WRITE,
 585 
 586         /* FILE_ACTION_RENAMED_NEW_NAME */
 587         FILE_NOTIFY_CHANGE_NAME |
 588         FILE_NOTIFY_CHANGE_LAST_WRITE,
 589 
 590         /* FILE_ACTION_ADDED_STREAM */
 591         FILE_NOTIFY_CHANGE_STREAM_NAME,
 592 
 593         /* FILE_ACTION_REMOVED_STREAM */
 594         FILE_NOTIFY_CHANGE_STREAM_NAME,
 595 
 596         /* FILE_ACTION_MODIFIED_STREAM */
 597         FILE_NOTIFY_CHANGE_STREAM_SIZE |
 598         FILE_NOTIFY_CHANGE_STREAM_WRITE,
 599 
 600         /* FILE_ACTION_SUBDIR_CHANGED */
 601         FILE_NOTIFY_CHANGE_EV_SUBDIR,
 602 
 603         /* FILE_ACTION_DELETE_PENDING */
 604         FILE_NOTIFY_CHANGE_EV_DELETE,
 605 
 606         /* FILE_ACTION_HANDLE_CLOSED */
 607         FILE_NOTIFY_CHANGE_EV_CLOSED,
 608 };
 609 static const int smb_notify_action_nelm =
 610         sizeof (smb_notify_action_mask) /
 611         sizeof (smb_notify_action_mask[0]);
 612 
 613 /*
 614  * smb_notify_ofile
 615  *
 616  * Post an event to the change notify buffer for this ofile,
 617  * subject to the mask that selects subscribed event types.
 618  * If an SR is waiting for events and we've delivered some,
 619  * wake the SR.
 620  */
 621 void
 622 smb_notify_ofile(smb_ofile_t *of, uint_t action, const char *name)
 623 {
 624         smb_notify_t    *nc;
 625         smb_request_t   *sr;
 626         uint32_t        filter, events;
 627 
 628         SMB_OFILE_VALID(of);

 629 
 630         mutex_enter(&of->f_mutex);
 631         nc = &of->f_notify;
 632 
 633         /*
 634          * Compute the filter & event bits for this action,
 635          * which determine whether we'll post the event.
 636          * Note: always sensitive to: delete, closed.
 637          */
 638         filter = nc->nc_filter |
 639             FILE_NOTIFY_CHANGE_EV_DELETE |
 640             FILE_NOTIFY_CHANGE_EV_CLOSED;
 641         VERIFY(action < smb_notify_action_nelm);
 642         events = smb_notify_action_mask[action];
 643         if ((filter & events) == 0)
 644                 goto unlock_out;
 645 




 646         /*
 647          * OK, we're going to post this event.

 648          */
 649         switch (action) {
 650         case FILE_ACTION_ADDED:
 651         case FILE_ACTION_REMOVED:
 652         case FILE_ACTION_MODIFIED:
 653         case FILE_ACTION_RENAMED_OLD_NAME:
 654         case FILE_ACTION_RENAMED_NEW_NAME:
 655         case FILE_ACTION_ADDED_STREAM:
 656         case FILE_ACTION_REMOVED_STREAM:
 657         case FILE_ACTION_MODIFIED_STREAM:
 658                 /*
 659                  * Append this event to the buffer.
 660                  * Also keep track of events seen.
 661                  */
 662                 smb_notify_encode_action(of, action, name);
 663                 nc->nc_events |= events;
 664                 break;
 665 
 666         case FILE_ACTION_SUBDIR_CHANGED:
 667         case FILE_ACTION_DELETE_PENDING:
 668         case FILE_ACTION_HANDLE_CLOSED:
 669                 /*
 670                  * These are "internal" events, and therefore
 671                  * are not appended to the response buffer.
 672                  * Just record the event flags and wakeup.
 673                  */
 674                 nc->nc_events |= events;
 675                 break;
 676 
 677         default:
 678                 ASSERT(0);      /* bogus action */
 679                 break;
 680         }
 681 
 682         sr = list_head(&nc->nc_waiters);
 683         while (sr != NULL) {
 684                 smb_notify_wakeup(sr);
 685                 sr = list_next(&nc->nc_waiters, sr);
 686         }
 687 
 688 unlock_out:
 689         mutex_exit(&of->f_mutex);
 690 }
 691 
 692 /*
 693  * Encode a FILE_NOTIFY_INFORMATION struct.
 694  */
 695 static void
 696 smb_notify_encode_action(smb_ofile_t *of,
 697     uint32_t action, const char *fname)
 698 {
 699         smb_notify_t *nc = &of->f_notify;
 700         mbuf_chain_t *mbc;
 701         uint32_t namelen, totlen;
 702 
 703         ASSERT(nc != NULL);
 704         ASSERT(FILE_ACTION_ADDED <= action &&
 705             action <= FILE_ACTION_MODIFIED_STREAM);
 706         ASSERT(fname != NULL);
 707         ASSERT(MUTEX_HELD(&of->f_mutex));
 708 
 709         /* Once we've run out of room, stop trying to append. */
 710         if ((nc->nc_events & FILE_NOTIFY_CHANGE_EV_OVERFLOW) != 0)
 711                 return;
 712 
 713         if (fname == NULL)
 714                 return;
 715         namelen = smb_wcequiv_strlen(fname);
 716         if (namelen == 0)
 717                 return;
 718 
 719         /*
 720          * Layout is: 3 DWORDS, Unicode string, pad(4).
 721          */
 722         mbc = &nc->nc_buffer;
 723         totlen = (12 + namelen + 3) & ~3;
 724         if (MBC_ROOM_FOR(mbc, totlen) == 0) {
 725                 nc->nc_events |= FILE_NOTIFY_CHANGE_EV_OVERFLOW;
 726                 return;
 727         }
 728 
 729         /*
 730          * Keep track of where this entry starts (nc_last_off)
 731          * because after we put all entries, we need to zap
 732          * the NextEntryOffset field in the last one.
 733          */
 734         nc->nc_last_off = mbc->chain_offset;
 735 
 736         /*
 737          * Encode this entry, then 4-byte alignment padding.
 738          *
 739          * Note that smb_mbc_encodef with a "U" code puts a
 740          * Unicode string with a null termination.  We don't
 741          * want a null, but do want alignment padding.  We
 742          * get that by encoding with "U.." at the end of the
 743          * encoding string, which gets us two bytes for the
 744          * Unicode NULL, and two more zeros for the "..".
 745          * We then "back up" the chain_offset (finger) so it's
 746          * correctly 4-byte aligned.  We will sometimes have
 747          * written a couple more bytes than needed, but we'll
 748          * just overwrite those with the next entry.  At the
 749          * end, we trim the mbuf chain to the correct length.
 750          */
 751         (void) smb_mbc_encodef(mbc, "lllU..",
 752             totlen, /* NextEntryOffset */
 753             action, namelen, fname);
 754         mbc->chain_offset = nc->nc_last_off + totlen;
 755 }