Print this page
    
7127  remove -Wno-missing-braces from Makefile.uts
    
      
        | Split | Close | 
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/fs/tmpfs/tmp_vnops.c
          +++ new/usr/src/uts/common/fs/tmpfs/tmp_vnops.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
  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   23   * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24   24   * Use is subject to license terms.
  25   25   */
  26   26  
  27   27  /*
  28   28   * Copyright (c) 2015, Joyent, Inc. All rights reserved.
  29   29   * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  30   30   */
  31   31  
  32   32  #include <sys/types.h>
  33   33  #include <sys/param.h>
  34   34  #include <sys/t_lock.h>
  35   35  #include <sys/systm.h>
  36   36  #include <sys/sysmacros.h>
  37   37  #include <sys/user.h>
  38   38  #include <sys/time.h>
  39   39  #include <sys/vfs.h>
  40   40  #include <sys/vfs_opreg.h>
  41   41  #include <sys/vnode.h>
  42   42  #include <sys/file.h>
  43   43  #include <sys/fcntl.h>
  44   44  #include <sys/flock.h>
  45   45  #include <sys/kmem.h>
  46   46  #include <sys/uio.h>
  47   47  #include <sys/errno.h>
  48   48  #include <sys/stat.h>
  49   49  #include <sys/cred.h>
  50   50  #include <sys/dirent.h>
  51   51  #include <sys/pathname.h>
  52   52  #include <sys/vmsystm.h>
  53   53  #include <sys/fs/tmp.h>
  54   54  #include <sys/fs/tmpnode.h>
  55   55  #include <sys/mman.h>
  56   56  #include <vm/hat.h>
  57   57  #include <vm/seg_vn.h>
  58   58  #include <vm/seg_map.h>
  59   59  #include <vm/seg.h>
  60   60  #include <vm/anon.h>
  61   61  #include <vm/as.h>
  62   62  #include <vm/page.h>
  63   63  #include <vm/pvn.h>
  64   64  #include <sys/cmn_err.h>
  65   65  #include <sys/debug.h>
  66   66  #include <sys/swap.h>
  67   67  #include <sys/buf.h>
  68   68  #include <sys/vm.h>
  69   69  #include <sys/vtrace.h>
  70   70  #include <sys/policy.h>
  71   71  #include <fs/fs_subr.h>
  72   72  
  73   73  static int      tmp_getapage(struct vnode *, u_offset_t, size_t, uint_t *,
  74   74          page_t **, size_t, struct seg *, caddr_t, enum seg_rw, struct cred *);
  75   75  static int      tmp_putapage(struct vnode *, page_t *, u_offset_t *, size_t *,
  76   76          int, struct cred *);
  77   77  
  78   78  /* ARGSUSED1 */
  79   79  static int
  80   80  tmp_open(struct vnode **vpp, int flag, struct cred *cred, caller_context_t *ct)
  81   81  {
  82   82          /*
  83   83           * swapon to a tmpfs file is not supported so access
  84   84           * is denied on open if VISSWAP is set.
  85   85           */
  86   86          if ((*vpp)->v_flag & VISSWAP)
  87   87                  return (EINVAL);
  88   88          return (0);
  89   89  }
  90   90  
  91   91  /* ARGSUSED1 */
  92   92  static int
  93   93  tmp_close(
  94   94          struct vnode *vp,
  95   95          int flag,
  96   96          int count,
  97   97          offset_t offset,
  98   98          struct cred *cred,
  99   99          caller_context_t *ct)
 100  100  {
 101  101          cleanlocks(vp, ttoproc(curthread)->p_pid, 0);
 102  102          cleanshares(vp, ttoproc(curthread)->p_pid);
 103  103          return (0);
 104  104  }
 105  105  
 106  106  /*
 107  107   * wrtmp does the real work of write requests for tmpfs.
 108  108   */
 109  109  static int
 110  110  wrtmp(
 111  111          struct tmount *tm,
 112  112          struct tmpnode *tp,
 113  113          struct uio *uio,
 114  114          struct cred *cr,
 115  115          struct caller_context *ct)
 116  116  {
 117  117          pgcnt_t pageoffset;     /* offset in pages */
 118  118          ulong_t segmap_offset;  /* pagesize byte offset into segmap */
 119  119          caddr_t base;           /* base of segmap */
 120  120          ssize_t bytes;          /* bytes to uiomove */
 121  121          pfn_t pagenumber;       /* offset in pages into tmp file */
 122  122          struct vnode *vp;
 123  123          int error = 0;
 124  124          int     pagecreate;     /* == 1 if we allocated a page */
 125  125          int     newpage;
 126  126          rlim64_t limit = uio->uio_llimit;
 127  127          long oresid = uio->uio_resid;
 128  128          timestruc_t now;
 129  129  
 130  130          long tn_size_changed = 0;
 131  131          long old_tn_size;
 132  132          long new_tn_size;
 133  133  
 134  134          vp = TNTOV(tp);
 135  135          ASSERT(vp->v_type == VREG);
 136  136  
 137  137          TRACE_1(TR_FAC_TMPFS, TR_TMPFS_RWTMP_START,
 138  138              "tmp_wrtmp_start:vp %p", vp);
 139  139  
 140  140          ASSERT(RW_WRITE_HELD(&tp->tn_contents));
 141  141          ASSERT(RW_WRITE_HELD(&tp->tn_rwlock));
 142  142  
 143  143          if (MANDLOCK(vp, tp->tn_mode)) {
 144  144                  rw_exit(&tp->tn_contents);
 145  145                  /*
 146  146                   * tmp_getattr ends up being called by chklock
 147  147                   */
 148  148                  error = chklock(vp, FWRITE, uio->uio_loffset, uio->uio_resid,
 149  149                      uio->uio_fmode, ct);
 150  150                  rw_enter(&tp->tn_contents, RW_WRITER);
 151  151                  if (error != 0) {
 152  152                          TRACE_2(TR_FAC_TMPFS, TR_TMPFS_RWTMP_END,
 153  153                              "tmp_wrtmp_end:vp %p error %d", vp, error);
 154  154                          return (error);
 155  155                  }
 156  156          }
 157  157  
 158  158          if (uio->uio_loffset < 0)
 159  159                  return (EINVAL);
 160  160  
 161  161          if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T)
 162  162                  limit = MAXOFFSET_T;
 163  163  
 164  164          if (uio->uio_loffset >= limit) {
 165  165                  proc_t *p = ttoproc(curthread);
 166  166  
 167  167                  mutex_enter(&p->p_lock);
 168  168                  (void) rctl_action(rctlproc_legacy[RLIMIT_FSIZE], p->p_rctls,
 169  169                      p, RCA_UNSAFE_SIGINFO);
 170  170                  mutex_exit(&p->p_lock);
 171  171                  return (EFBIG);
 172  172          }
 173  173  
 174  174          if (uio->uio_loffset >= MAXOFF_T) {
 175  175                  TRACE_2(TR_FAC_TMPFS, TR_TMPFS_RWTMP_END,
 176  176                      "tmp_wrtmp_end:vp %p error %d", vp, EINVAL);
 177  177                  return (EFBIG);
 178  178          }
 179  179  
 180  180          if (uio->uio_resid == 0) {
 181  181                  TRACE_2(TR_FAC_TMPFS, TR_TMPFS_RWTMP_END,
 182  182                      "tmp_wrtmp_end:vp %p error %d", vp, 0);
 183  183                  return (0);
 184  184          }
 185  185  
 186  186          if (limit > MAXOFF_T)
 187  187                  limit = MAXOFF_T;
 188  188  
 189  189          do {
 190  190                  long    offset;
 191  191                  long    delta;
 192  192  
 193  193                  offset = (long)uio->uio_offset;
 194  194                  pageoffset = offset & PAGEOFFSET;
 195  195                  /*
 196  196                   * A maximum of PAGESIZE bytes of data is transferred
 197  197                   * each pass through this loop
 198  198                   */
 199  199                  bytes = MIN(PAGESIZE - pageoffset, uio->uio_resid);
 200  200  
 201  201                  if (offset + bytes >= limit) {
 202  202                          if (offset >= limit) {
 203  203                                  error = EFBIG;
 204  204                                  goto out;
 205  205                          }
 206  206                          bytes = limit - offset;
 207  207                  }
 208  208                  pagenumber = btop(offset);
 209  209  
 210  210                  /*
 211  211                   * delta is the amount of anonymous memory
 212  212                   * to reserve for the file.
 213  213                   * We always reserve in pagesize increments so
 214  214                   * unless we're extending the file into a new page,
 215  215                   * we don't need to call tmp_resv.
 216  216                   */
 217  217                  delta = offset + bytes -
 218  218                      P2ROUNDUP_TYPED(tp->tn_size, PAGESIZE, u_offset_t);
 219  219                  if (delta > 0) {
 220  220                          pagecreate = 1;
 221  221                          if (tmp_resv(tm, tp, delta, pagecreate)) {
 222  222                                  /*
 223  223                                   * Log file system full in the zone that owns
 224  224                                   * the tmpfs mount, as well as in the global
 225  225                                   * zone if necessary.
 226  226                                   */
 227  227                                  zcmn_err(tm->tm_vfsp->vfs_zone->zone_id,
 228  228                                      CE_WARN, "%s: File system full, "
 229  229                                      "swap space limit exceeded",
 230  230                                      tm->tm_mntpath);
 231  231  
 232  232                                  if (tm->tm_vfsp->vfs_zone->zone_id !=
 233  233                                      GLOBAL_ZONEID) {
 234  234  
 235  235                                          vfs_t *vfs = tm->tm_vfsp;
 236  236  
 237  237                                          zcmn_err(GLOBAL_ZONEID,
 238  238                                              CE_WARN, "%s: File system full, "
 239  239                                              "swap space limit exceeded",
 240  240                                              vfs->vfs_vnodecovered->v_path);
 241  241                                  }
 242  242                                  error = ENOSPC;
 243  243                                  break;
 244  244                          }
 245  245                          tmpnode_growmap(tp, (ulong_t)offset + bytes);
 246  246                  }
 247  247                  /* grow the file to the new length */
 248  248                  if (offset + bytes > tp->tn_size) {
 249  249                          tn_size_changed = 1;
 250  250                          old_tn_size = tp->tn_size;
 251  251                          /*
 252  252                           * Postpone updating tp->tn_size until uiomove() is
 253  253                           * done.
 254  254                           */
 255  255                          new_tn_size = offset + bytes;
 256  256                  }
 257  257                  if (bytes == PAGESIZE) {
 258  258                          /*
 259  259                           * Writing whole page so reading from disk
 260  260                           * is a waste
 261  261                           */
 262  262                          pagecreate = 1;
 263  263                  } else {
 264  264                          pagecreate = 0;
 265  265                  }
 266  266                  /*
 267  267                   * If writing past EOF or filling in a hole
 268  268                   * we need to allocate an anon slot.
 269  269                   */
 270  270                  if (anon_get_ptr(tp->tn_anon, pagenumber) == NULL) {
 271  271                          (void) anon_set_ptr(tp->tn_anon, pagenumber,
 272  272                              anon_alloc(vp, ptob(pagenumber)), ANON_SLEEP);
 273  273                          pagecreate = 1;
 274  274                          tp->tn_nblocks++;
 275  275                  }
 276  276  
 277  277                  /*
 278  278                   * We have to drop the contents lock to allow the VM
 279  279                   * system to reacquire it in tmp_getpage()
 280  280                   */
 281  281                  rw_exit(&tp->tn_contents);
 282  282  
 283  283                  /*
 284  284                   * Touch the page and fault it in if it is not in core
 285  285                   * before segmap_getmapflt or vpm_data_copy can lock it.
 286  286                   * This is to avoid the deadlock if the buffer is mapped
 287  287                   * to the same file through mmap which we want to write.
 288  288                   */
 289  289                  uio_prefaultpages((long)bytes, uio);
 290  290  
 291  291                  newpage = 0;
 292  292                  if (vpm_enable) {
 293  293                          /*
 294  294                           * Copy data. If new pages are created, part of
 295  295                           * the page that is not written will be initizliazed
 296  296                           * with zeros.
 297  297                           */
 298  298                          error = vpm_data_copy(vp, offset, bytes, uio,
 299  299                              !pagecreate, &newpage, 1, S_WRITE);
 300  300                  } else {
 301  301                          /* Get offset within the segmap mapping */
 302  302                          segmap_offset = (offset & PAGEMASK) & MAXBOFFSET;
 303  303                          base = segmap_getmapflt(segkmap, vp,
 304  304                              (offset &  MAXBMASK), PAGESIZE, !pagecreate,
 305  305                              S_WRITE);
 306  306                  }
 307  307  
 308  308  
 309  309                  if (!vpm_enable && pagecreate) {
 310  310                          /*
 311  311                           * segmap_pagecreate() returns 1 if it calls
 312  312                           * page_create_va() to allocate any pages.
 313  313                           */
 314  314                          newpage = segmap_pagecreate(segkmap,
 315  315                              base + segmap_offset, (size_t)PAGESIZE, 0);
 316  316                          /*
 317  317                           * Clear from the beginning of the page to the starting
 318  318                           * offset of the data.
 319  319                           */
 320  320                          if (pageoffset != 0)
 321  321                                  (void) kzero(base + segmap_offset,
 322  322                                      (size_t)pageoffset);
 323  323                  }
 324  324  
 325  325                  if (!vpm_enable) {
 326  326                          error = uiomove(base + segmap_offset + pageoffset,
 327  327                              (long)bytes, UIO_WRITE, uio);
 328  328                  }
 329  329  
 330  330                  if (!vpm_enable && pagecreate &&
 331  331                      uio->uio_offset < P2ROUNDUP(offset + bytes, PAGESIZE)) {
 332  332                          long    zoffset; /* zero from offset into page */
 333  333                          /*
 334  334                           * We created pages w/o initializing them completely,
 335  335                           * thus we need to zero the part that wasn't set up.
 336  336                           * This happens on most EOF write cases and if
 337  337                           * we had some sort of error during the uiomove.
 338  338                           */
 339  339                          long nmoved;
 340  340  
 341  341                          nmoved = uio->uio_offset - offset;
 342  342                          ASSERT((nmoved + pageoffset) <= PAGESIZE);
 343  343  
 344  344                          /*
 345  345                           * Zero from the end of data in the page to the
 346  346                           * end of the page.
 347  347                           */
 348  348                          if ((zoffset = pageoffset + nmoved) < PAGESIZE)
 349  349                                  (void) kzero(base + segmap_offset + zoffset,
 350  350                                      (size_t)PAGESIZE - zoffset);
 351  351                  }
 352  352  
 353  353                  /*
 354  354                   * Unlock the pages which have been allocated by
 355  355                   * page_create_va() in segmap_pagecreate()
 356  356                   */
 357  357                  if (!vpm_enable && newpage) {
 358  358                          segmap_pageunlock(segkmap, base + segmap_offset,
 359  359                              (size_t)PAGESIZE, S_WRITE);
 360  360                  }
 361  361  
 362  362                  if (error) {
 363  363                          /*
 364  364                           * If we failed on a write, we must
 365  365                           * be sure to invalidate any pages that may have
 366  366                           * been allocated.
 367  367                           */
 368  368                          if (vpm_enable) {
 369  369                                  (void) vpm_sync_pages(vp, offset, PAGESIZE,
 370  370                                      SM_INVAL);
 371  371                          } else {
 372  372                                  (void) segmap_release(segkmap, base, SM_INVAL);
 373  373                          }
 374  374                  } else {
 375  375                          if (vpm_enable) {
 376  376                                  error = vpm_sync_pages(vp, offset, PAGESIZE,
 377  377                                      0);
 378  378                          } else {
 379  379                                  error = segmap_release(segkmap, base, 0);
 380  380                          }
 381  381                  }
 382  382  
 383  383                  /*
 384  384                   * Re-acquire contents lock.
 385  385                   */
 386  386                  rw_enter(&tp->tn_contents, RW_WRITER);
 387  387  
 388  388                  /*
 389  389                   * Update tn_size.
 390  390                   */
 391  391                  if (tn_size_changed)
 392  392                          tp->tn_size = new_tn_size;
 393  393  
 394  394                  /*
 395  395                   * If the uiomove failed, fix up tn_size.
 396  396                   */
 397  397                  if (error) {
 398  398                          if (tn_size_changed) {
 399  399                                  /*
 400  400                                   * The uiomove failed, and we
 401  401                                   * allocated blocks,so get rid
 402  402                                   * of them.
 403  403                                   */
 404  404                                  (void) tmpnode_trunc(tm, tp,
 405  405                                      (ulong_t)old_tn_size);
 406  406                          }
 407  407                  } else {
 408  408                          /*
 409  409                           * XXX - Can this be out of the loop?
 410  410                           */
 411  411                          if ((tp->tn_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) &&
 412  412                              (tp->tn_mode & (S_ISUID | S_ISGID)) &&
 413  413                              secpolicy_vnode_setid_retain(cr,
 414  414                              (tp->tn_mode & S_ISUID) != 0 && tp->tn_uid == 0)) {
 415  415                                  /*
 416  416                                   * Clear Set-UID & Set-GID bits on
 417  417                                   * successful write if not privileged
 418  418                                   * and at least one of the execute bits
 419  419                                   * is set.  If we always clear Set-GID,
 420  420                                   * mandatory file and record locking is
 421  421                                   * unuseable.
 422  422                                   */
 423  423                                  tp->tn_mode &= ~(S_ISUID | S_ISGID);
 424  424                          }
 425  425                          gethrestime(&now);
 426  426                          tp->tn_mtime = now;
 427  427                          tp->tn_ctime = now;
 428  428                  }
 429  429          } while (error == 0 && uio->uio_resid > 0 && bytes != 0);
 430  430  
 431  431  out:
 432  432          /*
 433  433           * If we've already done a partial-write, terminate
 434  434           * the write but return no error.
 435  435           */
 436  436          if (oresid != uio->uio_resid)
 437  437                  error = 0;
 438  438          TRACE_2(TR_FAC_TMPFS, TR_TMPFS_RWTMP_END,
 439  439              "tmp_wrtmp_end:vp %p error %d", vp, error);
 440  440          return (error);
 441  441  }
 442  442  
 443  443  /*
 444  444   * rdtmp does the real work of read requests for tmpfs.
 445  445   */
 446  446  static int
 447  447  rdtmp(
 448  448          struct tmount *tm,
 449  449          struct tmpnode *tp,
 450  450          struct uio *uio,
 451  451          struct caller_context *ct)
 452  452  {
 453  453          ulong_t pageoffset;     /* offset in tmpfs file (uio_offset) */
 454  454          ulong_t segmap_offset;  /* pagesize byte offset into segmap */
 455  455          caddr_t base;           /* base of segmap */
 456  456          ssize_t bytes;          /* bytes to uiomove */
 457  457          struct vnode *vp;
 458  458          int error;
 459  459          long oresid = uio->uio_resid;
 460  460  
 461  461  #if defined(lint)
 462  462          tm = tm;
 463  463  #endif
 464  464          vp = TNTOV(tp);
 465  465  
 466  466          TRACE_1(TR_FAC_TMPFS, TR_TMPFS_RWTMP_START, "tmp_rdtmp_start:vp %p",
 467  467              vp);
 468  468  
 469  469          ASSERT(RW_LOCK_HELD(&tp->tn_contents));
 470  470  
 471  471          if (MANDLOCK(vp, tp->tn_mode)) {
 472  472                  rw_exit(&tp->tn_contents);
 473  473                  /*
 474  474                   * tmp_getattr ends up being called by chklock
 475  475                   */
 476  476                  error = chklock(vp, FREAD, uio->uio_loffset, uio->uio_resid,
 477  477                      uio->uio_fmode, ct);
 478  478                  rw_enter(&tp->tn_contents, RW_READER);
 479  479                  if (error != 0) {
 480  480                          TRACE_2(TR_FAC_TMPFS, TR_TMPFS_RWTMP_END,
 481  481                              "tmp_rdtmp_end:vp %p error %d", vp, error);
 482  482                          return (error);
 483  483                  }
 484  484          }
 485  485          ASSERT(tp->tn_type == VREG);
 486  486  
 487  487          if (uio->uio_loffset >= MAXOFF_T) {
 488  488                  TRACE_2(TR_FAC_TMPFS, TR_TMPFS_RWTMP_END,
 489  489                      "tmp_rdtmp_end:vp %p error %d", vp, EINVAL);
 490  490                  return (0);
 491  491          }
 492  492          if (uio->uio_loffset < 0)
 493  493                  return (EINVAL);
 494  494          if (uio->uio_resid == 0) {
 495  495                  TRACE_2(TR_FAC_TMPFS, TR_TMPFS_RWTMP_END,
 496  496                      "tmp_rdtmp_end:vp %p error %d", vp, 0);
 497  497                  return (0);
 498  498          }
 499  499  
 500  500          vp = TNTOV(tp);
 501  501  
 502  502          do {
 503  503                  long diff;
 504  504                  long offset;
 505  505  
 506  506                  offset = uio->uio_offset;
 507  507                  pageoffset = offset & PAGEOFFSET;
 508  508                  bytes = MIN(PAGESIZE - pageoffset, uio->uio_resid);
 509  509  
 510  510                  diff = tp->tn_size - offset;
 511  511  
 512  512                  if (diff <= 0) {
 513  513                          error = 0;
 514  514                          goto out;
 515  515                  }
 516  516                  if (diff < bytes)
 517  517                          bytes = diff;
 518  518  
 519  519                  /*
 520  520                   * We have to drop the contents lock to allow the VM system
 521  521                   * to reacquire it in tmp_getpage() should the uiomove cause a
 522  522                   * pagefault.
 523  523                   */
 524  524                  rw_exit(&tp->tn_contents);
 525  525  
 526  526                  if (vpm_enable) {
 527  527                          /*
 528  528                           * Copy data.
 529  529                           */
 530  530                          error = vpm_data_copy(vp, offset, bytes, uio, 1, NULL,
 531  531                              0, S_READ);
 532  532                  } else {
 533  533                          segmap_offset = (offset & PAGEMASK) & MAXBOFFSET;
 534  534                          base = segmap_getmapflt(segkmap, vp, offset & MAXBMASK,
 535  535                              bytes, 1, S_READ);
 536  536  
 537  537                          error = uiomove(base + segmap_offset + pageoffset,
 538  538                              (long)bytes, UIO_READ, uio);
 539  539                  }
 540  540  
 541  541                  if (error) {
 542  542                          if (vpm_enable) {
 543  543                                  (void) vpm_sync_pages(vp, offset, PAGESIZE, 0);
 544  544                          } else {
 545  545                                  (void) segmap_release(segkmap, base, 0);
 546  546                          }
 547  547                  } else {
 548  548                          if (vpm_enable) {
 549  549                                  error = vpm_sync_pages(vp, offset, PAGESIZE,
 550  550                                      0);
 551  551                          } else {
 552  552                                  error = segmap_release(segkmap, base, 0);
 553  553                          }
 554  554                  }
 555  555  
 556  556                  /*
 557  557                   * Re-acquire contents lock.
 558  558                   */
 559  559                  rw_enter(&tp->tn_contents, RW_READER);
 560  560  
 561  561          } while (error == 0 && uio->uio_resid > 0);
 562  562  
 563  563  out:
 564  564          gethrestime(&tp->tn_atime);
 565  565  
 566  566          /*
 567  567           * If we've already done a partial read, terminate
 568  568           * the read but return no error.
 569  569           */
 570  570          if (oresid != uio->uio_resid)
 571  571                  error = 0;
 572  572  
 573  573          TRACE_2(TR_FAC_TMPFS, TR_TMPFS_RWTMP_END,
 574  574              "tmp_rdtmp_end:vp %x error %d", vp, error);
 575  575          return (error);
 576  576  }
 577  577  
 578  578  /* ARGSUSED2 */
 579  579  static int
 580  580  tmp_read(struct vnode *vp, struct uio *uiop, int ioflag, cred_t *cred,
 581  581      struct caller_context *ct)
 582  582  {
 583  583          struct tmpnode *tp = (struct tmpnode *)VTOTN(vp);
 584  584          struct tmount *tm = (struct tmount *)VTOTM(vp);
 585  585          int error;
 586  586  
 587  587          /*
 588  588           * We don't currently support reading non-regular files
 589  589           */
 590  590          if (vp->v_type == VDIR)
 591  591                  return (EISDIR);
 592  592          if (vp->v_type != VREG)
 593  593                  return (EINVAL);
 594  594          /*
 595  595           * tmp_rwlock should have already been called from layers above
 596  596           */
 597  597          ASSERT(RW_READ_HELD(&tp->tn_rwlock));
 598  598  
 599  599          rw_enter(&tp->tn_contents, RW_READER);
 600  600  
 601  601          error = rdtmp(tm, tp, uiop, ct);
 602  602  
 603  603          rw_exit(&tp->tn_contents);
 604  604  
 605  605          return (error);
 606  606  }
 607  607  
 608  608  static int
 609  609  tmp_write(struct vnode *vp, struct uio *uiop, int ioflag, struct cred *cred,
 610  610      struct caller_context *ct)
 611  611  {
 612  612          struct tmpnode *tp = (struct tmpnode *)VTOTN(vp);
 613  613          struct tmount *tm = (struct tmount *)VTOTM(vp);
 614  614          int error;
 615  615  
 616  616          /*
 617  617           * We don't currently support writing to non-regular files
 618  618           */
 619  619          if (vp->v_type != VREG)
 620  620                  return (EINVAL);        /* XXX EISDIR? */
 621  621  
 622  622          /*
 623  623           * tmp_rwlock should have already been called from layers above
 624  624           */
 625  625          ASSERT(RW_WRITE_HELD(&tp->tn_rwlock));
 626  626  
 627  627          rw_enter(&tp->tn_contents, RW_WRITER);
 628  628  
 629  629          if (ioflag & FAPPEND) {
 630  630                  /*
 631  631                   * In append mode start at end of file.
 632  632                   */
 633  633                  uiop->uio_loffset = tp->tn_size;
 634  634          }
 635  635  
 636  636          error = wrtmp(tm, tp, uiop, cred, ct);
 637  637  
 638  638          rw_exit(&tp->tn_contents);
 639  639  
 640  640          return (error);
 641  641  }
 642  642  
 643  643  /* ARGSUSED */
 644  644  static int
 645  645  tmp_ioctl(
 646  646          struct vnode *vp,
 647  647          int com,
 648  648          intptr_t data,
 649  649          int flag,
 650  650          struct cred *cred,
 651  651          int *rvalp,
 652  652          caller_context_t *ct)
 653  653  {
 654  654          return (ENOTTY);
 655  655  }
 656  656  
 657  657  /* ARGSUSED2 */
 658  658  static int
 659  659  tmp_getattr(
 660  660          struct vnode *vp,
 661  661          struct vattr *vap,
 662  662          int flags,
 663  663          struct cred *cred,
 664  664          caller_context_t *ct)
 665  665  {
 666  666          struct tmpnode *tp = (struct tmpnode *)VTOTN(vp);
 667  667          struct vnode *mvp;
 668  668          struct vattr va;
 669  669          int attrs = 1;
 670  670  
 671  671          /*
 672  672           * A special case to handle the root tnode on a diskless nfs
 673  673           * client who may have had its uid and gid inherited
 674  674           * from an nfs vnode with nobody ownership.  Likely the
 675  675           * root filesystem. After nfs is fully functional the uid/gid
 676  676           * may be mapable so ask again.
 677  677           * vfsp can't get unmounted because we hold vp.
 678  678           */
 679  679          if (vp->v_flag & VROOT &&
 680  680              (mvp = vp->v_vfsp->vfs_vnodecovered) != NULL) {
 681  681                  mutex_enter(&tp->tn_tlock);
 682  682                  if (tp->tn_uid == UID_NOBODY || tp->tn_gid == GID_NOBODY) {
 683  683                          mutex_exit(&tp->tn_tlock);
 684  684                          bzero(&va, sizeof (struct vattr));
 685  685                          va.va_mask = AT_UID|AT_GID;
 686  686                          attrs = VOP_GETATTR(mvp, &va, 0, cred, ct);
 687  687                  } else {
 688  688                          mutex_exit(&tp->tn_tlock);
 689  689                  }
 690  690          }
 691  691          mutex_enter(&tp->tn_tlock);
 692  692          if (attrs == 0) {
 693  693                  tp->tn_uid = va.va_uid;
 694  694                  tp->tn_gid = va.va_gid;
 695  695          }
 696  696          vap->va_type = vp->v_type;
 697  697          vap->va_mode = tp->tn_mode & MODEMASK;
 698  698          vap->va_uid = tp->tn_uid;
 699  699          vap->va_gid = tp->tn_gid;
 700  700          vap->va_fsid = tp->tn_fsid;
 701  701          vap->va_nodeid = (ino64_t)tp->tn_nodeid;
 702  702          vap->va_nlink = tp->tn_nlink;
 703  703          vap->va_size = (u_offset_t)tp->tn_size;
 704  704          vap->va_atime = tp->tn_atime;
 705  705          vap->va_mtime = tp->tn_mtime;
 706  706          vap->va_ctime = tp->tn_ctime;
 707  707          vap->va_blksize = PAGESIZE;
 708  708          vap->va_rdev = tp->tn_rdev;
 709  709          vap->va_seq = tp->tn_seq;
 710  710  
 711  711          /*
 712  712           * XXX Holes are not taken into account.  We could take the time to
 713  713           * run through the anon array looking for allocated slots...
 714  714           */
 715  715          vap->va_nblocks = (fsblkcnt64_t)btodb(ptob(btopr(vap->va_size)));
 716  716          mutex_exit(&tp->tn_tlock);
 717  717          return (0);
 718  718  }
 719  719  
 720  720  /*ARGSUSED4*/
 721  721  static int
 722  722  tmp_setattr(
 723  723          struct vnode *vp,
 724  724          struct vattr *vap,
 725  725          int flags,
 726  726          struct cred *cred,
 727  727          caller_context_t *ct)
 728  728  {
 729  729          struct tmount *tm = (struct tmount *)VTOTM(vp);
 730  730          struct tmpnode *tp = (struct tmpnode *)VTOTN(vp);
 731  731          int error = 0;
 732  732          struct vattr *get;
 733  733          long mask;
 734  734  
 735  735          /*
 736  736           * Cannot set these attributes
 737  737           */
 738  738          if ((vap->va_mask & AT_NOSET) || (vap->va_mask & AT_XVATTR))
 739  739                  return (EINVAL);
 740  740  
 741  741          mutex_enter(&tp->tn_tlock);
 742  742  
 743  743          get = &tp->tn_attr;
 744  744          /*
 745  745           * Change file access modes. Must be owner or have sufficient
 746  746           * privileges.
 747  747           */
 748  748          error = secpolicy_vnode_setattr(cred, vp, vap, get, flags, tmp_taccess,
 749  749              tp);
 750  750  
 751  751          if (error)
 752  752                  goto out;
 753  753  
 754  754          mask = vap->va_mask;
 755  755  
 756  756          if (mask & AT_MODE) {
 757  757                  get->va_mode &= S_IFMT;
 758  758                  get->va_mode |= vap->va_mode & ~S_IFMT;
 759  759          }
 760  760  
 761  761          if (mask & AT_UID)
 762  762                  get->va_uid = vap->va_uid;
 763  763          if (mask & AT_GID)
 764  764                  get->va_gid = vap->va_gid;
 765  765          if (mask & AT_ATIME)
 766  766                  get->va_atime = vap->va_atime;
 767  767          if (mask & AT_MTIME)
 768  768                  get->va_mtime = vap->va_mtime;
 769  769  
 770  770          if (mask & (AT_UID | AT_GID | AT_MODE | AT_MTIME))
 771  771                  gethrestime(&tp->tn_ctime);
 772  772  
 773  773          if (mask & AT_SIZE) {
 774  774                  ASSERT(vp->v_type != VDIR);
 775  775  
 776  776                  /* Don't support large files. */
 777  777                  if (vap->va_size > MAXOFF_T) {
 778  778                          error = EFBIG;
 779  779                          goto out;
 780  780                  }
 781  781                  mutex_exit(&tp->tn_tlock);
 782  782  
 783  783                  rw_enter(&tp->tn_rwlock, RW_WRITER);
 784  784                  rw_enter(&tp->tn_contents, RW_WRITER);
 785  785                  error = tmpnode_trunc(tm, tp, (ulong_t)vap->va_size);
 786  786                  rw_exit(&tp->tn_contents);
 787  787                  rw_exit(&tp->tn_rwlock);
 788  788  
 789  789                  if (error == 0 && vap->va_size == 0)
 790  790                          vnevent_truncate(vp, ct);
 791  791  
 792  792                  goto out1;
 793  793          }
 794  794  out:
 795  795          mutex_exit(&tp->tn_tlock);
 796  796  out1:
 797  797          return (error);
 798  798  }
 799  799  
 800  800  /* ARGSUSED2 */
 801  801  static int
 802  802  tmp_access(
 803  803          struct vnode *vp,
 804  804          int mode,
 805  805          int flags,
 806  806          struct cred *cred,
 807  807          caller_context_t *ct)
 808  808  {
 809  809          struct tmpnode *tp = (struct tmpnode *)VTOTN(vp);
 810  810          int error;
 811  811  
 812  812          mutex_enter(&tp->tn_tlock);
 813  813          error = tmp_taccess(tp, mode, cred);
 814  814          mutex_exit(&tp->tn_tlock);
 815  815          return (error);
 816  816  }
 817  817  
 818  818  /* ARGSUSED3 */
 819  819  static int
 820  820  tmp_lookup(
 821  821          struct vnode *dvp,
 822  822          char *nm,
 823  823          struct vnode **vpp,
 824  824          struct pathname *pnp,
 825  825          int flags,
 826  826          struct vnode *rdir,
 827  827          struct cred *cred,
 828  828          caller_context_t *ct,
 829  829          int *direntflags,
 830  830          pathname_t *realpnp)
 831  831  {
 832  832          struct tmpnode *tp = (struct tmpnode *)VTOTN(dvp);
 833  833          struct tmpnode *ntp = NULL;
 834  834          int error;
 835  835  
 836  836  
 837  837          /* allow cd into @ dir */
 838  838          if (flags & LOOKUP_XATTR) {
 839  839                  struct tmpnode *xdp;
 840  840                  struct tmount *tm;
 841  841  
 842  842                  /*
 843  843                   * don't allow attributes if not mounted XATTR support
 844  844                   */
 845  845                  if (!(dvp->v_vfsp->vfs_flag & VFS_XATTR))
 846  846                          return (EINVAL);
 847  847  
 848  848                  if (tp->tn_flags & ISXATTR)
 849  849                          /* No attributes on attributes */
 850  850                          return (EINVAL);
 851  851  
 852  852                  rw_enter(&tp->tn_rwlock, RW_WRITER);
 853  853                  if (tp->tn_xattrdp == NULL) {
 854  854                          if (!(flags & CREATE_XATTR_DIR)) {
 855  855                                  rw_exit(&tp->tn_rwlock);
 856  856                                  return (ENOENT);
 857  857                          }
 858  858  
 859  859                          /*
 860  860                           * No attribute directory exists for this
 861  861                           * node - create the attr dir as a side effect
 862  862                           * of this lookup.
 863  863                           */
 864  864  
 865  865                          /*
 866  866                           * Make sure we have adequate permission...
 867  867                           */
 868  868  
 869  869                          if ((error = tmp_taccess(tp, VWRITE, cred)) != 0) {
 870  870                                  rw_exit(&tp->tn_rwlock);
 871  871                                  return (error);
 872  872                          }
 873  873  
 874  874                          xdp = tmp_memalloc(sizeof (struct tmpnode),
 875  875                              TMP_MUSTHAVE);
 876  876                          tm = VTOTM(dvp);
 877  877                          tmpnode_init(tm, xdp, &tp->tn_attr, NULL);
 878  878                          /*
 879  879                           * Fix-up fields unique to attribute directories.
 880  880                           */
 881  881                          xdp->tn_flags = ISXATTR;
 882  882                          xdp->tn_type = VDIR;
 883  883                          if (tp->tn_type == VDIR) {
 884  884                                  xdp->tn_mode = tp->tn_attr.va_mode;
 885  885                          } else {
 886  886                                  xdp->tn_mode = 0700;
 887  887                                  if (tp->tn_attr.va_mode & 0040)
 888  888                                          xdp->tn_mode |= 0750;
 889  889                                  if (tp->tn_attr.va_mode & 0004)
 890  890                                          xdp->tn_mode |= 0705;
 891  891                          }
 892  892                          xdp->tn_vnode->v_type = VDIR;
 893  893                          xdp->tn_vnode->v_flag |= V_XATTRDIR;
 894  894                          tdirinit(tp, xdp);
 895  895                          tp->tn_xattrdp = xdp;
 896  896                  } else {
 897  897                          VN_HOLD(tp->tn_xattrdp->tn_vnode);
 898  898                  }
 899  899                  *vpp = TNTOV(tp->tn_xattrdp);
 900  900                  rw_exit(&tp->tn_rwlock);
 901  901                  return (0);
 902  902          }
 903  903  
 904  904          /*
 905  905           * Null component name is a synonym for directory being searched.
 906  906           */
 907  907          if (*nm == '\0') {
 908  908                  VN_HOLD(dvp);
 909  909                  *vpp = dvp;
 910  910                  return (0);
 911  911          }
 912  912          ASSERT(tp);
 913  913  
 914  914          error = tdirlookup(tp, nm, &ntp, cred);
 915  915  
 916  916          if (error == 0) {
 917  917                  ASSERT(ntp);
 918  918                  *vpp = TNTOV(ntp);
 919  919                  /*
 920  920                   * If vnode is a device return special vnode instead
 921  921                   */
 922  922                  if (IS_DEVVP(*vpp)) {
 923  923                          struct vnode *newvp;
 924  924  
 925  925                          newvp = specvp(*vpp, (*vpp)->v_rdev, (*vpp)->v_type,
 926  926                              cred);
 927  927                          VN_RELE(*vpp);
 928  928                          *vpp = newvp;
 929  929                  }
 930  930          }
 931  931          TRACE_4(TR_FAC_TMPFS, TR_TMPFS_LOOKUP,
 932  932              "tmpfs lookup:vp %p name %s vpp %p error %d",
 933  933              dvp, nm, vpp, error);
 934  934          return (error);
 935  935  }
 936  936  
 937  937  /*ARGSUSED7*/
 938  938  static int
 939  939  tmp_create(
 940  940          struct vnode *dvp,
 941  941          char *nm,
 942  942          struct vattr *vap,
 943  943          enum vcexcl exclusive,
 944  944          int mode,
 945  945          struct vnode **vpp,
 946  946          struct cred *cred,
 947  947          int flag,
 948  948          caller_context_t *ct,
 949  949          vsecattr_t *vsecp)
 950  950  {
 951  951          struct tmpnode *parent;
 952  952          struct tmount *tm;
 953  953          struct tmpnode *self;
 954  954          int error;
 955  955          struct tmpnode *oldtp;
 956  956  
 957  957  again:
 958  958          parent = (struct tmpnode *)VTOTN(dvp);
 959  959          tm = (struct tmount *)VTOTM(dvp);
 960  960          self = NULL;
 961  961          error = 0;
 962  962          oldtp = NULL;
 963  963  
 964  964          /* device files not allowed in ext. attr dirs */
 965  965          if ((parent->tn_flags & ISXATTR) &&
 966  966              (vap->va_type == VBLK || vap->va_type == VCHR ||
 967  967              vap->va_type == VFIFO || vap->va_type == VDOOR ||
 968  968              vap->va_type == VSOCK || vap->va_type == VPORT))
 969  969                          return (EINVAL);
 970  970  
 971  971          if (vap->va_type == VREG && (vap->va_mode & VSVTX)) {
 972  972                  /* Must be privileged to set sticky bit */
 973  973                  if (secpolicy_vnode_stky_modify(cred))
 974  974                          vap->va_mode &= ~VSVTX;
 975  975          } else if (vap->va_type == VNON) {
 976  976                  return (EINVAL);
 977  977          }
 978  978  
 979  979          /*
 980  980           * Null component name is a synonym for directory being searched.
 981  981           */
 982  982          if (*nm == '\0') {
 983  983                  VN_HOLD(dvp);
 984  984                  oldtp = parent;
 985  985          } else {
 986  986                  error = tdirlookup(parent, nm, &oldtp, cred);
 987  987          }
 988  988  
 989  989          if (error == 0) {       /* name found */
 990  990                  boolean_t trunc = B_FALSE;
 991  991  
 992  992                  ASSERT(oldtp);
 993  993  
 994  994                  rw_enter(&oldtp->tn_rwlock, RW_WRITER);
 995  995  
 996  996                  /*
 997  997                   * if create/read-only an existing
 998  998                   * directory, allow it
 999  999                   */
1000 1000                  if (exclusive == EXCL)
1001 1001                          error = EEXIST;
1002 1002                  else if ((oldtp->tn_type == VDIR) && (mode & VWRITE))
1003 1003                          error = EISDIR;
1004 1004                  else {
1005 1005                          error = tmp_taccess(oldtp, mode, cred);
1006 1006                  }
1007 1007  
1008 1008                  if (error) {
1009 1009                          rw_exit(&oldtp->tn_rwlock);
1010 1010                          tmpnode_rele(oldtp);
1011 1011                          return (error);
1012 1012                  }
1013 1013                  *vpp = TNTOV(oldtp);
1014 1014                  if ((*vpp)->v_type == VREG && (vap->va_mask & AT_SIZE) &&
1015 1015                      vap->va_size == 0) {
1016 1016                          rw_enter(&oldtp->tn_contents, RW_WRITER);
1017 1017                          (void) tmpnode_trunc(tm, oldtp, 0);
1018 1018                          rw_exit(&oldtp->tn_contents);
1019 1019                          trunc = B_TRUE;
1020 1020                  }
1021 1021                  rw_exit(&oldtp->tn_rwlock);
1022 1022                  if (IS_DEVVP(*vpp)) {
1023 1023                          struct vnode *newvp;
1024 1024  
1025 1025                          newvp = specvp(*vpp, (*vpp)->v_rdev, (*vpp)->v_type,
1026 1026                              cred);
1027 1027                          VN_RELE(*vpp);
1028 1028                          if (newvp == NULL) {
1029 1029                                  return (ENOSYS);
1030 1030                          }
1031 1031                          *vpp = newvp;
1032 1032                  }
1033 1033  
1034 1034                  if (trunc)
1035 1035                          vnevent_create(*vpp, ct);
1036 1036  
1037 1037                  return (0);
1038 1038          }
1039 1039  
1040 1040          if (error != ENOENT)
1041 1041                  return (error);
1042 1042  
1043 1043          rw_enter(&parent->tn_rwlock, RW_WRITER);
1044 1044          error = tdirenter(tm, parent, nm, DE_CREATE,
1045 1045              (struct tmpnode *)NULL, (struct tmpnode *)NULL,
1046 1046              vap, &self, cred, ct);
1047 1047          rw_exit(&parent->tn_rwlock);
1048 1048  
1049 1049          if (error) {
1050 1050                  if (self)
1051 1051                          tmpnode_rele(self);
1052 1052  
1053 1053                  if (error == EEXIST) {
1054 1054                          /*
1055 1055                           * This means that the file was created sometime
1056 1056                           * after we checked and did not find it and when
1057 1057                           * we went to create it.
1058 1058                           * Since creat() is supposed to truncate a file
1059 1059                           * that already exits go back to the begining
1060 1060                           * of the function. This time we will find it
1061 1061                           * and go down the tmp_trunc() path
1062 1062                           */
1063 1063                          goto again;
1064 1064                  }
1065 1065                  return (error);
1066 1066          }
1067 1067  
1068 1068          *vpp = TNTOV(self);
1069 1069  
1070 1070          if (!error && IS_DEVVP(*vpp)) {
1071 1071                  struct vnode *newvp;
1072 1072  
1073 1073                  newvp = specvp(*vpp, (*vpp)->v_rdev, (*vpp)->v_type, cred);
1074 1074                  VN_RELE(*vpp);
1075 1075                  if (newvp == NULL)
1076 1076                          return (ENOSYS);
1077 1077                  *vpp = newvp;
1078 1078          }
1079 1079          TRACE_3(TR_FAC_TMPFS, TR_TMPFS_CREATE,
1080 1080              "tmpfs create:dvp %p nm %s vpp %p", dvp, nm, vpp);
1081 1081          return (0);
1082 1082  }
1083 1083  
1084 1084  /* ARGSUSED3 */
1085 1085  static int
1086 1086  tmp_remove(
1087 1087          struct vnode *dvp,
1088 1088          char *nm,
1089 1089          struct cred *cred,
1090 1090          caller_context_t *ct,
1091 1091          int flags)
1092 1092  {
1093 1093          struct tmpnode *parent = (struct tmpnode *)VTOTN(dvp);
1094 1094          int error;
1095 1095          struct tmpnode *tp = NULL;
1096 1096  
1097 1097          error = tdirlookup(parent, nm, &tp, cred);
1098 1098          if (error)
1099 1099                  return (error);
1100 1100  
1101 1101          ASSERT(tp);
1102 1102          rw_enter(&parent->tn_rwlock, RW_WRITER);
1103 1103          rw_enter(&tp->tn_rwlock, RW_WRITER);
1104 1104  
1105 1105          if (tp->tn_type != VDIR ||
1106 1106              (error = secpolicy_fs_linkdir(cred, dvp->v_vfsp)) == 0)
1107 1107                  error = tdirdelete(parent, tp, nm, DR_REMOVE, cred);
1108 1108  
1109 1109          rw_exit(&tp->tn_rwlock);
1110 1110          rw_exit(&parent->tn_rwlock);
1111 1111          vnevent_remove(TNTOV(tp), dvp, nm, ct);
1112 1112          tmpnode_rele(tp);
1113 1113  
1114 1114          TRACE_3(TR_FAC_TMPFS, TR_TMPFS_REMOVE,
1115 1115              "tmpfs remove:dvp %p nm %s error %d", dvp, nm, error);
1116 1116          return (error);
1117 1117  }
1118 1118  
1119 1119  /* ARGSUSED4 */
1120 1120  static int
1121 1121  tmp_link(
1122 1122          struct vnode *dvp,
1123 1123          struct vnode *srcvp,
1124 1124          char *tnm,
1125 1125          struct cred *cred,
1126 1126          caller_context_t *ct,
1127 1127          int flags)
1128 1128  {
1129 1129          struct tmpnode *parent;
1130 1130          struct tmpnode *from;
1131 1131          struct tmount *tm = (struct tmount *)VTOTM(dvp);
1132 1132          int error;
1133 1133          struct tmpnode *found = NULL;
1134 1134          struct vnode *realvp;
1135 1135  
1136 1136          if (VOP_REALVP(srcvp, &realvp, ct) == 0)
1137 1137                  srcvp = realvp;
1138 1138  
1139 1139          parent = (struct tmpnode *)VTOTN(dvp);
1140 1140          from = (struct tmpnode *)VTOTN(srcvp);
1141 1141  
1142 1142          if ((srcvp->v_type == VDIR &&
1143 1143              secpolicy_fs_linkdir(cred, dvp->v_vfsp)) ||
1144 1144              (from->tn_uid != crgetuid(cred) && secpolicy_basic_link(cred)))
1145 1145                  return (EPERM);
1146 1146  
1147 1147          /*
1148 1148           * Make sure link for extended attributes is valid
1149 1149           * We only support hard linking of xattr's in xattrdir to an xattrdir
1150 1150           */
1151 1151          if ((from->tn_flags & ISXATTR) != (parent->tn_flags & ISXATTR))
1152 1152                  return (EINVAL);
1153 1153  
1154 1154          error = tdirlookup(parent, tnm, &found, cred);
1155 1155          if (error == 0) {
1156 1156                  ASSERT(found);
1157 1157                  tmpnode_rele(found);
1158 1158                  return (EEXIST);
1159 1159          }
1160 1160  
1161 1161          if (error != ENOENT)
1162 1162                  return (error);
1163 1163  
1164 1164          rw_enter(&parent->tn_rwlock, RW_WRITER);
1165 1165          error = tdirenter(tm, parent, tnm, DE_LINK, (struct tmpnode *)NULL,
1166 1166              from, NULL, (struct tmpnode **)NULL, cred, ct);
1167 1167          rw_exit(&parent->tn_rwlock);
1168 1168          if (error == 0) {
1169 1169                  vnevent_link(srcvp, ct);
1170 1170          }
1171 1171          return (error);
1172 1172  }
1173 1173  
1174 1174  /* ARGSUSED5 */
1175 1175  static int
1176 1176  tmp_rename(
1177 1177          struct vnode *odvp,     /* source parent vnode */
1178 1178          char *onm,              /* source name */
1179 1179          struct vnode *ndvp,     /* destination parent vnode */
1180 1180          char *nnm,              /* destination name */
1181 1181          struct cred *cred,
1182 1182          caller_context_t *ct,
1183 1183          int flags)
1184 1184  {
1185 1185          struct tmpnode *fromparent;
1186 1186          struct tmpnode *toparent;
1187 1187          struct tmpnode *fromtp = NULL;  /* source tmpnode */
1188 1188          struct tmpnode *totp;           /* target tmpnode */
1189 1189          struct tmount *tm = (struct tmount *)VTOTM(odvp);
1190 1190          int error;
1191 1191          int samedir = 0;        /* set if odvp == ndvp */
1192 1192          struct vnode *realvp;
1193 1193  
1194 1194          if (VOP_REALVP(ndvp, &realvp, ct) == 0)
1195 1195                  ndvp = realvp;
1196 1196  
1197 1197          fromparent = (struct tmpnode *)VTOTN(odvp);
1198 1198          toparent = (struct tmpnode *)VTOTN(ndvp);
1199 1199  
1200 1200          if ((fromparent->tn_flags & ISXATTR) != (toparent->tn_flags & ISXATTR))
1201 1201                  return (EINVAL);
1202 1202  
1203 1203          mutex_enter(&tm->tm_renamelck);
1204 1204  
1205 1205          /*
1206 1206           * Look up tmpnode of file we're supposed to rename.
1207 1207           */
1208 1208          error = tdirlookup(fromparent, onm, &fromtp, cred);
1209 1209          if (error) {
1210 1210                  mutex_exit(&tm->tm_renamelck);
1211 1211                  return (error);
1212 1212          }
1213 1213  
1214 1214          /*
1215 1215           * Make sure we can delete the old (source) entry.  This
1216 1216           * requires write permission on the containing directory.  If
1217 1217           * that directory is "sticky" it requires further checks.
1218 1218           */
1219 1219          if (((error = tmp_taccess(fromparent, VWRITE, cred)) != 0) ||
1220 1220              (error = tmp_sticky_remove_access(fromparent, fromtp, cred)) != 0)
1221 1221                  goto done;
1222 1222  
1223 1223          /*
1224 1224           * Check for renaming to or from '.' or '..' or that
1225 1225           * fromtp == fromparent
1226 1226           */
1227 1227          if ((onm[0] == '.' &&
1228 1228              (onm[1] == '\0' || (onm[1] == '.' && onm[2] == '\0'))) ||
1229 1229              (nnm[0] == '.' &&
1230 1230              (nnm[1] == '\0' || (nnm[1] == '.' && nnm[2] == '\0'))) ||
1231 1231              (fromparent == fromtp)) {
1232 1232                  error = EINVAL;
1233 1233                  goto done;
1234 1234          }
1235 1235  
1236 1236          samedir = (fromparent == toparent);
1237 1237          /*
1238 1238           * Make sure we can search and rename into the new
1239 1239           * (destination) directory.
1240 1240           */
1241 1241          if (!samedir) {
1242 1242                  error = tmp_taccess(toparent, VEXEC|VWRITE, cred);
1243 1243                  if (error)
1244 1244                          goto done;
1245 1245          }
1246 1246  
1247 1247          if (tdirlookup(toparent, nnm, &totp, cred) == 0) {
1248 1248                  vnevent_pre_rename_dest(TNTOV(totp), ndvp, nnm, ct);
1249 1249                  tmpnode_rele(totp);
1250 1250          }
1251 1251  
1252 1252          /* Notify the target dir. if not the same as the source dir. */
1253 1253          if (ndvp != odvp) {
1254 1254                  vnevent_pre_rename_dest_dir(ndvp, TNTOV(fromtp), nnm, ct);
1255 1255          }
1256 1256  
1257 1257          vnevent_pre_rename_src(TNTOV(fromtp), odvp, onm, ct);
1258 1258  
1259 1259          /*
1260 1260           * Link source to new target
1261 1261           */
1262 1262          rw_enter(&toparent->tn_rwlock, RW_WRITER);
1263 1263          error = tdirenter(tm, toparent, nnm, DE_RENAME,
1264 1264              fromparent, fromtp, (struct vattr *)NULL,
1265 1265              (struct tmpnode **)NULL, cred, ct);
1266 1266          rw_exit(&toparent->tn_rwlock);
1267 1267  
1268 1268          if (error) {
1269 1269                  /*
1270 1270                   * ESAME isn't really an error; it indicates that the
1271 1271                   * operation should not be done because the source and target
1272 1272                   * are the same file, but that no error should be reported.
1273 1273                   */
1274 1274                  if (error == ESAME)
1275 1275                          error = 0;
1276 1276                  goto done;
1277 1277          }
1278 1278  
1279 1279          /*
1280 1280           * Unlink from source.
1281 1281           */
1282 1282          rw_enter(&fromparent->tn_rwlock, RW_WRITER);
1283 1283          rw_enter(&fromtp->tn_rwlock, RW_WRITER);
1284 1284  
1285 1285          error = tdirdelete(fromparent, fromtp, onm, DR_RENAME, cred);
1286 1286  
1287 1287          /*
1288 1288           * The following handles the case where our source tmpnode was
1289 1289           * removed before we got to it.
1290 1290           *
1291 1291           * XXX We should also cleanup properly in the case where tdirdelete
1292 1292           * fails for some other reason.  Currently this case shouldn't happen.
1293 1293           * (see 1184991).
1294 1294           */
1295 1295          if (error == ENOENT)
1296 1296                  error = 0;
1297 1297  
1298 1298          rw_exit(&fromtp->tn_rwlock);
1299 1299          rw_exit(&fromparent->tn_rwlock);
1300 1300  
1301 1301          if (error == 0) {
1302 1302                  vnevent_rename_src(TNTOV(fromtp), odvp, onm, ct);
1303 1303                  /*
1304 1304                   * vnevent_rename_dest is called in tdirenter().
1305 1305                   * Notify the target dir if not same as source dir.
1306 1306                   */
1307 1307                  if (ndvp != odvp)
1308 1308                          vnevent_rename_dest_dir(ndvp, ct);
1309 1309          }
1310 1310  
1311 1311  done:
1312 1312          tmpnode_rele(fromtp);
1313 1313          mutex_exit(&tm->tm_renamelck);
1314 1314  
1315 1315          TRACE_5(TR_FAC_TMPFS, TR_TMPFS_RENAME,
1316 1316              "tmpfs rename:ovp %p onm %s nvp %p nnm %s error %d", odvp, onm,
1317 1317              ndvp, nnm, error);
1318 1318          return (error);
1319 1319  }
1320 1320  
1321 1321  /* ARGSUSED5 */
1322 1322  static int
1323 1323  tmp_mkdir(
1324 1324          struct vnode *dvp,
1325 1325          char *nm,
1326 1326          struct vattr *va,
1327 1327          struct vnode **vpp,
1328 1328          struct cred *cred,
1329 1329          caller_context_t *ct,
1330 1330          int flags,
1331 1331          vsecattr_t *vsecp)
1332 1332  {
1333 1333          struct tmpnode *parent = (struct tmpnode *)VTOTN(dvp);
1334 1334          struct tmpnode *self = NULL;
1335 1335          struct tmount *tm = (struct tmount *)VTOTM(dvp);
1336 1336          int error;
1337 1337  
1338 1338          /* no new dirs allowed in xattr dirs */
1339 1339          if (parent->tn_flags & ISXATTR)
1340 1340                  return (EINVAL);
1341 1341  
1342 1342          /*
1343 1343           * Might be dangling directory.  Catch it here,
1344 1344           * because a ENOENT return from tdirlookup() is
1345 1345           * an "o.k. return".
1346 1346           */
1347 1347          if (parent->tn_nlink == 0)
1348 1348                  return (ENOENT);
1349 1349  
1350 1350          error = tdirlookup(parent, nm, &self, cred);
1351 1351          if (error == 0) {
1352 1352                  ASSERT(self);
1353 1353                  tmpnode_rele(self);
1354 1354                  return (EEXIST);
1355 1355          }
1356 1356          if (error != ENOENT)
1357 1357                  return (error);
1358 1358  
1359 1359          rw_enter(&parent->tn_rwlock, RW_WRITER);
1360 1360          error = tdirenter(tm, parent, nm, DE_MKDIR, (struct tmpnode *)NULL,
1361 1361              (struct tmpnode *)NULL, va, &self, cred, ct);
1362 1362          if (error) {
1363 1363                  rw_exit(&parent->tn_rwlock);
1364 1364                  if (self)
1365 1365                          tmpnode_rele(self);
1366 1366                  return (error);
1367 1367          }
1368 1368          rw_exit(&parent->tn_rwlock);
1369 1369          *vpp = TNTOV(self);
1370 1370          return (0);
1371 1371  }
1372 1372  
1373 1373  /* ARGSUSED4 */
1374 1374  static int
1375 1375  tmp_rmdir(
1376 1376          struct vnode *dvp,
1377 1377          char *nm,
1378 1378          struct vnode *cdir,
1379 1379          struct cred *cred,
1380 1380          caller_context_t *ct,
1381 1381          int flags)
1382 1382  {
1383 1383          struct tmpnode *parent = (struct tmpnode *)VTOTN(dvp);
1384 1384          struct tmpnode *self = NULL;
1385 1385          struct vnode *vp;
1386 1386          int error = 0;
1387 1387  
1388 1388          /*
1389 1389           * Return error when removing . and ..
1390 1390           */
1391 1391          if (strcmp(nm, ".") == 0)
1392 1392                  return (EINVAL);
1393 1393          if (strcmp(nm, "..") == 0)
1394 1394                  return (EEXIST); /* Should be ENOTEMPTY */
1395 1395          error = tdirlookup(parent, nm, &self, cred);
1396 1396          if (error)
1397 1397                  return (error);
1398 1398  
1399 1399          rw_enter(&parent->tn_rwlock, RW_WRITER);
1400 1400          rw_enter(&self->tn_rwlock, RW_WRITER);
1401 1401  
1402 1402          vp = TNTOV(self);
1403 1403          if (vp == dvp || vp == cdir) {
1404 1404                  error = EINVAL;
1405 1405                  goto done1;
1406 1406          }
1407 1407          if (self->tn_type != VDIR) {
1408 1408                  error = ENOTDIR;
1409 1409                  goto done1;
1410 1410          }
1411 1411  
1412 1412          mutex_enter(&self->tn_tlock);
1413 1413          if (self->tn_nlink > 2) {
1414 1414                  mutex_exit(&self->tn_tlock);
1415 1415                  error = EEXIST;
1416 1416                  goto done1;
1417 1417          }
1418 1418          mutex_exit(&self->tn_tlock);
1419 1419  
1420 1420          if (vn_vfswlock(vp)) {
1421 1421                  error = EBUSY;
1422 1422                  goto done1;
1423 1423          }
1424 1424          if (vn_mountedvfs(vp) != NULL) {
1425 1425                  error = EBUSY;
1426 1426                  goto done;
1427 1427          }
1428 1428  
1429 1429          /*
1430 1430           * Check for an empty directory
1431 1431           * i.e. only includes entries for "." and ".."
1432 1432           */
1433 1433          if (self->tn_dirents > 2) {
1434 1434                  error = EEXIST;         /* SIGH should be ENOTEMPTY */
1435 1435                  /*
1436 1436                   * Update atime because checking tn_dirents is logically
1437 1437                   * equivalent to reading the directory
1438 1438                   */
1439 1439                  gethrestime(&self->tn_atime);
1440 1440                  goto done;
1441 1441          }
1442 1442  
1443 1443          error = tdirdelete(parent, self, nm, DR_RMDIR, cred);
1444 1444  done:
1445 1445          vn_vfsunlock(vp);
1446 1446  done1:
1447 1447          rw_exit(&self->tn_rwlock);
1448 1448          rw_exit(&parent->tn_rwlock);
1449 1449          vnevent_rmdir(TNTOV(self), dvp, nm, ct);
1450 1450          tmpnode_rele(self);
1451 1451  
1452 1452          return (error);
1453 1453  }
1454 1454  
1455 1455  /* ARGSUSED2 */
1456 1456  static int
1457 1457  tmp_readdir(
1458 1458          struct vnode *vp,
1459 1459          struct uio *uiop,
1460 1460          struct cred *cred,
1461 1461          int *eofp,
1462 1462          caller_context_t *ct,
1463 1463          int flags)
1464 1464  {
1465 1465          struct tmpnode *tp = (struct tmpnode *)VTOTN(vp);
1466 1466          struct tdirent *tdp;
1467 1467          int error = 0;
1468 1468          size_t namelen;
1469 1469          struct dirent64 *dp;
1470 1470          ulong_t offset;
1471 1471          ulong_t total_bytes_wanted;
1472 1472          long outcount = 0;
1473 1473          long bufsize;
1474 1474          int reclen;
1475 1475          caddr_t outbuf;
1476 1476  
1477 1477          if (uiop->uio_loffset >= MAXOFF_T) {
1478 1478                  if (eofp)
1479 1479                          *eofp = 1;
1480 1480                  return (0);
1481 1481          }
1482 1482          /*
1483 1483           * assuming system call has already called tmp_rwlock
1484 1484           */
1485 1485          ASSERT(RW_READ_HELD(&tp->tn_rwlock));
1486 1486  
1487 1487          if (uiop->uio_iovcnt != 1)
1488 1488                  return (EINVAL);
1489 1489  
1490 1490          if (vp->v_type != VDIR)
1491 1491                  return (ENOTDIR);
1492 1492  
1493 1493          /*
1494 1494           * There's a window here where someone could have removed
1495 1495           * all the entries in the directory after we put a hold on the
1496 1496           * vnode but before we grabbed the rwlock.  Just return.
1497 1497           */
1498 1498          if (tp->tn_dir == NULL) {
1499 1499                  if (tp->tn_nlink) {
1500 1500                          panic("empty directory 0x%p", (void *)tp);
1501 1501                          /*NOTREACHED*/
1502 1502                  }
1503 1503                  return (0);
1504 1504          }
1505 1505  
1506 1506          /*
1507 1507           * Get space for multiple directory entries
1508 1508           */
1509 1509          total_bytes_wanted = uiop->uio_iov->iov_len;
1510 1510          bufsize = total_bytes_wanted + sizeof (struct dirent64);
1511 1511          outbuf = kmem_alloc(bufsize, KM_SLEEP);
1512 1512  
1513 1513          dp = (struct dirent64 *)outbuf;
1514 1514  
1515 1515  
1516 1516          offset = 0;
1517 1517          tdp = tp->tn_dir;
1518 1518          while (tdp) {
1519 1519                  namelen = strlen(tdp->td_name); /* no +1 needed */
1520 1520                  offset = tdp->td_offset;
1521 1521                  if (offset >= uiop->uio_offset) {
1522 1522                          reclen = (int)DIRENT64_RECLEN(namelen);
1523 1523                          if (outcount + reclen > total_bytes_wanted) {
1524 1524                                  if (!outcount)
1525 1525                                          /*
1526 1526                                           * Buffer too small for any entries.
1527 1527                                           */
1528 1528                                          error = EINVAL;
1529 1529                                  break;
1530 1530                          }
1531 1531                          ASSERT(tdp->td_tmpnode != NULL);
1532 1532  
1533 1533                          /* use strncpy(9f) to zero out uninitialized bytes */
1534 1534  
1535 1535                          (void) strncpy(dp->d_name, tdp->td_name,
1536 1536                              DIRENT64_NAMELEN(reclen));
1537 1537                          dp->d_reclen = (ushort_t)reclen;
1538 1538                          dp->d_ino = (ino64_t)tdp->td_tmpnode->tn_nodeid;
1539 1539                          dp->d_off = (offset_t)tdp->td_offset + 1;
1540 1540                          dp = (struct dirent64 *)
1541 1541                              ((uintptr_t)dp + dp->d_reclen);
1542 1542                          outcount += reclen;
1543 1543                          ASSERT(outcount <= bufsize);
1544 1544                  }
1545 1545                  tdp = tdp->td_next;
1546 1546          }
1547 1547  
1548 1548          if (!error)
1549 1549                  error = uiomove(outbuf, outcount, UIO_READ, uiop);
1550 1550  
1551 1551          if (!error) {
1552 1552                  /* If we reached the end of the list our offset */
1553 1553                  /* should now be just past the end. */
1554 1554                  if (!tdp) {
1555 1555                          offset += 1;
1556 1556                          if (eofp)
1557 1557                                  *eofp = 1;
1558 1558                  } else if (eofp)
1559 1559                          *eofp = 0;
1560 1560                  uiop->uio_offset = offset;
1561 1561          }
1562 1562          gethrestime(&tp->tn_atime);
1563 1563          kmem_free(outbuf, bufsize);
1564 1564          return (error);
1565 1565  }
1566 1566  
1567 1567  /* ARGSUSED5 */
1568 1568  static int
1569 1569  tmp_symlink(
1570 1570          struct vnode *dvp,
1571 1571          char *lnm,
1572 1572          struct vattr *tva,
1573 1573          char *tnm,
1574 1574          struct cred *cred,
1575 1575          caller_context_t *ct,
1576 1576          int flags)
1577 1577  {
1578 1578          struct tmpnode *parent = (struct tmpnode *)VTOTN(dvp);
1579 1579          struct tmpnode *self = (struct tmpnode *)NULL;
1580 1580          struct tmount *tm = (struct tmount *)VTOTM(dvp);
1581 1581          char *cp = NULL;
1582 1582          int error;
1583 1583          size_t len;
1584 1584  
1585 1585          /* no symlinks allowed to files in xattr dirs */
1586 1586          if (parent->tn_flags & ISXATTR)
1587 1587                  return (EINVAL);
1588 1588  
1589 1589          error = tdirlookup(parent, lnm, &self, cred);
1590 1590          if (error == 0) {
1591 1591                  /*
1592 1592                   * The entry already exists
1593 1593                   */
1594 1594                  tmpnode_rele(self);
1595 1595                  return (EEXIST);        /* was 0 */
1596 1596          }
1597 1597  
1598 1598          if (error != ENOENT) {
1599 1599                  if (self != NULL)
1600 1600                          tmpnode_rele(self);
1601 1601                  return (error);
1602 1602          }
1603 1603  
1604 1604          rw_enter(&parent->tn_rwlock, RW_WRITER);
1605 1605          error = tdirenter(tm, parent, lnm, DE_CREATE, (struct tmpnode *)NULL,
1606 1606              (struct tmpnode *)NULL, tva, &self, cred, ct);
1607 1607          rw_exit(&parent->tn_rwlock);
1608 1608  
1609 1609          if (error) {
1610 1610                  if (self)
1611 1611                          tmpnode_rele(self);
1612 1612                  return (error);
1613 1613          }
1614 1614          len = strlen(tnm) + 1;
1615 1615          cp = tmp_memalloc(len, 0);
1616 1616          if (cp == NULL) {
1617 1617                  tmpnode_rele(self);
1618 1618                  return (ENOSPC);
1619 1619          }
1620 1620          (void) strcpy(cp, tnm);
1621 1621  
1622 1622          self->tn_symlink = cp;
1623 1623          self->tn_size = len - 1;
1624 1624          tmpnode_rele(self);
1625 1625          return (error);
1626 1626  }
1627 1627  
1628 1628  /* ARGSUSED2 */
1629 1629  static int
1630 1630  tmp_readlink(
1631 1631          struct vnode *vp,
1632 1632          struct uio *uiop,
1633 1633          struct cred *cred,
1634 1634          caller_context_t *ct)
1635 1635  {
1636 1636          struct tmpnode *tp = (struct tmpnode *)VTOTN(vp);
1637 1637          int error = 0;
1638 1638  
1639 1639          if (vp->v_type != VLNK)
1640 1640                  return (EINVAL);
1641 1641  
1642 1642          rw_enter(&tp->tn_rwlock, RW_READER);
1643 1643          rw_enter(&tp->tn_contents, RW_READER);
1644 1644          error = uiomove(tp->tn_symlink, tp->tn_size, UIO_READ, uiop);
1645 1645          gethrestime(&tp->tn_atime);
1646 1646          rw_exit(&tp->tn_contents);
1647 1647          rw_exit(&tp->tn_rwlock);
1648 1648          return (error);
1649 1649  }
1650 1650  
1651 1651  /* ARGSUSED */
1652 1652  static int
1653 1653  tmp_fsync(
1654 1654          struct vnode *vp,
1655 1655          int syncflag,
1656 1656          struct cred *cred,
1657 1657          caller_context_t *ct)
1658 1658  {
1659 1659          return (0);
1660 1660  }
1661 1661  
1662 1662  /* ARGSUSED */
1663 1663  static void
1664 1664  tmp_inactive(struct vnode *vp, struct cred *cred, caller_context_t *ct)
1665 1665  {
1666 1666          struct tmpnode *tp = (struct tmpnode *)VTOTN(vp);
1667 1667          struct tmount *tm = (struct tmount *)VFSTOTM(vp->v_vfsp);
1668 1668  
1669 1669          rw_enter(&tp->tn_rwlock, RW_WRITER);
1670 1670  top:
1671 1671          mutex_enter(&tp->tn_tlock);
1672 1672          mutex_enter(&vp->v_lock);
1673 1673          ASSERT(vp->v_count >= 1);
1674 1674  
1675 1675          /*
1676 1676           * If we don't have the last hold or the link count is non-zero,
1677 1677           * there's little to do -- just drop our hold.
1678 1678           */
1679 1679          if (vp->v_count > 1 || tp->tn_nlink != 0) {
1680 1680                  vp->v_count--;
1681 1681                  mutex_exit(&vp->v_lock);
1682 1682                  mutex_exit(&tp->tn_tlock);
1683 1683                  rw_exit(&tp->tn_rwlock);
1684 1684                  return;
1685 1685          }
1686 1686  
1687 1687          /*
1688 1688           * We have the last hold *and* the link count is zero, so this
1689 1689           * tmpnode is dead from the filesystem's viewpoint.  However,
1690 1690           * if the tmpnode has any pages associated with it (i.e. if it's
1691 1691           * a normal file with non-zero size), the tmpnode can still be
1692 1692           * discovered by pageout or fsflush via the page vnode pointers.
1693 1693           * In this case we must drop all our locks, truncate the tmpnode,
1694 1694           * and try the whole dance again.
1695 1695           */
1696 1696          if (tp->tn_size != 0) {
1697 1697                  if (tp->tn_type == VREG) {
1698 1698                          mutex_exit(&vp->v_lock);
1699 1699                          mutex_exit(&tp->tn_tlock);
1700 1700                          rw_enter(&tp->tn_contents, RW_WRITER);
1701 1701                          (void) tmpnode_trunc(tm, tp, 0);
1702 1702                          rw_exit(&tp->tn_contents);
1703 1703                          ASSERT(tp->tn_size == 0);
1704 1704                          ASSERT(tp->tn_nblocks == 0);
1705 1705                          goto top;
1706 1706                  }
1707 1707                  if (tp->tn_type == VLNK)
1708 1708                          tmp_memfree(tp->tn_symlink, tp->tn_size + 1);
1709 1709          }
1710 1710  
1711 1711          /*
1712 1712           * Remove normal file/dir's xattr dir and xattrs.
1713 1713           */
1714 1714          if (tp->tn_xattrdp) {
1715 1715                  struct tmpnode *xtp = tp->tn_xattrdp;
1716 1716  
1717 1717                  ASSERT(xtp->tn_flags & ISXATTR);
1718 1718                  tmpnode_hold(xtp);
1719 1719                  rw_enter(&xtp->tn_rwlock, RW_WRITER);
1720 1720                  tdirtrunc(xtp);
1721 1721                  DECR_COUNT(&xtp->tn_nlink, &xtp->tn_tlock);
1722 1722                  tp->tn_xattrdp = NULL;
1723 1723                  rw_exit(&xtp->tn_rwlock);
1724 1724                  tmpnode_rele(xtp);
1725 1725          }
1726 1726  
1727 1727          mutex_exit(&vp->v_lock);
1728 1728          mutex_exit(&tp->tn_tlock);
1729 1729          /* Here's our chance to send invalid event while we're between locks */
1730 1730          vn_invalid(TNTOV(tp));
1731 1731          mutex_enter(&tm->tm_contents);
1732 1732          if (tp->tn_forw == NULL)
1733 1733                  tm->tm_rootnode->tn_back = tp->tn_back;
1734 1734          else
1735 1735                  tp->tn_forw->tn_back = tp->tn_back;
1736 1736          tp->tn_back->tn_forw = tp->tn_forw;
1737 1737          mutex_exit(&tm->tm_contents);
1738 1738          rw_exit(&tp->tn_rwlock);
1739 1739          rw_destroy(&tp->tn_rwlock);
1740 1740          mutex_destroy(&tp->tn_tlock);
1741 1741          vn_free(TNTOV(tp));
1742 1742          tmp_memfree(tp, sizeof (struct tmpnode));
1743 1743  }
1744 1744  
1745 1745  /* ARGSUSED2 */
1746 1746  static int
1747 1747  tmp_fid(struct vnode *vp, struct fid *fidp, caller_context_t *ct)
1748 1748  {
1749 1749          struct tmpnode *tp = (struct tmpnode *)VTOTN(vp);
1750 1750          struct tfid *tfid;
1751 1751  
1752 1752          if (fidp->fid_len < (sizeof (struct tfid) - sizeof (ushort_t))) {
1753 1753                  fidp->fid_len = sizeof (struct tfid) - sizeof (ushort_t);
1754 1754                  return (ENOSPC);
1755 1755          }
1756 1756  
1757 1757          tfid = (struct tfid *)fidp;
1758 1758          bzero(tfid, sizeof (struct tfid));
1759 1759          tfid->tfid_len = (int)sizeof (struct tfid) - sizeof (ushort_t);
1760 1760  
1761 1761          tfid->tfid_ino = tp->tn_nodeid;
1762 1762          tfid->tfid_gen = tp->tn_gen;
1763 1763  
1764 1764          return (0);
1765 1765  }
1766 1766  
1767 1767  
1768 1768  /*
1769 1769   * Return all the pages from [off..off+len] in given file
1770 1770   */
1771 1771  /* ARGSUSED */
1772 1772  static int
1773 1773  tmp_getpage(
1774 1774          struct vnode *vp,
1775 1775          offset_t off,
1776 1776          size_t len,
1777 1777          uint_t *protp,
1778 1778          page_t *pl[],
1779 1779          size_t plsz,
1780 1780          struct seg *seg,
1781 1781          caddr_t addr,
1782 1782          enum seg_rw rw,
1783 1783          struct cred *cr,
1784 1784          caller_context_t *ct)
1785 1785  {
1786 1786          int err = 0;
1787 1787          struct tmpnode *tp = VTOTN(vp);
1788 1788          anoff_t toff = (anoff_t)off;
1789 1789          size_t tlen = len;
1790 1790          u_offset_t tmpoff;
1791 1791          timestruc_t now;
1792 1792  
1793 1793          rw_enter(&tp->tn_contents, RW_READER);
1794 1794  
1795 1795          if (off + len  > tp->tn_size + PAGEOFFSET) {
1796 1796                  err = EFAULT;
1797 1797                  goto out;
1798 1798          }
1799 1799          /*
1800 1800           * Look for holes (no anon slot) in faulting range. If there are
1801 1801           * holes we have to switch to a write lock and fill them in. Swap
1802 1802           * space for holes was already reserved when the file was grown.
1803 1803           */
1804 1804          tmpoff = toff;
1805 1805          if (non_anon(tp->tn_anon, btop(off), &tmpoff, &tlen)) {
1806 1806                  if (!rw_tryupgrade(&tp->tn_contents)) {
1807 1807                          rw_exit(&tp->tn_contents);
1808 1808                          rw_enter(&tp->tn_contents, RW_WRITER);
1809 1809                          /* Size may have changed when lock was dropped */
1810 1810                          if (off + len  > tp->tn_size + PAGEOFFSET) {
1811 1811                                  err = EFAULT;
1812 1812                                  goto out;
1813 1813                          }
1814 1814                  }
1815 1815                  for (toff = (anoff_t)off; toff < (anoff_t)off + len;
1816 1816                      toff += PAGESIZE) {
1817 1817                          if (anon_get_ptr(tp->tn_anon, btop(toff)) == NULL) {
1818 1818                                  /* XXX - may allocate mem w. write lock held */
1819 1819                                  (void) anon_set_ptr(tp->tn_anon, btop(toff),
1820 1820                                      anon_alloc(vp, toff), ANON_SLEEP);
1821 1821                                  tp->tn_nblocks++;
1822 1822                          }
1823 1823                  }
1824 1824                  rw_downgrade(&tp->tn_contents);
1825 1825          }
1826 1826  
1827 1827  
1828 1828          err = pvn_getpages(tmp_getapage, vp, (u_offset_t)off, len, protp,
1829 1829              pl, plsz, seg, addr, rw, cr);
1830 1830  
1831 1831          gethrestime(&now);
1832 1832          tp->tn_atime = now;
1833 1833          if (rw == S_WRITE)
1834 1834                  tp->tn_mtime = now;
1835 1835  
1836 1836  out:
1837 1837          rw_exit(&tp->tn_contents);
1838 1838          return (err);
1839 1839  }
1840 1840  
1841 1841  /*
1842 1842   * Called from pvn_getpages to get a particular page.
1843 1843   */
1844 1844  /*ARGSUSED*/
1845 1845  static int
1846 1846  tmp_getapage(
1847 1847          struct vnode *vp,
1848 1848          u_offset_t off,
1849 1849          size_t len,
1850 1850          uint_t *protp,
1851 1851          page_t *pl[],
1852 1852          size_t plsz,
1853 1853          struct seg *seg,
1854 1854          caddr_t addr,
1855 1855          enum seg_rw rw,
1856 1856          struct cred *cr)
1857 1857  {
1858 1858          struct page *pp;
1859 1859          int flags;
1860 1860          int err = 0;
1861 1861          struct vnode *pvp;
1862 1862          u_offset_t poff;
1863 1863  
1864 1864          if (protp != NULL)
1865 1865                  *protp = PROT_ALL;
1866 1866  again:
1867 1867          if (pp = page_lookup(vp, off, rw == S_CREATE ? SE_EXCL : SE_SHARED)) {
1868 1868                  if (pl) {
1869 1869                          pl[0] = pp;
1870 1870                          pl[1] = NULL;
1871 1871                  } else {
1872 1872                          page_unlock(pp);
1873 1873                  }
1874 1874          } else {
1875 1875                  pp = page_create_va(vp, off, PAGESIZE,
1876 1876                      PG_WAIT | PG_EXCL, seg, addr);
1877 1877                  /*
1878 1878                   * Someone raced in and created the page after we did the
1879 1879                   * lookup but before we did the create, so go back and
1880 1880                   * try to look it up again.
1881 1881                   */
1882 1882                  if (pp == NULL)
1883 1883                          goto again;
1884 1884                  /*
1885 1885                   * Fill page from backing store, if any. If none, then
1886 1886                   * either this is a newly filled hole or page must have
1887 1887                   * been unmodified and freed so just zero it out.
1888 1888                   */
1889 1889                  err = swap_getphysname(vp, off, &pvp, &poff);
1890 1890                  if (err) {
1891 1891                          panic("tmp_getapage: no anon slot vp %p "
1892 1892                              "off %llx pp %p\n", (void *)vp, off, (void *)pp);
1893 1893                  }
1894 1894                  if (pvp) {
1895 1895                          flags = (pl == NULL ? B_ASYNC|B_READ : B_READ);
1896 1896                          err = VOP_PAGEIO(pvp, pp, (u_offset_t)poff, PAGESIZE,
1897 1897                              flags, cr, NULL);
1898 1898                          if (flags & B_ASYNC)
1899 1899                                  pp = NULL;
1900 1900                  } else if (rw != S_CREATE) {
1901 1901                          pagezero(pp, 0, PAGESIZE);
1902 1902                  }
1903 1903                  if (err && pp)
1904 1904                          pvn_read_done(pp, B_ERROR);
1905 1905                  if (err == 0) {
1906 1906                          if (pl)
1907 1907                                  pvn_plist_init(pp, pl, plsz, off, PAGESIZE, rw);
1908 1908                          else
1909 1909                                  pvn_io_done(pp);
1910 1910                  }
1911 1911          }
1912 1912          return (err);
1913 1913  }
1914 1914  
1915 1915  
1916 1916  /*
1917 1917   * Flags are composed of {B_INVAL, B_DIRTY B_FREE, B_DONTNEED}.
1918 1918   * If len == 0, do from off to EOF.
1919 1919   */
1920 1920  static int tmp_nopage = 0;      /* Don't do tmp_putpage's if set */
1921 1921  
1922 1922  /* ARGSUSED */
1923 1923  int
1924 1924  tmp_putpage(
1925 1925          register struct vnode *vp,
1926 1926          offset_t off,
1927 1927          size_t len,
1928 1928          int flags,
1929 1929          struct cred *cr,
1930 1930          caller_context_t *ct)
1931 1931  {
1932 1932          register page_t *pp;
1933 1933          u_offset_t io_off;
1934 1934          size_t io_len = 0;
1935 1935          int err = 0;
1936 1936          struct tmpnode *tp = VTOTN(vp);
1937 1937          int dolock;
1938 1938  
1939 1939          if (tmp_nopage)
1940 1940                  return (0);
1941 1941  
1942 1942          ASSERT(vp->v_count != 0);
1943 1943  
1944 1944          if (vp->v_flag & VNOMAP)
1945 1945                  return (ENOSYS);
1946 1946  
1947 1947          /*
1948 1948           * This being tmpfs, we don't ever do i/o unless we really
1949 1949           * have to (when we're low on memory and pageout calls us
1950 1950           * with B_ASYNC | B_FREE or the user explicitly asks for it with
1951 1951           * B_DONTNEED).
1952 1952           * XXX to approximately track the mod time like ufs we should
1953 1953           * update the times here. The problem is, once someone does a
1954 1954           * store we never clear the mod bit and do i/o, thus fsflush
1955 1955           * will keep calling us every 30 seconds to do the i/o and we'll
1956 1956           * continually update the mod time. At least we update the mod
1957 1957           * time on the first store because this results in a call to getpage.
1958 1958           */
1959 1959          if (flags != (B_ASYNC | B_FREE) && (flags & B_INVAL) == 0 &&
1960 1960              (flags & B_DONTNEED) == 0)
1961 1961                  return (0);
1962 1962          /*
1963 1963           * If this thread owns the lock, i.e., this thread grabbed it
1964 1964           * as writer somewhere above, then we don't need to grab the
1965 1965           * lock as reader in this routine.
1966 1966           */
1967 1967          dolock = (rw_owner(&tp->tn_contents) != curthread);
1968 1968  
1969 1969          /*
1970 1970           * If this is pageout don't block on the lock as you could deadlock
1971 1971           * when freemem == 0 (another thread has the read lock and is blocked
1972 1972           * creating a page, and a third thread is waiting to get the writers
1973 1973           * lock - waiting writers priority blocks us from getting the read
1974 1974           * lock). Of course, if the only freeable pages are on this tmpnode
1975 1975           * we're hosed anyways. A better solution might be a new lock type.
1976 1976           * Note: ufs has the same problem.
1977 1977           */
1978 1978          if (curproc == proc_pageout) {
1979 1979                  if (!rw_tryenter(&tp->tn_contents, RW_READER))
1980 1980                          return (ENOMEM);
1981 1981          } else if (dolock)
1982 1982                  rw_enter(&tp->tn_contents, RW_READER);
1983 1983  
1984 1984          if (!vn_has_cached_data(vp))
1985 1985                  goto out;
1986 1986  
1987 1987          if (len == 0) {
1988 1988                  if (curproc == proc_pageout) {
1989 1989                          panic("tmp: pageout can't block");
1990 1990                          /*NOTREACHED*/
1991 1991                  }
1992 1992  
1993 1993                  /* Search the entire vp list for pages >= off. */
1994 1994                  err = pvn_vplist_dirty(vp, (u_offset_t)off, tmp_putapage,
1995 1995                      flags, cr);
1996 1996          } else {
1997 1997                  u_offset_t eoff;
1998 1998  
1999 1999                  /*
2000 2000                   * Loop over all offsets in the range [off...off + len]
2001 2001                   * looking for pages to deal with.
2002 2002                   */
2003 2003                  eoff = MIN(off + len, tp->tn_size);
2004 2004                  for (io_off = off; io_off < eoff; io_off += io_len) {
2005 2005                          /*
2006 2006                           * If we are not invalidating, synchronously
2007 2007                           * freeing or writing pages use the routine
2008 2008                           * page_lookup_nowait() to prevent reclaiming
2009 2009                           * them from the free list.
2010 2010                           */
2011 2011                          if ((flags & B_INVAL) || ((flags & B_ASYNC) == 0)) {
2012 2012                                  pp = page_lookup(vp, io_off,
2013 2013                                      (flags & (B_INVAL | B_FREE)) ?
2014 2014                                      SE_EXCL : SE_SHARED);
2015 2015                          } else {
2016 2016                                  pp = page_lookup_nowait(vp, io_off,
2017 2017                                      (flags & B_FREE) ? SE_EXCL : SE_SHARED);
2018 2018                          }
2019 2019  
2020 2020                          if (pp == NULL || pvn_getdirty(pp, flags) == 0)
2021 2021                                  io_len = PAGESIZE;
2022 2022                          else {
2023 2023                                  err = tmp_putapage(vp, pp, &io_off, &io_len,
2024 2024                                      flags, cr);
2025 2025                                  if (err != 0)
2026 2026                                          break;
2027 2027                          }
2028 2028                  }
2029 2029          }
2030 2030          /* If invalidating, verify all pages on vnode list are gone. */
2031 2031          if (err == 0 && off == 0 && len == 0 &&
2032 2032              (flags & B_INVAL) && vn_has_cached_data(vp)) {
2033 2033                  panic("tmp_putpage: B_INVAL, pages not gone");
2034 2034                  /*NOTREACHED*/
2035 2035          }
2036 2036  out:
2037 2037          if ((curproc == proc_pageout) || dolock)
2038 2038                  rw_exit(&tp->tn_contents);
2039 2039          /*
2040 2040           * Only reason putapage is going to give us SE_NOSWAP as error
2041 2041           * is when we ask a page to be written to physical backing store
2042 2042           * and there is none. Ignore this because we might be dealing
2043 2043           * with a swap page which does not have any backing store
2044 2044           * on disk. In any other case we won't get this error over here.
2045 2045           */
2046 2046          if (err == SE_NOSWAP)
2047 2047                  err = 0;
2048 2048          return (err);
2049 2049  }
2050 2050  
2051 2051  long tmp_putpagecnt, tmp_pagespushed;
2052 2052  
2053 2053  /*
2054 2054   * Write out a single page.
2055 2055   * For tmpfs this means choose a physical swap slot and write the page
2056 2056   * out using VOP_PAGEIO. For performance, we attempt to kluster; i.e.,
2057 2057   * we try to find a bunch of other dirty pages adjacent in the file
2058 2058   * and a bunch of contiguous swap slots, and then write all the pages
2059 2059   * out in a single i/o.
2060 2060   */
2061 2061  /*ARGSUSED*/
2062 2062  static int
2063 2063  tmp_putapage(
2064 2064          struct vnode *vp,
2065 2065          page_t *pp,
2066 2066          u_offset_t *offp,
2067 2067          size_t *lenp,
2068 2068          int flags,
2069 2069          struct cred *cr)
2070 2070  {
2071 2071          int err;
2072 2072          ulong_t klstart, kllen;
2073 2073          page_t *pplist, *npplist;
2074 2074          extern int klustsize;
2075 2075          long tmp_klustsize;
2076 2076          struct tmpnode *tp;
2077 2077          size_t pp_off, pp_len;
2078 2078          u_offset_t io_off;
2079 2079          size_t io_len;
2080 2080          struct vnode *pvp;
2081 2081          u_offset_t pstart;
2082 2082          u_offset_t offset;
2083 2083          u_offset_t tmpoff;
2084 2084  
2085 2085          ASSERT(PAGE_LOCKED(pp));
2086 2086  
2087 2087          /* Kluster in tmp_klustsize chunks */
2088 2088          tp = VTOTN(vp);
2089 2089          tmp_klustsize = klustsize;
2090 2090          offset = pp->p_offset;
2091 2091          klstart = (offset / tmp_klustsize) * tmp_klustsize;
2092 2092          kllen = MIN(tmp_klustsize, tp->tn_size - klstart);
2093 2093  
2094 2094          /* Get a kluster of pages */
2095 2095          pplist =
2096 2096              pvn_write_kluster(vp, pp, &tmpoff, &pp_len, klstart, kllen, flags);
2097 2097  
2098 2098          pp_off = (size_t)tmpoff;
2099 2099  
2100 2100          /*
2101 2101           * Get a cluster of physical offsets for the pages; the amount we
2102 2102           * get may be some subrange of what we ask for (io_off, io_len).
2103 2103           */
2104 2104          io_off = pp_off;
2105 2105          io_len = pp_len;
2106 2106          err = swap_newphysname(vp, offset, &io_off, &io_len, &pvp, &pstart);
2107 2107          ASSERT(err != SE_NOANON); /* anon slot must have been filled */
2108 2108          if (err) {
2109 2109                  pvn_write_done(pplist, B_ERROR | B_WRITE | flags);
2110 2110                  /*
2111 2111                   * If this routine is called as a result of segvn_sync
2112 2112                   * operation and we have no physical swap then we can get an
2113 2113                   * error here. In such case we would return SE_NOSWAP as error.
2114 2114                   * At this point, we expect only SE_NOSWAP.
2115 2115                   */
2116 2116                  ASSERT(err == SE_NOSWAP);
2117 2117                  if (flags & B_INVAL)
2118 2118                          err = ENOMEM;
2119 2119                  goto out;
2120 2120          }
2121 2121          ASSERT(pp_off <= io_off && io_off + io_len <= pp_off + pp_len);
2122 2122          ASSERT(io_off <= offset && offset < io_off + io_len);
2123 2123  
2124 2124          /* Toss pages at front/rear that we couldn't get physical backing for */
2125 2125          if (io_off != pp_off) {
2126 2126                  npplist = NULL;
2127 2127                  page_list_break(&pplist, &npplist, btop(io_off - pp_off));
2128 2128                  ASSERT(pplist->p_offset == pp_off);
2129 2129                  ASSERT(pplist->p_prev->p_offset == io_off - PAGESIZE);
2130 2130                  pvn_write_done(pplist, B_ERROR | B_WRITE | flags);
2131 2131                  pplist = npplist;
2132 2132          }
2133 2133          if (io_off + io_len < pp_off + pp_len) {
2134 2134                  npplist = NULL;
2135 2135                  page_list_break(&pplist, &npplist, btop(io_len));
2136 2136                  ASSERT(npplist->p_offset == io_off + io_len);
2137 2137                  ASSERT(npplist->p_prev->p_offset == pp_off + pp_len - PAGESIZE);
2138 2138                  pvn_write_done(npplist, B_ERROR | B_WRITE | flags);
2139 2139          }
2140 2140  
2141 2141          ASSERT(pplist->p_offset == io_off);
2142 2142          ASSERT(pplist->p_prev->p_offset == io_off + io_len - PAGESIZE);
2143 2143          ASSERT(btopr(io_len) <= btopr(kllen));
2144 2144  
2145 2145          /* Do i/o on the remaining kluster */
2146 2146          err = VOP_PAGEIO(pvp, pplist, (u_offset_t)pstart, io_len,
2147 2147              B_WRITE | flags, cr, NULL);
2148 2148  
2149 2149          if ((flags & B_ASYNC) == 0) {
2150 2150                  pvn_write_done(pplist, ((err) ? B_ERROR : 0) | B_WRITE | flags);
2151 2151          }
2152 2152  out:
2153 2153          if (!err) {
2154 2154                  if (offp)
2155 2155                          *offp = io_off;
2156 2156                  if (lenp)
2157 2157                          *lenp = io_len;
2158 2158                  tmp_putpagecnt++;
2159 2159                  tmp_pagespushed += btop(io_len);
2160 2160          }
2161 2161          if (err && err != ENOMEM && err != SE_NOSWAP)
2162 2162                  cmn_err(CE_WARN, "tmp_putapage: err %d\n", err);
2163 2163          return (err);
2164 2164  }
2165 2165  
2166 2166  /* ARGSUSED */
2167 2167  static int
2168 2168  tmp_map(
2169 2169          struct vnode *vp,
2170 2170          offset_t off,
2171 2171          struct as *as,
2172 2172          caddr_t *addrp,
2173 2173          size_t len,
2174 2174          uchar_t prot,
2175 2175          uchar_t maxprot,
2176 2176          uint_t flags,
2177 2177          struct cred *cred,
2178 2178          caller_context_t *ct)
2179 2179  {
2180 2180          struct segvn_crargs vn_a;
2181 2181          struct tmpnode *tp = (struct tmpnode *)VTOTN(vp);
2182 2182          int error;
2183 2183  
2184 2184  #ifdef _ILP32
2185 2185          if (len > MAXOFF_T)
2186 2186                  return (ENOMEM);
2187 2187  #endif
2188 2188  
2189 2189          if (vp->v_flag & VNOMAP)
2190 2190                  return (ENOSYS);
2191 2191  
2192 2192          if (off < 0 || (offset_t)(off + len) < 0 ||
2193 2193              off > MAXOFF_T || (off + len) > MAXOFF_T)
2194 2194                  return (ENXIO);
2195 2195  
2196 2196          if (vp->v_type != VREG)
2197 2197                  return (ENODEV);
2198 2198  
2199 2199          /*
2200 2200           * Don't allow mapping to locked file
2201 2201           */
2202 2202          if (vn_has_mandatory_locks(vp, tp->tn_mode)) {
2203 2203                  return (EAGAIN);
2204 2204          }
2205 2205  
2206 2206          as_rangelock(as);
2207 2207          error = choose_addr(as, addrp, len, off, ADDR_VACALIGN, flags);
2208 2208          if (error != 0) {
2209 2209                  as_rangeunlock(as);
2210 2210                  return (error);
2211 2211          }
2212 2212  
2213 2213          vn_a.vp = vp;
2214 2214          vn_a.offset = (u_offset_t)off;
2215 2215          vn_a.type = flags & MAP_TYPE;
2216 2216          vn_a.prot = prot;
2217 2217          vn_a.maxprot = maxprot;
2218 2218          vn_a.flags = flags & ~MAP_TYPE;
2219 2219          vn_a.cred = cred;
2220 2220          vn_a.amp = NULL;
2221 2221          vn_a.szc = 0;
2222 2222          vn_a.lgrp_mem_policy_flags = 0;
2223 2223  
2224 2224          error = as_map(as, *addrp, len, segvn_create, &vn_a);
2225 2225          as_rangeunlock(as);
2226 2226          return (error);
2227 2227  }
2228 2228  
2229 2229  /*
2230 2230   * tmp_addmap and tmp_delmap can't be called since the vp
2231 2231   * maintained in the segvn mapping is NULL.
2232 2232   */
2233 2233  /* ARGSUSED */
2234 2234  static int
2235 2235  tmp_addmap(
2236 2236          struct vnode *vp,
2237 2237          offset_t off,
2238 2238          struct as *as,
2239 2239          caddr_t addr,
2240 2240          size_t len,
2241 2241          uchar_t prot,
2242 2242          uchar_t maxprot,
2243 2243          uint_t flags,
2244 2244          struct cred *cred,
2245 2245          caller_context_t *ct)
2246 2246  {
2247 2247          return (0);
2248 2248  }
2249 2249  
2250 2250  /* ARGSUSED */
2251 2251  static int
2252 2252  tmp_delmap(
2253 2253          struct vnode *vp,
2254 2254          offset_t off,
2255 2255          struct as *as,
2256 2256          caddr_t addr,
2257 2257          size_t len,
2258 2258          uint_t prot,
2259 2259          uint_t maxprot,
2260 2260          uint_t flags,
2261 2261          struct cred *cred,
2262 2262          caller_context_t *ct)
2263 2263  {
2264 2264          return (0);
2265 2265  }
2266 2266  
2267 2267  static int
2268 2268  tmp_freesp(struct vnode *vp, struct flock64 *lp, int flag)
2269 2269  {
2270 2270          register int i;
2271 2271          register struct tmpnode *tp = VTOTN(vp);
2272 2272          int error;
2273 2273  
2274 2274          ASSERT(vp->v_type == VREG);
2275 2275          ASSERT(lp->l_start >= 0);
2276 2276  
2277 2277          if (lp->l_len != 0)
2278 2278                  return (EINVAL);
2279 2279  
2280 2280          rw_enter(&tp->tn_rwlock, RW_WRITER);
2281 2281          if (tp->tn_size == lp->l_start) {
2282 2282                  rw_exit(&tp->tn_rwlock);
2283 2283                  return (0);
2284 2284          }
2285 2285  
2286 2286          /*
2287 2287           * Check for any mandatory locks on the range
2288 2288           */
2289 2289          if (MANDLOCK(vp, tp->tn_mode)) {
2290 2290                  long save_start;
2291 2291  
2292 2292                  save_start = lp->l_start;
2293 2293  
2294 2294                  if (tp->tn_size < lp->l_start) {
2295 2295                          /*
2296 2296                           * "Truncate up" case: need to make sure there
2297 2297                           * is no lock beyond current end-of-file. To
2298 2298                           * do so, we need to set l_start to the size
2299 2299                           * of the file temporarily.
2300 2300                           */
2301 2301                          lp->l_start = tp->tn_size;
2302 2302                  }
2303 2303                  lp->l_type = F_WRLCK;
2304 2304                  lp->l_sysid = 0;
2305 2305                  lp->l_pid = ttoproc(curthread)->p_pid;
2306 2306                  i = (flag & (FNDELAY|FNONBLOCK)) ? 0 : SLPFLCK;
2307 2307                  if ((i = reclock(vp, lp, i, 0, lp->l_start, NULL)) != 0 ||
2308 2308                      lp->l_type != F_UNLCK) {
2309 2309                          rw_exit(&tp->tn_rwlock);
2310 2310                          return (i ? i : EAGAIN);
2311 2311                  }
2312 2312  
2313 2313                  lp->l_start = save_start;
2314 2314          }
2315 2315          VFSTOTM(vp->v_vfsp);
2316 2316  
2317 2317          rw_enter(&tp->tn_contents, RW_WRITER);
2318 2318          error = tmpnode_trunc((struct tmount *)VFSTOTM(vp->v_vfsp),
2319 2319              tp, (ulong_t)lp->l_start);
2320 2320          rw_exit(&tp->tn_contents);
2321 2321          rw_exit(&tp->tn_rwlock);
2322 2322          return (error);
2323 2323  }
2324 2324  
2325 2325  /* ARGSUSED */
2326 2326  static int
2327 2327  tmp_space(
2328 2328          struct vnode *vp,
2329 2329          int cmd,
2330 2330          struct flock64 *bfp,
2331 2331          int flag,
2332 2332          offset_t offset,
2333 2333          cred_t *cred,
2334 2334          caller_context_t *ct)
2335 2335  {
2336 2336          int error;
2337 2337  
2338 2338          if (cmd != F_FREESP)
2339 2339                  return (EINVAL);
2340 2340          if ((error = convoff(vp, bfp, 0, (offset_t)offset)) == 0) {
2341 2341                  if ((bfp->l_start > MAXOFF_T) || (bfp->l_len > MAXOFF_T))
2342 2342                          return (EFBIG);
2343 2343                  error = tmp_freesp(vp, bfp, flag);
2344 2344  
2345 2345                  if (error == 0 && bfp->l_start == 0)
2346 2346                          vnevent_truncate(vp, ct);
2347 2347          }
2348 2348          return (error);
2349 2349  }
2350 2350  
2351 2351  /* ARGSUSED */
2352 2352  static int
2353 2353  tmp_seek(
2354 2354          struct vnode *vp,
2355 2355          offset_t ooff,
2356 2356          offset_t *noffp,
2357 2357          caller_context_t *ct)
2358 2358  {
2359 2359          return ((*noffp < 0 || *noffp > MAXOFFSET_T) ? EINVAL : 0);
2360 2360  }
2361 2361  
2362 2362  /* ARGSUSED2 */
2363 2363  static int
2364 2364  tmp_rwlock(struct vnode *vp, int write_lock, caller_context_t *ctp)
2365 2365  {
2366 2366          struct tmpnode *tp = VTOTN(vp);
2367 2367  
2368 2368          if (write_lock) {
2369 2369                  rw_enter(&tp->tn_rwlock, RW_WRITER);
2370 2370          } else {
2371 2371                  rw_enter(&tp->tn_rwlock, RW_READER);
2372 2372          }
2373 2373          return (write_lock);
2374 2374  }
2375 2375  
2376 2376  /* ARGSUSED1 */
2377 2377  static void
2378 2378  tmp_rwunlock(struct vnode *vp, int write_lock, caller_context_t *ctp)
2379 2379  {
2380 2380          struct tmpnode *tp = VTOTN(vp);
2381 2381  
2382 2382          rw_exit(&tp->tn_rwlock);
2383 2383  }
2384 2384  
2385 2385  static int
2386 2386  tmp_pathconf(
2387 2387          struct vnode *vp,
2388 2388          int cmd,
2389 2389          ulong_t *valp,
2390 2390          cred_t *cr,
2391 2391          caller_context_t *ct)
2392 2392  {
2393 2393          struct tmpnode *tp = NULL;
2394 2394          int error;
2395 2395  
2396 2396          switch (cmd) {
2397 2397          case _PC_XATTR_EXISTS:
2398 2398                  if (vp->v_vfsp->vfs_flag & VFS_XATTR) {
2399 2399                          *valp = 0;      /* assume no attributes */
2400 2400                          error = 0;      /* okay to ask */
2401 2401                          tp = VTOTN(vp);
2402 2402                          rw_enter(&tp->tn_rwlock, RW_READER);
2403 2403                          if (tp->tn_xattrdp) {
2404 2404                                  rw_enter(&tp->tn_xattrdp->tn_rwlock, RW_READER);
2405 2405                                  /* do not count "." and ".." */
2406 2406                                  if (tp->tn_xattrdp->tn_dirents > 2)
2407 2407                                          *valp = 1;
2408 2408                                  rw_exit(&tp->tn_xattrdp->tn_rwlock);
2409 2409                          }
2410 2410                          rw_exit(&tp->tn_rwlock);
2411 2411                  } else {
2412 2412                          error = EINVAL;
2413 2413                  }
2414 2414                  break;
2415 2415          case _PC_SATTR_ENABLED:
2416 2416          case _PC_SATTR_EXISTS:
2417 2417                  *valp = vfs_has_feature(vp->v_vfsp, VFSFT_SYSATTR_VIEWS) &&
2418 2418                      (vp->v_type == VREG || vp->v_type == VDIR);
2419 2419                  error = 0;
2420 2420                  break;
2421 2421          case _PC_TIMESTAMP_RESOLUTION:
2422 2422                  /* nanosecond timestamp resolution */
2423 2423                  *valp = 1L;
2424 2424                  error = 0;
2425 2425                  break;
  
    | ↓ open down ↓ | 2425 lines elided | ↑ open up ↑ | 
2426 2426          default:
2427 2427                  error = fs_pathconf(vp, cmd, valp, cr, ct);
2428 2428          }
2429 2429          return (error);
2430 2430  }
2431 2431  
2432 2432  
2433 2433  struct vnodeops *tmp_vnodeops;
2434 2434  
2435 2435  const fs_operation_def_t tmp_vnodeops_template[] = {
2436      -        VOPNAME_OPEN,           { .vop_open = tmp_open },
2437      -        VOPNAME_CLOSE,          { .vop_close = tmp_close },
2438      -        VOPNAME_READ,           { .vop_read = tmp_read },
2439      -        VOPNAME_WRITE,          { .vop_write = tmp_write },
2440      -        VOPNAME_IOCTL,          { .vop_ioctl = tmp_ioctl },
2441      -        VOPNAME_GETATTR,        { .vop_getattr = tmp_getattr },
2442      -        VOPNAME_SETATTR,        { .vop_setattr = tmp_setattr },
2443      -        VOPNAME_ACCESS,         { .vop_access = tmp_access },
2444      -        VOPNAME_LOOKUP,         { .vop_lookup = tmp_lookup },
2445      -        VOPNAME_CREATE,         { .vop_create = tmp_create },
2446      -        VOPNAME_REMOVE,         { .vop_remove = tmp_remove },
2447      -        VOPNAME_LINK,           { .vop_link = tmp_link },
2448      -        VOPNAME_RENAME,         { .vop_rename = tmp_rename },
2449      -        VOPNAME_MKDIR,          { .vop_mkdir = tmp_mkdir },
2450      -        VOPNAME_RMDIR,          { .vop_rmdir = tmp_rmdir },
2451      -        VOPNAME_READDIR,        { .vop_readdir = tmp_readdir },
2452      -        VOPNAME_SYMLINK,        { .vop_symlink = tmp_symlink },
2453      -        VOPNAME_READLINK,       { .vop_readlink = tmp_readlink },
2454      -        VOPNAME_FSYNC,          { .vop_fsync = tmp_fsync },
2455      -        VOPNAME_INACTIVE,       { .vop_inactive = tmp_inactive },
2456      -        VOPNAME_FID,            { .vop_fid = tmp_fid },
2457      -        VOPNAME_RWLOCK,         { .vop_rwlock = tmp_rwlock },
2458      -        VOPNAME_RWUNLOCK,       { .vop_rwunlock = tmp_rwunlock },
2459      -        VOPNAME_SEEK,           { .vop_seek = tmp_seek },
2460      -        VOPNAME_SPACE,          { .vop_space = tmp_space },
2461      -        VOPNAME_GETPAGE,        { .vop_getpage = tmp_getpage },
2462      -        VOPNAME_PUTPAGE,        { .vop_putpage = tmp_putpage },
2463      -        VOPNAME_MAP,            { .vop_map = tmp_map },
2464      -        VOPNAME_ADDMAP,         { .vop_addmap = tmp_addmap },
2465      -        VOPNAME_DELMAP,         { .vop_delmap = tmp_delmap },
2466      -        VOPNAME_PATHCONF,       { .vop_pathconf = tmp_pathconf },
2467      -        VOPNAME_VNEVENT,        { .vop_vnevent = fs_vnevent_support },
2468      -        NULL,                   NULL
     2436 +        { VOPNAME_OPEN,         { .vop_open = tmp_open } },
     2437 +        { VOPNAME_CLOSE,        { .vop_close = tmp_close } },
     2438 +        { VOPNAME_READ,         { .vop_read = tmp_read } },
     2439 +        { VOPNAME_WRITE,        { .vop_write = tmp_write } },
     2440 +        { VOPNAME_IOCTL,        { .vop_ioctl = tmp_ioctl } },
     2441 +        { VOPNAME_GETATTR,      { .vop_getattr = tmp_getattr } },
     2442 +        { VOPNAME_SETATTR,      { .vop_setattr = tmp_setattr } },
     2443 +        { VOPNAME_ACCESS,       { .vop_access = tmp_access } },
     2444 +        { VOPNAME_LOOKUP,       { .vop_lookup = tmp_lookup } },
     2445 +        { VOPNAME_CREATE,       { .vop_create = tmp_create } },
     2446 +        { VOPNAME_REMOVE,       { .vop_remove = tmp_remove } },
     2447 +        { VOPNAME_LINK,         { .vop_link = tmp_link } },
     2448 +        { VOPNAME_RENAME,       { .vop_rename = tmp_rename } },
     2449 +        { VOPNAME_MKDIR,        { .vop_mkdir = tmp_mkdir } },
     2450 +        { VOPNAME_RMDIR,        { .vop_rmdir = tmp_rmdir } },
     2451 +        { VOPNAME_READDIR,      { .vop_readdir = tmp_readdir } },
     2452 +        { VOPNAME_SYMLINK,      { .vop_symlink = tmp_symlink } },
     2453 +        { VOPNAME_READLINK,     { .vop_readlink = tmp_readlink } },
     2454 +        { VOPNAME_FSYNC,        { .vop_fsync = tmp_fsync } },
     2455 +        { VOPNAME_INACTIVE,     { .vop_inactive = tmp_inactive } },
     2456 +        { VOPNAME_FID,          { .vop_fid = tmp_fid } },
     2457 +        { VOPNAME_RWLOCK,       { .vop_rwlock = tmp_rwlock } },
     2458 +        { VOPNAME_RWUNLOCK,     { .vop_rwunlock = tmp_rwunlock } },
     2459 +        { VOPNAME_SEEK,         { .vop_seek = tmp_seek } },
     2460 +        { VOPNAME_SPACE,        { .vop_space = tmp_space } },
     2461 +        { VOPNAME_GETPAGE,      { .vop_getpage = tmp_getpage } },
     2462 +        { VOPNAME_PUTPAGE,      { .vop_putpage = tmp_putpage } },
     2463 +        { VOPNAME_MAP,          { .vop_map = tmp_map } },
     2464 +        { VOPNAME_ADDMAP,       { .vop_addmap = tmp_addmap } },
     2465 +        { VOPNAME_DELMAP,       { .vop_delmap = tmp_delmap } },
     2466 +        { VOPNAME_PATHCONF,     { .vop_pathconf = tmp_pathconf } },
     2467 +        { VOPNAME_VNEVENT,      { .vop_vnevent = fs_vnevent_support } },
     2468 +        { NULL,                 { NULL } }
2469 2469  };
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX