123400Smckusick /* 229118Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 323400Smckusick * All rights reserved. The Berkeley software License Agreement 423400Smckusick * specifies the terms and conditions for redistribution. 523400Smckusick * 6*31385Skarels * @(#)lfs_vfsops.c 7.5 (Berkeley) 06/04/87 723400Smckusick */ 812795Ssam 917100Sbloom #include "param.h" 1017100Sbloom #include "systm.h" 1117100Sbloom #include "dir.h" 1217100Sbloom #include "user.h" 1317100Sbloom #include "inode.h" 1417100Sbloom #include "proc.h" 1517100Sbloom #include "fs.h" 1617100Sbloom #include "buf.h" 1717100Sbloom #include "mount.h" 1817100Sbloom #include "file.h" 1917100Sbloom #include "conf.h" 2030749Skarels #include "ioctl.h" 2130749Skarels #include "disklabel.h" 2230749Skarels #include "stat.h" 2312795Ssam 2412795Ssam smount() 2512795Ssam { 2612795Ssam register struct a { 2712795Ssam char *fspec; 2812795Ssam char *freg; 2912795Ssam int ronly; 3016697Smckusick } *uap = (struct a *)u.u_ap; 3112795Ssam dev_t dev; 3212795Ssam register struct inode *ip; 3312795Ssam register struct fs *fs; 3416697Smckusick register struct nameidata *ndp = &u.u_nd; 3516705Smckusick u_int len; 3612795Ssam 3716697Smckusick u.u_error = getmdev(&dev, uap->fspec); 3812795Ssam if (u.u_error) 3912795Ssam return; 4027267Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 4116697Smckusick ndp->ni_segflg = UIO_USERSPACE; 4216697Smckusick ndp->ni_dirp = (caddr_t)uap->freg; 4316697Smckusick ip = namei(ndp); 4412795Ssam if (ip == NULL) 4512795Ssam return; 4621013Smckusick if (ip->i_count != 1) { 4712795Ssam iput(ip); 4812795Ssam u.u_error = EBUSY; 4912795Ssam return; 5012795Ssam } 5121013Smckusick if ((ip->i_mode&IFMT) != IFDIR) { 5221013Smckusick iput(ip); 5321013Smckusick u.u_error = ENOTDIR; 5421013Smckusick return; 5521013Smckusick } 5612795Ssam fs = mountfs(dev, uap->ronly, ip); 5712795Ssam if (fs == 0) 5812795Ssam return; 5916705Smckusick (void) copyinstr(uap->freg, fs->fs_fsmnt, sizeof(fs->fs_fsmnt)-1, &len); 6016728Skarels bzero(fs->fs_fsmnt + len, sizeof (fs->fs_fsmnt) - len); 6112795Ssam } 6212795Ssam 6312795Ssam /* this routine has races if running twice */ 6412795Ssam struct fs * 6512795Ssam mountfs(dev, ronly, ip) 6612795Ssam dev_t dev; 6712795Ssam int ronly; 6812795Ssam struct inode *ip; 6912795Ssam { 7012795Ssam register struct mount *mp = 0; 7112795Ssam struct buf *tp = 0; 7212795Ssam register struct buf *bp = 0; 7312795Ssam register struct fs *fs; 7430749Skarels struct partinfo dpart; 7530749Skarels int havepart = 0, blks; 7612795Ssam caddr_t space; 7712795Ssam int i, size; 7816639Skarels register error; 7921013Smckusick int needclose = 0; 8012795Ssam 8116639Skarels error = 8230749Skarels (*bdevsw[major(dev)].d_open)(dev, ronly ? FREAD : FREAD|FWRITE, 8330749Skarels S_IFBLK); 8416639Skarels if (error) 8512795Ssam goto out; 8621013Smckusick needclose = 1; 8730749Skarels if ((*bdevsw[major(dev)].d_ioctl)(dev, DIOCGPART, 8830749Skarels (caddr_t)&dpart, FREAD) == 0) { 8930749Skarels havepart = 1; 9030749Skarels size = dpart.disklab->d_secsize; 9130749Skarels } else 9230749Skarels size = DEV_BSIZE; 9312795Ssam tp = bread(dev, SBLOCK, SBSIZE); 9412795Ssam if (tp->b_flags & B_ERROR) 9512795Ssam goto out; 9612795Ssam for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 9712795Ssam if (mp->m_bufp != 0 && dev == mp->m_dev) { 9812795Ssam mp = 0; 9916639Skarels error = EBUSY; 10012795Ssam goto out; 10112795Ssam } 10212795Ssam for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 10312795Ssam if (mp->m_bufp == 0) 10412795Ssam goto found; 10512795Ssam mp = 0; 10616639Skarels error = EMFILE; /* needs translation */ 10712795Ssam goto out; 10812795Ssam found: 10912795Ssam mp->m_bufp = tp; /* just to reserve this slot */ 11012795Ssam mp->m_dev = NODEV; 11112795Ssam fs = tp->b_un.b_fs; 11230749Skarels if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || 11330749Skarels fs->fs_bsize < sizeof(struct fs)) { 11416639Skarels error = EINVAL; /* also needs translation */ 11516639Skarels goto out; 11616639Skarels } 11712795Ssam bp = geteblk((int)fs->fs_sbsize); 11812795Ssam mp->m_bufp = bp; 11912795Ssam bcopy((caddr_t)tp->b_un.b_addr, (caddr_t)bp->b_un.b_addr, 12012795Ssam (u_int)fs->fs_sbsize); 12112795Ssam brelse(tp); 12212795Ssam tp = 0; 12312795Ssam fs = bp->b_un.b_fs; 12412795Ssam fs->fs_ronly = (ronly != 0); 12512795Ssam if (ronly == 0) 12612795Ssam fs->fs_fmod = 1; 12730749Skarels if (havepart) { 12830749Skarels dpart.part->p_fstype = FS_BSDFFS; 12930749Skarels dpart.part->p_fsize = fs->fs_fsize; 13030749Skarels dpart.part->p_frag = fs->fs_frag; 131*31385Skarels dpart.part->p_cpg = fs->fs_cpg; 13230749Skarels fs->fs_dbsize = size; 13330749Skarels } 13412795Ssam blks = howmany(fs->fs_cssize, fs->fs_fsize); 13512795Ssam space = wmemall(vmemall, (int)fs->fs_cssize); 13616639Skarels if (space == 0) { 13716639Skarels error = ENOMEM; 13812795Ssam goto out; 13916639Skarels } 14012795Ssam for (i = 0; i < blks; i += fs->fs_frag) { 14112795Ssam size = fs->fs_bsize; 14212795Ssam if (i + fs->fs_frag > blks) 14312795Ssam size = (blks - i) * fs->fs_fsize; 14412795Ssam tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size); 14512795Ssam if (tp->b_flags&B_ERROR) { 14612795Ssam wmemfree(space, (int)fs->fs_cssize); 14712795Ssam goto out; 14812795Ssam } 14912795Ssam bcopy((caddr_t)tp->b_un.b_addr, space, (u_int)size); 15017225Smckusick fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space; 15112795Ssam space += size; 15212795Ssam brelse(tp); 15312795Ssam tp = 0; 15412795Ssam } 15512795Ssam mp->m_inodp = ip; 15612795Ssam mp->m_dev = dev; 15712795Ssam if (ip) { 15812795Ssam ip->i_flag |= IMOUNT; 15927267Smckusick cacheinval(ip); 16012795Ssam iunlock(ip); 16112795Ssam } 16230383Smckusick /* Sanity checks for old file systems. XXX */ 16330383Smckusick fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect); /* XXX */ 16430383Smckusick fs->fs_interleave = MAX(fs->fs_interleave, 1); /* XXX */ 16530749Skarels 16612795Ssam return (fs); 16712795Ssam out: 16816639Skarels if (error == 0) 16916639Skarels error = EIO; 17031020Ssam if (needclose && ip) 17130749Skarels (void) closei((dev_t)ip->i_rdev, IFBLK, 17230749Skarels ronly? FREAD : FREAD|FWRITE); 17312795Ssam if (ip) 17412795Ssam iput(ip); 17512795Ssam if (mp) 17612795Ssam mp->m_bufp = 0; 17712795Ssam if (bp) 17812795Ssam brelse(bp); 17912795Ssam if (tp) 18012795Ssam brelse(tp); 18116639Skarels u.u_error = error; 18212795Ssam return (0); 18312795Ssam } 18412795Ssam 18512795Ssam umount() 18612795Ssam { 18712795Ssam struct a { 18812795Ssam char *fspec; 18916697Smckusick } *uap = (struct a *)u.u_ap; 19012795Ssam 19116697Smckusick u.u_error = unmount1(uap->fspec, 0); 19212795Ssam } 19312795Ssam 19416697Smckusick unmount1(fname, forcibly) 19516697Smckusick caddr_t fname; 19612795Ssam int forcibly; 19712795Ssam { 19812795Ssam dev_t dev; 19912795Ssam register struct mount *mp; 20030749Skarels int error; 20112795Ssam register struct inode *ip; 20212795Ssam register struct fs *fs; 20312795Ssam 20430749Skarels forcibly = 0; /* XXX */ 20516697Smckusick error = getmdev(&dev, fname); 20612795Ssam if (error) 20712795Ssam return (error); 20812795Ssam for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 20912795Ssam if (mp->m_bufp != NULL && dev == mp->m_dev) 21012795Ssam goto found; 21112795Ssam return (EINVAL); 21212795Ssam found: 21312795Ssam xumount(dev); /* remove unused sticky files from text table */ 21415800Smckusick nchinval(dev); /* flush the name cache */ 21512795Ssam update(); 21612795Ssam #ifdef QUOTA 21730749Skarels if ((error = iflush(dev, mp->m_qinod)) && !forcibly) 21812795Ssam #else 21930749Skarels if ((error = iflush(dev)) && !forcibly) 22012795Ssam #endif 22130749Skarels return (error); 22212795Ssam #ifdef QUOTA 22312795Ssam closedq(mp); 22412795Ssam /* 22512795Ssam * Here we have to iflush again to get rid of the quota inode. 22630749Skarels * A drag, but it would be ugly to cheat, & this doesn't happen often. 22712795Ssam */ 22812795Ssam (void)iflush(dev, (struct inode *)NULL); 22912795Ssam #endif 23012795Ssam ip = mp->m_inodp; 23112795Ssam ip->i_flag &= ~IMOUNT; 23212795Ssam fs = mp->m_bufp->b_un.b_fs; 23312795Ssam wmemfree((caddr_t)fs->fs_csp[0], (int)fs->fs_cssize); 23412795Ssam brelse(mp->m_bufp); 23512795Ssam mp->m_bufp = 0; 23612795Ssam mp->m_dev = 0; 23712795Ssam mpurge(mp - &mount[0]); 23830749Skarels error = closei(dev, IFBLK, fs->fs_ronly? FREAD : FREAD|FWRITE); 23930749Skarels irele(ip); 24030749Skarels return (error); 24112795Ssam } 24212795Ssam 24312795Ssam sbupdate(mp) 24412795Ssam struct mount *mp; 24512795Ssam { 24612795Ssam register struct fs *fs = mp->m_bufp->b_un.b_fs; 24712795Ssam register struct buf *bp; 24812795Ssam int blks; 24912795Ssam caddr_t space; 25012795Ssam int i, size; 25112795Ssam 25212795Ssam bp = getblk(mp->m_dev, SBLOCK, (int)fs->fs_sbsize); 25312795Ssam bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize); 25412795Ssam bwrite(bp); 25512795Ssam blks = howmany(fs->fs_cssize, fs->fs_fsize); 25612795Ssam space = (caddr_t)fs->fs_csp[0]; 25712795Ssam for (i = 0; i < blks; i += fs->fs_frag) { 25812795Ssam size = fs->fs_bsize; 25912795Ssam if (i + fs->fs_frag > blks) 26012795Ssam size = (blks - i) * fs->fs_fsize; 26112795Ssam bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size); 26212795Ssam bcopy(space, bp->b_un.b_addr, (u_int)size); 26312795Ssam space += size; 26412795Ssam bwrite(bp); 26512795Ssam } 26612795Ssam } 26712795Ssam 26812795Ssam /* 26912795Ssam * Common code for mount and umount. 27012795Ssam * Check that the user's argument is a reasonable 27112795Ssam * thing on which to mount, and return the device number if so. 27212795Ssam */ 27316697Smckusick getmdev(pdev, fname) 27416697Smckusick caddr_t fname; 27512795Ssam dev_t *pdev; 27612795Ssam { 27712795Ssam dev_t dev; 27812795Ssam register struct inode *ip; 27916697Smckusick register struct nameidata *ndp = &u.u_nd; 28012795Ssam 28112795Ssam if (!suser()) 28212795Ssam return (u.u_error); 28316697Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 28416697Smckusick ndp->ni_segflg = UIO_USERSPACE; 28516697Smckusick ndp->ni_dirp = fname; 28616697Smckusick ip = namei(ndp); 28721013Smckusick if (ip == NULL) { 28821013Smckusick if (u.u_error == ENOENT) 28921013Smckusick return (ENODEV); /* needs translation */ 29012795Ssam return (u.u_error); 29121013Smckusick } 29215956Skarels if ((ip->i_mode&IFMT) != IFBLK) { 29315956Skarels iput(ip); 29412795Ssam return (ENOTBLK); 29515956Skarels } 29612795Ssam dev = (dev_t)ip->i_rdev; 29715956Skarels iput(ip); 29812795Ssam if (major(dev) >= nblkdev) 29912795Ssam return (ENXIO); 30012795Ssam *pdev = dev; 30112795Ssam return (0); 30212795Ssam } 303