1 /* 2 * Copyright (c) 1989, 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)lfs_vfsops.c 7.72 (Berkeley) 01/18/92 8 */ 9 10 #include <sys/param.h> 11 #include <sys/systm.h> 12 #include <sys/namei.h> 13 #include <sys/proc.h> 14 #include <sys/kernel.h> 15 #include <sys/vnode.h> 16 #include <sys/specdev.h> 17 #include <sys/mount.h> 18 #include <sys/buf.h> 19 #include <sys/file.h> 20 #include <sys/disklabel.h> 21 #include <sys/ioctl.h> 22 #include <sys/errno.h> 23 #include <sys/malloc.h> 24 25 #include <ufs/ufs/quota.h> 26 #include <ufs/ufs/inode.h> 27 #include <ufs/ufs/ufsmount.h> 28 #include <ufs/ufs/ufs_extern.h> 29 30 #include <ufs/lfs/lfs.h> 31 #include <ufs/lfs/lfs_extern.h> 32 33 int lfs_mountfs __P((struct vnode *, struct mount *, struct proc *)); 34 35 struct vfsops lfs_vfsops = { 36 lfs_mount, 37 ufs_start, 38 lfs_unmount, 39 lfs_root, 40 ufs_quotactl, 41 lfs_statfs, 42 lfs_sync, 43 lfs_fhtovp, 44 lfs_vptofh, 45 lfs_init, 46 }; 47 48 int 49 lfs_mountroot() 50 { 51 panic("lfs_mountroot"); /* XXX -- implement */ 52 } 53 54 /* 55 * VFS Operations. 56 * 57 * mount system call 58 */ 59 lfs_mount(mp, path, data, ndp, p) 60 register struct mount *mp; 61 char *path; 62 caddr_t data; 63 struct nameidata *ndp; 64 struct proc *p; 65 { 66 struct vnode *devvp; 67 struct ufs_args args; 68 struct ufsmount *ump; 69 register struct lfs *fs; /* LFS */ 70 u_int size; 71 int error; 72 73 if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args))) 74 return (error); 75 76 /* Until LFS can do NFS right. XXX */ 77 if (args.exflags & MNT_EXPORTED) 78 return (EINVAL); 79 /* 80 * If updating, check whether changing from read-only to 81 * read/write; if there is no device name, that's all we do. 82 */ 83 if (mp->mnt_flag & MNT_UPDATE) { 84 ump = VFSTOUFS(mp); 85 #ifdef NOTLFS /* LFS */ 86 fs = ump->um_fs; 87 if (fs->fs_ronly && (mp->mnt_flag & MNT_RDONLY) == 0) 88 fs->fs_ronly = 0; 89 #else 90 fs = ump->um_lfs; 91 if (fs->lfs_ronly && (mp->mnt_flag & MNT_RDONLY) == 0) 92 fs->lfs_ronly = 0; 93 #endif 94 if (args.fspec == 0) { 95 /* 96 * Process export requests. 97 */ 98 if (args.exflags & MNT_EXPORTED) { 99 if (error = hang_addrlist(mp, &args)) 100 return (error); 101 mp->mnt_flag |= MNT_EXPORTED; 102 } 103 if (args.exflags & MNT_DELEXPORT) { 104 free_addrlist(ump); 105 mp->mnt_flag &= 106 ~(MNT_EXPORTED | MNT_DEFEXPORTED); 107 } 108 return (0); 109 } 110 } 111 /* 112 * Not an update, or updating the name: look up the name 113 * and verify that it refers to a sensible block device. 114 */ 115 ndp->ni_nameiop = LOOKUP | FOLLOW; 116 ndp->ni_segflg = UIO_USERSPACE; 117 ndp->ni_dirp = args.fspec; 118 if (error = namei(ndp, p)) 119 return (error); 120 devvp = ndp->ni_vp; 121 if (devvp->v_type != VBLK) { 122 vrele(devvp); 123 return (ENOTBLK); 124 } 125 if (major(devvp->v_rdev) >= nblkdev) { 126 vrele(devvp); 127 return (ENXIO); 128 } 129 if ((mp->mnt_flag & MNT_UPDATE) == 0) 130 error = lfs_mountfs(devvp, mp, p); /* LFS */ 131 else { 132 if (devvp != ump->um_devvp) 133 error = EINVAL; /* needs translation */ 134 else 135 vrele(devvp); 136 } 137 if (error) { 138 vrele(devvp); 139 return (error); 140 } 141 ump = VFSTOUFS(mp); 142 fs = ump->um_lfs; /* LFS */ 143 #ifdef NOTLFS /* LFS */ 144 (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size); 145 bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size); 146 bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, 147 MNAMELEN); 148 (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 149 &size); 150 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 151 (void) ufs_statfs(mp, &mp->mnt_stat, p); 152 #else 153 (void)copyinstr(path, fs->lfs_fsmnt, sizeof(fs->lfs_fsmnt) - 1, &size); 154 bzero(fs->lfs_fsmnt + size, sizeof(fs->lfs_fsmnt) - size); 155 bcopy((caddr_t)fs->lfs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, 156 MNAMELEN); 157 (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 158 &size); 159 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 160 (void) lfs_statfs(mp, &mp->mnt_stat, p); 161 #endif 162 return (0); 163 } 164 165 /* 166 * Common code for mount and mountroot 167 * LFS specific 168 */ 169 int 170 lfs_mountfs(devvp, mp, p) 171 register struct vnode *devvp; 172 struct mount *mp; 173 struct proc *p; 174 { 175 extern struct vnode *rootvp; 176 register struct lfs *fs; 177 register struct ufsmount *ump; 178 struct vnode *vp; 179 struct buf *bp; 180 struct partinfo dpart; 181 dev_t dev; 182 int error, i, ronly, size; 183 184 /* 185 * Disallow multiple mounts of the same device. 186 * Disallow mounting of a device that is currently in use 187 * (except for root, which might share swap device for miniroot). 188 * Flush out any old buffers remaining from a previous use. 189 */ 190 if (error = ufs_mountedon(devvp)) 191 return (error); 192 if (vcount(devvp) > 1 && devvp != rootvp) 193 return (EBUSY); 194 vinvalbuf(devvp, 1); 195 196 ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 197 if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p)) 198 return (error); 199 200 if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0) 201 size = DEV_BSIZE; 202 else { 203 size = dpart.disklab->d_secsize; 204 #ifdef NEVER_USED 205 dpart.part->p_fstype = FS_LFS; 206 dpart.part->p_fsize = fs->lfs_fsize; /* frag size */ 207 dpart.part->p_frag = fs->lfs_frag; /* frags per block */ 208 dpart.part->p_cpg = fs->lfs_segshift; /* segment shift */ 209 #endif 210 } 211 212 /* Don't free random space on error. */ 213 bp = NULL; 214 ump = NULL; 215 216 /* Read in the superblock. */ 217 if (error = bread(devvp, LFS_LABELPAD / size, LFS_SBPAD, NOCRED, &bp)) 218 goto out; 219 fs = bp->b_un.b_lfs; 220 221 /* Check the basics. */ 222 if (fs->lfs_magic != LFS_MAGIC || fs->lfs_bsize > MAXBSIZE || 223 fs->lfs_bsize < sizeof(struct lfs)) { 224 error = EINVAL; /* XXX needs translation */ 225 goto out; 226 } 227 #ifdef DEBUG 228 lfs_dump_super(fs); 229 #endif 230 231 /* Allocate the mount structure, copy the superblock into it. */ 232 ump = (struct ufsmount *)malloc(sizeof *ump, M_UFSMNT, M_WAITOK); 233 ump->um_lfs = malloc(sizeof(struct lfs), M_UFSMNT, M_WAITOK); 234 bcopy(bp->b_un.b_addr, ump->um_lfs, sizeof(struct lfs)); 235 if (sizeof(struct lfs) < LFS_SBPAD) /* XXX why? */ 236 bp->b_flags |= B_INVAL; 237 brelse(bp); 238 bp = NULL; 239 240 /* Set up the I/O information */ 241 fs->lfs_iocount = 0; 242 243 /* Set the file system readonly/modify bits. */ 244 fs = ump->um_lfs; 245 fs->lfs_ronly = ronly; 246 if (ronly == 0) 247 fs->lfs_fmod = 1; 248 249 /* Initialize the mount structure. */ 250 dev = devvp->v_rdev; 251 mp->mnt_data = (qaddr_t)ump; 252 mp->mnt_stat.f_fsid.val[0] = (long)dev; 253 mp->mnt_stat.f_fsid.val[1] = MOUNT_LFS; 254 mp->mnt_flag |= MNT_LOCAL; 255 ump->um_mountp = mp; 256 ump->um_dev = dev; 257 ump->um_devvp = devvp; 258 for (i = 0; i < MAXQUOTAS; i++) 259 ump->um_quotas[i] = NULLVP; 260 devvp->v_specflags |= SI_MOUNTEDON; 261 262 /* 263 * We use the ifile vnode for almost every operation. Instead of 264 * retrieving it from the hash table each time we retrieve it here, 265 * artificially increment the reference count and keep a pointer 266 * to it in the incore copy of the superblock. 267 */ 268 if (error = lfs_vget(mp, LFS_IFILE_INUM, &vp)) 269 goto out; 270 fs->lfs_ivnode = vp; 271 VREF(vp); 272 vput(vp); 273 274 return (0); 275 out: 276 if (bp) 277 brelse(bp); 278 (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p); 279 if (ump) { 280 free(ump->um_lfs, M_UFSMNT); 281 free(ump, M_UFSMNT); 282 mp->mnt_data = (qaddr_t)0; 283 } 284 return (error); 285 } 286 287 /* 288 * unmount system call 289 */ 290 lfs_unmount(mp, mntflags, p) 291 struct mount *mp; 292 int mntflags; 293 struct proc *p; 294 { 295 extern int doforce; 296 register struct ufsmount *ump; 297 register struct lfs *fs; /* LFS */ 298 int i, error, ronly, flags = 0; 299 int ndirty; /* LFS */ 300 301 #ifdef VERBOSE 302 printf("lfs_unmount\n"); 303 #endif 304 if (mntflags & MNT_FORCE) { 305 if (!doforce || mp == rootfs) 306 return (EINVAL); 307 flags |= FORCECLOSE; 308 } 309 if (error = lfs_segwrite(mp, 1)) 310 return(error); 311 312 ndirty = lfs_umountdebug(mp); 313 printf("lfs_umountdebug: returned %d dirty\n", ndirty); 314 return(0); 315 if (mntinvalbuf(mp)) 316 return (EBUSY); 317 ump = VFSTOUFS(mp); 318 #ifdef QUOTA 319 if (mp->mnt_flag & MNT_QUOTA) { 320 if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags)) 321 return (error); 322 for (i = 0; i < MAXQUOTAS; i++) { 323 if (ump->um_quotas[i] == NULLVP) 324 continue; 325 quotaoff(p, mp, i); 326 } 327 /* 328 * Here we fall through to vflush again to ensure 329 * that we have gotten rid of all the system vnodes. 330 */ 331 } 332 #endif 333 if (error = vflush(mp, NULLVP, flags)) 334 return (error); 335 fs = ump->um_lfs; 336 ronly = !fs->lfs_ronly; 337 vrele(fs->lfs_ivnode); 338 ump->um_devvp->v_specflags &= ~SI_MOUNTEDON; 339 error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE, 340 NOCRED, p); 341 vrele(ump->um_devvp); 342 free(fs, M_UFSMNT); 343 free(ump, M_UFSMNT); 344 mp->mnt_data = (qaddr_t)0; 345 mp->mnt_flag &= ~MNT_LOCAL; 346 return (error); 347 } 348 349 /* 350 * Return root of a filesystem 351 */ 352 int 353 lfs_root(mp, vpp) 354 struct mount *mp; 355 struct vnode **vpp; 356 { 357 struct vnode *nvp; 358 int error; 359 360 #ifdef VERBOSE 361 printf("lfs_root\n"); 362 #endif 363 if (error = lfs_vget(mp, (ino_t)ROOTINO, &nvp)) 364 return (error); 365 *vpp = nvp; 366 return (0); 367 } 368 369 /* 370 * Get file system statistics. 371 */ 372 lfs_statfs(mp, sbp, p) 373 struct mount *mp; 374 register struct statfs *sbp; 375 struct proc *p; 376 { 377 register struct lfs *fs; 378 register struct ufsmount *ump; 379 380 ump = VFSTOUFS(mp); 381 fs = ump->um_lfs; 382 if (fs->lfs_magic != LFS_MAGIC) 383 panic("lfs_statfs: magic"); 384 sbp->f_type = MOUNT_LFS; 385 sbp->f_bsize = fs->lfs_bsize; 386 sbp->f_iosize = fs->lfs_bsize; 387 sbp->f_blocks = fs->lfs_dsize; 388 sbp->f_bfree = fs->lfs_bfree; 389 sbp->f_bavail = (fs->lfs_dsize * (100 - fs->lfs_minfree) / 100) - 390 (fs->lfs_dsize - sbp->f_bfree); 391 sbp->f_files = fs->lfs_nfiles; 392 sbp->f_ffree = fs->lfs_bfree * INOPB(fs); 393 if (sbp != &mp->mnt_stat) { 394 bcopy((caddr_t)mp->mnt_stat.f_mntonname, 395 (caddr_t)&sbp->f_mntonname[0], MNAMELEN); 396 bcopy((caddr_t)mp->mnt_stat.f_mntfromname, 397 (caddr_t)&sbp->f_mntfromname[0], MNAMELEN); 398 } 399 return (0); 400 } 401 402 /* 403 * Go through the disk queues to initiate sandbagged IO; 404 * go through the inodes to write those that have been modified; 405 * initiate the writing of the super block if it has been modified. 406 * 407 * Note: we are always called with the filesystem marked `MPBUSY'. 408 */ 409 lfs_sync(mp, waitfor) 410 struct mount *mp; 411 int waitfor; 412 { 413 extern int crashandburn, syncprt; 414 int error; 415 416 #ifdef VERBOSE 417 printf("lfs_sync\n"); 418 #endif 419 420 #ifdef DIAGNOSTIC 421 if (crashandburn) 422 return (0); 423 #endif 424 if (syncprt) 425 ufs_bufstats(); 426 427 /* All syncs must be checkpoints until roll-forward is implemented. */ 428 error = lfs_segwrite(mp, 1); 429 #ifdef QUOTA 430 qsync(mp); 431 #endif 432 return (error); 433 } 434 435 /* 436 * File handle to vnode 437 * 438 * Have to be really careful about stale file handles: 439 * - check that the inode number is valid 440 * - call lfs_vget() to get the locked inode 441 * - check for an unallocated inode (i_mode == 0) 442 * - check that the generation number matches 443 * 444 * XXX 445 * use ifile to see if inode is allocated instead of reading off disk 446 * what is the relationship between my generational number and the NFS 447 * generational number. 448 */ 449 int 450 lfs_fhtovp(mp, fhp, setgen, vpp) 451 register struct mount *mp; 452 struct fid *fhp; 453 int setgen; 454 struct vnode **vpp; 455 { 456 register struct inode *ip; 457 register struct ufid *ufhp; 458 struct vnode *nvp; 459 int error; 460 461 ufhp = (struct ufid *)fhp; 462 if (ufhp->ufid_ino < ROOTINO) 463 return (EINVAL); 464 if (error = lfs_vget(mp, ufhp->ufid_ino, &nvp)) { 465 *vpp = NULLVP; 466 return (error); 467 } 468 ip = VTOI(nvp); 469 if (ip->i_mode == 0) { 470 ufs_iput(ip); 471 *vpp = NULLVP; 472 return (EINVAL); 473 } 474 if (ip->i_gen != ufhp->ufid_gen) { 475 if (setgen) 476 ufhp->ufid_gen = ip->i_gen; 477 else { 478 ufs_iput(ip); 479 *vpp = NULLVP; 480 return (EINVAL); 481 } 482 } 483 *vpp = nvp; 484 return (0); 485 } 486 487 /* 488 * Vnode pointer to File handle 489 */ 490 /* ARGSUSED */ 491 lfs_vptofh(vp, fhp) 492 struct vnode *vp; 493 struct fid *fhp; 494 { 495 register struct inode *ip; 496 register struct ufid *ufhp; 497 498 ip = VTOI(vp); 499 ufhp = (struct ufid *)fhp; 500 ufhp->ufid_len = sizeof(struct ufid); 501 ufhp->ufid_ino = ip->i_number; 502 ufhp->ufid_gen = ip->i_gen; 503 return (0); 504 } 505