1: /* 2: * Copyright (c) 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 2.1 (2.11BSD GTE) 1997/6/29 7: */ 8: 9: #include "param.h" 10: #include "../machine/seg.h" 11: 12: #include "systm.h" 13: #include "user.h" 14: #include "inode.h" 15: #include "fs.h" 16: #include "buf.h" 17: #include "mount.h" 18: #include "file.h" 19: #include "namei.h" 20: #include "conf.h" 21: #include "stat.h" 22: #include "disklabel.h" 23: #include "ioctl.h" 24: #ifdef QUOTA 25: #include "quota.h" 26: #endif 27: 28: smount() 29: { 30: register struct a { 31: char *fspec; 32: char *freg; 33: int flags; 34: } *uap = (struct a *)u.u_ap; 35: dev_t dev; 36: register struct inode *ip; 37: register struct fs *fs; 38: struct nameidata nd; 39: struct nameidata *ndp = &nd; 40: struct mount *mp; 41: u_int lenon, lenfrom; 42: int error = 0; 43: char mnton[MNAMELEN], mntfrom[MNAMELEN]; 44: 45: if (u.u_error = getmdev(&dev, uap->fspec)) 46: return; 47: NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, uap->freg); 48: if ((ip = namei(ndp)) == NULL) 49: return; 50: if ((ip->i_mode&IFMT) != IFDIR) { 51: error = ENOTDIR; 52: goto cmnout; 53: } 54: /* 55: * The following two copyinstr calls will not fault because getmdev() or 56: * namei() would have returned an error for invalid parameters. 57: */ 58: copyinstr(uap->freg, mnton, sizeof (mnton) - 1, &lenon); 59: copyinstr(uap->fspec, mntfrom, sizeof (mntfrom) - 1, &lenfrom); 60: 61: if (uap->flags & MNT_UPDATE) 62: { 63: fs = ip->i_fs; 64: mp = (struct mount *) 65: ((int)fs - offsetof(struct mount, m_filsys)); 66: if (ip->i_number != ROOTINO) 67: { 68: error = EINVAL; /* Not a mount point */ 69: goto cmnout; 70: } 71: /* 72: * Check that the device passed in is the same one that is in the mount 73: * table entry for this mount point. 74: */ 75: if (dev != mp->m_dev) 76: { 77: error = EINVAL; /* not right mount point */ 78: goto cmnout; 79: } 80: /* 81: * This is where the RW to RO transformation would be done. It is, for now, 82: * too much work to port pages of code to do (besides which most 83: * programs get very upset at having access yanked out from under them). 84: */ 85: if (fs->fs_ronly == 0 && (uap->flags & MNT_RDONLY)) 86: { 87: error = EPERM; /* ! RW to RO updates */ 88: goto cmnout; 89: } 90: /* 91: * However, going from RO to RW is easy. Then merge in the new 92: * flags (async, sync, nodev, etc) passed in from the program. 93: */ 94: if (fs->fs_ronly && ((uap->flags & MNT_RDONLY) == 0)) 95: { 96: fs->fs_ronly = 0; 97: mp->m_flags &= ~MNT_RDONLY; 98: } 99: #define _MF (MNT_NOSUID | MNT_NODEV | MNT_NOEXEC | MNT_ASYNC | MNT_SYNCHRONOUS | MNT_NOATIME) 100: mp->m_flags &= ~_MF; 101: mp->m_flags |= (uap->flags & _MF); 102: #undef _MF 103: iput(ip); 104: u.u_error = 0; 105: goto updname; 106: } 107: else 108: { 109: /* 110: * This is where a new mount (not an update of an existing mount point) is 111: * done. 112: * 113: * The directory being mounted on can have no other references AND can not 114: * currently be a mount point. Mount points have an inode number of (you 115: * guessed it) ROOTINO which is 2. 116: */ 117: if (ip->i_count != 1 || (ip->i_number == ROOTINO)) 118: { 119: error = EBUSY; 120: goto cmnout; 121: } 122: fs = mountfs(dev, uap->flags, ip); 123: if (fs == 0) 124: return; 125: } 126: /* 127: * Lastly, both for new mounts and updates of existing mounts, update the 128: * mounted-on and mounted-from fields. 129: */ 130: updname: 131: mount_updname(fs, mnton, mntfrom, lenon, lenfrom); 132: return; 133: cmnout: 134: iput(ip); 135: return(u.u_error = error); 136: } 137: 138: mount_updname(fs, on, from, lenon, lenfrom) 139: struct fs *fs; 140: char *on, *from; 141: int lenon, lenfrom; 142: { 143: struct mount *mp; 144: register struct xmount *xmp; 145: 146: bzero(fs->fs_fsmnt, sizeof (fs->fs_fsmnt)); 147: bcopy(on, fs->fs_fsmnt, sizeof (fs->fs_fsmnt) - 1); 148: mp = (struct mount *)((int)fs - offsetof(struct mount, m_filsys)); 149: xmp = (struct xmount *)SEG5; 150: mapseg5(mp->m_extern, XMOUNTDESC); 151: bzero(xmp, sizeof (struct xmount)); 152: bcopy(on, xmp->xm_mnton, lenon); 153: bcopy(from, xmp->xm_mntfrom, lenfrom); 154: normalseg5(); 155: } 156: 157: /* this routine has races if running twice */ 158: struct fs * 159: mountfs(dev, flags, ip) 160: dev_t dev; 161: int flags; 162: struct inode *ip; 163: { 164: register struct mount *mp = 0; 165: struct buf *tp = 0; 166: register struct fs *fs; 167: register int error; 168: int ronly = flags & MNT_RDONLY; 169: int needclose = 0; 170: int chrdev, (*ioctl)(); 171: struct partinfo dpart; 172: 173: error = 174: (*bdevsw[major(dev)].d_open)(dev, ronly ? FREAD : FREAD|FWRITE, S_IFBLK); 175: if (error) 176: goto out; 177: /* 178: * Now make a check that the partition is really a filesystem if the 179: * underlying driver supports disklabels (there is an ioctl entry point 180: * and calling it does not return an error). 181: * 182: * XXX - Check for NODEV because BLK only devices (i.e. the 'ram' driver) do not 183: * XXX - have a CHR counterpart. Such drivers can not support labels due to 184: * XXX - the lack of an ioctl entry point. 185: */ 186: chrdev = blktochr(dev); 187: if (chrdev == NODEV) 188: ioctl = NULL; 189: else 190: ioctl = cdevsw[chrdev].d_ioctl; 191: if (ioctl && !(*ioctl)(dev, DIOCGPART, &dpart, FREAD)) 192: { 193: if (dpart.part->p_fstype != FS_V71K) 194: { 195: error = EINVAL; 196: goto out; 197: } 198: } 199: needclose = 1; 200: tp = bread(dev, SBLOCK); 201: if (tp->b_flags & B_ERROR) 202: goto out; 203: for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 204: if (mp->m_inodp != 0 && dev == mp->m_dev) { 205: mp = 0; 206: error = EBUSY; 207: needclose = 0; 208: goto out; 209: } 210: for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 211: if (mp->m_inodp == 0) 212: goto found; 213: mp = 0; 214: error = EMFILE; /* needs translation */ 215: goto out; 216: found: 217: mp->m_inodp = ip; /* reserve slot */ 218: mp->m_dev = dev; 219: fs = &mp->m_filsys; 220: bcopy(mapin(tp), (caddr_t)fs, sizeof(struct fs)); 221: mapout(tp); 222: brelse(tp); 223: tp = 0; 224: fs->fs_ronly = (ronly != 0); 225: if (ronly == 0) 226: fs->fs_fmod = 1; 227: fs->fs_ilock = 0; 228: fs->fs_flock = 0; 229: fs->fs_nbehind = 0; 230: fs->fs_lasti = 1; 231: fs->fs_flags = flags; 232: if (ip) { 233: ip->i_flag |= IMOUNT; 234: cacheinval(ip); 235: IUNLOCK(ip); 236: } 237: return (fs); 238: out: 239: if (error == 0) 240: error = EIO; 241: if (ip) 242: iput(ip); 243: if (mp) 244: mp->m_inodp = 0; 245: if (tp) 246: brelse(tp); 247: if (needclose) { 248: (*bdevsw[major(dev)].d_close)(dev, 249: ronly? FREAD : FREAD|FWRITE, S_IFBLK); 250: binval(dev); 251: } 252: u.u_error = error; 253: return (0); 254: } 255: 256: umount() 257: { 258: struct a { 259: char *fspec; 260: } *uap = (struct a *)u.u_ap; 261: 262: u.u_error = unmount1(uap->fspec); 263: } 264: 265: unmount1(fname) 266: caddr_t fname; 267: { 268: dev_t dev; 269: register struct mount *mp; 270: register struct inode *ip; 271: register int error; 272: int aflag; 273: 274: error = getmdev(&dev, fname); 275: if (error) 276: return (error); 277: for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 278: if (mp->m_inodp != NULL && dev == mp->m_dev) 279: goto found; 280: return (EINVAL); 281: found: 282: xumount(dev); /* remove unused sticky files from text table */ 283: nchinval(dev); /* flush the name cache */ 284: aflag = mp->m_flags & MNT_ASYNC; 285: mp->m_flags &= ~MNT_ASYNC; /* Don't want async when unmounting */ 286: ufs_sync(mp); 287: 288: #ifdef QUOTA 289: if (iflush(dev, mp->m_qinod) < 0) 290: #else 291: if (iflush(dev) < 0) 292: #endif 293: { 294: mp->m_flags |= aflag; 295: return (EBUSY); 296: } 297: #ifdef QUOTA 298: QUOTAMAP(); 299: closedq(mp); 300: QUOTAUNMAP(); 301: /* 302: * Here we have to iflush again to get rid of the quota inode. 303: * A drag, but it would be ugly to cheat, & this doesn't happen often 304: */ 305: (void)iflush(dev, (struct inode *)NULL); 306: #endif 307: ip = mp->m_inodp; 308: ip->i_flag &= ~IMOUNT; 309: irele(ip); 310: mp->m_inodp = 0; 311: mp->m_dev = 0; 312: (*bdevsw[major(dev)].d_close)(dev, 0, S_IFBLK); 313: binval(dev); 314: return (0); 315: } 316: 317: /* 318: * Common code for mount and umount. 319: * Check that the user's argument is a reasonable 320: * thing on which to mount, otherwise return error. 321: */ 322: getmdev(pdev, fname) 323: caddr_t fname; 324: dev_t *pdev; 325: { 326: register dev_t dev; 327: register struct inode *ip; 328: struct nameidata nd; 329: register struct nameidata *ndp = &nd; 330: 331: if (!suser()) 332: return (u.u_error); 333: NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, fname); 334: ip = namei(ndp); 335: if (ip == NULL) { 336: if (u.u_error == ENOENT) 337: return (ENODEV); /* needs translation */ 338: return (u.u_error); 339: } 340: if ((ip->i_mode&IFMT) != IFBLK) { 341: iput(ip); 342: return (ENOTBLK); 343: } 344: dev = (dev_t)ip->i_rdev; 345: iput(ip); 346: if (major(dev) >= nblkdev) 347: return (ENXIO); 348: *pdev = dev; 349: return (0); 350: }