17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5aa59c4cbSrsb * Common Development and Distribution License (the "License"). 6aa59c4cbSrsb * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 220fbb751dSJohn Levon * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved. 237c478bd9Sstevel@tonic-gate */ 247c478bd9Sstevel@tonic-gate 257c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 267c478bd9Sstevel@tonic-gate /* All rights reserved. */ 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #include <sys/types.h> 307c478bd9Sstevel@tonic-gate #include <sys/param.h> 317c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 327c478bd9Sstevel@tonic-gate #include <sys/debug.h> 337c478bd9Sstevel@tonic-gate #include <sys/dirent.h> 347c478bd9Sstevel@tonic-gate #include <sys/errno.h> 357c478bd9Sstevel@tonic-gate #include <sys/file.h> 367c478bd9Sstevel@tonic-gate #include <sys/inline.h> 377c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 387c478bd9Sstevel@tonic-gate #include <sys/pathname.h> 397c478bd9Sstevel@tonic-gate #include <sys/resource.h> 407c478bd9Sstevel@tonic-gate #include <sys/statvfs.h> 417c478bd9Sstevel@tonic-gate #include <sys/mount.h> 427c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 437c478bd9Sstevel@tonic-gate #include <sys/systm.h> 447c478bd9Sstevel@tonic-gate #include <sys/uio.h> 457c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 46aa59c4cbSrsb #include <sys/vfs_opreg.h> 477c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 487c478bd9Sstevel@tonic-gate #include <sys/cred.h> 497c478bd9Sstevel@tonic-gate #include <sys/mntent.h> 507c478bd9Sstevel@tonic-gate #include <sys/mount.h> 517c478bd9Sstevel@tonic-gate #include <sys/user.h> 527c478bd9Sstevel@tonic-gate #include <sys/t_lock.h> 537c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 547c478bd9Sstevel@tonic-gate #include <sys/policy.h> 557c478bd9Sstevel@tonic-gate #include <fs/fs_subr.h> 567c478bd9Sstevel@tonic-gate #include <sys/atomic.h> 577c478bd9Sstevel@tonic-gate #include <sys/mkdev.h> 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate #define round(r) (((r)+sizeof (int)-1)&(~(sizeof (int)-1))) 607c478bd9Sstevel@tonic-gate #define fdtoi(n) ((n)+100) 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate #define FDDIRSIZE 14 637c478bd9Sstevel@tonic-gate struct fddirect { 647c478bd9Sstevel@tonic-gate short d_ino; 657c478bd9Sstevel@tonic-gate char d_name[FDDIRSIZE]; 667c478bd9Sstevel@tonic-gate }; 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate #define FDROOTINO 2 697c478bd9Sstevel@tonic-gate #define FDSDSIZE sizeof (struct fddirect) 707c478bd9Sstevel@tonic-gate #define FDNSIZE 10 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate static int fdfstype = 0; 737c478bd9Sstevel@tonic-gate static major_t fdfsmaj; 747c478bd9Sstevel@tonic-gate static minor_t fdfsmin; 757c478bd9Sstevel@tonic-gate static major_t fdrmaj; 767c478bd9Sstevel@tonic-gate static kmutex_t fd_minor_lock; 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate static int fdget(vnode_t *, char *, vnode_t **); 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate /* ARGSUSED */ 817c478bd9Sstevel@tonic-gate static int 82da6c28aaSamw fdopen(vnode_t **vpp, int mode, cred_t *cr, caller_context_t *ct) 837c478bd9Sstevel@tonic-gate { 847c478bd9Sstevel@tonic-gate if ((*vpp)->v_type != VDIR) { 857c478bd9Sstevel@tonic-gate mutex_enter(&(*vpp)->v_lock); 867c478bd9Sstevel@tonic-gate (*vpp)->v_flag |= VDUP; 877c478bd9Sstevel@tonic-gate mutex_exit(&(*vpp)->v_lock); 887c478bd9Sstevel@tonic-gate } 897c478bd9Sstevel@tonic-gate return (0); 907c478bd9Sstevel@tonic-gate } 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate /* ARGSUSED */ 937c478bd9Sstevel@tonic-gate static int 94da6c28aaSamw fdclose(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr, 95da6c28aaSamw caller_context_t *ct) 967c478bd9Sstevel@tonic-gate { 977c478bd9Sstevel@tonic-gate return (0); 987c478bd9Sstevel@tonic-gate } 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1017c478bd9Sstevel@tonic-gate static int 1027c478bd9Sstevel@tonic-gate fdread(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr, caller_context_t *ct) 1037c478bd9Sstevel@tonic-gate { 1047c478bd9Sstevel@tonic-gate static struct fddirect dotbuf[] = { 1057c478bd9Sstevel@tonic-gate { FDROOTINO, "." }, 1067c478bd9Sstevel@tonic-gate { FDROOTINO, ".." } 1077c478bd9Sstevel@tonic-gate }; 1087c478bd9Sstevel@tonic-gate struct fddirect dirbuf; 1097c478bd9Sstevel@tonic-gate int i, n; 1107c478bd9Sstevel@tonic-gate int minfd, maxfd, modoff, error = 0; 1117c478bd9Sstevel@tonic-gate int nentries; 1127c478bd9Sstevel@tonic-gate rctl_qty_t fdno_ctl; 1137c478bd9Sstevel@tonic-gate int endoff; 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate if (vp->v_type != VDIR) 1167c478bd9Sstevel@tonic-gate return (ENOSYS); 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate mutex_enter(&curproc->p_lock); 1197c478bd9Sstevel@tonic-gate fdno_ctl = rctl_enforced_value(rctlproc_legacy[RLIMIT_NOFILE], 1207c478bd9Sstevel@tonic-gate curproc->p_rctls, curproc); 1217c478bd9Sstevel@tonic-gate nentries = MIN(P_FINFO(curproc)->fi_nfiles, (int)fdno_ctl); 1227c478bd9Sstevel@tonic-gate mutex_exit(&curproc->p_lock); 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate endoff = (nentries + 2) * FDSDSIZE; 1257c478bd9Sstevel@tonic-gate 1267c478bd9Sstevel@tonic-gate /* 1277c478bd9Sstevel@tonic-gate * Fake up ".", "..", and the /dev/fd directory entries. 1287c478bd9Sstevel@tonic-gate */ 1297c478bd9Sstevel@tonic-gate if (uiop->uio_loffset < (offset_t)0 || 1307c478bd9Sstevel@tonic-gate uiop->uio_loffset >= (offset_t)endoff || 1317c478bd9Sstevel@tonic-gate uiop->uio_resid <= 0) 1327c478bd9Sstevel@tonic-gate return (0); 1337c478bd9Sstevel@tonic-gate ASSERT(uiop->uio_loffset <= MAXOFF_T); 1347c478bd9Sstevel@tonic-gate if (uiop->uio_offset < 2*FDSDSIZE) { 1357c478bd9Sstevel@tonic-gate error = uiomove((caddr_t)dotbuf + uiop->uio_offset, 1367c478bd9Sstevel@tonic-gate MIN(uiop->uio_resid, 2*FDSDSIZE - uiop->uio_offset), 1377c478bd9Sstevel@tonic-gate UIO_READ, uiop); 1387c478bd9Sstevel@tonic-gate if (uiop->uio_resid <= 0 || error) 1397c478bd9Sstevel@tonic-gate return (error); 1407c478bd9Sstevel@tonic-gate } 1417c478bd9Sstevel@tonic-gate minfd = (uiop->uio_offset - 2*FDSDSIZE)/FDSDSIZE; 1427c478bd9Sstevel@tonic-gate maxfd = (uiop->uio_offset + uiop->uio_resid - 1)/FDSDSIZE; 1437c478bd9Sstevel@tonic-gate modoff = uiop->uio_offset % FDSDSIZE; 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate for (i = 0; i < FDDIRSIZE; i++) 1467c478bd9Sstevel@tonic-gate dirbuf.d_name[i] = '\0'; 1477c478bd9Sstevel@tonic-gate for (i = minfd; i < MIN(maxfd, nentries); i++) { 1487c478bd9Sstevel@tonic-gate n = i; 1497c478bd9Sstevel@tonic-gate dirbuf.d_ino = fdtoi(n); 1507c478bd9Sstevel@tonic-gate numtos((ulong_t)n, dirbuf.d_name); 1517c478bd9Sstevel@tonic-gate error = uiomove((caddr_t)&dirbuf + modoff, 1527c478bd9Sstevel@tonic-gate MIN(uiop->uio_resid, FDSDSIZE - modoff), 1537c478bd9Sstevel@tonic-gate UIO_READ, uiop); 1547c478bd9Sstevel@tonic-gate if (uiop->uio_resid <= 0 || error) 1557c478bd9Sstevel@tonic-gate return (error); 1567c478bd9Sstevel@tonic-gate modoff = 0; 1577c478bd9Sstevel@tonic-gate } 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate return (error); 1607c478bd9Sstevel@tonic-gate } 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1637c478bd9Sstevel@tonic-gate static int 164da6c28aaSamw fdgetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, 165da6c28aaSamw caller_context_t *ct) 1667c478bd9Sstevel@tonic-gate { 1677c478bd9Sstevel@tonic-gate vfs_t *vfsp = vp->v_vfsp; 1687c478bd9Sstevel@tonic-gate timestruc_t now; 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate if (vp->v_type == VDIR) { 1717c478bd9Sstevel@tonic-gate vap->va_nlink = 2; 1727c478bd9Sstevel@tonic-gate vap->va_size = (u_offset_t) 1737c478bd9Sstevel@tonic-gate ((P_FINFO(curproc)->fi_nfiles + 2) * FDSDSIZE); 1747c478bd9Sstevel@tonic-gate vap->va_mode = 0555; 1757c478bd9Sstevel@tonic-gate vap->va_nodeid = (ino64_t)FDROOTINO; 1767c478bd9Sstevel@tonic-gate } else { 1777c478bd9Sstevel@tonic-gate vap->va_nlink = 1; 1787c478bd9Sstevel@tonic-gate vap->va_size = (u_offset_t)0; 1797c478bd9Sstevel@tonic-gate vap->va_mode = 0666; 1807c478bd9Sstevel@tonic-gate vap->va_nodeid = (ino64_t)fdtoi(getminor(vp->v_rdev)); 1817c478bd9Sstevel@tonic-gate } 1827c478bd9Sstevel@tonic-gate vap->va_type = vp->v_type; 1837c478bd9Sstevel@tonic-gate vap->va_rdev = vp->v_rdev; 1847c478bd9Sstevel@tonic-gate vap->va_blksize = vfsp->vfs_bsize; 1857c478bd9Sstevel@tonic-gate vap->va_nblocks = (fsblkcnt64_t)0; 1867c478bd9Sstevel@tonic-gate gethrestime(&now); 1877c478bd9Sstevel@tonic-gate vap->va_atime = vap->va_mtime = vap->va_ctime = now; 1887c478bd9Sstevel@tonic-gate vap->va_uid = 0; 1897c478bd9Sstevel@tonic-gate vap->va_gid = 0; 1907c478bd9Sstevel@tonic-gate vap->va_fsid = vfsp->vfs_dev; 1917c478bd9Sstevel@tonic-gate vap->va_seq = 0; 1927c478bd9Sstevel@tonic-gate return (0); 1937c478bd9Sstevel@tonic-gate } 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1967c478bd9Sstevel@tonic-gate static int 197da6c28aaSamw fdaccess(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct) 1987c478bd9Sstevel@tonic-gate { 1997c478bd9Sstevel@tonic-gate return (0); 2007c478bd9Sstevel@tonic-gate } 2017c478bd9Sstevel@tonic-gate 2027c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2037c478bd9Sstevel@tonic-gate static int 2047c478bd9Sstevel@tonic-gate fdlookup(vnode_t *dp, char *comp, vnode_t **vpp, pathname_t *pnp, 205da6c28aaSamw int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct, 206da6c28aaSamw int *direntflags, pathname_t *realpnp) 2077c478bd9Sstevel@tonic-gate { 2087c478bd9Sstevel@tonic-gate if (comp[0] == 0 || strcmp(comp, ".") == 0 || strcmp(comp, "..") == 0) { 2097c478bd9Sstevel@tonic-gate VN_HOLD(dp); 2107c478bd9Sstevel@tonic-gate *vpp = dp; 2117c478bd9Sstevel@tonic-gate return (0); 2127c478bd9Sstevel@tonic-gate } 2137c478bd9Sstevel@tonic-gate return (fdget(dp, comp, vpp)); 2147c478bd9Sstevel@tonic-gate } 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2177c478bd9Sstevel@tonic-gate static int 2187c478bd9Sstevel@tonic-gate fdcreate(vnode_t *dvp, char *comp, vattr_t *vap, enum vcexcl excl, 219da6c28aaSamw int mode, vnode_t **vpp, cred_t *cr, int flag, caller_context_t *ct, 220da6c28aaSamw vsecattr_t *vsecp) 2217c478bd9Sstevel@tonic-gate { 2227c478bd9Sstevel@tonic-gate return (fdget(dvp, comp, vpp)); 2237c478bd9Sstevel@tonic-gate } 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2267c478bd9Sstevel@tonic-gate static int 227da6c28aaSamw fdreaddir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp, caller_context_t *ct, 228da6c28aaSamw int flags) 2297c478bd9Sstevel@tonic-gate { 2307c478bd9Sstevel@tonic-gate /* bp holds one dirent structure */ 2317c478bd9Sstevel@tonic-gate u_offset_t bp[DIRENT64_RECLEN(FDNSIZE) / sizeof (u_offset_t)]; 2327c478bd9Sstevel@tonic-gate struct dirent64 *dirent = (struct dirent64 *)bp; 2337c478bd9Sstevel@tonic-gate int reclen, nentries; 2347c478bd9Sstevel@tonic-gate rctl_qty_t fdno_ctl; 2357c478bd9Sstevel@tonic-gate int n; 2367c478bd9Sstevel@tonic-gate int oresid; 2377c478bd9Sstevel@tonic-gate off_t off; 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate if (uiop->uio_offset < 0 || uiop->uio_resid <= 0 || 2407c478bd9Sstevel@tonic-gate (uiop->uio_offset % FDSDSIZE) != 0) 2417c478bd9Sstevel@tonic-gate return (ENOENT); 2427c478bd9Sstevel@tonic-gate 2437c478bd9Sstevel@tonic-gate ASSERT(uiop->uio_loffset <= MAXOFF_T); 2447c478bd9Sstevel@tonic-gate oresid = uiop->uio_resid; 2457c478bd9Sstevel@tonic-gate bzero(bp, sizeof (bp)); 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate mutex_enter(&curproc->p_lock); 2487c478bd9Sstevel@tonic-gate fdno_ctl = rctl_enforced_value(rctlproc_legacy[RLIMIT_NOFILE], 2497c478bd9Sstevel@tonic-gate curproc->p_rctls, curproc); 2507c478bd9Sstevel@tonic-gate nentries = MIN(P_FINFO(curproc)->fi_nfiles, (int)fdno_ctl); 2517c478bd9Sstevel@tonic-gate mutex_exit(&curproc->p_lock); 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate while (uiop->uio_resid > 0) { 2547c478bd9Sstevel@tonic-gate if ((off = uiop->uio_offset) == 0) { /* "." */ 2557c478bd9Sstevel@tonic-gate dirent->d_ino = (ino64_t)FDROOTINO; 2567c478bd9Sstevel@tonic-gate dirent->d_name[0] = '.'; 2577c478bd9Sstevel@tonic-gate dirent->d_name[1] = '\0'; 2587c478bd9Sstevel@tonic-gate reclen = DIRENT64_RECLEN(1); 2597c478bd9Sstevel@tonic-gate } else if (off == FDSDSIZE) { /* ".." */ 2607c478bd9Sstevel@tonic-gate dirent->d_ino = (ino64_t)FDROOTINO; 2617c478bd9Sstevel@tonic-gate dirent->d_name[0] = '.'; 2627c478bd9Sstevel@tonic-gate dirent->d_name[1] = '.'; 2637c478bd9Sstevel@tonic-gate dirent->d_name[2] = '\0'; 2647c478bd9Sstevel@tonic-gate reclen = DIRENT64_RECLEN(2); 2657c478bd9Sstevel@tonic-gate } else { 2667c478bd9Sstevel@tonic-gate /* 2677c478bd9Sstevel@tonic-gate * Return entries corresponding to the allowable 2687c478bd9Sstevel@tonic-gate * number of file descriptors for this process. 2697c478bd9Sstevel@tonic-gate */ 2707c478bd9Sstevel@tonic-gate if ((n = (off-2*FDSDSIZE)/FDSDSIZE) >= nentries) 2717c478bd9Sstevel@tonic-gate break; 2727c478bd9Sstevel@tonic-gate dirent->d_ino = (ino64_t)fdtoi(n); 2737c478bd9Sstevel@tonic-gate numtos((ulong_t)n, dirent->d_name); 2747c478bd9Sstevel@tonic-gate reclen = DIRENT64_RECLEN(strlen(dirent->d_name)); 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate dirent->d_off = (offset_t)(uiop->uio_offset + FDSDSIZE); 2777c478bd9Sstevel@tonic-gate dirent->d_reclen = (ushort_t)reclen; 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate if (reclen > uiop->uio_resid) { 2807c478bd9Sstevel@tonic-gate /* 2817c478bd9Sstevel@tonic-gate * Error if no entries have been returned yet. 2827c478bd9Sstevel@tonic-gate */ 2837c478bd9Sstevel@tonic-gate if (uiop->uio_resid == oresid) 2847c478bd9Sstevel@tonic-gate return (EINVAL); 2857c478bd9Sstevel@tonic-gate break; 2867c478bd9Sstevel@tonic-gate } 2877c478bd9Sstevel@tonic-gate /* 2887c478bd9Sstevel@tonic-gate * uiomove() updates both resid and offset by the same 2897c478bd9Sstevel@tonic-gate * amount. But we want offset to change in increments 2907c478bd9Sstevel@tonic-gate * of FDSDSIZE, which is different from the number of bytes 2917c478bd9Sstevel@tonic-gate * being returned to the user. So we set uio_offset 2927c478bd9Sstevel@tonic-gate * separately, ignoring what uiomove() does. 2937c478bd9Sstevel@tonic-gate */ 2947c478bd9Sstevel@tonic-gate if (uiomove((caddr_t)dirent, reclen, UIO_READ, uiop)) 2957c478bd9Sstevel@tonic-gate return (EFAULT); 2967c478bd9Sstevel@tonic-gate uiop->uio_offset = off + FDSDSIZE; 2977c478bd9Sstevel@tonic-gate } 2987c478bd9Sstevel@tonic-gate if (eofp) 2997c478bd9Sstevel@tonic-gate *eofp = ((uiop->uio_offset-2*FDSDSIZE)/FDSDSIZE >= nentries); 3007c478bd9Sstevel@tonic-gate return (0); 3017c478bd9Sstevel@tonic-gate } 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3047c478bd9Sstevel@tonic-gate static void 305da6c28aaSamw fdinactive(vnode_t *vp, cred_t *cr, caller_context_t *ct) 3067c478bd9Sstevel@tonic-gate { 3077c478bd9Sstevel@tonic-gate mutex_enter(&vp->v_lock); 3087c478bd9Sstevel@tonic-gate ASSERT(vp->v_count >= 1); 3097c478bd9Sstevel@tonic-gate if (--vp->v_count != 0) { 3107c478bd9Sstevel@tonic-gate mutex_exit(&vp->v_lock); 3117c478bd9Sstevel@tonic-gate return; 3127c478bd9Sstevel@tonic-gate } 3137c478bd9Sstevel@tonic-gate mutex_exit(&vp->v_lock); 3147c478bd9Sstevel@tonic-gate vn_invalid(vp); 3157c478bd9Sstevel@tonic-gate vn_free(vp); 3167c478bd9Sstevel@tonic-gate } 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate static struct vnodeops *fd_vnodeops; 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate static const fs_operation_def_t fd_vnodeops_template[] = { 321aa59c4cbSrsb VOPNAME_OPEN, { .vop_open = fdopen }, 322aa59c4cbSrsb VOPNAME_CLOSE, { .vop_close = fdclose }, 323aa59c4cbSrsb VOPNAME_READ, { .vop_read = fdread }, 324aa59c4cbSrsb VOPNAME_GETATTR, { .vop_getattr = fdgetattr }, 325aa59c4cbSrsb VOPNAME_ACCESS, { .vop_access = fdaccess }, 326aa59c4cbSrsb VOPNAME_LOOKUP, { .vop_lookup = fdlookup }, 327aa59c4cbSrsb VOPNAME_CREATE, { .vop_create = fdcreate }, 328aa59c4cbSrsb VOPNAME_READDIR, { .vop_readdir = fdreaddir }, 329aa59c4cbSrsb VOPNAME_INACTIVE, { .vop_inactive = fdinactive }, 330aa59c4cbSrsb VOPNAME_FRLOCK, { .error = fs_error }, 331aa59c4cbSrsb VOPNAME_POLL, { .error = fs_error }, 332aa59c4cbSrsb VOPNAME_DISPOSE, { .error = fs_error }, 3337c478bd9Sstevel@tonic-gate NULL, NULL 3347c478bd9Sstevel@tonic-gate }; 3357c478bd9Sstevel@tonic-gate 3367c478bd9Sstevel@tonic-gate static int 3377c478bd9Sstevel@tonic-gate fdget(struct vnode *dvp, char *comp, struct vnode **vpp) 3387c478bd9Sstevel@tonic-gate { 3397c478bd9Sstevel@tonic-gate int n = 0; 3407c478bd9Sstevel@tonic-gate struct vnode *vp; 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate while (*comp) { 3437c478bd9Sstevel@tonic-gate if (*comp < '0' || *comp > '9') 3447c478bd9Sstevel@tonic-gate return (ENOENT); 3457c478bd9Sstevel@tonic-gate n = 10 * n + *comp++ - '0'; 3467c478bd9Sstevel@tonic-gate } 3477c478bd9Sstevel@tonic-gate vp = vn_alloc(KM_SLEEP); 3487c478bd9Sstevel@tonic-gate vp->v_type = VCHR; 3497c478bd9Sstevel@tonic-gate vp->v_vfsp = dvp->v_vfsp; 3507c478bd9Sstevel@tonic-gate vn_setops(vp, fd_vnodeops); 3517c478bd9Sstevel@tonic-gate vp->v_data = NULL; 3527c478bd9Sstevel@tonic-gate vp->v_flag = VNOMAP; 3537c478bd9Sstevel@tonic-gate vp->v_rdev = makedevice(fdrmaj, n); 3547c478bd9Sstevel@tonic-gate vn_exists(vp); 3557c478bd9Sstevel@tonic-gate *vpp = vp; 3567c478bd9Sstevel@tonic-gate return (0); 3577c478bd9Sstevel@tonic-gate } 3587c478bd9Sstevel@tonic-gate 3597c478bd9Sstevel@tonic-gate /* 3607c478bd9Sstevel@tonic-gate * fdfs is mounted on /dev/fd, however, there are two interesting 3617c478bd9Sstevel@tonic-gate * possibilities - two threads racing to do the same mount (protected 3627c478bd9Sstevel@tonic-gate * by vfs locking), and two threads mounting fdfs in different places. 3637c478bd9Sstevel@tonic-gate */ 3647c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3657c478bd9Sstevel@tonic-gate static int 3667c478bd9Sstevel@tonic-gate fdmount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) 3677c478bd9Sstevel@tonic-gate { 3687c478bd9Sstevel@tonic-gate struct vnode *vp; 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate if (secpolicy_fs_mount(cr, mvp, vfsp) != 0) 3717c478bd9Sstevel@tonic-gate return (EPERM); 3727c478bd9Sstevel@tonic-gate if (mvp->v_type != VDIR) 3737c478bd9Sstevel@tonic-gate return (ENOTDIR); 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate mutex_enter(&mvp->v_lock); 3767c478bd9Sstevel@tonic-gate if ((uap->flags & MS_OVERLAY) == 0 && 3777c478bd9Sstevel@tonic-gate (mvp->v_count > 1 || (mvp->v_flag & VROOT))) { 3787c478bd9Sstevel@tonic-gate mutex_exit(&mvp->v_lock); 3797c478bd9Sstevel@tonic-gate return (EBUSY); 3807c478bd9Sstevel@tonic-gate } 3817c478bd9Sstevel@tonic-gate mutex_exit(&mvp->v_lock); 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate /* 3847c478bd9Sstevel@tonic-gate * Having the resource be anything but "fd" doesn't make sense 3857c478bd9Sstevel@tonic-gate */ 386*d7de0ceaSRobert Harris vfs_setresource(vfsp, "fd", 0); 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate vp = vn_alloc(KM_SLEEP); 3897c478bd9Sstevel@tonic-gate vp->v_vfsp = vfsp; 3907c478bd9Sstevel@tonic-gate vn_setops(vp, fd_vnodeops); 3917c478bd9Sstevel@tonic-gate vp->v_type = VDIR; 3927c478bd9Sstevel@tonic-gate vp->v_data = NULL; 3937c478bd9Sstevel@tonic-gate vp->v_flag |= VROOT; 3947c478bd9Sstevel@tonic-gate vfsp->vfs_fstype = fdfstype; 3957c478bd9Sstevel@tonic-gate vfsp->vfs_data = (char *)vp; 3967c478bd9Sstevel@tonic-gate mutex_enter(&fd_minor_lock); 3977c478bd9Sstevel@tonic-gate do { 3987c478bd9Sstevel@tonic-gate fdfsmin = (fdfsmin + 1) & L_MAXMIN32; 3997c478bd9Sstevel@tonic-gate vfsp->vfs_dev = makedevice(fdfsmaj, fdfsmin); 4007c478bd9Sstevel@tonic-gate } while (vfs_devismounted(vfsp->vfs_dev)); 4017c478bd9Sstevel@tonic-gate mutex_exit(&fd_minor_lock); 4027c478bd9Sstevel@tonic-gate vfs_make_fsid(&vfsp->vfs_fsid, vfsp->vfs_dev, fdfstype); 4037c478bd9Sstevel@tonic-gate vfsp->vfs_bsize = 1024; 4047c478bd9Sstevel@tonic-gate return (0); 4057c478bd9Sstevel@tonic-gate } 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate /* ARGSUSED */ 4087c478bd9Sstevel@tonic-gate static int 4097c478bd9Sstevel@tonic-gate fdunmount(vfs_t *vfsp, int flag, cred_t *cr) 4107c478bd9Sstevel@tonic-gate { 4117c478bd9Sstevel@tonic-gate vnode_t *rvp; 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate if (secpolicy_fs_unmount(cr, vfsp) != 0) 4147c478bd9Sstevel@tonic-gate return (EPERM); 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate /* 4177c478bd9Sstevel@tonic-gate * forced unmount is not supported by this file system 4187c478bd9Sstevel@tonic-gate * and thus, ENOTSUP, is being returned. 4197c478bd9Sstevel@tonic-gate */ 4207c478bd9Sstevel@tonic-gate if (flag & MS_FORCE) 4217c478bd9Sstevel@tonic-gate return (ENOTSUP); 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate rvp = (vnode_t *)vfsp->vfs_data; 4247c478bd9Sstevel@tonic-gate if (rvp->v_count > 1) 4257c478bd9Sstevel@tonic-gate return (EBUSY); 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate VN_RELE(rvp); 4287c478bd9Sstevel@tonic-gate return (0); 4297c478bd9Sstevel@tonic-gate } 4307c478bd9Sstevel@tonic-gate 4317c478bd9Sstevel@tonic-gate /* ARGSUSED */ 4327c478bd9Sstevel@tonic-gate static int 4337c478bd9Sstevel@tonic-gate fdroot(vfs_t *vfsp, vnode_t **vpp) 4347c478bd9Sstevel@tonic-gate { 4357c478bd9Sstevel@tonic-gate vnode_t *vp = (vnode_t *)vfsp->vfs_data; 4367c478bd9Sstevel@tonic-gate 4377c478bd9Sstevel@tonic-gate VN_HOLD(vp); 4387c478bd9Sstevel@tonic-gate *vpp = vp; 4397c478bd9Sstevel@tonic-gate return (0); 4407c478bd9Sstevel@tonic-gate } 4417c478bd9Sstevel@tonic-gate 4427c478bd9Sstevel@tonic-gate /* 4437c478bd9Sstevel@tonic-gate * No locking required because I held the root vnode before calling this 4447c478bd9Sstevel@tonic-gate * function so the vfs won't disappear on me. To be more explicit: 4457c478bd9Sstevel@tonic-gate * fdvrootp->v_count will be greater than 1 so fdunmount will just return. 4467c478bd9Sstevel@tonic-gate */ 4477c478bd9Sstevel@tonic-gate static int 4487c478bd9Sstevel@tonic-gate fdstatvfs(struct vfs *vfsp, struct statvfs64 *sp) 4497c478bd9Sstevel@tonic-gate { 4507c478bd9Sstevel@tonic-gate dev32_t d32; 4517c478bd9Sstevel@tonic-gate rctl_qty_t fdno_ctl; 4527c478bd9Sstevel@tonic-gate 4537c478bd9Sstevel@tonic-gate mutex_enter(&curproc->p_lock); 4547c478bd9Sstevel@tonic-gate fdno_ctl = rctl_enforced_value(rctlproc_legacy[RLIMIT_NOFILE], 4557c478bd9Sstevel@tonic-gate curproc->p_rctls, curproc); 4567c478bd9Sstevel@tonic-gate mutex_exit(&curproc->p_lock); 4577c478bd9Sstevel@tonic-gate 4587c478bd9Sstevel@tonic-gate bzero(sp, sizeof (*sp)); 4597c478bd9Sstevel@tonic-gate sp->f_bsize = 1024; 4607c478bd9Sstevel@tonic-gate sp->f_frsize = 1024; 4617c478bd9Sstevel@tonic-gate sp->f_blocks = (fsblkcnt64_t)0; 4627c478bd9Sstevel@tonic-gate sp->f_bfree = (fsblkcnt64_t)0; 4637c478bd9Sstevel@tonic-gate sp->f_bavail = (fsblkcnt64_t)0; 4647c478bd9Sstevel@tonic-gate sp->f_files = (fsfilcnt64_t) 4657c478bd9Sstevel@tonic-gate (MIN(P_FINFO(curproc)->fi_nfiles, fdno_ctl + 2)); 4667c478bd9Sstevel@tonic-gate sp->f_ffree = (fsfilcnt64_t)0; 4677c478bd9Sstevel@tonic-gate sp->f_favail = (fsfilcnt64_t)0; 4687c478bd9Sstevel@tonic-gate (void) cmpldev(&d32, vfsp->vfs_dev); 4697c478bd9Sstevel@tonic-gate sp->f_fsid = d32; 4707c478bd9Sstevel@tonic-gate (void) strcpy(sp->f_basetype, vfssw[fdfstype].vsw_name); 4717c478bd9Sstevel@tonic-gate sp->f_flag = vf_to_stf(vfsp->vfs_flag); 4727c478bd9Sstevel@tonic-gate sp->f_namemax = FDNSIZE; 4737c478bd9Sstevel@tonic-gate (void) strcpy(sp->f_fstr, "/dev/fd"); 4747c478bd9Sstevel@tonic-gate (void) strcpy(&sp->f_fstr[8], "/dev/fd"); 4757c478bd9Sstevel@tonic-gate return (0); 4767c478bd9Sstevel@tonic-gate } 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate int 4797c478bd9Sstevel@tonic-gate fdinit(int fstype, char *name) 4807c478bd9Sstevel@tonic-gate { 4817c478bd9Sstevel@tonic-gate static const fs_operation_def_t fd_vfsops_template[] = { 482aa59c4cbSrsb VFSNAME_MOUNT, { .vfs_mount = fdmount }, 483aa59c4cbSrsb VFSNAME_UNMOUNT, { .vfs_unmount = fdunmount }, 484aa59c4cbSrsb VFSNAME_ROOT, { .vfs_root = fdroot }, 485aa59c4cbSrsb VFSNAME_STATVFS, { .vfs_statvfs = fdstatvfs }, 4867c478bd9Sstevel@tonic-gate NULL, NULL 4877c478bd9Sstevel@tonic-gate }; 4887c478bd9Sstevel@tonic-gate int error; 4897c478bd9Sstevel@tonic-gate 4907c478bd9Sstevel@tonic-gate fdfstype = fstype; 4917c478bd9Sstevel@tonic-gate ASSERT(fdfstype != 0); 4927c478bd9Sstevel@tonic-gate 4937c478bd9Sstevel@tonic-gate /* 4947c478bd9Sstevel@tonic-gate * Associate VFS ops vector with this fstype. 4957c478bd9Sstevel@tonic-gate */ 4967c478bd9Sstevel@tonic-gate error = vfs_setfsops(fstype, fd_vfsops_template, NULL); 4977c478bd9Sstevel@tonic-gate if (error != 0) { 4987c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "fdinit: bad vnode ops template"); 4997c478bd9Sstevel@tonic-gate return (error); 5007c478bd9Sstevel@tonic-gate } 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate error = vn_make_ops(name, fd_vnodeops_template, &fd_vnodeops); 5037c478bd9Sstevel@tonic-gate if (error != 0) { 5047c478bd9Sstevel@tonic-gate (void) vfs_freevfsops_by_type(fstype); 5057c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "fdinit: bad vnode ops template"); 5067c478bd9Sstevel@tonic-gate return (error); 5077c478bd9Sstevel@tonic-gate } 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate /* 5107c478bd9Sstevel@tonic-gate * Assign unique "device" numbers (reported by stat(2)). 5117c478bd9Sstevel@tonic-gate */ 5127c478bd9Sstevel@tonic-gate fdfsmaj = getudev(); 5137c478bd9Sstevel@tonic-gate fdrmaj = getudev(); 5147c478bd9Sstevel@tonic-gate if (fdfsmaj == (major_t)-1 || fdrmaj == (major_t)-1) { 5157c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "fdinit: can't get unique device numbers"); 5167c478bd9Sstevel@tonic-gate if (fdfsmaj == (major_t)-1) 5177c478bd9Sstevel@tonic-gate fdfsmaj = 0; 5187c478bd9Sstevel@tonic-gate if (fdrmaj == (major_t)-1) 5197c478bd9Sstevel@tonic-gate fdrmaj = 0; 5207c478bd9Sstevel@tonic-gate } 5217c478bd9Sstevel@tonic-gate mutex_init(&fd_minor_lock, NULL, MUTEX_DEFAULT, NULL); 5227c478bd9Sstevel@tonic-gate return (0); 5237c478bd9Sstevel@tonic-gate } 5247c478bd9Sstevel@tonic-gate 5257c478bd9Sstevel@tonic-gate /* 5267c478bd9Sstevel@tonic-gate * FDFS Mount options table 5277c478bd9Sstevel@tonic-gate */ 5287c478bd9Sstevel@tonic-gate static char *rw_cancel[] = { MNTOPT_RO, NULL }; 5297c478bd9Sstevel@tonic-gate 5307c478bd9Sstevel@tonic-gate static mntopt_t mntopts[] = { 5317c478bd9Sstevel@tonic-gate /* 5327c478bd9Sstevel@tonic-gate * option name cancel option default arg flags 5337c478bd9Sstevel@tonic-gate */ 5347c478bd9Sstevel@tonic-gate { MNTOPT_RW, rw_cancel, NULL, MO_DEFAULT, 5357c478bd9Sstevel@tonic-gate (void *)MNTOPT_NOINTR }, 5367c478bd9Sstevel@tonic-gate { MNTOPT_IGNORE, NULL, NULL, 0, 5377c478bd9Sstevel@tonic-gate (void *)0 }, 5387c478bd9Sstevel@tonic-gate }; 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate static mntopts_t fdfs_mntopts = { 5417c478bd9Sstevel@tonic-gate sizeof (mntopts) / sizeof (mntopt_t), 5427c478bd9Sstevel@tonic-gate mntopts 5437c478bd9Sstevel@tonic-gate }; 5447c478bd9Sstevel@tonic-gate 5457c478bd9Sstevel@tonic-gate static vfsdef_t vfw = { 5467c478bd9Sstevel@tonic-gate VFSDEF_VERSION, 5477c478bd9Sstevel@tonic-gate "fd", 5487c478bd9Sstevel@tonic-gate fdinit, 5490fbb751dSJohn Levon VSW_HASPROTO | VSW_ZMOUNT, 5507c478bd9Sstevel@tonic-gate &fdfs_mntopts 5517c478bd9Sstevel@tonic-gate }; 5527c478bd9Sstevel@tonic-gate 5537c478bd9Sstevel@tonic-gate static struct modlfs modlfs = { 5547c478bd9Sstevel@tonic-gate &mod_fsops, 5557c478bd9Sstevel@tonic-gate "filesystem for fd", 5567c478bd9Sstevel@tonic-gate &vfw 5577c478bd9Sstevel@tonic-gate }; 5587c478bd9Sstevel@tonic-gate 5597c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 5607c478bd9Sstevel@tonic-gate MODREV_1, 5617c478bd9Sstevel@tonic-gate &modlfs, 5627c478bd9Sstevel@tonic-gate NULL 5637c478bd9Sstevel@tonic-gate }; 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate int 5667c478bd9Sstevel@tonic-gate _init(void) 5677c478bd9Sstevel@tonic-gate { 5687c478bd9Sstevel@tonic-gate return (mod_install(&modlinkage)); 5697c478bd9Sstevel@tonic-gate } 5707c478bd9Sstevel@tonic-gate 5717c478bd9Sstevel@tonic-gate int 5727c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 5737c478bd9Sstevel@tonic-gate { 5747c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 5757c478bd9Sstevel@tonic-gate } 576