10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
52720Sfrankho * Common Development and Distribution License (the "License").
62720Sfrankho * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
21*10440SRoger.Faulkner@Sun.COM
220Sstevel@tonic-gate /*
23*10440SRoger.Faulkner@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
240Sstevel@tonic-gate * Use is subject to license terms.
250Sstevel@tonic-gate */
260Sstevel@tonic-gate
270Sstevel@tonic-gate #include <sys/param.h>
280Sstevel@tonic-gate #include <sys/t_lock.h>
290Sstevel@tonic-gate #include <sys/systm.h>
300Sstevel@tonic-gate #include <sys/sysmacros.h>
310Sstevel@tonic-gate #include <sys/user.h>
320Sstevel@tonic-gate #include <sys/buf.h>
330Sstevel@tonic-gate #include <sys/stat.h>
340Sstevel@tonic-gate #include <sys/vfs.h>
353898Srsb #include <sys/vfs_opreg.h>
360Sstevel@tonic-gate #include <sys/dirent.h>
370Sstevel@tonic-gate #include <sys/vnode.h>
380Sstevel@tonic-gate #include <sys/proc.h>
390Sstevel@tonic-gate #include <sys/file.h>
400Sstevel@tonic-gate #include <sys/fcntl.h>
410Sstevel@tonic-gate #include <sys/uio.h>
420Sstevel@tonic-gate #include <sys/fs/pc_label.h>
430Sstevel@tonic-gate #include <sys/fs/pc_fs.h>
440Sstevel@tonic-gate #include <sys/fs/pc_dir.h>
450Sstevel@tonic-gate #include <sys/fs/pc_node.h>
460Sstevel@tonic-gate #include <sys/mman.h>
470Sstevel@tonic-gate #include <sys/pathname.h>
480Sstevel@tonic-gate #include <sys/vmsystm.h>
490Sstevel@tonic-gate #include <sys/cmn_err.h>
500Sstevel@tonic-gate #include <sys/debug.h>
510Sstevel@tonic-gate #include <sys/statvfs.h>
520Sstevel@tonic-gate #include <sys/unistd.h>
530Sstevel@tonic-gate #include <sys/kmem.h>
540Sstevel@tonic-gate #include <sys/conf.h>
550Sstevel@tonic-gate #include <sys/flock.h>
560Sstevel@tonic-gate #include <sys/policy.h>
572720Sfrankho #include <sys/sdt.h>
584723Sksn #include <sys/sunddi.h>
597735SOwen.Roberts@Sun.Com #include <sys/types.h>
607735SOwen.Roberts@Sun.Com #include <sys/errno.h>
610Sstevel@tonic-gate
620Sstevel@tonic-gate #include <vm/seg.h>
630Sstevel@tonic-gate #include <vm/page.h>
640Sstevel@tonic-gate #include <vm/pvn.h>
650Sstevel@tonic-gate #include <vm/seg_map.h>
660Sstevel@tonic-gate #include <vm/seg_vn.h>
670Sstevel@tonic-gate #include <vm/hat.h>
680Sstevel@tonic-gate #include <vm/as.h>
690Sstevel@tonic-gate #include <vm/seg_kmem.h>
700Sstevel@tonic-gate
710Sstevel@tonic-gate #include <fs/fs_subr.h>
720Sstevel@tonic-gate
735331Samw static int pcfs_open(struct vnode **, int, struct cred *, caller_context_t *ct);
745331Samw static int pcfs_close(struct vnode *, int, int, offset_t, struct cred *,
755331Samw caller_context_t *ct);
760Sstevel@tonic-gate static int pcfs_read(struct vnode *, struct uio *, int, struct cred *,
775331Samw caller_context_t *);
780Sstevel@tonic-gate static int pcfs_write(struct vnode *, struct uio *, int, struct cred *,
795331Samw caller_context_t *);
805331Samw static int pcfs_getattr(struct vnode *, struct vattr *, int, struct cred *,
815331Samw caller_context_t *ct);
820Sstevel@tonic-gate static int pcfs_setattr(struct vnode *, struct vattr *, int, struct cred *,
830Sstevel@tonic-gate caller_context_t *);
845331Samw static int pcfs_access(struct vnode *, int, int, struct cred *,
855331Samw caller_context_t *ct);
860Sstevel@tonic-gate static int pcfs_lookup(struct vnode *, char *, struct vnode **,
875331Samw struct pathname *, int, struct vnode *, struct cred *,
885331Samw caller_context_t *, int *, pathname_t *);
890Sstevel@tonic-gate static int pcfs_create(struct vnode *, char *, struct vattr *,
905331Samw enum vcexcl, int mode, struct vnode **, struct cred *, int,
915331Samw caller_context_t *, vsecattr_t *);
925331Samw static int pcfs_remove(struct vnode *, char *, struct cred *,
935331Samw caller_context_t *, int);
940Sstevel@tonic-gate static int pcfs_rename(struct vnode *, char *, struct vnode *, char *,
955331Samw struct cred *, caller_context_t *, int);
960Sstevel@tonic-gate static int pcfs_mkdir(struct vnode *, char *, struct vattr *, struct vnode **,
975331Samw struct cred *, caller_context_t *, int, vsecattr_t *);
985331Samw static int pcfs_rmdir(struct vnode *, char *, struct vnode *, struct cred *,
995331Samw caller_context_t *, int);
1005331Samw static int pcfs_readdir(struct vnode *, struct uio *, struct cred *, int *,
1015331Samw caller_context_t *, int);
1025331Samw static int pcfs_fsync(struct vnode *, int, struct cred *, caller_context_t *);
1035331Samw static void pcfs_inactive(struct vnode *, struct cred *, caller_context_t *);
1045331Samw static int pcfs_fid(struct vnode *vp, struct fid *fidp, caller_context_t *);
1050Sstevel@tonic-gate static int pcfs_space(struct vnode *, int, struct flock64 *, int,
1060Sstevel@tonic-gate offset_t, cred_t *, caller_context_t *);
1070Sstevel@tonic-gate static int pcfs_getpage(struct vnode *, offset_t, size_t, uint_t *, page_t *[],
1085331Samw size_t, struct seg *, caddr_t, enum seg_rw, struct cred *,
1095331Samw caller_context_t *);
1100Sstevel@tonic-gate static int pcfs_getapage(struct vnode *, u_offset_t, size_t, uint_t *,
1110Sstevel@tonic-gate page_t *[], size_t, struct seg *, caddr_t, enum seg_rw, struct cred *);
1125331Samw static int pcfs_putpage(struct vnode *, offset_t, size_t, int, struct cred *,
1135331Samw caller_context_t *);
1140Sstevel@tonic-gate static int pcfs_map(struct vnode *, offset_t, struct as *, caddr_t *, size_t,
1155331Samw uchar_t, uchar_t, uint_t, struct cred *, caller_context_t *);
1160Sstevel@tonic-gate static int pcfs_addmap(struct vnode *, offset_t, struct as *, caddr_t,
1175331Samw size_t, uchar_t, uchar_t, uint_t, struct cred *, caller_context_t *);
1180Sstevel@tonic-gate static int pcfs_delmap(struct vnode *, offset_t, struct as *, caddr_t,
1195331Samw size_t, uint_t, uint_t, uint_t, struct cred *, caller_context_t *);
1205331Samw static int pcfs_seek(struct vnode *, offset_t, offset_t *,
1215331Samw caller_context_t *);
1225331Samw static int pcfs_pathconf(struct vnode *, int, ulong_t *, struct cred *,
1235331Samw caller_context_t *);
1240Sstevel@tonic-gate
1250Sstevel@tonic-gate int pcfs_putapage(struct vnode *, page_t *, u_offset_t *, size_t *, int,
1260Sstevel@tonic-gate struct cred *);
1270Sstevel@tonic-gate static int rwpcp(struct pcnode *, struct uio *, enum uio_rw, int);
1287735SOwen.Roberts@Sun.Com static int get_long_fn_chunk(struct pcdir_lfn *ep, char *buf);
1290Sstevel@tonic-gate
1300Sstevel@tonic-gate extern krwlock_t pcnodes_lock;
1310Sstevel@tonic-gate
1320Sstevel@tonic-gate #define lround(r) (((r)+sizeof (long long)-1)&(~(sizeof (long long)-1)))
1330Sstevel@tonic-gate
1340Sstevel@tonic-gate /*
1350Sstevel@tonic-gate * vnode op vectors for files and directories.
1360Sstevel@tonic-gate */
1370Sstevel@tonic-gate struct vnodeops *pcfs_fvnodeops;
1380Sstevel@tonic-gate struct vnodeops *pcfs_dvnodeops;
1390Sstevel@tonic-gate
1400Sstevel@tonic-gate const fs_operation_def_t pcfs_fvnodeops_template[] = {
1413898Srsb VOPNAME_OPEN, { .vop_open = pcfs_open },
1423898Srsb VOPNAME_CLOSE, { .vop_close = pcfs_close },
1433898Srsb VOPNAME_READ, { .vop_read = pcfs_read },
1443898Srsb VOPNAME_WRITE, { .vop_write = pcfs_write },
1453898Srsb VOPNAME_GETATTR, { .vop_getattr = pcfs_getattr },
1463898Srsb VOPNAME_SETATTR, { .vop_setattr = pcfs_setattr },
1473898Srsb VOPNAME_ACCESS, { .vop_access = pcfs_access },
1483898Srsb VOPNAME_FSYNC, { .vop_fsync = pcfs_fsync },
1493898Srsb VOPNAME_INACTIVE, { .vop_inactive = pcfs_inactive },
1503898Srsb VOPNAME_FID, { .vop_fid = pcfs_fid },
1513898Srsb VOPNAME_SEEK, { .vop_seek = pcfs_seek },
1523898Srsb VOPNAME_SPACE, { .vop_space = pcfs_space },
1533898Srsb VOPNAME_GETPAGE, { .vop_getpage = pcfs_getpage },
1543898Srsb VOPNAME_PUTPAGE, { .vop_putpage = pcfs_putpage },
1553898Srsb VOPNAME_MAP, { .vop_map = pcfs_map },
1563898Srsb VOPNAME_ADDMAP, { .vop_addmap = pcfs_addmap },
1573898Srsb VOPNAME_DELMAP, { .vop_delmap = pcfs_delmap },
1583898Srsb VOPNAME_PATHCONF, { .vop_pathconf = pcfs_pathconf },
1593898Srsb VOPNAME_VNEVENT, { .vop_vnevent = fs_vnevent_support },
1603898Srsb NULL, NULL
1610Sstevel@tonic-gate };
1620Sstevel@tonic-gate
1630Sstevel@tonic-gate const fs_operation_def_t pcfs_dvnodeops_template[] = {
1643898Srsb VOPNAME_OPEN, { .vop_open = pcfs_open },
1653898Srsb VOPNAME_CLOSE, { .vop_close = pcfs_close },
1663898Srsb VOPNAME_GETATTR, { .vop_getattr = pcfs_getattr },
1673898Srsb VOPNAME_SETATTR, { .vop_setattr = pcfs_setattr },
1683898Srsb VOPNAME_ACCESS, { .vop_access = pcfs_access },
1693898Srsb VOPNAME_LOOKUP, { .vop_lookup = pcfs_lookup },
1703898Srsb VOPNAME_CREATE, { .vop_create = pcfs_create },
1713898Srsb VOPNAME_REMOVE, { .vop_remove = pcfs_remove },
1723898Srsb VOPNAME_RENAME, { .vop_rename = pcfs_rename },
1733898Srsb VOPNAME_MKDIR, { .vop_mkdir = pcfs_mkdir },
1743898Srsb VOPNAME_RMDIR, { .vop_rmdir = pcfs_rmdir },
1753898Srsb VOPNAME_READDIR, { .vop_readdir = pcfs_readdir },
1763898Srsb VOPNAME_FSYNC, { .vop_fsync = pcfs_fsync },
1773898Srsb VOPNAME_INACTIVE, { .vop_inactive = pcfs_inactive },
1783898Srsb VOPNAME_FID, { .vop_fid = pcfs_fid },
1793898Srsb VOPNAME_SEEK, { .vop_seek = pcfs_seek },
1803898Srsb VOPNAME_PATHCONF, { .vop_pathconf = pcfs_pathconf },
1813898Srsb VOPNAME_VNEVENT, { .vop_vnevent = fs_vnevent_support },
1823898Srsb NULL, NULL
1830Sstevel@tonic-gate };
1840Sstevel@tonic-gate
1850Sstevel@tonic-gate
1860Sstevel@tonic-gate /*ARGSUSED*/
1870Sstevel@tonic-gate static int
pcfs_open(struct vnode ** vpp,int flag,struct cred * cr,caller_context_t * ct)1880Sstevel@tonic-gate pcfs_open(
1890Sstevel@tonic-gate struct vnode **vpp,
1900Sstevel@tonic-gate int flag,
1915331Samw struct cred *cr,
1925331Samw caller_context_t *ct)
1930Sstevel@tonic-gate {
1940Sstevel@tonic-gate return (0);
1950Sstevel@tonic-gate }
1960Sstevel@tonic-gate
1970Sstevel@tonic-gate /*
1980Sstevel@tonic-gate * files are sync'ed on close to keep floppy up to date
1990Sstevel@tonic-gate */
2000Sstevel@tonic-gate
2010Sstevel@tonic-gate /*ARGSUSED*/
2020Sstevel@tonic-gate static int
pcfs_close(struct vnode * vp,int flag,int count,offset_t offset,struct cred * cr,caller_context_t * ct)2030Sstevel@tonic-gate pcfs_close(
2040Sstevel@tonic-gate struct vnode *vp,
2050Sstevel@tonic-gate int flag,
2060Sstevel@tonic-gate int count,
2070Sstevel@tonic-gate offset_t offset,
2085331Samw struct cred *cr,
2095331Samw caller_context_t *ct)
2100Sstevel@tonic-gate {
2110Sstevel@tonic-gate return (0);
2120Sstevel@tonic-gate }
2130Sstevel@tonic-gate
2140Sstevel@tonic-gate /*ARGSUSED*/
2150Sstevel@tonic-gate static int
pcfs_read(struct vnode * vp,struct uio * uiop,int ioflag,struct cred * cr,struct caller_context * ct)2160Sstevel@tonic-gate pcfs_read(
2170Sstevel@tonic-gate struct vnode *vp,
2180Sstevel@tonic-gate struct uio *uiop,
2190Sstevel@tonic-gate int ioflag,
2200Sstevel@tonic-gate struct cred *cr,
2210Sstevel@tonic-gate struct caller_context *ct)
2220Sstevel@tonic-gate {
2230Sstevel@tonic-gate struct pcfs *fsp;
2240Sstevel@tonic-gate struct pcnode *pcp;
2250Sstevel@tonic-gate int error;
2260Sstevel@tonic-gate
2270Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp);
2280Sstevel@tonic-gate if (error = pc_verify(fsp))
2290Sstevel@tonic-gate return (error);
2300Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0);
2310Sstevel@tonic-gate if (error)
2320Sstevel@tonic-gate return (error);
2332972Sfrankho if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) {
2340Sstevel@tonic-gate pc_unlockfs(fsp);
2350Sstevel@tonic-gate return (EIO);
2360Sstevel@tonic-gate }
2370Sstevel@tonic-gate error = rwpcp(pcp, uiop, UIO_READ, ioflag);
2380Sstevel@tonic-gate if ((fsp->pcfs_vfs->vfs_flag & VFS_RDONLY) == 0) {
2395121Sfrankho pc_mark_acc(fsp, pcp);
2400Sstevel@tonic-gate }
2410Sstevel@tonic-gate pc_unlockfs(fsp);
2420Sstevel@tonic-gate if (error) {
2430Sstevel@tonic-gate PC_DPRINTF1(1, "pcfs_read: io error = %d\n", error);
2440Sstevel@tonic-gate }
2450Sstevel@tonic-gate return (error);
2460Sstevel@tonic-gate }
2470Sstevel@tonic-gate
2480Sstevel@tonic-gate /*ARGSUSED*/
2490Sstevel@tonic-gate static int
pcfs_write(struct vnode * vp,struct uio * uiop,int ioflag,struct cred * cr,struct caller_context * ct)2500Sstevel@tonic-gate pcfs_write(
2510Sstevel@tonic-gate struct vnode *vp,
2520Sstevel@tonic-gate struct uio *uiop,
2530Sstevel@tonic-gate int ioflag,
2540Sstevel@tonic-gate struct cred *cr,
2550Sstevel@tonic-gate struct caller_context *ct)
2560Sstevel@tonic-gate {
2570Sstevel@tonic-gate struct pcfs *fsp;
2580Sstevel@tonic-gate struct pcnode *pcp;
2590Sstevel@tonic-gate int error;
2600Sstevel@tonic-gate
2610Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp);
2620Sstevel@tonic-gate if (error = pc_verify(fsp))
2630Sstevel@tonic-gate return (error);
2640Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0);
2650Sstevel@tonic-gate if (error)
2660Sstevel@tonic-gate return (error);
2672972Sfrankho if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) {
2680Sstevel@tonic-gate pc_unlockfs(fsp);
2690Sstevel@tonic-gate return (EIO);
2700Sstevel@tonic-gate }
2710Sstevel@tonic-gate if (ioflag & FAPPEND) {
2720Sstevel@tonic-gate /*
2730Sstevel@tonic-gate * in append mode start at end of file.
2740Sstevel@tonic-gate */
2750Sstevel@tonic-gate uiop->uio_loffset = pcp->pc_size;
2760Sstevel@tonic-gate }
2770Sstevel@tonic-gate error = rwpcp(pcp, uiop, UIO_WRITE, ioflag);
2780Sstevel@tonic-gate pcp->pc_flags |= PC_MOD;
2795121Sfrankho pc_mark_mod(fsp, pcp);
2800Sstevel@tonic-gate if (ioflag & (FSYNC|FDSYNC))
2810Sstevel@tonic-gate (void) pc_nodeupdate(pcp);
2820Sstevel@tonic-gate
2830Sstevel@tonic-gate pc_unlockfs(fsp);
2840Sstevel@tonic-gate if (error) {
2850Sstevel@tonic-gate PC_DPRINTF1(1, "pcfs_write: io error = %d\n", error);
2860Sstevel@tonic-gate }
2870Sstevel@tonic-gate return (error);
2880Sstevel@tonic-gate }
2890Sstevel@tonic-gate
2900Sstevel@tonic-gate /*
2910Sstevel@tonic-gate * read or write a vnode
2920Sstevel@tonic-gate */
2930Sstevel@tonic-gate static int
rwpcp(struct pcnode * pcp,struct uio * uio,enum uio_rw rw,int ioflag)2940Sstevel@tonic-gate rwpcp(
2950Sstevel@tonic-gate struct pcnode *pcp,
2960Sstevel@tonic-gate struct uio *uio,
2970Sstevel@tonic-gate enum uio_rw rw,
2980Sstevel@tonic-gate int ioflag)
2990Sstevel@tonic-gate {
3000Sstevel@tonic-gate struct vnode *vp = PCTOV(pcp);
3010Sstevel@tonic-gate struct pcfs *fsp;
3020Sstevel@tonic-gate daddr_t bn; /* phys block number */
3030Sstevel@tonic-gate int n;
3040Sstevel@tonic-gate offset_t off;
3050Sstevel@tonic-gate caddr_t base;
3060Sstevel@tonic-gate int mapon, pagecreate;
3070Sstevel@tonic-gate int newpage;
3080Sstevel@tonic-gate int error = 0;
3090Sstevel@tonic-gate rlim64_t limit = uio->uio_llimit;
3100Sstevel@tonic-gate int oresid = uio->uio_resid;
3110Sstevel@tonic-gate
3122720Sfrankho /*
3132720Sfrankho * If the filesystem was umounted by force, return immediately.
3142720Sfrankho */
3152720Sfrankho if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
3162720Sfrankho return (EIO);
3172720Sfrankho
3180Sstevel@tonic-gate PC_DPRINTF4(5, "rwpcp pcp=%p off=%lld resid=%ld size=%u\n", (void *)pcp,
3190Sstevel@tonic-gate uio->uio_loffset, uio->uio_resid, pcp->pc_size);
3200Sstevel@tonic-gate
3210Sstevel@tonic-gate ASSERT(rw == UIO_READ || rw == UIO_WRITE);
3220Sstevel@tonic-gate ASSERT(vp->v_type == VREG);
3230Sstevel@tonic-gate
3240Sstevel@tonic-gate if (uio->uio_loffset >= UINT32_MAX && rw == UIO_READ) {
3250Sstevel@tonic-gate return (0);
3260Sstevel@tonic-gate }
3270Sstevel@tonic-gate
3280Sstevel@tonic-gate if (uio->uio_loffset < 0)
3290Sstevel@tonic-gate return (EINVAL);
3300Sstevel@tonic-gate
3310Sstevel@tonic-gate if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T)
3320Sstevel@tonic-gate limit = MAXOFFSET_T;
3330Sstevel@tonic-gate
3340Sstevel@tonic-gate if (uio->uio_loffset >= limit && rw == UIO_WRITE) {
3350Sstevel@tonic-gate proc_t *p = ttoproc(curthread);
3360Sstevel@tonic-gate
3370Sstevel@tonic-gate mutex_enter(&p->p_lock);
3380Sstevel@tonic-gate (void) rctl_action(rctlproc_legacy[RLIMIT_FSIZE], p->p_rctls,
3390Sstevel@tonic-gate p, RCA_UNSAFE_SIGINFO);
3400Sstevel@tonic-gate mutex_exit(&p->p_lock);
3410Sstevel@tonic-gate return (EFBIG);
3420Sstevel@tonic-gate }
3430Sstevel@tonic-gate
3440Sstevel@tonic-gate /* the following condition will occur only for write */
3450Sstevel@tonic-gate
3460Sstevel@tonic-gate if (uio->uio_loffset >= UINT32_MAX)
3470Sstevel@tonic-gate return (EFBIG);
3480Sstevel@tonic-gate
3490Sstevel@tonic-gate if (uio->uio_resid == 0)
3500Sstevel@tonic-gate return (0);
3510Sstevel@tonic-gate
3520Sstevel@tonic-gate if (limit > UINT32_MAX)
3530Sstevel@tonic-gate limit = UINT32_MAX;
3540Sstevel@tonic-gate
3550Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp);
3560Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_IRRECOV)
3570Sstevel@tonic-gate return (EIO);
3580Sstevel@tonic-gate
3590Sstevel@tonic-gate do {
3600Sstevel@tonic-gate /*
3610Sstevel@tonic-gate * Assignments to "n" in this block may appear
3620Sstevel@tonic-gate * to overflow in some cases. However, after careful
3630Sstevel@tonic-gate * analysis it was determined that all assignments to
3640Sstevel@tonic-gate * "n" serve only to make "n" smaller. Since "n"
3650Sstevel@tonic-gate * starts out as no larger than MAXBSIZE, "int" is
3660Sstevel@tonic-gate * safe.
3670Sstevel@tonic-gate */
3680Sstevel@tonic-gate off = uio->uio_loffset & MAXBMASK;
3690Sstevel@tonic-gate mapon = (int)(uio->uio_loffset & MAXBOFFSET);
3700Sstevel@tonic-gate n = MIN(MAXBSIZE - mapon, uio->uio_resid);
3710Sstevel@tonic-gate if (rw == UIO_READ) {
3720Sstevel@tonic-gate offset_t diff;
3730Sstevel@tonic-gate
3740Sstevel@tonic-gate diff = pcp->pc_size - uio->uio_loffset;
3750Sstevel@tonic-gate if (diff <= 0)
3760Sstevel@tonic-gate return (0);
3770Sstevel@tonic-gate if (diff < n)
3780Sstevel@tonic-gate n = (int)diff;
3790Sstevel@tonic-gate }
3800Sstevel@tonic-gate /*
3810Sstevel@tonic-gate * Compare limit with the actual offset + n, not the
3820Sstevel@tonic-gate * rounded down offset "off" or we will overflow
3830Sstevel@tonic-gate * the maximum file size after all.
3840Sstevel@tonic-gate */
3850Sstevel@tonic-gate if (rw == UIO_WRITE && uio->uio_loffset + n >= limit) {
3860Sstevel@tonic-gate if (uio->uio_loffset >= limit) {
3870Sstevel@tonic-gate error = EFBIG;
3880Sstevel@tonic-gate break;
3890Sstevel@tonic-gate }
3900Sstevel@tonic-gate n = (int)(limit - uio->uio_loffset);
3910Sstevel@tonic-gate }
3928059SDonghai.Qiao@Sun.COM
3938059SDonghai.Qiao@Sun.COM /*
3948059SDonghai.Qiao@Sun.COM * Touch the page and fault it in if it is not in
3958059SDonghai.Qiao@Sun.COM * core before segmap_getmapflt can lock it. This
3968059SDonghai.Qiao@Sun.COM * is to avoid the deadlock if the buffer is mapped
3978059SDonghai.Qiao@Sun.COM * to the same file through mmap which we want to
3988059SDonghai.Qiao@Sun.COM * write to.
3998059SDonghai.Qiao@Sun.COM */
4008059SDonghai.Qiao@Sun.COM uio_prefaultpages((long)n, uio);
4018059SDonghai.Qiao@Sun.COM
4020Sstevel@tonic-gate base = segmap_getmap(segkmap, vp, (u_offset_t)off);
4030Sstevel@tonic-gate pagecreate = 0;
4040Sstevel@tonic-gate newpage = 0;
4050Sstevel@tonic-gate if (rw == UIO_WRITE) {
4060Sstevel@tonic-gate /*
4070Sstevel@tonic-gate * If PAGESIZE < MAXBSIZE, perhaps we ought to deal
4080Sstevel@tonic-gate * with one page at a time, instead of one MAXBSIZE
4090Sstevel@tonic-gate * at a time, so we can fully explore pagecreate
4100Sstevel@tonic-gate * optimization??
4110Sstevel@tonic-gate */
4120Sstevel@tonic-gate if (uio->uio_loffset + n > pcp->pc_size) {
4130Sstevel@tonic-gate uint_t ncl, lcn;
4140Sstevel@tonic-gate
4150Sstevel@tonic-gate ncl = (uint_t)howmany((offset_t)pcp->pc_size,
4164723Sksn fsp->pcfs_clsize);
4170Sstevel@tonic-gate if (uio->uio_loffset > pcp->pc_size &&
4180Sstevel@tonic-gate ncl < (uint_t)howmany(uio->uio_loffset,
4194723Sksn fsp->pcfs_clsize)) {
4200Sstevel@tonic-gate /*
4210Sstevel@tonic-gate * Allocate and zerofill skipped
4220Sstevel@tonic-gate * clusters. This may not be worth the
4230Sstevel@tonic-gate * effort since a small lseek beyond
4240Sstevel@tonic-gate * eof but still within the cluster
4250Sstevel@tonic-gate * will not be zeroed out.
4260Sstevel@tonic-gate */
4270Sstevel@tonic-gate lcn = pc_lblkno(fsp, uio->uio_loffset);
4280Sstevel@tonic-gate error = pc_balloc(pcp, (daddr_t)lcn,
4290Sstevel@tonic-gate 1, &bn);
4300Sstevel@tonic-gate ncl = lcn + 1;
4310Sstevel@tonic-gate }
4320Sstevel@tonic-gate if (!error &&
4330Sstevel@tonic-gate ncl < (uint_t)howmany(uio->uio_loffset + n,
4344723Sksn fsp->pcfs_clsize))
4350Sstevel@tonic-gate /*
4360Sstevel@tonic-gate * allocate clusters w/o zerofill
4370Sstevel@tonic-gate */
4380Sstevel@tonic-gate error = pc_balloc(pcp,
4390Sstevel@tonic-gate (daddr_t)pc_lblkno(fsp,
4400Sstevel@tonic-gate uio->uio_loffset + n - 1),
4410Sstevel@tonic-gate 0, &bn);
4420Sstevel@tonic-gate
4430Sstevel@tonic-gate pcp->pc_flags |= PC_CHG;
4440Sstevel@tonic-gate
4450Sstevel@tonic-gate if (error) {
4462972Sfrankho pc_cluster32_t ncl;
4472972Sfrankho int nerror;
4482972Sfrankho
4492972Sfrankho /*
4502972Sfrankho * figure out new file size from
4512972Sfrankho * cluster chain length. If this
4522972Sfrankho * is detected to loop, the chain
4532972Sfrankho * is corrupted and we'd better
4542972Sfrankho * keep our fingers off that file.
4552972Sfrankho */
4562972Sfrankho nerror = pc_fileclsize(fsp,
4572972Sfrankho pcp->pc_scluster, &ncl);
4582972Sfrankho if (nerror) {
4592972Sfrankho PC_DPRINTF1(2,
4602972Sfrankho "cluster chain "
4612972Sfrankho "corruption, "
4622972Sfrankho "scluster=%d\n",
4632972Sfrankho pcp->pc_scluster);
4642972Sfrankho pcp->pc_size = 0;
4652972Sfrankho pcp->pc_flags |= PC_INVAL;
4662972Sfrankho error = nerror;
4672972Sfrankho (void) segmap_release(segkmap,
4682972Sfrankho base, 0);
4692972Sfrankho break;
4702972Sfrankho }
4712972Sfrankho pcp->pc_size = fsp->pcfs_clsize * ncl;
4720Sstevel@tonic-gate
4730Sstevel@tonic-gate if (error == ENOSPC &&
4740Sstevel@tonic-gate (pcp->pc_size - uio->uio_loffset)
4754723Sksn > 0) {
4760Sstevel@tonic-gate PC_DPRINTF3(2, "rwpcp ENOSPC "
4770Sstevel@tonic-gate "off=%lld n=%d size=%d\n",
4780Sstevel@tonic-gate uio->uio_loffset,
4790Sstevel@tonic-gate n, pcp->pc_size);
4800Sstevel@tonic-gate n = (int)(pcp->pc_size -
4814723Sksn uio->uio_loffset);
4820Sstevel@tonic-gate } else {
4830Sstevel@tonic-gate PC_DPRINTF1(1,
4840Sstevel@tonic-gate "rwpcp error1=%d\n", error);
4850Sstevel@tonic-gate (void) segmap_release(segkmap,
4860Sstevel@tonic-gate base, 0);
4870Sstevel@tonic-gate break;
4880Sstevel@tonic-gate }
4890Sstevel@tonic-gate } else {
4900Sstevel@tonic-gate pcp->pc_size =
4910Sstevel@tonic-gate (uint_t)(uio->uio_loffset + n);
4920Sstevel@tonic-gate }
4930Sstevel@tonic-gate if (mapon == 0) {
4940Sstevel@tonic-gate newpage = segmap_pagecreate(segkmap,
4954723Sksn base, (size_t)n, 0);
4960Sstevel@tonic-gate pagecreate = 1;
4970Sstevel@tonic-gate }
4980Sstevel@tonic-gate } else if (n == MAXBSIZE) {
4990Sstevel@tonic-gate newpage = segmap_pagecreate(segkmap, base,
5004723Sksn (size_t)n, 0);
5010Sstevel@tonic-gate pagecreate = 1;
5020Sstevel@tonic-gate }
5030Sstevel@tonic-gate }
5040Sstevel@tonic-gate error = uiomove(base + mapon, (size_t)n, rw, uio);
5050Sstevel@tonic-gate
5060Sstevel@tonic-gate if (pagecreate && uio->uio_loffset <
5074723Sksn roundup(off + mapon + n, PAGESIZE)) {
5080Sstevel@tonic-gate offset_t nzero, nmoved;
5090Sstevel@tonic-gate
5100Sstevel@tonic-gate nmoved = uio->uio_loffset - (off + mapon);
5110Sstevel@tonic-gate nzero = roundup(mapon + n, PAGESIZE) - nmoved;
5120Sstevel@tonic-gate (void) kzero(base + mapon + nmoved, (size_t)nzero);
5130Sstevel@tonic-gate }
5140Sstevel@tonic-gate
5150Sstevel@tonic-gate /*
5160Sstevel@tonic-gate * Unlock the pages which have been allocated by
5170Sstevel@tonic-gate * page_create_va() in segmap_pagecreate().
5180Sstevel@tonic-gate */
5195121Sfrankho if (newpage) {
5200Sstevel@tonic-gate segmap_pageunlock(segkmap, base, (size_t)n,
5214723Sksn rw == UIO_WRITE ? S_WRITE : S_READ);
5225121Sfrankho }
5230Sstevel@tonic-gate
5240Sstevel@tonic-gate if (error) {
5250Sstevel@tonic-gate PC_DPRINTF1(1, "rwpcp error2=%d\n", error);
5260Sstevel@tonic-gate /*
5270Sstevel@tonic-gate * If we failed on a write, we may have already
5280Sstevel@tonic-gate * allocated file blocks as well as pages. It's hard
5290Sstevel@tonic-gate * to undo the block allocation, but we must be sure
5300Sstevel@tonic-gate * to invalidate any pages that may have been
5310Sstevel@tonic-gate * allocated.
5320Sstevel@tonic-gate */
5330Sstevel@tonic-gate if (rw == UIO_WRITE)
5340Sstevel@tonic-gate (void) segmap_release(segkmap, base, SM_INVAL);
5350Sstevel@tonic-gate else
5360Sstevel@tonic-gate (void) segmap_release(segkmap, base, 0);
5370Sstevel@tonic-gate } else {
5380Sstevel@tonic-gate uint_t flags = 0;
5390Sstevel@tonic-gate
5400Sstevel@tonic-gate if (rw == UIO_READ) {
5410Sstevel@tonic-gate if (n + mapon == MAXBSIZE ||
5420Sstevel@tonic-gate uio->uio_loffset == pcp->pc_size)
5430Sstevel@tonic-gate flags = SM_DONTNEED;
5440Sstevel@tonic-gate } else if (ioflag & (FSYNC|FDSYNC)) {
5450Sstevel@tonic-gate flags = SM_WRITE;
5460Sstevel@tonic-gate } else if (n + mapon == MAXBSIZE) {
5470Sstevel@tonic-gate flags = SM_WRITE|SM_ASYNC|SM_DONTNEED;
5480Sstevel@tonic-gate }
5490Sstevel@tonic-gate error = segmap_release(segkmap, base, flags);
5500Sstevel@tonic-gate }
5510Sstevel@tonic-gate
5520Sstevel@tonic-gate } while (error == 0 && uio->uio_resid > 0 && n != 0);
5530Sstevel@tonic-gate
5540Sstevel@tonic-gate if (oresid != uio->uio_resid)
5550Sstevel@tonic-gate error = 0;
5560Sstevel@tonic-gate return (error);
5570Sstevel@tonic-gate }
5580Sstevel@tonic-gate
5590Sstevel@tonic-gate /*ARGSUSED*/
5600Sstevel@tonic-gate static int
pcfs_getattr(struct vnode * vp,struct vattr * vap,int flags,struct cred * cr,caller_context_t * ct)5610Sstevel@tonic-gate pcfs_getattr(
5620Sstevel@tonic-gate struct vnode *vp,
5630Sstevel@tonic-gate struct vattr *vap,
5640Sstevel@tonic-gate int flags,
5655331Samw struct cred *cr,
5665331Samw caller_context_t *ct)
5670Sstevel@tonic-gate {
5680Sstevel@tonic-gate struct pcnode *pcp;
5690Sstevel@tonic-gate struct pcfs *fsp;
5700Sstevel@tonic-gate int error;
5710Sstevel@tonic-gate char attr;
5720Sstevel@tonic-gate struct pctime atime;
5732720Sfrankho int64_t unixtime;
5740Sstevel@tonic-gate
5750Sstevel@tonic-gate PC_DPRINTF1(8, "pcfs_getattr: vp=%p\n", (void *)vp);
5760Sstevel@tonic-gate
5770Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp);
5780Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0);
5790Sstevel@tonic-gate if (error)
5800Sstevel@tonic-gate return (error);
5812972Sfrankho
5822972Sfrankho /*
5832972Sfrankho * Note that we don't check for "invalid node" (PC_INVAL) here
5842972Sfrankho * only in order to make stat() succeed. We allow no I/O on such
5855331Samw * a node, but do allow to check for its existence.
5862972Sfrankho */
5870Sstevel@tonic-gate if ((pcp = VTOPC(vp)) == NULL) {
5880Sstevel@tonic-gate pc_unlockfs(fsp);
5890Sstevel@tonic-gate return (EIO);
5900Sstevel@tonic-gate }
5910Sstevel@tonic-gate /*
5920Sstevel@tonic-gate * Copy from pcnode.
5930Sstevel@tonic-gate */
5940Sstevel@tonic-gate vap->va_type = vp->v_type;
5950Sstevel@tonic-gate attr = pcp->pc_entry.pcd_attr;
5960Sstevel@tonic-gate if (PCA_IS_HIDDEN(fsp, attr))
5970Sstevel@tonic-gate vap->va_mode = 0;
5980Sstevel@tonic-gate else if (attr & PCA_LABEL)
5990Sstevel@tonic-gate vap->va_mode = 0444;
6000Sstevel@tonic-gate else if (attr & PCA_RDONLY)
6010Sstevel@tonic-gate vap->va_mode = 0555;
6020Sstevel@tonic-gate else if (fsp->pcfs_flags & PCFS_BOOTPART) {
6030Sstevel@tonic-gate vap->va_mode = 0755;
6040Sstevel@tonic-gate } else {
6050Sstevel@tonic-gate vap->va_mode = 0777;
6060Sstevel@tonic-gate }
6070Sstevel@tonic-gate
6080Sstevel@tonic-gate if (attr & PCA_DIR)
6090Sstevel@tonic-gate vap->va_mode |= S_IFDIR;
6100Sstevel@tonic-gate else
6110Sstevel@tonic-gate vap->va_mode |= S_IFREG;
6120Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_BOOTPART) {
6130Sstevel@tonic-gate vap->va_uid = 0;
6140Sstevel@tonic-gate vap->va_gid = 0;
6150Sstevel@tonic-gate } else {
6160Sstevel@tonic-gate vap->va_uid = crgetuid(cr);
6170Sstevel@tonic-gate vap->va_gid = crgetgid(cr);
6180Sstevel@tonic-gate }
6190Sstevel@tonic-gate vap->va_fsid = vp->v_vfsp->vfs_dev;
6200Sstevel@tonic-gate vap->va_nodeid = (ino64_t)pc_makenodeid(pcp->pc_eblkno,
6210Sstevel@tonic-gate pcp->pc_eoffset, pcp->pc_entry.pcd_attr,
6225121Sfrankho pc_getstartcluster(fsp, &pcp->pc_entry), pc_direntpersec(fsp));
6230Sstevel@tonic-gate vap->va_nlink = 1;
6240Sstevel@tonic-gate vap->va_size = (u_offset_t)pcp->pc_size;
6255121Sfrankho vap->va_rdev = 0;
6265121Sfrankho vap->va_nblocks =
6275121Sfrankho (fsblkcnt64_t)howmany((offset_t)pcp->pc_size, DEV_BSIZE);
6285121Sfrankho vap->va_blksize = fsp->pcfs_clsize;
6295121Sfrankho
6305121Sfrankho /*
6315121Sfrankho * FAT root directories have no timestamps. In order not to return
6325121Sfrankho * "time zero" (1/1/1970), we record the time of the mount and give
6335121Sfrankho * that. This breaks less expectations.
6345121Sfrankho */
6355121Sfrankho if (vp->v_flag & VROOT) {
6365121Sfrankho vap->va_mtime = fsp->pcfs_mounttime;
6375121Sfrankho vap->va_atime = fsp->pcfs_mounttime;
6385121Sfrankho vap->va_ctime = fsp->pcfs_mounttime;
6395121Sfrankho pc_unlockfs(fsp);
6405121Sfrankho return (0);
6415121Sfrankho }
6422720Sfrankho
6432720Sfrankho pc_pcttotv(&pcp->pc_entry.pcd_mtime, &unixtime);
6442720Sfrankho if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0) {
6452720Sfrankho if (unixtime > INT32_MAX)
6462720Sfrankho DTRACE_PROBE1(pcfs__mtimeclamped, int64_t, unixtime);
6472720Sfrankho unixtime = MIN(unixtime, INT32_MAX);
6482720Sfrankho } else if (unixtime > INT32_MAX &&
6492720Sfrankho get_udatamodel() == DATAMODEL_ILP32) {
6502720Sfrankho pc_unlockfs(fsp);
6512720Sfrankho DTRACE_PROBE1(pcfs__mtimeoverflowed, int64_t, unixtime);
6522720Sfrankho return (EOVERFLOW);
6532720Sfrankho }
6542720Sfrankho
6552720Sfrankho vap->va_mtime.tv_sec = (time_t)unixtime;
6562720Sfrankho vap->va_mtime.tv_nsec = 0;
6572720Sfrankho
6582720Sfrankho /*
6592720Sfrankho * FAT doesn't know about POSIX ctime.
6602720Sfrankho * Best approximation is to always set it to mtime.
6612720Sfrankho */
6620Sstevel@tonic-gate vap->va_ctime = vap->va_mtime;
6632720Sfrankho
6642720Sfrankho /*
6652720Sfrankho * FAT only stores "last access date". If that's the
6662720Sfrankho * same as the date of last modification then the time
6672720Sfrankho * of last access is known. Otherwise, use midnight.
6682720Sfrankho */
6690Sstevel@tonic-gate atime.pct_date = pcp->pc_entry.pcd_ladate;
6702720Sfrankho if (atime.pct_date == pcp->pc_entry.pcd_mtime.pct_date)
6712720Sfrankho atime.pct_time = pcp->pc_entry.pcd_mtime.pct_time;
6722720Sfrankho else
6732720Sfrankho atime.pct_time = 0;
6742720Sfrankho pc_pcttotv(&atime, &unixtime);
6752720Sfrankho if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0) {
6762720Sfrankho if (unixtime > INT32_MAX)
6772720Sfrankho DTRACE_PROBE1(pcfs__atimeclamped, int64_t, unixtime);
6782720Sfrankho unixtime = MIN(unixtime, INT32_MAX);
6792720Sfrankho } else if (unixtime > INT32_MAX &&
6802720Sfrankho get_udatamodel() == DATAMODEL_ILP32) {
6812720Sfrankho pc_unlockfs(fsp);
6822720Sfrankho DTRACE_PROBE1(pcfs__atimeoverflowed, int64_t, unixtime);
6832720Sfrankho return (EOVERFLOW);
6842720Sfrankho }
6852720Sfrankho
6862720Sfrankho vap->va_atime.tv_sec = (time_t)unixtime;
6872720Sfrankho vap->va_atime.tv_nsec = 0;
6882720Sfrankho
6890Sstevel@tonic-gate pc_unlockfs(fsp);
6900Sstevel@tonic-gate return (0);
6910Sstevel@tonic-gate }
6920Sstevel@tonic-gate
6930Sstevel@tonic-gate
6940Sstevel@tonic-gate /*ARGSUSED*/
6950Sstevel@tonic-gate static int
pcfs_setattr(struct vnode * vp,struct vattr * vap,int flags,struct cred * cr,caller_context_t * ct)6960Sstevel@tonic-gate pcfs_setattr(
6970Sstevel@tonic-gate struct vnode *vp,
6980Sstevel@tonic-gate struct vattr *vap,
6990Sstevel@tonic-gate int flags,
7000Sstevel@tonic-gate struct cred *cr,
7010Sstevel@tonic-gate caller_context_t *ct)
7020Sstevel@tonic-gate {
7030Sstevel@tonic-gate struct pcnode *pcp;
7040Sstevel@tonic-gate mode_t mask = vap->va_mask;
7050Sstevel@tonic-gate int error;
7060Sstevel@tonic-gate struct pcfs *fsp;
7072720Sfrankho timestruc_t now, *timep;
7080Sstevel@tonic-gate
7090Sstevel@tonic-gate PC_DPRINTF2(6, "pcfs_setattr: vp=%p mask=%x\n", (void *)vp, (int)mask);
7100Sstevel@tonic-gate /*
7110Sstevel@tonic-gate * cannot set these attributes
7120Sstevel@tonic-gate */
7130Sstevel@tonic-gate if (mask & (AT_NOSET | AT_UID | AT_GID)) {
7140Sstevel@tonic-gate return (EINVAL);
7150Sstevel@tonic-gate }
7160Sstevel@tonic-gate /*
7172720Sfrankho * pcfs_setattr is now allowed on directories to avoid silly warnings
7180Sstevel@tonic-gate * from 'tar' when it tries to set times on a directory, and console
7190Sstevel@tonic-gate * printf's on the NFS server when it gets EINVAL back on such a
7200Sstevel@tonic-gate * request. One possible problem with that since a directory entry
7210Sstevel@tonic-gate * identifies a file, '.' and all the '..' entries in subdirectories
7220Sstevel@tonic-gate * may get out of sync when the directory is updated since they're
7230Sstevel@tonic-gate * treated like separate files. We could fix that by looking for
7240Sstevel@tonic-gate * '.' and giving it the same attributes, and then looking for
7250Sstevel@tonic-gate * all the subdirectories and updating '..', but that's pretty
7260Sstevel@tonic-gate * expensive for something that doesn't seem likely to matter.
7270Sstevel@tonic-gate */
7280Sstevel@tonic-gate /* can't do some ops on directories anyway */
7290Sstevel@tonic-gate if ((vp->v_type == VDIR) &&
7300Sstevel@tonic-gate (mask & AT_SIZE)) {
7310Sstevel@tonic-gate return (EINVAL);
7320Sstevel@tonic-gate }
7330Sstevel@tonic-gate
7340Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp);
7350Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0);
7360Sstevel@tonic-gate if (error)
7370Sstevel@tonic-gate return (error);
7382972Sfrankho if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) {
7390Sstevel@tonic-gate pc_unlockfs(fsp);
7400Sstevel@tonic-gate return (EIO);
7410Sstevel@tonic-gate }
7420Sstevel@tonic-gate
7430Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_BOOTPART) {
7440Sstevel@tonic-gate if (secpolicy_pcfs_modify_bootpartition(cr) != 0) {
7450Sstevel@tonic-gate pc_unlockfs(fsp);
7460Sstevel@tonic-gate return (EACCES);
7470Sstevel@tonic-gate }
7480Sstevel@tonic-gate }
7490Sstevel@tonic-gate
7500Sstevel@tonic-gate /*
7510Sstevel@tonic-gate * Change file access modes.
7520Sstevel@tonic-gate * If nobody has write permission, file is marked readonly.
7530Sstevel@tonic-gate * Otherwise file is writable by anyone.
7540Sstevel@tonic-gate */
7550Sstevel@tonic-gate if ((mask & AT_MODE) && (vap->va_mode != (mode_t)-1)) {
7560Sstevel@tonic-gate if ((vap->va_mode & 0222) == 0)
7570Sstevel@tonic-gate pcp->pc_entry.pcd_attr |= PCA_RDONLY;
7580Sstevel@tonic-gate else
7590Sstevel@tonic-gate pcp->pc_entry.pcd_attr &= ~PCA_RDONLY;
7600Sstevel@tonic-gate pcp->pc_flags |= PC_CHG;
7610Sstevel@tonic-gate }
7620Sstevel@tonic-gate /*
7630Sstevel@tonic-gate * Truncate file. Must have write permission.
7640Sstevel@tonic-gate */
7650Sstevel@tonic-gate if ((mask & AT_SIZE) && (vap->va_size != (u_offset_t)-1)) {
7660Sstevel@tonic-gate if (pcp->pc_entry.pcd_attr & PCA_RDONLY) {
7670Sstevel@tonic-gate error = EACCES;
7680Sstevel@tonic-gate goto out;
7690Sstevel@tonic-gate }
7700Sstevel@tonic-gate if (vap->va_size > UINT32_MAX) {
7710Sstevel@tonic-gate error = EFBIG;
7720Sstevel@tonic-gate goto out;
7730Sstevel@tonic-gate }
7740Sstevel@tonic-gate error = pc_truncate(pcp, (uint_t)vap->va_size);
7750Sstevel@tonic-gate if (error)
7760Sstevel@tonic-gate goto out;
7770Sstevel@tonic-gate }
7780Sstevel@tonic-gate /*
7790Sstevel@tonic-gate * Change file modified times.
7800Sstevel@tonic-gate */
7812720Sfrankho if (mask & (AT_MTIME | AT_CTIME)) {
7820Sstevel@tonic-gate /*
7830Sstevel@tonic-gate * If SysV-compatible option to set access and
7840Sstevel@tonic-gate * modified times if privileged, owner, or write access,
7850Sstevel@tonic-gate * use current time rather than va_mtime.
7860Sstevel@tonic-gate *
7870Sstevel@tonic-gate * XXX - va_mtime.tv_sec == -1 flags this.
7880Sstevel@tonic-gate */
7892720Sfrankho timep = &vap->va_mtime;
7900Sstevel@tonic-gate if (vap->va_mtime.tv_sec == -1) {
7910Sstevel@tonic-gate gethrestime(&now);
7922720Sfrankho timep = &now;
7930Sstevel@tonic-gate }
7942720Sfrankho if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0 &&
7952720Sfrankho timep->tv_sec > INT32_MAX) {
7962720Sfrankho error = EOVERFLOW;
7972720Sfrankho goto out;
7982720Sfrankho }
7992720Sfrankho error = pc_tvtopct(timep, &pcp->pc_entry.pcd_mtime);
8002720Sfrankho if (error)
8012720Sfrankho goto out;
8020Sstevel@tonic-gate pcp->pc_flags |= PC_CHG;
8030Sstevel@tonic-gate }
8040Sstevel@tonic-gate /*
8050Sstevel@tonic-gate * Change file access times.
8060Sstevel@tonic-gate */
8072720Sfrankho if (mask & AT_ATIME) {
8080Sstevel@tonic-gate /*
8090Sstevel@tonic-gate * If SysV-compatible option to set access and
8100Sstevel@tonic-gate * modified times if privileged, owner, or write access,
8110Sstevel@tonic-gate * use current time rather than va_mtime.
8120Sstevel@tonic-gate *
8130Sstevel@tonic-gate * XXX - va_atime.tv_sec == -1 flags this.
8140Sstevel@tonic-gate */
8150Sstevel@tonic-gate struct pctime atime;
8160Sstevel@tonic-gate
8172720Sfrankho timep = &vap->va_atime;
8180Sstevel@tonic-gate if (vap->va_atime.tv_sec == -1) {
8190Sstevel@tonic-gate gethrestime(&now);
8202720Sfrankho timep = &now;
8210Sstevel@tonic-gate }
8222720Sfrankho if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0 &&
8232720Sfrankho timep->tv_sec > INT32_MAX) {
8242720Sfrankho error = EOVERFLOW;
8252720Sfrankho goto out;
8262720Sfrankho }
8272720Sfrankho error = pc_tvtopct(timep, &atime);
8282720Sfrankho if (error)
8292720Sfrankho goto out;
8300Sstevel@tonic-gate pcp->pc_entry.pcd_ladate = atime.pct_date;
8310Sstevel@tonic-gate pcp->pc_flags |= PC_CHG;
8320Sstevel@tonic-gate }
8330Sstevel@tonic-gate out:
8340Sstevel@tonic-gate pc_unlockfs(fsp);
8350Sstevel@tonic-gate return (error);
8360Sstevel@tonic-gate }
8370Sstevel@tonic-gate
8380Sstevel@tonic-gate
8390Sstevel@tonic-gate /*ARGSUSED*/
8400Sstevel@tonic-gate static int
pcfs_access(struct vnode * vp,int mode,int flags,struct cred * cr,caller_context_t * ct)8410Sstevel@tonic-gate pcfs_access(
8420Sstevel@tonic-gate struct vnode *vp,
8430Sstevel@tonic-gate int mode,
8440Sstevel@tonic-gate int flags,
8455331Samw struct cred *cr,
8465331Samw caller_context_t *ct)
8470Sstevel@tonic-gate {
8480Sstevel@tonic-gate struct pcnode *pcp;
8490Sstevel@tonic-gate struct pcfs *fsp;
8500Sstevel@tonic-gate
8510Sstevel@tonic-gate
8520Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp);
8530Sstevel@tonic-gate
8542972Sfrankho if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL)
8550Sstevel@tonic-gate return (EIO);
8560Sstevel@tonic-gate if ((mode & VWRITE) && (pcp->pc_entry.pcd_attr & PCA_RDONLY))
8570Sstevel@tonic-gate return (EACCES);
8580Sstevel@tonic-gate
8590Sstevel@tonic-gate /*
8600Sstevel@tonic-gate * If this is a boot partition, privileged users have full access while
8610Sstevel@tonic-gate * others have read-only access.
8620Sstevel@tonic-gate */
8630Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_BOOTPART) {
8640Sstevel@tonic-gate if ((mode & VWRITE) &&
8650Sstevel@tonic-gate secpolicy_pcfs_modify_bootpartition(cr) != 0)
8660Sstevel@tonic-gate return (EACCES);
8670Sstevel@tonic-gate }
8680Sstevel@tonic-gate return (0);
8690Sstevel@tonic-gate }
8700Sstevel@tonic-gate
8710Sstevel@tonic-gate
8720Sstevel@tonic-gate /*ARGSUSED*/
8730Sstevel@tonic-gate static int
pcfs_fsync(struct vnode * vp,int syncflag,struct cred * cr,caller_context_t * ct)8740Sstevel@tonic-gate pcfs_fsync(
8750Sstevel@tonic-gate struct vnode *vp,
8760Sstevel@tonic-gate int syncflag,
8775331Samw struct cred *cr,
8785331Samw caller_context_t *ct)
8790Sstevel@tonic-gate {
8800Sstevel@tonic-gate struct pcfs *fsp;
8810Sstevel@tonic-gate struct pcnode *pcp;
8820Sstevel@tonic-gate int error;
8830Sstevel@tonic-gate
8840Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp);
8850Sstevel@tonic-gate if (error = pc_verify(fsp))
8860Sstevel@tonic-gate return (error);
8870Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0);
8880Sstevel@tonic-gate if (error)
8890Sstevel@tonic-gate return (error);
8902972Sfrankho if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) {
8910Sstevel@tonic-gate pc_unlockfs(fsp);
8920Sstevel@tonic-gate return (EIO);
8930Sstevel@tonic-gate }
8940Sstevel@tonic-gate rw_enter(&pcnodes_lock, RW_WRITER);
8950Sstevel@tonic-gate error = pc_nodesync(pcp);
8960Sstevel@tonic-gate rw_exit(&pcnodes_lock);
8970Sstevel@tonic-gate pc_unlockfs(fsp);
8980Sstevel@tonic-gate return (error);
8990Sstevel@tonic-gate }
9000Sstevel@tonic-gate
9010Sstevel@tonic-gate
9020Sstevel@tonic-gate /*ARGSUSED*/
9030Sstevel@tonic-gate static void
pcfs_inactive(struct vnode * vp,struct cred * cr,caller_context_t * ct)9040Sstevel@tonic-gate pcfs_inactive(
9050Sstevel@tonic-gate struct vnode *vp,
9065331Samw struct cred *cr,
9075331Samw caller_context_t *ct)
9080Sstevel@tonic-gate {
9090Sstevel@tonic-gate struct pcnode *pcp;
9100Sstevel@tonic-gate struct pcfs *fsp;
9110Sstevel@tonic-gate int error;
9120Sstevel@tonic-gate
9130Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp);
9140Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 1);
9150Sstevel@tonic-gate
9162720Sfrankho /*
9172720Sfrankho * If the filesystem was umounted by force, all dirty
9182720Sfrankho * pages associated with this vnode are invalidated
9192720Sfrankho * and then the vnode will be freed.
9202720Sfrankho */
9212720Sfrankho if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) {
9222720Sfrankho pcp = VTOPC(vp);
9232720Sfrankho if (vn_has_cached_data(vp)) {
9242720Sfrankho (void) pvn_vplist_dirty(vp, (u_offset_t)0,
9252720Sfrankho pcfs_putapage, B_INVAL, (struct cred *)NULL);
9262720Sfrankho }
9272720Sfrankho remque(pcp);
9282720Sfrankho if (error == 0)
9292720Sfrankho pc_unlockfs(fsp);
9302720Sfrankho vn_free(vp);
9312720Sfrankho kmem_free(pcp, sizeof (struct pcnode));
9322720Sfrankho VFS_RELE(PCFSTOVFS(fsp));
9332720Sfrankho return;
9342720Sfrankho }
9352720Sfrankho
9360Sstevel@tonic-gate mutex_enter(&vp->v_lock);
9370Sstevel@tonic-gate ASSERT(vp->v_count >= 1);
9380Sstevel@tonic-gate if (vp->v_count > 1) {
9390Sstevel@tonic-gate vp->v_count--; /* release our hold from vn_rele */
9400Sstevel@tonic-gate mutex_exit(&vp->v_lock);
9410Sstevel@tonic-gate pc_unlockfs(fsp);
9420Sstevel@tonic-gate return;
9430Sstevel@tonic-gate }
9440Sstevel@tonic-gate mutex_exit(&vp->v_lock);
9450Sstevel@tonic-gate
9460Sstevel@tonic-gate /*
9470Sstevel@tonic-gate * Check again to confirm that no intervening I/O error
9480Sstevel@tonic-gate * with a subsequent pc_diskchanged() call has released
9492972Sfrankho * the pcnode. If it has then release the vnode as above.
9500Sstevel@tonic-gate */
9512972Sfrankho pcp = VTOPC(vp);
9522972Sfrankho if (pcp == NULL || pcp->pc_flags & PC_INVAL) {
9532720Sfrankho if (vn_has_cached_data(vp))
9542720Sfrankho (void) pvn_vplist_dirty(vp, (u_offset_t)0,
9552720Sfrankho pcfs_putapage, B_INVAL | B_TRUNC,
9562720Sfrankho (struct cred *)NULL);
9572972Sfrankho }
9582972Sfrankho
9592972Sfrankho if (pcp == NULL) {
9600Sstevel@tonic-gate vn_free(vp);
9612720Sfrankho } else {
9620Sstevel@tonic-gate pc_rele(pcp);
9632720Sfrankho }
9640Sstevel@tonic-gate
9650Sstevel@tonic-gate if (!error)
9660Sstevel@tonic-gate pc_unlockfs(fsp);
9670Sstevel@tonic-gate }
9680Sstevel@tonic-gate
9690Sstevel@tonic-gate /*ARGSUSED*/
9700Sstevel@tonic-gate static int
pcfs_lookup(struct vnode * dvp,char * nm,struct vnode ** vpp,struct pathname * pnp,int flags,struct vnode * rdir,struct cred * cr,caller_context_t * ct,int * direntflags,pathname_t * realpnp)9710Sstevel@tonic-gate pcfs_lookup(
9720Sstevel@tonic-gate struct vnode *dvp,
9730Sstevel@tonic-gate char *nm,
9740Sstevel@tonic-gate struct vnode **vpp,
9750Sstevel@tonic-gate struct pathname *pnp,
9760Sstevel@tonic-gate int flags,
9770Sstevel@tonic-gate struct vnode *rdir,
9785331Samw struct cred *cr,
9795331Samw caller_context_t *ct,
9805331Samw int *direntflags,
9815331Samw pathname_t *realpnp)
9820Sstevel@tonic-gate {
9830Sstevel@tonic-gate struct pcfs *fsp;
9840Sstevel@tonic-gate struct pcnode *pcp;
9850Sstevel@tonic-gate int error;
9860Sstevel@tonic-gate
9870Sstevel@tonic-gate /*
9882720Sfrankho * If the filesystem was umounted by force, return immediately.
9892720Sfrankho */
9902720Sfrankho if (dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
9912720Sfrankho return (EIO);
9922720Sfrankho
9932720Sfrankho /*
9940Sstevel@tonic-gate * verify that the dvp is still valid on the disk
9950Sstevel@tonic-gate */
9960Sstevel@tonic-gate fsp = VFSTOPCFS(dvp->v_vfsp);
9970Sstevel@tonic-gate if (error = pc_verify(fsp))
9980Sstevel@tonic-gate return (error);
9990Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0);
10000Sstevel@tonic-gate if (error)
10010Sstevel@tonic-gate return (error);
10022972Sfrankho if (VTOPC(dvp) == NULL || VTOPC(dvp)->pc_flags & PC_INVAL) {
10030Sstevel@tonic-gate pc_unlockfs(fsp);
10040Sstevel@tonic-gate return (EIO);
10050Sstevel@tonic-gate }
10060Sstevel@tonic-gate /*
10070Sstevel@tonic-gate * Null component name is a synonym for directory being searched.
10080Sstevel@tonic-gate */
10090Sstevel@tonic-gate if (*nm == '\0') {
10100Sstevel@tonic-gate VN_HOLD(dvp);
10110Sstevel@tonic-gate *vpp = dvp;
10120Sstevel@tonic-gate pc_unlockfs(fsp);
10130Sstevel@tonic-gate return (0);
10140Sstevel@tonic-gate }
10150Sstevel@tonic-gate
10160Sstevel@tonic-gate error = pc_dirlook(VTOPC(dvp), nm, &pcp);
10170Sstevel@tonic-gate if (!error) {
10180Sstevel@tonic-gate *vpp = PCTOV(pcp);
10190Sstevel@tonic-gate pcp->pc_flags |= PC_EXTERNAL;
10200Sstevel@tonic-gate }
10210Sstevel@tonic-gate pc_unlockfs(fsp);
10220Sstevel@tonic-gate return (error);
10230Sstevel@tonic-gate }
10240Sstevel@tonic-gate
10250Sstevel@tonic-gate
10260Sstevel@tonic-gate /*ARGSUSED*/
10270Sstevel@tonic-gate static int
pcfs_create(struct vnode * dvp,char * nm,struct vattr * vap,enum vcexcl exclusive,int mode,struct vnode ** vpp,struct cred * cr,int flag,caller_context_t * ct,vsecattr_t * vsecp)10280Sstevel@tonic-gate pcfs_create(
10290Sstevel@tonic-gate struct vnode *dvp,
10300Sstevel@tonic-gate char *nm,
10310Sstevel@tonic-gate struct vattr *vap,
10320Sstevel@tonic-gate enum vcexcl exclusive,
10330Sstevel@tonic-gate int mode,
10340Sstevel@tonic-gate struct vnode **vpp,
10350Sstevel@tonic-gate struct cred *cr,
10365331Samw int flag,
10375331Samw caller_context_t *ct,
10385331Samw vsecattr_t *vsecp)
10390Sstevel@tonic-gate {
10400Sstevel@tonic-gate int error;
10410Sstevel@tonic-gate struct pcnode *pcp;
10420Sstevel@tonic-gate struct vnode *vp;
10430Sstevel@tonic-gate struct pcfs *fsp;
10440Sstevel@tonic-gate
10450Sstevel@tonic-gate /*
10460Sstevel@tonic-gate * can't create directories. use pcfs_mkdir.
10470Sstevel@tonic-gate * can't create anything other than files.
10480Sstevel@tonic-gate */
10490Sstevel@tonic-gate if (vap->va_type == VDIR)
10500Sstevel@tonic-gate return (EISDIR);
10510Sstevel@tonic-gate else if (vap->va_type != VREG)
10520Sstevel@tonic-gate return (EINVAL);
10530Sstevel@tonic-gate
10540Sstevel@tonic-gate pcp = NULL;
10550Sstevel@tonic-gate fsp = VFSTOPCFS(dvp->v_vfsp);
10560Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0);
10570Sstevel@tonic-gate if (error)
10580Sstevel@tonic-gate return (error);
10592972Sfrankho if (VTOPC(dvp) == NULL || VTOPC(dvp)->pc_flags & PC_INVAL) {
10600Sstevel@tonic-gate pc_unlockfs(fsp);
10610Sstevel@tonic-gate return (EIO);
10620Sstevel@tonic-gate }
10630Sstevel@tonic-gate
10640Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_BOOTPART) {
10650Sstevel@tonic-gate if (secpolicy_pcfs_modify_bootpartition(cr) != 0) {
10660Sstevel@tonic-gate pc_unlockfs(fsp);
10670Sstevel@tonic-gate return (EACCES);
10680Sstevel@tonic-gate }
10690Sstevel@tonic-gate }
10700Sstevel@tonic-gate
10710Sstevel@tonic-gate if (*nm == '\0') {
10720Sstevel@tonic-gate /*
10730Sstevel@tonic-gate * Null component name refers to the directory itself.
10740Sstevel@tonic-gate */
10750Sstevel@tonic-gate VN_HOLD(dvp);
10760Sstevel@tonic-gate pcp = VTOPC(dvp);
10770Sstevel@tonic-gate error = EEXIST;
10780Sstevel@tonic-gate } else {
10790Sstevel@tonic-gate error = pc_direnter(VTOPC(dvp), nm, vap, &pcp);
10800Sstevel@tonic-gate }
10810Sstevel@tonic-gate /*
10820Sstevel@tonic-gate * if file exists and this is a nonexclusive create,
10830Sstevel@tonic-gate * check for access permissions
10840Sstevel@tonic-gate */
10850Sstevel@tonic-gate if (error == EEXIST) {
10860Sstevel@tonic-gate vp = PCTOV(pcp);
10870Sstevel@tonic-gate if (exclusive == NONEXCL) {
10880Sstevel@tonic-gate if (vp->v_type == VDIR) {
10890Sstevel@tonic-gate error = EISDIR;
10900Sstevel@tonic-gate } else if (mode) {
10910Sstevel@tonic-gate error = pcfs_access(PCTOV(pcp), mode, 0,
10925331Samw cr, ct);
10930Sstevel@tonic-gate } else {
10940Sstevel@tonic-gate error = 0;
10950Sstevel@tonic-gate }
10960Sstevel@tonic-gate }
10970Sstevel@tonic-gate if (error) {
10980Sstevel@tonic-gate VN_RELE(PCTOV(pcp));
10990Sstevel@tonic-gate } else if ((vp->v_type == VREG) && (vap->va_mask & AT_SIZE) &&
11004723Sksn (vap->va_size == 0)) {
11010Sstevel@tonic-gate error = pc_truncate(pcp, 0L);
11024863Spraks if (error) {
11030Sstevel@tonic-gate VN_RELE(PCTOV(pcp));
11044863Spraks } else {
11055331Samw vnevent_create(PCTOV(pcp), ct);
11064863Spraks }
11070Sstevel@tonic-gate }
11080Sstevel@tonic-gate }
11090Sstevel@tonic-gate if (error) {
11100Sstevel@tonic-gate pc_unlockfs(fsp);
11110Sstevel@tonic-gate return (error);
11120Sstevel@tonic-gate }
11130Sstevel@tonic-gate *vpp = PCTOV(pcp);
11140Sstevel@tonic-gate pcp->pc_flags |= PC_EXTERNAL;
11150Sstevel@tonic-gate pc_unlockfs(fsp);
11160Sstevel@tonic-gate return (error);
11170Sstevel@tonic-gate }
11180Sstevel@tonic-gate
11190Sstevel@tonic-gate /*ARGSUSED*/
11200Sstevel@tonic-gate static int
pcfs_remove(struct vnode * vp,char * nm,struct cred * cr,caller_context_t * ct,int flags)11210Sstevel@tonic-gate pcfs_remove(
11220Sstevel@tonic-gate struct vnode *vp,
11230Sstevel@tonic-gate char *nm,
11245331Samw struct cred *cr,
11255331Samw caller_context_t *ct,
11265331Samw int flags)
11270Sstevel@tonic-gate {
11280Sstevel@tonic-gate struct pcfs *fsp;
11290Sstevel@tonic-gate struct pcnode *pcp;
11300Sstevel@tonic-gate int error;
11310Sstevel@tonic-gate
11320Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp);
11330Sstevel@tonic-gate if (error = pc_verify(fsp))
11340Sstevel@tonic-gate return (error);
11350Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0);
11360Sstevel@tonic-gate if (error)
11370Sstevel@tonic-gate return (error);
11382972Sfrankho if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) {
11390Sstevel@tonic-gate pc_unlockfs(fsp);
11400Sstevel@tonic-gate return (EIO);
11410Sstevel@tonic-gate }
11420Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_BOOTPART) {
11430Sstevel@tonic-gate if (secpolicy_pcfs_modify_bootpartition(cr) != 0) {
11440Sstevel@tonic-gate pc_unlockfs(fsp);
11450Sstevel@tonic-gate return (EACCES);
11460Sstevel@tonic-gate }
11470Sstevel@tonic-gate }
11485331Samw error = pc_dirremove(pcp, nm, (struct vnode *)0, VREG, ct);
11490Sstevel@tonic-gate pc_unlockfs(fsp);
11500Sstevel@tonic-gate return (error);
11510Sstevel@tonic-gate }
11520Sstevel@tonic-gate
11530Sstevel@tonic-gate /*
11540Sstevel@tonic-gate * Rename a file or directory
11550Sstevel@tonic-gate * This rename is restricted to only rename files within a directory.
11560Sstevel@tonic-gate * XX should make rename more general
11570Sstevel@tonic-gate */
11580Sstevel@tonic-gate /*ARGSUSED*/
11590Sstevel@tonic-gate static int
pcfs_rename(struct vnode * sdvp,char * snm,struct vnode * tdvp,char * tnm,struct cred * cr,caller_context_t * ct,int flags)11600Sstevel@tonic-gate pcfs_rename(
11610Sstevel@tonic-gate struct vnode *sdvp, /* old (source) parent vnode */
11620Sstevel@tonic-gate char *snm, /* old (source) entry name */
11630Sstevel@tonic-gate struct vnode *tdvp, /* new (target) parent vnode */
11640Sstevel@tonic-gate char *tnm, /* new (target) entry name */
11655331Samw struct cred *cr,
11665331Samw caller_context_t *ct,
11675331Samw int flags)
11680Sstevel@tonic-gate {
11690Sstevel@tonic-gate struct pcfs *fsp;
11700Sstevel@tonic-gate struct pcnode *dp; /* parent pcnode */
11710Sstevel@tonic-gate struct pcnode *tdp;
11720Sstevel@tonic-gate int error;
11730Sstevel@tonic-gate
11740Sstevel@tonic-gate fsp = VFSTOPCFS(sdvp->v_vfsp);
11750Sstevel@tonic-gate if (error = pc_verify(fsp))
11760Sstevel@tonic-gate return (error);
11770Sstevel@tonic-gate
11780Sstevel@tonic-gate /*
11790Sstevel@tonic-gate * make sure we can muck with this directory.
11800Sstevel@tonic-gate */
11815331Samw error = pcfs_access(sdvp, VWRITE, 0, cr, ct);
11820Sstevel@tonic-gate if (error) {
11830Sstevel@tonic-gate return (error);
11840Sstevel@tonic-gate }
11850Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0);
11860Sstevel@tonic-gate if (error)
11870Sstevel@tonic-gate return (error);
11882972Sfrankho if (((dp = VTOPC(sdvp)) == NULL) || ((tdp = VTOPC(tdvp)) == NULL) ||
11892972Sfrankho (dp->pc_flags & PC_INVAL) || (tdp->pc_flags & PC_INVAL)) {
11900Sstevel@tonic-gate pc_unlockfs(fsp);
11910Sstevel@tonic-gate return (EIO);
11920Sstevel@tonic-gate }
11935331Samw error = pc_rename(dp, tdp, snm, tnm, ct);
11940Sstevel@tonic-gate pc_unlockfs(fsp);
11950Sstevel@tonic-gate return (error);
11960Sstevel@tonic-gate }
11970Sstevel@tonic-gate
11980Sstevel@tonic-gate /*ARGSUSED*/
11990Sstevel@tonic-gate static int
pcfs_mkdir(struct vnode * dvp,char * nm,struct vattr * vap,struct vnode ** vpp,struct cred * cr,caller_context_t * ct,int flags,vsecattr_t * vsecp)12000Sstevel@tonic-gate pcfs_mkdir(
12010Sstevel@tonic-gate struct vnode *dvp,
12020Sstevel@tonic-gate char *nm,
12030Sstevel@tonic-gate struct vattr *vap,
12040Sstevel@tonic-gate struct vnode **vpp,
12055331Samw struct cred *cr,
12065331Samw caller_context_t *ct,
12075331Samw int flags,
12085331Samw vsecattr_t *vsecp)
12090Sstevel@tonic-gate {
12100Sstevel@tonic-gate struct pcfs *fsp;
12110Sstevel@tonic-gate struct pcnode *pcp;
12120Sstevel@tonic-gate int error;
12130Sstevel@tonic-gate
12140Sstevel@tonic-gate fsp = VFSTOPCFS(dvp->v_vfsp);
12150Sstevel@tonic-gate if (error = pc_verify(fsp))
12160Sstevel@tonic-gate return (error);
12170Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0);
12180Sstevel@tonic-gate if (error)
12190Sstevel@tonic-gate return (error);
12202972Sfrankho if (VTOPC(dvp) == NULL || VTOPC(dvp)->pc_flags & PC_INVAL) {
12210Sstevel@tonic-gate pc_unlockfs(fsp);
12220Sstevel@tonic-gate return (EIO);
12230Sstevel@tonic-gate }
12240Sstevel@tonic-gate
12250Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_BOOTPART) {
12260Sstevel@tonic-gate if (secpolicy_pcfs_modify_bootpartition(cr) != 0) {
12270Sstevel@tonic-gate pc_unlockfs(fsp);
12280Sstevel@tonic-gate return (EACCES);
12290Sstevel@tonic-gate }
12300Sstevel@tonic-gate }
12310Sstevel@tonic-gate
12320Sstevel@tonic-gate error = pc_direnter(VTOPC(dvp), nm, vap, &pcp);
12330Sstevel@tonic-gate
12340Sstevel@tonic-gate if (!error) {
12350Sstevel@tonic-gate pcp -> pc_flags |= PC_EXTERNAL;
12360Sstevel@tonic-gate *vpp = PCTOV(pcp);
12370Sstevel@tonic-gate } else if (error == EEXIST) {
12380Sstevel@tonic-gate VN_RELE(PCTOV(pcp));
12390Sstevel@tonic-gate }
12400Sstevel@tonic-gate pc_unlockfs(fsp);
12410Sstevel@tonic-gate return (error);
12420Sstevel@tonic-gate }
12430Sstevel@tonic-gate
12440Sstevel@tonic-gate /*ARGSUSED*/
12450Sstevel@tonic-gate static int
pcfs_rmdir(struct vnode * dvp,char * nm,struct vnode * cdir,struct cred * cr,caller_context_t * ct,int flags)12460Sstevel@tonic-gate pcfs_rmdir(
12470Sstevel@tonic-gate struct vnode *dvp,
12480Sstevel@tonic-gate char *nm,
12490Sstevel@tonic-gate struct vnode *cdir,
12505331Samw struct cred *cr,
12515331Samw caller_context_t *ct,
12525331Samw int flags)
12530Sstevel@tonic-gate {
12540Sstevel@tonic-gate struct pcfs *fsp;
12550Sstevel@tonic-gate struct pcnode *pcp;
12560Sstevel@tonic-gate int error;
12570Sstevel@tonic-gate
12580Sstevel@tonic-gate fsp = VFSTOPCFS(dvp -> v_vfsp);
12590Sstevel@tonic-gate if (error = pc_verify(fsp))
12600Sstevel@tonic-gate return (error);
12610Sstevel@tonic-gate if (error = pc_lockfs(fsp, 0, 0))
12620Sstevel@tonic-gate return (error);
12630Sstevel@tonic-gate
12642972Sfrankho if ((pcp = VTOPC(dvp)) == NULL || pcp->pc_flags & PC_INVAL) {
12650Sstevel@tonic-gate pc_unlockfs(fsp);
12660Sstevel@tonic-gate return (EIO);
12670Sstevel@tonic-gate }
12680Sstevel@tonic-gate
12690Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_BOOTPART) {
12700Sstevel@tonic-gate if (secpolicy_pcfs_modify_bootpartition(cr) != 0) {
12710Sstevel@tonic-gate pc_unlockfs(fsp);
12720Sstevel@tonic-gate return (EACCES);
12730Sstevel@tonic-gate }
12740Sstevel@tonic-gate }
12750Sstevel@tonic-gate
12765331Samw error = pc_dirremove(pcp, nm, cdir, VDIR, ct);
12770Sstevel@tonic-gate pc_unlockfs(fsp);
12780Sstevel@tonic-gate return (error);
12790Sstevel@tonic-gate }
12800Sstevel@tonic-gate
12810Sstevel@tonic-gate /*
12820Sstevel@tonic-gate * read entries in a directory.
12830Sstevel@tonic-gate * we must convert pc format to unix format
12840Sstevel@tonic-gate */
12850Sstevel@tonic-gate
12860Sstevel@tonic-gate /*ARGSUSED*/
12870Sstevel@tonic-gate static int
pcfs_readdir(struct vnode * dvp,struct uio * uiop,struct cred * cr,int * eofp,caller_context_t * ct,int flags)12880Sstevel@tonic-gate pcfs_readdir(
12890Sstevel@tonic-gate struct vnode *dvp,
12900Sstevel@tonic-gate struct uio *uiop,
12910Sstevel@tonic-gate struct cred *cr,
12925331Samw int *eofp,
12935331Samw caller_context_t *ct,
12945331Samw int flags)
12950Sstevel@tonic-gate {
12960Sstevel@tonic-gate struct pcnode *pcp;
12970Sstevel@tonic-gate struct pcfs *fsp;
12980Sstevel@tonic-gate struct pcdir *ep;
12990Sstevel@tonic-gate struct buf *bp = NULL;
13000Sstevel@tonic-gate offset_t offset;
13010Sstevel@tonic-gate int boff;
13020Sstevel@tonic-gate struct pc_dirent lbp;
13030Sstevel@tonic-gate struct pc_dirent *ld = &lbp;
13040Sstevel@tonic-gate int error;
13050Sstevel@tonic-gate
13062720Sfrankho /*
13072720Sfrankho * If the filesystem was umounted by force, return immediately.
13082720Sfrankho */
13092720Sfrankho if (dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
13102720Sfrankho return (EIO);
13112720Sfrankho
13120Sstevel@tonic-gate if ((uiop->uio_iovcnt != 1) ||
13130Sstevel@tonic-gate (uiop->uio_loffset % sizeof (struct pcdir)) != 0) {
13140Sstevel@tonic-gate return (EINVAL);
13150Sstevel@tonic-gate }
13160Sstevel@tonic-gate fsp = VFSTOPCFS(dvp->v_vfsp);
13170Sstevel@tonic-gate /*
13180Sstevel@tonic-gate * verify that the dp is still valid on the disk
13190Sstevel@tonic-gate */
13200Sstevel@tonic-gate if (error = pc_verify(fsp)) {
13210Sstevel@tonic-gate return (error);
13220Sstevel@tonic-gate }
13230Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0);
13240Sstevel@tonic-gate if (error)
13250Sstevel@tonic-gate return (error);
13262972Sfrankho if ((pcp = VTOPC(dvp)) == NULL || pcp->pc_flags & PC_INVAL) {
13270Sstevel@tonic-gate pc_unlockfs(fsp);
13280Sstevel@tonic-gate return (EIO);
13290Sstevel@tonic-gate }
13300Sstevel@tonic-gate
13310Sstevel@tonic-gate bzero(ld, sizeof (*ld));
13320Sstevel@tonic-gate
13330Sstevel@tonic-gate if (eofp != NULL)
13340Sstevel@tonic-gate *eofp = 0;
13350Sstevel@tonic-gate offset = uiop->uio_loffset;
13360Sstevel@tonic-gate
13370Sstevel@tonic-gate if (dvp->v_flag & VROOT) {
13380Sstevel@tonic-gate /*
13390Sstevel@tonic-gate * kludge up entries for "." and ".." in the root.
13400Sstevel@tonic-gate */
13410Sstevel@tonic-gate if (offset == 0) {
13420Sstevel@tonic-gate (void) strcpy(ld->d_name, ".");
13430Sstevel@tonic-gate ld->d_reclen = DIRENT64_RECLEN(1);
13440Sstevel@tonic-gate ld->d_off = (off64_t)sizeof (struct pcdir);
13450Sstevel@tonic-gate ld->d_ino = (ino64_t)UINT_MAX;
13460Sstevel@tonic-gate if (ld->d_reclen > uiop->uio_resid) {
13470Sstevel@tonic-gate pc_unlockfs(fsp);
13480Sstevel@tonic-gate return (ENOSPC);
13490Sstevel@tonic-gate }
13500Sstevel@tonic-gate (void) uiomove(ld, ld->d_reclen, UIO_READ, uiop);
13510Sstevel@tonic-gate uiop->uio_loffset = ld->d_off;
13520Sstevel@tonic-gate offset = uiop->uio_loffset;
13530Sstevel@tonic-gate }
13540Sstevel@tonic-gate if (offset == sizeof (struct pcdir)) {
13550Sstevel@tonic-gate (void) strcpy(ld->d_name, "..");
13560Sstevel@tonic-gate ld->d_reclen = DIRENT64_RECLEN(2);
13570Sstevel@tonic-gate if (ld->d_reclen > uiop->uio_resid) {
13580Sstevel@tonic-gate pc_unlockfs(fsp);
13590Sstevel@tonic-gate return (ENOSPC);
13600Sstevel@tonic-gate }
13610Sstevel@tonic-gate ld->d_off = (off64_t)(uiop->uio_loffset +
13620Sstevel@tonic-gate sizeof (struct pcdir));
13630Sstevel@tonic-gate ld->d_ino = (ino64_t)UINT_MAX;
13640Sstevel@tonic-gate (void) uiomove(ld, ld->d_reclen, UIO_READ, uiop);
13650Sstevel@tonic-gate uiop->uio_loffset = ld->d_off;
13660Sstevel@tonic-gate offset = uiop->uio_loffset;
13670Sstevel@tonic-gate }
13680Sstevel@tonic-gate offset -= 2 * sizeof (struct pcdir);
13690Sstevel@tonic-gate /* offset now has the real offset value into directory file */
13700Sstevel@tonic-gate }
13710Sstevel@tonic-gate
13720Sstevel@tonic-gate for (;;) {
13730Sstevel@tonic-gate boff = pc_blkoff(fsp, offset);
13740Sstevel@tonic-gate if (boff == 0 || bp == NULL || boff >= bp->b_bcount) {
13750Sstevel@tonic-gate if (bp != NULL) {
13760Sstevel@tonic-gate brelse(bp);
13770Sstevel@tonic-gate bp = NULL;
13780Sstevel@tonic-gate }
13790Sstevel@tonic-gate error = pc_blkatoff(pcp, offset, &bp, &ep);
13800Sstevel@tonic-gate if (error) {
13810Sstevel@tonic-gate if (error == ENOENT) {
13820Sstevel@tonic-gate error = 0;
13830Sstevel@tonic-gate if (eofp)
13840Sstevel@tonic-gate *eofp = 1;
13850Sstevel@tonic-gate }
13860Sstevel@tonic-gate break;
13870Sstevel@tonic-gate }
13880Sstevel@tonic-gate }
13890Sstevel@tonic-gate if (ep->pcd_filename[0] == PCD_UNUSED) {
13900Sstevel@tonic-gate if (eofp)
13910Sstevel@tonic-gate *eofp = 1;
13920Sstevel@tonic-gate break;
13930Sstevel@tonic-gate }
13940Sstevel@tonic-gate /*
13950Sstevel@tonic-gate * Don't display label because it may contain funny characters.
13960Sstevel@tonic-gate */
13970Sstevel@tonic-gate if (ep->pcd_filename[0] == PCD_ERASED) {
13980Sstevel@tonic-gate uiop->uio_loffset += sizeof (struct pcdir);
13990Sstevel@tonic-gate offset += sizeof (struct pcdir);
14000Sstevel@tonic-gate ep++;
14010Sstevel@tonic-gate continue;
14020Sstevel@tonic-gate }
14030Sstevel@tonic-gate if (PCDL_IS_LFN(ep)) {
14040Sstevel@tonic-gate if (pc_read_long_fn(dvp, uiop, ld, &ep, &offset, &bp) !=
14050Sstevel@tonic-gate 0)
14060Sstevel@tonic-gate break;
14070Sstevel@tonic-gate continue;
14080Sstevel@tonic-gate }
14090Sstevel@tonic-gate
14100Sstevel@tonic-gate if (pc_read_short_fn(dvp, uiop, ld, &ep, &offset, &bp) != 0)
14110Sstevel@tonic-gate break;
14120Sstevel@tonic-gate }
14130Sstevel@tonic-gate if (bp)
14140Sstevel@tonic-gate brelse(bp);
14150Sstevel@tonic-gate pc_unlockfs(fsp);
14160Sstevel@tonic-gate return (error);
14170Sstevel@tonic-gate }
14180Sstevel@tonic-gate
14190Sstevel@tonic-gate
14200Sstevel@tonic-gate /*
14210Sstevel@tonic-gate * Called from pvn_getpages or pcfs_getpage to get a particular page.
14220Sstevel@tonic-gate * When we are called the pcfs is already locked.
14230Sstevel@tonic-gate */
14240Sstevel@tonic-gate /*ARGSUSED*/
14250Sstevel@tonic-gate static int
pcfs_getapage(struct vnode * vp,u_offset_t off,size_t len,uint_t * protp,page_t * pl[],size_t plsz,struct seg * seg,caddr_t addr,enum seg_rw rw,struct cred * cr)14260Sstevel@tonic-gate pcfs_getapage(
14270Sstevel@tonic-gate struct vnode *vp,
14280Sstevel@tonic-gate u_offset_t off,
14290Sstevel@tonic-gate size_t len,
14300Sstevel@tonic-gate uint_t *protp,
14310Sstevel@tonic-gate page_t *pl[], /* NULL if async IO is requested */
14320Sstevel@tonic-gate size_t plsz,
14330Sstevel@tonic-gate struct seg *seg,
14340Sstevel@tonic-gate caddr_t addr,
14350Sstevel@tonic-gate enum seg_rw rw,
14360Sstevel@tonic-gate struct cred *cr)
14370Sstevel@tonic-gate {
14380Sstevel@tonic-gate struct pcnode *pcp;
14390Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp);
14400Sstevel@tonic-gate struct vnode *devvp;
14410Sstevel@tonic-gate page_t *pp;
14420Sstevel@tonic-gate page_t *pagefound;
14430Sstevel@tonic-gate int err;
14440Sstevel@tonic-gate
14452720Sfrankho /*
14462720Sfrankho * If the filesystem was umounted by force, return immediately.
14472720Sfrankho */
14482720Sfrankho if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
14492720Sfrankho return (EIO);
14502720Sfrankho
14510Sstevel@tonic-gate PC_DPRINTF3(5, "pcfs_getapage: vp=%p off=%lld len=%lu\n",
14520Sstevel@tonic-gate (void *)vp, off, len);
14530Sstevel@tonic-gate
14542972Sfrankho if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL)
14550Sstevel@tonic-gate return (EIO);
14560Sstevel@tonic-gate devvp = fsp->pcfs_devvp;
14570Sstevel@tonic-gate
14580Sstevel@tonic-gate /* pcfs doesn't do readaheads */
14590Sstevel@tonic-gate if (pl == NULL)
14600Sstevel@tonic-gate return (0);
14610Sstevel@tonic-gate
14620Sstevel@tonic-gate pl[0] = NULL;
14630Sstevel@tonic-gate err = 0;
14640Sstevel@tonic-gate /*
14650Sstevel@tonic-gate * If the accessed time on the pcnode has not already been
14660Sstevel@tonic-gate * set elsewhere (e.g. for read/setattr) we set the time now.
14670Sstevel@tonic-gate * This gives us approximate modified times for mmap'ed files
14680Sstevel@tonic-gate * which are accessed via loads in the user address space.
14690Sstevel@tonic-gate */
14700Sstevel@tonic-gate if ((pcp->pc_flags & PC_ACC) == 0 &&
14710Sstevel@tonic-gate ((fsp->pcfs_vfs->vfs_flag & VFS_RDONLY) == 0)) {
14725121Sfrankho pc_mark_acc(fsp, pcp);
14730Sstevel@tonic-gate }
14740Sstevel@tonic-gate reread:
14750Sstevel@tonic-gate if ((pagefound = page_exists(vp, off)) == NULL) {
14760Sstevel@tonic-gate /*
14770Sstevel@tonic-gate * Need to really do disk IO to get the page(s).
14780Sstevel@tonic-gate */
14790Sstevel@tonic-gate struct buf *bp;
14800Sstevel@tonic-gate daddr_t lbn, bn;
14810Sstevel@tonic-gate u_offset_t io_off;
14820Sstevel@tonic-gate size_t io_len;
14830Sstevel@tonic-gate u_offset_t lbnoff, xferoffset;
14840Sstevel@tonic-gate u_offset_t pgoff;
14850Sstevel@tonic-gate uint_t xfersize;
14860Sstevel@tonic-gate int err1;
14870Sstevel@tonic-gate
14880Sstevel@tonic-gate lbn = pc_lblkno(fsp, off);
14890Sstevel@tonic-gate lbnoff = off & ~(fsp->pcfs_clsize - 1);
14900Sstevel@tonic-gate xferoffset = off & ~(fsp->pcfs_secsize - 1);
14910Sstevel@tonic-gate
14920Sstevel@tonic-gate pp = pvn_read_kluster(vp, off, seg, addr, &io_off, &io_len,
14930Sstevel@tonic-gate off, (size_t)MIN(pc_blksize(fsp, pcp, off), PAGESIZE), 0);
14940Sstevel@tonic-gate if (pp == NULL)
14950Sstevel@tonic-gate /*
14960Sstevel@tonic-gate * XXX - If pcfs is made MT-hot, this should go
14970Sstevel@tonic-gate * back to reread.
14980Sstevel@tonic-gate */
14990Sstevel@tonic-gate panic("pcfs_getapage pvn_read_kluster");
15000Sstevel@tonic-gate
15010Sstevel@tonic-gate for (pgoff = 0; pgoff < PAGESIZE && xferoffset < pcp->pc_size;
15020Sstevel@tonic-gate pgoff += xfersize,
15030Sstevel@tonic-gate lbn += howmany(xfersize, fsp->pcfs_clsize),
15040Sstevel@tonic-gate lbnoff += xfersize, xferoffset += xfersize) {
15050Sstevel@tonic-gate /*
15060Sstevel@tonic-gate * read as many contiguous blocks as possible to
15070Sstevel@tonic-gate * fill this page
15080Sstevel@tonic-gate */
15090Sstevel@tonic-gate xfersize = PAGESIZE - pgoff;
15100Sstevel@tonic-gate err1 = pc_bmap(pcp, lbn, &bn, &xfersize);
15110Sstevel@tonic-gate if (err1) {
15120Sstevel@tonic-gate PC_DPRINTF1(1, "pc_getapage err=%d", err1);
15130Sstevel@tonic-gate err = err1;
15140Sstevel@tonic-gate goto out;
15150Sstevel@tonic-gate }
15160Sstevel@tonic-gate bp = pageio_setup(pp, xfersize, devvp, B_READ);
15170Sstevel@tonic-gate bp->b_edev = devvp->v_rdev;
15180Sstevel@tonic-gate bp->b_dev = cmpdev(devvp->v_rdev);
15195121Sfrankho bp->b_blkno = bn + btodt(xferoffset - lbnoff);
1520973Selowe bp->b_un.b_addr = (caddr_t)(uintptr_t)pgoff;
15210Sstevel@tonic-gate bp->b_file = vp;
15220Sstevel@tonic-gate bp->b_offset = (offset_t)(off + pgoff);
15230Sstevel@tonic-gate
15240Sstevel@tonic-gate (void) bdev_strategy(bp);
15250Sstevel@tonic-gate
15260Sstevel@tonic-gate lwp_stat_update(LWP_STAT_INBLK, 1);
15270Sstevel@tonic-gate
15280Sstevel@tonic-gate if (err == 0)
15290Sstevel@tonic-gate err = biowait(bp);
15300Sstevel@tonic-gate else
15310Sstevel@tonic-gate (void) biowait(bp);
15320Sstevel@tonic-gate pageio_done(bp);
15330Sstevel@tonic-gate if (err)
15340Sstevel@tonic-gate goto out;
15350Sstevel@tonic-gate }
15360Sstevel@tonic-gate if (pgoff < PAGESIZE) {
15370Sstevel@tonic-gate pagezero(pp->p_prev, pgoff, PAGESIZE - pgoff);
15380Sstevel@tonic-gate }
15390Sstevel@tonic-gate pvn_plist_init(pp, pl, plsz, off, io_len, rw);
15400Sstevel@tonic-gate }
15410Sstevel@tonic-gate out:
15420Sstevel@tonic-gate if (err) {
15430Sstevel@tonic-gate if (pp != NULL)
15440Sstevel@tonic-gate pvn_read_done(pp, B_ERROR);
15450Sstevel@tonic-gate return (err);
15460Sstevel@tonic-gate }
15470Sstevel@tonic-gate
15480Sstevel@tonic-gate if (pagefound) {
15490Sstevel@tonic-gate /*
15500Sstevel@tonic-gate * Page exists in the cache, acquire the "shared"
15510Sstevel@tonic-gate * lock. If this fails, go back to reread.
15520Sstevel@tonic-gate */
15530Sstevel@tonic-gate if ((pp = page_lookup(vp, off, SE_SHARED)) == NULL) {
15540Sstevel@tonic-gate goto reread;
15550Sstevel@tonic-gate }
15560Sstevel@tonic-gate pl[0] = pp;
15570Sstevel@tonic-gate pl[1] = NULL;
15580Sstevel@tonic-gate }
15590Sstevel@tonic-gate return (err);
15600Sstevel@tonic-gate }
15610Sstevel@tonic-gate
15620Sstevel@tonic-gate /*
15630Sstevel@tonic-gate * Return all the pages from [off..off+len] in given file
15640Sstevel@tonic-gate */
15655331Samw /* ARGSUSED */
15660Sstevel@tonic-gate static int
pcfs_getpage(struct vnode * vp,offset_t off,size_t len,uint_t * protp,page_t * pl[],size_t plsz,struct seg * seg,caddr_t addr,enum seg_rw rw,struct cred * cr,caller_context_t * ct)15670Sstevel@tonic-gate pcfs_getpage(
15680Sstevel@tonic-gate struct vnode *vp,
15690Sstevel@tonic-gate offset_t off,
15700Sstevel@tonic-gate size_t len,
15710Sstevel@tonic-gate uint_t *protp,
15720Sstevel@tonic-gate page_t *pl[],
15730Sstevel@tonic-gate size_t plsz,
15740Sstevel@tonic-gate struct seg *seg,
15750Sstevel@tonic-gate caddr_t addr,
15760Sstevel@tonic-gate enum seg_rw rw,
15775331Samw struct cred *cr,
15785331Samw caller_context_t *ct)
15790Sstevel@tonic-gate {
15800Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp);
15810Sstevel@tonic-gate int err;
15820Sstevel@tonic-gate
15830Sstevel@tonic-gate PC_DPRINTF0(6, "pcfs_getpage\n");
15840Sstevel@tonic-gate if (err = pc_verify(fsp))
15850Sstevel@tonic-gate return (err);
15860Sstevel@tonic-gate if (vp->v_flag & VNOMAP)
15870Sstevel@tonic-gate return (ENOSYS);
15880Sstevel@tonic-gate ASSERT(off <= UINT32_MAX);
15890Sstevel@tonic-gate err = pc_lockfs(fsp, 0, 0);
15900Sstevel@tonic-gate if (err)
15910Sstevel@tonic-gate return (err);
15920Sstevel@tonic-gate if (protp != NULL)
15930Sstevel@tonic-gate *protp = PROT_ALL;
15940Sstevel@tonic-gate
15950Sstevel@tonic-gate ASSERT((off & PAGEOFFSET) == 0);
15960Sstevel@tonic-gate if (len <= PAGESIZE) {
15970Sstevel@tonic-gate err = pcfs_getapage(vp, off, len, protp, pl,
15980Sstevel@tonic-gate plsz, seg, addr, rw, cr);
15990Sstevel@tonic-gate } else {
16000Sstevel@tonic-gate err = pvn_getpages(pcfs_getapage, vp, off,
16010Sstevel@tonic-gate len, protp, pl, plsz, seg, addr, rw, cr);
16020Sstevel@tonic-gate }
16030Sstevel@tonic-gate pc_unlockfs(fsp);
16040Sstevel@tonic-gate return (err);
16050Sstevel@tonic-gate }
16060Sstevel@tonic-gate
16070Sstevel@tonic-gate
16080Sstevel@tonic-gate /*
16090Sstevel@tonic-gate * Flags are composed of {B_INVAL, B_FREE, B_DONTNEED, B_FORCE}
16100Sstevel@tonic-gate * If len == 0, do from off to EOF.
16110Sstevel@tonic-gate *
16120Sstevel@tonic-gate * The normal cases should be len == 0 & off == 0 (entire vp list),
16130Sstevel@tonic-gate * len == MAXBSIZE (from segmap_release actions), and len == PAGESIZE
16140Sstevel@tonic-gate * (from pageout).
16150Sstevel@tonic-gate *
16160Sstevel@tonic-gate */
16170Sstevel@tonic-gate /*ARGSUSED*/
16180Sstevel@tonic-gate static int
pcfs_putpage(struct vnode * vp,offset_t off,size_t len,int flags,struct cred * cr,caller_context_t * ct)16190Sstevel@tonic-gate pcfs_putpage(
16200Sstevel@tonic-gate struct vnode *vp,
16210Sstevel@tonic-gate offset_t off,
16220Sstevel@tonic-gate size_t len,
16230Sstevel@tonic-gate int flags,
16245331Samw struct cred *cr,
16255331Samw caller_context_t *ct)
16260Sstevel@tonic-gate {
16270Sstevel@tonic-gate struct pcnode *pcp;
16280Sstevel@tonic-gate page_t *pp;
16290Sstevel@tonic-gate struct pcfs *fsp;
16300Sstevel@tonic-gate u_offset_t io_off;
16310Sstevel@tonic-gate size_t io_len;
16320Sstevel@tonic-gate offset_t eoff;
16330Sstevel@tonic-gate int err;
16340Sstevel@tonic-gate
16352720Sfrankho /*
16362720Sfrankho * If the filesystem was umounted by force, return immediately.
16372720Sfrankho */
16382720Sfrankho if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
16392720Sfrankho return (EIO);
16402720Sfrankho
16410Sstevel@tonic-gate PC_DPRINTF1(6, "pcfs_putpage vp=0x%p\n", (void *)vp);
16420Sstevel@tonic-gate if (vp->v_flag & VNOMAP)
16430Sstevel@tonic-gate return (ENOSYS);
16440Sstevel@tonic-gate
16450Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp);
16460Sstevel@tonic-gate
16470Sstevel@tonic-gate if (err = pc_verify(fsp))
16480Sstevel@tonic-gate return (err);
16490Sstevel@tonic-gate if ((pcp = VTOPC(vp)) == NULL) {
16500Sstevel@tonic-gate PC_DPRINTF1(3, "pcfs_putpage NULL vp=0x%p\n", (void *)vp);
16510Sstevel@tonic-gate return (EIO);
16520Sstevel@tonic-gate }
16532972Sfrankho if (pcp->pc_flags & PC_INVAL)
16542972Sfrankho return (EIO);
16550Sstevel@tonic-gate
16560Sstevel@tonic-gate if (curproc == proc_pageout) {
16570Sstevel@tonic-gate /*
16580Sstevel@tonic-gate * XXX - This is a quick hack to avoid blocking
16590Sstevel@tonic-gate * pageout. Also to avoid pcfs_getapage deadlocking
16600Sstevel@tonic-gate * with putpage when memory is running out,
16610Sstevel@tonic-gate * since we only have one global lock and we don't
16620Sstevel@tonic-gate * support async putpage.
16630Sstevel@tonic-gate * It should be fixed someday.
16640Sstevel@tonic-gate *
16650Sstevel@tonic-gate * Interestingly, this used to be a test of NOMEMWAIT().
16660Sstevel@tonic-gate * We only ever got here once pcfs started supporting
16670Sstevel@tonic-gate * NFS sharing, and then only because the NFS server
16680Sstevel@tonic-gate * threads seem to do writes in sched's process context.
16690Sstevel@tonic-gate * Since everyone else seems to just care about pageout,
16700Sstevel@tonic-gate * the test was changed to look for pageout directly.
16710Sstevel@tonic-gate */
16720Sstevel@tonic-gate return (ENOMEM);
16730Sstevel@tonic-gate }
16740Sstevel@tonic-gate
16750Sstevel@tonic-gate ASSERT(off <= UINT32_MAX);
16760Sstevel@tonic-gate
16770Sstevel@tonic-gate flags &= ~B_ASYNC; /* XXX should fix this later */
16780Sstevel@tonic-gate
16790Sstevel@tonic-gate err = pc_lockfs(fsp, 0, 0);
16800Sstevel@tonic-gate if (err)
16810Sstevel@tonic-gate return (err);
16820Sstevel@tonic-gate if (!vn_has_cached_data(vp) || off >= pcp->pc_size) {
16830Sstevel@tonic-gate pc_unlockfs(fsp);
16840Sstevel@tonic-gate return (0);
16850Sstevel@tonic-gate }
16860Sstevel@tonic-gate
16870Sstevel@tonic-gate if (len == 0) {
16880Sstevel@tonic-gate /*
16890Sstevel@tonic-gate * Search the entire vp list for pages >= off
16900Sstevel@tonic-gate */
16910Sstevel@tonic-gate err = pvn_vplist_dirty(vp, off,
16920Sstevel@tonic-gate pcfs_putapage, flags, cr);
16930Sstevel@tonic-gate } else {
16940Sstevel@tonic-gate eoff = off + len;
16950Sstevel@tonic-gate
16960Sstevel@tonic-gate for (io_off = off; io_off < eoff &&
16970Sstevel@tonic-gate io_off < pcp->pc_size; io_off += io_len) {
16980Sstevel@tonic-gate /*
16990Sstevel@tonic-gate * If we are not invalidating, synchronously
17000Sstevel@tonic-gate * freeing or writing pages use the routine
17010Sstevel@tonic-gate * page_lookup_nowait() to prevent reclaiming
17020Sstevel@tonic-gate * them from the free list.
17030Sstevel@tonic-gate */
17040Sstevel@tonic-gate if ((flags & B_INVAL) || ((flags & B_ASYNC) == 0)) {
17050Sstevel@tonic-gate pp = page_lookup(vp, io_off,
17064723Sksn (flags & (B_INVAL | B_FREE)) ?
17074723Sksn SE_EXCL : SE_SHARED);
17080Sstevel@tonic-gate } else {
17090Sstevel@tonic-gate pp = page_lookup_nowait(vp, io_off,
17104723Sksn (flags & B_FREE) ? SE_EXCL : SE_SHARED);
17110Sstevel@tonic-gate }
17120Sstevel@tonic-gate
17130Sstevel@tonic-gate if (pp == NULL || pvn_getdirty(pp, flags) == 0)
17140Sstevel@tonic-gate io_len = PAGESIZE;
17150Sstevel@tonic-gate else {
17160Sstevel@tonic-gate err = pcfs_putapage(vp, pp, &io_off, &io_len,
17174723Sksn flags, cr);
17180Sstevel@tonic-gate if (err != 0)
17190Sstevel@tonic-gate break;
17200Sstevel@tonic-gate /*
17210Sstevel@tonic-gate * "io_off" and "io_len" are returned as
17220Sstevel@tonic-gate * the range of pages we actually wrote.
17230Sstevel@tonic-gate * This allows us to skip ahead more quickly
17240Sstevel@tonic-gate * since several pages may've been dealt
17250Sstevel@tonic-gate * with by this iteration of the loop.
17260Sstevel@tonic-gate */
17270Sstevel@tonic-gate }
17280Sstevel@tonic-gate }
17290Sstevel@tonic-gate }
17300Sstevel@tonic-gate if (err == 0 && (flags & B_INVAL) &&
17310Sstevel@tonic-gate off == 0 && len == 0 && vn_has_cached_data(vp)) {
17320Sstevel@tonic-gate /*
17330Sstevel@tonic-gate * If doing "invalidation", make sure that
17340Sstevel@tonic-gate * all pages on the vnode list are actually
17350Sstevel@tonic-gate * gone.
17360Sstevel@tonic-gate */
17370Sstevel@tonic-gate cmn_err(CE_PANIC,
17384723Sksn "pcfs_putpage: B_INVAL, pages not gone");
17390Sstevel@tonic-gate } else if (err) {
17400Sstevel@tonic-gate PC_DPRINTF1(1, "pcfs_putpage err=%d\n", err);
17410Sstevel@tonic-gate }
17420Sstevel@tonic-gate pc_unlockfs(fsp);
17430Sstevel@tonic-gate return (err);
17440Sstevel@tonic-gate }
17450Sstevel@tonic-gate
17460Sstevel@tonic-gate /*
17470Sstevel@tonic-gate * Write out a single page, possibly klustering adjacent dirty pages.
17480Sstevel@tonic-gate */
17490Sstevel@tonic-gate /*ARGSUSED*/
17500Sstevel@tonic-gate int
pcfs_putapage(struct vnode * vp,page_t * pp,u_offset_t * offp,size_t * lenp,int flags,struct cred * cr)17510Sstevel@tonic-gate pcfs_putapage(
17520Sstevel@tonic-gate struct vnode *vp,
17530Sstevel@tonic-gate page_t *pp,
17540Sstevel@tonic-gate u_offset_t *offp,
17550Sstevel@tonic-gate size_t *lenp,
17560Sstevel@tonic-gate int flags,
17570Sstevel@tonic-gate struct cred *cr)
17580Sstevel@tonic-gate {
17590Sstevel@tonic-gate struct pcnode *pcp;
17600Sstevel@tonic-gate struct pcfs *fsp;
17610Sstevel@tonic-gate struct vnode *devvp;
17620Sstevel@tonic-gate size_t io_len;
17630Sstevel@tonic-gate daddr_t bn;
17640Sstevel@tonic-gate u_offset_t lbn, lbnoff, xferoffset;
17650Sstevel@tonic-gate uint_t pgoff, xfersize;
17660Sstevel@tonic-gate int err = 0;
17670Sstevel@tonic-gate u_offset_t io_off;
17680Sstevel@tonic-gate
17690Sstevel@tonic-gate pcp = VTOPC(vp);
17700Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp);
17710Sstevel@tonic-gate devvp = fsp->pcfs_devvp;
17720Sstevel@tonic-gate
17730Sstevel@tonic-gate /*
17740Sstevel@tonic-gate * If the modified time on the inode has not already been
17750Sstevel@tonic-gate * set elsewhere (e.g. for write/setattr) and this is not
17760Sstevel@tonic-gate * a call from msync (B_FORCE) we set the time now.
17770Sstevel@tonic-gate * This gives us approximate modified times for mmap'ed files
17780Sstevel@tonic-gate * which are modified via stores in the user address space.
17790Sstevel@tonic-gate */
17800Sstevel@tonic-gate if ((pcp->pc_flags & PC_MOD) == 0 || (flags & B_FORCE)) {
17810Sstevel@tonic-gate pcp->pc_flags |= PC_MOD;
17825121Sfrankho pc_mark_mod(fsp, pcp);
17830Sstevel@tonic-gate }
17840Sstevel@tonic-gate pp = pvn_write_kluster(vp, pp, &io_off, &io_len, pp->p_offset,
17850Sstevel@tonic-gate PAGESIZE, flags);
17860Sstevel@tonic-gate
17870Sstevel@tonic-gate if (fsp->pcfs_flags & PCFS_IRRECOV) {
17880Sstevel@tonic-gate goto out;
17890Sstevel@tonic-gate }
17900Sstevel@tonic-gate
17910Sstevel@tonic-gate PC_DPRINTF1(7, "pc_putpage writing dirty page off=%llu\n", io_off);
17920Sstevel@tonic-gate
17930Sstevel@tonic-gate lbn = pc_lblkno(fsp, io_off);
17940Sstevel@tonic-gate lbnoff = io_off & ~(fsp->pcfs_clsize - 1);
17950Sstevel@tonic-gate xferoffset = io_off & ~(fsp->pcfs_secsize - 1);
17960Sstevel@tonic-gate
17970Sstevel@tonic-gate for (pgoff = 0; pgoff < io_len && xferoffset < pcp->pc_size;
17980Sstevel@tonic-gate pgoff += xfersize,
17990Sstevel@tonic-gate lbn += howmany(xfersize, fsp->pcfs_clsize),
18000Sstevel@tonic-gate lbnoff += xfersize, xferoffset += xfersize) {
18010Sstevel@tonic-gate
18020Sstevel@tonic-gate struct buf *bp;
18030Sstevel@tonic-gate int err1;
18040Sstevel@tonic-gate
18050Sstevel@tonic-gate /*
18060Sstevel@tonic-gate * write as many contiguous blocks as possible from this page
18070Sstevel@tonic-gate */
18080Sstevel@tonic-gate xfersize = io_len - pgoff;
18090Sstevel@tonic-gate err1 = pc_bmap(pcp, (daddr_t)lbn, &bn, &xfersize);
18100Sstevel@tonic-gate if (err1) {
18110Sstevel@tonic-gate err = err1;
18120Sstevel@tonic-gate goto out;
18130Sstevel@tonic-gate }
18140Sstevel@tonic-gate bp = pageio_setup(pp, xfersize, devvp, B_WRITE | flags);
18150Sstevel@tonic-gate bp->b_edev = devvp->v_rdev;
18160Sstevel@tonic-gate bp->b_dev = cmpdev(devvp->v_rdev);
18175121Sfrankho bp->b_blkno = bn + btodt(xferoffset - lbnoff);
18180Sstevel@tonic-gate bp->b_un.b_addr = (caddr_t)(uintptr_t)pgoff;
18190Sstevel@tonic-gate bp->b_file = vp;
18200Sstevel@tonic-gate bp->b_offset = (offset_t)(io_off + pgoff);
18210Sstevel@tonic-gate
18220Sstevel@tonic-gate (void) bdev_strategy(bp);
18230Sstevel@tonic-gate
18240Sstevel@tonic-gate lwp_stat_update(LWP_STAT_OUBLK, 1);
18250Sstevel@tonic-gate
18260Sstevel@tonic-gate if (err == 0)
18270Sstevel@tonic-gate err = biowait(bp);
18280Sstevel@tonic-gate else
18290Sstevel@tonic-gate (void) biowait(bp);
18300Sstevel@tonic-gate pageio_done(bp);
18310Sstevel@tonic-gate }
18320Sstevel@tonic-gate pvn_write_done(pp, ((err) ? B_ERROR : 0) | B_WRITE | flags);
18330Sstevel@tonic-gate pp = NULL;
18340Sstevel@tonic-gate
18350Sstevel@tonic-gate out:
18360Sstevel@tonic-gate if ((fsp->pcfs_flags & PCFS_IRRECOV) && pp != NULL) {
18370Sstevel@tonic-gate pvn_write_done(pp, B_WRITE | flags);
18380Sstevel@tonic-gate } else if (err != 0 && pp != NULL) {
18390Sstevel@tonic-gate pvn_write_done(pp, B_ERROR | B_WRITE | flags);
18400Sstevel@tonic-gate }
18410Sstevel@tonic-gate
18420Sstevel@tonic-gate if (offp)
18430Sstevel@tonic-gate *offp = io_off;
18440Sstevel@tonic-gate if (lenp)
18450Sstevel@tonic-gate *lenp = io_len;
18460Sstevel@tonic-gate PC_DPRINTF4(4, "pcfs_putapage: vp=%p pp=%p off=%lld len=%lu\n",
18470Sstevel@tonic-gate (void *)vp, (void *)pp, io_off, io_len);
18480Sstevel@tonic-gate if (err) {
18490Sstevel@tonic-gate PC_DPRINTF1(1, "pcfs_putapage err=%d", err);
18500Sstevel@tonic-gate }
18510Sstevel@tonic-gate return (err);
18520Sstevel@tonic-gate }
18530Sstevel@tonic-gate
18540Sstevel@tonic-gate /*ARGSUSED*/
18550Sstevel@tonic-gate static int
pcfs_map(struct vnode * vp,offset_t off,struct as * as,caddr_t * addrp,size_t len,uchar_t prot,uchar_t maxprot,uint_t flags,struct cred * cr,caller_context_t * ct)18560Sstevel@tonic-gate pcfs_map(
18570Sstevel@tonic-gate struct vnode *vp,
18580Sstevel@tonic-gate offset_t off,
18590Sstevel@tonic-gate struct as *as,
18600Sstevel@tonic-gate caddr_t *addrp,
18610Sstevel@tonic-gate size_t len,
18620Sstevel@tonic-gate uchar_t prot,
18630Sstevel@tonic-gate uchar_t maxprot,
18640Sstevel@tonic-gate uint_t flags,
18655331Samw struct cred *cr,
18665331Samw caller_context_t *ct)
18670Sstevel@tonic-gate {
18680Sstevel@tonic-gate struct segvn_crargs vn_a;
18690Sstevel@tonic-gate int error;
18700Sstevel@tonic-gate
18710Sstevel@tonic-gate PC_DPRINTF0(6, "pcfs_map\n");
18720Sstevel@tonic-gate if (vp->v_flag & VNOMAP)
18730Sstevel@tonic-gate return (ENOSYS);
18740Sstevel@tonic-gate
18750Sstevel@tonic-gate if (off > UINT32_MAX || off + len > UINT32_MAX)
18760Sstevel@tonic-gate return (ENXIO);
18770Sstevel@tonic-gate
18780Sstevel@tonic-gate as_rangelock(as);
18796036Smec error = choose_addr(as, addrp, len, off, ADDR_VACALIGN, flags);
18806036Smec if (error != 0) {
18816036Smec as_rangeunlock(as);
18826036Smec return (error);
18830Sstevel@tonic-gate }
18840Sstevel@tonic-gate
18850Sstevel@tonic-gate vn_a.vp = vp;
18860Sstevel@tonic-gate vn_a.offset = off;
18870Sstevel@tonic-gate vn_a.type = flags & MAP_TYPE;
18880Sstevel@tonic-gate vn_a.prot = prot;
18890Sstevel@tonic-gate vn_a.maxprot = maxprot;
18900Sstevel@tonic-gate vn_a.flags = flags & ~MAP_TYPE;
18910Sstevel@tonic-gate vn_a.cred = cr;
18920Sstevel@tonic-gate vn_a.amp = NULL;
18930Sstevel@tonic-gate vn_a.szc = 0;
18940Sstevel@tonic-gate vn_a.lgrp_mem_policy_flags = 0;
18950Sstevel@tonic-gate
18960Sstevel@tonic-gate error = as_map(as, *addrp, len, segvn_create, &vn_a);
18970Sstevel@tonic-gate as_rangeunlock(as);
18980Sstevel@tonic-gate return (error);
18990Sstevel@tonic-gate }
19000Sstevel@tonic-gate
19010Sstevel@tonic-gate /* ARGSUSED */
19020Sstevel@tonic-gate static int
pcfs_seek(struct vnode * vp,offset_t ooff,offset_t * noffp,caller_context_t * ct)19030Sstevel@tonic-gate pcfs_seek(
19040Sstevel@tonic-gate struct vnode *vp,
19050Sstevel@tonic-gate offset_t ooff,
19065331Samw offset_t *noffp,
19075331Samw caller_context_t *ct)
19080Sstevel@tonic-gate {
19090Sstevel@tonic-gate if (*noffp < 0)
19100Sstevel@tonic-gate return (EINVAL);
19110Sstevel@tonic-gate else if (*noffp > MAXOFFSET_T)
19120Sstevel@tonic-gate return (EINVAL);
19130Sstevel@tonic-gate else
19140Sstevel@tonic-gate return (0);
19150Sstevel@tonic-gate }
19160Sstevel@tonic-gate
19170Sstevel@tonic-gate /* ARGSUSED */
19180Sstevel@tonic-gate static int
pcfs_addmap(struct vnode * vp,offset_t off,struct as * as,caddr_t addr,size_t len,uchar_t prot,uchar_t maxprot,uint_t flags,struct cred * cr,caller_context_t * ct)19190Sstevel@tonic-gate pcfs_addmap(
19200Sstevel@tonic-gate struct vnode *vp,
19210Sstevel@tonic-gate offset_t off,
19220Sstevel@tonic-gate struct as *as,
19230Sstevel@tonic-gate caddr_t addr,
19240Sstevel@tonic-gate size_t len,
19250Sstevel@tonic-gate uchar_t prot,
19260Sstevel@tonic-gate uchar_t maxprot,
19270Sstevel@tonic-gate uint_t flags,
19285331Samw struct cred *cr,
19295331Samw caller_context_t *ct)
19300Sstevel@tonic-gate {
19310Sstevel@tonic-gate if (vp->v_flag & VNOMAP)
19320Sstevel@tonic-gate return (ENOSYS);
19330Sstevel@tonic-gate return (0);
19340Sstevel@tonic-gate }
19350Sstevel@tonic-gate
19360Sstevel@tonic-gate /*ARGSUSED*/
19370Sstevel@tonic-gate static int
pcfs_delmap(struct vnode * vp,offset_t off,struct as * as,caddr_t addr,size_t len,uint_t prot,uint_t maxprot,uint_t flags,struct cred * cr,caller_context_t * ct)19380Sstevel@tonic-gate pcfs_delmap(
19390Sstevel@tonic-gate struct vnode *vp,
19400Sstevel@tonic-gate offset_t off,
19410Sstevel@tonic-gate struct as *as,
19420Sstevel@tonic-gate caddr_t addr,
19430Sstevel@tonic-gate size_t len,
19440Sstevel@tonic-gate uint_t prot,
19450Sstevel@tonic-gate uint_t maxprot,
19460Sstevel@tonic-gate uint_t flags,
19475331Samw struct cred *cr,
19485331Samw caller_context_t *ct)
19490Sstevel@tonic-gate {
19500Sstevel@tonic-gate if (vp->v_flag & VNOMAP)
19510Sstevel@tonic-gate return (ENOSYS);
19520Sstevel@tonic-gate return (0);
19530Sstevel@tonic-gate }
19540Sstevel@tonic-gate
19550Sstevel@tonic-gate /*
19560Sstevel@tonic-gate * POSIX pathconf() support.
19570Sstevel@tonic-gate */
19580Sstevel@tonic-gate /* ARGSUSED */
19590Sstevel@tonic-gate static int
pcfs_pathconf(struct vnode * vp,int cmd,ulong_t * valp,struct cred * cr,caller_context_t * ct)19600Sstevel@tonic-gate pcfs_pathconf(
19610Sstevel@tonic-gate struct vnode *vp,
19620Sstevel@tonic-gate int cmd,
19630Sstevel@tonic-gate ulong_t *valp,
19645331Samw struct cred *cr,
19655331Samw caller_context_t *ct)
19660Sstevel@tonic-gate {
19670Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp);
19680Sstevel@tonic-gate
19690Sstevel@tonic-gate switch (cmd) {
19700Sstevel@tonic-gate case _PC_LINK_MAX:
19716971Sbatschul *valp = 1;
19726971Sbatschul return (0);
19730Sstevel@tonic-gate
19746971Sbatschul case _PC_CASE_BEHAVIOR:
19756971Sbatschul return (EINVAL);
19760Sstevel@tonic-gate
19770Sstevel@tonic-gate case _PC_FILESIZEBITS:
19780Sstevel@tonic-gate /*
19790Sstevel@tonic-gate * Both FAT16 and FAT32 support 4GB - 1 byte for file size.
19800Sstevel@tonic-gate * FAT12 can only go up to the maximum filesystem capacity
19810Sstevel@tonic-gate * which is ~509MB.
19820Sstevel@tonic-gate */
19836971Sbatschul *valp = IS_FAT12(fsp) ? 30 : 33;
19846971Sbatschul return (0);
19856971Sbatschul
1986*10440SRoger.Faulkner@Sun.COM case _PC_TIMESTAMP_RESOLUTION:
1987*10440SRoger.Faulkner@Sun.COM /*
1988*10440SRoger.Faulkner@Sun.COM * PCFS keeps track of modification times, it its own
1989*10440SRoger.Faulkner@Sun.COM * internal format, to a resolution of 2 seconds.
1990*10440SRoger.Faulkner@Sun.COM * Since 2000 million is representable in an int32_t
1991*10440SRoger.Faulkner@Sun.COM * without overflow (or becoming negative), we allow
1992*10440SRoger.Faulkner@Sun.COM * this value to be returned.
1993*10440SRoger.Faulkner@Sun.COM */
1994*10440SRoger.Faulkner@Sun.COM *valp = 2000000000L;
1995*10440SRoger.Faulkner@Sun.COM return (0);
1996*10440SRoger.Faulkner@Sun.COM
19970Sstevel@tonic-gate default:
19986971Sbatschul return (fs_pathconf(vp, cmd, valp, cr, ct));
19990Sstevel@tonic-gate }
20000Sstevel@tonic-gate
20010Sstevel@tonic-gate }
20020Sstevel@tonic-gate
20030Sstevel@tonic-gate /* ARGSUSED */
20040Sstevel@tonic-gate static int
pcfs_space(struct vnode * vp,int cmd,struct flock64 * bfp,int flag,offset_t offset,cred_t * cr,caller_context_t * ct)20050Sstevel@tonic-gate pcfs_space(
20060Sstevel@tonic-gate struct vnode *vp,
20070Sstevel@tonic-gate int cmd,
20080Sstevel@tonic-gate struct flock64 *bfp,
20090Sstevel@tonic-gate int flag,
20100Sstevel@tonic-gate offset_t offset,
20110Sstevel@tonic-gate cred_t *cr,
20120Sstevel@tonic-gate caller_context_t *ct)
20130Sstevel@tonic-gate {
20140Sstevel@tonic-gate struct vattr vattr;
20150Sstevel@tonic-gate int error;
20160Sstevel@tonic-gate
20170Sstevel@tonic-gate if (cmd != F_FREESP)
20180Sstevel@tonic-gate return (EINVAL);
20190Sstevel@tonic-gate
20200Sstevel@tonic-gate if ((error = convoff(vp, bfp, 0, offset)) == 0) {
20210Sstevel@tonic-gate if ((bfp->l_start > UINT32_MAX) || (bfp->l_len > UINT32_MAX))
20220Sstevel@tonic-gate return (EFBIG);
20230Sstevel@tonic-gate /*
20240Sstevel@tonic-gate * we only support the special case of l_len == 0,
20250Sstevel@tonic-gate * meaning free to end of file at this moment.
20260Sstevel@tonic-gate */
20270Sstevel@tonic-gate if (bfp->l_len != 0)
20280Sstevel@tonic-gate return (EINVAL);
20290Sstevel@tonic-gate vattr.va_mask = AT_SIZE;
20300Sstevel@tonic-gate vattr.va_size = bfp->l_start;
20315331Samw error = VOP_SETATTR(vp, (vattr_t *)&vattr, 0, cr, ct);
20320Sstevel@tonic-gate }
20330Sstevel@tonic-gate return (error);
20340Sstevel@tonic-gate }
20350Sstevel@tonic-gate
20360Sstevel@tonic-gate /*
20370Sstevel@tonic-gate * Break up 'len' chars from 'buf' into a long file name chunk.
20380Sstevel@tonic-gate * Pad with '0xff' to make Norton Disk Doctor and Microsoft ScanDisk happy.
20390Sstevel@tonic-gate */
20400Sstevel@tonic-gate void
set_long_fn_chunk(struct pcdir_lfn * ep,char * buf,int len)20410Sstevel@tonic-gate set_long_fn_chunk(struct pcdir_lfn *ep, char *buf, int len)
20420Sstevel@tonic-gate {
20430Sstevel@tonic-gate int i;
20440Sstevel@tonic-gate
20454723Sksn ASSERT(buf != NULL);
20460Sstevel@tonic-gate
20470Sstevel@tonic-gate for (i = 0; i < PCLF_FIRSTNAMESIZE; i += 2) {
20480Sstevel@tonic-gate if (len > 0) {
20494723Sksn ep->pcdl_firstfilename[i] = *buf++;
20504723Sksn ep->pcdl_firstfilename[i + 1] = *buf++;
20514723Sksn len -= 2;
20520Sstevel@tonic-gate } else {
20530Sstevel@tonic-gate ep->pcdl_firstfilename[i] = (uchar_t)0xff;
20544723Sksn ep->pcdl_firstfilename[i + 1] = (uchar_t)0xff;
20550Sstevel@tonic-gate }
20560Sstevel@tonic-gate }
20570Sstevel@tonic-gate
20580Sstevel@tonic-gate for (i = 0; i < PCLF_SECONDNAMESIZE; i += 2) {
20590Sstevel@tonic-gate if (len > 0) {
20604723Sksn ep->pcdl_secondfilename[i] = *buf++;
20614723Sksn ep->pcdl_secondfilename[i + 1] = *buf++;
20624723Sksn len -= 2;
20630Sstevel@tonic-gate } else {
20640Sstevel@tonic-gate ep->pcdl_secondfilename[i] = (uchar_t)0xff;
20654723Sksn ep->pcdl_secondfilename[i + 1] = (uchar_t)0xff;
20660Sstevel@tonic-gate }
20670Sstevel@tonic-gate }
20680Sstevel@tonic-gate for (i = 0; i < PCLF_THIRDNAMESIZE; i += 2) {
20690Sstevel@tonic-gate if (len > 0) {
20704723Sksn ep->pcdl_thirdfilename[i] = *buf++;
20714723Sksn ep->pcdl_thirdfilename[i + 1] = *buf++;
20724723Sksn len -= 2;
20730Sstevel@tonic-gate } else {
20740Sstevel@tonic-gate ep->pcdl_thirdfilename[i] = (uchar_t)0xff;
20754723Sksn ep->pcdl_thirdfilename[i + 1] = (uchar_t)0xff;
20760Sstevel@tonic-gate }
20770Sstevel@tonic-gate }
20780Sstevel@tonic-gate }
20790Sstevel@tonic-gate
20800Sstevel@tonic-gate /*
20810Sstevel@tonic-gate * Extract the characters from the long filename chunk into 'buf'.
20820Sstevel@tonic-gate * Return the number of characters extracted.
20830Sstevel@tonic-gate */
20840Sstevel@tonic-gate static int
get_long_fn_chunk(struct pcdir_lfn * ep,char * buf)20857735SOwen.Roberts@Sun.Com get_long_fn_chunk(struct pcdir_lfn *ep, char *buf)
20860Sstevel@tonic-gate {
20870Sstevel@tonic-gate char *tmp = buf;
20880Sstevel@tonic-gate int i;
20890Sstevel@tonic-gate
20904723Sksn /* Copy all the names, no filtering now */
20914723Sksn
20924723Sksn for (i = 0; i < PCLF_FIRSTNAMESIZE; i += 2, tmp += 2) {
20934723Sksn *tmp = ep->pcdl_firstfilename[i];
20944723Sksn *(tmp + 1) = ep->pcdl_firstfilename[i + 1];
20954723Sksn
20964723Sksn if ((*tmp == '\0') && (*(tmp+1) == '\0'))
20970Sstevel@tonic-gate return (tmp - buf);
20980Sstevel@tonic-gate }
20994723Sksn for (i = 0; i < PCLF_SECONDNAMESIZE; i += 2, tmp += 2) {
21004723Sksn *tmp = ep->pcdl_secondfilename[i];
21014723Sksn *(tmp + 1) = ep->pcdl_secondfilename[i + 1];
21024723Sksn
21034723Sksn if ((*tmp == '\0') && (*(tmp+1) == '\0'))
21040Sstevel@tonic-gate return (tmp - buf);
21050Sstevel@tonic-gate }
21064723Sksn for (i = 0; i < PCLF_THIRDNAMESIZE; i += 2, tmp += 2) {
21074723Sksn *tmp = ep->pcdl_thirdfilename[i];
21084723Sksn *(tmp + 1) = ep->pcdl_thirdfilename[i + 1];
21094723Sksn
21104723Sksn if ((*tmp == '\0') && (*(tmp+1) == '\0'))
21110Sstevel@tonic-gate return (tmp - buf);
21120Sstevel@tonic-gate }
21130Sstevel@tonic-gate return (tmp - buf);
21140Sstevel@tonic-gate }
21150Sstevel@tonic-gate
21160Sstevel@tonic-gate
21170Sstevel@tonic-gate /*
21180Sstevel@tonic-gate * Checksum the passed in short filename.
21190Sstevel@tonic-gate * This is used to validate each component of the long name to make
21200Sstevel@tonic-gate * sure the long name is valid (it hasn't been "detached" from the
21210Sstevel@tonic-gate * short filename). This algorithm was found in FreeBSD.
21220Sstevel@tonic-gate * (sys/fs/msdosfs/msdosfs_conv.c:winChksum(), Wolfgang Solfrank)
21230Sstevel@tonic-gate */
21240Sstevel@tonic-gate
21250Sstevel@tonic-gate uchar_t
pc_checksum_long_fn(char * name,char * ext)21260Sstevel@tonic-gate pc_checksum_long_fn(char *name, char *ext)
21270Sstevel@tonic-gate {
21280Sstevel@tonic-gate uchar_t c;
21290Sstevel@tonic-gate char b[11];
21300Sstevel@tonic-gate
21310Sstevel@tonic-gate bcopy(name, b, 8);
21320Sstevel@tonic-gate bcopy(ext, b+8, 3);
21330Sstevel@tonic-gate
21340Sstevel@tonic-gate c = b[0];
21350Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[1];
21360Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[2];
21370Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[3];
21380Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[4];
21390Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[5];
21400Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[6];
21410Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[7];
21420Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[8];
21430Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[9];
21440Sstevel@tonic-gate c = ((c << 7) | (c >> 1)) + b[10];
21450Sstevel@tonic-gate
21460Sstevel@tonic-gate return (c);
21470Sstevel@tonic-gate }
21480Sstevel@tonic-gate
21490Sstevel@tonic-gate /*
21500Sstevel@tonic-gate * Read a chunk of long filename entries into 'namep'.
21510Sstevel@tonic-gate * Return with offset pointing to short entry (on success), or next
21520Sstevel@tonic-gate * entry to read (if this wasn't a valid lfn really).
21530Sstevel@tonic-gate * Uses the passed-in buffer if it can, otherwise kmem_allocs() room for
21540Sstevel@tonic-gate * a long filename.
21550Sstevel@tonic-gate *
21560Sstevel@tonic-gate * Can also be called with a NULL namep, in which case it just returns
21570Sstevel@tonic-gate * whether this was really a valid long filename and consumes it
21580Sstevel@tonic-gate * (used by pc_dirempty()).
21590Sstevel@tonic-gate */
21600Sstevel@tonic-gate int
pc_extract_long_fn(struct pcnode * pcp,char * namep,struct pcdir ** epp,offset_t * offset,struct buf ** bp)21610Sstevel@tonic-gate pc_extract_long_fn(struct pcnode *pcp, char *namep,
21620Sstevel@tonic-gate struct pcdir **epp, offset_t *offset, struct buf **bp)
21630Sstevel@tonic-gate {
21640Sstevel@tonic-gate struct pcdir *ep = *epp;
21650Sstevel@tonic-gate struct pcdir_lfn *lep = (struct pcdir_lfn *)ep;
21660Sstevel@tonic-gate struct vnode *dvp = PCTOV(pcp);
21670Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(dvp->v_vfsp);
21680Sstevel@tonic-gate char *lfn;
21690Sstevel@tonic-gate char *lfn_base;
21700Sstevel@tonic-gate int boff;
21710Sstevel@tonic-gate int i, cs;
21725121Sfrankho char *buf;
21730Sstevel@tonic-gate uchar_t cksum;
21745121Sfrankho int detached = 0;
21750Sstevel@tonic-gate int error = 0;
21760Sstevel@tonic-gate int foldcase;
21774723Sksn int count = 0;
21785121Sfrankho size_t u16l = 0, u8l = 0;
21797735SOwen.Roberts@Sun.Com char *outbuf;
21807735SOwen.Roberts@Sun.Com size_t ret, inlen, outlen;
21810Sstevel@tonic-gate
21820Sstevel@tonic-gate foldcase = (fsp->pcfs_flags & PCFS_FOLDCASE);
21834723Sksn lfn_base = kmem_alloc(PCMAXNAM_UTF16, KM_SLEEP);
21844723Sksn lfn = lfn_base + PCMAXNAM_UTF16 - sizeof (uint16_t);
21850Sstevel@tonic-gate *lfn = '\0';
21864723Sksn *(lfn + 1) = '\0';
21870Sstevel@tonic-gate cksum = lep->pcdl_checksum;
21880Sstevel@tonic-gate
21894723Sksn buf = kmem_alloc(PCMAXNAM_UTF16, KM_SLEEP);
21900Sstevel@tonic-gate for (i = (lep->pcdl_ordinal & ~0xc0); i > 0; i--) {
21910Sstevel@tonic-gate /* read next block if necessary */
21920Sstevel@tonic-gate boff = pc_blkoff(fsp, *offset);
21930Sstevel@tonic-gate if (boff == 0 || *bp == NULL || boff >= (*bp)->b_bcount) {
21940Sstevel@tonic-gate if (*bp != NULL) {
21950Sstevel@tonic-gate brelse(*bp);
21960Sstevel@tonic-gate *bp = NULL;
21970Sstevel@tonic-gate }
21980Sstevel@tonic-gate error = pc_blkatoff(pcp, *offset, bp, &ep);
21990Sstevel@tonic-gate if (error) {
22004723Sksn kmem_free(lfn_base, PCMAXNAM_UTF16);
22014723Sksn kmem_free(buf, PCMAXNAM_UTF16);
22020Sstevel@tonic-gate return (error);
22030Sstevel@tonic-gate }
22040Sstevel@tonic-gate lep = (struct pcdir_lfn *)ep;
22050Sstevel@tonic-gate }
22060Sstevel@tonic-gate /* can this happen? Bad fs? */
22070Sstevel@tonic-gate if (!PCDL_IS_LFN((struct pcdir *)lep)) {
22080Sstevel@tonic-gate detached = 1;
22090Sstevel@tonic-gate break;
22100Sstevel@tonic-gate }
22110Sstevel@tonic-gate if (cksum != lep->pcdl_checksum)
22120Sstevel@tonic-gate detached = 1;
22130Sstevel@tonic-gate /* process current entry */
22147735SOwen.Roberts@Sun.Com cs = get_long_fn_chunk(lep, buf);
22154723Sksn count += cs;
22164723Sksn for (; cs > 0; cs--) {
22174723Sksn /* see if we underflow */
22184723Sksn if (lfn >= lfn_base)
22194723Sksn *--lfn = buf[cs - 1];
22204723Sksn else
22214723Sksn detached = 1;
22220Sstevel@tonic-gate }
22230Sstevel@tonic-gate lep++;
22240Sstevel@tonic-gate *offset += sizeof (struct pcdir);
22250Sstevel@tonic-gate }
22264723Sksn kmem_free(buf, PCMAXNAM_UTF16);
22270Sstevel@tonic-gate /* read next block if necessary */
22280Sstevel@tonic-gate boff = pc_blkoff(fsp, *offset);
22290Sstevel@tonic-gate ep = (struct pcdir *)lep;
22300Sstevel@tonic-gate if (boff == 0 || *bp == NULL || boff >= (*bp)->b_bcount) {
22310Sstevel@tonic-gate if (*bp != NULL) {
22320Sstevel@tonic-gate brelse(*bp);
22330Sstevel@tonic-gate *bp = NULL;
22340Sstevel@tonic-gate }
22350Sstevel@tonic-gate error = pc_blkatoff(pcp, *offset, bp, &ep);
22360Sstevel@tonic-gate if (error) {
22374723Sksn kmem_free(lfn_base, PCMAXNAM_UTF16);
22380Sstevel@tonic-gate return (error);
22390Sstevel@tonic-gate }
22400Sstevel@tonic-gate }
22410Sstevel@tonic-gate /* should be on the short one */
22420Sstevel@tonic-gate if (PCDL_IS_LFN(ep) || ((ep->pcd_filename[0] == PCD_UNUSED) ||
22430Sstevel@tonic-gate (ep->pcd_filename[0] == PCD_ERASED))) {
22440Sstevel@tonic-gate detached = 1;
22450Sstevel@tonic-gate }
22460Sstevel@tonic-gate if (detached ||
22470Sstevel@tonic-gate (cksum != pc_checksum_long_fn(ep->pcd_filename, ep->pcd_ext)) ||
22484723Sksn !pc_valid_long_fn(lfn, 0)) {
22490Sstevel@tonic-gate /*
22500Sstevel@tonic-gate * process current entry again. This may end up another lfn
22510Sstevel@tonic-gate * or a short name.
22520Sstevel@tonic-gate */
22530Sstevel@tonic-gate *epp = ep;
22544723Sksn kmem_free(lfn_base, PCMAXNAM_UTF16);
22550Sstevel@tonic-gate return (EINVAL);
22560Sstevel@tonic-gate }
22570Sstevel@tonic-gate if (PCA_IS_HIDDEN(fsp, ep->pcd_attr)) {
22580Sstevel@tonic-gate /*
22590Sstevel@tonic-gate * Don't display label because it may contain
22600Sstevel@tonic-gate * funny characters.
22610Sstevel@tonic-gate */
22620Sstevel@tonic-gate *offset += sizeof (struct pcdir);
22630Sstevel@tonic-gate ep++;
22640Sstevel@tonic-gate *epp = ep;
22654723Sksn kmem_free(lfn_base, PCMAXNAM_UTF16);
22660Sstevel@tonic-gate return (EINVAL);
22670Sstevel@tonic-gate }
22680Sstevel@tonic-gate if (namep) {
22694723Sksn u16l = count / 2;
22704723Sksn u8l = PCMAXNAMLEN;
22714723Sksn error = uconv_u16tou8((const uint16_t *)lfn, &u16l,
22724723Sksn (uchar_t *)namep, &u8l, UCONV_IN_LITTLE_ENDIAN);
22734723Sksn /*
22744723Sksn * uconv_u16tou8() will catch conversion errors including
22754723Sksn * the case where there is not enough room to write the
22764723Sksn * converted result and the u8l will never go over the given
22774723Sksn * PCMAXNAMLEN.
22784723Sksn */
22794723Sksn if (error != 0) {
22804723Sksn kmem_free(lfn_base, PCMAXNAM_UTF16);
22814723Sksn return (EINVAL);
22824723Sksn }
22834723Sksn namep[u8l] = '\0';
22847735SOwen.Roberts@Sun.Com if (foldcase) {
22857735SOwen.Roberts@Sun.Com inlen = strlen(namep);
22867735SOwen.Roberts@Sun.Com outlen = PCMAXNAMLEN;
22877735SOwen.Roberts@Sun.Com outbuf = kmem_alloc(PCMAXNAMLEN + 1, KM_SLEEP);
22887735SOwen.Roberts@Sun.Com ret = u8_textprep_str(namep, &inlen, outbuf,
22897735SOwen.Roberts@Sun.Com &outlen, U8_TEXTPREP_TOLOWER, U8_UNICODE_LATEST,
22907735SOwen.Roberts@Sun.Com &error);
22917735SOwen.Roberts@Sun.Com if (ret == -1) {
22927735SOwen.Roberts@Sun.Com kmem_free(outbuf, PCMAXNAMLEN + 1);
22937735SOwen.Roberts@Sun.Com kmem_free(lfn_base, PCMAXNAM_UTF16);
22947735SOwen.Roberts@Sun.Com return (EINVAL);
22957735SOwen.Roberts@Sun.Com }
22967735SOwen.Roberts@Sun.Com outbuf[PCMAXNAMLEN - outlen] = '\0';
22977735SOwen.Roberts@Sun.Com (void) strncpy(namep, outbuf, PCMAXNAMLEN + 1);
22987735SOwen.Roberts@Sun.Com kmem_free(outbuf, PCMAXNAMLEN + 1);
22997735SOwen.Roberts@Sun.Com }
23000Sstevel@tonic-gate }
23014723Sksn kmem_free(lfn_base, PCMAXNAM_UTF16);
23020Sstevel@tonic-gate *epp = ep;
23030Sstevel@tonic-gate return (0);
23040Sstevel@tonic-gate }
23050Sstevel@tonic-gate /*
23060Sstevel@tonic-gate * Read a long filename into the pc_dirent structure and copy it out.
23070Sstevel@tonic-gate */
23080Sstevel@tonic-gate int
pc_read_long_fn(struct vnode * dvp,struct uio * uiop,struct pc_dirent * ld,struct pcdir ** epp,offset_t * offset,struct buf ** bp)23090Sstevel@tonic-gate pc_read_long_fn(struct vnode *dvp, struct uio *uiop, struct pc_dirent *ld,
23100Sstevel@tonic-gate struct pcdir **epp, offset_t *offset, struct buf **bp)
23110Sstevel@tonic-gate {
23120Sstevel@tonic-gate struct pcdir *ep;
23130Sstevel@tonic-gate struct pcnode *pcp = VTOPC(dvp);
23140Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(dvp->v_vfsp);
23150Sstevel@tonic-gate offset_t uiooffset = uiop->uio_loffset;
23160Sstevel@tonic-gate int error = 0;
23170Sstevel@tonic-gate offset_t oldoffset;
23180Sstevel@tonic-gate
23190Sstevel@tonic-gate oldoffset = *offset;
23200Sstevel@tonic-gate error = pc_extract_long_fn(pcp, ld->d_name, epp, offset, bp);
23210Sstevel@tonic-gate if (error) {
23220Sstevel@tonic-gate if (error == EINVAL) {
23230Sstevel@tonic-gate uiop->uio_loffset += *offset - oldoffset;
23240Sstevel@tonic-gate return (0);
23250Sstevel@tonic-gate } else
23260Sstevel@tonic-gate return (error);
23270Sstevel@tonic-gate }
23280Sstevel@tonic-gate
23290Sstevel@tonic-gate ep = *epp;
23300Sstevel@tonic-gate uiop->uio_loffset += *offset - oldoffset;
23310Sstevel@tonic-gate ld->d_reclen = DIRENT64_RECLEN(strlen(ld->d_name));
23320Sstevel@tonic-gate if (ld->d_reclen > uiop->uio_resid) {
23330Sstevel@tonic-gate uiop->uio_loffset = uiooffset;
23340Sstevel@tonic-gate return (ENOSPC);
23350Sstevel@tonic-gate }
23360Sstevel@tonic-gate ld->d_off = uiop->uio_loffset + sizeof (struct pcdir);
23370Sstevel@tonic-gate ld->d_ino = pc_makenodeid(pc_daddrdb(fsp, (*bp)->b_blkno),
23380Sstevel@tonic-gate pc_blkoff(fsp, *offset), ep->pcd_attr,
23395121Sfrankho pc_getstartcluster(fsp, ep), pc_direntpersec(fsp));
23400Sstevel@tonic-gate (void) uiomove((caddr_t)ld, ld->d_reclen, UIO_READ, uiop);
23410Sstevel@tonic-gate uiop->uio_loffset = ld->d_off;
23420Sstevel@tonic-gate *offset += sizeof (struct pcdir);
23430Sstevel@tonic-gate ep++;
23440Sstevel@tonic-gate *epp = ep;
23450Sstevel@tonic-gate return (0);
23460Sstevel@tonic-gate }
23470Sstevel@tonic-gate
23480Sstevel@tonic-gate /*
23490Sstevel@tonic-gate * Read a short filename into the pc_dirent structure and copy it out.
23500Sstevel@tonic-gate */
23510Sstevel@tonic-gate int
pc_read_short_fn(struct vnode * dvp,struct uio * uiop,struct pc_dirent * ld,struct pcdir ** epp,offset_t * offset,struct buf ** bp)23520Sstevel@tonic-gate pc_read_short_fn(struct vnode *dvp, struct uio *uiop, struct pc_dirent *ld,
23530Sstevel@tonic-gate struct pcdir **epp, offset_t *offset, struct buf **bp)
23540Sstevel@tonic-gate {
23550Sstevel@tonic-gate struct pcfs *fsp = VFSTOPCFS(dvp->v_vfsp);
23560Sstevel@tonic-gate int boff = pc_blkoff(fsp, *offset);
23570Sstevel@tonic-gate struct pcdir *ep = *epp;
23580Sstevel@tonic-gate offset_t oldoffset = uiop->uio_loffset;
23590Sstevel@tonic-gate int error;
23600Sstevel@tonic-gate int foldcase;
23610Sstevel@tonic-gate
23620Sstevel@tonic-gate if (PCA_IS_HIDDEN(fsp, ep->pcd_attr)) {
23630Sstevel@tonic-gate uiop->uio_loffset += sizeof (struct pcdir);
23640Sstevel@tonic-gate *offset += sizeof (struct pcdir);
23650Sstevel@tonic-gate ep++;
23660Sstevel@tonic-gate *epp = ep;
23670Sstevel@tonic-gate return (0);
23680Sstevel@tonic-gate }
23690Sstevel@tonic-gate ld->d_ino = (ino64_t)pc_makenodeid(pc_daddrdb(fsp, (*bp)->b_blkno),
23705121Sfrankho boff, ep->pcd_attr, pc_getstartcluster(fsp, ep),
23715121Sfrankho pc_direntpersec(fsp));
23720Sstevel@tonic-gate foldcase = (fsp->pcfs_flags & PCFS_FOLDCASE);
23730Sstevel@tonic-gate error = pc_fname_ext_to_name(&ld->d_name[0], &ep->pcd_filename[0],
23740Sstevel@tonic-gate &ep->pcd_ext[0], foldcase);
23750Sstevel@tonic-gate if (error == 0) {
23760Sstevel@tonic-gate ld->d_reclen = DIRENT64_RECLEN(strlen(ld->d_name));
23770Sstevel@tonic-gate if (ld->d_reclen > uiop->uio_resid) {
23780Sstevel@tonic-gate uiop->uio_loffset = oldoffset;
23790Sstevel@tonic-gate return (ENOSPC);
23800Sstevel@tonic-gate }
23810Sstevel@tonic-gate ld->d_off = (off64_t)(uiop->uio_loffset +
23820Sstevel@tonic-gate sizeof (struct pcdir));
23830Sstevel@tonic-gate (void) uiomove((caddr_t)ld,
23840Sstevel@tonic-gate ld->d_reclen, UIO_READ, uiop);
23850Sstevel@tonic-gate uiop->uio_loffset = ld->d_off;
23860Sstevel@tonic-gate } else {
23870Sstevel@tonic-gate uiop->uio_loffset += sizeof (struct pcdir);
23880Sstevel@tonic-gate }
23890Sstevel@tonic-gate *offset += sizeof (struct pcdir);
23900Sstevel@tonic-gate ep++;
23910Sstevel@tonic-gate *epp = ep;
23920Sstevel@tonic-gate return (0);
23930Sstevel@tonic-gate }
23940Sstevel@tonic-gate
23955331Samw /* ARGSUSED */
23960Sstevel@tonic-gate static int
pcfs_fid(struct vnode * vp,struct fid * fidp,caller_context_t * ct)23975331Samw pcfs_fid(struct vnode *vp, struct fid *fidp, caller_context_t *ct)
23980Sstevel@tonic-gate {
23990Sstevel@tonic-gate struct pc_fid *pcfid;
24000Sstevel@tonic-gate struct pcnode *pcp;
24010Sstevel@tonic-gate struct pcfs *fsp;
24020Sstevel@tonic-gate int error;
24030Sstevel@tonic-gate
24040Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp);
24050Sstevel@tonic-gate if (fsp == NULL)
24060Sstevel@tonic-gate return (EIO);
24070Sstevel@tonic-gate error = pc_lockfs(fsp, 0, 0);
24080Sstevel@tonic-gate if (error)
24090Sstevel@tonic-gate return (error);
24102972Sfrankho if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) {
24110Sstevel@tonic-gate pc_unlockfs(fsp);
24120Sstevel@tonic-gate return (EIO);
24130Sstevel@tonic-gate }
24140Sstevel@tonic-gate if (fidp->fid_len < (sizeof (struct pc_fid) - sizeof (ushort_t))) {
24150Sstevel@tonic-gate fidp->fid_len = sizeof (struct pc_fid) - sizeof (ushort_t);
24160Sstevel@tonic-gate pc_unlockfs(fsp);
24170Sstevel@tonic-gate return (ENOSPC);
24180Sstevel@tonic-gate }
24190Sstevel@tonic-gate
24200Sstevel@tonic-gate pcfid = (struct pc_fid *)fidp;
24210Sstevel@tonic-gate bzero(pcfid, sizeof (struct pc_fid));
24220Sstevel@tonic-gate pcfid->pcfid_len = sizeof (struct pc_fid) - sizeof (ushort_t);
24230Sstevel@tonic-gate if (vp->v_flag & VROOT) {
24240Sstevel@tonic-gate pcfid->pcfid_block = 0;
24250Sstevel@tonic-gate pcfid->pcfid_offset = 0;
24260Sstevel@tonic-gate pcfid->pcfid_ctime = 0;
24270Sstevel@tonic-gate } else {
24280Sstevel@tonic-gate pcfid->pcfid_block = pcp->pc_eblkno;
24290Sstevel@tonic-gate pcfid->pcfid_offset = pcp->pc_eoffset;
24300Sstevel@tonic-gate pcfid->pcfid_ctime = pcp->pc_entry.pcd_crtime.pct_time;
24310Sstevel@tonic-gate }
24320Sstevel@tonic-gate pc_unlockfs(fsp);
24330Sstevel@tonic-gate return (0);
24340Sstevel@tonic-gate }
2435