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