collect lock holder when locking inodes
[unix-history] / usr / src / sys / ufs / ffs / ufs_vfsops.c
index 9456b4f..f36295a 100644 (file)
 /*
 /*
- * Copyright (c) 1982, 1986 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
  *
  *
- *     @(#)ufs_vfsops.c        7.12 (Berkeley) %G%
+ * %sccs.include.redist.c%
+ *
+ *     @(#)ufs_vfsops.c        7.65 (Berkeley) %G%
  */
 
  */
 
-#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"
-#include "ioctl.h"
-#include "disklabel.h"
-#include "stat.h"
-#include "malloc.h"
+#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 "ioctl.h"
 #include "disklabel.h"
 #include "stat.h"
 
-smount()
+#include <ufs/ufs/quota.h>
+#include <ufs/ufs/inode.h>
+#include <ufs/ufs/ufsmount.h>
+#include <ufs/ufs/ufs_extern.h>
+
+/*
+ * 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;
 {
 {
-       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 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 | 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) {
-               iput(ip);
-               u.u_error = EBUSY;
-               return;
-       }
-       if ((ip->i_mode&IFMT) != IFDIR) {
-               iput(ip);
-               u.u_error = ENOTDIR;
-               return;
-       }
-       fs = mountfs(dev, uap->ronly, ip);
-       if (fs == 0) {
-               iput(ip);
-               return;
-       }
-       (void) copyinstr(uap->freg, fs->fs_fsmnt, sizeof(fs->fs_fsmnt)-1, &len);
-       bzero(fs->fs_fsmnt + len, sizeof (fs->fs_fsmnt) - len);
+       return (0);
 }
 
 }
 
-struct fs *
-mountfs(dev, ronly, ip)
-       dev_t dev;
-       int ronly;
-       struct inode *ip;
+/*
+       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;
 {
 {
-       register struct mount *mp;
-       struct mount *fmp = NULL;
-       register struct buf *bp = NULL;
-       register struct fs *fs;
-       struct partinfo dpart;
-       int havepart = 0, blks;
-       caddr_t base, space;
-       int i, size;
-       register error;
-       int needclose = 0;
+       int cmd, type, error;
 
 
-       for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) {
-               if (mp->m_fs == NULL) {
-                       if (fmp == NULL)
-                               fmp = mp;
-               } else if (dev == mp->m_dev) {
-                       u.u_error = EBUSY;              /* XXX */
-                       return ((struct fs *) NULL);
-               }
-       }
-       if ((mp = fmp) == NULL) {
-               u.u_error = EMFILE;             /* needs translation      XXX */
-               return ((struct fs *) NULL);
+#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);
        }
        }
-       mp->m_fs = (struct fs *)1;      /* just to reserve this slot */
-       mp->m_dev = dev;
-       mp->m_inodp = NULL;
-       error =
-           (*bdevsw[major(dev)].d_open)(dev, ronly ? FREAD : FREAD|FWRITE,
-               S_IFBLK);
-       if (error) {
-               u.u_error = error;
-               mp->m_fs = NULL;
-               return ((struct fs *) NULL);
+
+       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);
        }
        }
-       needclose = 1;
-       if ((*bdevsw[major(dev)].d_ioctl)(dev, DIOCGPART,
-           (caddr_t)&dpart, FREAD) == 0) {
-               havepart = 1;
-               size = dpart.disklab->d_secsize;
-       } else
-               size = DEV_BSIZE;
-#ifdef SECSIZE
-       /*
-        * If possible, determine hardware sector size
-        * and adjust fsbtodb to correspond.
-        */
-#endif SECSIZE
-       if ((*bdevsw[major(dev)].d_ioctl)(dev, DIOCGPART,
-           (caddr_t)&dpart, FREAD) == 0) {
-               havepart = 1;
-               size = dpart.disklab->d_secsize;
-#ifdef SECSIZE
-               if (size < MINSECSIZE) {
-                       error = EINVAL;
-                       goto out;
-               }
-#endif SECSIZE
-       } else
-               size = DEV_BSIZE;
-#ifdef SECSIZE
-       tp = bread(dev, (daddr_t)(SBOFF / size), SBSIZE, size);
-#else SECSIZE
-       bp = bread(dev, SBLOCK, SBSIZE);
-       if (bp->b_flags & B_ERROR) {
-               mp->m_fs = NULL;
-               goto out;
+       /* NOTREACHED */
+#endif
+}
+
+/*
+ * 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);
        }
        }
-       fs = bp->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 */
+       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;
        }
        }
-       mp->m_fs = (struct fs *)malloc((u_long)fs->fs_sbsize, M_SUPERBLK,
-           M_WAITOK);
-       bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)mp->m_fs,
-          (u_int)fs->fs_sbsize);
-       brelse(bp);
-       bp = NULL;
-       fs = mp->m_fs;
-       fs->fs_ronly = (ronly != 0);
-       if (ronly == 0)
-               fs->fs_fmod = 1;
-       if (havepart) {
-               dpart.part->p_fstype = FS_BSDFFS;
-               dpart.part->p_fsize = fs->fs_fsize;
-               dpart.part->p_frag = fs->fs_frag;
-               dpart.part->p_cpg = fs->fs_cpg;
-       }
-#ifdef SECSIZE
-       /*
-        * If we have a disk label, force per-partition
-        * filesystem information to be correct
-        * and set correct current fsbtodb shift.
-        */
-#endif SECSIZE
-       if (havepart) {
-               dpart.part->p_fstype = FS_BSDFFS;
-               dpart.part->p_fsize = fs->fs_fsize;
-               dpart.part->p_frag = fs->fs_frag;
-#ifdef SECSIZE
-#ifdef tahoe
+       ump = VFSTOUFS(mp);
+       i = saddr->sa_family;
+       if ((rnh = ump->um_rtable[i]) == 0) {
                /*
                /*
-                * Save the original fsbtodb shift to restore on updates.
-                * (Console doesn't understand fsbtodb changes.)
+                * Seems silly to initialize every AF when most are not
+                * used, do so on demand here
                 */
                 */
-               fs->fs_sparecon[0] = fs->fs_fsbtodb;
-#endif
-               i = fs->fs_fsize / size;
-               for (fs->fs_fsbtodb = 0; i > 1; i >>= 1)
-                       fs->fs_fsbtodb++;
-#endif SECSIZE
-               fs->fs_dbsize = size;
-       }
-       blks = howmany(fs->fs_cssize, fs->fs_fsize);
-       base = space = (caddr_t)malloc((u_long)fs->fs_cssize, M_SUPERBLK,
-           M_WAITOK);
-       if (space == NULL) {
-               error = ENOMEM;
-               goto out;
-       }
-       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;
-#ifdef SECSIZE
-               tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size,
-                   fs->fs_dbsize);
-#else SECSIZE
-               bp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size);
-               if (bp->b_flags&B_ERROR) {
-                       free((caddr_t)base, M_SUPERBLK);
+               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)bp->b_un.b_addr, space, (u_int)size);
-               fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space;
-               space += size;
-               brelse(bp);
-               bp = NULL;
        }
        }
-       mp->m_inodp = ip;
-       if (ip) {
-               ip->i_flag |= IMOUNT;
-               cacheinval(ip);
-               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;
        }
        }
-       /* Sanity checks for old file systems.                     XXX */
-       fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect);       /* XXX */
-       fs->fs_interleave = MAX(fs->fs_interleave, 1);          /* XXX */
-       if (fs->fs_postblformat == FS_42POSTBLFMT)              /* XXX */
-               fs->fs_nrpos = 8;                               /* XXX */
-
-       return (fs);
+       np->netc_exflags = argp->exflags;
+       np->netc_anon = argp->anon;
+       np->netc_anon.cr_ref = 1;
+       return (0);
 out:
 out:
-       if (needclose)
-               (void) closei(dev, IFBLK, ronly? FREAD : FREAD|FWRITE);
-       if (mp->m_fs) {
-               free((caddr_t)mp->m_fs, M_SUPERBLK);
-               mp->m_fs = NULL;
-       }
-       if (bp)
-               brelse(bp);
-       u.u_error = error ? error : EIO;                        /* XXX */
-       return ((struct fs *) NULL);
-}
-
-umount()
-{
-       struct a {
-               char    *fspec;
-       } *uap = (struct a *)u.u_ap;
-
-       u.u_error = unmount1(uap->fspec, 0);
+       free(np, M_NETADDR);
+       return (error);
 }
 
 }
 
-unmount1(fname, forcibly)
-       caddr_t fname;
-       int forcibly;
+/* ARGSUSED */
+static int
+ufs_free_netcred(rn, w)
+       struct radix_node *rn;
+       caddr_t w;
 {
 {
-       dev_t dev;
-       register struct mount *mp;
-       int error;
-       register struct inode *ip;
-       register struct fs *fs;
-
-       forcibly = 0;                                   /* XXX */
-       forcibly = 0;                                   /* XXX */
-       error = getmdev(&dev, fname);
-       if (error)
-               return (error);
-       for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
-               if (mp->m_fs != 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 ((error = iflush(dev, mp->m_qinod)) && !forcibly)
-#else
-       if ((error = iflush(dev)) && !forcibly)
-#endif
-               return (error);
-#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;
-       fs = mp->m_fs;
-       free((caddr_t)fs->fs_csp[0], M_SUPERBLK);
-       free((caddr_t)mp->m_fs, M_SUPERBLK);
-       mp->m_fs = NULL;
-       mp->m_dev = NODEV;
-       mpurge(mp - &mount[0]);
-       error = closei(dev, IFBLK, fs->fs_ronly? FREAD : FREAD|FWRITE);
-       irele(ip);
-       return (error);
+       free((caddr_t)rn, M_NETADDR);
 }
 }
+       
 
 
-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_fs;
-       register struct buf *bp;
-       int blks;
-       caddr_t space;
-       int i, size;
+       register int i;
+       register struct radix_node_head *rnh;
 
 
-#ifdef SECSIZE
-       bp = getblk(mp->m_dev, (daddr_t)fsbtodb(fs, SBOFF / fs->fs_fsize),
-           (int)fs->fs_sbsize, fs->fs_dbsize);
-#else SECSIZE
-       bp = getblk(mp->m_dev, SBLOCK, (int)fs->fs_sbsize);
-#endif SECSIZE
-       bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize);
-       /* Restore compatibility to old file systems.              XXX */
-       if (fs->fs_postblformat == FS_42POSTBLFMT)              /* XXX */
-               bp->b_un.b_fs->fs_nrpos = -1;                   /* XXX */
-#ifdef SECSIZE
-#ifdef tahoe
-       /* restore standard fsbtodb shift */
-       bp->b_un.b_fs->fs_fsbtodb = fs->fs_sparecon[0];
-       bp->b_un.b_fs->fs_sparecon[0] = 0;
-#endif
-#endif SECSIZE
-       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;
-#ifdef SECSIZE
-               bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size,
-                   fs->fs_dbsize);
-#else SECSIZE
-               bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size);
-#endif SECSIZE
-               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 (u.u_error = suser(u.u_cred, &u.u_acflag))
-               return (u.u_error);
-       ndp->ni_nameiop = LOOKUP | FOLLOW;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = fname;
-       ip = namei(ndp);
-       if (ip == NULL) {
-               if (u.u_error == ENOENT)
-                       return (ENODEV); /* needs translation */
-               return (u.u_error);
+       /*
+        * 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);
        }
        }
-       if ((ip->i_mode&IFMT) != IFBLK) {
-               iput(ip);
-               return (ENOTBLK);
+       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);
 }