Print this page
    
OS-5148 ftruncate at offset should emit proper events
Reviewed by: Bryan Cantrill <bryan@joyent.com>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/fs/pcfs/pc_vnops.c
          +++ new/usr/src/uts/common/fs/pcfs/pc_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) 2013, Joyent, Inc. All rights reserved.
  29   29   * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  30   30   */
  31   31  
  32   32  #include <sys/param.h>
  33   33  #include <sys/t_lock.h>
  34   34  #include <sys/systm.h>
  35   35  #include <sys/sysmacros.h>
  36   36  #include <sys/user.h>
  37   37  #include <sys/buf.h>
  38   38  #include <sys/stat.h>
  39   39  #include <sys/vfs.h>
  40   40  #include <sys/vfs_opreg.h>
  41   41  #include <sys/dirent.h>
  42   42  #include <sys/vnode.h>
  43   43  #include <sys/proc.h>
  44   44  #include <sys/file.h>
  45   45  #include <sys/fcntl.h>
  46   46  #include <sys/uio.h>
  47   47  #include <sys/fs/pc_label.h>
  48   48  #include <sys/fs/pc_fs.h>
  49   49  #include <sys/fs/pc_dir.h>
  50   50  #include <sys/fs/pc_node.h>
  51   51  #include <sys/mman.h>
  52   52  #include <sys/pathname.h>
  53   53  #include <sys/vmsystm.h>
  54   54  #include <sys/cmn_err.h>
  55   55  #include <sys/debug.h>
  56   56  #include <sys/statvfs.h>
  57   57  #include <sys/unistd.h>
  58   58  #include <sys/kmem.h>
  59   59  #include <sys/conf.h>
  60   60  #include <sys/flock.h>
  61   61  #include <sys/policy.h>
  62   62  #include <sys/sdt.h>
  63   63  #include <sys/sunddi.h>
  64   64  #include <sys/types.h>
  65   65  #include <sys/errno.h>
  66   66  
  67   67  #include <vm/seg.h>
  68   68  #include <vm/page.h>
  69   69  #include <vm/pvn.h>
  70   70  #include <vm/seg_map.h>
  71   71  #include <vm/seg_vn.h>
  72   72  #include <vm/hat.h>
  73   73  #include <vm/as.h>
  74   74  #include <vm/seg_kmem.h>
  75   75  
  76   76  #include <fs/fs_subr.h>
  77   77  
  78   78  static int pcfs_open(struct vnode **, int, struct cred *, caller_context_t *ct);
  79   79  static int pcfs_close(struct vnode *, int, int, offset_t, struct cred *,
  80   80          caller_context_t *ct);
  81   81  static int pcfs_read(struct vnode *, struct uio *, int, struct cred *,
  82   82          caller_context_t *);
  83   83  static int pcfs_write(struct vnode *, struct uio *, int, struct cred *,
  84   84          caller_context_t *);
  85   85  static int pcfs_getattr(struct vnode *, struct vattr *, int, struct cred *,
  86   86          caller_context_t *ct);
  87   87  static int pcfs_setattr(struct vnode *, struct vattr *, int, struct cred *,
  88   88          caller_context_t *);
  89   89  static int pcfs_access(struct vnode *, int, int, struct cred *,
  90   90          caller_context_t *ct);
  91   91  static int pcfs_lookup(struct vnode *, char *, struct vnode **,
  92   92          struct pathname *, int, struct vnode *, struct cred *,
  93   93          caller_context_t *, int *, pathname_t *);
  94   94  static int pcfs_create(struct vnode *, char *, struct vattr *,
  95   95          enum vcexcl, int mode, struct vnode **, struct cred *, int,
  96   96          caller_context_t *, vsecattr_t *);
  97   97  static int pcfs_remove(struct vnode *, char *, struct cred *,
  98   98          caller_context_t *, int);
  99   99  static int pcfs_rename(struct vnode *, char *, struct vnode *, char *,
 100  100          struct cred *, caller_context_t *, int);
 101  101  static int pcfs_mkdir(struct vnode *, char *, struct vattr *, struct vnode **,
 102  102          struct cred *, caller_context_t *, int, vsecattr_t *);
 103  103  static int pcfs_rmdir(struct vnode *, char *, struct vnode *, struct cred *,
 104  104          caller_context_t *, int);
 105  105  static int pcfs_readdir(struct vnode *, struct uio *, struct cred *, int *,
 106  106          caller_context_t *, int);
 107  107  static int pcfs_fsync(struct vnode *, int, struct cred *, caller_context_t *);
 108  108  static void pcfs_inactive(struct vnode *, struct cred *, caller_context_t *);
 109  109  static int pcfs_fid(struct vnode *vp, struct fid *fidp, caller_context_t *);
 110  110  static int pcfs_space(struct vnode *, int, struct flock64 *, int,
 111  111          offset_t, cred_t *, caller_context_t *);
 112  112  static int pcfs_getpage(struct vnode *, offset_t, size_t, uint_t *, page_t *[],
 113  113          size_t, struct seg *, caddr_t, enum seg_rw, struct cred *,
 114  114          caller_context_t *);
 115  115  static int pcfs_getapage(struct vnode *, u_offset_t, size_t, uint_t *,
 116  116          page_t *[], size_t, struct seg *, caddr_t, enum seg_rw, struct cred *);
 117  117  static int pcfs_putpage(struct vnode *, offset_t, size_t, int, struct cred *,
 118  118          caller_context_t *);
 119  119  static int pcfs_map(struct vnode *, offset_t, struct as *, caddr_t *, size_t,
 120  120          uchar_t, uchar_t, uint_t, struct cred *, caller_context_t *);
 121  121  static int pcfs_addmap(struct vnode *, offset_t, struct as *, caddr_t,
 122  122          size_t, uchar_t, uchar_t, uint_t, struct cred *, caller_context_t *);
 123  123  static int pcfs_delmap(struct vnode *, offset_t, struct as *, caddr_t,
 124  124          size_t, uint_t, uint_t, uint_t, struct cred *, caller_context_t *);
 125  125  static int pcfs_seek(struct vnode *, offset_t, offset_t *,
 126  126          caller_context_t *);
 127  127  static int pcfs_pathconf(struct vnode *, int, ulong_t *, struct cred *,
 128  128          caller_context_t *);
 129  129  
 130  130  int pcfs_putapage(struct vnode *, page_t *, u_offset_t *, size_t *, int,
 131  131          struct cred *);
 132  132  static int rwpcp(struct pcnode *, struct uio *, enum uio_rw, int);
 133  133  static int get_long_fn_chunk(struct pcdir_lfn *ep, char *buf);
 134  134  
 135  135  extern krwlock_t pcnodes_lock;
 136  136  
 137  137  #define lround(r)       (((r)+sizeof (long long)-1)&(~(sizeof (long long)-1)))
 138  138  
 139  139  /*
 140  140   * vnode op vectors for files and directories.
 141  141   */
 142  142  struct vnodeops *pcfs_fvnodeops;
 143  143  struct vnodeops *pcfs_dvnodeops;
 144  144  
 145  145  const fs_operation_def_t pcfs_fvnodeops_template[] = {
 146  146          VOPNAME_OPEN,           { .vop_open = pcfs_open },
 147  147          VOPNAME_CLOSE,          { .vop_close = pcfs_close },
 148  148          VOPNAME_READ,           { .vop_read = pcfs_read },
 149  149          VOPNAME_WRITE,          { .vop_write = pcfs_write },
 150  150          VOPNAME_GETATTR,        { .vop_getattr = pcfs_getattr },
 151  151          VOPNAME_SETATTR,        { .vop_setattr = pcfs_setattr },
 152  152          VOPNAME_ACCESS,         { .vop_access = pcfs_access },
 153  153          VOPNAME_FSYNC,          { .vop_fsync = pcfs_fsync },
 154  154          VOPNAME_INACTIVE,       { .vop_inactive = pcfs_inactive },
 155  155          VOPNAME_FID,            { .vop_fid = pcfs_fid },
 156  156          VOPNAME_SEEK,           { .vop_seek = pcfs_seek },
 157  157          VOPNAME_SPACE,          { .vop_space = pcfs_space },
 158  158          VOPNAME_GETPAGE,        { .vop_getpage = pcfs_getpage },
 159  159          VOPNAME_PUTPAGE,        { .vop_putpage = pcfs_putpage },
 160  160          VOPNAME_MAP,            { .vop_map = pcfs_map },
 161  161          VOPNAME_ADDMAP,         { .vop_addmap = pcfs_addmap },
 162  162          VOPNAME_DELMAP,         { .vop_delmap = pcfs_delmap },
 163  163          VOPNAME_PATHCONF,       { .vop_pathconf = pcfs_pathconf },
 164  164          VOPNAME_VNEVENT,        { .vop_vnevent = fs_vnevent_support },
 165  165          NULL,                   NULL
 166  166  };
 167  167  
 168  168  const fs_operation_def_t pcfs_dvnodeops_template[] = {
 169  169          VOPNAME_OPEN,           { .vop_open = pcfs_open },
 170  170          VOPNAME_CLOSE,          { .vop_close = pcfs_close },
 171  171          VOPNAME_GETATTR,        { .vop_getattr = pcfs_getattr },
 172  172          VOPNAME_SETATTR,        { .vop_setattr = pcfs_setattr },
 173  173          VOPNAME_ACCESS,         { .vop_access = pcfs_access },
 174  174          VOPNAME_LOOKUP,         { .vop_lookup = pcfs_lookup },
 175  175          VOPNAME_CREATE,         { .vop_create = pcfs_create },
 176  176          VOPNAME_REMOVE,         { .vop_remove = pcfs_remove },
 177  177          VOPNAME_RENAME,         { .vop_rename = pcfs_rename },
 178  178          VOPNAME_MKDIR,          { .vop_mkdir = pcfs_mkdir },
 179  179          VOPNAME_RMDIR,          { .vop_rmdir = pcfs_rmdir },
 180  180          VOPNAME_READDIR,        { .vop_readdir = pcfs_readdir },
 181  181          VOPNAME_FSYNC,          { .vop_fsync = pcfs_fsync },
 182  182          VOPNAME_INACTIVE,       { .vop_inactive = pcfs_inactive },
 183  183          VOPNAME_FID,            { .vop_fid = pcfs_fid },
 184  184          VOPNAME_SEEK,           { .vop_seek = pcfs_seek },
 185  185          VOPNAME_PATHCONF,       { .vop_pathconf = pcfs_pathconf },
 186  186          VOPNAME_VNEVENT,        { .vop_vnevent = fs_vnevent_support },
 187  187          NULL,                   NULL
 188  188  };
 189  189  
 190  190  
 191  191  /*ARGSUSED*/
 192  192  static int
 193  193  pcfs_open(
 194  194          struct vnode **vpp,
 195  195          int flag,
 196  196          struct cred *cr,
 197  197          caller_context_t *ct)
 198  198  {
 199  199          return (0);
 200  200  }
 201  201  
 202  202  /*
 203  203   * files are sync'ed on close to keep floppy up to date
 204  204   */
 205  205  
 206  206  /*ARGSUSED*/
 207  207  static int
 208  208  pcfs_close(
 209  209          struct vnode *vp,
 210  210          int flag,
 211  211          int count,
 212  212          offset_t offset,
 213  213          struct cred *cr,
 214  214          caller_context_t *ct)
 215  215  {
 216  216          return (0);
 217  217  }
 218  218  
 219  219  /*ARGSUSED*/
 220  220  static int
 221  221  pcfs_read(
 222  222          struct vnode *vp,
 223  223          struct uio *uiop,
 224  224          int ioflag,
 225  225          struct cred *cr,
 226  226          struct caller_context *ct)
 227  227  {
 228  228          struct pcfs *fsp;
 229  229          struct pcnode *pcp;
 230  230          int error;
 231  231  
 232  232          fsp = VFSTOPCFS(vp->v_vfsp);
 233  233          if (error = pc_verify(fsp))
 234  234                  return (error);
 235  235          error = pc_lockfs(fsp, 0, 0);
 236  236          if (error)
 237  237                  return (error);
 238  238          if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) {
 239  239                  pc_unlockfs(fsp);
 240  240                  return (EIO);
 241  241          }
 242  242          error = rwpcp(pcp, uiop, UIO_READ, ioflag);
 243  243          if ((fsp->pcfs_vfs->vfs_flag & VFS_RDONLY) == 0) {
 244  244                  pc_mark_acc(fsp, pcp);
 245  245          }
 246  246          pc_unlockfs(fsp);
 247  247          if (error) {
 248  248                  PC_DPRINTF1(1, "pcfs_read: io error = %d\n", error);
 249  249          }
 250  250          return (error);
 251  251  }
 252  252  
 253  253  /*ARGSUSED*/
 254  254  static int
 255  255  pcfs_write(
 256  256          struct vnode *vp,
 257  257          struct uio *uiop,
 258  258          int ioflag,
 259  259          struct cred *cr,
 260  260          struct caller_context *ct)
 261  261  {
 262  262          struct pcfs *fsp;
 263  263          struct pcnode *pcp;
 264  264          int error;
 265  265  
 266  266          fsp = VFSTOPCFS(vp->v_vfsp);
 267  267          if (error = pc_verify(fsp))
 268  268                  return (error);
 269  269          error = pc_lockfs(fsp, 0, 0);
 270  270          if (error)
 271  271                  return (error);
 272  272          if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) {
 273  273                  pc_unlockfs(fsp);
 274  274                  return (EIO);
 275  275          }
 276  276          if (ioflag & FAPPEND) {
 277  277                  /*
 278  278                   * in append mode start at end of file.
 279  279                   */
 280  280                  uiop->uio_loffset = pcp->pc_size;
 281  281          }
 282  282          error = rwpcp(pcp, uiop, UIO_WRITE, ioflag);
 283  283          pcp->pc_flags |= PC_MOD;
 284  284          pc_mark_mod(fsp, pcp);
 285  285          if (ioflag & (FSYNC|FDSYNC))
 286  286                  (void) pc_nodeupdate(pcp);
 287  287  
 288  288          pc_unlockfs(fsp);
 289  289          if (error) {
 290  290                  PC_DPRINTF1(1, "pcfs_write: io error = %d\n", error);
 291  291          }
 292  292          return (error);
 293  293  }
 294  294  
 295  295  /*
 296  296   * read or write a vnode
 297  297   */
 298  298  static int
 299  299  rwpcp(
 300  300          struct pcnode *pcp,
 301  301          struct uio *uio,
 302  302          enum uio_rw rw,
 303  303          int ioflag)
 304  304  {
 305  305          struct vnode *vp = PCTOV(pcp);
 306  306          struct pcfs *fsp;
 307  307          daddr_t bn;                     /* phys block number */
 308  308          int n;
 309  309          offset_t off;
 310  310          caddr_t base;
 311  311          int mapon, pagecreate;
 312  312          int newpage;
 313  313          int error = 0;
 314  314          rlim64_t limit = uio->uio_llimit;
 315  315          int oresid = uio->uio_resid;
 316  316  
 317  317          /*
 318  318           * If the filesystem was umounted by force, return immediately.
 319  319           */
 320  320          if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
 321  321                  return (EIO);
 322  322  
 323  323          PC_DPRINTF4(5, "rwpcp pcp=%p off=%lld resid=%ld size=%u\n", (void *)pcp,
 324  324              uio->uio_loffset, uio->uio_resid, pcp->pc_size);
 325  325  
 326  326          ASSERT(rw == UIO_READ || rw == UIO_WRITE);
 327  327          ASSERT(vp->v_type == VREG);
 328  328  
 329  329          if (uio->uio_loffset >= UINT32_MAX && rw == UIO_READ) {
 330  330                  return (0);
 331  331          }
 332  332  
 333  333          if (uio->uio_loffset < 0)
 334  334                  return (EINVAL);
 335  335  
 336  336          if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T)
 337  337                  limit = MAXOFFSET_T;
 338  338  
 339  339          if (uio->uio_loffset >= limit && rw == UIO_WRITE) {
 340  340                  proc_t *p = ttoproc(curthread);
 341  341  
 342  342                  mutex_enter(&p->p_lock);
 343  343                  (void) rctl_action(rctlproc_legacy[RLIMIT_FSIZE], p->p_rctls,
 344  344                      p, RCA_UNSAFE_SIGINFO);
 345  345                  mutex_exit(&p->p_lock);
 346  346                  return (EFBIG);
 347  347          }
 348  348  
 349  349          /* the following condition will occur only for write */
 350  350  
 351  351          if (uio->uio_loffset >= UINT32_MAX)
 352  352                  return (EFBIG);
 353  353  
 354  354          if (uio->uio_resid == 0)
 355  355                  return (0);
 356  356  
 357  357          if (limit > UINT32_MAX)
 358  358                  limit = UINT32_MAX;
 359  359  
 360  360          fsp = VFSTOPCFS(vp->v_vfsp);
 361  361          if (fsp->pcfs_flags & PCFS_IRRECOV)
 362  362                  return (EIO);
 363  363  
 364  364          do {
 365  365                  /*
 366  366                   * Assignments to "n" in this block may appear
 367  367                   * to overflow in some cases.  However, after careful
 368  368                   * analysis it was determined that all assignments to
 369  369                   * "n" serve only to make "n" smaller.  Since "n"
 370  370                   * starts out as no larger than MAXBSIZE, "int" is
 371  371                   * safe.
 372  372                   */
 373  373                  off = uio->uio_loffset & MAXBMASK;
 374  374                  mapon = (int)(uio->uio_loffset & MAXBOFFSET);
 375  375                  n = MIN(MAXBSIZE - mapon, uio->uio_resid);
 376  376                  if (rw == UIO_READ) {
 377  377                          offset_t diff;
 378  378  
 379  379                          diff = pcp->pc_size - uio->uio_loffset;
 380  380                          if (diff <= 0)
 381  381                                  return (0);
 382  382                          if (diff < n)
 383  383                                  n = (int)diff;
 384  384                  }
 385  385                  /*
 386  386                   * Compare limit with the actual offset + n, not the
 387  387                   * rounded down offset "off" or we will overflow
 388  388                   * the maximum file size after all.
 389  389                   */
 390  390                  if (rw == UIO_WRITE && uio->uio_loffset + n >= limit) {
 391  391                          if (uio->uio_loffset >= limit) {
 392  392                                  error = EFBIG;
 393  393                                  break;
 394  394                          }
 395  395                          n = (int)(limit - uio->uio_loffset);
 396  396                  }
 397  397  
 398  398                  /*
 399  399                   * Touch the page and fault it in if it is not in
 400  400                   * core before segmap_getmapflt can lock it. This
 401  401                   * is to avoid the deadlock if the buffer is mapped
 402  402                   * to the same file through mmap which we want to
 403  403                   * write to.
 404  404                   */
 405  405                  uio_prefaultpages((long)n, uio);
 406  406  
 407  407                  base = segmap_getmap(segkmap, vp, (u_offset_t)off);
 408  408                  pagecreate = 0;
 409  409                  newpage = 0;
 410  410                  if (rw == UIO_WRITE) {
 411  411                          /*
 412  412                           * If PAGESIZE < MAXBSIZE, perhaps we ought to deal
 413  413                           * with one page at a time, instead of one MAXBSIZE
 414  414                           * at a time, so we can fully explore pagecreate
 415  415                           * optimization??
 416  416                           */
 417  417                          if (uio->uio_loffset + n > pcp->pc_size) {
 418  418                                  uint_t ncl, lcn;
 419  419  
 420  420                                  ncl = (uint_t)howmany((offset_t)pcp->pc_size,
 421  421                                      fsp->pcfs_clsize);
 422  422                                  if (uio->uio_loffset > pcp->pc_size &&
 423  423                                      ncl < (uint_t)howmany(uio->uio_loffset,
 424  424                                      fsp->pcfs_clsize)) {
 425  425                                          /*
 426  426                                           * Allocate and zerofill skipped
 427  427                                           * clusters. This may not be worth the
 428  428                                           * effort since a small lseek beyond
 429  429                                           * eof but still within the cluster
 430  430                                           * will not be zeroed out.
 431  431                                           */
 432  432                                          lcn = pc_lblkno(fsp, uio->uio_loffset);
 433  433                                          error = pc_balloc(pcp, (daddr_t)lcn,
 434  434                                              1, &bn);
 435  435                                          ncl = lcn + 1;
 436  436                                  }
 437  437                                  if (!error &&
 438  438                                      ncl < (uint_t)howmany(uio->uio_loffset + n,
 439  439                                      fsp->pcfs_clsize))
 440  440                                          /*
 441  441                                           * allocate clusters w/o zerofill
 442  442                                           */
 443  443                                          error = pc_balloc(pcp,
 444  444                                              (daddr_t)pc_lblkno(fsp,
 445  445                                              uio->uio_loffset + n - 1),
 446  446                                              0, &bn);
 447  447  
 448  448                                  pcp->pc_flags |= PC_CHG;
 449  449  
 450  450                                  if (error) {
 451  451                                          pc_cluster32_t ncl;
 452  452                                          int nerror;
 453  453  
 454  454                                          /*
 455  455                                           * figure out new file size from
 456  456                                           * cluster chain length. If this
 457  457                                           * is detected to loop, the chain
 458  458                                           * is corrupted and we'd better
 459  459                                           * keep our fingers off that file.
 460  460                                           */
 461  461                                          nerror = pc_fileclsize(fsp,
 462  462                                              pcp->pc_scluster, &ncl);
 463  463                                          if (nerror) {
 464  464                                                  PC_DPRINTF1(2,
 465  465                                                      "cluster chain "
 466  466                                                      "corruption, "
 467  467                                                      "scluster=%d\n",
 468  468                                                      pcp->pc_scluster);
 469  469                                                  pcp->pc_size = 0;
 470  470                                                  pcp->pc_flags |= PC_INVAL;
 471  471                                                  error = nerror;
 472  472                                                  (void) segmap_release(segkmap,
 473  473                                                      base, 0);
 474  474                                                  break;
 475  475                                          }
 476  476                                          pcp->pc_size = fsp->pcfs_clsize * ncl;
 477  477  
 478  478                                          if (error == ENOSPC &&
 479  479                                              (pcp->pc_size - uio->uio_loffset)
 480  480                                              > 0) {
 481  481                                                  PC_DPRINTF3(2, "rwpcp ENOSPC "
 482  482                                                      "off=%lld n=%d size=%d\n",
 483  483                                                      uio->uio_loffset,
 484  484                                                      n, pcp->pc_size);
 485  485                                                  n = (int)(pcp->pc_size -
 486  486                                                      uio->uio_loffset);
 487  487                                          } else {
 488  488                                                  PC_DPRINTF1(1,
 489  489                                                      "rwpcp error1=%d\n", error);
 490  490                                                  (void) segmap_release(segkmap,
 491  491                                                      base, 0);
 492  492                                                  break;
 493  493                                          }
 494  494                                  } else {
 495  495                                          pcp->pc_size =
 496  496                                              (uint_t)(uio->uio_loffset + n);
 497  497                                  }
 498  498                                  if (mapon == 0) {
 499  499                                          newpage = segmap_pagecreate(segkmap,
 500  500                                              base, (size_t)n, 0);
 501  501                                          pagecreate = 1;
 502  502                                  }
 503  503                          } else if (n == MAXBSIZE) {
 504  504                                  newpage = segmap_pagecreate(segkmap, base,
 505  505                                      (size_t)n, 0);
 506  506                                  pagecreate = 1;
 507  507                          }
 508  508                  }
 509  509                  error = uiomove(base + mapon, (size_t)n, rw, uio);
 510  510  
 511  511                  if (pagecreate && uio->uio_loffset <
 512  512                      roundup(off + mapon + n, PAGESIZE)) {
 513  513                          offset_t nzero, nmoved;
 514  514  
 515  515                          nmoved = uio->uio_loffset - (off + mapon);
 516  516                          nzero = roundup(mapon + n, PAGESIZE) - nmoved;
 517  517                          (void) kzero(base + mapon + nmoved, (size_t)nzero);
 518  518                  }
 519  519  
 520  520                  /*
 521  521                   * Unlock the pages which have been allocated by
 522  522                   * page_create_va() in segmap_pagecreate().
 523  523                   */
 524  524                  if (newpage) {
 525  525                          segmap_pageunlock(segkmap, base, (size_t)n,
 526  526                              rw == UIO_WRITE ? S_WRITE : S_READ);
 527  527                  }
 528  528  
 529  529                  if (error) {
 530  530                          PC_DPRINTF1(1, "rwpcp error2=%d\n", error);
 531  531                          /*
 532  532                           * If we failed on a write, we may have already
 533  533                           * allocated file blocks as well as pages.  It's hard
 534  534                           * to undo the block allocation, but we must be sure
 535  535                           * to invalidate any pages that may have been
 536  536                           * allocated.
 537  537                           */
 538  538                          if (rw == UIO_WRITE)
 539  539                                  (void) segmap_release(segkmap, base, SM_INVAL);
 540  540                          else
 541  541                                  (void) segmap_release(segkmap, base, 0);
 542  542                  } else {
 543  543                          uint_t flags = 0;
 544  544  
 545  545                          if (rw == UIO_READ) {
 546  546                                  if (n + mapon == MAXBSIZE ||
 547  547                                      uio->uio_loffset == pcp->pc_size)
 548  548                                          flags = SM_DONTNEED;
 549  549                          } else if (ioflag & (FSYNC|FDSYNC)) {
 550  550                                  flags = SM_WRITE;
 551  551                          } else if (n + mapon == MAXBSIZE) {
 552  552                                  flags = SM_WRITE|SM_ASYNC|SM_DONTNEED;
 553  553                          }
 554  554                          error = segmap_release(segkmap, base, flags);
 555  555                  }
 556  556  
 557  557          } while (error == 0 && uio->uio_resid > 0 && n != 0);
 558  558  
 559  559          if (oresid != uio->uio_resid)
 560  560                  error = 0;
 561  561          return (error);
 562  562  }
 563  563  
 564  564  /*ARGSUSED*/
 565  565  static int
 566  566  pcfs_getattr(
 567  567          struct vnode *vp,
 568  568          struct vattr *vap,
 569  569          int flags,
 570  570          struct cred *cr,
 571  571          caller_context_t *ct)
 572  572  {
 573  573          struct pcnode *pcp;
 574  574          struct pcfs *fsp;
 575  575          int error;
 576  576          char attr;
 577  577          struct pctime atime;
 578  578          int64_t unixtime;
 579  579  
 580  580          PC_DPRINTF1(8, "pcfs_getattr: vp=%p\n", (void *)vp);
 581  581  
 582  582          fsp = VFSTOPCFS(vp->v_vfsp);
 583  583          error = pc_lockfs(fsp, 0, 0);
 584  584          if (error)
 585  585                  return (error);
 586  586  
 587  587          /*
 588  588           * Note that we don't check for "invalid node" (PC_INVAL) here
 589  589           * only in order to make stat() succeed. We allow no I/O on such
 590  590           * a node, but do allow to check for its existence.
 591  591           */
 592  592          if ((pcp = VTOPC(vp)) == NULL) {
 593  593                  pc_unlockfs(fsp);
 594  594                  return (EIO);
 595  595          }
 596  596          /*
 597  597           * Copy from pcnode.
 598  598           */
 599  599          vap->va_type = vp->v_type;
 600  600          attr = pcp->pc_entry.pcd_attr;
 601  601          if (PCA_IS_HIDDEN(fsp, attr))
 602  602                  vap->va_mode = 0;
 603  603          else if (attr & PCA_LABEL)
 604  604                  vap->va_mode = 0444;
 605  605          else if (attr & PCA_RDONLY)
 606  606                  vap->va_mode = 0555;
 607  607          else if (fsp->pcfs_flags & PCFS_BOOTPART) {
 608  608                  vap->va_mode = 0755;
 609  609          } else {
 610  610                  vap->va_mode = 0777;
 611  611          }
 612  612  
 613  613          if (attr & PCA_DIR)
 614  614                  vap->va_mode |= S_IFDIR;
 615  615          else
 616  616                  vap->va_mode |= S_IFREG;
 617  617          if (fsp->pcfs_flags & PCFS_BOOTPART) {
 618  618                  vap->va_uid = 0;
 619  619                  vap->va_gid = 0;
 620  620          } else {
 621  621                  vap->va_uid = crgetuid(cr);
 622  622                  vap->va_gid = crgetgid(cr);
 623  623          }
 624  624          vap->va_fsid = vp->v_vfsp->vfs_dev;
 625  625          vap->va_nodeid = (ino64_t)pc_makenodeid(pcp->pc_eblkno,
 626  626              pcp->pc_eoffset, pcp->pc_entry.pcd_attr,
 627  627              pc_getstartcluster(fsp, &pcp->pc_entry), pc_direntpersec(fsp));
 628  628          vap->va_nlink = 1;
 629  629          vap->va_size = (u_offset_t)pcp->pc_size;
 630  630          vap->va_rdev = 0;
 631  631          vap->va_nblocks =
 632  632              (fsblkcnt64_t)howmany((offset_t)pcp->pc_size, DEV_BSIZE);
 633  633          vap->va_blksize = fsp->pcfs_clsize;
 634  634  
 635  635          /*
 636  636           * FAT root directories have no timestamps. In order not to return
 637  637           * "time zero" (1/1/1970), we record the time of the mount and give
 638  638           * that. This breaks less expectations.
 639  639           */
 640  640          if (vp->v_flag & VROOT) {
 641  641                  vap->va_mtime = fsp->pcfs_mounttime;
 642  642                  vap->va_atime = fsp->pcfs_mounttime;
 643  643                  vap->va_ctime = fsp->pcfs_mounttime;
 644  644                  pc_unlockfs(fsp);
 645  645                  return (0);
 646  646          }
 647  647  
 648  648          pc_pcttotv(&pcp->pc_entry.pcd_mtime, &unixtime);
 649  649          if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0) {
 650  650                  if (unixtime > INT32_MAX)
 651  651                          DTRACE_PROBE1(pcfs__mtimeclamped, int64_t, unixtime);
 652  652                  unixtime = MIN(unixtime, INT32_MAX);
 653  653          } else if (unixtime > INT32_MAX &&
 654  654              get_udatamodel() == DATAMODEL_ILP32) {
 655  655                  pc_unlockfs(fsp);
 656  656                  DTRACE_PROBE1(pcfs__mtimeoverflowed, int64_t, unixtime);
 657  657                  return (EOVERFLOW);
 658  658          }
 659  659  
 660  660          vap->va_mtime.tv_sec = (time_t)unixtime;
 661  661          vap->va_mtime.tv_nsec = 0;
 662  662  
 663  663          /*
 664  664           * FAT doesn't know about POSIX ctime.
 665  665           * Best approximation is to always set it to mtime.
 666  666           */
 667  667          vap->va_ctime = vap->va_mtime;
 668  668  
 669  669          /*
 670  670           * FAT only stores "last access date". If that's the
 671  671           * same as the date of last modification then the time
 672  672           * of last access is known. Otherwise, use midnight.
 673  673           */
 674  674          atime.pct_date = pcp->pc_entry.pcd_ladate;
 675  675          if (atime.pct_date == pcp->pc_entry.pcd_mtime.pct_date)
 676  676                  atime.pct_time = pcp->pc_entry.pcd_mtime.pct_time;
 677  677          else
 678  678                  atime.pct_time = 0;
 679  679          pc_pcttotv(&atime, &unixtime);
 680  680          if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0) {
 681  681                  if (unixtime > INT32_MAX)
 682  682                          DTRACE_PROBE1(pcfs__atimeclamped, int64_t, unixtime);
 683  683                  unixtime = MIN(unixtime, INT32_MAX);
 684  684          } else if (unixtime > INT32_MAX &&
 685  685              get_udatamodel() == DATAMODEL_ILP32) {
 686  686                  pc_unlockfs(fsp);
 687  687                  DTRACE_PROBE1(pcfs__atimeoverflowed, int64_t, unixtime);
 688  688                  return (EOVERFLOW);
 689  689          }
 690  690  
 691  691          vap->va_atime.tv_sec = (time_t)unixtime;
 692  692          vap->va_atime.tv_nsec = 0;
 693  693  
 694  694          pc_unlockfs(fsp);
 695  695          return (0);
 696  696  }
 697  697  
 698  698  
 699  699  /*ARGSUSED*/
 700  700  static int
 701  701  pcfs_setattr(
 702  702          struct vnode *vp,
 703  703          struct vattr *vap,
 704  704          int flags,
 705  705          struct cred *cr,
 706  706          caller_context_t *ct)
 707  707  {
 708  708          struct pcnode *pcp;
 709  709          mode_t mask = vap->va_mask;
 710  710          int error;
 711  711          struct pcfs *fsp;
 712  712          timestruc_t now, *timep;
 713  713  
 714  714          PC_DPRINTF2(6, "pcfs_setattr: vp=%p mask=%x\n", (void *)vp, (int)mask);
 715  715          /*
 716  716           * cannot set these attributes
 717  717           */
 718  718          if (mask & (AT_NOSET | AT_UID | AT_GID)) {
 719  719                  return (EINVAL);
 720  720          }
 721  721          /*
 722  722           * pcfs_setattr is now allowed on directories to avoid silly warnings
 723  723           * from 'tar' when it tries to set times on a directory, and console
 724  724           * printf's on the NFS server when it gets EINVAL back on such a
 725  725           * request. One possible problem with that since a directory entry
 726  726           * identifies a file, '.' and all the '..' entries in subdirectories
 727  727           * may get out of sync when the directory is updated since they're
 728  728           * treated like separate files. We could fix that by looking for
 729  729           * '.' and giving it the same attributes, and then looking for
 730  730           * all the subdirectories and updating '..', but that's pretty
 731  731           * expensive for something that doesn't seem likely to matter.
 732  732           */
 733  733          /* can't do some ops on directories anyway */
 734  734          if ((vp->v_type == VDIR) &&
 735  735              (mask & AT_SIZE)) {
 736  736                  return (EINVAL);
 737  737          }
 738  738  
 739  739          fsp = VFSTOPCFS(vp->v_vfsp);
 740  740          error = pc_lockfs(fsp, 0, 0);
 741  741          if (error)
 742  742                  return (error);
 743  743          if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) {
 744  744                  pc_unlockfs(fsp);
 745  745                  return (EIO);
 746  746          }
 747  747  
 748  748          if (fsp->pcfs_flags & PCFS_BOOTPART) {
 749  749                  if (secpolicy_pcfs_modify_bootpartition(cr) != 0) {
 750  750                          pc_unlockfs(fsp);
 751  751                          return (EACCES);
 752  752                  }
 753  753          }
 754  754  
 755  755          /*
 756  756           * Change file access modes.
 757  757           * If nobody has write permission, file is marked readonly.
 758  758           * Otherwise file is writable by anyone.
 759  759           */
 760  760          if ((mask & AT_MODE) && (vap->va_mode != (mode_t)-1)) {
 761  761                  if ((vap->va_mode & 0222) == 0)
 762  762                          pcp->pc_entry.pcd_attr |= PCA_RDONLY;
 763  763                  else
 764  764                          pcp->pc_entry.pcd_attr &= ~PCA_RDONLY;
 765  765                  pcp->pc_flags |= PC_CHG;
 766  766          }
 767  767          /*
 768  768           * Truncate file. Must have write permission.
 769  769           */
 770  770          if ((mask & AT_SIZE) && (vap->va_size != (u_offset_t)-1)) {
 771  771                  if (pcp->pc_entry.pcd_attr & PCA_RDONLY) {
 772  772                          error = EACCES;
 773  773                          goto out;
  
    | 
      ↓ open down ↓ | 
    773 lines elided | 
    
      ↑ open up ↑ | 
  
 774  774                  }
 775  775                  if (vap->va_size > UINT32_MAX) {
 776  776                          error = EFBIG;
 777  777                          goto out;
 778  778                  }
 779  779                  error = pc_truncate(pcp, (uint_t)vap->va_size);
 780  780  
 781  781                  if (error)
 782  782                          goto out;
 783  783  
 784      -                if (vap->va_size == 0)
      784 +                if (vap->va_size == 0) {
 785  785                          vnevent_truncate(vp, ct);
      786 +                } else {
      787 +                        vnevent_resize(vp, ct);
      788 +                }
 786  789          }
 787  790          /*
 788  791           * Change file modified times.
 789  792           */
 790  793          if (mask & (AT_MTIME | AT_CTIME)) {
 791  794                  /*
 792  795                   * If SysV-compatible option to set access and
 793  796                   * modified times if privileged, owner, or write access,
 794  797                   * use current time rather than va_mtime.
 795  798                   *
 796  799                   * XXX - va_mtime.tv_sec == -1 flags this.
 797  800                   */
 798  801                  timep = &vap->va_mtime;
 799  802                  if (vap->va_mtime.tv_sec == -1) {
 800  803                          gethrestime(&now);
 801  804                          timep = &now;
 802  805                  }
 803  806                  if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0 &&
 804  807                      timep->tv_sec > INT32_MAX) {
 805  808                          error = EOVERFLOW;
 806  809                          goto out;
 807  810                  }
 808  811                  error = pc_tvtopct(timep, &pcp->pc_entry.pcd_mtime);
 809  812                  if (error)
 810  813                          goto out;
 811  814                  pcp->pc_flags |= PC_CHG;
 812  815          }
 813  816          /*
 814  817           * Change file access times.
 815  818           */
 816  819          if (mask & AT_ATIME) {
 817  820                  /*
 818  821                   * If SysV-compatible option to set access and
 819  822                   * modified times if privileged, owner, or write access,
 820  823                   * use current time rather than va_mtime.
 821  824                   *
 822  825                   * XXX - va_atime.tv_sec == -1 flags this.
 823  826                   */
 824  827                  struct pctime   atime;
 825  828  
 826  829                  timep = &vap->va_atime;
 827  830                  if (vap->va_atime.tv_sec == -1) {
 828  831                          gethrestime(&now);
 829  832                          timep = &now;
 830  833                  }
 831  834                  if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0 &&
 832  835                      timep->tv_sec > INT32_MAX) {
 833  836                          error = EOVERFLOW;
 834  837                          goto out;
 835  838                  }
 836  839                  error = pc_tvtopct(timep, &atime);
 837  840                  if (error)
 838  841                          goto out;
 839  842                  pcp->pc_entry.pcd_ladate = atime.pct_date;
 840  843                  pcp->pc_flags |= PC_CHG;
 841  844          }
 842  845  out:
 843  846          pc_unlockfs(fsp);
 844  847          return (error);
 845  848  }
 846  849  
 847  850  
 848  851  /*ARGSUSED*/
 849  852  static int
 850  853  pcfs_access(
 851  854          struct vnode *vp,
 852  855          int mode,
 853  856          int flags,
 854  857          struct cred *cr,
 855  858          caller_context_t *ct)
 856  859  {
 857  860          struct pcnode *pcp;
 858  861          struct pcfs *fsp;
 859  862  
 860  863  
 861  864          fsp = VFSTOPCFS(vp->v_vfsp);
 862  865  
 863  866          if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL)
 864  867                  return (EIO);
 865  868          if ((mode & VWRITE) && (pcp->pc_entry.pcd_attr & PCA_RDONLY))
 866  869                  return (EACCES);
 867  870  
 868  871          /*
 869  872           * If this is a boot partition, privileged users have full access while
 870  873           * others have read-only access.
 871  874           */
 872  875          if (fsp->pcfs_flags & PCFS_BOOTPART) {
 873  876                  if ((mode & VWRITE) &&
 874  877                      secpolicy_pcfs_modify_bootpartition(cr) != 0)
 875  878                          return (EACCES);
 876  879          }
 877  880          return (0);
 878  881  }
 879  882  
 880  883  
 881  884  /*ARGSUSED*/
 882  885  static int
 883  886  pcfs_fsync(
 884  887          struct vnode *vp,
 885  888          int syncflag,
 886  889          struct cred *cr,
 887  890          caller_context_t *ct)
 888  891  {
 889  892          struct pcfs *fsp;
 890  893          struct pcnode *pcp;
 891  894          int error;
 892  895  
 893  896          fsp = VFSTOPCFS(vp->v_vfsp);
 894  897          if (error = pc_verify(fsp))
 895  898                  return (error);
 896  899          error = pc_lockfs(fsp, 0, 0);
 897  900          if (error)
 898  901                  return (error);
 899  902          if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) {
 900  903                  pc_unlockfs(fsp);
 901  904                  return (EIO);
 902  905          }
 903  906          rw_enter(&pcnodes_lock, RW_WRITER);
 904  907          error = pc_nodesync(pcp);
 905  908          rw_exit(&pcnodes_lock);
 906  909          pc_unlockfs(fsp);
 907  910          return (error);
 908  911  }
 909  912  
 910  913  
 911  914  /*ARGSUSED*/
 912  915  static void
 913  916  pcfs_inactive(
 914  917          struct vnode *vp,
 915  918          struct cred *cr,
 916  919          caller_context_t *ct)
 917  920  {
 918  921          struct pcnode *pcp;
 919  922          struct pcfs *fsp;
 920  923          int error;
 921  924  
 922  925          fsp = VFSTOPCFS(vp->v_vfsp);
 923  926          error = pc_lockfs(fsp, 0, 1);
 924  927  
 925  928          /*
 926  929           * If the filesystem was umounted by force, all dirty
 927  930           * pages associated with this vnode are invalidated
 928  931           * and then the vnode will be freed.
 929  932           */
 930  933          if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) {
 931  934                  pcp = VTOPC(vp);
 932  935                  if (vn_has_cached_data(vp)) {
 933  936                          (void) pvn_vplist_dirty(vp, (u_offset_t)0,
 934  937                              pcfs_putapage, B_INVAL, (struct cred *)NULL);
 935  938                  }
 936  939                  remque(pcp);
 937  940                  if (error == 0)
 938  941                          pc_unlockfs(fsp);
 939  942                  vn_free(vp);
 940  943                  kmem_free(pcp, sizeof (struct pcnode));
 941  944                  VFS_RELE(PCFSTOVFS(fsp));
 942  945                  return;
 943  946          }
 944  947  
 945  948          mutex_enter(&vp->v_lock);
 946  949          ASSERT(vp->v_count >= 1);
 947  950          if (vp->v_count > 1) {
 948  951                  vp->v_count--;  /* release our hold from vn_rele */
 949  952                  mutex_exit(&vp->v_lock);
 950  953                  pc_unlockfs(fsp);
 951  954                  return;
 952  955          }
 953  956          mutex_exit(&vp->v_lock);
 954  957  
 955  958          /*
 956  959           * Check again to confirm that no intervening I/O error
 957  960           * with a subsequent pc_diskchanged() call has released
 958  961           * the pcnode. If it has then release the vnode as above.
 959  962           */
 960  963          pcp = VTOPC(vp);
 961  964          if (pcp == NULL || pcp->pc_flags & PC_INVAL) {
 962  965                  if (vn_has_cached_data(vp))
 963  966                          (void) pvn_vplist_dirty(vp, (u_offset_t)0,
 964  967                              pcfs_putapage, B_INVAL | B_TRUNC,
 965  968                              (struct cred *)NULL);
 966  969          }
 967  970  
 968  971          if (pcp == NULL) {
 969  972                  vn_free(vp);
 970  973          } else {
 971  974                  pc_rele(pcp);
 972  975          }
 973  976  
 974  977          if (!error)
 975  978                  pc_unlockfs(fsp);
 976  979  }
 977  980  
 978  981  /*ARGSUSED*/
 979  982  static int
 980  983  pcfs_lookup(
 981  984          struct vnode *dvp,
 982  985          char *nm,
 983  986          struct vnode **vpp,
 984  987          struct pathname *pnp,
 985  988          int flags,
 986  989          struct vnode *rdir,
 987  990          struct cred *cr,
 988  991          caller_context_t *ct,
 989  992          int *direntflags,
 990  993          pathname_t *realpnp)
 991  994  {
 992  995          struct pcfs *fsp;
 993  996          struct pcnode *pcp;
 994  997          int error;
 995  998  
 996  999          /*
 997 1000           * If the filesystem was umounted by force, return immediately.
 998 1001           */
 999 1002          if (dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
1000 1003                  return (EIO);
1001 1004  
1002 1005          /*
1003 1006           * verify that the dvp is still valid on the disk
1004 1007           */
1005 1008          fsp = VFSTOPCFS(dvp->v_vfsp);
1006 1009          if (error = pc_verify(fsp))
1007 1010                  return (error);
1008 1011          error = pc_lockfs(fsp, 0, 0);
1009 1012          if (error)
1010 1013                  return (error);
1011 1014          if (VTOPC(dvp) == NULL || VTOPC(dvp)->pc_flags & PC_INVAL) {
1012 1015                  pc_unlockfs(fsp);
1013 1016                  return (EIO);
1014 1017          }
1015 1018          /*
1016 1019           * Null component name is a synonym for directory being searched.
1017 1020           */
1018 1021          if (*nm == '\0') {
1019 1022                  VN_HOLD(dvp);
1020 1023                  *vpp = dvp;
1021 1024                  pc_unlockfs(fsp);
1022 1025                  return (0);
1023 1026          }
1024 1027  
1025 1028          error = pc_dirlook(VTOPC(dvp), nm, &pcp);
1026 1029          if (!error) {
1027 1030                  *vpp = PCTOV(pcp);
1028 1031                  pcp->pc_flags |= PC_EXTERNAL;
1029 1032          }
1030 1033          pc_unlockfs(fsp);
1031 1034          return (error);
1032 1035  }
1033 1036  
1034 1037  
1035 1038  /*ARGSUSED*/
1036 1039  static int
1037 1040  pcfs_create(
1038 1041          struct vnode *dvp,
1039 1042          char *nm,
1040 1043          struct vattr *vap,
1041 1044          enum vcexcl exclusive,
1042 1045          int mode,
1043 1046          struct vnode **vpp,
1044 1047          struct cred *cr,
1045 1048          int flag,
1046 1049          caller_context_t *ct,
1047 1050          vsecattr_t *vsecp)
1048 1051  {
1049 1052          int error;
1050 1053          struct pcnode *pcp;
1051 1054          struct vnode *vp;
1052 1055          struct pcfs *fsp;
1053 1056  
1054 1057          /*
1055 1058           * can't create directories. use pcfs_mkdir.
1056 1059           * can't create anything other than files.
1057 1060           */
1058 1061          if (vap->va_type == VDIR)
1059 1062                  return (EISDIR);
1060 1063          else if (vap->va_type != VREG)
1061 1064                  return (EINVAL);
1062 1065  
1063 1066          pcp = NULL;
1064 1067          fsp = VFSTOPCFS(dvp->v_vfsp);
1065 1068          error = pc_lockfs(fsp, 0, 0);
1066 1069          if (error)
1067 1070                  return (error);
1068 1071          if (VTOPC(dvp) == NULL || VTOPC(dvp)->pc_flags & PC_INVAL) {
1069 1072                  pc_unlockfs(fsp);
1070 1073                  return (EIO);
1071 1074          }
1072 1075  
1073 1076          if (fsp->pcfs_flags & PCFS_BOOTPART) {
1074 1077                  if (secpolicy_pcfs_modify_bootpartition(cr) != 0) {
1075 1078                          pc_unlockfs(fsp);
1076 1079                          return (EACCES);
1077 1080                  }
1078 1081          }
1079 1082  
1080 1083          if (*nm == '\0') {
1081 1084                  /*
1082 1085                   * Null component name refers to the directory itself.
1083 1086                   */
1084 1087                  VN_HOLD(dvp);
1085 1088                  pcp = VTOPC(dvp);
1086 1089                  error = EEXIST;
1087 1090          } else {
1088 1091                  error = pc_direnter(VTOPC(dvp), nm, vap, &pcp);
1089 1092          }
1090 1093          /*
1091 1094           * if file exists and this is a nonexclusive create,
1092 1095           * check for access permissions
1093 1096           */
1094 1097          if (error == EEXIST) {
1095 1098                  vp = PCTOV(pcp);
1096 1099                  if (exclusive == NONEXCL) {
1097 1100                          if (vp->v_type == VDIR) {
1098 1101                                  error = EISDIR;
1099 1102                          } else if (mode) {
1100 1103                                  error = pcfs_access(PCTOV(pcp), mode, 0,
1101 1104                                      cr, ct);
1102 1105                          } else {
1103 1106                                  error = 0;
1104 1107                          }
1105 1108                  }
1106 1109                  if (error) {
1107 1110                          VN_RELE(PCTOV(pcp));
1108 1111                  } else if ((vp->v_type == VREG) && (vap->va_mask & AT_SIZE) &&
1109 1112                      (vap->va_size == 0)) {
1110 1113                          error = pc_truncate(pcp, 0L);
1111 1114                          if (error) {
1112 1115                                  VN_RELE(PCTOV(pcp));
1113 1116                          } else {
1114 1117                                  vnevent_create(PCTOV(pcp), ct);
1115 1118                          }
1116 1119                  }
1117 1120          }
1118 1121          if (error) {
1119 1122                  pc_unlockfs(fsp);
1120 1123                  return (error);
1121 1124          }
1122 1125          *vpp = PCTOV(pcp);
1123 1126          pcp->pc_flags |= PC_EXTERNAL;
1124 1127          pc_unlockfs(fsp);
1125 1128          return (error);
1126 1129  }
1127 1130  
1128 1131  /*ARGSUSED*/
1129 1132  static int
1130 1133  pcfs_remove(
1131 1134          struct vnode *vp,
1132 1135          char *nm,
1133 1136          struct cred *cr,
1134 1137          caller_context_t *ct,
1135 1138          int flags)
1136 1139  {
1137 1140          struct pcfs *fsp;
1138 1141          struct pcnode *pcp;
1139 1142          int error;
1140 1143  
1141 1144          fsp = VFSTOPCFS(vp->v_vfsp);
1142 1145          if (error = pc_verify(fsp))
1143 1146                  return (error);
1144 1147          error = pc_lockfs(fsp, 0, 0);
1145 1148          if (error)
1146 1149                  return (error);
1147 1150          if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) {
1148 1151                  pc_unlockfs(fsp);
1149 1152                  return (EIO);
1150 1153          }
1151 1154          if (fsp->pcfs_flags & PCFS_BOOTPART) {
1152 1155                  if (secpolicy_pcfs_modify_bootpartition(cr) != 0) {
1153 1156                          pc_unlockfs(fsp);
1154 1157                          return (EACCES);
1155 1158                  }
1156 1159          }
1157 1160          error = pc_dirremove(pcp, nm, (struct vnode *)0, VREG, ct);
1158 1161          pc_unlockfs(fsp);
1159 1162          return (error);
1160 1163  }
1161 1164  
1162 1165  /*
1163 1166   * Rename a file or directory
1164 1167   * This rename is restricted to only rename files within a directory.
1165 1168   * XX should make rename more general
1166 1169   */
1167 1170  /*ARGSUSED*/
1168 1171  static int
1169 1172  pcfs_rename(
1170 1173          struct vnode *sdvp,             /* old (source) parent vnode */
1171 1174          char *snm,                      /* old (source) entry name */
1172 1175          struct vnode *tdvp,             /* new (target) parent vnode */
1173 1176          char *tnm,                      /* new (target) entry name */
1174 1177          struct cred *cr,
1175 1178          caller_context_t *ct,
1176 1179          int flags)
1177 1180  {
1178 1181          struct pcfs *fsp;
1179 1182          struct pcnode *dp;      /* parent pcnode */
1180 1183          struct pcnode *tdp;
1181 1184          int error;
1182 1185  
1183 1186          fsp = VFSTOPCFS(sdvp->v_vfsp);
1184 1187          if (error = pc_verify(fsp))
1185 1188                  return (error);
1186 1189  
1187 1190          /*
1188 1191           * make sure we can muck with this directory.
1189 1192           */
1190 1193          error = pcfs_access(sdvp, VWRITE, 0, cr, ct);
1191 1194          if (error) {
1192 1195                  return (error);
1193 1196          }
1194 1197          error = pc_lockfs(fsp, 0, 0);
1195 1198          if (error)
1196 1199                  return (error);
1197 1200          if (((dp = VTOPC(sdvp)) == NULL) || ((tdp = VTOPC(tdvp)) == NULL) ||
1198 1201              (dp->pc_flags & PC_INVAL) || (tdp->pc_flags & PC_INVAL)) {
1199 1202                  pc_unlockfs(fsp);
1200 1203                  return (EIO);
1201 1204          }
1202 1205          error = pc_rename(dp, tdp, snm, tnm, ct);
1203 1206          pc_unlockfs(fsp);
1204 1207          return (error);
1205 1208  }
1206 1209  
1207 1210  /*ARGSUSED*/
1208 1211  static int
1209 1212  pcfs_mkdir(
1210 1213          struct vnode *dvp,
1211 1214          char *nm,
1212 1215          struct vattr *vap,
1213 1216          struct vnode **vpp,
1214 1217          struct cred *cr,
1215 1218          caller_context_t *ct,
1216 1219          int flags,
1217 1220          vsecattr_t *vsecp)
1218 1221  {
1219 1222          struct pcfs *fsp;
1220 1223          struct pcnode *pcp;
1221 1224          int error;
1222 1225  
1223 1226          fsp = VFSTOPCFS(dvp->v_vfsp);
1224 1227          if (error = pc_verify(fsp))
1225 1228                  return (error);
1226 1229          error = pc_lockfs(fsp, 0, 0);
1227 1230          if (error)
1228 1231                  return (error);
1229 1232          if (VTOPC(dvp) == NULL || VTOPC(dvp)->pc_flags & PC_INVAL) {
1230 1233                  pc_unlockfs(fsp);
1231 1234                  return (EIO);
1232 1235          }
1233 1236  
1234 1237          if (fsp->pcfs_flags & PCFS_BOOTPART) {
1235 1238                  if (secpolicy_pcfs_modify_bootpartition(cr) != 0) {
1236 1239                          pc_unlockfs(fsp);
1237 1240                          return (EACCES);
1238 1241                  }
1239 1242          }
1240 1243  
1241 1244          error = pc_direnter(VTOPC(dvp), nm, vap, &pcp);
1242 1245  
1243 1246          if (!error) {
1244 1247                  pcp -> pc_flags |= PC_EXTERNAL;
1245 1248                  *vpp = PCTOV(pcp);
1246 1249          } else if (error == EEXIST) {
1247 1250                  VN_RELE(PCTOV(pcp));
1248 1251          }
1249 1252          pc_unlockfs(fsp);
1250 1253          return (error);
1251 1254  }
1252 1255  
1253 1256  /*ARGSUSED*/
1254 1257  static int
1255 1258  pcfs_rmdir(
1256 1259          struct vnode *dvp,
1257 1260          char *nm,
1258 1261          struct vnode *cdir,
1259 1262          struct cred *cr,
1260 1263          caller_context_t *ct,
1261 1264          int flags)
1262 1265  {
1263 1266          struct pcfs *fsp;
1264 1267          struct pcnode *pcp;
1265 1268          int error;
1266 1269  
1267 1270          fsp = VFSTOPCFS(dvp -> v_vfsp);
1268 1271          if (error = pc_verify(fsp))
1269 1272                  return (error);
1270 1273          if (error = pc_lockfs(fsp, 0, 0))
1271 1274                  return (error);
1272 1275  
1273 1276          if ((pcp = VTOPC(dvp)) == NULL || pcp->pc_flags & PC_INVAL) {
1274 1277                  pc_unlockfs(fsp);
1275 1278                  return (EIO);
1276 1279          }
1277 1280  
1278 1281          if (fsp->pcfs_flags & PCFS_BOOTPART) {
1279 1282                  if (secpolicy_pcfs_modify_bootpartition(cr) != 0) {
1280 1283                          pc_unlockfs(fsp);
1281 1284                          return (EACCES);
1282 1285                  }
1283 1286          }
1284 1287  
1285 1288          error = pc_dirremove(pcp, nm, cdir, VDIR, ct);
1286 1289          pc_unlockfs(fsp);
1287 1290          return (error);
1288 1291  }
1289 1292  
1290 1293  /*
1291 1294   * read entries in a directory.
1292 1295   * we must convert pc format to unix format
1293 1296   */
1294 1297  
1295 1298  /*ARGSUSED*/
1296 1299  static int
1297 1300  pcfs_readdir(
1298 1301          struct vnode *dvp,
1299 1302          struct uio *uiop,
1300 1303          struct cred *cr,
1301 1304          int *eofp,
1302 1305          caller_context_t *ct,
1303 1306          int flags)
1304 1307  {
1305 1308          struct pcnode *pcp;
1306 1309          struct pcfs *fsp;
1307 1310          struct pcdir *ep;
1308 1311          struct buf *bp = NULL;
1309 1312          offset_t offset;
1310 1313          int boff;
1311 1314          struct pc_dirent lbp;
1312 1315          struct pc_dirent *ld = &lbp;
1313 1316          int error;
1314 1317  
1315 1318          /*
1316 1319           * If the filesystem was umounted by force, return immediately.
1317 1320           */
1318 1321          if (dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
1319 1322                  return (EIO);
1320 1323  
1321 1324          if ((uiop->uio_iovcnt != 1) ||
1322 1325              (uiop->uio_loffset % sizeof (struct pcdir)) != 0) {
1323 1326                  return (EINVAL);
1324 1327          }
1325 1328          fsp = VFSTOPCFS(dvp->v_vfsp);
1326 1329          /*
1327 1330           * verify that the dp is still valid on the disk
1328 1331           */
1329 1332          if (error = pc_verify(fsp)) {
1330 1333                  return (error);
1331 1334          }
1332 1335          error = pc_lockfs(fsp, 0, 0);
1333 1336          if (error)
1334 1337                  return (error);
1335 1338          if ((pcp = VTOPC(dvp)) == NULL || pcp->pc_flags & PC_INVAL) {
1336 1339                  pc_unlockfs(fsp);
1337 1340                  return (EIO);
1338 1341          }
1339 1342  
1340 1343          bzero(ld, sizeof (*ld));
1341 1344  
1342 1345          if (eofp != NULL)
1343 1346                  *eofp = 0;
1344 1347          offset = uiop->uio_loffset;
1345 1348  
1346 1349          if (dvp->v_flag & VROOT) {
1347 1350                  /*
1348 1351                   * kludge up entries for "." and ".." in the root.
1349 1352                   */
1350 1353                  if (offset == 0) {
1351 1354                          (void) strcpy(ld->d_name, ".");
1352 1355                          ld->d_reclen = DIRENT64_RECLEN(1);
1353 1356                          ld->d_off = (off64_t)sizeof (struct pcdir);
1354 1357                          ld->d_ino = (ino64_t)UINT_MAX;
1355 1358                          if (ld->d_reclen > uiop->uio_resid) {
1356 1359                                  pc_unlockfs(fsp);
1357 1360                                  return (ENOSPC);
1358 1361                          }
1359 1362                          (void) uiomove(ld, ld->d_reclen, UIO_READ, uiop);
1360 1363                          uiop->uio_loffset = ld->d_off;
1361 1364                          offset = uiop->uio_loffset;
1362 1365                  }
1363 1366                  if (offset == sizeof (struct pcdir)) {
1364 1367                          (void) strcpy(ld->d_name, "..");
1365 1368                          ld->d_reclen = DIRENT64_RECLEN(2);
1366 1369                          if (ld->d_reclen > uiop->uio_resid) {
1367 1370                                  pc_unlockfs(fsp);
1368 1371                                  return (ENOSPC);
1369 1372                          }
1370 1373                          ld->d_off = (off64_t)(uiop->uio_loffset +
1371 1374                              sizeof (struct pcdir));
1372 1375                          ld->d_ino = (ino64_t)UINT_MAX;
1373 1376                          (void) uiomove(ld, ld->d_reclen, UIO_READ, uiop);
1374 1377                          uiop->uio_loffset = ld->d_off;
1375 1378                          offset = uiop->uio_loffset;
1376 1379                  }
1377 1380                  offset -= 2 * sizeof (struct pcdir);
1378 1381                  /* offset now has the real offset value into directory file */
1379 1382          }
1380 1383  
1381 1384          for (;;) {
1382 1385                  boff = pc_blkoff(fsp, offset);
1383 1386                  if (boff == 0 || bp == NULL || boff >= bp->b_bcount) {
1384 1387                          if (bp != NULL) {
1385 1388                                  brelse(bp);
1386 1389                                  bp = NULL;
1387 1390                          }
1388 1391                          error = pc_blkatoff(pcp, offset, &bp, &ep);
1389 1392                          if (error) {
1390 1393                                  if (error == ENOENT) {
1391 1394                                          error = 0;
1392 1395                                          if (eofp)
1393 1396                                                  *eofp = 1;
1394 1397                                  }
1395 1398                                  break;
1396 1399                          }
1397 1400                  }
1398 1401                  if (ep->pcd_filename[0] == PCD_UNUSED) {
1399 1402                          if (eofp)
1400 1403                                  *eofp = 1;
1401 1404                          break;
1402 1405                  }
1403 1406                  /*
1404 1407                   * Don't display label because it may contain funny characters.
1405 1408                   */
1406 1409                  if (ep->pcd_filename[0] == PCD_ERASED) {
1407 1410                          uiop->uio_loffset += sizeof (struct pcdir);
1408 1411                          offset += sizeof (struct pcdir);
1409 1412                          ep++;
1410 1413                          continue;
1411 1414                  }
1412 1415                  if (PCDL_IS_LFN(ep)) {
1413 1416                          if (pc_read_long_fn(dvp, uiop, ld, &ep, &offset, &bp) !=
1414 1417                              0)
1415 1418                                  break;
1416 1419                          continue;
1417 1420                  }
1418 1421  
1419 1422                  if (pc_read_short_fn(dvp, uiop, ld, &ep, &offset, &bp) != 0)
1420 1423                          break;
1421 1424          }
1422 1425          if (bp)
1423 1426                  brelse(bp);
1424 1427          pc_unlockfs(fsp);
1425 1428          return (error);
1426 1429  }
1427 1430  
1428 1431  
1429 1432  /*
1430 1433   * Called from pvn_getpages to get a particular page.  When we are called
1431 1434   * the pcfs is already locked.
1432 1435   */
1433 1436  /*ARGSUSED*/
1434 1437  static int
1435 1438  pcfs_getapage(
1436 1439          struct vnode *vp,
1437 1440          u_offset_t off,
1438 1441          size_t len,
1439 1442          uint_t *protp,
1440 1443          page_t *pl[],           /* NULL if async IO is requested */
1441 1444          size_t plsz,
1442 1445          struct seg *seg,
1443 1446          caddr_t addr,
1444 1447          enum seg_rw rw,
1445 1448          struct cred *cr)
1446 1449  {
1447 1450          struct pcnode *pcp;
1448 1451          struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp);
1449 1452          struct vnode *devvp;
1450 1453          page_t *pp;
1451 1454          page_t *pagefound;
1452 1455          int err;
1453 1456  
1454 1457          /*
1455 1458           * If the filesystem was umounted by force, return immediately.
1456 1459           */
1457 1460          if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
1458 1461                  return (EIO);
1459 1462  
1460 1463          PC_DPRINTF3(5, "pcfs_getapage: vp=%p off=%lld len=%lu\n",
1461 1464              (void *)vp, off, len);
1462 1465  
1463 1466          if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL)
1464 1467                  return (EIO);
1465 1468          devvp = fsp->pcfs_devvp;
1466 1469  
1467 1470          /* pcfs doesn't do readaheads */
1468 1471          if (pl == NULL)
1469 1472                  return (0);
1470 1473  
1471 1474          pl[0] = NULL;
1472 1475          err = 0;
1473 1476          /*
1474 1477           * If the accessed time on the pcnode has not already been
1475 1478           * set elsewhere (e.g. for read/setattr) we set the time now.
1476 1479           * This gives us approximate modified times for mmap'ed files
1477 1480           * which are accessed via loads in the user address space.
1478 1481           */
1479 1482          if ((pcp->pc_flags & PC_ACC) == 0 &&
1480 1483              ((fsp->pcfs_vfs->vfs_flag & VFS_RDONLY) == 0)) {
1481 1484                  pc_mark_acc(fsp, pcp);
1482 1485          }
1483 1486  reread:
1484 1487          if ((pagefound = page_exists(vp, off)) == NULL) {
1485 1488                  /*
1486 1489                   * Need to really do disk IO to get the page(s).
1487 1490                   */
1488 1491                  struct buf *bp;
1489 1492                  daddr_t lbn, bn;
1490 1493                  u_offset_t io_off;
1491 1494                  size_t io_len;
1492 1495                  u_offset_t lbnoff, xferoffset;
1493 1496                  u_offset_t pgoff;
1494 1497                  uint_t  xfersize;
1495 1498                  int err1;
1496 1499  
1497 1500                  lbn = pc_lblkno(fsp, off);
1498 1501                  lbnoff = off & ~(fsp->pcfs_clsize - 1);
1499 1502                  xferoffset = off & ~(fsp->pcfs_secsize - 1);
1500 1503  
1501 1504                  pp = pvn_read_kluster(vp, off, seg, addr, &io_off, &io_len,
1502 1505                      off, (size_t)MIN(pc_blksize(fsp, pcp, off), PAGESIZE), 0);
1503 1506                  if (pp == NULL)
1504 1507                          /*
1505 1508                           * XXX - If pcfs is made MT-hot, this should go
1506 1509                           * back to reread.
1507 1510                           */
1508 1511                          panic("pcfs_getapage pvn_read_kluster");
1509 1512  
1510 1513                  for (pgoff = 0; pgoff < PAGESIZE && xferoffset < pcp->pc_size;
1511 1514                      pgoff += xfersize,
1512 1515                      lbn +=  howmany(xfersize, fsp->pcfs_clsize),
1513 1516                      lbnoff += xfersize, xferoffset += xfersize) {
1514 1517                          /*
1515 1518                           * read as many contiguous blocks as possible to
1516 1519                           * fill this page
1517 1520                           */
1518 1521                          xfersize = PAGESIZE - pgoff;
1519 1522                          err1 = pc_bmap(pcp, lbn, &bn, &xfersize);
1520 1523                          if (err1) {
1521 1524                                  PC_DPRINTF1(1, "pc_getapage err=%d", err1);
1522 1525                                  err = err1;
1523 1526                                  goto out;
1524 1527                          }
1525 1528                          bp = pageio_setup(pp, xfersize, devvp, B_READ);
1526 1529                          bp->b_edev = devvp->v_rdev;
1527 1530                          bp->b_dev = cmpdev(devvp->v_rdev);
1528 1531                          bp->b_blkno = bn + btodt(xferoffset - lbnoff);
1529 1532                          bp->b_un.b_addr = (caddr_t)(uintptr_t)pgoff;
1530 1533                          bp->b_file = vp;
1531 1534                          bp->b_offset = (offset_t)(off + pgoff);
1532 1535  
1533 1536                          (void) bdev_strategy(bp);
1534 1537  
1535 1538                          lwp_stat_update(LWP_STAT_INBLK, 1);
1536 1539  
1537 1540                          if (err == 0)
1538 1541                                  err = biowait(bp);
1539 1542                          else
1540 1543                                  (void) biowait(bp);
1541 1544                          pageio_done(bp);
1542 1545                          if (err)
1543 1546                                  goto out;
1544 1547                  }
1545 1548                  if (pgoff < PAGESIZE) {
1546 1549                          pagezero(pp->p_prev, pgoff, PAGESIZE - pgoff);
1547 1550                  }
1548 1551                  pvn_plist_init(pp, pl, plsz, off, io_len, rw);
1549 1552          }
1550 1553  out:
1551 1554          if (err) {
1552 1555                  if (pp != NULL)
1553 1556                          pvn_read_done(pp, B_ERROR);
1554 1557                  return (err);
1555 1558          }
1556 1559  
1557 1560          if (pagefound) {
1558 1561                  /*
1559 1562                   * Page exists in the cache, acquire the "shared"
1560 1563                   * lock.  If this fails, go back to reread.
1561 1564                   */
1562 1565                  if ((pp = page_lookup(vp, off, SE_SHARED)) == NULL) {
1563 1566                          goto reread;
1564 1567                  }
1565 1568                  pl[0] = pp;
1566 1569                  pl[1] = NULL;
1567 1570          }
1568 1571          return (err);
1569 1572  }
1570 1573  
1571 1574  /*
1572 1575   * Return all the pages from [off..off+len] in given file
1573 1576   */
1574 1577  /* ARGSUSED */
1575 1578  static int
1576 1579  pcfs_getpage(
1577 1580          struct vnode *vp,
1578 1581          offset_t off,
1579 1582          size_t len,
1580 1583          uint_t *protp,
1581 1584          page_t *pl[],
1582 1585          size_t plsz,
1583 1586          struct seg *seg,
1584 1587          caddr_t addr,
1585 1588          enum seg_rw rw,
1586 1589          struct cred *cr,
1587 1590          caller_context_t *ct)
1588 1591  {
1589 1592          struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp);
1590 1593          int err;
1591 1594  
1592 1595          PC_DPRINTF0(6, "pcfs_getpage\n");
1593 1596          if (err = pc_verify(fsp))
1594 1597                  return (err);
1595 1598          if (vp->v_flag & VNOMAP)
1596 1599                  return (ENOSYS);
1597 1600          ASSERT(off <= UINT32_MAX);
1598 1601          err = pc_lockfs(fsp, 0, 0);
1599 1602          if (err)
1600 1603                  return (err);
1601 1604          if (protp != NULL)
1602 1605                  *protp = PROT_ALL;
1603 1606  
1604 1607          ASSERT((off & PAGEOFFSET) == 0);
1605 1608          err = pvn_getpages(pcfs_getapage, vp, off, len, protp, pl, plsz,
1606 1609              seg, addr, rw, cr);
1607 1610  
1608 1611          pc_unlockfs(fsp);
1609 1612          return (err);
1610 1613  }
1611 1614  
1612 1615  
1613 1616  /*
1614 1617   * Flags are composed of {B_INVAL, B_FREE, B_DONTNEED, B_FORCE}
1615 1618   * If len == 0, do from off to EOF.
1616 1619   *
1617 1620   * The normal cases should be len == 0 & off == 0 (entire vp list),
1618 1621   * len == MAXBSIZE (from segmap_release actions), and len == PAGESIZE
1619 1622   * (from pageout).
1620 1623   *
1621 1624   */
1622 1625  /*ARGSUSED*/
1623 1626  static int
1624 1627  pcfs_putpage(
1625 1628          struct vnode *vp,
1626 1629          offset_t off,
1627 1630          size_t len,
1628 1631          int flags,
1629 1632          struct cred *cr,
1630 1633          caller_context_t *ct)
1631 1634  {
1632 1635          struct pcnode *pcp;
1633 1636          page_t *pp;
1634 1637          struct pcfs *fsp;
1635 1638          u_offset_t io_off;
1636 1639          size_t io_len;
1637 1640          offset_t eoff;
1638 1641          int err;
1639 1642  
1640 1643          /*
1641 1644           * If the filesystem was umounted by force, return immediately.
1642 1645           */
1643 1646          if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
1644 1647                  return (EIO);
1645 1648  
1646 1649          PC_DPRINTF1(6, "pcfs_putpage vp=0x%p\n", (void *)vp);
1647 1650          if (vp->v_flag & VNOMAP)
1648 1651                  return (ENOSYS);
1649 1652  
1650 1653          fsp = VFSTOPCFS(vp->v_vfsp);
1651 1654  
1652 1655          if (err = pc_verify(fsp))
1653 1656                  return (err);
1654 1657          if ((pcp = VTOPC(vp)) == NULL) {
1655 1658                  PC_DPRINTF1(3, "pcfs_putpage NULL vp=0x%p\n", (void *)vp);
1656 1659                  return (EIO);
1657 1660          }
1658 1661          if (pcp->pc_flags & PC_INVAL)
1659 1662                  return (EIO);
1660 1663  
1661 1664          if (curproc == proc_pageout) {
1662 1665                  /*
1663 1666                   * XXX - This is a quick hack to avoid blocking
1664 1667                   * pageout. Also to avoid pcfs_getapage deadlocking
1665 1668                   * with putpage when memory is running out,
1666 1669                   * since we only have one global lock and we don't
1667 1670                   * support async putpage.
1668 1671                   * It should be fixed someday.
1669 1672                   *
1670 1673                   * Interestingly, this used to be a test of NOMEMWAIT().
1671 1674                   * We only ever got here once pcfs started supporting
1672 1675                   * NFS sharing, and then only because the NFS server
1673 1676                   * threads seem to do writes in sched's process context.
1674 1677                   * Since everyone else seems to just care about pageout,
1675 1678                   * the test was changed to look for pageout directly.
1676 1679                   */
1677 1680                  return (ENOMEM);
1678 1681          }
1679 1682  
1680 1683          ASSERT(off <= UINT32_MAX);
1681 1684  
1682 1685          flags &= ~B_ASYNC;      /* XXX should fix this later */
1683 1686  
1684 1687          err = pc_lockfs(fsp, 0, 0);
1685 1688          if (err)
1686 1689                  return (err);
1687 1690          if (!vn_has_cached_data(vp) || off >= pcp->pc_size) {
1688 1691                  pc_unlockfs(fsp);
1689 1692                  return (0);
1690 1693          }
1691 1694  
1692 1695          if (len == 0) {
1693 1696                  /*
1694 1697                   * Search the entire vp list for pages >= off
1695 1698                   */
1696 1699                  err = pvn_vplist_dirty(vp, off,
1697 1700                      pcfs_putapage, flags, cr);
1698 1701          } else {
1699 1702                  eoff = off + len;
1700 1703  
1701 1704                  for (io_off = off; io_off < eoff &&
1702 1705                      io_off < pcp->pc_size; io_off += io_len) {
1703 1706                          /*
1704 1707                           * If we are not invalidating, synchronously
1705 1708                           * freeing or writing pages use the routine
1706 1709                           * page_lookup_nowait() to prevent reclaiming
1707 1710                           * them from the free list.
1708 1711                           */
1709 1712                          if ((flags & B_INVAL) || ((flags & B_ASYNC) == 0)) {
1710 1713                                  pp = page_lookup(vp, io_off,
1711 1714                                      (flags & (B_INVAL | B_FREE)) ?
1712 1715                                      SE_EXCL : SE_SHARED);
1713 1716                          } else {
1714 1717                                  pp = page_lookup_nowait(vp, io_off,
1715 1718                                      (flags & B_FREE) ? SE_EXCL : SE_SHARED);
1716 1719                          }
1717 1720  
1718 1721                          if (pp == NULL || pvn_getdirty(pp, flags) == 0)
1719 1722                                  io_len = PAGESIZE;
1720 1723                          else {
1721 1724                                  err = pcfs_putapage(vp, pp, &io_off, &io_len,
1722 1725                                      flags, cr);
1723 1726                                  if (err != 0)
1724 1727                                          break;
1725 1728                                  /*
1726 1729                                   * "io_off" and "io_len" are returned as
1727 1730                                   * the range of pages we actually wrote.
1728 1731                                   * This allows us to skip ahead more quickly
1729 1732                                   * since several pages may've been dealt
1730 1733                                   * with by this iteration of the loop.
1731 1734                                   */
1732 1735                          }
1733 1736                  }
1734 1737          }
1735 1738          if (err == 0 && (flags & B_INVAL) &&
1736 1739              off == 0 && len == 0 && vn_has_cached_data(vp)) {
1737 1740                  /*
1738 1741                   * If doing "invalidation", make sure that
1739 1742                   * all pages on the vnode list are actually
1740 1743                   * gone.
1741 1744                   */
1742 1745                  cmn_err(CE_PANIC,
1743 1746                      "pcfs_putpage: B_INVAL, pages not gone");
1744 1747          } else if (err) {
1745 1748                  PC_DPRINTF1(1, "pcfs_putpage err=%d\n", err);
1746 1749          }
1747 1750          pc_unlockfs(fsp);
1748 1751          return (err);
1749 1752  }
1750 1753  
1751 1754  /*
1752 1755   * Write out a single page, possibly klustering adjacent dirty pages.
1753 1756   */
1754 1757  /*ARGSUSED*/
1755 1758  int
1756 1759  pcfs_putapage(
1757 1760          struct vnode *vp,
1758 1761          page_t *pp,
1759 1762          u_offset_t *offp,
1760 1763          size_t *lenp,
1761 1764          int flags,
1762 1765          struct cred *cr)
1763 1766  {
1764 1767          struct pcnode *pcp;
1765 1768          struct pcfs *fsp;
1766 1769          struct vnode *devvp;
1767 1770          size_t io_len;
1768 1771          daddr_t bn;
1769 1772          u_offset_t lbn, lbnoff, xferoffset;
1770 1773          uint_t pgoff, xfersize;
1771 1774          int err = 0;
1772 1775          u_offset_t io_off;
1773 1776  
1774 1777          pcp = VTOPC(vp);
1775 1778          fsp = VFSTOPCFS(vp->v_vfsp);
1776 1779          devvp = fsp->pcfs_devvp;
1777 1780  
1778 1781          /*
1779 1782           * If the modified time on the inode has not already been
1780 1783           * set elsewhere (e.g. for write/setattr) and this is not
1781 1784           * a call from msync (B_FORCE) we set the time now.
1782 1785           * This gives us approximate modified times for mmap'ed files
1783 1786           * which are modified via stores in the user address space.
1784 1787           */
1785 1788          if ((pcp->pc_flags & PC_MOD) == 0 || (flags & B_FORCE)) {
1786 1789                  pcp->pc_flags |= PC_MOD;
1787 1790                  pc_mark_mod(fsp, pcp);
1788 1791          }
1789 1792          pp = pvn_write_kluster(vp, pp, &io_off, &io_len, pp->p_offset,
1790 1793              PAGESIZE, flags);
1791 1794  
1792 1795          if (fsp->pcfs_flags & PCFS_IRRECOV) {
1793 1796                  goto out;
1794 1797          }
1795 1798  
1796 1799          PC_DPRINTF1(7, "pc_putpage writing dirty page off=%llu\n", io_off);
1797 1800  
1798 1801          lbn = pc_lblkno(fsp, io_off);
1799 1802          lbnoff = io_off & ~(fsp->pcfs_clsize - 1);
1800 1803          xferoffset = io_off & ~(fsp->pcfs_secsize - 1);
1801 1804  
1802 1805          for (pgoff = 0; pgoff < io_len && xferoffset < pcp->pc_size;
1803 1806              pgoff += xfersize,
1804 1807              lbn += howmany(xfersize, fsp->pcfs_clsize),
1805 1808              lbnoff += xfersize, xferoffset += xfersize) {
1806 1809  
1807 1810                  struct buf *bp;
1808 1811                  int err1;
1809 1812  
1810 1813                  /*
1811 1814                   * write as many contiguous blocks as possible from this page
1812 1815                   */
1813 1816                  xfersize = io_len - pgoff;
1814 1817                  err1 = pc_bmap(pcp, (daddr_t)lbn, &bn, &xfersize);
1815 1818                  if (err1) {
1816 1819                          err = err1;
1817 1820                          goto out;
1818 1821                  }
1819 1822                  bp = pageio_setup(pp, xfersize, devvp, B_WRITE | flags);
1820 1823                  bp->b_edev = devvp->v_rdev;
1821 1824                  bp->b_dev = cmpdev(devvp->v_rdev);
1822 1825                  bp->b_blkno = bn + btodt(xferoffset - lbnoff);
1823 1826                  bp->b_un.b_addr = (caddr_t)(uintptr_t)pgoff;
1824 1827                  bp->b_file = vp;
1825 1828                  bp->b_offset = (offset_t)(io_off + pgoff);
1826 1829  
1827 1830                  (void) bdev_strategy(bp);
1828 1831  
1829 1832                  lwp_stat_update(LWP_STAT_OUBLK, 1);
1830 1833  
1831 1834                  if (err == 0)
1832 1835                          err = biowait(bp);
1833 1836                  else
1834 1837                          (void) biowait(bp);
1835 1838                  pageio_done(bp);
1836 1839          }
1837 1840          pvn_write_done(pp, ((err) ? B_ERROR : 0) | B_WRITE | flags);
1838 1841          pp = NULL;
1839 1842  
1840 1843  out:
1841 1844          if ((fsp->pcfs_flags & PCFS_IRRECOV) && pp != NULL) {
1842 1845                  pvn_write_done(pp, B_WRITE | flags);
1843 1846          } else if (err != 0 && pp != NULL) {
1844 1847                  pvn_write_done(pp, B_ERROR | B_WRITE | flags);
1845 1848          }
1846 1849  
1847 1850          if (offp)
1848 1851                  *offp = io_off;
1849 1852          if (lenp)
1850 1853                  *lenp = io_len;
1851 1854                  PC_DPRINTF4(4, "pcfs_putapage: vp=%p pp=%p off=%lld len=%lu\n",
1852 1855                      (void *)vp, (void *)pp, io_off, io_len);
1853 1856          if (err) {
1854 1857                  PC_DPRINTF1(1, "pcfs_putapage err=%d", err);
1855 1858          }
1856 1859          return (err);
1857 1860  }
1858 1861  
1859 1862  /*ARGSUSED*/
1860 1863  static int
1861 1864  pcfs_map(
1862 1865          struct vnode *vp,
1863 1866          offset_t off,
1864 1867          struct as *as,
1865 1868          caddr_t *addrp,
1866 1869          size_t len,
1867 1870          uchar_t prot,
1868 1871          uchar_t maxprot,
1869 1872          uint_t flags,
1870 1873          struct cred *cr,
1871 1874          caller_context_t *ct)
1872 1875  {
1873 1876          struct segvn_crargs vn_a;
1874 1877          int error;
1875 1878  
1876 1879          PC_DPRINTF0(6, "pcfs_map\n");
1877 1880          if (vp->v_flag & VNOMAP)
1878 1881                  return (ENOSYS);
1879 1882  
1880 1883          if (off > UINT32_MAX || off + len > UINT32_MAX)
1881 1884                  return (ENXIO);
1882 1885  
1883 1886          as_rangelock(as);
1884 1887          error = choose_addr(as, addrp, len, off, ADDR_VACALIGN, flags);
1885 1888          if (error != 0) {
1886 1889                  as_rangeunlock(as);
1887 1890                  return (error);
1888 1891          }
1889 1892  
1890 1893          vn_a.vp = vp;
1891 1894          vn_a.offset = off;
1892 1895          vn_a.type = flags & MAP_TYPE;
1893 1896          vn_a.prot = prot;
1894 1897          vn_a.maxprot = maxprot;
1895 1898          vn_a.flags = flags & ~MAP_TYPE;
1896 1899          vn_a.cred = cr;
1897 1900          vn_a.amp = NULL;
1898 1901          vn_a.szc = 0;
1899 1902          vn_a.lgrp_mem_policy_flags = 0;
1900 1903  
1901 1904          error = as_map(as, *addrp, len, segvn_create, &vn_a);
1902 1905          as_rangeunlock(as);
1903 1906          return (error);
1904 1907  }
1905 1908  
1906 1909  /* ARGSUSED */
1907 1910  static int
1908 1911  pcfs_seek(
1909 1912          struct vnode *vp,
1910 1913          offset_t ooff,
1911 1914          offset_t *noffp,
1912 1915          caller_context_t *ct)
1913 1916  {
1914 1917          if (*noffp < 0)
1915 1918                  return (EINVAL);
1916 1919          else if (*noffp > MAXOFFSET_T)
1917 1920                  return (EINVAL);
1918 1921          else
1919 1922                  return (0);
1920 1923  }
1921 1924  
1922 1925  /* ARGSUSED */
1923 1926  static int
1924 1927  pcfs_addmap(
1925 1928          struct vnode *vp,
1926 1929          offset_t off,
1927 1930          struct as *as,
1928 1931          caddr_t addr,
1929 1932          size_t len,
1930 1933          uchar_t prot,
1931 1934          uchar_t maxprot,
1932 1935          uint_t flags,
1933 1936          struct cred *cr,
1934 1937          caller_context_t *ct)
1935 1938  {
1936 1939          if (vp->v_flag & VNOMAP)
1937 1940                  return (ENOSYS);
1938 1941          return (0);
1939 1942  }
1940 1943  
1941 1944  /*ARGSUSED*/
1942 1945  static int
1943 1946  pcfs_delmap(
1944 1947          struct vnode *vp,
1945 1948          offset_t off,
1946 1949          struct as *as,
1947 1950          caddr_t addr,
1948 1951          size_t len,
1949 1952          uint_t prot,
1950 1953          uint_t maxprot,
1951 1954          uint_t flags,
1952 1955          struct cred *cr,
1953 1956          caller_context_t *ct)
1954 1957  {
1955 1958          if (vp->v_flag & VNOMAP)
1956 1959                  return (ENOSYS);
1957 1960          return (0);
1958 1961  }
1959 1962  
1960 1963  /*
1961 1964   * POSIX pathconf() support.
1962 1965   */
1963 1966  /* ARGSUSED */
1964 1967  static int
1965 1968  pcfs_pathconf(
1966 1969          struct vnode *vp,
1967 1970          int cmd,
1968 1971          ulong_t *valp,
1969 1972          struct cred *cr,
1970 1973          caller_context_t *ct)
1971 1974  {
1972 1975          struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp);
1973 1976  
1974 1977          switch (cmd) {
1975 1978          case _PC_LINK_MAX:
1976 1979                  *valp = 1;
1977 1980                  return (0);
1978 1981  
1979 1982          case _PC_CASE_BEHAVIOR:
1980 1983                  return (EINVAL);
1981 1984  
1982 1985          case _PC_FILESIZEBITS:
1983 1986                  /*
1984 1987                   * Both FAT16 and FAT32 support 4GB - 1 byte for file size.
1985 1988                   * FAT12 can only go up to the maximum filesystem capacity
1986 1989                   * which is ~509MB.
1987 1990                   */
1988 1991                  *valp = IS_FAT12(fsp) ? 30 : 33;
1989 1992                  return (0);
1990 1993  
1991 1994          case _PC_TIMESTAMP_RESOLUTION:
1992 1995                  /*
1993 1996                   * PCFS keeps track of modification times, it its own
1994 1997                   * internal format, to a resolution of 2 seconds.
1995 1998                   * Since 2000 million is representable in an int32_t
1996 1999                   * without overflow (or becoming negative), we allow
1997 2000                   * this value to be returned.
1998 2001                   */
1999 2002                  *valp = 2000000000L;
2000 2003                  return (0);
2001 2004  
2002 2005          default:
2003 2006                  return (fs_pathconf(vp, cmd, valp, cr, ct));
2004 2007          }
2005 2008  
2006 2009  }
2007 2010  
2008 2011  /* ARGSUSED */
2009 2012  static int
2010 2013  pcfs_space(
2011 2014          struct vnode *vp,
2012 2015          int cmd,
2013 2016          struct flock64 *bfp,
2014 2017          int flag,
2015 2018          offset_t offset,
2016 2019          cred_t *cr,
2017 2020          caller_context_t *ct)
2018 2021  {
2019 2022          struct vattr vattr;
2020 2023          int error;
2021 2024  
2022 2025          if (cmd != F_FREESP)
2023 2026                  return (EINVAL);
2024 2027  
2025 2028          if ((error = convoff(vp, bfp, 0, offset)) == 0) {
2026 2029                  if ((bfp->l_start > UINT32_MAX) || (bfp->l_len > UINT32_MAX))
2027 2030                          return (EFBIG);
2028 2031                  /*
2029 2032                   * we only support the special case of l_len == 0,
2030 2033                   * meaning free to end of file at this moment.
2031 2034                   */
2032 2035                  if (bfp->l_len != 0)
2033 2036                          return (EINVAL);
2034 2037                  vattr.va_mask = AT_SIZE;
2035 2038                  vattr.va_size = bfp->l_start;
2036 2039                  error = VOP_SETATTR(vp, (vattr_t *)&vattr, 0, cr, ct);
2037 2040          }
2038 2041          return (error);
2039 2042  }
2040 2043  
2041 2044  /*
2042 2045   * Break up 'len' chars from 'buf' into a long file name chunk.
2043 2046   * Pad with '0xff' to make Norton Disk Doctor and Microsoft ScanDisk happy.
2044 2047   */
2045 2048  void
2046 2049  set_long_fn_chunk(struct pcdir_lfn *ep, char *buf, int len)
2047 2050  {
2048 2051          int     i;
2049 2052  
2050 2053          ASSERT(buf != NULL);
2051 2054  
2052 2055          for (i = 0; i < PCLF_FIRSTNAMESIZE; i += 2) {
2053 2056                  if (len > 0) {
2054 2057                          ep->pcdl_firstfilename[i] = *buf++;
2055 2058                          ep->pcdl_firstfilename[i + 1] = *buf++;
2056 2059                          len -= 2;
2057 2060                  } else {
2058 2061                          ep->pcdl_firstfilename[i] = (uchar_t)0xff;
2059 2062                          ep->pcdl_firstfilename[i + 1] = (uchar_t)0xff;
2060 2063                  }
2061 2064          }
2062 2065  
2063 2066          for (i = 0; i < PCLF_SECONDNAMESIZE; i += 2) {
2064 2067                  if (len > 0) {
2065 2068                          ep->pcdl_secondfilename[i] = *buf++;
2066 2069                          ep->pcdl_secondfilename[i + 1] = *buf++;
2067 2070                          len -= 2;
2068 2071                  } else {
2069 2072                          ep->pcdl_secondfilename[i] = (uchar_t)0xff;
2070 2073                          ep->pcdl_secondfilename[i + 1] = (uchar_t)0xff;
2071 2074                  }
2072 2075          }
2073 2076          for (i = 0; i < PCLF_THIRDNAMESIZE; i += 2) {
2074 2077                  if (len > 0) {
2075 2078                          ep->pcdl_thirdfilename[i] = *buf++;
2076 2079                          ep->pcdl_thirdfilename[i + 1] = *buf++;
2077 2080                          len -= 2;
2078 2081                  } else {
2079 2082                          ep->pcdl_thirdfilename[i] = (uchar_t)0xff;
2080 2083                          ep->pcdl_thirdfilename[i + 1] = (uchar_t)0xff;
2081 2084                  }
2082 2085          }
2083 2086  }
2084 2087  
2085 2088  /*
2086 2089   * Extract the characters from the long filename chunk into 'buf'.
2087 2090   * Return the number of characters extracted.
2088 2091   */
2089 2092  static int
2090 2093  get_long_fn_chunk(struct pcdir_lfn *ep, char *buf)
2091 2094  {
2092 2095          char    *tmp = buf;
2093 2096          int     i;
2094 2097  
2095 2098          /* Copy all the names, no filtering now */
2096 2099  
2097 2100          for (i = 0; i < PCLF_FIRSTNAMESIZE; i += 2, tmp += 2) {
2098 2101                  *tmp = ep->pcdl_firstfilename[i];
2099 2102                  *(tmp + 1) = ep->pcdl_firstfilename[i + 1];
2100 2103  
2101 2104                  if ((*tmp == '\0') && (*(tmp+1) == '\0'))
2102 2105                          return (tmp - buf);
2103 2106          }
2104 2107          for (i = 0; i < PCLF_SECONDNAMESIZE; i += 2, tmp += 2) {
2105 2108                  *tmp = ep->pcdl_secondfilename[i];
2106 2109                  *(tmp + 1) = ep->pcdl_secondfilename[i + 1];
2107 2110  
2108 2111                  if ((*tmp == '\0') && (*(tmp+1) == '\0'))
2109 2112                          return (tmp - buf);
2110 2113          }
2111 2114          for (i = 0; i < PCLF_THIRDNAMESIZE; i += 2, tmp += 2) {
2112 2115                  *tmp = ep->pcdl_thirdfilename[i];
2113 2116                  *(tmp + 1) = ep->pcdl_thirdfilename[i + 1];
2114 2117  
2115 2118                  if ((*tmp == '\0') && (*(tmp+1) == '\0'))
2116 2119                          return (tmp - buf);
2117 2120          }
2118 2121          return (tmp - buf);
2119 2122  }
2120 2123  
2121 2124  
2122 2125  /*
2123 2126   * Checksum the passed in short filename.
2124 2127   * This is used to validate each component of the long name to make
2125 2128   * sure the long name is valid (it hasn't been "detached" from the
2126 2129   * short filename). This algorithm was found in FreeBSD.
2127 2130   * (sys/fs/msdosfs/msdosfs_conv.c:winChksum(), Wolfgang Solfrank)
2128 2131   */
2129 2132  
2130 2133  uchar_t
2131 2134  pc_checksum_long_fn(char *name, char *ext)
2132 2135  {
2133 2136          uchar_t c;
2134 2137          char    b[11];
2135 2138  
2136 2139          bcopy(name, b, 8);
2137 2140          bcopy(ext, b+8, 3);
2138 2141  
2139 2142          c = b[0];
2140 2143          c = ((c << 7) | (c >> 1)) + b[1];
2141 2144          c = ((c << 7) | (c >> 1)) + b[2];
2142 2145          c = ((c << 7) | (c >> 1)) + b[3];
2143 2146          c = ((c << 7) | (c >> 1)) + b[4];
2144 2147          c = ((c << 7) | (c >> 1)) + b[5];
2145 2148          c = ((c << 7) | (c >> 1)) + b[6];
2146 2149          c = ((c << 7) | (c >> 1)) + b[7];
2147 2150          c = ((c << 7) | (c >> 1)) + b[8];
2148 2151          c = ((c << 7) | (c >> 1)) + b[9];
2149 2152          c = ((c << 7) | (c >> 1)) + b[10];
2150 2153  
2151 2154          return (c);
2152 2155  }
2153 2156  
2154 2157  /*
2155 2158   * Read a chunk of long filename entries into 'namep'.
2156 2159   * Return with offset pointing to short entry (on success), or next
2157 2160   * entry to read (if this wasn't a valid lfn really).
2158 2161   * Uses the passed-in buffer if it can, otherwise kmem_allocs() room for
2159 2162   * a long filename.
2160 2163   *
2161 2164   * Can also be called with a NULL namep, in which case it just returns
2162 2165   * whether this was really a valid long filename and consumes it
2163 2166   * (used by pc_dirempty()).
2164 2167   */
2165 2168  int
2166 2169  pc_extract_long_fn(struct pcnode *pcp, char *namep,
2167 2170      struct pcdir **epp, offset_t *offset, struct buf **bp)
2168 2171  {
2169 2172          struct pcdir *ep = *epp;
2170 2173          struct pcdir_lfn *lep = (struct pcdir_lfn *)ep;
2171 2174          struct vnode *dvp = PCTOV(pcp);
2172 2175          struct pcfs *fsp = VFSTOPCFS(dvp->v_vfsp);
2173 2176          char    *lfn;
2174 2177          char    *lfn_base;
2175 2178          int     boff;
2176 2179          int     i, cs;
2177 2180          char    *buf;
2178 2181          uchar_t cksum;
2179 2182          int     detached = 0;
2180 2183          int     error = 0;
2181 2184          int     foldcase;
2182 2185          int     count = 0;
2183 2186          size_t  u16l = 0, u8l = 0;
2184 2187          char    *outbuf;
2185 2188          size_t  ret, inlen, outlen;
2186 2189  
2187 2190          foldcase = (fsp->pcfs_flags & PCFS_FOLDCASE);
2188 2191          lfn_base = kmem_alloc(PCMAXNAM_UTF16, KM_SLEEP);
2189 2192          lfn = lfn_base + PCMAXNAM_UTF16 - sizeof (uint16_t);
2190 2193          *lfn = '\0';
2191 2194          *(lfn + 1) = '\0';
2192 2195          cksum = lep->pcdl_checksum;
2193 2196  
2194 2197          buf = kmem_alloc(PCMAXNAM_UTF16, KM_SLEEP);
2195 2198          for (i = (lep->pcdl_ordinal & ~0xc0); i > 0; i--) {
2196 2199                  /* read next block if necessary */
2197 2200                  boff = pc_blkoff(fsp, *offset);
2198 2201                  if (boff == 0 || *bp == NULL || boff >= (*bp)->b_bcount) {
2199 2202                          if (*bp != NULL) {
2200 2203                                  brelse(*bp);
2201 2204                                  *bp = NULL;
2202 2205                          }
2203 2206                          error = pc_blkatoff(pcp, *offset, bp, &ep);
2204 2207                          if (error) {
2205 2208                                  kmem_free(lfn_base, PCMAXNAM_UTF16);
2206 2209                                  kmem_free(buf, PCMAXNAM_UTF16);
2207 2210                                  return (error);
2208 2211                          }
2209 2212                          lep = (struct pcdir_lfn *)ep;
2210 2213                  }
2211 2214                  /* can this happen? Bad fs? */
2212 2215                  if (!PCDL_IS_LFN((struct pcdir *)lep)) {
2213 2216                          detached = 1;
2214 2217                          break;
2215 2218                  }
2216 2219                  if (cksum != lep->pcdl_checksum)
2217 2220                          detached = 1;
2218 2221                  /* process current entry */
2219 2222                  cs = get_long_fn_chunk(lep, buf);
2220 2223                  count += cs;
2221 2224                  for (; cs > 0; cs--) {
2222 2225                          /* see if we underflow */
2223 2226                          if (lfn >= lfn_base)
2224 2227                                  *--lfn = buf[cs - 1];
2225 2228                          else
2226 2229                                  detached = 1;
2227 2230                  }
2228 2231                  lep++;
2229 2232                  *offset += sizeof (struct pcdir);
2230 2233          }
2231 2234          kmem_free(buf, PCMAXNAM_UTF16);
2232 2235          /* read next block if necessary */
2233 2236          boff = pc_blkoff(fsp, *offset);
2234 2237          ep = (struct pcdir *)lep;
2235 2238          if (boff == 0 || *bp == NULL || boff >= (*bp)->b_bcount) {
2236 2239                  if (*bp != NULL) {
2237 2240                          brelse(*bp);
2238 2241                          *bp = NULL;
2239 2242                  }
2240 2243                  error = pc_blkatoff(pcp, *offset, bp, &ep);
2241 2244                  if (error) {
2242 2245                          kmem_free(lfn_base, PCMAXNAM_UTF16);
2243 2246                          return (error);
2244 2247                  }
2245 2248          }
2246 2249          /* should be on the short one */
2247 2250          if (PCDL_IS_LFN(ep) || ((ep->pcd_filename[0] == PCD_UNUSED) ||
2248 2251              (ep->pcd_filename[0] == PCD_ERASED))) {
2249 2252                  detached = 1;
2250 2253          }
2251 2254          if (detached ||
2252 2255              (cksum != pc_checksum_long_fn(ep->pcd_filename, ep->pcd_ext)) ||
2253 2256              !pc_valid_long_fn(lfn, 0)) {
2254 2257                  /*
2255 2258                   * process current entry again. This may end up another lfn
2256 2259                   * or a short name.
2257 2260                   */
2258 2261                  *epp = ep;
2259 2262                  kmem_free(lfn_base, PCMAXNAM_UTF16);
2260 2263                  return (EINVAL);
2261 2264          }
2262 2265          if (PCA_IS_HIDDEN(fsp, ep->pcd_attr)) {
2263 2266                  /*
2264 2267                   * Don't display label because it may contain
2265 2268                   * funny characters.
2266 2269                   */
2267 2270                  *offset += sizeof (struct pcdir);
2268 2271                  ep++;
2269 2272                  *epp = ep;
2270 2273                  kmem_free(lfn_base, PCMAXNAM_UTF16);
2271 2274                  return (EINVAL);
2272 2275          }
2273 2276          if (namep) {
2274 2277                  u16l = count / 2;
2275 2278                  u8l = PCMAXNAMLEN;
2276 2279                  error = uconv_u16tou8((const uint16_t *)lfn, &u16l,
2277 2280                      (uchar_t *)namep, &u8l, UCONV_IN_LITTLE_ENDIAN);
2278 2281                  /*
2279 2282                   * uconv_u16tou8() will catch conversion errors including
2280 2283                   * the case where there is not enough room to write the
2281 2284                   * converted result and the u8l will never go over the given
2282 2285                   * PCMAXNAMLEN.
2283 2286                   */
2284 2287                  if (error != 0) {
2285 2288                          kmem_free(lfn_base, PCMAXNAM_UTF16);
2286 2289                          return (EINVAL);
2287 2290                  }
2288 2291                  namep[u8l] = '\0';
2289 2292                  if (foldcase) {
2290 2293                          inlen = strlen(namep);
2291 2294                          outlen = PCMAXNAMLEN;
2292 2295                          outbuf = kmem_alloc(PCMAXNAMLEN + 1, KM_SLEEP);
2293 2296                          ret = u8_textprep_str(namep, &inlen, outbuf,
2294 2297                              &outlen, U8_TEXTPREP_TOLOWER, U8_UNICODE_LATEST,
2295 2298                              &error);
2296 2299                          if (ret == -1) {
2297 2300                                  kmem_free(outbuf, PCMAXNAMLEN + 1);
2298 2301                                  kmem_free(lfn_base, PCMAXNAM_UTF16);
2299 2302                                  return (EINVAL);
2300 2303                          }
2301 2304                          outbuf[PCMAXNAMLEN - outlen] = '\0';
2302 2305                          (void) strncpy(namep, outbuf, PCMAXNAMLEN + 1);
2303 2306                          kmem_free(outbuf, PCMAXNAMLEN + 1);
2304 2307                  }
2305 2308          }
2306 2309          kmem_free(lfn_base, PCMAXNAM_UTF16);
2307 2310          *epp = ep;
2308 2311          return (0);
2309 2312  }
2310 2313  /*
2311 2314   * Read a long filename into the pc_dirent structure and copy it out.
2312 2315   */
2313 2316  int
2314 2317  pc_read_long_fn(struct vnode *dvp, struct uio *uiop, struct pc_dirent *ld,
2315 2318      struct pcdir **epp, offset_t *offset, struct buf **bp)
2316 2319  {
2317 2320          struct pcdir *ep;
2318 2321          struct pcnode *pcp = VTOPC(dvp);
2319 2322          struct pcfs *fsp = VFSTOPCFS(dvp->v_vfsp);
2320 2323          offset_t uiooffset = uiop->uio_loffset;
2321 2324          int     error = 0;
2322 2325          offset_t oldoffset;
2323 2326  
2324 2327          oldoffset = *offset;
2325 2328          error = pc_extract_long_fn(pcp, ld->d_name, epp, offset, bp);
2326 2329          if (error) {
2327 2330                  if (error == EINVAL) {
2328 2331                          uiop->uio_loffset += *offset - oldoffset;
2329 2332                          return (0);
2330 2333                  } else
2331 2334                          return (error);
2332 2335          }
2333 2336  
2334 2337          ep = *epp;
2335 2338          uiop->uio_loffset += *offset - oldoffset;
2336 2339          ld->d_reclen = DIRENT64_RECLEN(strlen(ld->d_name));
2337 2340          if (ld->d_reclen > uiop->uio_resid) {
2338 2341                  uiop->uio_loffset = uiooffset;
2339 2342                  return (ENOSPC);
2340 2343          }
2341 2344          ld->d_off = uiop->uio_loffset + sizeof (struct pcdir);
2342 2345          ld->d_ino = pc_makenodeid(pc_daddrdb(fsp, (*bp)->b_blkno),
2343 2346              pc_blkoff(fsp, *offset), ep->pcd_attr,
2344 2347              pc_getstartcluster(fsp, ep), pc_direntpersec(fsp));
2345 2348          (void) uiomove((caddr_t)ld, ld->d_reclen, UIO_READ, uiop);
2346 2349          uiop->uio_loffset = ld->d_off;
2347 2350          *offset += sizeof (struct pcdir);
2348 2351          ep++;
2349 2352          *epp = ep;
2350 2353          return (0);
2351 2354  }
2352 2355  
2353 2356  /*
2354 2357   * Read a short filename into the pc_dirent structure and copy it out.
2355 2358   */
2356 2359  int
2357 2360  pc_read_short_fn(struct vnode *dvp, struct uio *uiop, struct pc_dirent *ld,
2358 2361      struct pcdir **epp, offset_t *offset, struct buf **bp)
2359 2362  {
2360 2363          struct pcfs *fsp = VFSTOPCFS(dvp->v_vfsp);
2361 2364          int     boff = pc_blkoff(fsp, *offset);
2362 2365          struct pcdir *ep = *epp;
2363 2366          offset_t        oldoffset = uiop->uio_loffset;
2364 2367          int     error;
2365 2368          int     foldcase;
2366 2369  
2367 2370          if (PCA_IS_HIDDEN(fsp, ep->pcd_attr)) {
2368 2371                  uiop->uio_loffset += sizeof (struct pcdir);
2369 2372                  *offset += sizeof (struct pcdir);
2370 2373                  ep++;
2371 2374                  *epp = ep;
2372 2375                  return (0);
2373 2376          }
2374 2377          ld->d_ino = (ino64_t)pc_makenodeid(pc_daddrdb(fsp, (*bp)->b_blkno),
2375 2378              boff, ep->pcd_attr, pc_getstartcluster(fsp, ep),
2376 2379              pc_direntpersec(fsp));
2377 2380          foldcase = (fsp->pcfs_flags & PCFS_FOLDCASE);
2378 2381          error = pc_fname_ext_to_name(&ld->d_name[0], &ep->pcd_filename[0],
2379 2382              &ep->pcd_ext[0], foldcase);
2380 2383          if (error == 0) {
2381 2384                  ld->d_reclen = DIRENT64_RECLEN(strlen(ld->d_name));
2382 2385                  if (ld->d_reclen > uiop->uio_resid) {
2383 2386                          uiop->uio_loffset = oldoffset;
2384 2387                          return (ENOSPC);
2385 2388                  }
2386 2389                  ld->d_off = (off64_t)(uiop->uio_loffset +
2387 2390                      sizeof (struct pcdir));
2388 2391                  (void) uiomove((caddr_t)ld,
2389 2392                      ld->d_reclen, UIO_READ, uiop);
2390 2393                  uiop->uio_loffset = ld->d_off;
2391 2394          } else {
2392 2395                  uiop->uio_loffset += sizeof (struct pcdir);
2393 2396          }
2394 2397          *offset += sizeof (struct pcdir);
2395 2398          ep++;
2396 2399          *epp = ep;
2397 2400          return (0);
2398 2401  }
2399 2402  
2400 2403  /* ARGSUSED */
2401 2404  static int
2402 2405  pcfs_fid(struct vnode *vp, struct fid *fidp, caller_context_t *ct)
2403 2406  {
2404 2407          struct pc_fid *pcfid;
2405 2408          struct pcnode *pcp;
2406 2409          struct pcfs     *fsp;
2407 2410          int     error;
2408 2411  
2409 2412          fsp = VFSTOPCFS(vp->v_vfsp);
2410 2413          if (fsp == NULL)
2411 2414                  return (EIO);
2412 2415          error = pc_lockfs(fsp, 0, 0);
2413 2416          if (error)
2414 2417                  return (error);
2415 2418          if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) {
2416 2419                  pc_unlockfs(fsp);
2417 2420                  return (EIO);
2418 2421          }
2419 2422          if (fidp->fid_len < (sizeof (struct pc_fid) - sizeof (ushort_t))) {
2420 2423                  fidp->fid_len = sizeof (struct pc_fid) - sizeof (ushort_t);
2421 2424                  pc_unlockfs(fsp);
2422 2425                  return (ENOSPC);
2423 2426          }
2424 2427  
2425 2428          pcfid = (struct pc_fid *)fidp;
2426 2429          bzero(pcfid, sizeof (struct pc_fid));
2427 2430          pcfid->pcfid_len = sizeof (struct pc_fid) - sizeof (ushort_t);
2428 2431          if (vp->v_flag & VROOT) {
2429 2432                  pcfid->pcfid_block = 0;
2430 2433                  pcfid->pcfid_offset = 0;
2431 2434                  pcfid->pcfid_ctime = 0;
2432 2435          } else {
2433 2436                  pcfid->pcfid_block = pcp->pc_eblkno;
2434 2437                  pcfid->pcfid_offset = pcp->pc_eoffset;
2435 2438                  pcfid->pcfid_ctime = pcp->pc_entry.pcd_crtime.pct_time;
2436 2439          }
2437 2440          pc_unlockfs(fsp);
2438 2441          return (0);
2439 2442  }
  
    | 
      ↓ open down ↓ | 
    1644 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX