4.3BSD-UWisc/src/sys/ufs/ufs_vfsops.c

Compare this file to the similar file:
Show the results in this format:

/*	@(#)ufs_vfsops.c 1.1 86/02/03 SMI; from UCB 4.1 83/05/27	*/
/*	@(#)ufs_vfsops.c	2.2 86/05/14 NFSSRC */

#include "param.h"
#include "systm.h"
#include "user.h"
#include "proc.h"
#include "buf.h"
#include "pathname.h"
#include "vfs.h"
#include "vnode.h"
#include "file.h"
#include "uio.h"
#include "conf.h"

#include "../ufs/fs.h"
#include "../ufs/mount.h"
#include "../ufs/inode.h"
#undef NFS
/*
 * must specify ../h/mount.h so as not to get ufs/mount.h again
 */
#include "../h/mount.h"

/*
 * ufs vfs operations.
 */
extern int ufs_mount();
extern int ufs_unmount();
extern int ufs_root();
extern int ufs_statfs();
extern int ufs_sync();

struct vfsops ufs_vfsops = {
	ufs_mount,
	ufs_unmount,
	ufs_root,
	ufs_statfs,
	ufs_sync,
};

/*
 * this is the default filesystem type.
 * this should be setup by the configurator
 */
extern int ufs_mountroot();
int (*rootfsmount)() = ufs_mountroot;

/*
 * Default device to mount on.
 */
extern dev_t rootdev;

/*
 * Mount table.
 */
struct mount	mounttab[NMOUNT];

/*
 * ufs_mount system call
 */
ufs_mount(vfsp, path, data)
	struct vfs *vfsp;
	char *path;
	caddr_t data;
{
	int error;
	dev_t dev;
	struct vnode *vp;
	struct ufs_args args;

	/*
	 * Get arguments
	 */
	error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args));
	if (error) {
		return (error);
	}
	/*
	 * Get the device to be mounted
	 */
	error =
	    lookupname(args.fspec, UIO_USERSPACE, FOLLOW_LINK,
		(struct vnode **)0, &vp);
	if (error) {
		return (error);
	}
	if (vp->v_type != VBLK) {
		VN_RELE(vp);
		return (ENOTBLK);
	}
	dev = vp->v_rdev;
	VN_RELE(vp);
	if (major(dev) >= nblkdev) {
		return (ENXIO);
	}
	/*
	 * Mount the filesystem.
	 */
	error = mountfs(dev, path, vfsp);
	return (error);
}

/*
 * Called by vfs_mountroot when ufs is going to be mounted as root
 */
ufs_mountroot()
{
	struct vfs *vfsp;
	register struct fs *fsp;
	register int error;

	vfsp = (struct vfs *)kmem_alloc(sizeof (struct vfs));
	VFS_INIT(vfsp, &ufs_vfsops, (caddr_t)0);
	error = mountfs(rootdev, "/", vfsp);
	if (error) {
		kmem_free((caddr_t)vfsp, sizeof (struct vfs));
		return (error);
	}
	error = vfs_add((struct vnode *)0, vfsp, 0);
	if (error) {
		unmount1(vfsp, 0);
		kmem_free((caddr_t)vfsp, sizeof (struct vfs));
		return (error);
	}
	vfs_unlock(vfsp);
	fsp = ((struct mount *)(vfsp->vfs_data))->m_bufp->b_un.b_fs;
	inittodr(fsp->fs_time);
	return (0);
}

int
mountfs(dev, path, vfsp)
	dev_t dev;
	char *path;
	struct vfs *vfsp;
{
	register struct fs *fsp;
	register struct mount *mp = 0;
	register struct buf *bp = 0;
	struct buf *tp = 0;
	struct vnode *dev_vp;
	int error;
	int blks;
	caddr_t space;
	int i;
	int size;
	extern char *strncpy();

	/*
	 * Open block device mounted on.
	 * When bio is fixed for vnodes this can all be vnode operations
	 */
	error =
	    (*bdevsw[major(dev)].d_open)(
		dev, (vfsp->vfs_flag & VFS_RDONLY) ? FREAD : FREAD|FWRITE);
	if (error) {
		/* return (error); */
		return (EIO);
	}
	/*
	 * check for dev already mounted on
	 */
	for (mp = &mounttab[0]; mp < &mounttab[NMOUNT]; mp++) {
		if (mp->m_bufp != 0 && dev == mp->m_dev) {
			return (EBUSY);
		}
	}
	/*
	 * find empty mount table entry
	 */
	for (mp = &mounttab[0]; mp < &mounttab[NMOUNT]; mp++) {
		if (mp->m_bufp == 0)
			goto found;
	}
	return (EBUSY);
found:
	vfsp->vfs_data = (caddr_t)mp;
	mp->m_vfsp = vfsp;
	/*
	 * read in superblock
	 */
	dev_vp = devtovp(dev);
	tp = bread(dev_vp, SBLOCK, SBSIZE);
	if (tp->b_flags & B_ERROR)
		goto out;
	/*
	 * Copy the super block into a buffer in it's native size.
	 */
	mp->m_bufp = tp;	/* just to reserve this slot */
	mp->m_dev = NODEV;
	fsp = tp->b_un.b_fs;
	if (fsp->fs_magic != FS_MAGIC || fsp->fs_bsize > MAXBSIZE)
		goto out;
	bp = geteblk((int)fsp->fs_sbsize);
	mp->m_bufp = bp;
	bcopy((caddr_t)tp->b_un.b_addr, (caddr_t)bp->b_un.b_addr,
	   (u_int)fsp->fs_sbsize);
	brelse(tp);
	tp = 0;
	fsp = bp->b_un.b_fs;
	if (vfsp->vfs_flag & VFS_RDONLY) {
		fsp->fs_ronly = 1;
	} else {
		fsp->fs_fmod = 1;
		fsp->fs_ronly = 0;
	}
	vfsp->vfs_bsize = fsp->fs_bsize;
	/*
	 * Read in cyl group info
	 */
	blks = howmany(fsp->fs_cssize, fsp->fs_fsize);
	space = wmemall(vmemall, (int)fsp->fs_cssize);
	if (space == 0)
		goto out;
	for (i = 0; i < blks; i += fsp->fs_frag) {
		size = fsp->fs_bsize;
		if (i + fsp->fs_frag > blks)
			size = (blks - i) * fsp->fs_fsize;
		tp = bread(dev_vp, (daddr_t)fsbtodb(fsp, fsp->fs_csaddr + i),
		    size);
		if (tp->b_flags&B_ERROR) {
			wmemfree(space, (int)fsp->fs_cssize);
			goto out;
		}
		bcopy((caddr_t)tp->b_un.b_addr, space, (u_int)size);
		fsp->fs_csp[i / fsp->fs_frag] = (struct csum *)space;
		space += size;
		brelse(tp);
		tp = 0;
	}
	mp->m_dev = dev;
	(void) strncpy(fsp->fs_fsmnt, path, sizeof(fsp->fs_fsmnt));
	VN_RELE(dev_vp);
	return (0);
out:
	mp->m_bufp = 0;
	if (bp)
		brelse(bp);
	if (tp)
		brelse(tp);
	VN_RELE(dev_vp);
	return (EBUSY);
}

/*
 * vfs operations
 */

ufs_unmount(vfsp)
	struct vfs *vfsp;
{

	return (unmount1(vfsp, 0));
}

unmount1(vfsp, forcibly)
	register struct vfs *vfsp;
	int forcibly;
{
	dev_t dev;
	register struct mount *mp;
	register struct fs *fs;
	register int stillopen;
	int flag;

	mp = (struct mount *)vfsp->vfs_data;
	dev = mp->m_dev;
#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
	(void)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
	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;
	if (!stillopen) {
		register struct vnode *dev_vp;

		(*bdevsw[major(dev)].d_close)(dev, flag);
		dev_vp = devtovp(dev);
		binval(dev_vp);
		VN_RELE(dev_vp);
	}
	return (0);
}

/*
 * find root of ufs
 */
int
ufs_root(vfsp, vpp)
	struct vfs *vfsp;
	struct vnode **vpp;
{
	register struct mount *mp;
	register struct inode *ip;

	mp = (struct mount *)vfsp->vfs_data;
	ip = iget(mp->m_dev, mp->m_bufp->b_un.b_fs, (ino_t)ROOTINO);
	if (ip == (struct inode *)0) {
		return (u.u_error);
	}
	iunlock(ip);
	*vpp = ITOV(ip);
	return (0);
}

/*
 * Get file system statistics.
 */
int
ufs_statfs(vfsp, sbp)
register struct vfs *vfsp;
struct statfs *sbp;
{
	register struct fs *fsp;

	fsp = ((struct mount *)vfsp->vfs_data)->m_bufp->b_un.b_fs;
	if (fsp->fs_magic != FS_MAGIC)
		panic("ufs_statfs");
	sbp->f_bsize = fsp->fs_fsize;
	sbp->f_blocks = fsp->fs_dsize;
	sbp->f_bfree =
	    fsp->fs_cstotal.cs_nbfree * fsp->fs_frag +
		fsp->fs_cstotal.cs_nffree;
	/*
	 * avail = MAX(max_avail - used, 0)
	 */
	sbp->f_bavail =
	    (fsp->fs_dsize * (100 - fsp->fs_minfree) / 100) -
		 (fsp->fs_dsize - sbp->f_bfree);
	/*
	 * inodes
	 */
	sbp->f_files =  fsp->fs_ncg * fsp->fs_ipg;
	sbp->f_ffree = fsp->fs_cstotal.cs_nifree;
	bcopy((caddr_t)fsp->fs_id, (caddr_t)sbp->f_fsid, sizeof (fsid_t));
	return (0);
}

/*
 * Flush any pending I/O.
 */
int
ufs_sync()
{
	update();
	return (0);
}

sbupdate(mp)
	struct mount *mp;
{
	register struct fs *fs = mp->m_bufp->b_un.b_fs;
	register struct buf *bp;
	int blks;
	caddr_t space;
	int i, size;
	register struct vnode *dev_vp;

	dev_vp = devtovp(mp->m_dev);
	bp = getblk(dev_vp, 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(dev_vp, (daddr_t)fsbtodb(fs, fs->fs_csaddr + i),
		    size);
		bcopy(space, bp->b_un.b_addr, (u_int)size);
		space += size;
		bwrite(bp);
	}
	VN_RELE(dev_vp);
}