1*17100Sbloom /* lfs_vfsops.c 6.8 84/08/29 */ 212795Ssam 3*17100Sbloom #include "param.h" 4*17100Sbloom #include "systm.h" 5*17100Sbloom #include "dir.h" 6*17100Sbloom #include "user.h" 7*17100Sbloom #include "inode.h" 8*17100Sbloom #include "proc.h" 9*17100Sbloom #include "fs.h" 10*17100Sbloom #include "buf.h" 11*17100Sbloom #include "mount.h" 12*17100Sbloom #include "file.h" 13*17100Sbloom #include "conf.h" 1412795Ssam 1512795Ssam smount() 1612795Ssam { 1712795Ssam register struct a { 1812795Ssam char *fspec; 1912795Ssam char *freg; 2012795Ssam int ronly; 2116697Smckusick } *uap = (struct a *)u.u_ap; 2212795Ssam dev_t dev; 2312795Ssam register struct inode *ip; 2412795Ssam register struct fs *fs; 2512795Ssam register char *cp; 2616697Smckusick register struct nameidata *ndp = &u.u_nd; 2716705Smckusick u_int len; 2812795Ssam 2916697Smckusick u.u_error = getmdev(&dev, uap->fspec); 3012795Ssam if (u.u_error) 3112795Ssam return; 3216697Smckusick ndp->ni_nameiop = LOOKUP | NOCACHE | FOLLOW; 3316697Smckusick ndp->ni_segflg = UIO_USERSPACE; 3416697Smckusick ndp->ni_dirp = (caddr_t)uap->freg; 3516697Smckusick ip = namei(ndp); 3612795Ssam if (ip == NULL) 3712795Ssam return; 3812795Ssam if (ip->i_count!=1 || (ip->i_mode&IFMT) != IFDIR) { 3912795Ssam iput(ip); 4012795Ssam u.u_error = EBUSY; 4112795Ssam return; 4212795Ssam } 4312795Ssam fs = mountfs(dev, uap->ronly, ip); 4412795Ssam if (fs == 0) 4512795Ssam return; 4616705Smckusick (void) copyinstr(uap->freg, fs->fs_fsmnt, sizeof(fs->fs_fsmnt)-1, &len); 4716728Skarels bzero(fs->fs_fsmnt + len, sizeof (fs->fs_fsmnt) - len); 4812795Ssam } 4912795Ssam 5012795Ssam /* this routine has races if running twice */ 5112795Ssam struct fs * 5212795Ssam mountfs(dev, ronly, ip) 5312795Ssam dev_t dev; 5412795Ssam int ronly; 5512795Ssam struct inode *ip; 5612795Ssam { 5712795Ssam register struct mount *mp = 0; 5812795Ssam struct buf *tp = 0; 5912795Ssam register struct buf *bp = 0; 6012795Ssam register struct fs *fs; 6112795Ssam int blks; 6212795Ssam caddr_t space; 6312795Ssam int i, size; 6416639Skarels register error; 6512795Ssam 6616639Skarels error = 6712795Ssam (*bdevsw[major(dev)].d_open)(dev, ronly ? FREAD : FREAD|FWRITE); 6816639Skarels if (error) 6912795Ssam goto out; 7012795Ssam tp = bread(dev, SBLOCK, SBSIZE); 7112795Ssam if (tp->b_flags & B_ERROR) 7212795Ssam goto out; 7312795Ssam for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 7412795Ssam if (mp->m_bufp != 0 && dev == mp->m_dev) { 7512795Ssam mp = 0; 7616639Skarels error = EBUSY; 7712795Ssam goto out; 7812795Ssam } 7912795Ssam for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 8012795Ssam if (mp->m_bufp == 0) 8112795Ssam goto found; 8212795Ssam mp = 0; 8316639Skarels error = EMFILE; /* needs translation */ 8412795Ssam goto out; 8512795Ssam found: 8612795Ssam mp->m_bufp = tp; /* just to reserve this slot */ 8712795Ssam mp->m_dev = NODEV; 8812795Ssam fs = tp->b_un.b_fs; 8916639Skarels if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE 9016639Skarels || fs->fs_bsize < sizeof(struct fs)) { 9116639Skarels error = EINVAL; /* also needs translation */ 9216639Skarels goto out; 9316639Skarels } 9412795Ssam bp = geteblk((int)fs->fs_sbsize); 9512795Ssam mp->m_bufp = bp; 9612795Ssam bcopy((caddr_t)tp->b_un.b_addr, (caddr_t)bp->b_un.b_addr, 9712795Ssam (u_int)fs->fs_sbsize); 9812795Ssam brelse(tp); 9912795Ssam tp = 0; 10012795Ssam fs = bp->b_un.b_fs; 10112795Ssam fs->fs_ronly = (ronly != 0); 10212795Ssam if (ronly == 0) 10312795Ssam fs->fs_fmod = 1; 10412795Ssam blks = howmany(fs->fs_cssize, fs->fs_fsize); 10512795Ssam space = wmemall(vmemall, (int)fs->fs_cssize); 10616639Skarels if (space == 0) { 10716639Skarels error = ENOMEM; 10812795Ssam goto out; 10916639Skarels } 11012795Ssam for (i = 0; i < blks; i += fs->fs_frag) { 11112795Ssam size = fs->fs_bsize; 11212795Ssam if (i + fs->fs_frag > blks) 11312795Ssam size = (blks - i) * fs->fs_fsize; 11412795Ssam tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size); 11512795Ssam if (tp->b_flags&B_ERROR) { 11612795Ssam wmemfree(space, (int)fs->fs_cssize); 11712795Ssam goto out; 11812795Ssam } 11912795Ssam bcopy((caddr_t)tp->b_un.b_addr, space, (u_int)size); 12012795Ssam fs->fs_csp[i / fs->fs_frag] = (struct csum *)space; 12112795Ssam space += size; 12212795Ssam brelse(tp); 12312795Ssam tp = 0; 12412795Ssam } 12512795Ssam mp->m_inodp = ip; 12612795Ssam mp->m_dev = dev; 12712795Ssam if (ip) { 12812795Ssam ip->i_flag |= IMOUNT; 12912795Ssam iunlock(ip); 13012795Ssam } 13112795Ssam return (fs); 13212795Ssam out: 13316639Skarels if (error == 0) 13416639Skarels error = EIO; 13512795Ssam if (ip) 13612795Ssam iput(ip); 13712795Ssam if (mp) 13812795Ssam mp->m_bufp = 0; 13912795Ssam if (bp) 14012795Ssam brelse(bp); 14112795Ssam if (tp) 14212795Ssam brelse(tp); 14316639Skarels u.u_error = error; 14412795Ssam return (0); 14512795Ssam } 14612795Ssam 14712795Ssam umount() 14812795Ssam { 14912795Ssam struct a { 15012795Ssam char *fspec; 15116697Smckusick } *uap = (struct a *)u.u_ap; 15212795Ssam 15316697Smckusick u.u_error = unmount1(uap->fspec, 0); 15412795Ssam } 15512795Ssam 15616697Smckusick unmount1(fname, forcibly) 15716697Smckusick caddr_t fname; 15812795Ssam int forcibly; 15912795Ssam { 16012795Ssam dev_t dev; 16112795Ssam register struct mount *mp; 16212795Ssam int stillopen, flag, error; 16312795Ssam register struct inode *ip; 16412795Ssam register struct fs *fs; 16512795Ssam 16616697Smckusick error = getmdev(&dev, fname); 16712795Ssam if (error) 16812795Ssam return (error); 16912795Ssam for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 17012795Ssam if (mp->m_bufp != NULL && dev == mp->m_dev) 17112795Ssam goto found; 17212795Ssam return (EINVAL); 17312795Ssam found: 17412795Ssam xumount(dev); /* remove unused sticky files from text table */ 17515800Smckusick nchinval(dev); /* flush the name cache */ 17612795Ssam update(); 17712795Ssam #ifdef QUOTA 17812795Ssam if ((stillopen = iflush(dev, mp->m_qinod)) < 0 && !forcibly) 17912795Ssam #else 18012795Ssam if ((stillopen = iflush(dev)) < 0 && !forcibly) 18112795Ssam #endif 18212795Ssam return (EBUSY); 18312795Ssam if (stillopen < 0) 18412795Ssam return (EBUSY); /* XXX */ 18512795Ssam #ifdef QUOTA 18612795Ssam closedq(mp); 18712795Ssam /* 18812795Ssam * Here we have to iflush again to get rid of the quota inode. 18912795Ssam * A drag, but it would be ugly to cheat, & this doesn't happen often 19012795Ssam */ 19112795Ssam (void)iflush(dev, (struct inode *)NULL); 19212795Ssam #endif 19312795Ssam ip = mp->m_inodp; 19412795Ssam ip->i_flag &= ~IMOUNT; 19512795Ssam irele(ip); 19612795Ssam fs = mp->m_bufp->b_un.b_fs; 19712795Ssam wmemfree((caddr_t)fs->fs_csp[0], (int)fs->fs_cssize); 19812795Ssam flag = !fs->fs_ronly; 19912795Ssam brelse(mp->m_bufp); 20012795Ssam mp->m_bufp = 0; 20112795Ssam mp->m_dev = 0; 20212795Ssam mpurge(mp - &mount[0]); 20312795Ssam if (!stillopen) { 20412795Ssam (*bdevsw[major(dev)].d_close)(dev, flag); 20512795Ssam binval(dev); 20612795Ssam } 20712795Ssam return (0); 20812795Ssam } 20912795Ssam 21012795Ssam sbupdate(mp) 21112795Ssam struct mount *mp; 21212795Ssam { 21312795Ssam register struct fs *fs = mp->m_bufp->b_un.b_fs; 21412795Ssam register struct buf *bp; 21512795Ssam int blks; 21612795Ssam caddr_t space; 21712795Ssam int i, size; 21812795Ssam 21912795Ssam bp = getblk(mp->m_dev, SBLOCK, (int)fs->fs_sbsize); 22012795Ssam bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize); 22112795Ssam bwrite(bp); 22212795Ssam blks = howmany(fs->fs_cssize, fs->fs_fsize); 22312795Ssam space = (caddr_t)fs->fs_csp[0]; 22412795Ssam for (i = 0; i < blks; i += fs->fs_frag) { 22512795Ssam size = fs->fs_bsize; 22612795Ssam if (i + fs->fs_frag > blks) 22712795Ssam size = (blks - i) * fs->fs_fsize; 22812795Ssam bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size); 22912795Ssam bcopy(space, bp->b_un.b_addr, (u_int)size); 23012795Ssam space += size; 23112795Ssam bwrite(bp); 23212795Ssam } 23312795Ssam } 23412795Ssam 23512795Ssam /* 23612795Ssam * Common code for mount and umount. 23712795Ssam * Check that the user's argument is a reasonable 23812795Ssam * thing on which to mount, and return the device number if so. 23912795Ssam */ 24016697Smckusick getmdev(pdev, fname) 24116697Smckusick caddr_t fname; 24212795Ssam dev_t *pdev; 24312795Ssam { 24412795Ssam dev_t dev; 24512795Ssam register struct inode *ip; 24616697Smckusick register struct nameidata *ndp = &u.u_nd; 24712795Ssam 24812795Ssam if (!suser()) 24912795Ssam return (u.u_error); 25016697Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 25116697Smckusick ndp->ni_segflg = UIO_USERSPACE; 25216697Smckusick ndp->ni_dirp = fname; 25316697Smckusick ip = namei(ndp); 25412795Ssam if (ip == NULL) 25512795Ssam return (u.u_error); 25615956Skarels if ((ip->i_mode&IFMT) != IFBLK) { 25715956Skarels iput(ip); 25812795Ssam return (ENOTBLK); 25915956Skarels } 26012795Ssam dev = (dev_t)ip->i_rdev; 26115956Skarels iput(ip); 26212795Ssam if (major(dev) >= nblkdev) 26312795Ssam return (ENXIO); 26412795Ssam *pdev = dev; 26512795Ssam return (0); 26612795Ssam } 267