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