1: /* 2: * Copyright (c) 1982, 1986 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: * 6: * @(#)ufs_mount.c 7.1 (Berkeley) 6/5/86 7: */ 8: 9: #include "param.h" 10: #include "systm.h" 11: #include "dir.h" 12: #include "user.h" 13: #include "inode.h" 14: #include "proc.h" 15: #include "fs.h" 16: #include "buf.h" 17: #include "mount.h" 18: #include "file.h" 19: #include "conf.h" 20: 21: smount() 22: { 23: register struct a { 24: char *fspec; 25: char *freg; 26: int ronly; 27: } *uap = (struct a *)u.u_ap; 28: dev_t dev; 29: register struct inode *ip; 30: register struct fs *fs; 31: register struct nameidata *ndp = &u.u_nd; 32: u_int len; 33: 34: u.u_error = getmdev(&dev, uap->fspec); 35: if (u.u_error) 36: return; 37: ndp->ni_nameiop = LOOKUP | FOLLOW; 38: ndp->ni_segflg = UIO_USERSPACE; 39: ndp->ni_dirp = (caddr_t)uap->freg; 40: ip = namei(ndp); 41: if (ip == NULL) 42: return; 43: if (ip->i_count != 1) { 44: iput(ip); 45: u.u_error = EBUSY; 46: return; 47: } 48: if ((ip->i_mode&IFMT) != IFDIR) { 49: iput(ip); 50: u.u_error = ENOTDIR; 51: return; 52: } 53: fs = mountfs(dev, uap->ronly, ip); 54: if (fs == 0) 55: return; 56: (void) copyinstr(uap->freg, fs->fs_fsmnt, sizeof(fs->fs_fsmnt)-1, &len); 57: bzero(fs->fs_fsmnt + len, sizeof (fs->fs_fsmnt) - len); 58: } 59: 60: /* this routine has races if running twice */ 61: struct fs * 62: mountfs(dev, ronly, ip) 63: dev_t dev; 64: int ronly; 65: struct inode *ip; 66: { 67: register struct mount *mp = 0; 68: struct buf *tp = 0; 69: register struct buf *bp = 0; 70: register struct fs *fs; 71: int blks; 72: caddr_t space; 73: int i, size; 74: register error; 75: int needclose = 0; 76: 77: error = 78: (*bdevsw[major(dev)].d_open)(dev, ronly ? FREAD : FREAD|FWRITE); 79: if (error) 80: goto out; 81: needclose = 1; 82: tp = bread(dev, SBLOCK, SBSIZE); 83: if (tp->b_flags & B_ERROR) 84: goto out; 85: for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 86: if (mp->m_bufp != 0 && dev == mp->m_dev) { 87: mp = 0; 88: error = EBUSY; 89: needclose = 0; 90: goto out; 91: } 92: for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 93: if (mp->m_bufp == 0) 94: goto found; 95: mp = 0; 96: error = EMFILE; /* needs translation */ 97: goto out; 98: found: 99: mp->m_bufp = tp; /* just to reserve this slot */ 100: mp->m_dev = NODEV; 101: fs = tp->b_un.b_fs; 102: if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE 103: || fs->fs_bsize < sizeof(struct fs)) { 104: error = EINVAL; /* also needs translation */ 105: goto out; 106: } 107: bp = geteblk((int)fs->fs_sbsize); 108: mp->m_bufp = bp; 109: bcopy((caddr_t)tp->b_un.b_addr, (caddr_t)bp->b_un.b_addr, 110: (u_int)fs->fs_sbsize); 111: brelse(tp); 112: tp = 0; 113: fs = bp->b_un.b_fs; 114: fs->fs_ronly = (ronly != 0); 115: if (ronly == 0) 116: fs->fs_fmod = 1; 117: blks = howmany(fs->fs_cssize, fs->fs_fsize); 118: space = wmemall(vmemall, (int)fs->fs_cssize); 119: if (space == 0) { 120: error = ENOMEM; 121: goto out; 122: } 123: for (i = 0; i < blks; i += fs->fs_frag) { 124: size = fs->fs_bsize; 125: if (i + fs->fs_frag > blks) 126: size = (blks - i) * fs->fs_fsize; 127: tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size); 128: if (tp->b_flags&B_ERROR) { 129: wmemfree(space, (int)fs->fs_cssize); 130: goto out; 131: } 132: bcopy((caddr_t)tp->b_un.b_addr, space, (u_int)size); 133: fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space; 134: space += size; 135: brelse(tp); 136: tp = 0; 137: } 138: mp->m_inodp = ip; 139: mp->m_dev = dev; 140: if (ip) { 141: ip->i_flag |= IMOUNT; 142: cacheinval(ip); 143: iunlock(ip); 144: } 145: return (fs); 146: out: 147: if (error == 0) 148: error = EIO; 149: if (ip) 150: iput(ip); 151: if (mp) 152: mp->m_bufp = 0; 153: if (bp) 154: brelse(bp); 155: if (tp) 156: brelse(tp); 157: if (needclose) { 158: (*bdevsw[major(dev)].d_close)(dev, ronly? FREAD : FREAD|FWRITE); 159: binval(dev); 160: } 161: u.u_error = error; 162: return (0); 163: } 164: 165: umount() 166: { 167: struct a { 168: char *fspec; 169: } *uap = (struct a *)u.u_ap; 170: 171: u.u_error = unmount1(uap->fspec, 0); 172: } 173: 174: unmount1(fname, forcibly) 175: caddr_t fname; 176: int forcibly; 177: { 178: dev_t dev; 179: register struct mount *mp; 180: int stillopen, flag, error; 181: register struct inode *ip; 182: register struct fs *fs; 183: 184: error = getmdev(&dev, fname); 185: if (error) 186: return (error); 187: for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 188: if (mp->m_bufp != NULL && dev == mp->m_dev) 189: goto found; 190: return (EINVAL); 191: found: 192: xumount(dev); /* remove unused sticky files from text table */ 193: nchinval(dev); /* flush the name cache */ 194: update(); 195: #ifdef QUOTA 196: if ((stillopen = iflush(dev, mp->m_qinod)) < 0 && !forcibly) 197: #else 198: if ((stillopen = iflush(dev)) < 0 && !forcibly) 199: #endif 200: return (EBUSY); 201: if (stillopen < 0) 202: return (EBUSY); /* XXX */ 203: #ifdef QUOTA 204: closedq(mp); 205: /* 206: * Here we have to iflush again to get rid of the quota inode. 207: * A drag, but it would be ugly to cheat, & this doesn't happen often 208: */ 209: (void)iflush(dev, (struct inode *)NULL); 210: #endif 211: ip = mp->m_inodp; 212: ip->i_flag &= ~IMOUNT; 213: irele(ip); 214: fs = mp->m_bufp->b_un.b_fs; 215: wmemfree((caddr_t)fs->fs_csp[0], (int)fs->fs_cssize); 216: flag = !fs->fs_ronly; 217: brelse(mp->m_bufp); 218: mp->m_bufp = 0; 219: mp->m_dev = 0; 220: mpurge(mp - &mount[0]); 221: if (!stillopen) { 222: (*bdevsw[major(dev)].d_close)(dev, flag); 223: binval(dev); 224: } 225: return (0); 226: } 227: 228: sbupdate(mp) 229: struct mount *mp; 230: { 231: register struct fs *fs = mp->m_bufp->b_un.b_fs; 232: register struct buf *bp; 233: int blks; 234: caddr_t space; 235: int i, size; 236: 237: bp = getblk(mp->m_dev, SBLOCK, (int)fs->fs_sbsize); 238: bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize); 239: bwrite(bp); 240: blks = howmany(fs->fs_cssize, fs->fs_fsize); 241: space = (caddr_t)fs->fs_csp[0]; 242: for (i = 0; i < blks; i += fs->fs_frag) { 243: size = fs->fs_bsize; 244: if (i + fs->fs_frag > blks) 245: size = (blks - i) * fs->fs_fsize; 246: bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size); 247: bcopy(space, bp->b_un.b_addr, (u_int)size); 248: space += size; 249: bwrite(bp); 250: } 251: } 252: 253: /* 254: * Common code for mount and umount. 255: * Check that the user's argument is a reasonable 256: * thing on which to mount, and return the device number if so. 257: */ 258: getmdev(pdev, fname) 259: caddr_t fname; 260: dev_t *pdev; 261: { 262: dev_t dev; 263: register struct inode *ip; 264: register struct nameidata *ndp = &u.u_nd; 265: 266: if (!suser()) 267: return (u.u_error); 268: ndp->ni_nameiop = LOOKUP | FOLLOW; 269: ndp->ni_segflg = UIO_USERSPACE; 270: ndp->ni_dirp = fname; 271: ip = namei(ndp); 272: if (ip == NULL) { 273: if (u.u_error == ENOENT) 274: return (ENODEV); /* needs translation */ 275: return (u.u_error); 276: } 277: if ((ip->i_mode&IFMT) != IFBLK) { 278: iput(ip); 279: return (ENOTBLK); 280: } 281: dev = (dev_t)ip->i_rdev; 282: iput(ip); 283: if (major(dev) >= nblkdev) 284: return (ENXIO); 285: *pdev = dev; 286: return (0); 287: }