/* * Copyright (c) 1991 The Regents of the University of California. * All rights reserved. * * %sccs.include.redist.c% * * @(#)ufs_vfsops.c 7.62 (Berkeley) 08/11/92 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * Flag to permit forcible unmounting. */ int doforce = 1; /* * Make a filesystem operational. * Nothing to do at the moment. */ /* ARGSUSED */ int ufs_start(mp, flags, p) struct mount *mp; int flags; struct proc *p; { return (0); } /* * Check to see if a filesystem is mounted on a block device. */ int ufs_mountedon(vp) register struct vnode *vp; { register struct vnode *vq; if (vp->v_specflags & SI_MOUNTEDON) return (EBUSY); if (vp->v_flag & VALIASED) { for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type) continue; if (vq->v_specflags & SI_MOUNTEDON) return (EBUSY); } } return (0); } /* * Do operations associated with quotas */ int ufs_quotactl(mp, cmds, uid, arg, p) struct mount *mp; int cmds; uid_t uid; caddr_t arg; struct proc *p; { int cmd, type, error; #ifndef QUOTA return (EOPNOTSUPP); #else if (uid == -1) uid = p->p_cred->p_ruid; cmd = cmds >> SUBCMDSHIFT; switch (cmd) { case Q_GETQUOTA: case Q_SYNC: if (uid == p->p_cred->p_ruid) break; /* fall through */ default: if (error = suser(p->p_ucred, &p->p_acflag)) return (error); } type = cmd & SUBCMDMASK; if ((u_int)type >= MAXQUOTAS) return (EINVAL); switch (cmd) { case Q_QUOTAON: return (quotaon(p, mp, type, arg)); case Q_QUOTAOFF: if (vfs_busy(mp)) return (0); error = quotaoff(p, mp, type); vfs_unbusy(mp); return (error); case Q_SETQUOTA: return (setquota(mp, uid, type, arg)); case Q_SETUSE: return (setuse(mp, uid, type, arg)); case Q_GETQUOTA: return (getquota(mp, uid, type, arg)); case Q_SYNC: if (vfs_busy(mp)) return (0); error = qsync(mp); vfs_unbusy(mp); return (error); default: return (EINVAL); } /* NOTREACHED */ #endif } int syncprt = 0; /* * Print out statistics on the current allocation of the buffer pool. * Can be enabled to print out on every ``sync'' by setting "syncprt" * above. */ void ufs_bufstats() { int s, i, j, count; register struct buf *bp, *dp; int counts[MAXBSIZE/CLBYTES+1]; static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" }; for (bp = bfreelist, i = 0; bp < &bfreelist[BQUEUES]; bp++, i++) { count = 0; for (j = 0; j <= MAXBSIZE/CLBYTES; j++) counts[j] = 0; s = splbio(); for (dp = bp->av_forw; dp != bp; dp = dp->av_forw) { counts[dp->b_bufsize/CLBYTES]++; count++; } splx(s); printf("%s: total-%d", bname[i], count); for (j = 0; j <= MAXBSIZE/CLBYTES; j++) if (counts[j] != 0) printf(", %d-%d", j * CLBYTES, counts[j]); printf("\n"); } } /* * Build hash lists of net addresses and hang them off the mount point. * Called by ufs_mount() to set up the lists of export addresses. */ ufs_hang_addrlist(mp, argp) struct mount *mp; struct ufs_args *argp; { register struct netcred *np; register struct radix_node_head *rnh; register int i; struct radix_node *rn; struct ufsmount *ump; struct sockaddr *saddr, *smask = 0; struct domain *dom; int error; if (argp->slen == 0) { if (mp->mnt_flag & MNT_DEFEXPORTED) return (EPERM); np = &ump->um_defexported; np->netc_exflags = argp->exflags; np->netc_anon = argp->anon; np->netc_anon.cr_ref = 1; mp->mnt_flag |= MNT_DEFEXPORTED; return (0); } i = sizeof(struct netcred) + argp->slen + argp->msklen; np = (struct netcred *)malloc(i, M_NETADDR, M_WAITOK); bzero((caddr_t)np, i); saddr = (struct sockaddr *)(np + 1); if (error = copyin(argp->saddr, (caddr_t)saddr, argp->slen)) goto out; if (saddr->sa_len > argp->slen) saddr->sa_len = argp->slen; if (argp->msklen) { smask = (struct sockaddr *)((caddr_t)saddr + argp->slen); if (error = copyin(argp->saddr, (caddr_t)smask, argp->msklen)) goto out; if (smask->sa_len > argp->msklen) smask->sa_len = argp->msklen; } ump = VFSTOUFS(mp); i = saddr->sa_family; if ((rnh = ump->um_rtable[i]) == 0) { /* * Seems silly to initialize every AF when most are not * used, do so on demand here */ for (dom = domains; dom; dom = dom->dom_next) if (dom->dom_family == i && dom->dom_rtattach) { dom->dom_rtattach((void **)&ump->um_rtable[i], dom->dom_rtoffset); break; } if ((rnh = ump->um_rtable[i]) == 0) { error = ENOBUFS; goto out; } } rn = (*rnh->rnh_add)((caddr_t)saddr, (caddr_t)smask, rnh->rnh_treetop, np->netc_rnodes); if (rn == 0 || np != (struct netcred *)rn) { /* already exists */ error = EPERM; goto out; } np->netc_exflags = argp->exflags; np->netc_anon = argp->anon; np->netc_anon.cr_ref = 1; return (0); out: free(np, M_NETADDR); return (error); } /* ARGSUSED */ static int ufs_free_netcred(rn, w) struct radix_node *rn; caddr_t w; { free((caddr_t)rn, M_NETADDR); } /* * Free the net address hash lists that are hanging off the mount points. */ void ufs_free_addrlist(ump) struct ufsmount *ump; { register int i; register struct radix_node_head *rnh; for (i = 0; i <= AF_MAX; i++) if (rnh = ump->um_rtable[i]) { (*rnh->rnh_walk)(rnh->rnh_treetop, ufs_free_netcred, (caddr_t)0); free((caddr_t)rnh, M_RTABLE); ump->um_rtable[i] = 0; } } /* * This is the generic part of fhtovp called after the underlying * filesystem has validated the file handle. * * Verify that a host should have access to a filesystem, and if so * return a vnode for the presented file handle. */ int ufs_check_export(mp, fhp, nam, vpp, exflagsp, credanonp) register struct mount *mp; struct fid *fhp; struct mbuf *nam; struct vnode **vpp; int *exflagsp; struct ucred **credanonp; { register struct ufid *ufhp; register struct inode *ip; register struct netcred *np; register struct ufsmount *ump = VFSTOUFS(mp); register struct radix_node_head *rnh; struct vnode *nvp; struct sockaddr *saddr; int error; /* * Get the export permission structure for this tuple. */ if ((mp->mnt_flag & MNT_EXPORTED) == 0) return (EACCES); if (nam == NULL) { np = NULL; } else { saddr = mtod(nam, struct sockaddr *); rnh = ump->um_rtable[saddr->sa_family]; if (rnh == NULL) { np = NULL; } else { np = (struct netcred *) (*rnh->rnh_match)((caddr_t)saddr, rnh->rnh_treetop); if (np->netc_rnodes->rn_flags & RNF_ROOT) np = NULL; } } if (np == NULL) { /* * If no address match, use the default if it exists. */ if ((mp->mnt_flag & MNT_DEFEXPORTED) == 0) return (EACCES); np = &ump->um_defexported; } if (error = VFS_VGET(mp, ufhp->ufid_ino, &nvp)) { *vpp = NULLVP; return (error); } ip = VTOI(nvp); if (ip->i_mode == 0 || ip->i_gen != ufhp->ufid_gen) { ufs_iput(ip); *vpp = NULLVP; return (ESTALE); } *vpp = nvp; *exflagsp = np->netc_exflags; *credanonp = &np->netc_anon; return (0); }