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_vfsops.c 7.11 (Berkeley) 05/24/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 register struct buf *bp = NULL; 75 register struct fs *fs; 76 struct partinfo dpart; 77 int havepart = 0, blks; 78 caddr_t base, space; 79 int i, size; 80 register error; 81 int needclose = 0; 82 83 for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) { 84 if (mp->m_fs == NULL) { 85 if (fmp == NULL) 86 fmp = mp; 87 } else if (dev == mp->m_dev) { 88 u.u_error = EBUSY; /* XXX */ 89 return ((struct fs *) NULL); 90 } 91 } 92 if ((mp = fmp) == NULL) { 93 u.u_error = EMFILE; /* needs translation XXX */ 94 return ((struct fs *) NULL); 95 } 96 mp->m_fs = (struct fs *)1; /* just to reserve this slot */ 97 mp->m_dev = dev; 98 mp->m_inodp = NULL; 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 bp = bread(dev, SBLOCK, SBSIZE); 115 if (bp->b_flags & B_ERROR) { 116 mp->m_fs = NULL; 117 goto out; 118 } 119 fs = bp->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((u_long)fs->fs_sbsize, M_SUPERBLK, 127 M_WAITOK); 128 bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)mp->m_fs, 129 (u_int)fs->fs_sbsize); 130 brelse(bp); 131 bp = NULL; 132 fs = mp->m_fs; 133 fs->fs_ronly = (ronly != 0); 134 if (ronly == 0) 135 fs->fs_fmod = 1; 136 if (havepart) { 137 dpart.part->p_fstype = FS_BSDFFS; 138 dpart.part->p_fsize = fs->fs_fsize; 139 dpart.part->p_frag = fs->fs_frag; 140 dpart.part->p_cpg = fs->fs_cpg; 141 } 142 blks = howmany(fs->fs_cssize, fs->fs_fsize); 143 base = space = (caddr_t)malloc((u_long)fs->fs_cssize, M_SUPERBLK, 144 M_WAITOK); 145 if (space == NULL) { 146 error = ENOMEM; 147 goto out; 148 } 149 for (i = 0; i < blks; i += fs->fs_frag) { 150 size = fs->fs_bsize; 151 if (i + fs->fs_frag > blks) 152 size = (blks - i) * fs->fs_fsize; 153 bp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size); 154 if (bp->b_flags&B_ERROR) { 155 free((caddr_t)base, M_SUPERBLK); 156 goto out; 157 } 158 bcopy((caddr_t)bp->b_un.b_addr, space, (u_int)size); 159 fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space; 160 space += size; 161 brelse(bp); 162 bp = NULL; 163 } 164 mp->m_inodp = ip; 165 if (ip) { 166 ip->i_flag |= IMOUNT; 167 cacheinval(ip); 168 iunlock(ip); 169 } 170 /* Sanity checks for old file systems. XXX */ 171 fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect); /* XXX */ 172 fs->fs_interleave = MAX(fs->fs_interleave, 1); /* XXX */ 173 if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 174 fs->fs_nrpos = 8; /* XXX */ 175 return (fs); 176 out: 177 if (needclose) 178 (void) closei(dev, IFBLK, ronly? FREAD : FREAD|FWRITE); 179 if (mp->m_fs) { 180 free((caddr_t)mp->m_fs, M_SUPERBLK); 181 mp->m_fs = NULL; 182 } 183 if (bp) 184 brelse(bp); 185 u.u_error = error ? error : EIO; /* XXX */ 186 return ((struct fs *) NULL); 187 } 188 189 umount() 190 { 191 struct a { 192 char *fspec; 193 } *uap = (struct a *)u.u_ap; 194 195 u.u_error = unmount1(uap->fspec, 0); 196 } 197 198 unmount1(fname, forcibly) 199 caddr_t fname; 200 int forcibly; 201 { 202 dev_t dev; 203 register struct mount *mp; 204 int error; 205 register struct inode *ip; 206 register struct fs *fs; 207 208 forcibly = 0; /* XXX */ 209 error = getmdev(&dev, fname); 210 if (error) 211 return (error); 212 for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 213 if (mp->m_fs != NULL && dev == mp->m_dev) 214 goto found; 215 return (EINVAL); 216 found: 217 xumount(dev); /* remove unused sticky files from text table */ 218 nchinval(dev); /* flush the name cache */ 219 update(); 220 #ifdef QUOTA 221 if ((error = iflush(dev, mp->m_qinod)) && !forcibly) 222 #else 223 if ((error = iflush(dev)) && !forcibly) 224 #endif 225 return (error); 226 #ifdef QUOTA 227 closedq(mp); 228 /* 229 * Here we have to iflush again to get rid of the quota inode. 230 * A drag, but it would be ugly to cheat, & this doesn't happen often. 231 */ 232 (void)iflush(dev, (struct inode *)NULL); 233 #endif 234 ip = mp->m_inodp; 235 ip->i_flag &= ~IMOUNT; 236 fs = mp->m_fs; 237 free((caddr_t)fs->fs_csp[0], M_SUPERBLK); 238 free((caddr_t)mp->m_fs, M_SUPERBLK); 239 mp->m_fs = NULL; 240 mp->m_dev = NODEV; 241 mpurge(mp - &mount[0]); 242 error = closei(dev, IFBLK, fs->fs_ronly? FREAD : FREAD|FWRITE); 243 irele(ip); 244 return (error); 245 } 246 247 sbupdate(mp) 248 struct mount *mp; 249 { 250 register struct fs *fs = mp->m_fs; 251 register struct buf *bp; 252 int blks; 253 caddr_t space; 254 int i, size; 255 256 bp = getblk(mp->m_dev, SBLOCK, (int)fs->fs_sbsize); 257 bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize); 258 /* Restore compatibility to old file systems. XXX */ 259 if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 260 bp->b_un.b_fs->fs_nrpos = -1; /* XXX */ 261 bwrite(bp); 262 blks = howmany(fs->fs_cssize, fs->fs_fsize); 263 space = (caddr_t)fs->fs_csp[0]; 264 for (i = 0; i < blks; i += fs->fs_frag) { 265 size = fs->fs_bsize; 266 if (i + fs->fs_frag > blks) 267 size = (blks - i) * fs->fs_fsize; 268 bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size); 269 bcopy(space, bp->b_un.b_addr, (u_int)size); 270 space += size; 271 bwrite(bp); 272 } 273 } 274 275 /* 276 * Common code for mount and umount. 277 * Check that the user's argument is a reasonable 278 * thing on which to mount, and return the device number if so. 279 */ 280 getmdev(pdev, fname) 281 caddr_t fname; 282 dev_t *pdev; 283 { 284 dev_t dev; 285 register struct inode *ip; 286 register struct nameidata *ndp = &u.u_nd; 287 288 if (!suser()) 289 return (u.u_error); 290 ndp->ni_nameiop = LOOKUP | FOLLOW; 291 ndp->ni_segflg = UIO_USERSPACE; 292 ndp->ni_dirp = fname; 293 ip = namei(ndp); 294 if (ip == NULL) { 295 if (u.u_error == ENOENT) 296 return (ENODEV); /* needs translation */ 297 return (u.u_error); 298 } 299 if ((ip->i_mode&IFMT) != IFBLK) { 300 iput(ip); 301 return (ENOTBLK); 302 } 303 dev = (dev_t)ip->i_rdev; 304 iput(ip); 305 if (major(dev) >= nblkdev) 306 return (ENXIO); 307 *pdev = dev; 308 return (0); 309 } 310