1*21013Smckusick /* ffs_vfsops.c 6.10 85/05/22 */ 212795Ssam 317100Sbloom #include "param.h" 417100Sbloom #include "systm.h" 517100Sbloom #include "dir.h" 617100Sbloom #include "user.h" 717100Sbloom #include "inode.h" 817100Sbloom #include "proc.h" 917100Sbloom #include "fs.h" 1017100Sbloom #include "buf.h" 1117100Sbloom #include "mount.h" 1217100Sbloom #include "file.h" 1317100Sbloom #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; 38*21013Smckusick if (ip->i_count != 1) { 3912795Ssam iput(ip); 4012795Ssam u.u_error = EBUSY; 4112795Ssam return; 4212795Ssam } 43*21013Smckusick if ((ip->i_mode&IFMT) != IFDIR) { 44*21013Smckusick iput(ip); 45*21013Smckusick u.u_error = ENOTDIR; 46*21013Smckusick return; 47*21013Smckusick } 4812795Ssam fs = mountfs(dev, uap->ronly, ip); 4912795Ssam if (fs == 0) 5012795Ssam return; 5116705Smckusick (void) copyinstr(uap->freg, fs->fs_fsmnt, sizeof(fs->fs_fsmnt)-1, &len); 5216728Skarels bzero(fs->fs_fsmnt + len, sizeof (fs->fs_fsmnt) - len); 5312795Ssam } 5412795Ssam 5512795Ssam /* this routine has races if running twice */ 5612795Ssam struct fs * 5712795Ssam mountfs(dev, ronly, ip) 5812795Ssam dev_t dev; 5912795Ssam int ronly; 6012795Ssam struct inode *ip; 6112795Ssam { 6212795Ssam register struct mount *mp = 0; 6312795Ssam struct buf *tp = 0; 6412795Ssam register struct buf *bp = 0; 6512795Ssam register struct fs *fs; 6612795Ssam int blks; 6712795Ssam caddr_t space; 6812795Ssam int i, size; 6916639Skarels register error; 70*21013Smckusick int needclose = 0; 7112795Ssam 7216639Skarels error = 7312795Ssam (*bdevsw[major(dev)].d_open)(dev, ronly ? FREAD : FREAD|FWRITE); 7416639Skarels if (error) 7512795Ssam goto out; 76*21013Smckusick needclose = 1; 7712795Ssam tp = bread(dev, SBLOCK, SBSIZE); 7812795Ssam if (tp->b_flags & B_ERROR) 7912795Ssam goto out; 8012795Ssam for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 8112795Ssam if (mp->m_bufp != 0 && dev == mp->m_dev) { 8212795Ssam mp = 0; 8316639Skarels error = EBUSY; 8412795Ssam goto out; 8512795Ssam } 8612795Ssam for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 8712795Ssam if (mp->m_bufp == 0) 8812795Ssam goto found; 8912795Ssam mp = 0; 9016639Skarels error = EMFILE; /* needs translation */ 9112795Ssam goto out; 9212795Ssam found: 9312795Ssam mp->m_bufp = tp; /* just to reserve this slot */ 9412795Ssam mp->m_dev = NODEV; 9512795Ssam fs = tp->b_un.b_fs; 9616639Skarels if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE 9716639Skarels || fs->fs_bsize < sizeof(struct fs)) { 9816639Skarels error = EINVAL; /* also needs translation */ 9916639Skarels goto out; 10016639Skarels } 10112795Ssam bp = geteblk((int)fs->fs_sbsize); 10212795Ssam mp->m_bufp = bp; 10312795Ssam bcopy((caddr_t)tp->b_un.b_addr, (caddr_t)bp->b_un.b_addr, 10412795Ssam (u_int)fs->fs_sbsize); 10512795Ssam brelse(tp); 10612795Ssam tp = 0; 10712795Ssam fs = bp->b_un.b_fs; 10812795Ssam fs->fs_ronly = (ronly != 0); 10912795Ssam if (ronly == 0) 11012795Ssam fs->fs_fmod = 1; 11112795Ssam blks = howmany(fs->fs_cssize, fs->fs_fsize); 11212795Ssam space = wmemall(vmemall, (int)fs->fs_cssize); 11316639Skarels if (space == 0) { 11416639Skarels error = ENOMEM; 11512795Ssam goto out; 11616639Skarels } 11712795Ssam for (i = 0; i < blks; i += fs->fs_frag) { 11812795Ssam size = fs->fs_bsize; 11912795Ssam if (i + fs->fs_frag > blks) 12012795Ssam size = (blks - i) * fs->fs_fsize; 12112795Ssam tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size); 12212795Ssam if (tp->b_flags&B_ERROR) { 12312795Ssam wmemfree(space, (int)fs->fs_cssize); 12412795Ssam goto out; 12512795Ssam } 12612795Ssam bcopy((caddr_t)tp->b_un.b_addr, space, (u_int)size); 12717225Smckusick fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space; 12812795Ssam space += size; 12912795Ssam brelse(tp); 13012795Ssam tp = 0; 13112795Ssam } 13212795Ssam mp->m_inodp = ip; 13312795Ssam mp->m_dev = dev; 13412795Ssam if (ip) { 13512795Ssam ip->i_flag |= IMOUNT; 13612795Ssam iunlock(ip); 13712795Ssam } 13812795Ssam return (fs); 13912795Ssam out: 14016639Skarels if (error == 0) 14116639Skarels error = EIO; 14212795Ssam if (ip) 14312795Ssam iput(ip); 14412795Ssam if (mp) 14512795Ssam mp->m_bufp = 0; 14612795Ssam if (bp) 14712795Ssam brelse(bp); 14812795Ssam if (tp) 14912795Ssam brelse(tp); 150*21013Smckusick if (needclose) 151*21013Smckusick (*bdevsw[major(dev)].d_close)(dev, ronly ? FREAD : FREAD|FWRITE); 152*21013Smckusick binval(dev); 15316639Skarels u.u_error = error; 15412795Ssam return (0); 15512795Ssam } 15612795Ssam 15712795Ssam umount() 15812795Ssam { 15912795Ssam struct a { 16012795Ssam char *fspec; 16116697Smckusick } *uap = (struct a *)u.u_ap; 16212795Ssam 16316697Smckusick u.u_error = unmount1(uap->fspec, 0); 16412795Ssam } 16512795Ssam 16616697Smckusick unmount1(fname, forcibly) 16716697Smckusick caddr_t fname; 16812795Ssam int forcibly; 16912795Ssam { 17012795Ssam dev_t dev; 17112795Ssam register struct mount *mp; 17212795Ssam int stillopen, flag, error; 17312795Ssam register struct inode *ip; 17412795Ssam register struct fs *fs; 17512795Ssam 17616697Smckusick error = getmdev(&dev, fname); 17712795Ssam if (error) 17812795Ssam return (error); 17912795Ssam for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 18012795Ssam if (mp->m_bufp != NULL && dev == mp->m_dev) 18112795Ssam goto found; 18212795Ssam return (EINVAL); 18312795Ssam found: 18412795Ssam xumount(dev); /* remove unused sticky files from text table */ 18515800Smckusick nchinval(dev); /* flush the name cache */ 18612795Ssam update(); 18712795Ssam #ifdef QUOTA 18812795Ssam if ((stillopen = iflush(dev, mp->m_qinod)) < 0 && !forcibly) 18912795Ssam #else 19012795Ssam if ((stillopen = iflush(dev)) < 0 && !forcibly) 19112795Ssam #endif 19212795Ssam return (EBUSY); 19312795Ssam if (stillopen < 0) 19412795Ssam return (EBUSY); /* XXX */ 19512795Ssam #ifdef QUOTA 19612795Ssam closedq(mp); 19712795Ssam /* 19812795Ssam * Here we have to iflush again to get rid of the quota inode. 19912795Ssam * A drag, but it would be ugly to cheat, & this doesn't happen often 20012795Ssam */ 20112795Ssam (void)iflush(dev, (struct inode *)NULL); 20212795Ssam #endif 20312795Ssam ip = mp->m_inodp; 20412795Ssam ip->i_flag &= ~IMOUNT; 20512795Ssam irele(ip); 20612795Ssam fs = mp->m_bufp->b_un.b_fs; 20712795Ssam wmemfree((caddr_t)fs->fs_csp[0], (int)fs->fs_cssize); 20812795Ssam flag = !fs->fs_ronly; 20912795Ssam brelse(mp->m_bufp); 21012795Ssam mp->m_bufp = 0; 21112795Ssam mp->m_dev = 0; 21212795Ssam mpurge(mp - &mount[0]); 21312795Ssam if (!stillopen) { 21412795Ssam (*bdevsw[major(dev)].d_close)(dev, flag); 21512795Ssam binval(dev); 21612795Ssam } 21712795Ssam return (0); 21812795Ssam } 21912795Ssam 22012795Ssam sbupdate(mp) 22112795Ssam struct mount *mp; 22212795Ssam { 22312795Ssam register struct fs *fs = mp->m_bufp->b_un.b_fs; 22412795Ssam register struct buf *bp; 22512795Ssam int blks; 22612795Ssam caddr_t space; 22712795Ssam int i, size; 22812795Ssam 22912795Ssam bp = getblk(mp->m_dev, SBLOCK, (int)fs->fs_sbsize); 23012795Ssam bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize); 23112795Ssam bwrite(bp); 23212795Ssam blks = howmany(fs->fs_cssize, fs->fs_fsize); 23312795Ssam space = (caddr_t)fs->fs_csp[0]; 23412795Ssam for (i = 0; i < blks; i += fs->fs_frag) { 23512795Ssam size = fs->fs_bsize; 23612795Ssam if (i + fs->fs_frag > blks) 23712795Ssam size = (blks - i) * fs->fs_fsize; 23812795Ssam bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size); 23912795Ssam bcopy(space, bp->b_un.b_addr, (u_int)size); 24012795Ssam space += size; 24112795Ssam bwrite(bp); 24212795Ssam } 24312795Ssam } 24412795Ssam 24512795Ssam /* 24612795Ssam * Common code for mount and umount. 24712795Ssam * Check that the user's argument is a reasonable 24812795Ssam * thing on which to mount, and return the device number if so. 24912795Ssam */ 25016697Smckusick getmdev(pdev, fname) 25116697Smckusick caddr_t fname; 25212795Ssam dev_t *pdev; 25312795Ssam { 25412795Ssam dev_t dev; 25512795Ssam register struct inode *ip; 25616697Smckusick register struct nameidata *ndp = &u.u_nd; 25712795Ssam 25812795Ssam if (!suser()) 25912795Ssam return (u.u_error); 26016697Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 26116697Smckusick ndp->ni_segflg = UIO_USERSPACE; 26216697Smckusick ndp->ni_dirp = fname; 26316697Smckusick ip = namei(ndp); 264*21013Smckusick if (ip == NULL) { 265*21013Smckusick if (u.u_error == ENOENT) 266*21013Smckusick return (ENODEV); /* needs translation */ 26712795Ssam return (u.u_error); 268*21013Smckusick } 26915956Skarels if ((ip->i_mode&IFMT) != IFBLK) { 27015956Skarels iput(ip); 27112795Ssam return (ENOTBLK); 27215956Skarels } 27312795Ssam dev = (dev_t)ip->i_rdev; 27415956Skarels iput(ip); 27512795Ssam if (major(dev) >= nblkdev) 27612795Ssam return (ENXIO); 27712795Ssam *pdev = dev; 27812795Ssam return (0); 27912795Ssam } 280