1*16697Smckusick /* lfs_vfsops.c 6.5 84/07/08 */ 212795Ssam 312795Ssam #include "../h/param.h" 412795Ssam #include "../h/systm.h" 512795Ssam #include "../h/dir.h" 612795Ssam #include "../h/user.h" 712795Ssam #include "../h/inode.h" 812795Ssam #include "../h/proc.h" 912795Ssam #include "../h/fs.h" 1012795Ssam #include "../h/buf.h" 1112795Ssam #include "../h/mount.h" 1212795Ssam #include "../h/file.h" 1312795Ssam #include "../h/conf.h" 1412795Ssam 1512795Ssam smount() 1612795Ssam { 1712795Ssam register struct a { 1812795Ssam char *fspec; 1912795Ssam char *freg; 2012795Ssam int ronly; 21*16697Smckusick } *uap = (struct a *)u.u_ap; 2212795Ssam dev_t dev; 2312795Ssam register struct inode *ip; 2412795Ssam register struct fs *fs; 2512795Ssam register char *cp; 26*16697Smckusick register struct nameidata *ndp = &u.u_nd; 2712795Ssam 28*16697Smckusick u.u_error = getmdev(&dev, uap->fspec); 2912795Ssam if (u.u_error) 3012795Ssam return; 31*16697Smckusick ndp->ni_nameiop = LOOKUP | NOCACHE | FOLLOW; 32*16697Smckusick ndp->ni_segflg = UIO_USERSPACE; 33*16697Smckusick ndp->ni_dirp = (caddr_t)uap->freg; 34*16697Smckusick ip = namei(ndp); 3512795Ssam if (ip == NULL) 3612795Ssam return; 3712795Ssam if (ip->i_count!=1 || (ip->i_mode&IFMT) != IFDIR) { 3812795Ssam iput(ip); 3912795Ssam u.u_error = EBUSY; 4012795Ssam return; 4112795Ssam } 4212795Ssam fs = mountfs(dev, uap->ronly, ip); 4312795Ssam if (fs == 0) 4412795Ssam return; 45*16697Smckusick bzero(fs->fs_fsmnt, sizeof(fs->fs_fsmnt)); 46*16697Smckusick copyinstr(uap->freg, fs->fs_fsmnt, sizeof(fs->fs_fsmnt)); 4712795Ssam } 4812795Ssam 4912795Ssam /* this routine has races if running twice */ 5012795Ssam struct fs * 5112795Ssam mountfs(dev, ronly, ip) 5212795Ssam dev_t dev; 5312795Ssam int ronly; 5412795Ssam struct inode *ip; 5512795Ssam { 5612795Ssam register struct mount *mp = 0; 5712795Ssam struct buf *tp = 0; 5812795Ssam register struct buf *bp = 0; 5912795Ssam register struct fs *fs; 6012795Ssam int blks; 6112795Ssam caddr_t space; 6212795Ssam int i, size; 6316639Skarels register error; 6412795Ssam 6516639Skarels error = 6612795Ssam (*bdevsw[major(dev)].d_open)(dev, ronly ? FREAD : FREAD|FWRITE); 6716639Skarels if (error) 6812795Ssam goto out; 6912795Ssam tp = bread(dev, SBLOCK, SBSIZE); 7012795Ssam if (tp->b_flags & B_ERROR) 7112795Ssam goto out; 7212795Ssam for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 7312795Ssam if (mp->m_bufp != 0 && dev == mp->m_dev) { 7412795Ssam mp = 0; 7516639Skarels error = EBUSY; 7612795Ssam goto out; 7712795Ssam } 7812795Ssam for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 7912795Ssam if (mp->m_bufp == 0) 8012795Ssam goto found; 8112795Ssam mp = 0; 8216639Skarels error = EMFILE; /* needs translation */ 8312795Ssam goto out; 8412795Ssam found: 8512795Ssam mp->m_bufp = tp; /* just to reserve this slot */ 8612795Ssam mp->m_dev = NODEV; 8712795Ssam fs = tp->b_un.b_fs; 8816639Skarels if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE 8916639Skarels || fs->fs_bsize < sizeof(struct fs)) { 9016639Skarels error = EINVAL; /* also needs translation */ 9116639Skarels goto out; 9216639Skarels } 9312795Ssam bp = geteblk((int)fs->fs_sbsize); 9412795Ssam mp->m_bufp = bp; 9512795Ssam bcopy((caddr_t)tp->b_un.b_addr, (caddr_t)bp->b_un.b_addr, 9612795Ssam (u_int)fs->fs_sbsize); 9712795Ssam brelse(tp); 9812795Ssam tp = 0; 9912795Ssam fs = bp->b_un.b_fs; 10012795Ssam fs->fs_ronly = (ronly != 0); 10112795Ssam if (ronly == 0) 10212795Ssam fs->fs_fmod = 1; 10312795Ssam blks = howmany(fs->fs_cssize, fs->fs_fsize); 10412795Ssam space = wmemall(vmemall, (int)fs->fs_cssize); 10516639Skarels if (space == 0) { 10616639Skarels error = ENOMEM; 10712795Ssam goto out; 10816639Skarels } 10912795Ssam for (i = 0; i < blks; i += fs->fs_frag) { 11012795Ssam size = fs->fs_bsize; 11112795Ssam if (i + fs->fs_frag > blks) 11212795Ssam size = (blks - i) * fs->fs_fsize; 11312795Ssam tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size); 11412795Ssam if (tp->b_flags&B_ERROR) { 11512795Ssam wmemfree(space, (int)fs->fs_cssize); 11612795Ssam goto out; 11712795Ssam } 11812795Ssam bcopy((caddr_t)tp->b_un.b_addr, space, (u_int)size); 11912795Ssam fs->fs_csp[i / fs->fs_frag] = (struct csum *)space; 12012795Ssam space += size; 12112795Ssam brelse(tp); 12212795Ssam tp = 0; 12312795Ssam } 12412795Ssam mp->m_inodp = ip; 12512795Ssam mp->m_dev = dev; 12612795Ssam if (ip) { 12712795Ssam ip->i_flag |= IMOUNT; 12812795Ssam iunlock(ip); 12912795Ssam } 13012795Ssam return (fs); 13112795Ssam out: 13216639Skarels if (error == 0) 13316639Skarels error = EIO; 13412795Ssam if (ip) 13512795Ssam iput(ip); 13612795Ssam if (mp) 13712795Ssam mp->m_bufp = 0; 13812795Ssam if (bp) 13912795Ssam brelse(bp); 14012795Ssam if (tp) 14112795Ssam brelse(tp); 14216639Skarels u.u_error = error; 14312795Ssam return (0); 14412795Ssam } 14512795Ssam 14612795Ssam umount() 14712795Ssam { 14812795Ssam struct a { 14912795Ssam char *fspec; 150*16697Smckusick } *uap = (struct a *)u.u_ap; 15112795Ssam 152*16697Smckusick u.u_error = unmount1(uap->fspec, 0); 15312795Ssam } 15412795Ssam 155*16697Smckusick unmount1(fname, forcibly) 156*16697Smckusick caddr_t fname; 15712795Ssam int forcibly; 15812795Ssam { 15912795Ssam dev_t dev; 16012795Ssam register struct mount *mp; 16112795Ssam int stillopen, flag, error; 16212795Ssam register struct inode *ip; 16312795Ssam register struct fs *fs; 16412795Ssam 165*16697Smckusick error = getmdev(&dev, fname); 16612795Ssam if (error) 16712795Ssam return (error); 16812795Ssam for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 16912795Ssam if (mp->m_bufp != NULL && dev == mp->m_dev) 17012795Ssam goto found; 17112795Ssam return (EINVAL); 17212795Ssam found: 17312795Ssam xumount(dev); /* remove unused sticky files from text table */ 17415800Smckusick nchinval(dev); /* flush the name cache */ 17512795Ssam update(); 17612795Ssam #ifdef QUOTA 17712795Ssam if ((stillopen = iflush(dev, mp->m_qinod)) < 0 && !forcibly) 17812795Ssam #else 17912795Ssam if ((stillopen = iflush(dev)) < 0 && !forcibly) 18012795Ssam #endif 18112795Ssam return (EBUSY); 18212795Ssam if (stillopen < 0) 18312795Ssam return (EBUSY); /* XXX */ 18412795Ssam #ifdef QUOTA 18512795Ssam closedq(mp); 18612795Ssam /* 18712795Ssam * Here we have to iflush again to get rid of the quota inode. 18812795Ssam * A drag, but it would be ugly to cheat, & this doesn't happen often 18912795Ssam */ 19012795Ssam (void)iflush(dev, (struct inode *)NULL); 19112795Ssam #endif 19212795Ssam ip = mp->m_inodp; 19312795Ssam ip->i_flag &= ~IMOUNT; 19412795Ssam irele(ip); 19512795Ssam fs = mp->m_bufp->b_un.b_fs; 19612795Ssam wmemfree((caddr_t)fs->fs_csp[0], (int)fs->fs_cssize); 19712795Ssam flag = !fs->fs_ronly; 19812795Ssam brelse(mp->m_bufp); 19912795Ssam mp->m_bufp = 0; 20012795Ssam mp->m_dev = 0; 20112795Ssam mpurge(mp - &mount[0]); 20212795Ssam if (!stillopen) { 20312795Ssam (*bdevsw[major(dev)].d_close)(dev, flag); 20412795Ssam binval(dev); 20512795Ssam } 20612795Ssam return (0); 20712795Ssam } 20812795Ssam 20912795Ssam sbupdate(mp) 21012795Ssam struct mount *mp; 21112795Ssam { 21212795Ssam register struct fs *fs = mp->m_bufp->b_un.b_fs; 21312795Ssam register struct buf *bp; 21412795Ssam int blks; 21512795Ssam caddr_t space; 21612795Ssam int i, size; 21712795Ssam 21812795Ssam bp = getblk(mp->m_dev, SBLOCK, (int)fs->fs_sbsize); 21912795Ssam bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize); 22012795Ssam bwrite(bp); 22112795Ssam blks = howmany(fs->fs_cssize, fs->fs_fsize); 22212795Ssam space = (caddr_t)fs->fs_csp[0]; 22312795Ssam for (i = 0; i < blks; i += fs->fs_frag) { 22412795Ssam size = fs->fs_bsize; 22512795Ssam if (i + fs->fs_frag > blks) 22612795Ssam size = (blks - i) * fs->fs_fsize; 22712795Ssam bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size); 22812795Ssam bcopy(space, bp->b_un.b_addr, (u_int)size); 22912795Ssam space += size; 23012795Ssam bwrite(bp); 23112795Ssam } 23212795Ssam } 23312795Ssam 23412795Ssam /* 23512795Ssam * Common code for mount and umount. 23612795Ssam * Check that the user's argument is a reasonable 23712795Ssam * thing on which to mount, and return the device number if so. 23812795Ssam */ 239*16697Smckusick getmdev(pdev, fname) 240*16697Smckusick caddr_t fname; 24112795Ssam dev_t *pdev; 24212795Ssam { 24312795Ssam dev_t dev; 24412795Ssam register struct inode *ip; 245*16697Smckusick register struct nameidata *ndp = &u.u_nd; 24612795Ssam 24712795Ssam if (!suser()) 24812795Ssam return (u.u_error); 249*16697Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 250*16697Smckusick ndp->ni_segflg = UIO_USERSPACE; 251*16697Smckusick ndp->ni_dirp = fname; 252*16697Smckusick ip = namei(ndp); 25312795Ssam if (ip == NULL) 25412795Ssam return (u.u_error); 25515956Skarels if ((ip->i_mode&IFMT) != IFBLK) { 25615956Skarels iput(ip); 25712795Ssam return (ENOTBLK); 25815956Skarels } 25912795Ssam dev = (dev_t)ip->i_rdev; 26015956Skarels iput(ip); 26112795Ssam if (major(dev) >= nblkdev) 26212795Ssam return (ENXIO); 26312795Ssam *pdev = dev; 26412795Ssam return (0); 26512795Ssam } 266