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.74 (Berkeley) 05/14/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 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p); 116 if (error = namei(ndp)) 117 return (error); 118 devvp = ndp->ni_vp; 119 if (devvp->v_type != VBLK) { 120 vrele(devvp); 121 return (ENOTBLK); 122 } 123 if (major(devvp->v_rdev) >= nblkdev) { 124 vrele(devvp); 125 return (ENXIO); 126 } 127 if ((mp->mnt_flag & MNT_UPDATE) == 0) 128 error = lfs_mountfs(devvp, mp, p); /* LFS */ 129 else { 130 if (devvp != ump->um_devvp) 131 error = EINVAL; /* needs translation */ 132 else 133 vrele(devvp); 134 } 135 if (error) { 136 vrele(devvp); 137 return (error); 138 } 139 ump = VFSTOUFS(mp); 140 fs = ump->um_lfs; /* LFS */ 141 #ifdef NOTLFS /* LFS */ 142 (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size); 143 bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size); 144 bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, 145 MNAMELEN); 146 (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 147 &size); 148 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 149 (void) ufs_statfs(mp, &mp->mnt_stat, p); 150 #else 151 (void)copyinstr(path, fs->lfs_fsmnt, sizeof(fs->lfs_fsmnt) - 1, &size); 152 bzero(fs->lfs_fsmnt + size, sizeof(fs->lfs_fsmnt) - size); 153 bcopy((caddr_t)fs->lfs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, 154 MNAMELEN); 155 (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 156 &size); 157 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 158 (void) lfs_statfs(mp, &mp->mnt_stat, p); 159 #endif 160 return (0); 161 } 162 163 /* 164 * Common code for mount and mountroot 165 * LFS specific 166 */ 167 int 168 lfs_mountfs(devvp, mp, p) 169 register struct vnode *devvp; 170 struct mount *mp; 171 struct proc *p; 172 { 173 USES_VOP_CLOSE; 174 USES_VOP_IOCTL; 175 USES_VOP_OPEN; 176 USES_VOP_VGET; 177 extern struct vnode *rootvp; 178 register struct lfs *fs; 179 register struct ufsmount *ump; 180 struct vnode *vp; 181 struct buf *bp; 182 struct partinfo dpart; 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 245 /* Set the file system readonly/modify bits. */ 246 fs = ump->um_lfs; 247 fs->lfs_ronly = ronly; 248 if (ronly == 0) 249 fs->lfs_fmod = 1; 250 251 /* Initialize the mount structure. */ 252 dev = devvp->v_rdev; 253 mp->mnt_data = (qaddr_t)ump; 254 mp->mnt_stat.f_fsid.val[0] = (long)dev; 255 mp->mnt_stat.f_fsid.val[1] = MOUNT_LFS; 256 mp->mnt_flag |= MNT_LOCAL; 257 ump->um_mountp = mp; 258 ump->um_dev = dev; 259 ump->um_devvp = devvp; 260 for (i = 0; i < MAXQUOTAS; i++) 261 ump->um_quotas[i] = NULLVP; 262 devvp->v_specflags |= SI_MOUNTEDON; 263 264 /* 265 * We use the ifile vnode for almost every operation. Instead of 266 * retrieving it from the hash table each time we retrieve it here, 267 * artificially increment the reference count and keep a pointer 268 * to it in the incore copy of the superblock. 269 */ 270 if (error = LFS_VGET(mp, LFS_IFILE_INUM, &vp)) 271 goto out; 272 fs->lfs_ivnode = vp; 273 VREF(vp); 274 vput(vp); 275 276 return (0); 277 out: 278 if (bp) 279 brelse(bp); 280 (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p); 281 if (ump) { 282 free(ump->um_lfs, M_UFSMNT); 283 free(ump, M_UFSMNT); 284 mp->mnt_data = (qaddr_t)0; 285 } 286 return (error); 287 } 288 289 /* 290 * unmount system call 291 */ 292 lfs_unmount(mp, mntflags, p) 293 struct mount *mp; 294 int mntflags; 295 struct proc *p; 296 { 297 USES_VOP_CLOSE; 298 extern int doforce; 299 register struct ufsmount *ump; 300 register struct lfs *fs; /* LFS */ 301 int i, error, ronly, flags = 0; 302 int ndirty; /* LFS */ 303 304 #ifdef VERBOSE 305 printf("lfs_unmount\n"); 306 #endif 307 if (mntflags & MNT_FORCE) { 308 if (!doforce || mp == rootfs) 309 return (EINVAL); 310 flags |= FORCECLOSE; 311 } 312 if (error = lfs_segwrite(mp, 1)) 313 return(error); 314 315 ndirty = lfs_umountdebug(mp); 316 printf("lfs_umountdebug: returned %d dirty\n", ndirty); 317 return(0); 318 if (mntinvalbuf(mp)) 319 return (EBUSY); 320 ump = VFSTOUFS(mp); 321 #ifdef QUOTA 322 if (mp->mnt_flag & MNT_QUOTA) { 323 if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags)) 324 return (error); 325 for (i = 0; i < MAXQUOTAS; i++) { 326 if (ump->um_quotas[i] == NULLVP) 327 continue; 328 quotaoff(p, mp, i); 329 } 330 /* 331 * Here we fall through to vflush again to ensure 332 * that we have gotten rid of all the system vnodes. 333 */ 334 } 335 #endif 336 if (error = vflush(mp, NULLVP, flags)) 337 return (error); 338 fs = ump->um_lfs; 339 ronly = !fs->lfs_ronly; 340 vrele(fs->lfs_ivnode); 341 ump->um_devvp->v_specflags &= ~SI_MOUNTEDON; 342 error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE, 343 NOCRED, p); 344 vrele(ump->um_devvp); 345 free(fs, M_UFSMNT); 346 free(ump, M_UFSMNT); 347 mp->mnt_data = (qaddr_t)0; 348 mp->mnt_flag &= ~MNT_LOCAL; 349 return (error); 350 } 351 352 /* 353 * Return root of a filesystem 354 */ 355 int 356 lfs_root(mp, vpp) 357 struct mount *mp; 358 struct vnode **vpp; 359 { 360 USES_VOP_VGET; 361 struct vnode *nvp; 362 int error; 363 364 #ifdef VERBOSE 365 printf("lfs_root\n"); 366 #endif 367 if (error = LFS_VGET(mp, (ino_t)ROOTINO, &nvp)) 368 return (error); 369 *vpp = nvp; 370 return (0); 371 } 372 373 /* 374 * Get file system statistics. 375 */ 376 lfs_statfs(mp, sbp, p) 377 struct mount *mp; 378 register struct statfs *sbp; 379 struct proc *p; 380 { 381 register struct lfs *fs; 382 register struct ufsmount *ump; 383 384 ump = VFSTOUFS(mp); 385 fs = ump->um_lfs; 386 if (fs->lfs_magic != LFS_MAGIC) 387 panic("lfs_statfs: magic"); 388 sbp->f_type = MOUNT_LFS; 389 sbp->f_bsize = fs->lfs_bsize; 390 sbp->f_iosize = fs->lfs_bsize; 391 sbp->f_blocks = fs->lfs_dsize; 392 sbp->f_bfree = fs->lfs_bfree; 393 sbp->f_bavail = (fs->lfs_dsize * (100 - fs->lfs_minfree) / 100) - 394 (fs->lfs_dsize - sbp->f_bfree); 395 sbp->f_files = fs->lfs_nfiles; 396 sbp->f_ffree = fs->lfs_bfree * INOPB(fs); 397 if (sbp != &mp->mnt_stat) { 398 bcopy((caddr_t)mp->mnt_stat.f_mntonname, 399 (caddr_t)&sbp->f_mntonname[0], MNAMELEN); 400 bcopy((caddr_t)mp->mnt_stat.f_mntfromname, 401 (caddr_t)&sbp->f_mntfromname[0], MNAMELEN); 402 } 403 return (0); 404 } 405 406 /* 407 * Go through the disk queues to initiate sandbagged IO; 408 * go through the inodes to write those that have been modified; 409 * initiate the writing of the super block if it has been modified. 410 * 411 * Note: we are always called with the filesystem marked `MPBUSY'. 412 */ 413 lfs_sync(mp, waitfor) 414 struct mount *mp; 415 int waitfor; 416 { 417 extern int crashandburn, syncprt; 418 int error; 419 420 #ifdef VERBOSE 421 printf("lfs_sync\n"); 422 #endif 423 424 #ifdef DIAGNOSTIC 425 if (crashandburn) 426 return (0); 427 #endif 428 if (syncprt) 429 ufs_bufstats(); 430 431 /* All syncs must be checkpoints until roll-forward is implemented. */ 432 error = lfs_segwrite(mp, 1); 433 #ifdef QUOTA 434 qsync(mp); 435 #endif 436 return (error); 437 } 438 439 /* 440 * File handle to vnode 441 * 442 * Have to be really careful about stale file handles: 443 * - check that the inode number is valid 444 * - call lfs_vget() to get the locked inode 445 * - check for an unallocated inode (i_mode == 0) 446 * - check that the generation number matches 447 * 448 * XXX 449 * use ifile to see if inode is allocated instead of reading off disk 450 * what is the relationship between my generational number and the NFS 451 * generational number. 452 */ 453 int 454 lfs_fhtovp(mp, fhp, setgen, vpp) 455 register struct mount *mp; 456 struct fid *fhp; 457 int setgen; 458 struct vnode **vpp; 459 { 460 USES_VOP_VGET; 461 register struct inode *ip; 462 register struct ufid *ufhp; 463 struct vnode *nvp; 464 int error; 465 466 ufhp = (struct ufid *)fhp; 467 if (ufhp->ufid_ino < ROOTINO) 468 return (EINVAL); 469 if (error = LFS_VGET(mp, ufhp->ufid_ino, &nvp)) { 470 *vpp = NULLVP; 471 return (error); 472 } 473 ip = VTOI(nvp); 474 if (ip->i_mode == 0) { 475 ufs_iput(ip); 476 *vpp = NULLVP; 477 return (EINVAL); 478 } 479 if (ip->i_gen != ufhp->ufid_gen) { 480 if (setgen) 481 ufhp->ufid_gen = ip->i_gen; 482 else { 483 ufs_iput(ip); 484 *vpp = NULLVP; 485 return (EINVAL); 486 } 487 } 488 *vpp = nvp; 489 return (0); 490 } 491 492 /* 493 * Vnode pointer to File handle 494 */ 495 /* ARGSUSED */ 496 lfs_vptofh(vp, fhp) 497 struct vnode *vp; 498 struct fid *fhp; 499 { 500 register struct inode *ip; 501 register struct ufid *ufhp; 502 503 ip = VTOI(vp); 504 ufhp = (struct ufid *)fhp; 505 ufhp->ufid_len = sizeof(struct ufid); 506 ufhp->ufid_ino = ip->i_number; 507 ufhp->ufid_gen = ip->i_gen; 508 return (0); 509 } 510