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*30383Smckusick * @(#)lfs_vfsops.c 7.2 (Berkeley) 01/13/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" 2012795Ssam 2112795Ssam smount() 2212795Ssam { 2312795Ssam register struct a { 2412795Ssam char *fspec; 2512795Ssam char *freg; 2612795Ssam int ronly; 2716697Smckusick } *uap = (struct a *)u.u_ap; 2812795Ssam dev_t dev; 2912795Ssam register struct inode *ip; 3012795Ssam register struct fs *fs; 3116697Smckusick register struct nameidata *ndp = &u.u_nd; 3216705Smckusick u_int len; 3312795Ssam 3416697Smckusick u.u_error = getmdev(&dev, uap->fspec); 3512795Ssam if (u.u_error) 3612795Ssam return; 3727267Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 3816697Smckusick ndp->ni_segflg = UIO_USERSPACE; 3916697Smckusick ndp->ni_dirp = (caddr_t)uap->freg; 4016697Smckusick ip = namei(ndp); 4112795Ssam if (ip == NULL) 4212795Ssam return; 4321013Smckusick if (ip->i_count != 1) { 4412795Ssam iput(ip); 4512795Ssam u.u_error = EBUSY; 4612795Ssam return; 4712795Ssam } 4821013Smckusick if ((ip->i_mode&IFMT) != IFDIR) { 4921013Smckusick iput(ip); 5021013Smckusick u.u_error = ENOTDIR; 5121013Smckusick return; 5221013Smckusick } 5312795Ssam fs = mountfs(dev, uap->ronly, ip); 5412795Ssam if (fs == 0) 5512795Ssam return; 5616705Smckusick (void) copyinstr(uap->freg, fs->fs_fsmnt, sizeof(fs->fs_fsmnt)-1, &len); 5716728Skarels bzero(fs->fs_fsmnt + len, sizeof (fs->fs_fsmnt) - len); 5812795Ssam } 5912795Ssam 6012795Ssam /* this routine has races if running twice */ 6112795Ssam struct fs * 6212795Ssam mountfs(dev, ronly, ip) 6312795Ssam dev_t dev; 6412795Ssam int ronly; 6512795Ssam struct inode *ip; 6612795Ssam { 6712795Ssam register struct mount *mp = 0; 6812795Ssam struct buf *tp = 0; 6912795Ssam register struct buf *bp = 0; 7012795Ssam register struct fs *fs; 7112795Ssam int blks; 7212795Ssam caddr_t space; 7312795Ssam int i, size; 7416639Skarels register error; 7521013Smckusick int needclose = 0; 7612795Ssam 7716639Skarels error = 7812795Ssam (*bdevsw[major(dev)].d_open)(dev, ronly ? FREAD : FREAD|FWRITE); 7916639Skarels if (error) 8012795Ssam goto out; 8121013Smckusick needclose = 1; 8212795Ssam tp = bread(dev, SBLOCK, SBSIZE); 8312795Ssam if (tp->b_flags & B_ERROR) 8412795Ssam goto out; 8512795Ssam for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 8612795Ssam if (mp->m_bufp != 0 && dev == mp->m_dev) { 8712795Ssam mp = 0; 8816639Skarels error = EBUSY; 8926224Skarels needclose = 0; 9012795Ssam goto out; 9112795Ssam } 9212795Ssam for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 9312795Ssam if (mp->m_bufp == 0) 9412795Ssam goto found; 9512795Ssam mp = 0; 9616639Skarels error = EMFILE; /* needs translation */ 9712795Ssam goto out; 9812795Ssam found: 9912795Ssam mp->m_bufp = tp; /* just to reserve this slot */ 10012795Ssam mp->m_dev = NODEV; 10112795Ssam fs = tp->b_un.b_fs; 10216639Skarels if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE 10316639Skarels || fs->fs_bsize < sizeof(struct fs)) { 10416639Skarels error = EINVAL; /* also needs translation */ 10516639Skarels goto out; 10616639Skarels } 10712795Ssam bp = geteblk((int)fs->fs_sbsize); 10812795Ssam mp->m_bufp = bp; 10912795Ssam bcopy((caddr_t)tp->b_un.b_addr, (caddr_t)bp->b_un.b_addr, 11012795Ssam (u_int)fs->fs_sbsize); 11112795Ssam brelse(tp); 11212795Ssam tp = 0; 11312795Ssam fs = bp->b_un.b_fs; 11412795Ssam fs->fs_ronly = (ronly != 0); 11512795Ssam if (ronly == 0) 11612795Ssam fs->fs_fmod = 1; 11712795Ssam blks = howmany(fs->fs_cssize, fs->fs_fsize); 11812795Ssam space = wmemall(vmemall, (int)fs->fs_cssize); 11916639Skarels if (space == 0) { 12016639Skarels error = ENOMEM; 12112795Ssam goto out; 12216639Skarels } 12312795Ssam for (i = 0; i < blks; i += fs->fs_frag) { 12412795Ssam size = fs->fs_bsize; 12512795Ssam if (i + fs->fs_frag > blks) 12612795Ssam size = (blks - i) * fs->fs_fsize; 12712795Ssam tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size); 12812795Ssam if (tp->b_flags&B_ERROR) { 12912795Ssam wmemfree(space, (int)fs->fs_cssize); 13012795Ssam goto out; 13112795Ssam } 13212795Ssam bcopy((caddr_t)tp->b_un.b_addr, space, (u_int)size); 13317225Smckusick fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space; 13412795Ssam space += size; 13512795Ssam brelse(tp); 13612795Ssam tp = 0; 13712795Ssam } 13812795Ssam mp->m_inodp = ip; 13912795Ssam mp->m_dev = dev; 14012795Ssam if (ip) { 14112795Ssam ip->i_flag |= IMOUNT; 14227267Smckusick cacheinval(ip); 14312795Ssam iunlock(ip); 14412795Ssam } 145*30383Smckusick /* Sanity checks for old file systems. XXX */ 146*30383Smckusick fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect); /* XXX */ 147*30383Smckusick fs->fs_interleave = MAX(fs->fs_interleave, 1); /* XXX */ 14812795Ssam return (fs); 14912795Ssam out: 15016639Skarels if (error == 0) 15116639Skarels error = EIO; 15212795Ssam if (ip) 15312795Ssam iput(ip); 15412795Ssam if (mp) 15512795Ssam mp->m_bufp = 0; 15612795Ssam if (bp) 15712795Ssam brelse(bp); 15812795Ssam if (tp) 15912795Ssam brelse(tp); 16026224Skarels if (needclose) { 16126224Skarels (*bdevsw[major(dev)].d_close)(dev, ronly? FREAD : FREAD|FWRITE); 16226224Skarels binval(dev); 16326224Skarels } 16416639Skarels u.u_error = error; 16512795Ssam return (0); 16612795Ssam } 16712795Ssam 16812795Ssam umount() 16912795Ssam { 17012795Ssam struct a { 17112795Ssam char *fspec; 17216697Smckusick } *uap = (struct a *)u.u_ap; 17312795Ssam 17416697Smckusick u.u_error = unmount1(uap->fspec, 0); 17512795Ssam } 17612795Ssam 17716697Smckusick unmount1(fname, forcibly) 17816697Smckusick caddr_t fname; 17912795Ssam int forcibly; 18012795Ssam { 18112795Ssam dev_t dev; 18212795Ssam register struct mount *mp; 18312795Ssam int stillopen, flag, error; 18412795Ssam register struct inode *ip; 18512795Ssam register struct fs *fs; 18612795Ssam 18716697Smckusick error = getmdev(&dev, fname); 18812795Ssam if (error) 18912795Ssam return (error); 19012795Ssam for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 19112795Ssam if (mp->m_bufp != NULL && dev == mp->m_dev) 19212795Ssam goto found; 19312795Ssam return (EINVAL); 19412795Ssam found: 19512795Ssam xumount(dev); /* remove unused sticky files from text table */ 19615800Smckusick nchinval(dev); /* flush the name cache */ 19712795Ssam update(); 19812795Ssam #ifdef QUOTA 19912795Ssam if ((stillopen = iflush(dev, mp->m_qinod)) < 0 && !forcibly) 20012795Ssam #else 20112795Ssam if ((stillopen = iflush(dev)) < 0 && !forcibly) 20212795Ssam #endif 20312795Ssam return (EBUSY); 20412795Ssam if (stillopen < 0) 20512795Ssam return (EBUSY); /* XXX */ 20612795Ssam #ifdef QUOTA 20712795Ssam closedq(mp); 20812795Ssam /* 20912795Ssam * Here we have to iflush again to get rid of the quota inode. 21012795Ssam * A drag, but it would be ugly to cheat, & this doesn't happen often 21112795Ssam */ 21212795Ssam (void)iflush(dev, (struct inode *)NULL); 21312795Ssam #endif 21412795Ssam ip = mp->m_inodp; 21512795Ssam ip->i_flag &= ~IMOUNT; 21612795Ssam irele(ip); 21712795Ssam fs = mp->m_bufp->b_un.b_fs; 21812795Ssam wmemfree((caddr_t)fs->fs_csp[0], (int)fs->fs_cssize); 21912795Ssam flag = !fs->fs_ronly; 22012795Ssam brelse(mp->m_bufp); 22112795Ssam mp->m_bufp = 0; 22212795Ssam mp->m_dev = 0; 22312795Ssam mpurge(mp - &mount[0]); 22412795Ssam if (!stillopen) { 22512795Ssam (*bdevsw[major(dev)].d_close)(dev, flag); 22612795Ssam binval(dev); 22712795Ssam } 22812795Ssam return (0); 22912795Ssam } 23012795Ssam 23112795Ssam sbupdate(mp) 23212795Ssam struct mount *mp; 23312795Ssam { 23412795Ssam register struct fs *fs = mp->m_bufp->b_un.b_fs; 23512795Ssam register struct buf *bp; 23612795Ssam int blks; 23712795Ssam caddr_t space; 23812795Ssam int i, size; 23912795Ssam 24012795Ssam bp = getblk(mp->m_dev, SBLOCK, (int)fs->fs_sbsize); 24112795Ssam bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize); 24212795Ssam bwrite(bp); 24312795Ssam blks = howmany(fs->fs_cssize, fs->fs_fsize); 24412795Ssam space = (caddr_t)fs->fs_csp[0]; 24512795Ssam for (i = 0; i < blks; i += fs->fs_frag) { 24612795Ssam size = fs->fs_bsize; 24712795Ssam if (i + fs->fs_frag > blks) 24812795Ssam size = (blks - i) * fs->fs_fsize; 24912795Ssam bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size); 25012795Ssam bcopy(space, bp->b_un.b_addr, (u_int)size); 25112795Ssam space += size; 25212795Ssam bwrite(bp); 25312795Ssam } 25412795Ssam } 25512795Ssam 25612795Ssam /* 25712795Ssam * Common code for mount and umount. 25812795Ssam * Check that the user's argument is a reasonable 25912795Ssam * thing on which to mount, and return the device number if so. 26012795Ssam */ 26116697Smckusick getmdev(pdev, fname) 26216697Smckusick caddr_t fname; 26312795Ssam dev_t *pdev; 26412795Ssam { 26512795Ssam dev_t dev; 26612795Ssam register struct inode *ip; 26716697Smckusick register struct nameidata *ndp = &u.u_nd; 26812795Ssam 26912795Ssam if (!suser()) 27012795Ssam return (u.u_error); 27116697Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 27216697Smckusick ndp->ni_segflg = UIO_USERSPACE; 27316697Smckusick ndp->ni_dirp = fname; 27416697Smckusick ip = namei(ndp); 27521013Smckusick if (ip == NULL) { 27621013Smckusick if (u.u_error == ENOENT) 27721013Smckusick return (ENODEV); /* needs translation */ 27812795Ssam return (u.u_error); 27921013Smckusick } 28015956Skarels if ((ip->i_mode&IFMT) != IFBLK) { 28115956Skarels iput(ip); 28212795Ssam return (ENOTBLK); 28315956Skarels } 28412795Ssam dev = (dev_t)ip->i_rdev; 28515956Skarels iput(ip); 28612795Ssam if (major(dev) >= nblkdev) 28712795Ssam return (ENXIO); 28812795Ssam *pdev = dev; 28912795Ssam return (0); 29012795Ssam } 291