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