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
53898Srsb * Common Development and Distribution License (the "License").
63898Srsb * 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 */
210Sstevel@tonic-gate /*
2212633Sjohn.levon@sun.com * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate */
240Sstevel@tonic-gate
250Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
260Sstevel@tonic-gate /* All rights reserved. */
270Sstevel@tonic-gate
280Sstevel@tonic-gate
290Sstevel@tonic-gate #include <sys/types.h>
300Sstevel@tonic-gate #include <sys/param.h>
310Sstevel@tonic-gate #include <sys/cmn_err.h>
320Sstevel@tonic-gate #include <sys/debug.h>
330Sstevel@tonic-gate #include <sys/dirent.h>
340Sstevel@tonic-gate #include <sys/errno.h>
350Sstevel@tonic-gate #include <sys/file.h>
360Sstevel@tonic-gate #include <sys/inline.h>
370Sstevel@tonic-gate #include <sys/kmem.h>
380Sstevel@tonic-gate #include <sys/pathname.h>
390Sstevel@tonic-gate #include <sys/resource.h>
400Sstevel@tonic-gate #include <sys/statvfs.h>
410Sstevel@tonic-gate #include <sys/mount.h>
420Sstevel@tonic-gate #include <sys/sysmacros.h>
430Sstevel@tonic-gate #include <sys/systm.h>
440Sstevel@tonic-gate #include <sys/uio.h>
450Sstevel@tonic-gate #include <sys/vfs.h>
463898Srsb #include <sys/vfs_opreg.h>
470Sstevel@tonic-gate #include <sys/vnode.h>
480Sstevel@tonic-gate #include <sys/cred.h>
490Sstevel@tonic-gate #include <sys/mntent.h>
500Sstevel@tonic-gate #include <sys/mount.h>
510Sstevel@tonic-gate #include <sys/user.h>
520Sstevel@tonic-gate #include <sys/t_lock.h>
530Sstevel@tonic-gate #include <sys/modctl.h>
540Sstevel@tonic-gate #include <sys/policy.h>
550Sstevel@tonic-gate #include <fs/fs_subr.h>
560Sstevel@tonic-gate #include <sys/atomic.h>
570Sstevel@tonic-gate #include <sys/mkdev.h>
580Sstevel@tonic-gate
590Sstevel@tonic-gate #define round(r) (((r)+sizeof (int)-1)&(~(sizeof (int)-1)))
600Sstevel@tonic-gate #define fdtoi(n) ((n)+100)
610Sstevel@tonic-gate
620Sstevel@tonic-gate #define FDDIRSIZE 14
630Sstevel@tonic-gate struct fddirect {
640Sstevel@tonic-gate short d_ino;
650Sstevel@tonic-gate char d_name[FDDIRSIZE];
660Sstevel@tonic-gate };
670Sstevel@tonic-gate
680Sstevel@tonic-gate #define FDROOTINO 2
690Sstevel@tonic-gate #define FDSDSIZE sizeof (struct fddirect)
700Sstevel@tonic-gate #define FDNSIZE 10
710Sstevel@tonic-gate
720Sstevel@tonic-gate static int fdfstype = 0;
730Sstevel@tonic-gate static major_t fdfsmaj;
740Sstevel@tonic-gate static minor_t fdfsmin;
750Sstevel@tonic-gate static major_t fdrmaj;
760Sstevel@tonic-gate static kmutex_t fd_minor_lock;
770Sstevel@tonic-gate
780Sstevel@tonic-gate static int fdget(vnode_t *, char *, vnode_t **);
790Sstevel@tonic-gate
800Sstevel@tonic-gate /* ARGSUSED */
810Sstevel@tonic-gate static int
fdopen(vnode_t ** vpp,int mode,cred_t * cr,caller_context_t * ct)825331Samw fdopen(vnode_t **vpp, int mode, cred_t *cr, caller_context_t *ct)
830Sstevel@tonic-gate {
840Sstevel@tonic-gate if ((*vpp)->v_type != VDIR) {
850Sstevel@tonic-gate mutex_enter(&(*vpp)->v_lock);
860Sstevel@tonic-gate (*vpp)->v_flag |= VDUP;
870Sstevel@tonic-gate mutex_exit(&(*vpp)->v_lock);
880Sstevel@tonic-gate }
890Sstevel@tonic-gate return (0);
900Sstevel@tonic-gate }
910Sstevel@tonic-gate
920Sstevel@tonic-gate /* ARGSUSED */
930Sstevel@tonic-gate static int
fdclose(vnode_t * vp,int flag,int count,offset_t offset,cred_t * cr,caller_context_t * ct)945331Samw fdclose(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
955331Samw caller_context_t *ct)
960Sstevel@tonic-gate {
970Sstevel@tonic-gate return (0);
980Sstevel@tonic-gate }
990Sstevel@tonic-gate
1000Sstevel@tonic-gate /* ARGSUSED */
1010Sstevel@tonic-gate static int
fdread(vnode_t * vp,uio_t * uiop,int ioflag,cred_t * cr,caller_context_t * ct)1020Sstevel@tonic-gate fdread(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr, caller_context_t *ct)
1030Sstevel@tonic-gate {
1040Sstevel@tonic-gate static struct fddirect dotbuf[] = {
1050Sstevel@tonic-gate { FDROOTINO, "." },
1060Sstevel@tonic-gate { FDROOTINO, ".." }
1070Sstevel@tonic-gate };
1080Sstevel@tonic-gate struct fddirect dirbuf;
1090Sstevel@tonic-gate int i, n;
1100Sstevel@tonic-gate int minfd, maxfd, modoff, error = 0;
1110Sstevel@tonic-gate int nentries;
1120Sstevel@tonic-gate rctl_qty_t fdno_ctl;
1130Sstevel@tonic-gate int endoff;
1140Sstevel@tonic-gate
1150Sstevel@tonic-gate if (vp->v_type != VDIR)
1160Sstevel@tonic-gate return (ENOSYS);
1170Sstevel@tonic-gate
1180Sstevel@tonic-gate mutex_enter(&curproc->p_lock);
1190Sstevel@tonic-gate fdno_ctl = rctl_enforced_value(rctlproc_legacy[RLIMIT_NOFILE],
1200Sstevel@tonic-gate curproc->p_rctls, curproc);
1210Sstevel@tonic-gate nentries = MIN(P_FINFO(curproc)->fi_nfiles, (int)fdno_ctl);
1220Sstevel@tonic-gate mutex_exit(&curproc->p_lock);
1230Sstevel@tonic-gate
1240Sstevel@tonic-gate endoff = (nentries + 2) * FDSDSIZE;
1250Sstevel@tonic-gate
1260Sstevel@tonic-gate /*
1270Sstevel@tonic-gate * Fake up ".", "..", and the /dev/fd directory entries.
1280Sstevel@tonic-gate */
1290Sstevel@tonic-gate if (uiop->uio_loffset < (offset_t)0 ||
1300Sstevel@tonic-gate uiop->uio_loffset >= (offset_t)endoff ||
1310Sstevel@tonic-gate uiop->uio_resid <= 0)
1320Sstevel@tonic-gate return (0);
1330Sstevel@tonic-gate ASSERT(uiop->uio_loffset <= MAXOFF_T);
1340Sstevel@tonic-gate if (uiop->uio_offset < 2*FDSDSIZE) {
1350Sstevel@tonic-gate error = uiomove((caddr_t)dotbuf + uiop->uio_offset,
1360Sstevel@tonic-gate MIN(uiop->uio_resid, 2*FDSDSIZE - uiop->uio_offset),
1370Sstevel@tonic-gate UIO_READ, uiop);
1380Sstevel@tonic-gate if (uiop->uio_resid <= 0 || error)
1390Sstevel@tonic-gate return (error);
1400Sstevel@tonic-gate }
1410Sstevel@tonic-gate minfd = (uiop->uio_offset - 2*FDSDSIZE)/FDSDSIZE;
1420Sstevel@tonic-gate maxfd = (uiop->uio_offset + uiop->uio_resid - 1)/FDSDSIZE;
1430Sstevel@tonic-gate modoff = uiop->uio_offset % FDSDSIZE;
1440Sstevel@tonic-gate
1450Sstevel@tonic-gate for (i = 0; i < FDDIRSIZE; i++)
1460Sstevel@tonic-gate dirbuf.d_name[i] = '\0';
1470Sstevel@tonic-gate for (i = minfd; i < MIN(maxfd, nentries); i++) {
1480Sstevel@tonic-gate n = i;
1490Sstevel@tonic-gate dirbuf.d_ino = fdtoi(n);
1500Sstevel@tonic-gate numtos((ulong_t)n, dirbuf.d_name);
1510Sstevel@tonic-gate error = uiomove((caddr_t)&dirbuf + modoff,
1520Sstevel@tonic-gate MIN(uiop->uio_resid, FDSDSIZE - modoff),
1530Sstevel@tonic-gate UIO_READ, uiop);
1540Sstevel@tonic-gate if (uiop->uio_resid <= 0 || error)
1550Sstevel@tonic-gate return (error);
1560Sstevel@tonic-gate modoff = 0;
1570Sstevel@tonic-gate }
1580Sstevel@tonic-gate
1590Sstevel@tonic-gate return (error);
1600Sstevel@tonic-gate }
1610Sstevel@tonic-gate
1620Sstevel@tonic-gate /* ARGSUSED */
1630Sstevel@tonic-gate static int
fdgetattr(vnode_t * vp,vattr_t * vap,int flags,cred_t * cr,caller_context_t * ct)1645331Samw fdgetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
1655331Samw caller_context_t *ct)
1660Sstevel@tonic-gate {
1670Sstevel@tonic-gate vfs_t *vfsp = vp->v_vfsp;
1680Sstevel@tonic-gate timestruc_t now;
1690Sstevel@tonic-gate
1700Sstevel@tonic-gate if (vp->v_type == VDIR) {
1710Sstevel@tonic-gate vap->va_nlink = 2;
1720Sstevel@tonic-gate vap->va_size = (u_offset_t)
1730Sstevel@tonic-gate ((P_FINFO(curproc)->fi_nfiles + 2) * FDSDSIZE);
1740Sstevel@tonic-gate vap->va_mode = 0555;
1750Sstevel@tonic-gate vap->va_nodeid = (ino64_t)FDROOTINO;
1760Sstevel@tonic-gate } else {
1770Sstevel@tonic-gate vap->va_nlink = 1;
1780Sstevel@tonic-gate vap->va_size = (u_offset_t)0;
1790Sstevel@tonic-gate vap->va_mode = 0666;
1800Sstevel@tonic-gate vap->va_nodeid = (ino64_t)fdtoi(getminor(vp->v_rdev));
1810Sstevel@tonic-gate }
1820Sstevel@tonic-gate vap->va_type = vp->v_type;
1830Sstevel@tonic-gate vap->va_rdev = vp->v_rdev;
1840Sstevel@tonic-gate vap->va_blksize = vfsp->vfs_bsize;
1850Sstevel@tonic-gate vap->va_nblocks = (fsblkcnt64_t)0;
1860Sstevel@tonic-gate gethrestime(&now);
1870Sstevel@tonic-gate vap->va_atime = vap->va_mtime = vap->va_ctime = now;
1880Sstevel@tonic-gate vap->va_uid = 0;
1890Sstevel@tonic-gate vap->va_gid = 0;
1900Sstevel@tonic-gate vap->va_fsid = vfsp->vfs_dev;
1910Sstevel@tonic-gate vap->va_seq = 0;
1920Sstevel@tonic-gate return (0);
1930Sstevel@tonic-gate }
1940Sstevel@tonic-gate
1950Sstevel@tonic-gate /* ARGSUSED */
1960Sstevel@tonic-gate static int
fdaccess(vnode_t * vp,int mode,int flags,cred_t * cr,caller_context_t * ct)1975331Samw fdaccess(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
1980Sstevel@tonic-gate {
1990Sstevel@tonic-gate return (0);
2000Sstevel@tonic-gate }
2010Sstevel@tonic-gate
2020Sstevel@tonic-gate /* ARGSUSED */
2030Sstevel@tonic-gate static int
fdlookup(vnode_t * dp,char * comp,vnode_t ** vpp,pathname_t * pnp,int flags,vnode_t * rdir,cred_t * cr,caller_context_t * ct,int * direntflags,pathname_t * realpnp)2040Sstevel@tonic-gate fdlookup(vnode_t *dp, char *comp, vnode_t **vpp, pathname_t *pnp,
2055331Samw int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
2065331Samw int *direntflags, pathname_t *realpnp)
2070Sstevel@tonic-gate {
2080Sstevel@tonic-gate if (comp[0] == 0 || strcmp(comp, ".") == 0 || strcmp(comp, "..") == 0) {
2090Sstevel@tonic-gate VN_HOLD(dp);
2100Sstevel@tonic-gate *vpp = dp;
2110Sstevel@tonic-gate return (0);
2120Sstevel@tonic-gate }
2130Sstevel@tonic-gate return (fdget(dp, comp, vpp));
2140Sstevel@tonic-gate }
2150Sstevel@tonic-gate
2160Sstevel@tonic-gate /* ARGSUSED */
2170Sstevel@tonic-gate static int
fdcreate(vnode_t * dvp,char * comp,vattr_t * vap,enum vcexcl excl,int mode,vnode_t ** vpp,cred_t * cr,int flag,caller_context_t * ct,vsecattr_t * vsecp)2180Sstevel@tonic-gate fdcreate(vnode_t *dvp, char *comp, vattr_t *vap, enum vcexcl excl,
2195331Samw int mode, vnode_t **vpp, cred_t *cr, int flag, caller_context_t *ct,
2205331Samw vsecattr_t *vsecp)
2210Sstevel@tonic-gate {
2220Sstevel@tonic-gate return (fdget(dvp, comp, vpp));
2230Sstevel@tonic-gate }
2240Sstevel@tonic-gate
2250Sstevel@tonic-gate /* ARGSUSED */
2260Sstevel@tonic-gate static int
fdreaddir(vnode_t * vp,uio_t * uiop,cred_t * cr,int * eofp,caller_context_t * ct,int flags)2275331Samw fdreaddir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp, caller_context_t *ct,
2285331Samw int flags)
2290Sstevel@tonic-gate {
2300Sstevel@tonic-gate /* bp holds one dirent structure */
2310Sstevel@tonic-gate u_offset_t bp[DIRENT64_RECLEN(FDNSIZE) / sizeof (u_offset_t)];
2320Sstevel@tonic-gate struct dirent64 *dirent = (struct dirent64 *)bp;
2330Sstevel@tonic-gate int reclen, nentries;
2340Sstevel@tonic-gate rctl_qty_t fdno_ctl;
2350Sstevel@tonic-gate int n;
2360Sstevel@tonic-gate int oresid;
2370Sstevel@tonic-gate off_t off;
2380Sstevel@tonic-gate
2390Sstevel@tonic-gate if (uiop->uio_offset < 0 || uiop->uio_resid <= 0 ||
2400Sstevel@tonic-gate (uiop->uio_offset % FDSDSIZE) != 0)
2410Sstevel@tonic-gate return (ENOENT);
2420Sstevel@tonic-gate
2430Sstevel@tonic-gate ASSERT(uiop->uio_loffset <= MAXOFF_T);
2440Sstevel@tonic-gate oresid = uiop->uio_resid;
2450Sstevel@tonic-gate bzero(bp, sizeof (bp));
2460Sstevel@tonic-gate
2470Sstevel@tonic-gate mutex_enter(&curproc->p_lock);
2480Sstevel@tonic-gate fdno_ctl = rctl_enforced_value(rctlproc_legacy[RLIMIT_NOFILE],
2490Sstevel@tonic-gate curproc->p_rctls, curproc);
2500Sstevel@tonic-gate nentries = MIN(P_FINFO(curproc)->fi_nfiles, (int)fdno_ctl);
2510Sstevel@tonic-gate mutex_exit(&curproc->p_lock);
2520Sstevel@tonic-gate
2530Sstevel@tonic-gate while (uiop->uio_resid > 0) {
2540Sstevel@tonic-gate if ((off = uiop->uio_offset) == 0) { /* "." */
2550Sstevel@tonic-gate dirent->d_ino = (ino64_t)FDROOTINO;
2560Sstevel@tonic-gate dirent->d_name[0] = '.';
2570Sstevel@tonic-gate dirent->d_name[1] = '\0';
2580Sstevel@tonic-gate reclen = DIRENT64_RECLEN(1);
2590Sstevel@tonic-gate } else if (off == FDSDSIZE) { /* ".." */
2600Sstevel@tonic-gate dirent->d_ino = (ino64_t)FDROOTINO;
2610Sstevel@tonic-gate dirent->d_name[0] = '.';
2620Sstevel@tonic-gate dirent->d_name[1] = '.';
2630Sstevel@tonic-gate dirent->d_name[2] = '\0';
2640Sstevel@tonic-gate reclen = DIRENT64_RECLEN(2);
2650Sstevel@tonic-gate } else {
2660Sstevel@tonic-gate /*
2670Sstevel@tonic-gate * Return entries corresponding to the allowable
2680Sstevel@tonic-gate * number of file descriptors for this process.
2690Sstevel@tonic-gate */
2700Sstevel@tonic-gate if ((n = (off-2*FDSDSIZE)/FDSDSIZE) >= nentries)
2710Sstevel@tonic-gate break;
2720Sstevel@tonic-gate dirent->d_ino = (ino64_t)fdtoi(n);
2730Sstevel@tonic-gate numtos((ulong_t)n, dirent->d_name);
2740Sstevel@tonic-gate reclen = DIRENT64_RECLEN(strlen(dirent->d_name));
2750Sstevel@tonic-gate }
2760Sstevel@tonic-gate dirent->d_off = (offset_t)(uiop->uio_offset + FDSDSIZE);
2770Sstevel@tonic-gate dirent->d_reclen = (ushort_t)reclen;
2780Sstevel@tonic-gate
2790Sstevel@tonic-gate if (reclen > uiop->uio_resid) {
2800Sstevel@tonic-gate /*
2810Sstevel@tonic-gate * Error if no entries have been returned yet.
2820Sstevel@tonic-gate */
2830Sstevel@tonic-gate if (uiop->uio_resid == oresid)
2840Sstevel@tonic-gate return (EINVAL);
2850Sstevel@tonic-gate break;
2860Sstevel@tonic-gate }
2870Sstevel@tonic-gate /*
2880Sstevel@tonic-gate * uiomove() updates both resid and offset by the same
2890Sstevel@tonic-gate * amount. But we want offset to change in increments
2900Sstevel@tonic-gate * of FDSDSIZE, which is different from the number of bytes
2910Sstevel@tonic-gate * being returned to the user. So we set uio_offset
2920Sstevel@tonic-gate * separately, ignoring what uiomove() does.
2930Sstevel@tonic-gate */
2940Sstevel@tonic-gate if (uiomove((caddr_t)dirent, reclen, UIO_READ, uiop))
2950Sstevel@tonic-gate return (EFAULT);
2960Sstevel@tonic-gate uiop->uio_offset = off + FDSDSIZE;
2970Sstevel@tonic-gate }
2980Sstevel@tonic-gate if (eofp)
2990Sstevel@tonic-gate *eofp = ((uiop->uio_offset-2*FDSDSIZE)/FDSDSIZE >= nentries);
3000Sstevel@tonic-gate return (0);
3010Sstevel@tonic-gate }
3020Sstevel@tonic-gate
3030Sstevel@tonic-gate /* ARGSUSED */
3040Sstevel@tonic-gate static void
fdinactive(vnode_t * vp,cred_t * cr,caller_context_t * ct)3055331Samw fdinactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
3060Sstevel@tonic-gate {
3070Sstevel@tonic-gate mutex_enter(&vp->v_lock);
3080Sstevel@tonic-gate ASSERT(vp->v_count >= 1);
3090Sstevel@tonic-gate if (--vp->v_count != 0) {
3100Sstevel@tonic-gate mutex_exit(&vp->v_lock);
3110Sstevel@tonic-gate return;
3120Sstevel@tonic-gate }
3130Sstevel@tonic-gate mutex_exit(&vp->v_lock);
3140Sstevel@tonic-gate vn_invalid(vp);
3150Sstevel@tonic-gate vn_free(vp);
3160Sstevel@tonic-gate }
3170Sstevel@tonic-gate
3180Sstevel@tonic-gate static struct vnodeops *fd_vnodeops;
3190Sstevel@tonic-gate
3200Sstevel@tonic-gate static const fs_operation_def_t fd_vnodeops_template[] = {
3213898Srsb VOPNAME_OPEN, { .vop_open = fdopen },
3223898Srsb VOPNAME_CLOSE, { .vop_close = fdclose },
3233898Srsb VOPNAME_READ, { .vop_read = fdread },
3243898Srsb VOPNAME_GETATTR, { .vop_getattr = fdgetattr },
3253898Srsb VOPNAME_ACCESS, { .vop_access = fdaccess },
3263898Srsb VOPNAME_LOOKUP, { .vop_lookup = fdlookup },
3273898Srsb VOPNAME_CREATE, { .vop_create = fdcreate },
3283898Srsb VOPNAME_READDIR, { .vop_readdir = fdreaddir },
3293898Srsb VOPNAME_INACTIVE, { .vop_inactive = fdinactive },
3303898Srsb VOPNAME_FRLOCK, { .error = fs_error },
3313898Srsb VOPNAME_POLL, { .error = fs_error },
3323898Srsb VOPNAME_DISPOSE, { .error = fs_error },
3333898Srsb NULL, NULL
3340Sstevel@tonic-gate };
3350Sstevel@tonic-gate
3360Sstevel@tonic-gate static int
fdget(struct vnode * dvp,char * comp,struct vnode ** vpp)3370Sstevel@tonic-gate fdget(struct vnode *dvp, char *comp, struct vnode **vpp)
3380Sstevel@tonic-gate {
3390Sstevel@tonic-gate int n = 0;
3400Sstevel@tonic-gate struct vnode *vp;
3410Sstevel@tonic-gate
3420Sstevel@tonic-gate while (*comp) {
3430Sstevel@tonic-gate if (*comp < '0' || *comp > '9')
3440Sstevel@tonic-gate return (ENOENT);
3450Sstevel@tonic-gate n = 10 * n + *comp++ - '0';
3460Sstevel@tonic-gate }
3470Sstevel@tonic-gate vp = vn_alloc(KM_SLEEP);
3480Sstevel@tonic-gate vp->v_type = VCHR;
3490Sstevel@tonic-gate vp->v_vfsp = dvp->v_vfsp;
3500Sstevel@tonic-gate vn_setops(vp, fd_vnodeops);
3510Sstevel@tonic-gate vp->v_data = NULL;
3520Sstevel@tonic-gate vp->v_flag = VNOMAP;
3530Sstevel@tonic-gate vp->v_rdev = makedevice(fdrmaj, n);
3540Sstevel@tonic-gate vn_exists(vp);
3550Sstevel@tonic-gate *vpp = vp;
3560Sstevel@tonic-gate return (0);
3570Sstevel@tonic-gate }
3580Sstevel@tonic-gate
3590Sstevel@tonic-gate /*
3600Sstevel@tonic-gate * fdfs is mounted on /dev/fd, however, there are two interesting
3610Sstevel@tonic-gate * possibilities - two threads racing to do the same mount (protected
3620Sstevel@tonic-gate * by vfs locking), and two threads mounting fdfs in different places.
3630Sstevel@tonic-gate */
3640Sstevel@tonic-gate /*ARGSUSED*/
3650Sstevel@tonic-gate static int
fdmount(vfs_t * vfsp,vnode_t * mvp,struct mounta * uap,cred_t * cr)3660Sstevel@tonic-gate fdmount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
3670Sstevel@tonic-gate {
3680Sstevel@tonic-gate struct vnode *vp;
3690Sstevel@tonic-gate
3700Sstevel@tonic-gate if (secpolicy_fs_mount(cr, mvp, vfsp) != 0)
3710Sstevel@tonic-gate return (EPERM);
3720Sstevel@tonic-gate if (mvp->v_type != VDIR)
3730Sstevel@tonic-gate return (ENOTDIR);
3740Sstevel@tonic-gate
3750Sstevel@tonic-gate mutex_enter(&mvp->v_lock);
3760Sstevel@tonic-gate if ((uap->flags & MS_OVERLAY) == 0 &&
3770Sstevel@tonic-gate (mvp->v_count > 1 || (mvp->v_flag & VROOT))) {
3780Sstevel@tonic-gate mutex_exit(&mvp->v_lock);
3790Sstevel@tonic-gate return (EBUSY);
3800Sstevel@tonic-gate }
3810Sstevel@tonic-gate mutex_exit(&mvp->v_lock);
3820Sstevel@tonic-gate
3830Sstevel@tonic-gate /*
3840Sstevel@tonic-gate * Having the resource be anything but "fd" doesn't make sense
3850Sstevel@tonic-gate */
386*12894SRobert.Harris@Sun.COM vfs_setresource(vfsp, "fd", 0);
3870Sstevel@tonic-gate
3880Sstevel@tonic-gate vp = vn_alloc(KM_SLEEP);
3890Sstevel@tonic-gate vp->v_vfsp = vfsp;
3900Sstevel@tonic-gate vn_setops(vp, fd_vnodeops);
3910Sstevel@tonic-gate vp->v_type = VDIR;
3920Sstevel@tonic-gate vp->v_data = NULL;
3930Sstevel@tonic-gate vp->v_flag |= VROOT;
3940Sstevel@tonic-gate vfsp->vfs_fstype = fdfstype;
3950Sstevel@tonic-gate vfsp->vfs_data = (char *)vp;
3960Sstevel@tonic-gate mutex_enter(&fd_minor_lock);
3970Sstevel@tonic-gate do {
3980Sstevel@tonic-gate fdfsmin = (fdfsmin + 1) & L_MAXMIN32;
3990Sstevel@tonic-gate vfsp->vfs_dev = makedevice(fdfsmaj, fdfsmin);
4000Sstevel@tonic-gate } while (vfs_devismounted(vfsp->vfs_dev));
4010Sstevel@tonic-gate mutex_exit(&fd_minor_lock);
4020Sstevel@tonic-gate vfs_make_fsid(&vfsp->vfs_fsid, vfsp->vfs_dev, fdfstype);
4030Sstevel@tonic-gate vfsp->vfs_bsize = 1024;
4040Sstevel@tonic-gate return (0);
4050Sstevel@tonic-gate }
4060Sstevel@tonic-gate
4070Sstevel@tonic-gate /* ARGSUSED */
4080Sstevel@tonic-gate static int
fdunmount(vfs_t * vfsp,int flag,cred_t * cr)4090Sstevel@tonic-gate fdunmount(vfs_t *vfsp, int flag, cred_t *cr)
4100Sstevel@tonic-gate {
4110Sstevel@tonic-gate vnode_t *rvp;
4120Sstevel@tonic-gate
4130Sstevel@tonic-gate if (secpolicy_fs_unmount(cr, vfsp) != 0)
4140Sstevel@tonic-gate return (EPERM);
4150Sstevel@tonic-gate
4160Sstevel@tonic-gate /*
4170Sstevel@tonic-gate * forced unmount is not supported by this file system
4180Sstevel@tonic-gate * and thus, ENOTSUP, is being returned.
4190Sstevel@tonic-gate */
4200Sstevel@tonic-gate if (flag & MS_FORCE)
4210Sstevel@tonic-gate return (ENOTSUP);
4220Sstevel@tonic-gate
4230Sstevel@tonic-gate rvp = (vnode_t *)vfsp->vfs_data;
4240Sstevel@tonic-gate if (rvp->v_count > 1)
4250Sstevel@tonic-gate return (EBUSY);
4260Sstevel@tonic-gate
4270Sstevel@tonic-gate VN_RELE(rvp);
4280Sstevel@tonic-gate return (0);
4290Sstevel@tonic-gate }
4300Sstevel@tonic-gate
4310Sstevel@tonic-gate /* ARGSUSED */
4320Sstevel@tonic-gate static int
fdroot(vfs_t * vfsp,vnode_t ** vpp)4330Sstevel@tonic-gate fdroot(vfs_t *vfsp, vnode_t **vpp)
4340Sstevel@tonic-gate {
4350Sstevel@tonic-gate vnode_t *vp = (vnode_t *)vfsp->vfs_data;
4360Sstevel@tonic-gate
4370Sstevel@tonic-gate VN_HOLD(vp);
4380Sstevel@tonic-gate *vpp = vp;
4390Sstevel@tonic-gate return (0);
4400Sstevel@tonic-gate }
4410Sstevel@tonic-gate
4420Sstevel@tonic-gate /*
4430Sstevel@tonic-gate * No locking required because I held the root vnode before calling this
4440Sstevel@tonic-gate * function so the vfs won't disappear on me. To be more explicit:
4450Sstevel@tonic-gate * fdvrootp->v_count will be greater than 1 so fdunmount will just return.
4460Sstevel@tonic-gate */
4470Sstevel@tonic-gate static int
fdstatvfs(struct vfs * vfsp,struct statvfs64 * sp)4480Sstevel@tonic-gate fdstatvfs(struct vfs *vfsp, struct statvfs64 *sp)
4490Sstevel@tonic-gate {
4500Sstevel@tonic-gate dev32_t d32;
4510Sstevel@tonic-gate rctl_qty_t fdno_ctl;
4520Sstevel@tonic-gate
4530Sstevel@tonic-gate mutex_enter(&curproc->p_lock);
4540Sstevel@tonic-gate fdno_ctl = rctl_enforced_value(rctlproc_legacy[RLIMIT_NOFILE],
4550Sstevel@tonic-gate curproc->p_rctls, curproc);
4560Sstevel@tonic-gate mutex_exit(&curproc->p_lock);
4570Sstevel@tonic-gate
4580Sstevel@tonic-gate bzero(sp, sizeof (*sp));
4590Sstevel@tonic-gate sp->f_bsize = 1024;
4600Sstevel@tonic-gate sp->f_frsize = 1024;
4610Sstevel@tonic-gate sp->f_blocks = (fsblkcnt64_t)0;
4620Sstevel@tonic-gate sp->f_bfree = (fsblkcnt64_t)0;
4630Sstevel@tonic-gate sp->f_bavail = (fsblkcnt64_t)0;
4640Sstevel@tonic-gate sp->f_files = (fsfilcnt64_t)
4650Sstevel@tonic-gate (MIN(P_FINFO(curproc)->fi_nfiles, fdno_ctl + 2));
4660Sstevel@tonic-gate sp->f_ffree = (fsfilcnt64_t)0;
4670Sstevel@tonic-gate sp->f_favail = (fsfilcnt64_t)0;
4680Sstevel@tonic-gate (void) cmpldev(&d32, vfsp->vfs_dev);
4690Sstevel@tonic-gate sp->f_fsid = d32;
4700Sstevel@tonic-gate (void) strcpy(sp->f_basetype, vfssw[fdfstype].vsw_name);
4710Sstevel@tonic-gate sp->f_flag = vf_to_stf(vfsp->vfs_flag);
4720Sstevel@tonic-gate sp->f_namemax = FDNSIZE;
4730Sstevel@tonic-gate (void) strcpy(sp->f_fstr, "/dev/fd");
4740Sstevel@tonic-gate (void) strcpy(&sp->f_fstr[8], "/dev/fd");
4750Sstevel@tonic-gate return (0);
4760Sstevel@tonic-gate }
4770Sstevel@tonic-gate
4780Sstevel@tonic-gate int
fdinit(int fstype,char * name)4790Sstevel@tonic-gate fdinit(int fstype, char *name)
4800Sstevel@tonic-gate {
4810Sstevel@tonic-gate static const fs_operation_def_t fd_vfsops_template[] = {
4823898Srsb VFSNAME_MOUNT, { .vfs_mount = fdmount },
4833898Srsb VFSNAME_UNMOUNT, { .vfs_unmount = fdunmount },
4843898Srsb VFSNAME_ROOT, { .vfs_root = fdroot },
4853898Srsb VFSNAME_STATVFS, { .vfs_statvfs = fdstatvfs },
4863898Srsb NULL, NULL
4870Sstevel@tonic-gate };
4880Sstevel@tonic-gate int error;
4890Sstevel@tonic-gate
4900Sstevel@tonic-gate fdfstype = fstype;
4910Sstevel@tonic-gate ASSERT(fdfstype != 0);
4920Sstevel@tonic-gate
4930Sstevel@tonic-gate /*
4940Sstevel@tonic-gate * Associate VFS ops vector with this fstype.
4950Sstevel@tonic-gate */
4960Sstevel@tonic-gate error = vfs_setfsops(fstype, fd_vfsops_template, NULL);
4970Sstevel@tonic-gate if (error != 0) {
4980Sstevel@tonic-gate cmn_err(CE_WARN, "fdinit: bad vnode ops template");
4990Sstevel@tonic-gate return (error);
5000Sstevel@tonic-gate }
5010Sstevel@tonic-gate
5020Sstevel@tonic-gate error = vn_make_ops(name, fd_vnodeops_template, &fd_vnodeops);
5030Sstevel@tonic-gate if (error != 0) {
5040Sstevel@tonic-gate (void) vfs_freevfsops_by_type(fstype);
5050Sstevel@tonic-gate cmn_err(CE_WARN, "fdinit: bad vnode ops template");
5060Sstevel@tonic-gate return (error);
5070Sstevel@tonic-gate }
5080Sstevel@tonic-gate
5090Sstevel@tonic-gate /*
5100Sstevel@tonic-gate * Assign unique "device" numbers (reported by stat(2)).
5110Sstevel@tonic-gate */
5120Sstevel@tonic-gate fdfsmaj = getudev();
5130Sstevel@tonic-gate fdrmaj = getudev();
5140Sstevel@tonic-gate if (fdfsmaj == (major_t)-1 || fdrmaj == (major_t)-1) {
5150Sstevel@tonic-gate cmn_err(CE_WARN, "fdinit: can't get unique device numbers");
5160Sstevel@tonic-gate if (fdfsmaj == (major_t)-1)
5170Sstevel@tonic-gate fdfsmaj = 0;
5180Sstevel@tonic-gate if (fdrmaj == (major_t)-1)
5190Sstevel@tonic-gate fdrmaj = 0;
5200Sstevel@tonic-gate }
5210Sstevel@tonic-gate mutex_init(&fd_minor_lock, NULL, MUTEX_DEFAULT, NULL);
5220Sstevel@tonic-gate return (0);
5230Sstevel@tonic-gate }
5240Sstevel@tonic-gate
5250Sstevel@tonic-gate /*
5260Sstevel@tonic-gate * FDFS Mount options table
5270Sstevel@tonic-gate */
5280Sstevel@tonic-gate static char *rw_cancel[] = { MNTOPT_RO, NULL };
5290Sstevel@tonic-gate
5300Sstevel@tonic-gate static mntopt_t mntopts[] = {
5310Sstevel@tonic-gate /*
5320Sstevel@tonic-gate * option name cancel option default arg flags
5330Sstevel@tonic-gate */
5340Sstevel@tonic-gate { MNTOPT_RW, rw_cancel, NULL, MO_DEFAULT,
5350Sstevel@tonic-gate (void *)MNTOPT_NOINTR },
5360Sstevel@tonic-gate { MNTOPT_IGNORE, NULL, NULL, 0,
5370Sstevel@tonic-gate (void *)0 },
5380Sstevel@tonic-gate };
5390Sstevel@tonic-gate
5400Sstevel@tonic-gate static mntopts_t fdfs_mntopts = {
5410Sstevel@tonic-gate sizeof (mntopts) / sizeof (mntopt_t),
5420Sstevel@tonic-gate mntopts
5430Sstevel@tonic-gate };
5440Sstevel@tonic-gate
5450Sstevel@tonic-gate static vfsdef_t vfw = {
5460Sstevel@tonic-gate VFSDEF_VERSION,
5470Sstevel@tonic-gate "fd",
5480Sstevel@tonic-gate fdinit,
54912633Sjohn.levon@sun.com VSW_HASPROTO | VSW_ZMOUNT,
5500Sstevel@tonic-gate &fdfs_mntopts
5510Sstevel@tonic-gate };
5520Sstevel@tonic-gate
5530Sstevel@tonic-gate static struct modlfs modlfs = {
5540Sstevel@tonic-gate &mod_fsops,
5550Sstevel@tonic-gate "filesystem for fd",
5560Sstevel@tonic-gate &vfw
5570Sstevel@tonic-gate };
5580Sstevel@tonic-gate
5590Sstevel@tonic-gate static struct modlinkage modlinkage = {
5600Sstevel@tonic-gate MODREV_1,
5610Sstevel@tonic-gate &modlfs,
5620Sstevel@tonic-gate NULL
5630Sstevel@tonic-gate };
5640Sstevel@tonic-gate
5650Sstevel@tonic-gate int
_init(void)5660Sstevel@tonic-gate _init(void)
5670Sstevel@tonic-gate {
5680Sstevel@tonic-gate return (mod_install(&modlinkage));
5690Sstevel@tonic-gate }
5700Sstevel@tonic-gate
5710Sstevel@tonic-gate int
_info(struct modinfo * modinfop)5720Sstevel@tonic-gate _info(struct modinfo *modinfop)
5730Sstevel@tonic-gate {
5740Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop));
5750Sstevel@tonic-gate }
576