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.7 (Berkeley) 11/30/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 #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 fs->fs_dbsize = size; 141 } 142 blks = howmany(fs->fs_cssize, fs->fs_fsize); 143 base = space = (caddr_t)malloc(fs->fs_cssize, M_SUPERBLK, M_WAITOK); 144 if (space == NULL) { 145 error = ENOMEM; 146 goto out; 147 } 148 for (i = 0; i < blks; i += fs->fs_frag) { 149 size = fs->fs_bsize; 150 if (i + fs->fs_frag > blks) 151 size = (blks - i) * fs->fs_fsize; 152 tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size); 153 if (tp->b_flags&B_ERROR) { 154 free(base, M_SUPERBLK); 155 goto out; 156 } 157 bcopy((caddr_t)tp->b_un.b_addr, space, (u_int)size); 158 fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space; 159 space += size; 160 brelse(tp); 161 tp = NULL; 162 } 163 mp->m_inodp = ip; 164 if (ip) { 165 ip->i_flag |= IMOUNT; 166 cacheinval(ip); 167 iunlock(ip); 168 } 169 /* Sanity checks for old file systems. XXX */ 170 fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect); /* XXX */ 171 fs->fs_interleave = MAX(fs->fs_interleave, 1); /* XXX */ 172 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 bwrite(bp); 257 blks = howmany(fs->fs_cssize, fs->fs_fsize); 258 space = (caddr_t)fs->fs_csp[0]; 259 for (i = 0; i < blks; i += fs->fs_frag) { 260 size = fs->fs_bsize; 261 if (i + fs->fs_frag > blks) 262 size = (blks - i) * fs->fs_fsize; 263 bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size); 264 bcopy(space, bp->b_un.b_addr, (u_int)size); 265 space += size; 266 bwrite(bp); 267 } 268 } 269 270 /* 271 * Common code for mount and umount. 272 * Check that the user's argument is a reasonable 273 * thing on which to mount, and return the device number if so. 274 */ 275 getmdev(pdev, fname) 276 caddr_t fname; 277 dev_t *pdev; 278 { 279 dev_t dev; 280 register struct inode *ip; 281 register struct nameidata *ndp = &u.u_nd; 282 283 if (!suser()) 284 return (u.u_error); 285 ndp->ni_nameiop = LOOKUP | FOLLOW; 286 ndp->ni_segflg = UIO_USERSPACE; 287 ndp->ni_dirp = fname; 288 ip = namei(ndp); 289 if (ip == NULL) { 290 if (u.u_error == ENOENT) 291 return (ENODEV); /* needs translation */ 292 return (u.u_error); 293 } 294 if ((ip->i_mode&IFMT) != IFBLK) { 295 iput(ip); 296 return (ENOTBLK); 297 } 298 dev = (dev_t)ip->i_rdev; 299 iput(ip); 300 if (major(dev) >= nblkdev) 301 return (ENXIO); 302 *pdev = dev; 303 return (0); 304 } 305