1139776Simp/*- 21541Srgrimes * Copyright (c) 1992, 1993 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * 51541Srgrimes * This code is derived from software donated to Berkeley by 61541Srgrimes * Jan-Simon Pendry. 71541Srgrimes * 81541Srgrimes * Redistribution and use in source and binary forms, with or without 91541Srgrimes * modification, are permitted provided that the following conditions 101541Srgrimes * are met: 111541Srgrimes * 1. Redistributions of source code must retain the above copyright 121541Srgrimes * notice, this list of conditions and the following disclaimer. 131541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141541Srgrimes * notice, this list of conditions and the following disclaimer in the 151541Srgrimes * documentation and/or other materials provided with the distribution. 161541Srgrimes * 4. Neither the name of the University nor the names of its contributors 171541Srgrimes * may be used to endorse or promote products derived from this software 181541Srgrimes * without specific prior written permission. 191541Srgrimes * 201541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301541Srgrimes * SUCH DAMAGE. 311541Srgrimes * 321541Srgrimes * @(#)fdesc_vnops.c 8.9 (Berkeley) 1/21/94 331541Srgrimes * 3450477Speter * $FreeBSD$ 351541Srgrimes */ 361541Srgrimes 371541Srgrimes/* 381541Srgrimes * /dev/fd Filesystem 391541Srgrimes */ 401541Srgrimes 411541Srgrimes#include <sys/param.h> 421541Srgrimes#include <sys/systm.h> 43224778Srwatson#include <sys/capability.h> 4476166Smarkm#include <sys/conf.h> 4576166Smarkm#include <sys/dirent.h> 4676166Smarkm#include <sys/filedesc.h> 471541Srgrimes#include <sys/kernel.h> /* boottime */ 4876166Smarkm#include <sys/lock.h> 4989316Salfred#include <sys/mutex.h> 501541Srgrimes#include <sys/malloc.h> 5176166Smarkm#include <sys/file.h> /* Must come after sys/malloc.h */ 521541Srgrimes#include <sys/mount.h> 531541Srgrimes#include <sys/namei.h> 5476166Smarkm#include <sys/proc.h> 5576166Smarkm#include <sys/stat.h> 5676166Smarkm#include <sys/vnode.h> 5776166Smarkm 5877031Sru#include <fs/fdescfs/fdesc.h> 591541Srgrimes 602609Sdg#define NFDCACHE 4 6122521Sdyson#define FD_NHASH(ix) \ 6222521Sdyson (&fdhashtbl[(ix) & fdhash]) 6360938Sjakestatic LIST_HEAD(fdhashhead, fdescnode) *fdhashtbl; 6433181Seivindstatic u_long fdhash; 651541Srgrimes 66179288Slulfstruct mtx fdesc_hashmtx; 67179288Slulf 68138270Sphkstatic vop_getattr_t fdesc_getattr; 69138270Sphkstatic vop_lookup_t fdesc_lookup; 70138270Sphkstatic vop_open_t fdesc_open; 71138270Sphkstatic vop_readdir_t fdesc_readdir; 72138270Sphkstatic vop_reclaim_t fdesc_reclaim; 73138270Sphkstatic vop_setattr_t fdesc_setattr; 7412595Sbde 75148919Sobrienstatic struct vop_vector fdesc_vnodeops = { 76148919Sobrien .vop_default = &default_vnodeops, 77138290Sphk 78148919Sobrien .vop_access = VOP_NULL, 79148919Sobrien .vop_getattr = fdesc_getattr, 80148919Sobrien .vop_lookup = fdesc_lookup, 81148919Sobrien .vop_open = fdesc_open, 82148919Sobrien .vop_pathconf = vop_stdpathconf, 83148919Sobrien .vop_readdir = fdesc_readdir, 84148919Sobrien .vop_reclaim = fdesc_reclaim, 85148919Sobrien .vop_setattr = fdesc_setattr, 86148919Sobrien}; 87148919Sobrien 88179288Slulfstatic void fdesc_insmntque_dtr(struct vnode *, void *); 89179288Slulfstatic void fdesc_remove_entry(struct fdescnode *); 90179288Slulf 911541Srgrimes/* 921541Srgrimes * Initialise cache headers 931541Srgrimes */ 941549Srgrimesint 9522521Sdysonfdesc_init(vfsp) 9622521Sdyson struct vfsconf *vfsp; 971541Srgrimes{ 981541Srgrimes 99179288Slulf mtx_init(&fdesc_hashmtx, "fdescfs_hash", NULL, MTX_DEF); 10022521Sdyson fdhashtbl = hashinit(NFDCACHE, M_CACHE, &fdhash); 1011549Srgrimes return (0); 1021541Srgrimes} 1031541Srgrimes 104179288Slulf/* 105179288Slulf * Uninit ready for unload. 106179288Slulf */ 1071541Srgrimesint 108179288Slulffdesc_uninit(vfsp) 109179288Slulf struct vfsconf *vfsp; 110179288Slulf{ 111179288Slulf 112179288Slulf hashdestroy(fdhashtbl, M_CACHE, fdhash); 113179288Slulf mtx_destroy(&fdesc_hashmtx); 114179288Slulf return (0); 115179288Slulf} 116179288Slulf 117179288Slulf/* 118179288Slulf * If allocating vnode fails, call this. 119179288Slulf */ 120179288Slulfstatic void 121179288Slulffdesc_insmntque_dtr(struct vnode *vp, void *arg) 122179288Slulf{ 123179288Slulf 124179288Slulf vgone(vp); 125179288Slulf vput(vp); 126179288Slulf} 127179288Slulf 128179288Slulf/* 129179288Slulf * Remove an entry from the hash if it exists. 130179288Slulf */ 131179288Slulfstatic void 132179288Slulffdesc_remove_entry(struct fdescnode *fd) 133179288Slulf{ 134179288Slulf struct fdhashhead *fc; 135179288Slulf struct fdescnode *fd2; 136179288Slulf 137179288Slulf fc = FD_NHASH(fd->fd_ix); 138179288Slulf mtx_lock(&fdesc_hashmtx); 139179288Slulf LIST_FOREACH(fd2, fc, fd_hash) { 140179288Slulf if (fd == fd2) { 141179288Slulf LIST_REMOVE(fd, fd_hash); 142179288Slulf break; 143179288Slulf } 144179288Slulf } 145179288Slulf mtx_unlock(&fdesc_hashmtx); 146179288Slulf} 147179288Slulf 148179288Slulfint 149191990Sattiliofdesc_allocvp(ftype, fd_fd, ix, mp, vpp) 1501541Srgrimes fdntype ftype; 151179288Slulf unsigned fd_fd; 1521541Srgrimes int ix; 1531541Srgrimes struct mount *mp; 1541541Srgrimes struct vnode **vpp; 1551541Srgrimes{ 156179288Slulf struct fdescmount *fmp; 15722521Sdyson struct fdhashhead *fc; 158179288Slulf struct fdescnode *fd, *fd2; 159179288Slulf struct vnode *vp, *vp2; 160191990Sattilio struct thread *td; 1611541Srgrimes int error = 0; 1621541Srgrimes 163191990Sattilio td = curthread; 16422521Sdyson fc = FD_NHASH(ix); 1651541Srgrimesloop: 166179288Slulf mtx_lock(&fdesc_hashmtx); 167179288Slulf /* 168179288Slulf * If a forced unmount is progressing, we need to drop it. The flags are 169179288Slulf * protected by the hashmtx. 170179288Slulf */ 171179288Slulf fmp = (struct fdescmount *)mp->mnt_data; 172179288Slulf if (fmp == NULL || fmp->flags & FMNT_UNMOUNTF) { 173179288Slulf mtx_unlock(&fdesc_hashmtx); 174179288Slulf return (-1); 175179288Slulf } 176179288Slulf 17771999Sphk LIST_FOREACH(fd, fc, fd_hash) { 1781541Srgrimes if (fd->fd_ix == ix && fd->fd_vnode->v_mount == mp) { 179179288Slulf /* Get reference to vnode in case it's being free'd */ 180179288Slulf vp = fd->fd_vnode; 181179288Slulf VI_LOCK(vp); 182179288Slulf mtx_unlock(&fdesc_hashmtx); 183179288Slulf if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) 1841541Srgrimes goto loop; 185179288Slulf *vpp = vp; 186179288Slulf return (0); 1871541Srgrimes } 1881541Srgrimes } 189179288Slulf mtx_unlock(&fdesc_hashmtx); 1901541Srgrimes 191184205Sdes fd = malloc(sizeof(struct fdescnode), M_TEMP, M_WAITOK); 19216312Sdg 193179288Slulf error = getnewvnode("fdescfs", mp, &fdesc_vnodeops, &vp); 19416312Sdg if (error) { 195184205Sdes free(fd, M_TEMP); 196179288Slulf return (error); 19716312Sdg } 198179288Slulf vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 199179288Slulf vp->v_data = fd; 200179288Slulf fd->fd_vnode = vp; 2011541Srgrimes fd->fd_type = ftype; 202179288Slulf fd->fd_fd = fd_fd; 2031541Srgrimes fd->fd_ix = ix; 204179288Slulf error = insmntque1(vp, mp, fdesc_insmntque_dtr, NULL); 205167497Stegge if (error != 0) { 206167497Stegge *vpp = NULLVP; 207179288Slulf return (error); 208167497Stegge } 2091541Srgrimes 210179288Slulf /* Make sure that someone didn't beat us when inserting the vnode. */ 211179288Slulf mtx_lock(&fdesc_hashmtx); 212179288Slulf /* 213179288Slulf * If a forced unmount is progressing, we need to drop it. The flags are 214179288Slulf * protected by the hashmtx. 215179288Slulf */ 216179288Slulf fmp = (struct fdescmount *)mp->mnt_data; 217179288Slulf if (fmp == NULL || fmp->flags & FMNT_UNMOUNTF) { 218179288Slulf mtx_unlock(&fdesc_hashmtx); 219179288Slulf vgone(vp); 220179288Slulf vput(vp); 221179288Slulf *vpp = NULLVP; 222179288Slulf return (-1); 223179288Slulf } 2241541Srgrimes 225179288Slulf LIST_FOREACH(fd2, fc, fd_hash) { 226179288Slulf if (fd2->fd_ix == ix && fd2->fd_vnode->v_mount == mp) { 227179288Slulf /* Get reference to vnode in case it's being free'd */ 228179288Slulf vp2 = fd2->fd_vnode; 229179288Slulf VI_LOCK(vp2); 230179288Slulf mtx_unlock(&fdesc_hashmtx); 231179288Slulf error = vget(vp2, LK_EXCLUSIVE | LK_INTERLOCK, td); 232179288Slulf /* Someone beat us, dec use count and wait for reclaim */ 233179288Slulf vgone(vp); 234179288Slulf vput(vp); 235179288Slulf /* If we didn't get it, return no vnode. */ 236179288Slulf if (error) 237179288Slulf vp2 = NULLVP; 238179288Slulf *vpp = vp2; 239179288Slulf return (error); 240179288Slulf } 2411541Srgrimes } 2421541Srgrimes 243179288Slulf /* If we came here, we can insert it safely. */ 244179288Slulf LIST_INSERT_HEAD(fc, fd, fd_hash); 245179288Slulf mtx_unlock(&fdesc_hashmtx); 246179288Slulf *vpp = vp; 247179288Slulf return (0); 2481541Srgrimes} 2491541Srgrimes 2501541Srgrimes/* 2511541Srgrimes * vp is the current namei directory 2521541Srgrimes * ndp is the name to locate in that directory... 2531541Srgrimes */ 25412143Sphkstatic int 2551541Srgrimesfdesc_lookup(ap) 2561541Srgrimes struct vop_lookup_args /* { 2571541Srgrimes struct vnode * a_dvp; 2581541Srgrimes struct vnode ** a_vpp; 2591541Srgrimes struct componentname * a_cnp; 2601541Srgrimes } */ *ap; 2611541Srgrimes{ 2621541Srgrimes struct vnode **vpp = ap->a_vpp; 2631541Srgrimes struct vnode *dvp = ap->a_dvp; 26422521Sdyson struct componentname *cnp = ap->a_cnp; 26522521Sdyson char *pname = cnp->cn_nameptr; 26683366Sjulian struct thread *td = cnp->cn_thread; 26789306Salfred struct file *fp; 26860406Schris int nlen = cnp->cn_namelen; 269192012Skib u_int fd, fd1; 2701541Srgrimes int error; 2711541Srgrimes struct vnode *fvp; 2721541Srgrimes 273105998Smux if ((cnp->cn_flags & ISLASTCN) && 274105998Smux (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { 27510534Smpp error = EROFS; 27610534Smpp goto bad; 27710534Smpp } 27810534Smpp 27922521Sdyson if (cnp->cn_namelen == 1 && *pname == '.') { 2801541Srgrimes *vpp = dvp; 281111742Sdes VREF(dvp); 2821541Srgrimes return (0); 2831541Srgrimes } 2841541Srgrimes 28560406Schris if (VTOFDESC(dvp)->fd_type != Froot) { 2861541Srgrimes error = ENOTDIR; 2871541Srgrimes goto bad; 28860406Schris } 2891541Srgrimes 29060406Schris fd = 0; 29162182Salfred /* the only time a leading 0 is acceptable is if it's "0" */ 29262182Salfred if (*pname == '0' && nlen != 1) { 29362182Salfred error = ENOENT; 29462182Salfred goto bad; 29562182Salfred } 29660406Schris while (nlen--) { 29760406Schris if (*pname < '0' || *pname > '9') { 2981541Srgrimes error = ENOENT; 2991541Srgrimes goto bad; 3001541Srgrimes } 301192012Skib fd1 = 10 * fd + *pname++ - '0'; 302192012Skib if (fd1 < fd) { 303192012Skib error = ENOENT; 304192012Skib goto bad; 305192012Skib } 306192012Skib fd = fd1; 30760406Schris } 3081541Srgrimes 309224778Srwatson /* 310224778Srwatson * No rights to check since 'fp' isn't actually used. 311224778Srwatson */ 312224778Srwatson if ((error = fget(td, fd, 0, &fp)) != 0) 31360406Schris goto bad; 3141541Srgrimes 315179288Slulf /* Check if we're looking up ourselves. */ 316179288Slulf if (VTOFDESC(dvp)->fd_ix == FD_DESC + fd) { 317179288Slulf /* 318179288Slulf * In case we're holding the last reference to the file, the dvp 319179288Slulf * will be re-acquired. 320179288Slulf */ 321179288Slulf vhold(dvp); 322179288Slulf VOP_UNLOCK(dvp, 0); 323179288Slulf fdrop(fp, td); 324179288Slulf 325179288Slulf /* Re-aquire the lock afterwards. */ 326179288Slulf vn_lock(dvp, LK_RETRY | LK_EXCLUSIVE); 327179288Slulf vdrop(dvp); 328179288Slulf fvp = dvp; 329179288Slulf } else { 330179288Slulf /* 331179288Slulf * Unlock our root node (dvp) when doing this, since we might 332179288Slulf * deadlock since the vnode might be locked by another thread 333179288Slulf * and the root vnode lock will be obtained afterwards (in case 334179288Slulf * we're looking up the fd of the root vnode), which will be the 335179288Slulf * opposite lock order. Vhold the root vnode first so we don't 336258218Smav * lose it. 337179288Slulf */ 338179288Slulf vhold(dvp); 339179288Slulf VOP_UNLOCK(dvp, 0); 340179288Slulf error = fdesc_allocvp(Fdesc, fd, FD_DESC + fd, dvp->v_mount, 341191990Sattilio &fvp); 342179288Slulf fdrop(fp, td); 343179288Slulf /* 344179288Slulf * The root vnode must be locked last to prevent deadlock condition. 345179288Slulf */ 346179288Slulf vn_lock(dvp, LK_RETRY | LK_EXCLUSIVE); 347179288Slulf vdrop(dvp); 348179288Slulf } 349179288Slulf 35060406Schris if (error) 35160406Schris goto bad; 35260406Schris *vpp = fvp; 35360406Schris return (0); 3541541Srgrimes 35560406Schrisbad: 3561541Srgrimes *vpp = NULL; 3571541Srgrimes return (error); 3581541Srgrimes} 3591541Srgrimes 36012143Sphkstatic int 3611541Srgrimesfdesc_open(ap) 3621541Srgrimes struct vop_open_args /* { 3631541Srgrimes struct vnode *a_vp; 3641541Srgrimes int a_mode; 3651541Srgrimes struct ucred *a_cred; 36683366Sjulian struct thread *a_td; 3671541Srgrimes } */ *ap; 3681541Srgrimes{ 3691541Srgrimes struct vnode *vp = ap->a_vp; 3701541Srgrimes 37160406Schris if (VTOFDESC(vp)->fd_type == Froot) 37260406Schris return (0); 3731541Srgrimes 37460406Schris /* 375218909Sbrucec * XXX Kludge: set td->td_proc->p_dupfd to contain the value of the file 37660406Schris * descriptor being sought for duplication. The error return ensures 37760406Schris * that the vnode for this device will be released by vn_open. Open 37860406Schris * will detect this special error and take the actions in dupfdopen. 37960406Schris * Other callers of vn_open or VOP_OPEN will simply report the 38060406Schris * error. 38160406Schris */ 38283366Sjulian ap->a_td->td_dupfd = VTOFDESC(vp)->fd_fd; /* XXX */ 38360406Schris return (ENODEV); 3841541Srgrimes} 3851541Srgrimes 3861541Srgrimesstatic int 3871541Srgrimesfdesc_getattr(ap) 3881541Srgrimes struct vop_getattr_args /* { 3891541Srgrimes struct vnode *a_vp; 3901541Srgrimes struct vattr *a_vap; 3911541Srgrimes struct ucred *a_cred; 3921541Srgrimes } */ *ap; 3931541Srgrimes{ 3941541Srgrimes struct vnode *vp = ap->a_vp; 3951541Srgrimes struct vattr *vap = ap->a_vap; 3961541Srgrimes 397192013Skib vap->va_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; 398192013Skib vap->va_fileid = VTOFDESC(vp)->fd_ix; 399192013Skib vap->va_uid = 0; 400192013Skib vap->va_gid = 0; 401192013Skib vap->va_blocksize = DEV_BSIZE; 402192013Skib vap->va_atime.tv_sec = boottime.tv_sec; 403192013Skib vap->va_atime.tv_nsec = 0; 404192013Skib vap->va_mtime = vap->va_atime; 405192013Skib vap->va_ctime = vap->va_mtime; 406192013Skib vap->va_gen = 0; 407192013Skib vap->va_flags = 0; 408192013Skib vap->va_bytes = 0; 409192013Skib vap->va_filerev = 0; 410192013Skib 4111541Srgrimes switch (VTOFDESC(vp)->fd_type) { 4121541Srgrimes case Froot: 41360406Schris vap->va_type = VDIR; 41460406Schris vap->va_nlink = 2; 41560406Schris vap->va_size = DEV_BSIZE; 416183214Skib vap->va_rdev = NODEV; 4171541Srgrimes break; 4181541Srgrimes 4191541Srgrimes case Fdesc: 420192013Skib vap->va_type = VCHR; 421192013Skib vap->va_nlink = 1; 422192013Skib vap->va_size = 0; 423192013Skib vap->va_rdev = makedev(0, vap->va_fileid); 4241541Srgrimes break; 4251541Srgrimes 4261541Srgrimes default: 4271541Srgrimes panic("fdesc_getattr"); 4288876Srgrimes break; 4291541Srgrimes } 4301541Srgrimes 431192013Skib vp->v_type = vap->va_type; 432192013Skib return (0); 4331541Srgrimes} 4341541Srgrimes 43512143Sphkstatic int 4361541Srgrimesfdesc_setattr(ap) 4371541Srgrimes struct vop_setattr_args /* { 4381541Srgrimes struct vnode *a_vp; 4391541Srgrimes struct vattr *a_vap; 4401541Srgrimes struct ucred *a_cred; 4411541Srgrimes } */ *ap; 4421541Srgrimes{ 44336873Sdfr struct vattr *vap = ap->a_vap; 44462976Smckusick struct vnode *vp; 44562976Smckusick struct mount *mp; 4461541Srgrimes struct file *fp; 447182371Sattilio struct thread *td = curthread; 4481541Srgrimes unsigned fd; 4491541Srgrimes int error; 4501541Srgrimes 4511541Srgrimes /* 4521541Srgrimes * Can't mess with the root vnode 4531541Srgrimes */ 45460406Schris if (VTOFDESC(ap->a_vp)->fd_type == Froot) 4551541Srgrimes return (EACCES); 4561541Srgrimes 4571541Srgrimes fd = VTOFDESC(ap->a_vp)->fd_fd; 4581541Srgrimes 4591541Srgrimes /* 46061315Schris * Allow setattr where there is an underlying vnode. 4611541Srgrimes */ 462224778Srwatson error = getvnode(td->td_proc->p_fd, fd, CAP_EXTATTR_SET, &fp); 46366894Schris if (error) { 46466894Schris /* 46566894Schris * getvnode() returns EINVAL if the file descriptor is not 46666894Schris * backed by a vnode. Silently drop all changes except 46766894Schris * chflags(2) in this case. 46866894Schris */ 46966894Schris if (error == EINVAL) { 47066894Schris if (vap->va_flags != VNOVAL) 47166894Schris error = EOPNOTSUPP; 47266894Schris else 47366894Schris error = 0; 47466894Schris } 47566894Schris return (error); 4761541Srgrimes } 477116678Sphk vp = fp->f_vnode; 478122893Skan if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) == 0) { 479175202Sattilio vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 480182371Sattilio error = VOP_SETATTR(vp, ap->a_vap, ap->a_cred); 481175294Sattilio VOP_UNLOCK(vp, 0); 482122893Skan vn_finished_write(mp); 48389306Salfred } 484182371Sattilio fdrop(fp, td); 4851541Srgrimes return (error); 4861541Srgrimes} 4871541Srgrimes 4881541Srgrimes#define UIO_MX 16 4891541Srgrimes 49012143Sphkstatic int 4911541Srgrimesfdesc_readdir(ap) 4921541Srgrimes struct vop_readdir_args /* { 4931541Srgrimes struct vnode *a_vp; 4941541Srgrimes struct uio *a_uio; 4951541Srgrimes struct ucred *a_cred; 49622521Sdyson int *a_eofflag; 49722521Sdyson u_long *a_cookies; 49822521Sdyson int a_ncookies; 4991541Srgrimes } */ *ap; 5001541Srgrimes{ 5011541Srgrimes struct uio *uio = ap->a_uio; 5021541Srgrimes struct filedesc *fdp; 50360406Schris struct dirent d; 50460406Schris struct dirent *dp = &d; 50560406Schris int error, i, off, fcnt; 5061541Srgrimes 50760406Schris if (VTOFDESC(ap->a_vp)->fd_type != Froot) 50836963Sbde panic("fdesc_readdir: not dir"); 5091541Srgrimes 510220506Skib if (ap->a_ncookies != NULL) 511220506Skib *ap->a_ncookies = 0; 512220506Skib 51336963Sbde off = (int)uio->uio_offset; 51436963Sbde if (off != uio->uio_offset || off < 0 || (u_int)off % UIO_MX != 0 || 51536963Sbde uio->uio_resid < UIO_MX) 51636963Sbde return (EINVAL); 51736963Sbde i = (u_int)off / UIO_MX; 51883366Sjulian fdp = uio->uio_td->td_proc->p_fd; 51960406Schris error = 0; 5201541Srgrimes 52160406Schris fcnt = i - 2; /* The first two nodes are `.' and `..' */ 5221541Srgrimes 523168355Srwatson FILEDESC_SLOCK(fdp); 52460406Schris while (i < fdp->fd_nfiles + 2 && uio->uio_resid >= UIO_MX) { 525205223Sjkim bzero((caddr_t)dp, UIO_MX); 52660406Schris switch (i) { 52760406Schris case 0: /* `.' */ 52860406Schris case 1: /* `..' */ 52960406Schris dp->d_fileno = i + FD_ROOT; 53060406Schris dp->d_namlen = i + 1; 53160406Schris dp->d_reclen = UIO_MX; 53260406Schris bcopy("..", dp->d_name, dp->d_namlen); 53360406Schris dp->d_name[i + 1] = '\0'; 53460406Schris dp->d_type = DT_DIR; 53560406Schris break; 53660406Schris default: 537205223Sjkim if (fdp->fd_ofiles[fcnt] == NULL) 538205223Sjkim break; 53960406Schris dp->d_namlen = sprintf(dp->d_name, "%d", fcnt); 5401541Srgrimes dp->d_reclen = UIO_MX; 541252885Sjilles dp->d_type = DT_CHR; 54260406Schris dp->d_fileno = i + FD_DESC; 54360406Schris break; 5441541Srgrimes } 545205223Sjkim if (dp->d_namlen != 0) { 546205223Sjkim /* 547205223Sjkim * And ship to userland 548205223Sjkim */ 549205223Sjkim FILEDESC_SUNLOCK(fdp); 550205223Sjkim error = uiomove(dp, UIO_MX, uio); 551205223Sjkim if (error) 552205223Sjkim goto done; 553205223Sjkim FILEDESC_SLOCK(fdp); 554205223Sjkim } 5551541Srgrimes i++; 55660406Schris fcnt++; 5571541Srgrimes } 558168355Srwatson FILEDESC_SUNLOCK(fdp); 5591541Srgrimes 56060406Schrisdone: 5611541Srgrimes uio->uio_offset = i * UIO_MX; 5621541Srgrimes return (error); 5631541Srgrimes} 5641541Srgrimes 56512143Sphkstatic int 5661541Srgrimesfdesc_reclaim(ap) 5671541Srgrimes struct vop_reclaim_args /* { 5681541Srgrimes struct vnode *a_vp; 5691541Srgrimes } */ *ap; 5701541Srgrimes{ 571179288Slulf struct vnode *vp; 572179288Slulf struct fdescnode *fd; 5731541Srgrimes 574179288Slulf vp = ap->a_vp; 575179288Slulf fd = VTOFDESC(vp); 576179288Slulf fdesc_remove_entry(fd); 577184205Sdes free(vp->v_data, M_TEMP); 578179288Slulf vp->v_data = NULL; 5791541Srgrimes return (0); 5801541Srgrimes} 581