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