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