hpfs_vfsops.c revision 138487
1/*- 2 * Copyright (c) 1998, 1999 Semen Ustimenko (semenu@FreeBSD.org) 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: head/sys/fs/hpfs/hpfs_vfsops.c 138487 2004-12-06 20:14:20Z phk $ 27 */ 28 29 30#include <sys/param.h> 31#include <sys/systm.h> 32#include <sys/namei.h> 33#include <sys/conf.h> 34#include <sys/proc.h> 35#include <sys/kernel.h> 36#include <sys/vnode.h> 37#include <sys/mount.h> 38#include <sys/bio.h> 39#include <sys/buf.h> 40#include <sys/fcntl.h> 41#include <sys/malloc.h> 42 43#include <geom/geom.h> 44#include <geom/geom_vfs.h> 45 46#include <vm/vm.h> 47#include <vm/vm_param.h> 48#include <vm/vm_page.h> 49#include <vm/vm_object.h> 50#include <vm/vm_extern.h> 51 52#include <fs/hpfs/hpfs.h> 53#include <fs/hpfs/hpfsmount.h> 54#include <fs/hpfs/hpfs_subr.h> 55 56MALLOC_DEFINE(M_HPFSMNT, "HPFS mount", "HPFS mount structure"); 57MALLOC_DEFINE(M_HPFSNO, "HPFS node", "HPFS node structure"); 58 59struct sockaddr; 60 61static int hpfs_mountfs(register struct vnode *, struct mount *, 62 struct thread *); 63 64static vfs_init_t hpfs_init; 65static vfs_uninit_t hpfs_uninit; 66static vfs_fhtovp_t hpfs_fhtovp; 67static vfs_vget_t hpfs_vget; 68static vfs_cmount_t hpfs_cmount; 69static vfs_mount_t hpfs_mount; 70static vfs_root_t hpfs_root; 71static vfs_statfs_t hpfs_statfs; 72static vfs_unmount_t hpfs_unmount; 73static vfs_vptofh_t hpfs_vptofh; 74 75static int 76hpfs_init ( 77 struct vfsconf *vcp ) 78{ 79 dprintf(("hpfs_init():\n")); 80 81 hpfs_hphashinit(); 82 return 0; 83} 84 85static int 86hpfs_uninit (vfsp) 87 struct vfsconf *vfsp; 88{ 89 hpfs_hphashdestroy(); 90 return 0;; 91} 92 93static int 94hpfs_cmount ( 95 struct mntarg *ma, 96 void *data, 97 int flags, 98 struct thread *td ) 99{ 100 struct hpfs_args args; 101 int error; 102 103 error = copyin(data, (caddr_t)&args, sizeof (struct hpfs_args)); 104 if (error) 105 return (error); 106 107 ma = mount_argsu(ma, "from", args.fspec, MAXPATHLEN); 108 ma = mount_arg(ma, "export", &args.export, sizeof args.export); 109 ma = mount_argf(ma, "uid", "%d", args.uid); 110 ma = mount_argf(ma, "gid", "%d", args.gid); 111 ma = mount_argf(ma, "mode", "%d", args.mode); 112 if (args.flags & HPFSMNT_TABLES) { 113 ma = mount_arg(ma, "d2u", args.d2u, sizeof args.d2u); 114 ma = mount_arg(ma, "u2d", args.u2d, sizeof args.u2d); 115 } 116 117 error = kernel_mount(ma, flags); 118 119 return (error); 120} 121 122static const char *hpfs_opts[] = { 123 "from", "export", "uid", "gid", "mode", "d2u", "u2d", NULL 124}; 125 126static int 127hpfs_mount ( 128 struct mount *mp, 129 struct thread *td ) 130{ 131 int err = 0, error; 132 struct vnode *devvp; 133 struct hpfsmount *hpmp = 0; 134 struct nameidata ndp; 135 struct export_args export; 136 char *from; 137 138 dprintf(("hpfs_omount():\n")); 139 /* 140 *** 141 * Mounting non-root filesystem or updating a filesystem 142 *** 143 */ 144 if (vfs_filteropt(mp->mnt_optnew, hpfs_opts)) 145 return (EINVAL); 146 147 from = vfs_getopts(mp->mnt_optnew, "from", &error); 148 if (error) 149 return (error); 150 151 /* 152 * If updating, check whether changing from read-only to 153 * read/write; if there is no device name, that's all we do. 154 */ 155 if (mp->mnt_flag & MNT_UPDATE) { 156 dprintf(("hpfs_omount: MNT_UPDATE: ")); 157 158 hpmp = VFSTOHPFS(mp); 159 160 if (from == NULL) { 161 error = vfs_copyopt(mp->mnt_optnew, "export", 162 &export, sizeof export); 163 if (error) 164 return (error); 165 dprintf(("export 0x%x\n",args.export.ex_flags)); 166 err = vfs_export(mp, &export); 167 if (err) { 168 printf("hpfs_omount: vfs_export failed %d\n", 169 err); 170 } 171 goto success; 172 } else { 173 dprintf(("name [FAILED]\n")); 174 err = EINVAL; 175 goto success; 176 } 177 dprintf(("\n")); 178 } 179 180 /* 181 * Not an update, or updating the name: look up the name 182 * and verify that it refers to a sensible block device. 183 */ 184 NDINIT(&ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, from, td); 185 err = namei(&ndp); 186 if (err) { 187 /* can't get devvp!*/ 188 goto error_1; 189 } 190 191 devvp = ndp.ni_vp; 192 193 if (!vn_isdisk(devvp, &err)) 194 goto error_2; 195 196 /* 197 ******************** 198 * NEW MOUNT 199 ******************** 200 */ 201 202 /* 203 * Since this is a new mount, we want the names for 204 * the device and the mount point copied in. If an 205 * error occurs, the mountpoint is discarded by the 206 * upper level code. Note that vfs_omount() handles 207 * copying the mountpoint f_mntonname for us, so we 208 * don't have to do it here unless we want to set it 209 * to something other than "path" for some rason. 210 */ 211 /* Save "mounted from" info for mount point (NULL pad)*/ 212 vfs_mountedfrom(mp, from); 213 214 err = hpfs_mountfs(devvp, mp, td); 215 if (err) 216 goto error_2; 217 218 goto success; 219 220 221error_2: /* error with devvp held*/ 222 223 /* release devvp before failing*/ 224 vrele(devvp); 225 226error_1: /* no state to back out*/ 227 /* XXX: Missing NDFREE(&ndp, ...) */ 228 229success: 230 return( err); 231} 232 233/* 234 * Common code for mount and mountroot 235 */ 236int 237hpfs_mountfs(devvp, mp, td) 238 register struct vnode *devvp; 239 struct mount *mp; 240 struct thread *td; 241{ 242 int error, ronly, v; 243 struct sublock *sup; 244 struct spblock *spp; 245 struct hpfsmount *hpmp; 246 struct buf *bp = NULL; 247 struct vnode *vp; 248 struct cdev *dev = devvp->v_rdev; 249 struct g_consumer *cp; 250 struct bufobj *bo; 251 252 if (mp->mnt_flag & MNT_ROOTFS) 253 return (EOPNOTSUPP); 254 dprintf(("hpfs_mountfs():\n")); 255 ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 256 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); 257 /* XXX: use VOP_ACCESS to check FS perms */ 258 DROP_GIANT(); 259 g_topology_lock(); 260 error = g_vfs_open(devvp, &cp, "hpfs", ronly ? 0 : 1); 261 g_topology_unlock(); 262 PICKUP_GIANT(); 263 VOP_UNLOCK(devvp, 0, td); 264 if (error) 265 return (error); 266 267 bo = &devvp->v_bufobj; 268 bo->bo_private = cp; 269 bo->bo_ops = g_vfs_bufops; 270 271 /* 272 * Do actual mount 273 */ 274 hpmp = malloc(sizeof(struct hpfsmount), M_HPFSMNT, M_WAITOK | M_ZERO); 275 276 hpmp->hpm_cp = cp; 277 hpmp->hpm_bo = bo; 278 279 /* Read in SuperBlock */ 280 error = bread(devvp, SUBLOCK, SUSIZE, NOCRED, &bp); 281 if (error) 282 goto failed; 283 bcopy(bp->b_data, &hpmp->hpm_su, sizeof(struct sublock)); 284 brelse(bp); bp = NULL; 285 286 /* Read in SpareBlock */ 287 error = bread(devvp, SPBLOCK, SPSIZE, NOCRED, &bp); 288 if (error) 289 goto failed; 290 bcopy(bp->b_data, &hpmp->hpm_sp, sizeof(struct spblock)); 291 brelse(bp); bp = NULL; 292 293 sup = &hpmp->hpm_su; 294 spp = &hpmp->hpm_sp; 295 296 /* Check magic */ 297 if (sup->su_magic != SU_MAGIC) { 298 printf("hpfs_mountfs: SuperBlock MAGIC DOESN'T MATCH\n"); 299 error = EINVAL; 300 goto failed; 301 } 302 if (spp->sp_magic != SP_MAGIC) { 303 printf("hpfs_mountfs: SpareBlock MAGIC DOESN'T MATCH\n"); 304 error = EINVAL; 305 goto failed; 306 } 307 308 mp->mnt_data = (qaddr_t)hpmp; 309 hpmp->hpm_devvp = devvp; 310 hpmp->hpm_dev = devvp->v_rdev; 311 hpmp->hpm_mp = mp; 312 if (1 == vfs_scanopt(mp->mnt_optnew, "uid", "%d", &v)) 313 hpmp->hpm_uid = v; 314 if (1 == vfs_scanopt(mp->mnt_optnew, "gid", "%d", &v)) 315 hpmp->hpm_gid = v; 316 if (1 == vfs_scanopt(mp->mnt_optnew, "mode", "%d", &v)) 317 hpmp->hpm_mode = v; 318 319 error = hpfs_bminit(hpmp); 320 if (error) 321 goto failed; 322 323 error = hpfs_cpinit(mp, hpmp); 324 if (error) { 325 hpfs_bmdeinit(hpmp); 326 goto failed; 327 } 328 329 error = hpfs_root(mp, &vp, td); 330 if (error) { 331 hpfs_cpdeinit(hpmp); 332 hpfs_bmdeinit(hpmp); 333 goto failed; 334 } 335 336 vput(vp); 337 338 mp->mnt_stat.f_fsid.val[0] = (long)dev2udev(dev); 339 mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 340 mp->mnt_maxsymlinklen = 0; 341 mp->mnt_flag |= MNT_LOCAL; 342 return (0); 343 344failed: 345 if (bp) 346 brelse (bp); 347 mp->mnt_data = (qaddr_t)NULL; 348 g_wither_geom_close(cp->geom, ENXIO); 349 return (error); 350} 351 352static int 353hpfs_unmount( 354 struct mount *mp, 355 int mntflags, 356 struct thread *td) 357{ 358 int error, flags, ronly; 359 register struct hpfsmount *hpmp = VFSTOHPFS(mp); 360 361 dprintf(("hpfs_unmount():\n")); 362 363 ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 364 365 flags = 0; 366 if(mntflags & MNT_FORCE) 367 flags |= FORCECLOSE; 368 369 dprintf(("hpfs_unmount: vflushing...\n")); 370 371 error = vflush(mp, 0, flags, td); 372 if (error) { 373 printf("hpfs_unmount: vflush failed: %d\n",error); 374 return (error); 375 } 376 377 vinvalbuf(hpmp->hpm_devvp, V_SAVE, NOCRED, td, 0, 0); 378 g_wither_geom_close(hpmp->hpm_cp->geom, ENXIO); 379 vrele(hpmp->hpm_devvp); 380 381 dprintf(("hpfs_umount: freeing memory...\n")); 382 hpfs_cpdeinit(hpmp); 383 hpfs_bmdeinit(hpmp); 384 mp->mnt_data = (qaddr_t)0; 385 mp->mnt_flag &= ~MNT_LOCAL; 386 FREE(hpmp, M_HPFSMNT); 387 388 return (0); 389} 390 391static int 392hpfs_root( 393 struct mount *mp, 394 struct vnode **vpp, 395 struct thread *td ) 396{ 397 int error = 0; 398 struct hpfsmount *hpmp = VFSTOHPFS(mp); 399 400 dprintf(("hpfs_root():\n")); 401 error = VFS_VGET(mp, (ino_t)hpmp->hpm_su.su_rootfno, LK_EXCLUSIVE, vpp); 402 if(error) { 403 printf("hpfs_root: VFS_VGET failed: %d\n",error); 404 return (error); 405 } 406 407 return (error); 408} 409 410static int 411hpfs_statfs( 412 struct mount *mp, 413 struct statfs *sbp, 414 struct thread *td) 415{ 416 struct hpfsmount *hpmp = VFSTOHPFS(mp); 417 418 dprintf(("hpfs_statfs(): HPFS%d.%d\n", 419 hpmp->hpm_su.su_hpfsver, hpmp->hpm_su.su_fnctver)); 420 421 sbp->f_type = mp->mnt_vfc->vfc_typenum; 422 sbp->f_bsize = DEV_BSIZE; 423 sbp->f_iosize = DEV_BSIZE; 424 sbp->f_blocks = hpmp->hpm_su.su_btotal; 425 sbp->f_bfree = sbp->f_bavail = hpmp->hpm_bavail; 426 sbp->f_ffree = 0; 427 sbp->f_files = 0; 428 sbp->f_flags = mp->mnt_flag; 429 430 return (0); 431} 432 433/*ARGSUSED*/ 434static int 435hpfs_fhtovp( 436 struct mount *mp, 437 struct fid *fhp, 438 struct vnode **vpp) 439{ 440 struct vnode *nvp; 441 struct hpfid *hpfhp = (struct hpfid *)fhp; 442 int error; 443 444 if ((error = VFS_VGET(mp, hpfhp->hpfid_ino, LK_EXCLUSIVE, &nvp)) != 0) { 445 *vpp = NULLVP; 446 return (error); 447 } 448 /* XXX as unlink/rmdir/mkdir/creat are not currently possible 449 * with HPFS, we don't need to check anything else for now */ 450 *vpp = nvp; 451 452 return (0); 453} 454 455static int 456hpfs_vptofh( 457 struct vnode *vp, 458 struct fid *fhp) 459{ 460 register struct hpfsnode *hpp; 461 register struct hpfid *hpfhp; 462 463 hpp = VTOHP(vp); 464 hpfhp = (struct hpfid *)fhp; 465 hpfhp->hpfid_len = sizeof(struct hpfid); 466 hpfhp->hpfid_ino = hpp->h_no; 467 /* hpfhp->hpfid_gen = hpp->h_gen; */ 468 return (0); 469} 470 471static int 472hpfs_vget( 473 struct mount *mp, 474 ino_t ino, 475 int flags, 476 struct vnode **vpp) 477{ 478 struct hpfsmount *hpmp = VFSTOHPFS(mp); 479 struct vnode *vp; 480 struct hpfsnode *hp; 481 struct buf *bp; 482 struct thread *td = curthread; /* XXX */ 483 int error; 484 485 dprintf(("hpfs_vget(0x%x): ",ino)); 486 487 *vpp = NULL; 488 hp = NULL; 489 vp = NULL; 490 491 if ((error = hpfs_hphashvget(hpmp->hpm_dev, ino, flags, vpp, td)) != 0) 492 return (error); 493 if (*vpp != NULL) { 494 dprintf(("hashed\n")); 495 return (0); 496 } 497 498 /* 499 * We have to lock node creation for a while, 500 * but then we have to call getnewvnode(), 501 * this may cause hpfs_reclaim() to be called, 502 * this may need to VOP_VGET() parent dir for 503 * update reasons, and if parent is not in 504 * hash, we have to lock node creation... 505 * To solve this, we MALLOC, getnewvnode and init while 506 * not locked (probability of node appearence 507 * at that time is little, and anyway - we'll 508 * check for it). 509 */ 510 MALLOC(hp, struct hpfsnode *, sizeof(struct hpfsnode), 511 M_HPFSNO, M_WAITOK); 512 513 error = getnewvnode("hpfs", hpmp->hpm_mp, &hpfs_vnodeops, &vp); 514 if (error) { 515 printf("hpfs_vget: can't get new vnode\n"); 516 FREE(hp, M_HPFSNO); 517 return (error); 518 } 519 520 dprintf(("prenew ")); 521 522 vp->v_data = hp; 523 524 if (ino == (ino_t)hpmp->hpm_su.su_rootfno) 525 vp->v_vflag |= VV_ROOT; 526 527 528 mtx_init(&hp->h_interlock, "hpfsnode interlock", NULL, MTX_DEF); 529 530 hp->h_flag = H_INVAL; 531 hp->h_vp = vp; 532 hp->h_hpmp = hpmp; 533 hp->h_no = ino; 534 hp->h_dev = hpmp->hpm_dev; 535 hp->h_uid = hpmp->hpm_uid; 536 hp->h_gid = hpmp->hpm_uid; 537 hp->h_mode = hpmp->hpm_mode; 538 hp->h_devvp = hpmp->hpm_devvp; 539 VREF(hp->h_devvp); 540 541 error = vn_lock(vp, LK_EXCLUSIVE, td); 542 if (error) { 543 vput(vp); 544 return (error); 545 } 546 547 do { 548 if ((error = 549 hpfs_hphashvget(hpmp->hpm_dev, ino, flags, vpp, td))) { 550 vput(vp); 551 return (error); 552 } 553 if (*vpp != NULL) { 554 dprintf(("hashed2\n")); 555 vput(vp); 556 return (0); 557 } 558 } while(lockmgr(&hpfs_hphash_lock,LK_EXCLUSIVE|LK_SLEEPFAIL,NULL,NULL)); 559 560 hpfs_hphashins(hp); 561 562 lockmgr(&hpfs_hphash_lock, LK_RELEASE, NULL, NULL); 563 564 error = bread(hpmp->hpm_devvp, ino, FNODESIZE, NOCRED, &bp); 565 if (error) { 566 printf("hpfs_vget: can't read ino %d\n",ino); 567 vput(vp); 568 return (error); 569 } 570 bcopy(bp->b_data, &hp->h_fn, sizeof(struct fnode)); 571 brelse(bp); 572 573 if (hp->h_fn.fn_magic != FN_MAGIC) { 574 printf("hpfs_vget: MAGIC DOESN'T MATCH\n"); 575 vput(vp); 576 return (EINVAL); 577 } 578 579 vp->v_type = hp->h_fn.fn_flag ? VDIR:VREG; 580 hp->h_flag &= ~H_INVAL; 581 582 *vpp = vp; 583 584 return (0); 585} 586 587static struct vfsops hpfs_vfsops = { 588 .vfs_fhtovp = hpfs_fhtovp, 589 .vfs_init = hpfs_init, 590 .vfs_cmount = hpfs_cmount, 591 .vfs_mount = hpfs_mount, 592 .vfs_root = hpfs_root, 593 .vfs_statfs = hpfs_statfs, 594 .vfs_uninit = hpfs_uninit, 595 .vfs_unmount = hpfs_unmount, 596 .vfs_vget = hpfs_vget, 597 .vfs_vptofh = hpfs_vptofh, 598}; 599VFS_SET(hpfs_vfsops, hpfs, 0); 600