Print this page
    
11083 support NFS server in zone
Portions contributed by: Dan Kruchinin <dan.kruchinin@nexenta.com>
Portions contributed by: Stepan Zastupov <stepan.zastupov@gmail.com>
Portions contributed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Portions contributed by: Mike Zeller <mike@mikezeller.net>
Portions contributed by: Dan McDonald <danmcd@joyent.com>
Portions contributed by: Gordon Ross <gordon.w.ross@gmail.com>
Portions contributed by: Vitaliy Gusev <gusev.vitaliy@gmail.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Jason King <jbk@joyent.com>
Reviewed by: C Fraire <cfraire@me.com>
Change-Id: I22f289d357503f9b48a0bc2482cc4328a6d43d16
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/fs/nfs/nfs_log.c
          +++ new/usr/src/uts/common/fs/nfs/nfs_log.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  
    | 
      ↓ open down ↓ | 
    10 lines elided | 
    
      ↑ open up ↑ | 
  
  11   11   * and limitations under the License.
  12   12   *
  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   23   * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
  23   24   */
  24   25  
       26 +/*
       27 + * Copyright 2018 Nexenta Systems, Inc.
       28 + */
       29 +
  25   30  #include <sys/cred.h>
  26   31  #include <sys/cmn_err.h>
  27   32  #include <sys/debug.h>
  28   33  #include <sys/systm.h>
  29   34  #include <sys/kmem.h>
  30   35  #include <sys/disp.h>
  31   36  #include <sys/atomic.h>
  32   37  #include <rpc/types.h>
  33   38  #include <nfs/nfs.h>
  34   39  #include <nfs/nfssys.h>
  35   40  #include <nfs/export.h>
  
    | 
      ↓ open down ↓ | 
    1 lines elided | 
    
      ↑ open up ↑ | 
  
  36   41  #include <nfs/rnode.h>
  37   42  #include <rpc/auth.h>
  38   43  #include <rpc/svc.h>
  39   44  #include <rpc/xdr.h>
  40   45  #include <rpc/clnt.h>
  41   46  #include <nfs/nfs_log.h>
  42   47  
  43   48  #define NUM_RECORDS_TO_WRITE 256
  44   49  #define NUM_BYTES_TO_WRITE 65536
  45   50  
  46      -extern krwlock_t exported_lock;
  47      -
  48   51  static int nfslog_num_records_to_write = NUM_RECORDS_TO_WRITE;
  49   52  static int nfslog_num_bytes_to_write = NUM_BYTES_TO_WRITE;
  50   53  
  51   54  /*
  52   55   * This struct is used to 'hide' the details of managing the log
  53   56   * records internally to the logging code.  Allocation routines
  54   57   * are used to obtain pieces of memory for XDR encoding.  This struct
  55   58   * is a 'header' to those areas and a opaque cookie is used to pass
  56   59   * this data structure between the allocating function and the put
  57   60   * function.
  58   61   */
  59   62  struct lr_alloc {
  60   63          struct lr_alloc         *next;          /* links for write queuing */
  61   64          struct lr_alloc         *prev;
  62   65  #define LR_ALLOC_NOFREE 0x1                     /* not present, call free */
  63   66          int                     lr_flags;
  64   67          caddr_t                 log_record;     /* address to XDR encoding */
  65   68          size_t                  size;           /* final size of encoding */
  66   69          struct kmem_cache       *alloc_cache;   /* keep track of cache ptr */
  67   70          struct exportinfo       *exi;           /* who are we related to? */
  68   71          struct log_buffer       *lb;
  69   72  };
  70   73  
  71   74  struct flush_thread_params {
  72   75          struct nfsl_flush_args tp_args;
  73   76          int tp_error;
  74   77  };
  75   78  
  76   79  static int log_file_create(caddr_t, struct log_file **);
  77   80  static void log_file_rele(struct log_file *);
  78   81  static struct log_buffer *log_buffer_create(caddr_t);
  79   82  static void log_buffer_rele(struct log_buffer *);
  80   83  static int nfslog_record_append2all(struct lr_alloc *);
  81   84  static int nfslog_logbuffer_rename(struct log_buffer *);
  82   85  static void nfslog_logfile_wait(struct log_file *);
  83   86  static int nfslog_logfile_rename(char *, char *);
  84   87  static void nfslog_do_flush(struct flush_thread_params *);
  85   88  static void create_buffer_header(caddr_t *, size_t *, size_t *);
  86   89  
  87   90  static int nfslog_write_logrecords(struct log_file *, struct lr_alloc *, int);
  88   91  static void nfslog_free_logrecords(struct lr_alloc *);
  89   92  static int nfslog_records_flush_to_disk(struct log_buffer *);
  90   93  static int nfslog_records_flush_to_disk_nolock(struct log_buffer *);
  91   94  
  92   95  /*
  93   96   * Read/Write lock that protects 'nfslog_buffer_list'.
  94   97   * This lock must be held when searching or modifying 'nfslog_buffer_list'.
  95   98   */
  96   99  static krwlock_t nfslog_buffer_list_lock;
  97  100  
  98  101  /*
  99  102   * The list of "log_buffer" structures.
 100  103   */
 101  104  struct log_buffer *nfslog_buffer_list = NULL;
 102  105  
 103  106  
 104  107  #define LOG_BUFFER_HOLD(lbp)    { \
 105  108          mutex_enter(&(lbp)->lb_lock); \
 106  109          (lbp)->lb_refcnt++; \
 107  110          mutex_exit(&(lbp)->lb_lock); \
 108  111  }
 109  112  
 110  113  #define LOG_FILE_HOLD(lfp)      { \
 111  114          mutex_enter(&(lfp)->lf_lock); \
 112  115          (lfp)->lf_refcnt++; \
 113  116          mutex_exit(&(lfp)->lf_lock); \
 114  117  }
 115  118  
 116  119  #define LOG_FILE_RELE(lfp)      { \
 117  120          log_file_rele(lfp); \
 118  121  }
 119  122  
 120  123  /*
 121  124   * These two macros are used to prep a logfile data structure and
 122  125   * associated file for writing data.  Note that the lf_lock is
 123  126   * held as a result of the call to the first macro.  This is used
 124  127   * for serialization correctness between the logbuffer struct and
 125  128   * the logfile struct.
 126  129   */
 127  130  #define LOG_FILE_LOCK_TO_WRITE(lfp)     { \
 128  131          mutex_enter(&(lfp)->lf_lock); \
 129  132          (lfp)->lf_refcnt++; \
 130  133          (lfp)->lf_writers++; \
 131  134  }
 132  135  
 133  136  #define LOG_FILE_UNLOCK_FROM_WRITE(lfp) { \
 134  137          (lfp)->lf_writers--; \
 135  138          if ((lfp)->lf_writers == 0 && ((lfp)->lf_flags & L_WAITING)) { \
 136  139                  (lfp)->lf_flags &= ~L_WAITING; \
 137  140                  cv_broadcast(&(lfp)->lf_cv_waiters); \
 138  141          } \
 139  142          mutex_exit(&(lfp)->lf_lock); \
 140  143          log_file_rele(lfp); \
 141  144  }
 142  145  
 143  146  int rfsl_log_buffer = 0;
 144  147  static int rfsl_log_file = 0;
 145  148  
 146  149  /* This array is used for memory allocation of record encoding spaces */
 147  150  static struct {
 148  151          int     size;
 149  152          struct kmem_cache *mem_cache;
 150  153          char    *cache_name;
 151  154  } nfslog_mem_alloc[] = {
 152  155  #define SMALL_INDX 0
 153  156          { NFSLOG_SMALL_RECORD_SIZE - sizeof (struct lr_alloc),
 154  157          NULL, NFSLOG_SMALL_REC_NAME },
 155  158  #define MEDIUM_INDX 1
 156  159          { NFSLOG_MEDIUM_RECORD_SIZE - sizeof (struct lr_alloc),
 157  160          NULL, NFSLOG_MEDIUM_REC_NAME },
 158  161  #define LARGE_INDX 2
 159  162          { NFSLOG_LARGE_RECORD_SIZE - sizeof (struct lr_alloc),
 160  163          NULL, NFSLOG_LARGE_REC_NAME },
 161  164          { (-1), NULL }
 162  165  };
 163  166  
 164  167  /* Used to calculate the 'real' allocation size */
 165  168  #define ALLOC_SIZE(index) \
 166  169          (nfslog_mem_alloc[index].size + sizeof (struct lr_alloc))
 167  170  
 168  171  /*
 169  172   * Initialize logging data buffer cache
 170  173   */
 171  174  void
 172  175  nfslog_init()
 173  176  {
 174  177          int indx;
 175  178  
 176  179          rw_init(&nfslog_buffer_list_lock, NULL, RW_DEFAULT, NULL);
 177  180  
 178  181          /*
 179  182           * Initialize the kmem caches for encoding
 180  183           */
 181  184          for (indx = 0; nfslog_mem_alloc[indx].size != (-1); indx++) {
 182  185                  nfslog_mem_alloc[indx].mem_cache =
 183  186                      kmem_cache_create(nfslog_mem_alloc[indx].cache_name,
 184  187                      ALLOC_SIZE(indx), 0, NULL, NULL, NULL, NULL, NULL, 0);
 185  188          }
 186  189  }
 187  190  
 188  191  /*
 189  192   * Sets up the necessary log file and related buffers to enable logging
 190  193   * on the given export point.
 191  194   * Returns 0 on success, non-zero on failure.
 192  195   */
 193  196  int
 194  197  nfslog_setup(struct exportinfo *exi)
 195  198  {
 196  199          struct exportdata *kex;
 197  200          struct log_buffer *lbp;
 198  201          struct log_buffer *nlbp;
 199  202  
 200  203          kex = &exi->exi_export;
 201  204          ASSERT(kex->ex_flags & EX_LOG);
 202  205  
 203  206          /*
 204  207           * Logging is enabled for the new export point, check
 205  208           * the existing log_buffer structures to see if the
 206  209           * desired buffer has already been opened. If so, point
 207  210           * the new exportinfo's exi_logbuffer to the existing
 208  211           * one.
 209  212           */
 210  213          rw_enter(&nfslog_buffer_list_lock, RW_READER);
 211  214          for (lbp = nfslog_buffer_list; lbp != NULL; lbp = lbp->lb_next) {
 212  215                  LOGGING_DPRINT((10,
 213  216                      "searching for buffer... found log_buffer '%s'\n",
 214  217                      lbp->lb_path));
 215  218                  if (strcmp(lbp->lb_path, kex->ex_log_buffer) == 0) {
 216  219                          /* Found our match. Ref it and return */
 217  220                          LOG_BUFFER_HOLD(lbp);
 218  221                          exi->exi_logbuffer = lbp;
 219  222                          LOGGING_DPRINT((10,  "\tfound log_buffer for '%s'\n",
 220  223                              kex->ex_log_buffer));
 221  224                          rw_exit(&nfslog_buffer_list_lock);
 222  225                          return (0);
 223  226                  }
 224  227          }
 225  228          rw_exit(&nfslog_buffer_list_lock);
 226  229  
 227  230          /*
 228  231           * New buffer needed, allocate it.
 229  232           * The buffer list lock has been dropped so we will need to search
 230  233           * the list again to ensure that another thread has not added
 231  234           * a matching buffer.
 232  235           */
 233  236          if ((nlbp = log_buffer_create(kex->ex_log_buffer)) == NULL) {
 234  237                  /*
 235  238                   * Failed the buffer creation for some reason so we
 236  239                   * will need to return.
 237  240                   */
 238  241                  return (EIO);
 239  242          }
 240  243  
 241  244          rw_enter(&nfslog_buffer_list_lock, RW_WRITER);
 242  245          for (lbp = nfslog_buffer_list; lbp != NULL;
 243  246              lbp = lbp->lb_next) {
 244  247                  if (strcmp(lbp->lb_path, kex->ex_log_buffer) == 0) {
 245  248                                  /*
 246  249                                   * A log_buffer already exists for the
 247  250                                   * indicated buffer, use it instead.
 248  251                                   */
 249  252                          LOG_BUFFER_HOLD(lbp);
 250  253  
 251  254                          exi->exi_logbuffer = lbp;
 252  255  
 253  256                          LOGGING_DPRINT((10, "found log_buffer for '%s' "
 254  257                              "after allocation\n", kex->ex_log_buffer));
 255  258  
 256  259                          rw_exit(&nfslog_buffer_list_lock);
 257  260  
 258  261                          log_buffer_rele(nlbp);
 259  262  
 260  263                          return (0);
 261  264                  }
 262  265          }
 263  266          /*
 264  267           * Didn't find an existing log_buffer for this buffer,
 265  268           * use the the newly created one, and add to list.  We
 266  269           * increment the reference count because the node is
 267  270           * entered into the global list.
 268  271           */
 269  272          LOGGING_DPRINT((10, "exportfs: adding nlbp=%p to list\n",
 270  273              (void *)nlbp));
 271  274  
 272  275          nlbp->lb_next = nfslog_buffer_list;
 273  276          nfslog_buffer_list = nlbp;
 274  277  
 275  278          LOG_BUFFER_HOLD(nlbp);  /* hold is for export entry */
 276  279          exi->exi_logbuffer = nlbp;
 277  280  
 278  281          rw_exit(&nfslog_buffer_list_lock);
 279  282  
 280  283          return (0);
 281  284  }
 282  285  
 283  286  /*
 284  287   * Disables logging for the given export point.
 285  288   */
 286  289  void
 287  290  nfslog_disable(struct exportinfo *exi)
 288  291  {
 289  292          log_buffer_rele(exi->exi_logbuffer);
 290  293  }
 291  294  
 292  295  /*
 293  296   * Creates the corresponding log_buffer and log_file structures
 294  297   * for the the buffer named 'name'.
 295  298   * Returns a pointer to the log_buffer structure with reference one.
 296  299   */
 297  300  static struct log_buffer *
 298  301  log_buffer_create(caddr_t name)
 299  302  {
 300  303          struct log_buffer *buffer;
 301  304          struct log_file *logfile;
 302  305          int namelen = strlen(name);
 303  306  
 304  307          LOGGING_DPRINT((10,  "log_buffer_create: %s\n", name));
 305  308          if (log_file_create(name, &logfile))
 306  309                  return (NULL);
 307  310  
 308  311          buffer = (struct log_buffer *)kmem_alloc(sizeof (*buffer), KM_SLEEP);
 309  312          buffer->lb_refcnt = 1;
 310  313          buffer->lb_rec_id = 0;
 311  314          buffer->lb_path = (caddr_t)kmem_alloc(namelen + 1, KM_SLEEP);
 312  315          bcopy(name, buffer->lb_path, namelen + 1);
 313  316          buffer->lb_logfile = logfile;
 314  317          buffer->lb_records = NULL;
 315  318          buffer->lb_num_recs = 0;
 316  319          buffer->lb_size_queued = 0;
 317  320          mutex_init(&buffer->lb_lock, NULL, MUTEX_DEFAULT, NULL);
 318  321          rfsl_log_buffer++;
 319  322  
 320  323          return (buffer);
 321  324  }
 322  325  
 323  326  /*
 324  327   * Release a log_buffer structure
 325  328   */
 326  329  static void
 327  330  log_buffer_rele(struct log_buffer *lbp)
 328  331  {
 329  332          int len;
 330  333  
 331  334          mutex_enter(&lbp->lb_lock);
 332  335          if (--lbp->lb_refcnt > 1) {
 333  336                  mutex_exit(&lbp->lb_lock);
 334  337                  return;
 335  338          }
 336  339  
 337  340          if (lbp->lb_refcnt < 0) {
 338  341                  panic("log_rele: log_buffer refcnt < 0");
 339  342                  /*NOTREACHED*/
 340  343          }
 341  344  
 342  345          /*
 343  346           * Need to drop the lb_lock before acquiring the
 344  347           * nfslog_buffer_list_lock. To avoid double free we need
 345  348           * to hold an additional reference to the log buffer.
 346  349           * This will ensure that no two threads will simultaneously
 347  350           * be trying to free the same log buffer.
 348  351           */
 349  352  
 350  353          if (lbp->lb_refcnt == 1) {
 351  354  
 352  355                  /*
 353  356                   * If the ref count is 1, then the last
 354  357                   * unshare/reference has been given up and we need to
 355  358                   * clean up the buffer and remove it from the buffer
 356  359                   * list.
 357  360                   */
 358  361                  LOGGING_DPRINT((10,
 359  362                      "log_buffer_rele lbp=%p disconnecting\n", (void *)lbp));
 360  363                  /*
 361  364                   * Hold additional reference before dropping the lb_lock
 362  365                   */
 363  366  
 364  367                  lbp->lb_refcnt++;
 365  368                  mutex_exit(&lbp->lb_lock);
 366  369  
 367  370                  /*
 368  371                   * Make sure that all of the buffered records are written.
 369  372                   * Don't bother checking the write return value since there
 370  373                   * isn't much we can do at this point.
 371  374                   */
 372  375                  (void) nfslog_records_flush_to_disk(lbp);
 373  376  
 374  377                  rw_enter(&nfslog_buffer_list_lock, RW_WRITER);
 375  378                  mutex_enter(&lbp->lb_lock);
 376  379                  /*
 377  380                   * Drop the reference count held above.
 378  381                   * If the ref count is still > 1 then someone has
 379  382                   * stepped in to use this log buffer.  unlock and return.
 380  383                   */
 381  384                  if (--lbp->lb_refcnt > 1) {
 382  385                          mutex_exit(&lbp->lb_lock);
 383  386                          rw_exit(&nfslog_buffer_list_lock);
 384  387                          return;
 385  388                  }
 386  389  
 387  390                  if (lbp == nfslog_buffer_list) {
 388  391                          nfslog_buffer_list = lbp->lb_next;
 389  392                  } else {
 390  393                          struct log_buffer *tlbp;
 391  394  
 392  395                          /* Drop the log_buffer from the master list */
 393  396                          for (tlbp = nfslog_buffer_list; tlbp->lb_next != NULL;
 394  397                              tlbp = tlbp->lb_next) {
 395  398                                  if (tlbp->lb_next == lbp) {
 396  399                                          tlbp->lb_next = lbp->lb_next;
 397  400                                          break;
 398  401                                  }
 399  402                          }
 400  403                  }
 401  404  
 402  405                  mutex_exit(&lbp->lb_lock);
 403  406                  rw_exit(&nfslog_buffer_list_lock);
 404  407          }
 405  408          /*
 406  409           * ref count zero; finish clean up.
 407  410           */
 408  411          LOGGING_DPRINT((10, "log_buffer_rele lbp=%p freeing\n", (void *)lbp));
 409  412  
 410  413          log_file_rele(lbp->lb_logfile);
 411  414          len = strlen(lbp->lb_path) + 1;
 412  415          kmem_free(lbp->lb_path, len);
 413  416          kmem_free(lbp, sizeof (*lbp));
 414  417          rfsl_log_buffer--;
 415  418  }
 416  419  
 417  420  /*
 418  421   * Creates the corresponding log_file structure for the buffer
 419  422   * named 'log_file_name'.
 420  423   * 'log_file_name' is created by concatenating 'origname' and LOG_INPROG_STRING.
 421  424   * 'logfile' is set to be the log_file structure with reference one.
 422  425   */
 423  426  static int
 424  427  log_file_create(caddr_t origname, struct log_file **lfpp)
 425  428  {
 426  429          vnode_t *vp = NULL;
 427  430          char *name;
 428  431          int namelen;
 429  432          int error;
 430  433          struct log_file *logfile = NULL;
 431  434          vattr_t va;
 432  435          caddr_t loghdr = NULL;
 433  436          size_t loghdr_len = 0;
 434  437          size_t loghdr_free = 0;
 435  438  
 436  439          namelen = strlen(origname) + strlen(LOG_INPROG_STRING);
 437  440          name = (caddr_t)kmem_alloc(namelen + 1, KM_SLEEP);
 438  441          (void) sprintf(name, "%s%s", origname, LOG_INPROG_STRING);
 439  442  
 440  443          LOGGING_DPRINT((3, "log_file_create: %s\n", name));
 441  444          if (error = vn_open(name, UIO_SYSSPACE, FCREAT|FWRITE|FOFFMAX,
 442  445              LOG_MODE, &vp, CRCREAT, 0)) {
 443  446                  nfs_cmn_err(error, CE_WARN,
 444  447                      "log_file_create: Can not open %s - error %m", name);
 445  448                  goto out;
 446  449          }
 447  450          LOGGING_DPRINT((3, "log_file_create: %s vp=%p v_count=%d\n",
 448  451              name, (void *)vp, vp->v_count));
 449  452  
 450  453          logfile = (struct log_file *)kmem_zalloc(sizeof (*logfile), KM_SLEEP);
 451  454          logfile->lf_path = name;
 452  455          /*
 453  456           * No need to bump the vnode reference count since it is set
 454  457           * to one by vn_open().
 455  458           */
 456  459          logfile->lf_vp = vp;
 457  460          logfile->lf_refcnt = 1;
 458  461          mutex_init(&logfile->lf_lock, NULL, MUTEX_DEFAULT, NULL);
 459  462          rfsl_log_file++;
 460  463  
 461  464          va.va_mask = AT_SIZE;
 462  465          error = VOP_GETATTR(vp, &va, 0, CRED(), NULL);
 463  466          if (error) {
 464  467                  nfs_cmn_err(error, CE_WARN,
 465  468                      "log_file_create: Can not stat %s - error = %m",  name);
 466  469                  goto out;
 467  470          }
 468  471  
 469  472          if (va.va_size == 0) {
 470  473                  struct lr_alloc lr;
 471  474  
 472  475                  /*
 473  476                   * Write Header.
 474  477                   */
 475  478                  create_buffer_header(&loghdr, &loghdr_len, &loghdr_free);
 476  479                  /*
 477  480                   * Dummy up a lr_alloc struct for the write
 478  481                   */
 479  482                  lr.next = lr.prev = &lr;
 480  483                  lr.lr_flags = 0;
 481  484                  lr.log_record = loghdr;
 482  485                  lr.size = loghdr_len;
 483  486                  lr.alloc_cache = NULL;
 484  487                  lr.exi = NULL;
 485  488                  lr.lb = NULL;
 486  489  
 487  490                  mutex_enter(&logfile->lf_lock);
 488  491  
 489  492                  error = nfslog_write_logrecords(logfile, &lr, 1);
 490  493  
 491  494                  mutex_exit(&logfile->lf_lock);
 492  495  
 493  496                  if (error != 0) {
 494  497                          nfs_cmn_err(error, CE_WARN,
 495  498                              "log_file_create: Can not write header "
 496  499                              "on %s - error = %m", name);
 497  500                          goto out;
 498  501                  }
 499  502          }
 500  503          *lfpp = logfile;
 501  504  
 502  505          if (loghdr != NULL)
 503  506                  kmem_free(loghdr, loghdr_free);
 504  507  
 505  508          return (0);
 506  509  
 507  510  out:
 508  511          if (vp != NULL) {
 509  512                  int error1;
 510  513                  error1 = VOP_CLOSE(vp, FCREAT|FWRITE|FOFFMAX, 1, (offset_t)0,
 511  514                      CRED(), NULL);
 512  515                  if (error1) {
 513  516                          nfs_cmn_err(error1, CE_WARN,
 514  517                              "log_file_create: Can not close %s - "
 515  518                              "error = %m", name);
 516  519                  }
 517  520                  VN_RELE(vp);
 518  521          }
 519  522  
 520  523          kmem_free(name, namelen + 1);
 521  524          if (logfile != NULL) {
 522  525                  mutex_destroy(&logfile->lf_lock);
 523  526                  kmem_free(logfile, sizeof (*logfile));
 524  527                  rfsl_log_file--;
 525  528          }
 526  529          if (loghdr != NULL)
 527  530                  kmem_free(loghdr, loghdr_free);
 528  531  
 529  532          return (error);
 530  533  }
 531  534  
 532  535  /*
 533  536   * Release a log_file structure
 534  537   */
 535  538  static void
 536  539  log_file_rele(struct log_file *lfp)
 537  540  {
 538  541          int len;
 539  542          int error;
 540  543  
 541  544          mutex_enter(&lfp->lf_lock);
 542  545          if (--lfp->lf_refcnt > 0) {
 543  546                  LOGGING_DPRINT((10,
 544  547                      "log_file_rele lfp=%p decremented refcnt to %d\n",
 545  548                      (void *)lfp, lfp->lf_refcnt));
 546  549                  mutex_exit(&lfp->lf_lock);
 547  550                  return;
 548  551          }
 549  552          if (lfp->lf_refcnt < 0) {
 550  553                  panic("log_file_rele: log_file refcnt < 0");
 551  554                  /*NOTREACHED*/
 552  555          }
 553  556  
 554  557          LOGGING_DPRINT((10, "log_file_rele lfp=%p freeing node\n",
 555  558              (void *)lfp));
 556  559  
 557  560          lfp->lf_flags &= ~(L_PRINTED | L_ERROR);
 558  561  
 559  562          ASSERT(lfp->lf_flags == 0);
 560  563          ASSERT(lfp->lf_writers == 0);
 561  564  
 562  565          if (error = VOP_CLOSE(lfp->lf_vp, FCREAT|FWRITE|FOFFMAX, 1, (offset_t)0,
 563  566              CRED(), NULL)) {
 564  567                  nfs_cmn_err(error, CE_WARN,
 565  568                      "NFS: Could not close log buffer %s - error = %m",
 566  569                      lfp->lf_path);
 567  570  #ifdef DEBUG
 568  571          } else {
 569  572                  LOGGING_DPRINT((3,
 570  573                      "log_file_rele: %s has been closed vp=%p v_count=%d\n",
 571  574                      lfp->lf_path, (void *)lfp->lf_vp, lfp->lf_vp->v_count));
 572  575  #endif
 573  576          }
 574  577          VN_RELE(lfp->lf_vp);
 575  578  
 576  579          len = strlen(lfp->lf_path) + 1;
 577  580          kmem_free(lfp->lf_path, len);
 578  581          kmem_free(lfp, sizeof (*lfp));
 579  582          rfsl_log_file--;
 580  583  }
 581  584  
 582  585  /*
 583  586   * Allocates a record of the size specified.
 584  587   * 'exi' identifies the exportinfo structure being logged.
 585  588   * 'size' indicates how much memory should be allocated
 586  589   * 'cookie' is used to store an opaque value for the caller for later use
 587  590   * 'flags' currently ignored.
  
    | 
      ↓ open down ↓ | 
    530 lines elided | 
    
      ↑ open up ↑ | 
  
 588  591   *
 589  592   * Returns a pointer to the beginning of the allocated memory.
 590  593   * 'cookie' is a pointer to the 'lr_alloc' struct; this will be used
 591  594   * to keep track of the encoded record and contains all the info
 592  595   * for enqueuing the record on the log buffer for later writing.
 593  596   *
 594  597   * nfslog_record_put() must be used to 'free' this record or allocation.
 595  598   */
 596  599  /* ARGSUSED */
 597  600  void *
 598      -nfslog_record_alloc(
 599      -        struct exportinfo *exi,
 600      -        int alloc_indx,
 601      -        void **cookie,
 602      -        int flags)
      601 +nfslog_record_alloc(struct exportinfo *exi, int alloc_indx, void **cookie,
      602 +    int flags)
 603  603  {
 604  604          struct lr_alloc *lrp;
 605  605  
 606  606          lrp = (struct lr_alloc *)
 607  607              kmem_cache_alloc(nfslog_mem_alloc[alloc_indx].mem_cache,
 608  608              KM_NOSLEEP);
 609  609  
 610  610          if (lrp == NULL) {
 611  611                  *cookie = NULL;
 612  612                  return (NULL);
 613  613          }
 614  614  
 615  615          lrp->next = lrp;
 616  616          lrp->prev = lrp;
 617  617          lrp->lr_flags = 0;
 618  618  
 619  619          lrp->log_record = (caddr_t)((uintptr_t)lrp +
 620  620              (uintptr_t)sizeof (struct lr_alloc));
 621  621          lrp->size = nfslog_mem_alloc[alloc_indx].size;
 622  622          lrp->alloc_cache = nfslog_mem_alloc[alloc_indx].mem_cache;
 623  623          lrp->exi = exi;
 624  624  
 625  625          if (exi->exi_export.ex_flags & EX_LOG) {
 626  626                  LOG_BUFFER_HOLD(exi->exi_logbuffer);
 627  627                  lrp->lb = exi->exi_logbuffer;
 628  628          } else {
 629  629                  lrp->lb = NULL;
 630  630          }
 631  631  
 632  632          *cookie = (void *)lrp;
 633  633  
 634  634          LOGGING_DPRINT((3,
 635  635              "nfslog_record_alloc(log_buffer=%p mem=%p size=%lu)\n",
 636  636              (void *)exi->exi_logbuffer, (void *)lrp->log_record, lrp->size));
 637  637          return (lrp->log_record);
 638  638  }
 639  639  
 640  640  /*
 641  641   * After the above nfslog_record_alloc() has been called and a record
 642  642   * encoded into the buffer that was returned, this function is called
 643  643   * to handle appropriate disposition of the newly created record.
 644  644   * The cookie value is the one that was returned from nfslog_record_alloc().
  
    | 
      ↓ open down ↓ | 
    32 lines elided | 
    
      ↑ open up ↑ | 
  
 645  645   * Size is the actual size of the record that was encoded.  This is
 646  646   * passed in because the size used for the alloc was just an approximation.
 647  647   * The sync parameter is used to tell us if we need to force this record
 648  648   * to disk and if not it will be queued for later writing.
 649  649   *
 650  650   * Note that if the size parameter has a value of 0, then the record is
 651  651   * not written to the log and the associated data structures are released.
 652  652   */
 653  653  void
 654  654  nfslog_record_put(void *cookie, size_t size, bool_t sync,
 655      -        unsigned int which_buffers)
      655 +    unsigned int which_buffers)
 656  656  {
 657  657          struct lr_alloc *lrp = (struct lr_alloc *)cookie;
 658  658          struct log_buffer *lbp = lrp->lb;
 659  659  
 660  660          /*
 661  661           * If the caller has nothing to write or if there is
 662  662           * an apparent error, rele the buffer and free.
 663  663           */
 664  664          if (size == 0 || size > lrp->size) {
 665  665                  nfslog_free_logrecords(lrp);
 666  666                  return;
 667  667          }
 668  668  
 669  669          /*
 670  670           * Reset the size to what actually needs to be written
 671  671           * This is used later on when the iovec is built for
 672  672           * writing the records to the log file.
 673  673           */
 674  674          lrp->size = size;
 675  675  
 676  676          /* append to all if public exi */
 677  677          if (which_buffers == NFSLOG_ALL_BUFFERS) {
 678  678                  (void) nfslog_record_append2all(lrp);
 679  679                  nfslog_free_logrecords(lrp);
 680  680                  return;
 681  681          }
 682  682  
 683  683          /* Insert the record on the list to be written */
 684  684          mutex_enter(&lbp->lb_lock);
 685  685          if (lbp->lb_records == NULL) {
 686  686                  lbp->lb_records = (caddr_t)lrp;
 687  687                  lbp->lb_num_recs = 1;
 688  688                  lbp->lb_size_queued = lrp->size;
 689  689          } else {
 690  690                  insque(lrp, ((struct lr_alloc *)lbp->lb_records)->prev);
 691  691                  lbp->lb_num_recs++;
 692  692                  lbp->lb_size_queued += lrp->size;
 693  693          }
 694  694  
 695  695          /*
 696  696           * Determine if the queue for this log buffer should be flushed.
 697  697           * This is done by either the number of records queued, the total
 698  698           * size of all records queued or by the request of the caller
 699  699           * via the sync parameter.
 700  700           */
 701  701          if (lbp->lb_size_queued >= nfslog_num_bytes_to_write ||
 702  702              lbp->lb_num_recs > nfslog_num_records_to_write || sync == TRUE) {
 703  703                  mutex_exit(&lbp->lb_lock);
 704  704                  (void) nfslog_records_flush_to_disk(lbp);
 705  705          } else {
 706  706                  mutex_exit(&lbp->lb_lock);
 707  707          }
 708  708  
 709  709  }
 710  710  
 711  711  /*
 712  712   * Examine the log_buffer struct to see if there are queue log records
 713  713   * that need to be written to disk.  If some exist, pull them off of
 714  714   * the log buffer and write them to the log file.
 715  715   */
 716  716  static int
 717  717  nfslog_records_flush_to_disk(struct log_buffer *lbp)
 718  718  {
 719  719  
 720  720          mutex_enter(&lbp->lb_lock);
 721  721  
 722  722          if (lbp->lb_records == NULL) {
 723  723                  mutex_exit(&lbp->lb_lock);
 724  724                  return (0);
 725  725          }
 726  726          return  (nfslog_records_flush_to_disk_nolock(lbp));
 727  727  }
 728  728  
 729  729  /*
 730  730   * Function requires that the caller holds lb_lock.
 731  731   * Function flushes any records in the log buffer to the disk.
 732  732   * Function drops the lb_lock on return.
 733  733   */
 734  734  
 735  735  static int
 736  736  nfslog_records_flush_to_disk_nolock(struct log_buffer *lbp)
 737  737  {
 738  738          struct log_file *lfp = NULL;
 739  739          struct lr_alloc *lrp_writers;
 740  740          int num_recs;
 741  741          int error = 0;
 742  742  
 743  743          ASSERT(MUTEX_HELD(&lbp->lb_lock));
 744  744  
 745  745          lfp = lbp->lb_logfile;
 746  746  
 747  747          LOG_FILE_LOCK_TO_WRITE(lfp);
 748  748          ASSERT(lbp->lb_records != NULL);
 749  749  
 750  750          lrp_writers = (struct lr_alloc *)lbp->lb_records;
 751  751          lbp->lb_records = NULL;
 752  752          num_recs = lbp->lb_num_recs;
 753  753          lbp->lb_num_recs = 0;
 754  754          lbp->lb_size_queued = 0;
 755  755          mutex_exit(&lbp->lb_lock);
 756  756          error = nfslog_write_logrecords(lfp, lrp_writers, num_recs);
 757  757  
 758  758          LOG_FILE_UNLOCK_FROM_WRITE(lfp);
 759  759  
 760  760          nfslog_free_logrecords(lrp_writers);
  
    | 
      ↓ open down ↓ | 
    95 lines elided | 
    
      ↑ open up ↑ | 
  
 761  761          return (error);
 762  762  }
 763  763  
 764  764  
 765  765  /*
 766  766   * Take care of writing the provided log record(s) to the log file.
 767  767   * We group the log records with an iovec and use VOP_WRITE to append
 768  768   * them to the end of the log file.
 769  769   */
 770  770  static int
 771      -nfslog_write_logrecords(struct log_file *lfp,
 772      -        struct lr_alloc *lrp_writers, int num_recs)
      771 +nfslog_write_logrecords(struct log_file *lfp, struct lr_alloc *lrp_writers,
      772 +    int num_recs)
 773  773  {
 774  774          struct uio uio;
 775  775          struct iovec *iovp;
 776  776          int size_iovecs;
 777  777          vnode_t *vp;
 778  778          struct vattr va;
 779  779          struct lr_alloc *lrp;
 780  780          int i;
 781  781          ssize_t len;
 782  782          int ioflag = FAPPEND;
 783  783          int error = 0;
 784  784  
 785  785          ASSERT(MUTEX_HELD(&lfp->lf_lock));
 786  786  
 787  787          vp = lfp->lf_vp;
 788  788  
 789  789          size_iovecs = sizeof (struct iovec) * num_recs;
 790  790          iovp = (struct iovec *)kmem_alloc(size_iovecs, KM_NOSLEEP);
 791  791  
 792  792          if (iovp == NULL) {
 793  793                  error = ENOMEM;
 794  794                  goto out;
 795  795          }
 796  796  
 797  797          /* Build the iovec based on the list of log records */
 798  798          i = 0;
 799  799          len = 0;
 800  800          lrp = lrp_writers;
 801  801          do {
 802  802                  iovp[i].iov_base = lrp->log_record;
 803  803                  iovp[i].iov_len = lrp->size;
 804  804                  len += lrp->size;
 805  805                  lrp = lrp->next;
 806  806                  i++;
 807  807          } while (lrp != lrp_writers);
 808  808  
 809  809          ASSERT(i == num_recs);
 810  810  
 811  811          uio.uio_iov = iovp;
 812  812          uio.uio_iovcnt = num_recs;
 813  813          uio.uio_loffset = 0;
 814  814          uio.uio_segflg = (short)UIO_SYSSPACE;
 815  815          uio.uio_resid = len;
 816  816          uio.uio_llimit = (rlim64_t)MAXOFFSET_T;
 817  817          uio.uio_fmode = FWRITE;
 818  818          uio.uio_extflg = UIO_COPY_DEFAULT;
 819  819  
 820  820          /*
 821  821           * Save the size. If the write fails, reset the size to avoid
 822  822           * corrupted log buffer files.
 823  823           */
 824  824          va.va_mask = AT_SIZE;
 825  825  
 826  826          (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);  /* UIO_WRITE */
 827  827          if ((error = VOP_GETATTR(vp, &va, 0, CRED(), NULL)) == 0) {
 828  828                  if ((len + va.va_size) < (MAXOFF32_T)) {
 829  829                          error = VOP_WRITE(vp, &uio, ioflag, CRED(), NULL);
 830  830                          VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
 831  831                          if (uio.uio_resid)
 832  832                                  error = ENOSPC;
 833  833                          if (error)
 834  834                                  (void) VOP_SETATTR(vp, &va, 0, CRED(), NULL);
 835  835                  } else {
 836  836                          VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
 837  837                          if (!(lfp->lf_flags & L_PRINTED)) {
 838  838                                  cmn_err(CE_WARN,
 839  839                                      "NFS Logging: buffer file %s exceeds 2GB; "
 840  840                                      "stopped writing buffer \n", lfp->lf_path);
 841  841                          }
 842  842                          error = ENOSPC;
 843  843                  }
 844  844          } else {
 845  845                  VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
 846  846          }
 847  847  
 848  848          kmem_free(iovp, size_iovecs);
 849  849  
 850  850  out:
 851  851          if (error) {
 852  852                  if (!(lfp->lf_flags & L_PRINTED)) {
 853  853                          nfs_cmn_err(error, CE_WARN,
 854  854                              "NFS Logging disabled for buffer %s - "
 855  855                              "write error = %m\n", lfp->lf_path);
 856  856                          lfp->lf_flags |= L_PRINTED;
 857  857                  }
 858  858          } else if (lfp->lf_flags & (L_ERROR | L_PRINTED)) {
 859  859                  lfp->lf_flags &= ~(L_ERROR | L_PRINTED);
 860  860                  cmn_err(CE_WARN,
 861  861                      "NFS Logging re-enabled for buffer %s\n", lfp->lf_path);
 862  862          }
 863  863  
 864  864          return (error);
 865  865  }
 866  866  
 867  867  static void
 868  868  nfslog_free_logrecords(struct lr_alloc *lrp_writers)
 869  869  {
 870  870          struct lr_alloc *lrp = lrp_writers;
 871  871          struct lr_alloc *lrp_free;
 872  872  
 873  873          do {
 874  874                  lrp_free = lrp;
 875  875  
 876  876                  lrp = lrp->next;
 877  877  
 878  878                  /*
 879  879                   * Check to see if we are supposed to free this structure
 880  880                   * and relese the log_buffer ref count.
 881  881                   * It may be the case that the caller does not want this
 882  882                   * structure and its record contents freed just yet.
 883  883                   */
 884  884                  if ((lrp_free->lr_flags & LR_ALLOC_NOFREE) == 0) {
 885  885                          if (lrp_free->lb != NULL)
 886  886                                  log_buffer_rele(lrp_free->lb);
 887  887                          if (lrp_free->alloc_cache) /* double check */
 888  888                                  kmem_cache_free(lrp_free->alloc_cache,
 889  889                                      (void *)lrp_free);
 890  890                  } else {
 891  891                          /*
 892  892                           * after being pulled from the list the
 893  893                           * pointers need to be reinitialized.
 894  894                           */
 895  895                          lrp_free->next = lrp_free;
 896  896                          lrp_free->prev = lrp_free;
 897  897                  }
 898  898  
 899  899          } while (lrp != lrp_writers);
 900  900  }
 901  901  
 902  902  /*
 903  903   * Rename lbp->lb_logfile to reflect the true name requested by 'share'
 904  904   */
 905  905  static int
 906  906  nfslog_logbuffer_rename(struct log_buffer *lbp)
 907  907  {
 908  908          struct log_file *lf;
 909  909          int error;
 910  910          struct log_file *logfile;
 911  911  
 912  912          /*
 913  913           * Try our best to get the cache records into the log file
 914  914           * before the rename occurs.
 915  915           */
 916  916          (void) nfslog_records_flush_to_disk(lbp);
 917  917  
 918  918          /*
 919  919           * Hold lb_lock before retrieving
 920  920           * lb_logfile.
 921  921           * Hold a reference to the
 922  922           * "lf" structure. this is
 923  923           * same as LOG_FILE_HOLD()
 924  924           */
 925  925          mutex_enter(&(lbp)->lb_lock);
 926  926          lf = lbp->lb_logfile;
 927  927          mutex_enter(&(lf)->lf_lock);
 928  928          mutex_exit(&(lbp)->lb_lock);
 929  929          lf->lf_refcnt++;
 930  930          mutex_exit(&(lf)->lf_lock);
 931  931  
 932  932          LOGGING_DPRINT((10, "nfslog_logbuffer_rename: renaming %s to %s\n",
 933  933              lf->lf_path, lbp->lb_path));
 934  934  
 935  935          /*
 936  936           * rename the current buffer to what the daemon expects
 937  937           */
 938  938          if (error = nfslog_logfile_rename(lf->lf_path, lbp->lb_path))
 939  939                  goto out;
 940  940  
 941  941          /*
 942  942           * Create a new working buffer file and have all new data sent there.
 943  943           */
 944  944          if (error = log_file_create(lbp->lb_path, &logfile)) {
 945  945                  /* Attempt to rename to original */
 946  946                  (void) nfslog_logfile_rename(lbp->lb_path, lf->lf_path);
 947  947                  goto out;
 948  948          }
 949  949  
 950  950          /*
 951  951           * Hold the lb_lock here, this will make
 952  952           * all the threads trying to access lb->logfile block
 953  953           * and get a new logfile structure instead of old one.
 954  954           */
 955  955          mutex_enter(&(lbp)->lb_lock);
 956  956          lbp->lb_logfile = logfile;
 957  957          mutex_exit(&(lbp)->lb_lock);
 958  958  
 959  959          LOG_FILE_RELE(lf);      /* release log_buffer's reference */
 960  960  
 961  961          /*
 962  962           * Wait for log_file to be in a quiescent state before we
 963  963           * return to our caller to let it proceed with the reading of
 964  964           * this file.
 965  965           */
 966  966          nfslog_logfile_wait(lf);
 967  967  
 968  968  out:
 969  969          /*
 970  970           * Release our reference on "lf" in two different cases.
 971  971           * 1. Error condition, release only the reference
 972  972           *    that we held at the begining of this
 973  973           *    routine on "lf" structure.
 974  974           * 2. Fall through condition, no errors but the old
 975  975           *    logfile structure "lf" has been replaced with
 976  976           *    the new "logfile" structure, so release the
 977  977           *    reference that was part of the creation of
 978  978           *    "lf" structure to free up the resources.
 979  979           */
 980  980  
 981  981          LOG_FILE_RELE(lf);
 982  982  
 983  983          return (error);
 984  984  }
 985  985  
 986  986  /*
 987  987   * Renames the 'from' file to 'new'.
 988  988   */
 989  989  static int
 990  990  nfslog_logfile_rename(char *from, char *new)
 991  991  {
 992  992          int error;
 993  993  
 994  994          if (error = vn_rename(from, new, UIO_SYSSPACE)) {
 995  995                  cmn_err(CE_WARN,
 996  996                      "nfslog_logfile_rename: couldn't rename %s to %s\n",
 997  997                      from, new);
 998  998          }
 999  999          return (error);
1000 1000  }
1001 1001  
1002 1002  /*
1003 1003   * Wait for the log_file writers to finish before returning
1004 1004   */
1005 1005  static void
1006 1006  nfslog_logfile_wait(struct log_file *lf)
1007 1007  {
1008 1008          mutex_enter(&lf->lf_lock);
1009 1009          while (lf->lf_writers > 0) {
1010 1010                  lf->lf_flags |= L_WAITING;
1011 1011                  (void) cv_wait_sig(&lf->lf_cv_waiters, &lf->lf_lock);
1012 1012          }
1013 1013          mutex_exit(&lf->lf_lock);
1014 1014  }
1015 1015  
1016 1016  static int
1017 1017  nfslog_record_append2all(struct lr_alloc *lrp)
1018 1018  {
1019 1019          struct log_buffer *lbp, *nlbp;
1020 1020          int error, ret_error = 0;
1021 1021          int lr_flags = lrp->lr_flags;
1022 1022  
1023 1023          rw_enter(&nfslog_buffer_list_lock, RW_READER);
1024 1024          if ((lbp = nfslog_buffer_list) != NULL)
1025 1025                  LOG_BUFFER_HOLD(lbp);
1026 1026          for (nlbp = NULL; lbp != NULL; lbp = nlbp) {
1027 1027                  if ((nlbp = lbp->lb_next) != NULL) {
1028 1028                          /*
1029 1029                           * Remember next element in the list
1030 1030                           */
1031 1031                          LOG_BUFFER_HOLD(nlbp);
1032 1032                  }
1033 1033                  rw_exit(&nfslog_buffer_list_lock);
1034 1034  
1035 1035                  /*
1036 1036                   * Insert the record on the buffer's list to be written
1037 1037                   * and then flush the records to the log file.
1038 1038                   * Make sure to set the no free flag so that the
1039 1039                   * record can be used for the next write
1040 1040                   */
1041 1041                  lrp->lr_flags = LR_ALLOC_NOFREE;
1042 1042  
1043 1043                  ASSERT(lbp != NULL);
1044 1044                  mutex_enter(&lbp->lb_lock);
1045 1045                  if (lbp->lb_records == NULL) {
1046 1046                          lbp->lb_records = (caddr_t)lrp;
1047 1047                          lbp->lb_num_recs = 1;
1048 1048                          lbp->lb_size_queued = lrp->size;
1049 1049                  } else {
1050 1050                          insque(lrp, ((struct lr_alloc *)lbp->lb_records)->prev);
1051 1051                          lbp->lb_num_recs++;
1052 1052                          lbp->lb_size_queued += lrp->size;
1053 1053                  }
1054 1054  
1055 1055                  /*
1056 1056                   * Flush log records to disk.
1057 1057                   * Function is called with lb_lock held.
1058 1058                   * Function drops the lb_lock on return.
1059 1059                   */
1060 1060                  error = nfslog_records_flush_to_disk_nolock(lbp);
1061 1061  
1062 1062                  if (error) {
1063 1063                          ret_error = -1;
1064 1064                          nfs_cmn_err(error, CE_WARN,
1065 1065                              "rfsl_log_pubfh: could not append record to "
1066 1066                              "\"%s\" error = %m\n", lbp->lb_path);
1067 1067                  }
1068 1068                  log_buffer_rele(lbp);
1069 1069                  rw_enter(&nfslog_buffer_list_lock, RW_READER);
1070 1070          }
1071 1071          rw_exit(&nfslog_buffer_list_lock);
1072 1072  
1073 1073          lrp->lr_flags = lr_flags;
1074 1074  
1075 1075          return (ret_error);
1076 1076  }
1077 1077  
1078 1078  #ifdef DEBUG
1079 1079  static int logging_debug = 0;
1080 1080  
1081 1081  /*
1082 1082   * 0) no debugging
1083 1083   * 3) current test software
1084 1084   * 10) random stuff
1085 1085   */
1086 1086  void
1087 1087  nfslog_dprint(const int level, const char *fmt, ...)
1088 1088  {
1089 1089          va_list args;
1090 1090  
1091 1091          if (logging_debug == level ||
1092 1092              (logging_debug > 10 && (logging_debug - 10) >= level)) {
1093 1093                  va_start(args, fmt);
1094 1094                  (void) vprintf(fmt, args);
1095 1095                  va_end(args);
1096 1096          }
1097 1097  }
1098 1098  
1099 1099  #endif /* DEBUG */
1100 1100  
1101 1101  /*
1102 1102   * NFS Log Flush system call
1103 1103   * Caller must check privileges.
1104 1104   */
1105 1105  /* ARGSUSED */
1106 1106  int
1107 1107  nfsl_flush(struct nfsl_flush_args *args, model_t model)
1108 1108  {
1109 1109          struct flush_thread_params *tparams;
1110 1110          struct nfsl_flush_args *nfsl_args;
1111 1111          int error = 0;
1112 1112          ulong_t buffer_len;
1113 1113          STRUCT_HANDLE(nfsl_flush_args, uap);
1114 1114  
1115 1115          STRUCT_SET_HANDLE(uap, model, args);
1116 1116  
1117 1117          tparams = (struct flush_thread_params *)
1118 1118              kmem_zalloc(sizeof (*tparams), KM_SLEEP);
1119 1119  
1120 1120          nfsl_args = &tparams->tp_args;
1121 1121          nfsl_args->version =  STRUCT_FGET(uap, version);
1122 1122          if (nfsl_args->version != NFSL_FLUSH_ARGS_VERS) {
1123 1123                  cmn_err(CE_WARN, "nfsl_flush: exected version %d, got %d",
1124 1124                      NFSL_FLUSH_ARGS_VERS, nfsl_args->version);
1125 1125                  return (EIO);
1126 1126          }
1127 1127  
1128 1128          nfsl_args->directive = STRUCT_FGET(uap, directive);
1129 1129          if ((nfsl_args->directive & NFSL_ALL) == 0) {
1130 1130                  /*
1131 1131                   * Process a specific buffer
1132 1132                   */
1133 1133                  nfsl_args->buff_len = STRUCT_FGET(uap, buff_len);
1134 1134  
1135 1135                  nfsl_args->buff = (char *)
1136 1136                      kmem_alloc(nfsl_args->buff_len, KM_NOSLEEP);
1137 1137                  if (nfsl_args->buff == NULL)
1138 1138                          return (ENOMEM);
1139 1139  
1140 1140                  error = copyinstr((const char *)STRUCT_FGETP(uap, buff),
1141 1141                      nfsl_args->buff, nfsl_args->buff_len, &buffer_len);
1142 1142                  if (error)
1143 1143                          return (EFAULT);
1144 1144  
1145 1145                  if (nfsl_args->buff_len != buffer_len)
1146 1146                          return (EFAULT);
1147 1147          }
1148 1148  
1149 1149          LOGGING_DPRINT((10, "nfsl_flush: Flushing %s buffer(s)\n",
1150 1150              nfsl_args->directive & NFSL_ALL ? "all" : nfsl_args->buff));
1151 1151  
1152 1152          if (nfsl_args->directive & NFSL_SYNC) {
1153 1153                  /*
  
    | 
      ↓ open down ↓ | 
    371 lines elided | 
    
      ↑ open up ↑ | 
  
1154 1154                   * Do the work synchronously
1155 1155                   */
1156 1156                  nfslog_do_flush(tparams);
1157 1157                  error = tparams->tp_error;
1158 1158                  kmem_free(nfsl_args->buff, nfsl_args->buff_len);
1159 1159                  kmem_free(tparams, sizeof (*tparams));
1160 1160          } else {
1161 1161                  /*
1162 1162                   * Do the work asynchronously
1163 1163                   */
1164      -                (void) thread_create(NULL, 0, nfslog_do_flush,
1165      -                    tparams, 0, &p0, TS_RUN, minclsyspri);
     1164 +                (void) zthread_create(NULL, 0, nfslog_do_flush,
     1165 +                    tparams, 0, minclsyspri);
1166 1166          }
1167 1167  
1168 1168          return (error);
1169 1169  }
1170 1170  
1171 1171  /*
1172 1172   * This is where buffer flushing would occur, but there is no buffering
1173 1173   * at this time.
1174 1174   * Possibly rename the log buffer for processing.
1175 1175   * Sets tparams->ta_error equal to the value of the error that occurred,
1176 1176   * 0 otherwise.
1177 1177   * Returns ENOENT if the buffer is not found.
1178 1178   */
1179 1179  static void
1180 1180  nfslog_do_flush(struct flush_thread_params *tparams)
1181 1181  {
1182 1182          struct nfsl_flush_args *args;
1183 1183          struct log_buffer *lbp, *nlbp;
1184 1184          int error = ENOENT;
1185 1185          int found = 0;
1186 1186          char *buf_inprog;       /* name of buff in progress */
1187 1187          int buf_inprog_len;
1188 1188  
1189 1189          /*
1190 1190           * Sanity check on the arguments.
1191 1191           */
1192 1192          if (!tparams)
1193 1193                  return;
1194 1194          args = &tparams->tp_args;
1195 1195          if (!args)
1196 1196                  return;
1197 1197  
1198 1198          rw_enter(&nfslog_buffer_list_lock, RW_READER);
1199 1199          if ((lbp = nfslog_buffer_list) != NULL) {
1200 1200                  LOG_BUFFER_HOLD(lbp);
1201 1201          }
1202 1202          for (nlbp = NULL; lbp != NULL; lbp = nlbp) {
1203 1203                  if ((nlbp = lbp->lb_next) != NULL) {
1204 1204                          LOG_BUFFER_HOLD(nlbp);
1205 1205                  }
1206 1206                  rw_exit(&nfslog_buffer_list_lock);
1207 1207                  if (args->directive & NFSL_ALL) {
1208 1208                          (void) nfslog_records_flush_to_disk(lbp);
1209 1209                  } else {
1210 1210                          if ((strcmp(lbp->lb_path, args->buff) == 0) &&
1211 1211                              (args->directive & NFSL_RENAME)) {
1212 1212                                  error = nfslog_logbuffer_rename(lbp);
1213 1213                                  found++;
1214 1214                                  if (nlbp != NULL)
1215 1215                                          log_buffer_rele(nlbp);
1216 1216                                  log_buffer_rele(lbp);
1217 1217                                  break;
1218 1218                          }
1219 1219                  }
1220 1220                  log_buffer_rele(lbp);
1221 1221                  rw_enter(&nfslog_buffer_list_lock, RW_READER);
1222 1222          }
1223 1223          if (!found)
1224 1224                  rw_exit(&nfslog_buffer_list_lock);
1225 1225  
1226 1226          if (!found && ((args->directive & NFSL_ALL) == 0) &&
1227 1227              (args->directive & NFSL_RENAME)) {
1228 1228                  /*
1229 1229                   * The specified buffer is not currently in use,
1230 1230                   * simply rename the file indicated.
1231 1231                   */
1232 1232                  buf_inprog_len = strlen(args->buff) +
1233 1233                      strlen(LOG_INPROG_STRING) + 1;
1234 1234                  buf_inprog = (caddr_t)kmem_alloc(buf_inprog_len, KM_SLEEP);
1235 1235                  (void) sprintf(buf_inprog, "%s%s",
1236 1236                      args->buff, LOG_INPROG_STRING);
1237 1237  
1238 1238                  error = nfslog_logfile_rename(buf_inprog, args->buff);
1239 1239  
1240 1240                  kmem_free(buf_inprog, buf_inprog_len);
1241 1241          }
  
    | 
      ↓ open down ↓ | 
    66 lines elided | 
    
      ↑ open up ↑ | 
  
1242 1242  
1243 1243  out:
1244 1244          if ((args->directive & NFSL_SYNC) == 0) {
1245 1245                  /*
1246 1246                   * Work was performed asynchronously, the caller is
1247 1247                   * no longer waiting for us.
1248 1248                   * Free the thread arguments and exit.
1249 1249                   */
1250 1250                  kmem_free(args->buff, args->buff_len);
1251 1251                  kmem_free(tparams, sizeof (*tparams));
1252      -                thread_exit();
1253      -                /* NOTREACHED */
     1252 +                zthread_exit();
1254 1253          }
1255 1254  
1256 1255          tparams->tp_error = error;
1257 1256  }
1258 1257  
1259 1258  /*
1260 1259   * Generate buffer_header.
1261 1260   * 'loghdr' points the the buffer_header, and *reclen
1262 1261   * contains the length of the buffer.
1263 1262   */
1264 1263  static void
1265 1264  create_buffer_header(caddr_t *loghdr, size_t *reclen, size_t *freesize)
1266 1265  {
1267 1266          timestruc_t             now;
1268 1267          nfslog_buffer_header    lh;
1269 1268          XDR                     xdrs;
1270 1269          unsigned int            final_size;
1271 1270  
1272 1271  
1273 1272          /* pick some size that will hold the buffer_header */
1274 1273          *freesize = NFSLOG_SMALL_RECORD_SIZE;
1275 1274  
1276 1275          /*
1277 1276           * Fill header
1278 1277           */
1279 1278          lh.bh_length = 0;       /* don't know yet how large it will be */
1280 1279          lh.bh_version = NFSLOG_BUF_VERSION;
1281 1280          lh.bh_flags = 0;
1282 1281          lh.bh_offset = 0;
1283 1282          gethrestime(&now);
1284 1283          TIMESPEC_TO_TIMESPEC32(&lh.bh_timestamp, &now);
1285 1284  
1286 1285          /*
1287 1286           * Encode the header
1288 1287           */
1289 1288          *loghdr = (caddr_t)kmem_alloc(*freesize, KM_SLEEP);
1290 1289          xdrmem_create(&xdrs, *loghdr, *freesize, XDR_ENCODE);
1291 1290  
1292 1291          (void) xdr_nfslog_buffer_header(&xdrs, &lh);
1293 1292  
1294 1293          /*
1295 1294           * Reset with final size of the encoded data
1296 1295           */
1297 1296          final_size = xdr_getpos(&xdrs);
1298 1297          xdr_setpos(&xdrs, 0);
1299 1298          (void) xdr_u_int(&xdrs, &final_size);
1300 1299  
1301 1300          *reclen = (size_t)final_size;
1302 1301  }
1303 1302  
1304 1303  /*
1305 1304   * ****************************************************************
1306 1305   * RPC dispatch table for logging
1307 1306   * Indexed by program, version, proc
1308 1307   * Based on NFS dispatch table.
1309 1308   */
1310 1309  struct nfslog_proc_disp {
1311 1310          bool_t  (*xdrargs)();
1312 1311          bool_t  (*xdrres)();
1313 1312          bool_t  affects_transactions;   /* Operation affects transaction */
1314 1313                                          /* processing */
1315 1314  };
1316 1315  
1317 1316  struct nfslog_vers_disp {
1318 1317          int     nfslog_dis_nprocs;                      /* number of procs */
1319 1318          struct nfslog_proc_disp *nfslog_dis_proc_table; /* proc array */
1320 1319  };
1321 1320  
1322 1321  struct nfslog_prog_disp {
1323 1322          int     nfslog_dis_prog;                /* program number */
1324 1323          int     nfslog_dis_versmin;             /* Minimum version value */
1325 1324          int     nfslog_dis_nvers;               /* Number of version values */
1326 1325          struct nfslog_vers_disp *nfslog_dis_vers_table; /* versions array */
1327 1326  };
1328 1327  
1329 1328  static int rfs_log_bad = 0;     /* incremented on bad log attempts */
1330 1329  static int rfs_log_good = 0;    /* incremented on successful log attempts */
1331 1330  
1332 1331  /*
1333 1332   * Define the actions taken per prog/vers/proc:
1334 1333   *
1335 1334   * In some cases, the nl types are the same as the nfs types and a simple
1336 1335   * bcopy should suffice. Rather that define tens of identical procedures,
1337 1336   * simply define these to bcopy. Similarly this takes care of different
1338 1337   * procs that use same parameter struct.
1339 1338   */
1340 1339  
1341 1340  static struct nfslog_proc_disp nfslog_proc_v2[] = {
1342 1341          /*
1343 1342           * NFS VERSION 2
1344 1343           */
1345 1344  
1346 1345          /* RFS_NULL = 0 */
1347 1346          {xdr_void, xdr_void, FALSE},
1348 1347  
1349 1348          /* RFS_GETATTR = 1 */
1350 1349          {xdr_fhandle, xdr_nfslog_getattrres, FALSE},
1351 1350  
1352 1351          /* RFS_SETATTR = 2 */
1353 1352          {xdr_nfslog_setattrargs, xdr_nfsstat, TRUE},
1354 1353  
1355 1354          /* RFS_ROOT = 3 *** NO LONGER SUPPORTED *** */
1356 1355          {xdr_void, xdr_void, FALSE},
1357 1356  
1358 1357          /* RFS_LOOKUP = 4 */
1359 1358          {xdr_nfslog_diropargs, xdr_nfslog_diropres, TRUE},
1360 1359  
1361 1360          /* RFS_READLINK = 5 */
1362 1361          {xdr_fhandle, xdr_nfslog_rdlnres, FALSE},
1363 1362  
1364 1363          /* RFS_READ = 6 */
1365 1364          {xdr_nfslog_nfsreadargs, xdr_nfslog_rdresult, TRUE},
1366 1365  
1367 1366          /* RFS_WRITECACHE = 7 *** NO LONGER SUPPORTED *** */
1368 1367          {xdr_void, xdr_void, FALSE},
1369 1368  
1370 1369          /* RFS_WRITE = 8 */
1371 1370          {xdr_nfslog_writeargs, xdr_nfslog_writeresult, TRUE},
1372 1371  
1373 1372          /* RFS_CREATE = 9 */
1374 1373          {xdr_nfslog_createargs, xdr_nfslog_diropres, TRUE},
1375 1374  
1376 1375          /* RFS_REMOVE = 10 */
1377 1376          {xdr_nfslog_diropargs, xdr_nfsstat, TRUE},
1378 1377  
1379 1378          /* RFS_RENAME = 11 */
1380 1379          {xdr_nfslog_rnmargs, xdr_nfsstat, TRUE},
1381 1380  
1382 1381          /* RFS_LINK = 12 */
1383 1382          {xdr_nfslog_linkargs, xdr_nfsstat, TRUE},
1384 1383  
1385 1384          /* RFS_SYMLINK = 13 */
1386 1385          {xdr_nfslog_symlinkargs, xdr_nfsstat, TRUE},
1387 1386  
1388 1387          /* RFS_MKDIR = 14 */
1389 1388          {xdr_nfslog_createargs, xdr_nfslog_diropres, TRUE},
1390 1389  
1391 1390          /* RFS_RMDIR = 15 */
1392 1391          {xdr_nfslog_diropargs, xdr_nfsstat, TRUE},
1393 1392  
1394 1393          /* RFS_READDIR = 16 */
1395 1394          {xdr_nfslog_rddirargs, xdr_nfslog_rddirres, TRUE},
1396 1395  
1397 1396          /* RFS_STATFS = 17 */
1398 1397          {xdr_fhandle, xdr_nfslog_statfs, FALSE},
1399 1398  };
1400 1399  
1401 1400  
1402 1401  /*
1403 1402   * NFS VERSION 3
1404 1403   */
1405 1404  
1406 1405  static struct nfslog_proc_disp nfslog_proc_v3[] = {
1407 1406  
1408 1407          /* NFSPROC3_NULL = 0 */
1409 1408          {xdr_void, xdr_void, FALSE},
1410 1409  
1411 1410          /* NFSPROC3_GETATTR = 1 */
1412 1411          {xdr_nfslog_nfs_fh3, xdr_nfslog_GETATTR3res, FALSE},
1413 1412  
1414 1413          /* NFSPROC3_SETATTR = 2 */
1415 1414          {xdr_nfslog_SETATTR3args, xdr_nfslog_SETATTR3res, TRUE},
1416 1415  
1417 1416          /* NFSPROC3_LOOKUP = 3 */
1418 1417          {xdr_nfslog_diropargs3, xdr_nfslog_LOOKUP3res, TRUE},
1419 1418  
1420 1419          /* NFSPROC3_ACCESS = 4 */
1421 1420          {xdr_nfslog_ACCESS3args, xdr_nfslog_ACCESS3res, FALSE},
1422 1421  
1423 1422          /* NFSPROC3_READLINK = 5 */
1424 1423          {xdr_nfslog_nfs_fh3, xdr_nfslog_READLINK3res, FALSE},
1425 1424  
1426 1425          /* NFSPROC3_READ = 6 */
1427 1426          {xdr_nfslog_READ3args, xdr_nfslog_READ3res, TRUE},
1428 1427  
1429 1428          /* NFSPROC3_WRITE = 7 */
1430 1429          {xdr_nfslog_WRITE3args, xdr_nfslog_WRITE3res, TRUE},
1431 1430  
1432 1431          /* NFSPROC3_CREATE = 8 */
1433 1432          {xdr_nfslog_CREATE3args, xdr_nfslog_CREATE3res, TRUE},
1434 1433  
1435 1434          /* NFSPROC3_MKDIR = 9 */
1436 1435          {xdr_nfslog_MKDIR3args, xdr_nfslog_MKDIR3res, TRUE},
1437 1436  
1438 1437          /* NFSPROC3_SYMLINK = 10 */
1439 1438          {xdr_nfslog_SYMLINK3args, xdr_nfslog_SYMLINK3res, TRUE},
1440 1439  
1441 1440          /* NFSPROC3_MKNOD = 11 */
1442 1441          {xdr_nfslog_MKNOD3args, xdr_nfslog_MKNOD3res, TRUE},
1443 1442  
1444 1443          /* NFSPROC3_REMOVE = 12 */
1445 1444          {xdr_nfslog_REMOVE3args, xdr_nfslog_REMOVE3res, TRUE},
1446 1445  
1447 1446          /* NFSPROC3_RMDIR = 13 */
1448 1447          {xdr_nfslog_RMDIR3args, xdr_nfslog_RMDIR3res, TRUE},
1449 1448  
1450 1449          /* NFSPROC3_RENAME = 14 */
1451 1450          {xdr_nfslog_RENAME3args, xdr_nfslog_RENAME3res, TRUE},
1452 1451  
1453 1452          /* NFSPROC3_LINK = 15 */
1454 1453          {xdr_nfslog_LINK3args, xdr_nfslog_LINK3res, TRUE},
1455 1454  
1456 1455          /* NFSPROC3_READDIR = 16 */
1457 1456          {xdr_nfslog_READDIR3args, xdr_nfslog_READDIR3res, TRUE},
1458 1457  
1459 1458          /* NFSPROC3_READDIRPLUS = 17 */
1460 1459          {xdr_nfslog_READDIRPLUS3args, xdr_nfslog_READDIRPLUS3res, TRUE},
1461 1460  
1462 1461          /* NFSPROC3_FSSTAT = 18 */
1463 1462          {xdr_nfslog_FSSTAT3args, xdr_nfslog_FSSTAT3res, FALSE},
1464 1463  
1465 1464          /* NFSPROC3_FSINFO = 19 */
1466 1465          {xdr_nfslog_FSINFO3args, xdr_nfslog_FSINFO3res, FALSE},
1467 1466  
1468 1467          /* NFSPROC3_PATHCONF = 20 */
1469 1468          {xdr_nfslog_PATHCONF3args, xdr_nfslog_PATHCONF3res, FALSE},
1470 1469  
1471 1470          /* NFSPROC3_COMMIT = 21 */
1472 1471          {xdr_nfslog_COMMIT3args, xdr_nfslog_COMMIT3res, FALSE},
1473 1472  };
1474 1473  
1475 1474  static struct nfslog_proc_disp nfslog_proc_v1[] = {
1476 1475          /*
1477 1476           * NFSLOG VERSION 1
1478 1477           */
1479 1478  
1480 1479          /* NFSLOG_NULL = 0 */
1481 1480          {xdr_void, xdr_void, TRUE},
1482 1481  
1483 1482          /* NFSLOG_SHARE = 1 */
1484 1483          {xdr_nfslog_sharefsargs, xdr_nfslog_sharefsres, TRUE},
1485 1484  
1486 1485          /* NFSLOG_UNSHARE = 2 */
1487 1486          {xdr_nfslog_sharefsargs, xdr_nfslog_sharefsres, TRUE},
1488 1487  
1489 1488          /* NFSLOG_LOOKUP = 3 */
1490 1489          {xdr_nfslog_diropargs3, xdr_nfslog_LOOKUP3res, TRUE},
1491 1490  
1492 1491          /* NFSLOG_GETFH = 4 */
1493 1492          {xdr_nfslog_getfhargs, xdr_nfsstat, TRUE},
1494 1493  };
1495 1494  
1496 1495  static struct nfslog_vers_disp nfslog_vers_disptable[] = {
1497 1496          {sizeof (nfslog_proc_v2) / sizeof (nfslog_proc_v2[0]),
1498 1497              nfslog_proc_v2},
1499 1498          {sizeof (nfslog_proc_v3) / sizeof (nfslog_proc_v3[0]),
1500 1499              nfslog_proc_v3},
1501 1500  };
1502 1501  
1503 1502  static struct nfslog_vers_disp nfslog_nfslog_vers_disptable[] = {
1504 1503          {sizeof (nfslog_proc_v1) / sizeof (nfslog_proc_v1[0]),
1505 1504              nfslog_proc_v1},
1506 1505  };
1507 1506  
1508 1507  static struct nfslog_prog_disp nfslog_dispatch_table[] = {
1509 1508          {NFS_PROGRAM, NFS_VERSMIN,
1510 1509                  (sizeof (nfslog_vers_disptable) /
1511 1510                  sizeof (nfslog_vers_disptable[0])),
1512 1511                  nfslog_vers_disptable},
1513 1512  
1514 1513          {NFSLOG_PROGRAM, NFSLOG_VERSMIN,
1515 1514                  (sizeof (nfslog_nfslog_vers_disptable) /
1516 1515                  sizeof (nfslog_nfslog_vers_disptable[0])),
1517 1516                  nfslog_nfslog_vers_disptable},
1518 1517  };
1519 1518  
1520 1519  static int      nfslog_dispatch_table_arglen = sizeof (nfslog_dispatch_table) /
1521 1520                                          sizeof (nfslog_dispatch_table[0]);
  
    | 
      ↓ open down ↓ | 
    258 lines elided | 
    
      ↑ open up ↑ | 
  
1522 1521  
1523 1522  /*
1524 1523   * This function will determine the appropriate export info struct to use
1525 1524   * and allocate a record id to be used in the written log buffer.
1526 1525   * Usually this is a straightforward operation but the existence of the
1527 1526   * multicomponent lookup and its semantics of crossing file system
1528 1527   * boundaries add to the complexity.  See the comments below...
1529 1528   */
1530 1529  struct exportinfo *
1531 1530  nfslog_get_exi(
     1531 +        nfs_export_t *ne,
1532 1532          struct exportinfo *exi,
1533 1533          struct svc_req *req,
1534 1534          caddr_t res,
1535 1535          unsigned int *nfslog_rec_id)
1536 1536  {
1537 1537          struct log_buffer *lb;
1538 1538          struct exportinfo *exi_ret = NULL;
1539 1539          fhandle_t               *fh;
1540 1540          nfs_fh3                 *fh3;
1541 1541  
1542 1542          if (exi == NULL)
1543 1543                  return (NULL);
1544 1544  
1545 1545          /*
1546 1546           * If the exi is marked for logging, allocate a record id and return
1547 1547           */
1548 1548          if (exi->exi_export.ex_flags & EX_LOG) {
1549 1549                  lb = exi->exi_logbuffer;
1550 1550  
1551 1551                  /* obtain the unique record id for the caller */
1552 1552                  *nfslog_rec_id = atomic_add_32_nv(&lb->lb_rec_id, (int32_t)1);
  
    | 
      ↓ open down ↓ | 
    11 lines elided | 
    
      ↑ open up ↑ | 
  
1553 1553  
1554 1554                  /*
1555 1555                   * The caller will expect to be able to exi_rele() it,
1556 1556                   * so exi->exi_count must be incremented before it can
1557 1557                   * be returned, to make it uniform with exi_ret->exi_count
1558 1558                   */
1559 1559                  exi_hold(exi);
1560 1560                  return (exi);
1561 1561          }
1562 1562  
1563      -        if (exi != exi_public)
     1563 +        if (exi != ne->exi_public)
1564 1564                  return (NULL);
1565 1565  
1566 1566          /*
1567 1567           * Here we have an exi that is not marked for logging.
1568 1568           * It is possible that this request is a multicomponent lookup
1569 1569           * that was done from the public file handle (not logged) and
1570 1570           * the resulting file handle being returned to the client exists
1571 1571           * in a file system that is being logged.  If this is the case
1572 1572           * we need to log this multicomponent lookup to the appropriate
1573 1573           * log buffer.  This will allow for the appropriate path name
1574 1574           * mapping to occur at user level.
1575 1575           */
1576 1576          if (req->rq_prog == NFS_PROGRAM) {
1577 1577                  switch (req->rq_vers) {
1578 1578                  case NFS_V3:
1579 1579                          if ((req->rq_proc == NFSPROC3_LOOKUP) &&
1580 1580                              (((LOOKUP3res *)res)->status == NFS3_OK)) {
1581 1581                                  fh3 = &((LOOKUP3res *)res)->res_u.ok.object;
1582 1582                                  exi_ret = checkexport(&fh3->fh3_fsid,
1583 1583                                      FH3TOXFIDP(fh3));
1584 1584                          }
1585 1585                          break;
1586 1586  
1587 1587                  case NFS_VERSION:
1588 1588                          if ((req->rq_proc == RFS_LOOKUP) &&
1589 1589                              (((struct nfsdiropres *)
1590 1590                              res)->dr_status == NFS_OK)) {
1591 1591                                  fh =  &((struct nfsdiropres *)res)->
1592 1592                                      dr_u.dr_drok_u.drok_fhandle;
1593 1593                                  exi_ret = checkexport(&fh->fh_fsid,
1594 1594                                      (fid_t *)&fh->fh_xlen);
1595 1595                          }
1596 1596                          break;
1597 1597                  default:
1598 1598                          break;
1599 1599                  }
1600 1600          }
1601 1601  
1602 1602          if (exi_ret != NULL && exi_ret->exi_export.ex_flags & EX_LOG) {
1603 1603                  lb = exi_ret->exi_logbuffer;
1604 1604                  /* obtain the unique record id for the caller */
1605 1605                  *nfslog_rec_id = atomic_add_32_nv(&lb->lb_rec_id, (int32_t)1);
1606 1606  
1607 1607                  return (exi_ret);
1608 1608          }
1609 1609          return (NULL);
1610 1610  }
1611 1611  
1612 1612  #ifdef DEBUG
1613 1613  static long long rfslog_records_ignored = 0;
1614 1614  #endif
1615 1615  
1616 1616  /*
1617 1617   * nfslog_write_record - Fill in the record buffer for writing out.
  
    | 
      ↓ open down ↓ | 
    44 lines elided | 
    
      ↑ open up ↑ | 
  
1618 1618   * If logrecp is null, log it, otherwise, malloc the record and return it.
1619 1619   *
1620 1620   * It is the responsibility of the caller to check whether this exportinfo
1621 1621   * has logging enabled.
1622 1622   * Note that nfslog_share_public_record() only needs to check for the
1623 1623   * existence of at least one logbuffer to which the public filehandle record
1624 1624   * needs to be logged.
1625 1625   */
1626 1626  void
1627 1627  nfslog_write_record(struct exportinfo *exi, struct svc_req *req,
1628      -        caddr_t args, caddr_t res, cred_t *cr, struct netbuf *pnb,
1629      -        unsigned int record_id, unsigned int which_buffers)
     1628 +    caddr_t args, caddr_t res, cred_t *cr, struct netbuf *pnb,
     1629 +    unsigned int record_id, unsigned int which_buffers)
1630 1630  {
1631 1631          struct nfslog_prog_disp *progtable;     /* prog struct */
1632 1632          struct nfslog_vers_disp *verstable;     /* version struct */
1633 1633          struct nfslog_proc_disp *disp = NULL;   /* proc struct */
1634 1634          int                     i, vers;
1635 1635          void                    *log_cookie;    /* for logrecord if */
1636 1636          caddr_t                 buffer;
1637 1637          XDR                     xdrs;
1638 1638          unsigned int            final_size;
1639 1639          int                     encode_ok;
1640 1640          int                     alloc_indx;
1641 1641  
1642 1642          ASSERT(exi != NULL); ASSERT(req != NULL); ASSERT(args != NULL);
1643 1643          ASSERT(res != NULL); ASSERT(cr != NULL);
1644 1644  
1645 1645          /*
1646 1646           * Find program element
1647 1647           * Search the list since program can not be used as index
1648 1648           */
1649 1649          for (i = 0; (i < nfslog_dispatch_table_arglen); i++) {
1650 1650                  if (req->rq_prog == nfslog_dispatch_table[i].nfslog_dis_prog)
1651 1651                          break;
1652 1652          }
1653 1653          if (i >= nfslog_dispatch_table_arglen) {        /* program not logged */
1654 1654                  /* not an error */
1655 1655                  return;
1656 1656          }
1657 1657  
1658 1658          /*
1659 1659           * Extract the dispatch functions based on program/version
1660 1660           */
1661 1661          progtable = &nfslog_dispatch_table[i];
1662 1662          vers = req->rq_vers - progtable->nfslog_dis_versmin;
1663 1663          verstable = &progtable->nfslog_dis_vers_table[vers];
1664 1664          disp = &verstable->nfslog_dis_proc_table[req->rq_proc];
1665 1665  
1666 1666          if (!(exi->exi_export.ex_flags & EX_LOG_ALLOPS) &&
1667 1667              !disp->affects_transactions) {
1668 1668                  /*
1669 1669                   * Only interested in logging operations affecting
1670 1670                   * transaction generation. This is not one of them.
1671 1671                   */
1672 1672  #ifdef DEBUG
1673 1673                  rfslog_records_ignored++;
1674 1674  #endif
1675 1675                  return;
1676 1676          }
1677 1677  
1678 1678          switch (req->rq_prog) {
1679 1679          case NFS_PROGRAM:
1680 1680                  switch (req->rq_vers) {
1681 1681                  case NFS_V3:
1682 1682                          switch (req->rq_proc) {
1683 1683                          case NFSPROC3_READDIRPLUS:
1684 1684                                  alloc_indx = MEDIUM_INDX;
1685 1685                                  break;
1686 1686                          default:
1687 1687                                  alloc_indx = SMALL_INDX;
1688 1688                                  break;
1689 1689                          }
1690 1690                          break;
1691 1691                  default:
1692 1692                          alloc_indx = SMALL_INDX;
1693 1693                          break;
1694 1694                  }
1695 1695                  break;
1696 1696          case NFSLOG_PROGRAM:
1697 1697                  alloc_indx = MEDIUM_INDX;
1698 1698                  break;
1699 1699          default:
1700 1700                  alloc_indx = SMALL_INDX;
1701 1701                  break;
1702 1702          }
1703 1703  
1704 1704          do {
1705 1705                  encode_ok = FALSE;
1706 1706  
1707 1707                  /* Pick the size to alloc; end of the road - return */
1708 1708                  if (nfslog_mem_alloc[alloc_indx].size == (-1)) {
1709 1709                          cmn_err(CE_WARN,
1710 1710                              "NFSLOG: unable to encode record - prog=%d "
1711 1711                              "proc = %d", req->rq_prog, req->rq_proc);
1712 1712                          return;
1713 1713                  }
1714 1714  
1715 1715                  buffer = nfslog_record_alloc(exi, alloc_indx, &log_cookie, 0);
1716 1716                  if (buffer == NULL) {
1717 1717                          /* Error processing - no space alloced */
1718 1718                          rfs_log_bad++;
1719 1719                          cmn_err(CE_WARN, "NFSLOG: can't get record");
1720 1720                          return;
1721 1721                  }
1722 1722  
1723 1723                  xdrmem_create(&xdrs, buffer,
1724 1724                      nfslog_mem_alloc[alloc_indx].size, XDR_ENCODE);
1725 1725  
1726 1726                  /*
1727 1727                   * Encode the header, args and results of the record
1728 1728                   */
1729 1729                  if (xdr_nfslog_request_record(&xdrs, exi, req, cr, pnb,
1730 1730                      nfslog_mem_alloc[alloc_indx].size, record_id) &&
1731 1731                      (*disp->xdrargs)(&xdrs, args) &&
1732 1732                      (*disp->xdrres)(&xdrs, res)) {
1733 1733                                  encode_ok = TRUE;
1734 1734  
1735 1735                                  rfs_log_good++;
1736 1736                                  /*
1737 1737                                   * Get the final size of the encoded
1738 1738                                   * data and insert that length at the
1739 1739                                   * beginning.
1740 1740                                   */
1741 1741                                  final_size = xdr_getpos(&xdrs);
1742 1742                                  xdr_setpos(&xdrs, 0);
1743 1743                                  (void) xdr_u_int(&xdrs, &final_size);
1744 1744                  } else {
1745 1745                          /* Oops, the encode failed so we need to free memory */
1746 1746                          nfslog_record_put(log_cookie, 0, FALSE, which_buffers);
1747 1747                          alloc_indx++;
1748 1748                  }
1749 1749  
1750 1750          } while (encode_ok == FALSE);
1751 1751  
1752 1752  
1753 1753          /*
1754 1754           * Take the final log record and put it in the log file.
1755 1755           * This may be queued to the file internally and written
1756 1756           * later unless the last parameter is TRUE.
  
    | 
      ↓ open down ↓ | 
    117 lines elided | 
    
      ↑ open up ↑ | 
  
1757 1757           * If the record_id is 0 then this is most likely a share/unshare
1758 1758           * request and it should be written synchronously to the log file.
1759 1759           */
1760 1760          nfslog_record_put(log_cookie,
1761 1761              final_size, (record_id == 0), which_buffers);
1762 1762  }
1763 1763  
1764 1764  static char *
1765 1765  get_publicfh_path(int *alloc_length)
1766 1766  {
1767      -        extern struct exportinfo *exi_public;
1768 1767          char *pubpath;
     1768 +        nfs_export_t *ne = nfs_get_export();
1769 1769  
1770      -        rw_enter(&exported_lock, RW_READER);
     1770 +        rw_enter(&ne->exported_lock, RW_READER);
1771 1771  
1772      -        *alloc_length = exi_public->exi_export.ex_pathlen + 1;
     1772 +        *alloc_length = ne->exi_public->exi_export.ex_pathlen + 1;
1773 1773          pubpath = kmem_alloc(*alloc_length, KM_SLEEP);
1774 1774  
1775      -        (void) strcpy(pubpath, exi_public->exi_export.ex_path);
     1775 +        (void) strcpy(pubpath, ne->exi_public->exi_export.ex_path);
1776 1776  
1777      -        rw_exit(&exported_lock);
     1777 +        rw_exit(&ne->exported_lock);
1778 1778  
1779 1779          return (pubpath);
1780 1780  }
1781 1781  
1782 1782  static void
1783 1783  log_public_record(struct exportinfo *exi, cred_t *cr)
1784 1784  {
1785 1785          struct svc_req  req;
1786 1786          struct netbuf   nb = {0, 0, NULL};
1787 1787          int free_length = 0;
1788 1788          diropargs3 args;
1789 1789          LOOKUP3res res;
1790 1790  
1791 1791          bzero(&req, sizeof (req));
1792 1792          req.rq_prog = NFSLOG_PROGRAM;
1793 1793          req.rq_vers = NFSLOG_VERSION;
1794 1794          req.rq_proc = NFSLOG_LOOKUP;
1795 1795          req.rq_cred.oa_flavor = AUTH_NONE;
1796 1796  
1797 1797          bzero(&args, sizeof (diropargs3));
1798 1798          bzero(&res, sizeof (LOOKUP3res));
1799 1799  
1800 1800          args.dir.fh3_length = 0;
1801 1801          if ((args.name = get_publicfh_path(&free_length)) == NULL)
1802 1802                  return;
1803 1803          args.dirp = &args.dir;
1804 1804  
1805 1805          res.status = NFS3_OK;
1806 1806          res.res_u.ok.object.fh3_length = 0;
1807 1807  
1808 1808          /*
1809 1809           * Calling this function with the exi_public
1810 1810           * will have the effect of appending the record
1811 1811           * to each of the open log buffers
1812 1812           */
1813 1813          nfslog_write_record(exi, &req,
1814 1814              (caddr_t)&args, (caddr_t)&res, cr, &nb, 0, NFSLOG_ALL_BUFFERS);
1815 1815  
1816 1816          kmem_free(args.name, free_length);
1817 1817  }
1818 1818  
1819 1819  /*
1820 1820   * nfslog_share_record - logs a share request.
1821 1821   * This is not an NFS request, but we pretend here...
1822 1822   */
1823 1823  void
1824 1824  nfslog_share_record(struct exportinfo *exi, cred_t *cr)
1825 1825  {
1826 1826          struct svc_req  req;
1827 1827          int             res = 0;
1828 1828          struct netbuf   nb = {0, 0, NULL};
1829 1829  
1830 1830          ASSERT(exi != NULL);
1831 1831  
1832 1832          if (nfslog_buffer_list == NULL)
1833 1833                  return;
1834 1834  
1835 1835          if (exi->exi_export.ex_flags & EX_LOG) {
1836 1836                  bzero(&req, sizeof (req));
1837 1837                  req.rq_prog = NFSLOG_PROGRAM;
1838 1838                  req.rq_vers = NFSLOG_VERSION;
1839 1839                  req.rq_proc = NFSLOG_SHARE;
1840 1840                  req.rq_cred.oa_flavor = AUTH_NONE;
1841 1841                  nfslog_write_record(exi, &req, (caddr_t)exi, (caddr_t)&res, cr,
1842 1842                      &nb, 0, NFSLOG_ONE_BUFFER);
1843 1843          }
1844 1844  
1845 1845          log_public_record(exi, cr);
1846 1846  }
1847 1847  
1848 1848  /*
1849 1849   * nfslog_unshare_record - logs an unshare request.
1850 1850   * This is not an NFS request, but we pretend here...
1851 1851   */
1852 1852  void
1853 1853  nfslog_unshare_record(struct exportinfo *exi, cred_t *cr)
1854 1854  {
1855 1855          struct svc_req  req;
1856 1856          int             res = 0;
1857 1857          struct netbuf   nb = {0, 0, NULL};
1858 1858  
1859 1859          ASSERT(exi != NULL);
1860 1860          ASSERT(exi->exi_export.ex_flags & EX_LOG);
1861 1861  
1862 1862          bzero(&req, sizeof (req));
  
    | 
      ↓ open down ↓ | 
    75 lines elided | 
    
      ↑ open up ↑ | 
  
1863 1863          req.rq_prog = NFSLOG_PROGRAM;
1864 1864          req.rq_vers = NFSLOG_VERSION;
1865 1865          req.rq_proc = NFSLOG_UNSHARE;
1866 1866          req.rq_cred.oa_flavor = AUTH_NONE;
1867 1867          nfslog_write_record(exi, &req,
1868 1868              (caddr_t)exi, (caddr_t)&res, cr, &nb, 0, NFSLOG_ONE_BUFFER);
1869 1869  }
1870 1870  
1871 1871  
1872 1872  void
1873      -nfslog_getfh(struct exportinfo *exi,
1874      -        fhandle *fh,
1875      -        char *fname,
1876      -        enum uio_seg seg,
1877      -        cred_t *cr)
     1873 +nfslog_getfh(struct exportinfo *exi, fhandle *fh, char *fname, enum uio_seg seg,
     1874 +    cred_t *cr)
1878 1875  {
1879 1876          struct svc_req  req;
1880 1877          int             res = 0;
1881 1878          struct netbuf   nb = {0, 0, NULL};
1882 1879          int             error = 0;
1883 1880          char            *namebuf;
1884 1881          size_t          len;
1885 1882          nfslog_getfhargs gfh;
1886 1883  
1887 1884          ASSERT(exi != NULL);
1888 1885          ASSERT(exi->exi_export.ex_flags & EX_LOG);
1889 1886  
1890 1887          bzero(&req, sizeof (req));
1891 1888          req.rq_prog = NFSLOG_PROGRAM;
1892 1889          req.rq_vers = NFSLOG_VERSION;
1893 1890          req.rq_proc = NFSLOG_GETFH;
1894 1891          req.rq_cred.oa_flavor = AUTH_NONE;
1895 1892  
1896 1893          namebuf = kmem_alloc(MAXPATHLEN + 4, KM_SLEEP);
1897 1894          if (seg == UIO_USERSPACE) {
1898 1895                  error = copyinstr(fname, namebuf, MAXPATHLEN, &len);
1899 1896          } else {
1900 1897                  error = copystr(fname, namebuf, MAXPATHLEN, &len);
1901 1898          }
1902 1899  
1903 1900          if (!error) {
1904 1901                  gfh.gfh_fh_buf = *fh;
1905 1902                  gfh.gfh_path = namebuf;
1906 1903  
1907 1904                  nfslog_write_record(exi, &req, (caddr_t)&gfh, (caddr_t)&res,
1908 1905                      cr, &nb, 0, NFSLOG_ONE_BUFFER);
1909 1906          }
1910 1907          kmem_free(namebuf, MAXPATHLEN + 4);
1911 1908  }
  
    | 
      ↓ open down ↓ | 
    24 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX