collect lock holder when locking inodes
[unix-history] / usr / src / sys / ufs / ffs / ufs_vfsops.c
index 4fe3fb1..f36295a 100644 (file)
-/*     ufs_vfsops.c    6.9     84/09/28        */
+/*
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)ufs_vfsops.c        7.65 (Berkeley) %G%
+ */
+
+#include <sys/param.h>
+#include <net/radix.h>
+#include <sys/domain.h>
+#include <sys/socket.h>
+#include <sys/mbuf.h>
+#include <sys/mount.h>
+#include <sys/proc.h>
+#include <sys/buf.h>
+#include <sys/vnode.h>
+#include <sys/malloc.h>
+
+#include <miscfs/specfs/specdev.h>
+#include "ioctl.h"
+#include "disklabel.h"
+#include "stat.h"
+
+#include <ufs/ufs/quota.h>
+#include <ufs/ufs/inode.h>
+#include <ufs/ufs/ufsmount.h>
+#include <ufs/ufs/ufs_extern.h>
 
 
-#include "param.h"
-#include "systm.h"
-#include "dir.h"
-#include "user.h"
-#include "inode.h"
-#include "proc.h"
-#include "fs.h"
-#include "buf.h"
-#include "mount.h"
-#include "file.h"
-#include "conf.h"
+/*
+ * Flag to permit forcible unmounting.
+ */
+int doforce = 1;
 
 
-smount()
+/*
+ * 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;
 {
 {
-       register struct a {
-               char    *fspec;
-               char    *freg;
-               int     ronly;
-       } *uap = (struct a *)u.u_ap;
-       dev_t dev;
-       register struct inode *ip;
-       register struct fs *fs;
-       register char *cp;
-       register struct nameidata *ndp = &u.u_nd;
-       u_int len;
 
 
-       u.u_error = getmdev(&dev, uap->fspec);
-       if (u.u_error)
-               return;
-       ndp->ni_nameiop = LOOKUP | NOCACHE | FOLLOW;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = (caddr_t)uap->freg;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       if (ip->i_count!=1 || (ip->i_mode&IFMT) != IFDIR) {
-               iput(ip);
-               u.u_error = EBUSY;
-               return;
+       return (0);
+}
+
+/*
+       error = closei(dev, IFBLK, fs->fs_ronly? FREAD : FREAD|FWRITE);
+       irele(ip);
+       return (error);
+}
+
+/*
+ * 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);
        }
        }
-       fs = mountfs(dev, uap->ronly, ip);
-       if (fs == 0)
-               return;
-       (void) copyinstr(uap->freg, fs->fs_fsmnt, sizeof(fs->fs_fsmnt)-1, &len);
-       bzero(fs->fs_fsmnt + len, sizeof (fs->fs_fsmnt) - len);
+       /* NOTREACHED */
+#endif
 }
 
 }
 
-/* this routine has races if running twice */
-struct fs *
-mountfs(dev, ronly, ip)
-       dev_t dev;
-       int ronly;
-       struct inode *ip;
+/*
+ * 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 mount *mp = 0;
-       struct buf *tp = 0;
-       register struct buf *bp = 0;
-       register struct fs *fs;
-       int blks;
-       caddr_t space;
-       int i, size;
-       register error;
+       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;
 
 
-       error =
-           (*bdevsw[major(dev)].d_open)(dev, ronly ? FREAD : FREAD|FWRITE);
-       if (error)
-               goto out;
-       tp = bread(dev, SBLOCK, SBSIZE);
-       if (tp->b_flags & B_ERROR)
-               goto out;
-       for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
-               if (mp->m_bufp != 0 && dev == mp->m_dev) {
-                       mp = 0;
-                       error = EBUSY;
-                       goto out;
-               }
-       for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
-               if (mp->m_bufp == 0)
-                       goto found;
-       mp = 0;
-       error = EMFILE;         /* needs translation */
-       goto out;
-found:
-       mp->m_bufp = tp;        /* just to reserve this slot */
-       mp->m_dev = NODEV;
-       fs = tp->b_un.b_fs;
-       if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE
-           || fs->fs_bsize < sizeof(struct fs)) {
-               error = EINVAL;         /* also needs translation */
-               goto out;
+       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);
        }
        }
-       bp = geteblk((int)fs->fs_sbsize);
-       mp->m_bufp = bp;
-       bcopy((caddr_t)tp->b_un.b_addr, (caddr_t)bp->b_un.b_addr,
-          (u_int)fs->fs_sbsize);
-       brelse(tp);
-       tp = 0;
-       fs = bp->b_un.b_fs;
-       fs->fs_ronly = (ronly != 0);
-       if (ronly == 0)
-               fs->fs_fmod = 1;
-       blks = howmany(fs->fs_cssize, fs->fs_fsize);
-       space = wmemall(vmemall, (int)fs->fs_cssize);
-       if (space == 0) {
-               error = ENOMEM;
+       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;
                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;
        }
        }
-       for (i = 0; i < blks; i += fs->fs_frag) {
-               size = fs->fs_bsize;
-               if (i + fs->fs_frag > blks)
-                       size = (blks - i) * fs->fs_fsize;
-               tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size);
-               if (tp->b_flags&B_ERROR) {
-                       wmemfree(space, (int)fs->fs_cssize);
+       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;
                }
                        goto out;
                }
-               bcopy((caddr_t)tp->b_un.b_addr, space, (u_int)size);
-               fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space;
-               space += size;
-               brelse(tp);
-               tp = 0;
        }
        }
-       mp->m_inodp = ip;
-       mp->m_dev = dev;
-       if (ip) {
-               ip->i_flag |= IMOUNT;
-               iunlock(ip);
+       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;
        }
        }
-       return (fs);
-out:
-       if (error == 0)
-               error = EIO;
-       if (ip)
-               iput(ip);
-       if (mp)
-               mp->m_bufp = 0;
-       if (bp)
-               brelse(bp);
-       if (tp)
-               brelse(tp);
-       u.u_error = error;
+       np->netc_exflags = argp->exflags;
+       np->netc_anon = argp->anon;
+       np->netc_anon.cr_ref = 1;
        return (0);
        return (0);
+out:
+       free(np, M_NETADDR);
+       return (error);
 }
 
 }
 
-umount()
+/* ARGSUSED */
+static int
+ufs_free_netcred(rn, w)
+       struct radix_node *rn;
+       caddr_t w;
 {
 {
-       struct a {
-               char    *fspec;
-       } *uap = (struct a *)u.u_ap;
-
-       u.u_error = unmount1(uap->fspec, 0);
+       free((caddr_t)rn, M_NETADDR);
 }
 }
+       
 
 
-unmount1(fname, forcibly)
-       caddr_t fname;
-       int forcibly;
-{
-       dev_t dev;
-       register struct mount *mp;
-       int stillopen, flag, error;
-       register struct inode *ip;
-       register struct fs *fs;
-
-       error = getmdev(&dev, fname);
-       if (error)
-               return (error);
-       for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
-               if (mp->m_bufp != NULL && dev == mp->m_dev)
-                       goto found;
-       return (EINVAL);
-found:
-       xumount(dev);   /* remove unused sticky files from text table */
-       nchinval(dev);  /* flush the name cache */
-       update();
-#ifdef QUOTA
-       if ((stillopen = iflush(dev, mp->m_qinod)) < 0 && !forcibly)
-#else
-       if ((stillopen = iflush(dev)) < 0 && !forcibly)
-#endif
-               return (EBUSY);
-       if (stillopen < 0)
-               return (EBUSY);                 /* XXX */
-#ifdef QUOTA
-       closedq(mp);
-       /*
-        * Here we have to iflush again to get rid of the quota inode.
-        * A drag, but it would be ugly to cheat, & this doesn't happen often
-        */
-       (void)iflush(dev, (struct inode *)NULL);
-#endif
-       ip = mp->m_inodp;
-       ip->i_flag &= ~IMOUNT;
-       irele(ip);
-       fs = mp->m_bufp->b_un.b_fs;
-       wmemfree((caddr_t)fs->fs_csp[0], (int)fs->fs_cssize);
-       flag = !fs->fs_ronly;
-       brelse(mp->m_bufp);
-       mp->m_bufp = 0;
-       mp->m_dev = 0;
-       mpurge(mp - &mount[0]);
-       if (!stillopen) {
-               (*bdevsw[major(dev)].d_close)(dev, flag);
-               binval(dev);
-       }
-       return (0);
-}
-
-sbupdate(mp)
-       struct mount *mp;
+/*
+ * Free the net address hash lists that are hanging off the mount points.
+ */
+void
+ufs_free_addrlist(ump)
+       struct ufsmount *ump;
 {
 {
-       register struct fs *fs = mp->m_bufp->b_un.b_fs;
-       register struct buf *bp;
-       int blks;
-       caddr_t space;
-       int i, size;
+       register int i;
+       register struct radix_node_head *rnh;
 
 
-       bp = getblk(mp->m_dev, SBLOCK, (int)fs->fs_sbsize);
-       bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize);
-       bwrite(bp);
-       blks = howmany(fs->fs_cssize, fs->fs_fsize);
-       space = (caddr_t)fs->fs_csp[0];
-       for (i = 0; i < blks; i += fs->fs_frag) {
-               size = fs->fs_bsize;
-               if (i + fs->fs_frag > blks)
-                       size = (blks - i) * fs->fs_fsize;
-               bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size);
-               bcopy(space, bp->b_un.b_addr, (u_int)size);
-               space += size;
-               bwrite(bp);
-       }
+       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;
+               }
 }
 
 /*
 }
 
 /*
- * Common code for mount and umount.
- * Check that the user's argument is a reasonable
- * thing on which to mount, and return the device number if so.
+ * 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.
  */
  */
-getmdev(pdev, fname)
-       caddr_t fname;
-       dev_t *pdev;
+int
+ufs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp)
+       register struct mount *mp;
+       struct ufid *ufhp;
+       struct mbuf *nam;
+       struct vnode **vpp;
+       int *exflagsp;
+       struct ucred **credanonp;
 {
 {
-       dev_t dev;
        register struct inode *ip;
        register struct inode *ip;
-       register struct nameidata *ndp = &u.u_nd;
+       register struct netcred *np;
+       register struct ufsmount *ump = VFSTOUFS(mp);
+       register struct radix_node_head *rnh;
+       struct vnode *nvp;
+       struct sockaddr *saddr;
+       int error;
 
 
-       if (!suser())
-               return (u.u_error);
-       ndp->ni_nameiop = LOOKUP | FOLLOW;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = fname;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return (u.u_error);
-       if ((ip->i_mode&IFMT) != IFBLK) {
-               iput(ip);
-               return (ENOTBLK);
+       /*
+        * Get the export permission structure for this <mp, client> 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) {
+               vput(nvp);
+               *vpp = NULLVP;
+               return (ESTALE);
        }
        }
-       dev = (dev_t)ip->i_rdev;
-       iput(ip);
-       if (major(dev) >= nblkdev)
-               return (ENXIO);
-       *pdev = dev;
+       *vpp = nvp;
+       *exflagsp = np->netc_exflags;
+       *credanonp = &np->netc_anon;
        return (0);
 }
        return (0);
 }