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.70 (Berkeley) 12/31/91 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 * Process export requests. 81 */ 82 if ((args.exflags & MNT_EXPORTED) || (mp->mnt_flag & MNT_EXPORTED)) { 83 if (args.exflags & MNT_EXPORTED) 84 mp->mnt_flag |= MNT_EXPORTED; 85 else 86 mp->mnt_flag &= ~MNT_EXPORTED; 87 if (args.exflags & MNT_EXRDONLY) 88 mp->mnt_flag |= MNT_EXRDONLY; 89 else 90 mp->mnt_flag &= ~MNT_EXRDONLY; 91 mp->mnt_exroot = args.exroot; 92 } 93 /* 94 * If updating, check whether changing from read-only to 95 * read/write; if there is no device name, that's all we do. 96 */ 97 if (mp->mnt_flag & MNT_UPDATE) { 98 ump = VFSTOUFS(mp); 99 #ifdef NOTLFS /* LFS */ 100 fs = ump->um_fs; 101 if (fs->fs_ronly && (mp->mnt_flag & MNT_RDONLY) == 0) 102 fs->fs_ronly = 0; 103 #else 104 fs = ump->um_lfs; 105 if (fs->lfs_ronly && (mp->mnt_flag & MNT_RDONLY) == 0) 106 fs->lfs_ronly = 0; 107 #endif 108 if (args.fspec == 0) 109 return (0); 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 inode *ip; 179 struct vnode *vp; 180 struct buf *bp; 181 struct partinfo dpart; 182 daddr_t seg_addr; 183 dev_t dev; 184 int error, i, ronly, size; 185 186 /* 187 * Disallow multiple mounts of the same device. 188 * Disallow mounting of a device that is currently in use 189 * (except for root, which might share swap device for miniroot). 190 * Flush out any old buffers remaining from a previous use. 191 */ 192 if (error = ufs_mountedon(devvp)) 193 return (error); 194 if (vcount(devvp) > 1 && devvp != rootvp) 195 return (EBUSY); 196 vinvalbuf(devvp, 1); 197 198 ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 199 if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p)) 200 return (error); 201 202 if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0) 203 size = DEV_BSIZE; 204 else { 205 size = dpart.disklab->d_secsize; 206 #ifdef NEVER_USED 207 dpart.part->p_fstype = FS_LFS; 208 dpart.part->p_fsize = fs->lfs_fsize; /* frag size */ 209 dpart.part->p_frag = fs->lfs_frag; /* frags per block */ 210 dpart.part->p_cpg = fs->lfs_segshift; /* segment shift */ 211 #endif 212 } 213 214 /* Don't free random space on error. */ 215 bp = NULL; 216 ump = NULL; 217 218 /* Read in the superblock. */ 219 if (error = bread(devvp, LFS_LABELPAD / size, LFS_SBPAD, NOCRED, &bp)) 220 goto out; 221 fs = bp->b_un.b_lfs; 222 223 /* Check the basics. */ 224 if (fs->lfs_magic != LFS_MAGIC || fs->lfs_bsize > MAXBSIZE || 225 fs->lfs_bsize < sizeof(struct lfs)) { 226 error = EINVAL; /* XXX needs translation */ 227 goto out; 228 } 229 #ifdef DEBUG 230 lfs_dump_super(fs); 231 #endif 232 233 /* Allocate the mount structure, copy the superblock into it. */ 234 ump = (struct ufsmount *)malloc(sizeof *ump, M_UFSMNT, M_WAITOK); 235 ump->um_lfs = malloc(sizeof(struct lfs), M_UFSMNT, M_WAITOK); 236 bcopy(bp->b_un.b_addr, ump->um_lfs, sizeof(struct lfs)); 237 if (sizeof(struct lfs) < LFS_SBPAD) /* XXX why? */ 238 bp->b_flags |= B_INVAL; 239 brelse(bp); 240 bp = NULL; 241 242 /* Set up the I/O information */ 243 fs->lfs_iocount = 0; 244 /* XXX NOTUSED: fs->lfs_seglist = NULL; */ 245 246 /* Set the file system readonly/modify bits. */ 247 fs = ump->um_lfs; 248 fs->lfs_ronly = ronly; 249 if (ronly == 0) 250 fs->lfs_fmod = 1; 251 252 /* Initialize the mount structure. */ 253 dev = devvp->v_rdev; 254 mp->mnt_data = (qaddr_t)ump; 255 mp->mnt_stat.f_fsid.val[0] = (long)dev; 256 mp->mnt_stat.f_fsid.val[1] = MOUNT_LFS; 257 mp->mnt_flag |= MNT_LOCAL; 258 ump->um_mountp = mp; 259 ump->um_dev = dev; 260 ump->um_devvp = devvp; 261 for (i = 0; i < MAXQUOTAS; i++) 262 ump->um_quotas[i] = NULLVP; 263 264 /* Read the ifile disk inode and store it in a vnode. */ 265 if (error = bread(devvp, fs->lfs_idaddr, fs->lfs_bsize, NOCRED, &bp)) 266 goto out; 267 if (error = lfs_vcreate(mp, LFS_IFILE_INUM, &vp)) 268 goto out; 269 ip = VTOI(vp); 270 VREF(ip->i_devvp); 271 272 /* The ifile inode is stored in the superblock. */ 273 fs->lfs_ivnode = vp; 274 275 /* Copy the on-disk inode into place. */ 276 ip->i_din = *lfs_ifind(fs, LFS_IFILE_INUM, bp->b_un.b_dino); 277 brelse(bp); 278 279 /* Initialize the associated vnode */ 280 vp->v_type = IFTOVT(ip->i_mode); 281 282 devvp->v_specflags |= SI_MOUNTEDON; 283 VREF(ip->i_devvp); 284 return (0); 285 out: 286 if (bp) 287 brelse(bp); 288 (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p); 289 if (ump) { 290 free(ump->um_lfs, M_UFSMNT); 291 free(ump, M_UFSMNT); 292 mp->mnt_data = (qaddr_t)0; 293 } 294 return (error); 295 } 296 297 /* 298 * unmount system call 299 */ 300 lfs_unmount(mp, mntflags, p) 301 struct mount *mp; 302 int mntflags; 303 struct proc *p; 304 { 305 extern int doforce; 306 register struct ufsmount *ump; 307 register struct lfs *fs; /* LFS */ 308 int i, error, ronly, flags = 0; 309 int ndirty; /* LFS */ 310 311 #ifdef VERBOSE 312 printf("lfs_unmount\n"); 313 #endif 314 if (mntflags & MNT_FORCE) { 315 if (!doforce || mp == rootfs) 316 return (EINVAL); 317 flags |= FORCECLOSE; 318 } 319 if (error = lfs_segwrite(mp, 1)) 320 return(error); 321 322 ndirty = lfs_umountdebug(mp); 323 printf("lfs_umountdebug: returned %d dirty\n", ndirty); 324 return(0); 325 if (mntinvalbuf(mp)) 326 return (EBUSY); 327 ump = VFSTOUFS(mp); 328 #ifdef QUOTA 329 if (mp->mnt_flag & MNT_QUOTA) { 330 if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags)) 331 return (error); 332 for (i = 0; i < MAXQUOTAS; i++) { 333 if (ump->um_quotas[i] == NULLVP) 334 continue; 335 quotaoff(p, mp, i); 336 } 337 /* 338 * Here we fall through to vflush again to ensure 339 * that we have gotten rid of all the system vnodes. 340 */ 341 } 342 #endif 343 if (error = vflush(mp, NULLVP, flags)) 344 return (error); 345 #ifdef NOTLFS /* LFS */ 346 fs = ump->um_fs; 347 ronly = !fs->fs_ronly; 348 #else 349 fs = ump->um_lfs; 350 ronly = !fs->lfs_ronly; 351 #endif 352 ump->um_devvp->v_specflags &= ~SI_MOUNTEDON; 353 error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE, 354 NOCRED, p); 355 vrele(ump->um_devvp); 356 #ifdef NOTLFS /* LFS */ 357 free((caddr_t)fs->fs_csp[0], M_UFSMNT); 358 #else 359 iput(VTOI(fs->lfs_ivnode)); 360 #endif 361 free(fs, M_UFSMNT); 362 free(ump, M_UFSMNT); 363 mp->mnt_data = (qaddr_t)0; 364 mp->mnt_flag &= ~MNT_LOCAL; 365 return (error); 366 } 367 368 /* 369 * Return root of a filesystem 370 */ 371 int 372 lfs_root(mp, vpp) 373 struct mount *mp; 374 struct vnode **vpp; 375 { 376 struct vnode *nvp; 377 int error; 378 379 #ifdef VERBOSE 380 printf("lfs_root\n"); 381 #endif 382 if (error = lfs_vget(mp, (ino_t)ROOTINO, &nvp)) 383 return (error); 384 *vpp = nvp; 385 return (0); 386 } 387 388 /* 389 * Get file system statistics. 390 */ 391 lfs_statfs(mp, sbp, p) 392 struct mount *mp; 393 register struct statfs *sbp; 394 struct proc *p; 395 { 396 register struct lfs *fs; 397 register struct ufsmount *ump; 398 399 ump = VFSTOUFS(mp); 400 fs = ump->um_lfs; 401 if (fs->lfs_magic != LFS_MAGIC) 402 panic("lfs_statfs: magic"); 403 sbp->f_type = MOUNT_LFS; 404 sbp->f_bsize = fs->lfs_bsize; 405 sbp->f_iosize = fs->lfs_bsize; 406 sbp->f_blocks = fs->lfs_dsize; 407 sbp->f_bfree = fs->lfs_bfree; 408 sbp->f_bavail = (fs->lfs_dsize * (100 - fs->lfs_minfree) / 100) - 409 (fs->lfs_dsize - sbp->f_bfree); 410 sbp->f_files = fs->lfs_nfiles; 411 sbp->f_ffree = fs->lfs_bfree * INOPB(fs); 412 if (sbp != &mp->mnt_stat) { 413 bcopy((caddr_t)mp->mnt_stat.f_mntonname, 414 (caddr_t)&sbp->f_mntonname[0], MNAMELEN); 415 bcopy((caddr_t)mp->mnt_stat.f_mntfromname, 416 (caddr_t)&sbp->f_mntfromname[0], MNAMELEN); 417 } 418 return (0); 419 } 420 421 /* 422 * Go through the disk queues to initiate sandbagged IO; 423 * go through the inodes to write those that have been modified; 424 * initiate the writing of the super block if it has been modified. 425 * 426 * Note: we are always called with the filesystem marked `MPBUSY'. 427 */ 428 lfs_sync(mp, waitfor) 429 struct mount *mp; 430 int waitfor; 431 { 432 extern int crashandburn, syncprt; 433 int error; 434 435 #ifdef VERBOSE 436 printf("lfs_sync\n"); 437 #endif 438 439 #ifdef DIAGNOSTIC 440 if (crashandburn) 441 return (0); 442 #endif 443 if (syncprt) 444 ufs_bufstats(); 445 446 /* All syncs must be checkpoints until roll-forward is implemented. */ 447 error = lfs_segwrite(mp, 1); 448 #ifdef QUOTA 449 qsync(mp); 450 #endif 451 return (error); 452 } 453 454 /* 455 * File handle to vnode 456 * 457 * Have to be really careful about stale file handles: 458 * - check that the inode number is valid 459 * - call lfs_vget() to get the locked inode 460 * - check for an unallocated inode (i_mode == 0) 461 * - check that the generation number matches 462 * 463 * XXX 464 * use ifile to see if inode is allocated instead of reading off disk 465 * what is the relationship between my generational number and the NFS 466 * generational number. 467 */ 468 int 469 lfs_fhtovp(mp, fhp, vpp) 470 register struct mount *mp; 471 struct fid *fhp; 472 struct vnode **vpp; 473 { 474 register struct inode *ip; 475 register struct ufid *ufhp; 476 struct vnode *nvp; 477 int error; 478 479 ufhp = (struct ufid *)fhp; 480 if (ufhp->ufid_ino < ROOTINO) 481 return (EINVAL); 482 if (error = lfs_vget(mp, ufhp->ufid_ino, &nvp)) { 483 *vpp = NULLVP; 484 return (error); 485 } 486 ip = VTOI(nvp); 487 if (ip->i_mode == 0) { 488 ufs_iput(ip); 489 *vpp = NULLVP; 490 return (EINVAL); 491 } 492 if (ip->i_gen != ufhp->ufid_gen) { 493 ufs_iput(ip); 494 *vpp = NULLVP; 495 return (EINVAL); 496 } 497 *vpp = nvp; 498 return (0); 499 } 500 501 /* 502 * Vnode pointer to File handle 503 */ 504 /* ARGSUSED */ 505 lfs_vptofh(vp, fhp) 506 struct vnode *vp; 507 struct fid *fhp; 508 { 509 register struct inode *ip; 510 register struct ufid *ufhp; 511 512 ip = VTOI(vp); 513 ufhp = (struct ufid *)fhp; 514 ufhp->ufid_len = sizeof(struct ufid); 515 ufhp->ufid_ino = ip->i_number; 516 ufhp->ufid_gen = ip->i_gen; 517 return (0); 518 } 519