1 /* $NetBSD: lfs_vfsops.c,v 1.4 1994/12/15 19:51:06 mycroft Exp $ */ 2 3 /* 4 * Copyright (c) 1989, 1991, 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * @(#)lfs_vfsops.c 8.10 (Berkeley) 11/21/94 36 */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/namei.h> 41 #include <sys/proc.h> 42 #include <sys/kernel.h> 43 #include <sys/vnode.h> 44 #include <sys/mount.h> 45 #include <sys/buf.h> 46 #include <sys/mbuf.h> 47 #include <sys/file.h> 48 #include <sys/disklabel.h> 49 #include <sys/ioctl.h> 50 #include <sys/errno.h> 51 #include <sys/malloc.h> 52 #include <sys/socket.h> 53 54 #include <miscfs/specfs/specdev.h> 55 56 #include <ufs/ufs/quota.h> 57 #include <ufs/ufs/inode.h> 58 #include <ufs/ufs/ufsmount.h> 59 #include <ufs/ufs/ufs_extern.h> 60 61 #include <ufs/lfs/lfs.h> 62 #include <ufs/lfs/lfs_extern.h> 63 64 int lfs_mountfs __P((struct vnode *, struct mount *, struct proc *)); 65 66 struct vfsops lfs_vfsops = { 67 MOUNT_LFS, 68 lfs_mount, 69 ufs_start, 70 lfs_unmount, 71 ufs_root, 72 ufs_quotactl, 73 lfs_statfs, 74 lfs_sync, 75 lfs_vget, 76 lfs_fhtovp, 77 lfs_vptofh, 78 lfs_init, 79 }; 80 81 int 82 lfs_mountroot() 83 { 84 panic("lfs_mountroot"); /* XXX -- implement */ 85 } 86 87 /* 88 * VFS Operations. 89 * 90 * mount system call 91 */ 92 lfs_mount(mp, path, data, ndp, p) 93 register struct mount *mp; 94 char *path; 95 caddr_t data; 96 struct nameidata *ndp; 97 struct proc *p; 98 { 99 struct vnode *devvp; 100 struct ufs_args args; 101 struct ufsmount *ump; 102 register struct lfs *fs; /* LFS */ 103 u_int size; 104 int error; 105 mode_t accessmode; 106 107 if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args))) 108 return (error); 109 110 /* Until LFS can do NFS right. XXX */ 111 if (args.export.ex_flags & MNT_EXPORTED) 112 return (EINVAL); 113 114 /* 115 * If updating, check whether changing from read-only to 116 * read/write; if there is no device name, that's all we do. 117 */ 118 if (mp->mnt_flag & MNT_UPDATE) { 119 ump = VFSTOUFS(mp); 120 if (fs->lfs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) { 121 /* 122 * If upgrade to read-write by non-root, then verify 123 * that user has necessary permissions on the device. 124 */ 125 if (p->p_ucred->cr_uid != 0) { 126 VOP_LOCK(ump->um_devvp); 127 if (error = VOP_ACCESS(ump->um_devvp, 128 VREAD | VWRITE, p->p_ucred, p)) { 129 VOP_UNLOCK(ump->um_devvp); 130 return (error); 131 } 132 VOP_UNLOCK(ump->um_devvp); 133 } 134 fs->lfs_ronly = 0; 135 } 136 if (args.fspec == 0) { 137 /* 138 * Process export requests. 139 */ 140 return (vfs_export(mp, &ump->um_export, &args.export)); 141 } 142 } 143 /* 144 * Not an update, or updating the name: look up the name 145 * and verify that it refers to a sensible block device. 146 */ 147 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p); 148 if (error = namei(ndp)) 149 return (error); 150 devvp = ndp->ni_vp; 151 if (devvp->v_type != VBLK) { 152 vrele(devvp); 153 return (ENOTBLK); 154 } 155 if (major(devvp->v_rdev) >= nblkdev) { 156 vrele(devvp); 157 return (ENXIO); 158 } 159 /* 160 * If mount by non-root, then verify that user has necessary 161 * permissions on the device. 162 */ 163 if (p->p_ucred->cr_uid != 0) { 164 accessmode = VREAD; 165 if ((mp->mnt_flag & MNT_RDONLY) == 0) 166 accessmode |= VWRITE; 167 VOP_LOCK(devvp); 168 if (error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p)) { 169 vput(devvp); 170 return (error); 171 } 172 VOP_UNLOCK(devvp); 173 } 174 if ((mp->mnt_flag & MNT_UPDATE) == 0) 175 error = lfs_mountfs(devvp, mp, p); /* LFS */ 176 else { 177 if (devvp != ump->um_devvp) 178 error = EINVAL; /* needs translation */ 179 else 180 vrele(devvp); 181 } 182 if (error) { 183 vrele(devvp); 184 return (error); 185 } 186 ump = VFSTOUFS(mp); 187 fs = ump->um_lfs; /* LFS */ 188 #ifdef NOTLFS /* LFS */ 189 (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size); 190 bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size); 191 bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, 192 MNAMELEN); 193 #else 194 (void)copyinstr(path, fs->lfs_fsmnt, sizeof(fs->lfs_fsmnt) - 1, &size); 195 bzero(fs->lfs_fsmnt + size, sizeof(fs->lfs_fsmnt) - size); 196 bcopy((caddr_t)fs->lfs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, 197 MNAMELEN); 198 #endif 199 (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 200 &size); 201 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 202 return (0); 203 } 204 205 /* 206 * Common code for mount and mountroot 207 * LFS specific 208 */ 209 int 210 lfs_mountfs(devvp, mp, p) 211 register struct vnode *devvp; 212 struct mount *mp; 213 struct proc *p; 214 { 215 extern struct vnode *rootvp; 216 register struct lfs *fs; 217 register struct ufsmount *ump; 218 struct vnode *vp; 219 struct buf *bp; 220 struct partinfo dpart; 221 dev_t dev; 222 int error, i, ronly, size; 223 struct ucred *cred; 224 225 cred = p ? p->p_ucred : NOCRED; 226 /* 227 * Disallow multiple mounts of the same device. 228 * Disallow mounting of a device that is currently in use 229 * (except for root, which might share swap device for miniroot). 230 * Flush out any old buffers remaining from a previous use. 231 */ 232 if (error = vfs_mountedon(devvp)) 233 return (error); 234 if (vcount(devvp) > 1 && devvp != rootvp) 235 return (EBUSY); 236 if (error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0)) 237 return (error); 238 239 ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 240 if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p)) 241 return (error); 242 243 if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, p) != 0) 244 size = DEV_BSIZE; 245 else { 246 size = dpart.disklab->d_secsize; 247 #ifdef NEVER_USED 248 dpart.part->p_fstype = FS_LFS; 249 dpart.part->p_fsize = fs->lfs_fsize; /* frag size */ 250 dpart.part->p_frag = fs->lfs_frag; /* frags per block */ 251 dpart.part->p_cpg = fs->lfs_segshift; /* segment shift */ 252 #endif 253 } 254 255 /* Don't free random space on error. */ 256 bp = NULL; 257 ump = NULL; 258 259 /* Read in the superblock. */ 260 if (error = bread(devvp, LFS_LABELPAD / size, LFS_SBPAD, cred, &bp)) 261 goto out; 262 fs = (struct lfs *)bp->b_data; 263 264 /* Check the basics. */ 265 if (fs->lfs_magic != LFS_MAGIC || fs->lfs_bsize > MAXBSIZE || 266 fs->lfs_bsize < sizeof(struct lfs)) { 267 error = EINVAL; /* XXX needs translation */ 268 goto out; 269 } 270 271 /* Allocate the mount structure, copy the superblock into it. */ 272 ump = (struct ufsmount *)malloc(sizeof *ump, M_UFSMNT, M_WAITOK); 273 fs = ump->um_lfs = malloc(sizeof(struct lfs), M_UFSMNT, M_WAITOK); 274 bcopy(bp->b_data, fs, sizeof(struct lfs)); 275 if (sizeof(struct lfs) < LFS_SBPAD) /* XXX why? */ 276 bp->b_flags |= B_INVAL; 277 brelse(bp); 278 bp = NULL; 279 280 /* Set up the I/O information */ 281 fs->lfs_iocount = 0; 282 283 /* Set up the ifile and lock aflags */ 284 fs->lfs_doifile = 0; 285 fs->lfs_writer = 0; 286 fs->lfs_dirops = 0; 287 fs->lfs_seglock = 0; 288 289 /* Set the file system readonly/modify bits. */ 290 fs->lfs_ronly = ronly; 291 if (ronly == 0) 292 fs->lfs_fmod = 1; 293 294 /* Initialize the mount structure. */ 295 dev = devvp->v_rdev; 296 mp->mnt_data = (qaddr_t)ump; 297 mp->mnt_stat.f_fsid.val[0] = (long)dev; 298 mp->mnt_stat.f_fsid.val[1] = makefstype(MOUNT_LFS); 299 mp->mnt_maxsymlinklen = fs->lfs_maxsymlinklen; 300 mp->mnt_flag |= MNT_LOCAL; 301 ump->um_mountp = mp; 302 ump->um_dev = dev; 303 ump->um_devvp = devvp; 304 ump->um_bptrtodb = 0; 305 ump->um_seqinc = 1 << fs->lfs_fsbtodb; 306 ump->um_nindir = fs->lfs_nindir; 307 for (i = 0; i < MAXQUOTAS; i++) 308 ump->um_quotas[i] = NULLVP; 309 devvp->v_specflags |= SI_MOUNTEDON; 310 311 /* 312 * We use the ifile vnode for almost every operation. Instead of 313 * retrieving it from the hash table each time we retrieve it here, 314 * artificially increment the reference count and keep a pointer 315 * to it in the incore copy of the superblock. 316 */ 317 if (error = VFS_VGET(mp, LFS_IFILE_INUM, &vp)) 318 goto out; 319 fs->lfs_ivnode = vp; 320 VREF(vp); 321 vput(vp); 322 323 return (0); 324 out: 325 if (bp) 326 brelse(bp); 327 (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p); 328 if (ump) { 329 free(ump->um_lfs, M_UFSMNT); 330 free(ump, M_UFSMNT); 331 mp->mnt_data = (qaddr_t)0; 332 } 333 return (error); 334 } 335 336 /* 337 * unmount system call 338 */ 339 lfs_unmount(mp, mntflags, p) 340 struct mount *mp; 341 int mntflags; 342 struct proc *p; 343 { 344 extern int doforce; 345 register struct ufsmount *ump; 346 register struct lfs *fs; 347 int i, error, flags, ronly; 348 349 flags = 0; 350 if (mntflags & MNT_FORCE) { 351 if (!doforce || (mp->mnt_flag & MNT_ROOTFS)) 352 return (EINVAL); 353 flags |= FORCECLOSE; 354 } 355 356 ump = VFSTOUFS(mp); 357 fs = ump->um_lfs; 358 #ifdef QUOTA 359 if (mp->mnt_flag & MNT_QUOTA) { 360 if (error = vflush(mp, fs->lfs_ivnode, SKIPSYSTEM|flags)) 361 return (error); 362 for (i = 0; i < MAXQUOTAS; i++) { 363 if (ump->um_quotas[i] == NULLVP) 364 continue; 365 quotaoff(p, mp, i); 366 } 367 /* 368 * Here we fall through to vflush again to ensure 369 * that we have gotten rid of all the system vnodes. 370 */ 371 } 372 #endif 373 if (error = vflush(mp, fs->lfs_ivnode, flags)) 374 return (error); 375 fs->lfs_clean = 1; 376 if (error = VFS_SYNC(mp, 1, p->p_ucred, p)) 377 return (error); 378 if (fs->lfs_ivnode->v_dirtyblkhd.lh_first) 379 panic("lfs_unmount: still dirty blocks on ifile vnode\n"); 380 vrele(fs->lfs_ivnode); 381 vgone(fs->lfs_ivnode); 382 383 ronly = !fs->lfs_ronly; 384 ump->um_devvp->v_specflags &= ~SI_MOUNTEDON; 385 error = VOP_CLOSE(ump->um_devvp, 386 ronly ? FREAD : FREAD|FWRITE, NOCRED, p); 387 vrele(ump->um_devvp); 388 free(fs, M_UFSMNT); 389 free(ump, M_UFSMNT); 390 mp->mnt_data = (qaddr_t)0; 391 mp->mnt_flag &= ~MNT_LOCAL; 392 return (error); 393 } 394 395 /* 396 * Get file system statistics. 397 */ 398 lfs_statfs(mp, sbp, p) 399 struct mount *mp; 400 register struct statfs *sbp; 401 struct proc *p; 402 { 403 register struct lfs *fs; 404 register struct ufsmount *ump; 405 406 ump = VFSTOUFS(mp); 407 fs = ump->um_lfs; 408 if (fs->lfs_magic != LFS_MAGIC) 409 panic("lfs_statfs: magic"); 410 sbp->f_type = 0; 411 sbp->f_bsize = fs->lfs_bsize; 412 sbp->f_iosize = fs->lfs_bsize; 413 sbp->f_blocks = dbtofsb(fs,fs->lfs_dsize); 414 sbp->f_bfree = dbtofsb(fs, fs->lfs_bfree); 415 sbp->f_bavail = (fs->lfs_dsize * (100 - fs->lfs_minfree) / 100) - 416 (fs->lfs_dsize - fs->lfs_bfree); 417 sbp->f_bavail = dbtofsb(fs, sbp->f_bavail); 418 sbp->f_files = fs->lfs_nfiles; 419 sbp->f_ffree = sbp->f_bfree * INOPB(fs); 420 if (sbp != &mp->mnt_stat) { 421 bcopy((caddr_t)mp->mnt_stat.f_mntonname, 422 (caddr_t)&sbp->f_mntonname[0], MNAMELEN); 423 bcopy((caddr_t)mp->mnt_stat.f_mntfromname, 424 (caddr_t)&sbp->f_mntfromname[0], MNAMELEN); 425 } 426 strncpy(&sbp->f_fstypename[0], mp->mnt_op->vfs_name, MFSNAMELEN); 427 sbp->f_fstypename[MFSNAMELEN] = '\0'; 428 return (0); 429 } 430 431 /* 432 * Go through the disk queues to initiate sandbagged IO; 433 * go through the inodes to write those that have been modified; 434 * initiate the writing of the super block if it has been modified. 435 * 436 * Note: we are always called with the filesystem marked `MPBUSY'. 437 */ 438 lfs_sync(mp, waitfor, cred, p) 439 struct mount *mp; 440 int waitfor; 441 struct ucred *cred; 442 struct proc *p; 443 { 444 int error; 445 446 /* All syncs must be checkpoints until roll-forward is implemented. */ 447 error = lfs_segwrite(mp, SEGM_CKP | (waitfor ? SEGM_SYNC : 0)); 448 #ifdef QUOTA 449 qsync(mp); 450 #endif 451 return (error); 452 } 453 454 /* 455 * Look up an LFS dinode number to find its incore vnode. If not already 456 * in core, read it in from the specified device. Return the inode locked. 457 * Detection and handling of mount points must be done by the calling routine. 458 */ 459 int 460 lfs_vget(mp, ino, vpp) 461 struct mount *mp; 462 ino_t ino; 463 struct vnode **vpp; 464 { 465 register struct lfs *fs; 466 register struct inode *ip; 467 struct buf *bp; 468 struct ifile *ifp; 469 struct vnode *vp; 470 struct ufsmount *ump; 471 daddr_t daddr; 472 dev_t dev; 473 int error; 474 475 ump = VFSTOUFS(mp); 476 dev = ump->um_dev; 477 if ((*vpp = ufs_ihashget(dev, ino)) != NULL) 478 return (0); 479 480 /* Translate the inode number to a disk address. */ 481 fs = ump->um_lfs; 482 if (ino == LFS_IFILE_INUM) 483 daddr = fs->lfs_idaddr; 484 else { 485 LFS_IENTRY(ifp, fs, ino, bp); 486 daddr = ifp->if_daddr; 487 brelse(bp); 488 if (daddr == LFS_UNUSED_DADDR) 489 return (ENOENT); 490 } 491 492 /* Allocate new vnode/inode. */ 493 if (error = lfs_vcreate(mp, ino, &vp)) { 494 *vpp = NULL; 495 return (error); 496 } 497 498 /* 499 * Put it onto its hash chain and lock it so that other requests for 500 * this inode will block if they arrive while we are sleeping waiting 501 * for old data structures to be purged or for the contents of the 502 * disk portion of this inode to be read. 503 */ 504 ip = VTOI(vp); 505 ufs_ihashins(ip); 506 507 /* 508 * XXX 509 * This may not need to be here, logically it should go down with 510 * the i_devvp initialization. 511 * Ask Kirk. 512 */ 513 ip->i_lfs = ump->um_lfs; 514 515 /* Read in the disk contents for the inode, copy into the inode. */ 516 if (error = 517 bread(ump->um_devvp, daddr, (int)fs->lfs_bsize, NOCRED, &bp)) { 518 /* 519 * The inode does not contain anything useful, so it would 520 * be misleading to leave it on its hash chain. With mode 521 * still zero, it will be unlinked and returned to the free 522 * list by vput(). 523 */ 524 vput(vp); 525 brelse(bp); 526 *vpp = NULL; 527 return (error); 528 } 529 ip->i_din = *lfs_ifind(fs, ino, (struct dinode *)bp->b_data); 530 brelse(bp); 531 532 /* 533 * Initialize the vnode from the inode, check for aliases. In all 534 * cases re-init ip, the underlying vnode/inode may have changed. 535 */ 536 if (error = ufs_vinit(mp, lfs_specop_p, LFS_FIFOOPS, &vp)) { 537 vput(vp); 538 *vpp = NULL; 539 return (error); 540 } 541 /* 542 * Finish inode initialization now that aliasing has been resolved. 543 */ 544 ip->i_devvp = ump->um_devvp; 545 VREF(ip->i_devvp); 546 *vpp = vp; 547 return (0); 548 } 549 550 /* 551 * File handle to vnode 552 * 553 * Have to be really careful about stale file handles: 554 * - check that the inode number is valid 555 * - call lfs_vget() to get the locked inode 556 * - check for an unallocated inode (i_mode == 0) 557 * - check that the given client host has export rights and return 558 * those rights via. exflagsp and credanonp 559 * 560 * XXX 561 * use ifile to see if inode is allocated instead of reading off disk 562 * what is the relationship between my generational number and the NFS 563 * generational number. 564 */ 565 int 566 lfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) 567 register struct mount *mp; 568 struct fid *fhp; 569 struct mbuf *nam; 570 struct vnode **vpp; 571 int *exflagsp; 572 struct ucred **credanonp; 573 { 574 register struct ufid *ufhp; 575 576 ufhp = (struct ufid *)fhp; 577 if (ufhp->ufid_ino < ROOTINO) 578 return (ESTALE); 579 return (ufs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp)); 580 } 581 582 /* 583 * Vnode pointer to File handle 584 */ 585 /* ARGSUSED */ 586 lfs_vptofh(vp, fhp) 587 struct vnode *vp; 588 struct fid *fhp; 589 { 590 register struct inode *ip; 591 register struct ufid *ufhp; 592 593 ip = VTOI(vp); 594 ufhp = (struct ufid *)fhp; 595 ufhp->ufid_len = sizeof(struct ufid); 596 ufhp->ufid_ino = ip->i_number; 597 ufhp->ufid_gen = ip->i_gen; 598 return (0); 599 } 600