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*34356Skarels * @(#)lfs_vfsops.c 7.9 (Berkeley) 05/19/88 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" 2331660Smckusick #include "malloc.h" 2412795Ssam 2512795Ssam smount() 2612795Ssam { 2712795Ssam register struct a { 2812795Ssam char *fspec; 2912795Ssam char *freg; 3012795Ssam int ronly; 3116697Smckusick } *uap = (struct a *)u.u_ap; 3212795Ssam dev_t dev; 3312795Ssam register struct inode *ip; 3412795Ssam register struct fs *fs; 3516697Smckusick register struct nameidata *ndp = &u.u_nd; 3616705Smckusick u_int len; 3712795Ssam 3816697Smckusick u.u_error = getmdev(&dev, uap->fspec); 3912795Ssam if (u.u_error) 4012795Ssam return; 4127267Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 4216697Smckusick ndp->ni_segflg = UIO_USERSPACE; 4316697Smckusick ndp->ni_dirp = (caddr_t)uap->freg; 4416697Smckusick ip = namei(ndp); 4512795Ssam if (ip == NULL) 4612795Ssam return; 4721013Smckusick if (ip->i_count != 1) { 4812795Ssam iput(ip); 4912795Ssam u.u_error = EBUSY; 5012795Ssam return; 5112795Ssam } 5221013Smckusick if ((ip->i_mode&IFMT) != IFDIR) { 5321013Smckusick iput(ip); 5421013Smckusick u.u_error = ENOTDIR; 5521013Smckusick return; 5621013Smckusick } 5712795Ssam fs = mountfs(dev, uap->ronly, ip); 5832721Smckusick if (fs == 0) { 5932721Smckusick iput(ip); 6012795Ssam return; 6132721Smckusick } 6216705Smckusick (void) copyinstr(uap->freg, fs->fs_fsmnt, sizeof(fs->fs_fsmnt)-1, &len); 6316728Skarels bzero(fs->fs_fsmnt + len, sizeof (fs->fs_fsmnt) - len); 6412795Ssam } 6512795Ssam 6612795Ssam struct fs * 6712795Ssam mountfs(dev, ronly, ip) 6812795Ssam dev_t dev; 6912795Ssam int ronly; 7012795Ssam struct inode *ip; 7112795Ssam { 7232721Smckusick register struct mount *mp; 7332721Smckusick struct mount *fmp = NULL; 7432721Smckusick struct buf *tp = NULL; 7532721Smckusick register struct buf *bp = NULL; 7612795Ssam register struct fs *fs; 7730749Skarels struct partinfo dpart; 7830749Skarels int havepart = 0, blks; 7932721Smckusick caddr_t base, space; 8012795Ssam int i, size; 8116639Skarels register error; 8221013Smckusick int needclose = 0; 8312795Ssam 8432721Smckusick for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) { 8532721Smckusick if (mp->m_fs == NULL) { 8632721Smckusick if (fmp == NULL) 8732721Smckusick fmp = mp; 8832721Smckusick } else if (dev == mp->m_dev) { 8932721Smckusick u.u_error = EBUSY; /* XXX */ 9032721Smckusick return ((struct fs *) NULL); 9132721Smckusick } 9232721Smckusick } 9332721Smckusick if ((mp = fmp) == NULL) { 9432721Smckusick u.u_error = EMFILE; /* needs translation XXX */ 9532721Smckusick return ((struct fs *) NULL); 9632721Smckusick } 9732721Smckusick mp->m_fs = (struct fs *)1; /* just to reserve this slot */ 9832721Smckusick mp->m_dev = dev; 99*34356Skarels mp->m_inodp = NULL; 10016639Skarels error = 10130749Skarels (*bdevsw[major(dev)].d_open)(dev, ronly ? FREAD : FREAD|FWRITE, 10230749Skarels S_IFBLK); 10332721Smckusick if (error) { 10432721Smckusick u.u_error = error; 10532721Smckusick mp->m_fs = NULL; 10632721Smckusick return ((struct fs *) NULL); 10732721Smckusick } 10821013Smckusick needclose = 1; 10930749Skarels if ((*bdevsw[major(dev)].d_ioctl)(dev, DIOCGPART, 11030749Skarels (caddr_t)&dpart, FREAD) == 0) { 11130749Skarels havepart = 1; 11230749Skarels size = dpart.disklab->d_secsize; 11330749Skarels } else 11430749Skarels size = DEV_BSIZE; 11512795Ssam tp = bread(dev, SBLOCK, SBSIZE); 11632721Smckusick if (tp->b_flags & B_ERROR) { 11732721Smckusick mp->m_fs = NULL; 11812795Ssam goto out; 11932721Smckusick } 12032721Smckusick fs = tp->b_un.b_fs; 12130749Skarels if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || 12230749Skarels fs->fs_bsize < sizeof(struct fs)) { 12331660Smckusick mp->m_fs = NULL; 12416639Skarels error = EINVAL; /* also needs translation */ 12516639Skarels goto out; 12616639Skarels } 12731660Smckusick mp->m_fs = (struct fs *)malloc(fs->fs_sbsize, M_SUPERBLK, M_WAITOK); 12831660Smckusick bcopy((caddr_t)tp->b_un.b_addr, (caddr_t)mp->m_fs, 12912795Ssam (u_int)fs->fs_sbsize); 13012795Ssam brelse(tp); 13132721Smckusick tp = NULL; 13231660Smckusick fs = mp->m_fs; 13312795Ssam fs->fs_ronly = (ronly != 0); 13412795Ssam if (ronly == 0) 13512795Ssam fs->fs_fmod = 1; 13630749Skarels if (havepart) { 13730749Skarels dpart.part->p_fstype = FS_BSDFFS; 13830749Skarels dpart.part->p_fsize = fs->fs_fsize; 13930749Skarels dpart.part->p_frag = fs->fs_frag; 14031385Skarels dpart.part->p_cpg = fs->fs_cpg; 14130749Skarels } 14212795Ssam blks = howmany(fs->fs_cssize, fs->fs_fsize); 14332721Smckusick base = space = (caddr_t)malloc(fs->fs_cssize, M_SUPERBLK, M_WAITOK); 14432721Smckusick if (space == NULL) { 14516639Skarels error = ENOMEM; 14612795Ssam goto out; 14716639Skarels } 14812795Ssam for (i = 0; i < blks; i += fs->fs_frag) { 14912795Ssam size = fs->fs_bsize; 15012795Ssam if (i + fs->fs_frag > blks) 15112795Ssam size = (blks - i) * fs->fs_fsize; 15212795Ssam tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size); 15312795Ssam if (tp->b_flags&B_ERROR) { 15432721Smckusick free(base, M_SUPERBLK); 15512795Ssam goto out; 15612795Ssam } 15712795Ssam bcopy((caddr_t)tp->b_un.b_addr, space, (u_int)size); 15817225Smckusick fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space; 15912795Ssam space += size; 16012795Ssam brelse(tp); 16132721Smckusick tp = NULL; 16212795Ssam } 16312795Ssam mp->m_inodp = ip; 16412795Ssam if (ip) { 16512795Ssam ip->i_flag |= IMOUNT; 16627267Smckusick cacheinval(ip); 16712795Ssam iunlock(ip); 16812795Ssam } 16930383Smckusick /* Sanity checks for old file systems. XXX */ 17030383Smckusick fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect); /* XXX */ 17130383Smckusick fs->fs_interleave = MAX(fs->fs_interleave, 1); /* XXX */ 17234145Smckusick if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 17334145Smckusick fs->fs_nrpos = 8; /* XXX */ 17412795Ssam return (fs); 17512795Ssam out: 17632721Smckusick if (needclose) 17732721Smckusick (void) closei(dev, IFBLK, ronly? FREAD : FREAD|FWRITE); 17832721Smckusick if (mp->m_fs) { 17931660Smckusick free((caddr_t)mp->m_fs, M_SUPERBLK); 18032721Smckusick mp->m_fs = NULL; 18132721Smckusick } 18212795Ssam if (tp) 18312795Ssam brelse(tp); 18432721Smckusick u.u_error = error ? error : EIO; /* XXX */ 18532721Smckusick return ((struct fs *) NULL); 18612795Ssam } 18712795Ssam 18812795Ssam umount() 18912795Ssam { 19012795Ssam struct a { 19112795Ssam char *fspec; 19216697Smckusick } *uap = (struct a *)u.u_ap; 19312795Ssam 19416697Smckusick u.u_error = unmount1(uap->fspec, 0); 19512795Ssam } 19612795Ssam 19716697Smckusick unmount1(fname, forcibly) 19816697Smckusick caddr_t fname; 19912795Ssam int forcibly; 20012795Ssam { 20112795Ssam dev_t dev; 20212795Ssam register struct mount *mp; 20330749Skarels int error; 20412795Ssam register struct inode *ip; 20512795Ssam register struct fs *fs; 20612795Ssam 20730749Skarels forcibly = 0; /* XXX */ 20816697Smckusick error = getmdev(&dev, fname); 20912795Ssam if (error) 21012795Ssam return (error); 21112795Ssam for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 21231660Smckusick if (mp->m_fs != NULL && dev == mp->m_dev) 21312795Ssam goto found; 21412795Ssam return (EINVAL); 21512795Ssam found: 21612795Ssam xumount(dev); /* remove unused sticky files from text table */ 21715800Smckusick nchinval(dev); /* flush the name cache */ 21812795Ssam update(); 21912795Ssam #ifdef QUOTA 22030749Skarels if ((error = iflush(dev, mp->m_qinod)) && !forcibly) 22112795Ssam #else 22230749Skarels if ((error = iflush(dev)) && !forcibly) 22312795Ssam #endif 22430749Skarels return (error); 22512795Ssam #ifdef QUOTA 22612795Ssam closedq(mp); 22712795Ssam /* 22812795Ssam * Here we have to iflush again to get rid of the quota inode. 22930749Skarels * A drag, but it would be ugly to cheat, & this doesn't happen often. 23012795Ssam */ 23112795Ssam (void)iflush(dev, (struct inode *)NULL); 23212795Ssam #endif 23312795Ssam ip = mp->m_inodp; 23412795Ssam ip->i_flag &= ~IMOUNT; 23531660Smckusick fs = mp->m_fs; 23631660Smckusick free((caddr_t)fs->fs_csp[0], M_SUPERBLK); 23731660Smckusick free((caddr_t)mp->m_fs, M_SUPERBLK); 23832721Smckusick mp->m_fs = NULL; 23932721Smckusick mp->m_dev = NODEV; 24012795Ssam mpurge(mp - &mount[0]); 24130749Skarels error = closei(dev, IFBLK, fs->fs_ronly? FREAD : FREAD|FWRITE); 24230749Skarels irele(ip); 24330749Skarels return (error); 24412795Ssam } 24512795Ssam 24612795Ssam sbupdate(mp) 24712795Ssam struct mount *mp; 24812795Ssam { 24931660Smckusick register struct fs *fs = mp->m_fs; 25012795Ssam register struct buf *bp; 25112795Ssam int blks; 25212795Ssam caddr_t space; 25312795Ssam int i, size; 25412795Ssam 25512795Ssam bp = getblk(mp->m_dev, SBLOCK, (int)fs->fs_sbsize); 25612795Ssam bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize); 25734145Smckusick /* Restore compatibility to old file systems. XXX */ 25834145Smckusick if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 25934145Smckusick bp->b_un.b_fs->fs_nrpos = -1; /* XXX */ 26012795Ssam bwrite(bp); 26112795Ssam blks = howmany(fs->fs_cssize, fs->fs_fsize); 26212795Ssam space = (caddr_t)fs->fs_csp[0]; 26312795Ssam for (i = 0; i < blks; i += fs->fs_frag) { 26412795Ssam size = fs->fs_bsize; 26512795Ssam if (i + fs->fs_frag > blks) 26612795Ssam size = (blks - i) * fs->fs_fsize; 26712795Ssam bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size); 26812795Ssam bcopy(space, bp->b_un.b_addr, (u_int)size); 26912795Ssam space += size; 27012795Ssam bwrite(bp); 27112795Ssam } 27212795Ssam } 27312795Ssam 27412795Ssam /* 27512795Ssam * Common code for mount and umount. 27612795Ssam * Check that the user's argument is a reasonable 27712795Ssam * thing on which to mount, and return the device number if so. 27812795Ssam */ 27916697Smckusick getmdev(pdev, fname) 28016697Smckusick caddr_t fname; 28112795Ssam dev_t *pdev; 28212795Ssam { 28312795Ssam dev_t dev; 28412795Ssam register struct inode *ip; 28516697Smckusick register struct nameidata *ndp = &u.u_nd; 28612795Ssam 28712795Ssam if (!suser()) 28812795Ssam return (u.u_error); 28916697Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 29016697Smckusick ndp->ni_segflg = UIO_USERSPACE; 29116697Smckusick ndp->ni_dirp = fname; 29216697Smckusick ip = namei(ndp); 29321013Smckusick if (ip == NULL) { 29421013Smckusick if (u.u_error == ENOENT) 29521013Smckusick return (ENODEV); /* needs translation */ 29612795Ssam return (u.u_error); 29721013Smckusick } 29815956Skarels if ((ip->i_mode&IFMT) != IFBLK) { 29915956Skarels iput(ip); 30012795Ssam return (ENOTBLK); 30115956Skarels } 30212795Ssam dev = (dev_t)ip->i_rdev; 30315956Skarels iput(ip); 30412795Ssam if (major(dev) >= nblkdev) 30512795Ssam return (ENXIO); 30612795Ssam *pdev = dev; 30712795Ssam return (0); 30812795Ssam } 309