+/*
+ * Return root of a filesystem
+ */
+ufs_root(mp, vpp)
+ struct mount *mp;
+ struct vnode **vpp;
+{
+ register struct inode *ip;
+ struct inode *nip;
+ struct vnode tvp;
+ int error;
+
+ tvp.v_mount = mp;
+ ip = VTOI(&tvp);
+ ip->i_vnode = &tvp;
+ ip->i_dev = VFSTOUFS(mp)->um_dev;
+ error = iget(ip, (ino_t)ROOTINO, &nip);
+ if (error)
+ return (error);
+ *vpp = ITOV(nip);
+ return (0);
+}
+
+/*
+ * Do operations associated with quotas
+ */
+ufs_quotactl(mp, cmds, uid, arg)
+ struct mount *mp;
+ int cmds;
+ uid_t uid;
+ caddr_t arg;
+{
+ register struct nameidata *ndp = &u.u_nd;
+ struct ufsmount *ump = VFSTOUFS(mp);
+ struct proc *p = u.u_procp; /* XXX */
+ int cmd, type, error;
+
+#ifndef QUOTA
+ return (EOPNOTSUPP);
+#else
+ if (uid == -1)
+ uid = p->p_ruid;
+ cmd = cmds >> SUBCMDSHIFT;
+
+ switch (cmd) {
+ case Q_GETQUOTA:
+ case Q_SYNC:
+ if (uid == p->p_ruid)
+ break;
+ /* fall through */
+ default:
+ if (error = suser(ndp->ni_cred, &u.u_acflag))
+ return (error);
+ }
+
+ type = cmd & SUBCMDMASK;
+ if ((u_int)type >= MAXQUOTAS)
+ return (EINVAL);
+
+ switch (cmd) {
+
+ case Q_QUOTAON:
+ return (quotaon(ndp, mp, type, arg));
+
+ case Q_QUOTAOFF:
+ if (vfs_busy(mp))
+ return (0);
+ error = quotaoff(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
+}
+
+/*
+ * Get file system statistics.
+ */
+ufs_statfs(mp, sbp)
+ struct mount *mp;
+ register struct statfs *sbp;
+{
+ register struct ufsmount *ump;
+ register struct fs *fs;
+
+ ump = VFSTOUFS(mp);
+ fs = ump->um_fs;
+ if (fs->fs_magic != FS_MAGIC)
+ panic("ufs_statfs");
+ sbp->f_type = MOUNT_UFS;
+ sbp->f_fsize = fs->fs_fsize;
+ sbp->f_bsize = fs->fs_bsize;
+ sbp->f_blocks = fs->fs_dsize;
+ sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag +
+ fs->fs_cstotal.cs_nffree;
+ sbp->f_bavail = (fs->fs_dsize * (100 - fs->fs_minfree) / 100) -
+ (fs->fs_dsize - sbp->f_bfree);
+ sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO;
+ sbp->f_ffree = fs->fs_cstotal.cs_nifree;
+ if (sbp != &mp->mnt_stat) {
+ bcopy((caddr_t)mp->mnt_stat.f_mntonname,
+ (caddr_t)&sbp->f_mntonname[0], MNAMELEN);
+ bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
+ (caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
+ }
+ return (0);
+}
+
+int syncprt = 0;
+
+/*
+ * Go through the disk queues to initiate sandbagged IO;
+ * go through the inodes to write those that have been modified;
+ * initiate the writing of the super block if it has been modified.
+ *
+ * Note: we are always called with the filesystem marked `MPBUSY'.
+ */
+ufs_sync(mp, waitfor)