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*30749Skarels * @(#)lfs_vfsops.c 7.2.1.1 (Berkeley) 04/02/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" 20*30749Skarels #include "ioctl.h" 21*30749Skarels #include "disklabel.h" 22*30749Skarels #include "stat.h" 2312795Ssam 2412795Ssam smount() 2512795Ssam { 2612795Ssam register struct a { 2712795Ssam char *fspec; 2812795Ssam char *freg; 2912795Ssam int ronly; 3016697Smckusick } *uap = (struct a *)u.u_ap; 3112795Ssam dev_t dev; 3212795Ssam register struct inode *ip; 3312795Ssam register struct fs *fs; 3416697Smckusick register struct nameidata *ndp = &u.u_nd; 3516705Smckusick u_int len; 3612795Ssam 3716697Smckusick u.u_error = getmdev(&dev, uap->fspec); 3812795Ssam if (u.u_error) 3912795Ssam return; 4027267Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 4116697Smckusick ndp->ni_segflg = UIO_USERSPACE; 4216697Smckusick ndp->ni_dirp = (caddr_t)uap->freg; 4316697Smckusick ip = namei(ndp); 4412795Ssam if (ip == NULL) 4512795Ssam return; 4621013Smckusick if (ip->i_count != 1) { 4712795Ssam iput(ip); 4812795Ssam u.u_error = EBUSY; 4912795Ssam return; 5012795Ssam } 5121013Smckusick if ((ip->i_mode&IFMT) != IFDIR) { 5221013Smckusick iput(ip); 5321013Smckusick u.u_error = ENOTDIR; 5421013Smckusick return; 5521013Smckusick } 5612795Ssam fs = mountfs(dev, uap->ronly, ip); 5712795Ssam if (fs == 0) 5812795Ssam return; 5916705Smckusick (void) copyinstr(uap->freg, fs->fs_fsmnt, sizeof(fs->fs_fsmnt)-1, &len); 6016728Skarels bzero(fs->fs_fsmnt + len, sizeof (fs->fs_fsmnt) - len); 6112795Ssam } 6212795Ssam 6312795Ssam /* this routine has races if running twice */ 6412795Ssam struct fs * 6512795Ssam mountfs(dev, ronly, ip) 6612795Ssam dev_t dev; 6712795Ssam int ronly; 6812795Ssam struct inode *ip; 6912795Ssam { 7012795Ssam register struct mount *mp = 0; 7112795Ssam struct buf *tp = 0; 7212795Ssam register struct buf *bp = 0; 7312795Ssam register struct fs *fs; 74*30749Skarels struct partinfo dpart; 75*30749Skarels int havepart = 0, blks; 7612795Ssam caddr_t space; 7712795Ssam int i, size; 7816639Skarels register error; 7921013Smckusick int needclose = 0; 8012795Ssam 8116639Skarels error = 82*30749Skarels (*bdevsw[major(dev)].d_open)(dev, ronly ? FREAD : FREAD|FWRITE, 83*30749Skarels S_IFBLK); 8416639Skarels if (error) 8512795Ssam goto out; 8621013Smckusick needclose = 1; 87*30749Skarels #ifdef SECSIZE 88*30749Skarels /* 89*30749Skarels * If possible, determine hardware sector size 90*30749Skarels * and adjust fsbtodb to correspond. 91*30749Skarels */ 92*30749Skarels #endif SECSIZE 93*30749Skarels if ((*bdevsw[major(dev)].d_ioctl)(dev, DIOCGPART, 94*30749Skarels (caddr_t)&dpart, FREAD) == 0) { 95*30749Skarels havepart = 1; 96*30749Skarels size = dpart.disklab->d_secsize; 97*30749Skarels #ifdef SECSIZE 98*30749Skarels if (size < MINSECSIZE) { 99*30749Skarels error = EINVAL; 100*30749Skarels goto out; 101*30749Skarels } 102*30749Skarels #endif SECSIZE 103*30749Skarels } else 104*30749Skarels size = DEV_BSIZE; 105*30749Skarels #ifdef SECSIZE 106*30749Skarels tp = bread(dev, (daddr_t)(SBOFF / size), SBSIZE, size); 107*30749Skarels #else SECSIZE 10812795Ssam tp = bread(dev, SBLOCK, SBSIZE); 109*30749Skarels #endif SECSIZE 11012795Ssam if (tp->b_flags & B_ERROR) 11112795Ssam goto out; 11212795Ssam for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 11312795Ssam if (mp->m_bufp != 0 && dev == mp->m_dev) { 11412795Ssam mp = 0; 11516639Skarels error = EBUSY; 11612795Ssam goto out; 11712795Ssam } 11812795Ssam for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 11912795Ssam if (mp->m_bufp == 0) 12012795Ssam goto found; 12112795Ssam mp = 0; 12216639Skarels error = EMFILE; /* needs translation */ 12312795Ssam goto out; 12412795Ssam found: 12512795Ssam mp->m_bufp = tp; /* just to reserve this slot */ 12612795Ssam mp->m_dev = NODEV; 12712795Ssam fs = tp->b_un.b_fs; 128*30749Skarels if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || 129*30749Skarels fs->fs_bsize < sizeof(struct fs)) { 13016639Skarels error = EINVAL; /* also needs translation */ 13116639Skarels goto out; 13216639Skarels } 13312795Ssam bp = geteblk((int)fs->fs_sbsize); 13412795Ssam mp->m_bufp = bp; 13512795Ssam bcopy((caddr_t)tp->b_un.b_addr, (caddr_t)bp->b_un.b_addr, 13612795Ssam (u_int)fs->fs_sbsize); 13712795Ssam brelse(tp); 13812795Ssam tp = 0; 13912795Ssam fs = bp->b_un.b_fs; 14012795Ssam fs->fs_ronly = (ronly != 0); 14112795Ssam if (ronly == 0) 14212795Ssam fs->fs_fmod = 1; 143*30749Skarels #ifdef SECSIZE 144*30749Skarels /* 145*30749Skarels * If we have a disk label, force per-partition 146*30749Skarels * filesystem information to be correct 147*30749Skarels * and set correct current fsbtodb shift. 148*30749Skarels */ 149*30749Skarels #endif SECSIZE 150*30749Skarels if (havepart) { 151*30749Skarels dpart.part->p_fstype = FS_BSDFFS; 152*30749Skarels dpart.part->p_fsize = fs->fs_fsize; 153*30749Skarels dpart.part->p_frag = fs->fs_frag; 154*30749Skarels #ifdef SECSIZE 155*30749Skarels #ifdef tahoe 156*30749Skarels /* 157*30749Skarels * Save the original fsbtodb shift to restore on updates. 158*30749Skarels * (Console doesn't understand fsbtodb changes.) 159*30749Skarels */ 160*30749Skarels fs->fs_sparecon[0] = fs->fs_fsbtodb; 161*30749Skarels #endif 162*30749Skarels i = fs->fs_fsize / size; 163*30749Skarels for (fs->fs_fsbtodb = 0; i > 1; i >>= 1) 164*30749Skarels fs->fs_fsbtodb++; 165*30749Skarels #endif SECSIZE 166*30749Skarels fs->fs_dbsize = size; 167*30749Skarels } 16812795Ssam blks = howmany(fs->fs_cssize, fs->fs_fsize); 16912795Ssam space = wmemall(vmemall, (int)fs->fs_cssize); 17016639Skarels if (space == 0) { 17116639Skarels error = ENOMEM; 17212795Ssam goto out; 17316639Skarels } 17412795Ssam for (i = 0; i < blks; i += fs->fs_frag) { 17512795Ssam size = fs->fs_bsize; 17612795Ssam if (i + fs->fs_frag > blks) 17712795Ssam size = (blks - i) * fs->fs_fsize; 178*30749Skarels #ifdef SECSIZE 179*30749Skarels tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size, 180*30749Skarels fs->fs_dbsize); 181*30749Skarels #else SECSIZE 18212795Ssam tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size); 183*30749Skarels #endif SECSIZE 18412795Ssam if (tp->b_flags&B_ERROR) { 18512795Ssam wmemfree(space, (int)fs->fs_cssize); 18612795Ssam goto out; 18712795Ssam } 18812795Ssam bcopy((caddr_t)tp->b_un.b_addr, space, (u_int)size); 18917225Smckusick fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space; 19012795Ssam space += size; 19112795Ssam brelse(tp); 19212795Ssam tp = 0; 19312795Ssam } 19412795Ssam mp->m_inodp = ip; 19512795Ssam mp->m_dev = dev; 19612795Ssam if (ip) { 19712795Ssam ip->i_flag |= IMOUNT; 19827267Smckusick cacheinval(ip); 19912795Ssam iunlock(ip); 20012795Ssam } 20130383Smckusick /* Sanity checks for old file systems. XXX */ 20230383Smckusick fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect); /* XXX */ 20330383Smckusick fs->fs_interleave = MAX(fs->fs_interleave, 1); /* XXX */ 204*30749Skarels 20512795Ssam return (fs); 20612795Ssam out: 20716639Skarels if (error == 0) 20816639Skarels error = EIO; 209*30749Skarels if (needclose) 210*30749Skarels (void) closei((dev_t)ip->i_rdev, IFBLK, 211*30749Skarels ronly? FREAD : FREAD|FWRITE); 21212795Ssam if (ip) 21312795Ssam iput(ip); 21412795Ssam if (mp) 21512795Ssam mp->m_bufp = 0; 21612795Ssam if (bp) 21712795Ssam brelse(bp); 21812795Ssam if (tp) 21912795Ssam brelse(tp); 22016639Skarels u.u_error = error; 22112795Ssam return (0); 22212795Ssam } 22312795Ssam 22412795Ssam umount() 22512795Ssam { 22612795Ssam struct a { 22712795Ssam char *fspec; 22816697Smckusick } *uap = (struct a *)u.u_ap; 22912795Ssam 23016697Smckusick u.u_error = unmount1(uap->fspec, 0); 23112795Ssam } 23212795Ssam 23316697Smckusick unmount1(fname, forcibly) 23416697Smckusick caddr_t fname; 23512795Ssam int forcibly; 23612795Ssam { 23712795Ssam dev_t dev; 23812795Ssam register struct mount *mp; 239*30749Skarels int error; 24012795Ssam register struct inode *ip; 24112795Ssam register struct fs *fs; 24212795Ssam 243*30749Skarels forcibly = 0; /* XXX */ 24416697Smckusick error = getmdev(&dev, fname); 24512795Ssam if (error) 24612795Ssam return (error); 24712795Ssam for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 24812795Ssam if (mp->m_bufp != NULL && dev == mp->m_dev) 24912795Ssam goto found; 25012795Ssam return (EINVAL); 25112795Ssam found: 25212795Ssam xumount(dev); /* remove unused sticky files from text table */ 25315800Smckusick nchinval(dev); /* flush the name cache */ 25412795Ssam update(); 25512795Ssam #ifdef QUOTA 256*30749Skarels if ((error = iflush(dev, mp->m_qinod)) && !forcibly) 25712795Ssam #else 258*30749Skarels if ((error = iflush(dev)) && !forcibly) 25912795Ssam #endif 260*30749Skarels return (error); 26112795Ssam #ifdef QUOTA 26212795Ssam closedq(mp); 26312795Ssam /* 26412795Ssam * Here we have to iflush again to get rid of the quota inode. 265*30749Skarels * A drag, but it would be ugly to cheat, & this doesn't happen often. 26612795Ssam */ 26712795Ssam (void)iflush(dev, (struct inode *)NULL); 26812795Ssam #endif 26912795Ssam ip = mp->m_inodp; 27012795Ssam ip->i_flag &= ~IMOUNT; 27112795Ssam fs = mp->m_bufp->b_un.b_fs; 27212795Ssam wmemfree((caddr_t)fs->fs_csp[0], (int)fs->fs_cssize); 27312795Ssam brelse(mp->m_bufp); 27412795Ssam mp->m_bufp = 0; 27512795Ssam mp->m_dev = 0; 27612795Ssam mpurge(mp - &mount[0]); 277*30749Skarels error = closei(dev, IFBLK, fs->fs_ronly? FREAD : FREAD|FWRITE); 278*30749Skarels irele(ip); 279*30749Skarels return (error); 28012795Ssam } 28112795Ssam 28212795Ssam sbupdate(mp) 28312795Ssam struct mount *mp; 28412795Ssam { 28512795Ssam register struct fs *fs = mp->m_bufp->b_un.b_fs; 28612795Ssam register struct buf *bp; 28712795Ssam int blks; 28812795Ssam caddr_t space; 28912795Ssam int i, size; 29012795Ssam 291*30749Skarels #ifdef SECSIZE 292*30749Skarels bp = getblk(mp->m_dev, (daddr_t)fsbtodb(fs, SBOFF / fs->fs_fsize), 293*30749Skarels (int)fs->fs_sbsize, fs->fs_dbsize); 294*30749Skarels #else SECSIZE 29512795Ssam bp = getblk(mp->m_dev, SBLOCK, (int)fs->fs_sbsize); 296*30749Skarels #endif SECSIZE 29712795Ssam bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize); 298*30749Skarels #ifdef SECSIZE 299*30749Skarels #ifdef tahoe 300*30749Skarels /* restore standard fsbtodb shift */ 301*30749Skarels bp->b_un.b_fs->fs_fsbtodb = fs->fs_sparecon[0]; 302*30749Skarels bp->b_un.b_fs->fs_sparecon[0] = 0; 303*30749Skarels #endif 304*30749Skarels #endif SECSIZE 30512795Ssam bwrite(bp); 30612795Ssam blks = howmany(fs->fs_cssize, fs->fs_fsize); 30712795Ssam space = (caddr_t)fs->fs_csp[0]; 30812795Ssam for (i = 0; i < blks; i += fs->fs_frag) { 30912795Ssam size = fs->fs_bsize; 31012795Ssam if (i + fs->fs_frag > blks) 31112795Ssam size = (blks - i) * fs->fs_fsize; 312*30749Skarels #ifdef SECSIZE 313*30749Skarels bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size, 314*30749Skarels fs->fs_dbsize); 315*30749Skarels #else SECSIZE 31612795Ssam bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size); 317*30749Skarels #endif SECSIZE 31812795Ssam bcopy(space, bp->b_un.b_addr, (u_int)size); 31912795Ssam space += size; 32012795Ssam bwrite(bp); 32112795Ssam } 32212795Ssam } 32312795Ssam 32412795Ssam /* 32512795Ssam * Common code for mount and umount. 32612795Ssam * Check that the user's argument is a reasonable 32712795Ssam * thing on which to mount, and return the device number if so. 32812795Ssam */ 32916697Smckusick getmdev(pdev, fname) 33016697Smckusick caddr_t fname; 33112795Ssam dev_t *pdev; 33212795Ssam { 33312795Ssam dev_t dev; 33412795Ssam register struct inode *ip; 33516697Smckusick register struct nameidata *ndp = &u.u_nd; 33612795Ssam 33712795Ssam if (!suser()) 33812795Ssam return (u.u_error); 33916697Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 34016697Smckusick ndp->ni_segflg = UIO_USERSPACE; 34116697Smckusick ndp->ni_dirp = fname; 34216697Smckusick ip = namei(ndp); 34321013Smckusick if (ip == NULL) { 34421013Smckusick if (u.u_error == ENOENT) 34521013Smckusick return (ENODEV); /* needs translation */ 34612795Ssam return (u.u_error); 34721013Smckusick } 34815956Skarels if ((ip->i_mode&IFMT) != IFBLK) { 34915956Skarels iput(ip); 35012795Ssam return (ENOTBLK); 35115956Skarels } 35212795Ssam dev = (dev_t)ip->i_rdev; 35315956Skarels iput(ip); 35412795Ssam if (major(dev) >= nblkdev) 35512795Ssam return (ENXIO); 35612795Ssam *pdev = dev; 35712795Ssam return (0); 35812795Ssam } 359