hpfs_vfsops.c revision 137040
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 137040 2004-10-29 10:43:07Z 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 hpfs_args *, 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_omount_t hpfs_omount; 69static vfs_root_t hpfs_root; 70static vfs_statfs_t hpfs_statfs; 71static vfs_unmount_t hpfs_unmount; 72static vfs_vptofh_t hpfs_vptofh; 73 74static int 75hpfs_init ( 76 struct vfsconf *vcp ) 77{ 78 dprintf(("hpfs_init():\n")); 79 80 hpfs_hphashinit(); 81 return 0; 82} 83 84static int 85hpfs_uninit (vfsp) 86 struct vfsconf *vfsp; 87{ 88 hpfs_hphashdestroy(); 89 return 0;; 90} 91 92static int 93hpfs_omount ( 94 struct mount *mp, 95 char *path, 96 caddr_t data, 97 struct thread *td ) 98{ 99 size_t size; 100 int err = 0; 101 struct vnode *devvp; 102 struct hpfs_args args; 103 struct hpfsmount *hpmp = 0; 104 struct nameidata ndp; 105 106 dprintf(("hpfs_omount():\n")); 107 /* 108 *** 109 * Mounting non-root filesystem or updating a filesystem 110 *** 111 */ 112 113 /* copy in user arguments*/ 114 err = copyin(data, (caddr_t)&args, sizeof (struct hpfs_args)); 115 if (err) 116 goto error_1; /* can't get arguments*/ 117 118 /* 119 * If updating, check whether changing from read-only to 120 * read/write; if there is no device name, that's all we do. 121 */ 122 if (mp->mnt_flag & MNT_UPDATE) { 123 dprintf(("hpfs_omount: MNT_UPDATE: ")); 124 125 hpmp = VFSTOHPFS(mp); 126 127 if (args.fspec == 0) { 128 dprintf(("export 0x%x\n",args.export.ex_flags)); 129 err = vfs_export(mp, &args.export); 130 if (err) { 131 printf("hpfs_omount: vfs_export failed %d\n", 132 err); 133 } 134 goto success; 135 } else { 136 dprintf(("name [FAILED]\n")); 137 err = EINVAL; 138 goto success; 139 } 140 dprintf(("\n")); 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, td); 148 err = namei(&ndp); 149 if (err) { 150 /* can't get devvp!*/ 151 goto error_1; 152 } 153 154 devvp = ndp.ni_vp; 155 156 if (!vn_isdisk(devvp, &err)) 157 goto error_2; 158 159 /* 160 ******************** 161 * NEW MOUNT 162 ******************** 163 */ 164 165 /* 166 * Since this is a new mount, we want the names for 167 * the device and the mount point copied in. If an 168 * error occurs, the mountpoint is discarded by the 169 * upper level code. Note that vfs_omount() handles 170 * copying the mountpoint f_mntonname for us, so we 171 * don't have to do it here unless we want to set it 172 * to something other than "path" for some rason. 173 */ 174 /* Save "mounted from" info for mount point (NULL pad)*/ 175 copyinstr( args.fspec, /* device name*/ 176 mp->mnt_stat.f_mntfromname, /* save area*/ 177 MNAMELEN - 1, /* max size*/ 178 &size); /* real size*/ 179 bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 180 181 err = hpfs_mountfs(devvp, mp, &args, td); 182 if (err) 183 goto error_2; 184 185 /* 186 * Initialize FS stat information in mount struct; uses both 187 * mp->mnt_stat.f_mntonname and mp->mnt_stat.f_mntfromname 188 * 189 * This code is common to root and non-root mounts 190 */ 191 (void)VFS_STATFS(mp, &mp->mnt_stat, td); 192 193 goto success; 194 195 196error_2: /* error with devvp held*/ 197 198 /* release devvp before failing*/ 199 vrele(devvp); 200 201error_1: /* no state to back out*/ 202 /* XXX: Missing NDFREE(&ndp, ...) */ 203 204success: 205 return( err); 206} 207 208/* 209 * Common code for mount and mountroot 210 */ 211int 212hpfs_mountfs(devvp, mp, argsp, td) 213 register struct vnode *devvp; 214 struct mount *mp; 215 struct hpfs_args *argsp; 216 struct thread *td; 217{ 218 int error, ronly; 219 struct sublock *sup; 220 struct spblock *spp; 221 struct hpfsmount *hpmp; 222 struct buf *bp = NULL; 223 struct vnode *vp; 224 struct cdev *dev = devvp->v_rdev; 225 struct g_consumer *cp; 226 struct bufobj *bo; 227 228 dprintf(("hpfs_mountfs():\n")); 229 ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 230 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); 231 /* XXX: use VOP_ACCESS to check FS perms */ 232 DROP_GIANT(); 233 g_topology_lock(); 234 error = g_vfs_open(devvp, &cp, "hpfs", ronly ? 0 : 1); 235 g_topology_unlock(); 236 PICKUP_GIANT(); 237 VOP_UNLOCK(devvp, 0, td); 238 if (error) 239 return (error); 240 241 bo = &devvp->v_bufobj; 242 bo->bo_private = cp; 243 bo->bo_ops = g_vfs_bufops; 244 245 /* 246 * Do actual mount 247 */ 248 hpmp = malloc(sizeof(struct hpfsmount), M_HPFSMNT, M_WAITOK | M_ZERO); 249 250 hpmp->hpm_cp = cp; 251 hpmp->hpm_bo = bo; 252 253 /* Read in SuperBlock */ 254 error = bread(devvp, SUBLOCK, SUSIZE, NOCRED, &bp); 255 if (error) 256 goto failed; 257 bcopy(bp->b_data, &hpmp->hpm_su, sizeof(struct sublock)); 258 brelse(bp); bp = NULL; 259 260 /* Read in SpareBlock */ 261 error = bread(devvp, SPBLOCK, SPSIZE, NOCRED, &bp); 262 if (error) 263 goto failed; 264 bcopy(bp->b_data, &hpmp->hpm_sp, sizeof(struct spblock)); 265 brelse(bp); bp = NULL; 266 267 sup = &hpmp->hpm_su; 268 spp = &hpmp->hpm_sp; 269 270 /* Check magic */ 271 if (sup->su_magic != SU_MAGIC) { 272 printf("hpfs_mountfs: SuperBlock MAGIC DOESN'T MATCH\n"); 273 error = EINVAL; 274 goto failed; 275 } 276 if (spp->sp_magic != SP_MAGIC) { 277 printf("hpfs_mountfs: SpareBlock MAGIC DOESN'T MATCH\n"); 278 error = EINVAL; 279 goto failed; 280 } 281 282 mp->mnt_data = (qaddr_t)hpmp; 283 hpmp->hpm_devvp = devvp; 284 hpmp->hpm_dev = devvp->v_rdev; 285 hpmp->hpm_mp = mp; 286 hpmp->hpm_uid = argsp->uid; 287 hpmp->hpm_gid = argsp->gid; 288 hpmp->hpm_mode = argsp->mode; 289 290 error = hpfs_bminit(hpmp); 291 if (error) 292 goto failed; 293 294 error = hpfs_cpinit(hpmp, argsp); 295 if (error) { 296 hpfs_bmdeinit(hpmp); 297 goto failed; 298 } 299 300 error = hpfs_root(mp, &vp, td); 301 if (error) { 302 hpfs_cpdeinit(hpmp); 303 hpfs_bmdeinit(hpmp); 304 goto failed; 305 } 306 307 vput(vp); 308 309 mp->mnt_stat.f_fsid.val[0] = (long)dev2udev(dev); 310 mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 311 mp->mnt_maxsymlinklen = 0; 312 mp->mnt_flag |= MNT_LOCAL; 313 return (0); 314 315failed: 316 if (bp) 317 brelse (bp); 318 mp->mnt_data = (qaddr_t)NULL; 319 g_wither_geom_close(cp->geom, ENXIO); 320 return (error); 321} 322 323static int 324hpfs_unmount( 325 struct mount *mp, 326 int mntflags, 327 struct thread *td) 328{ 329 int error, flags, ronly; 330 register struct hpfsmount *hpmp = VFSTOHPFS(mp); 331 332 dprintf(("hpfs_unmount():\n")); 333 334 ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 335 336 flags = 0; 337 if(mntflags & MNT_FORCE) 338 flags |= FORCECLOSE; 339 340 dprintf(("hpfs_unmount: vflushing...\n")); 341 342 error = vflush(mp, 0, flags, td); 343 if (error) { 344 printf("hpfs_unmount: vflush failed: %d\n",error); 345 return (error); 346 } 347 348 vinvalbuf(hpmp->hpm_devvp, V_SAVE, NOCRED, td, 0, 0); 349 g_wither_geom_close(hpmp->hpm_cp->geom, ENXIO); 350 vrele(hpmp->hpm_devvp); 351 352 dprintf(("hpfs_umount: freeing memory...\n")); 353 hpfs_cpdeinit(hpmp); 354 hpfs_bmdeinit(hpmp); 355 mp->mnt_data = (qaddr_t)0; 356 mp->mnt_flag &= ~MNT_LOCAL; 357 FREE(hpmp, M_HPFSMNT); 358 359 return (0); 360} 361 362static int 363hpfs_root( 364 struct mount *mp, 365 struct vnode **vpp, 366 struct thread *td ) 367{ 368 int error = 0; 369 struct hpfsmount *hpmp = VFSTOHPFS(mp); 370 371 dprintf(("hpfs_root():\n")); 372 error = VFS_VGET(mp, (ino_t)hpmp->hpm_su.su_rootfno, LK_EXCLUSIVE, vpp); 373 if(error) { 374 printf("hpfs_root: VFS_VGET failed: %d\n",error); 375 return (error); 376 } 377 378 return (error); 379} 380 381static int 382hpfs_statfs( 383 struct mount *mp, 384 struct statfs *sbp, 385 struct thread *td) 386{ 387 struct hpfsmount *hpmp = VFSTOHPFS(mp); 388 389 dprintf(("hpfs_statfs(): HPFS%d.%d\n", 390 hpmp->hpm_su.su_hpfsver, hpmp->hpm_su.su_fnctver)); 391 392 sbp->f_type = mp->mnt_vfc->vfc_typenum; 393 sbp->f_bsize = DEV_BSIZE; 394 sbp->f_iosize = DEV_BSIZE; 395 sbp->f_blocks = hpmp->hpm_su.su_btotal; 396 sbp->f_bfree = sbp->f_bavail = hpmp->hpm_bavail; 397 sbp->f_ffree = 0; 398 sbp->f_files = 0; 399 if (sbp != &mp->mnt_stat) { 400 bcopy((caddr_t)mp->mnt_stat.f_mntonname, 401 (caddr_t)&sbp->f_mntonname[0], MNAMELEN); 402 bcopy((caddr_t)mp->mnt_stat.f_mntfromname, 403 (caddr_t)&sbp->f_mntfromname[0], MNAMELEN); 404 } 405 sbp->f_flags = mp->mnt_flag; 406 407 return (0); 408} 409 410/*ARGSUSED*/ 411static int 412hpfs_fhtovp( 413 struct mount *mp, 414 struct fid *fhp, 415 struct vnode **vpp) 416{ 417 struct vnode *nvp; 418 struct hpfid *hpfhp = (struct hpfid *)fhp; 419 int error; 420 421 if ((error = VFS_VGET(mp, hpfhp->hpfid_ino, LK_EXCLUSIVE, &nvp)) != 0) { 422 *vpp = NULLVP; 423 return (error); 424 } 425 /* XXX as unlink/rmdir/mkdir/creat are not currently possible 426 * with HPFS, we don't need to check anything else for now */ 427 *vpp = nvp; 428 429 return (0); 430} 431 432static int 433hpfs_vptofh( 434 struct vnode *vp, 435 struct fid *fhp) 436{ 437 register struct hpfsnode *hpp; 438 register struct hpfid *hpfhp; 439 440 hpp = VTOHP(vp); 441 hpfhp = (struct hpfid *)fhp; 442 hpfhp->hpfid_len = sizeof(struct hpfid); 443 hpfhp->hpfid_ino = hpp->h_no; 444 /* hpfhp->hpfid_gen = hpp->h_gen; */ 445 return (0); 446} 447 448static int 449hpfs_vget( 450 struct mount *mp, 451 ino_t ino, 452 int flags, 453 struct vnode **vpp) 454{ 455 struct hpfsmount *hpmp = VFSTOHPFS(mp); 456 struct vnode *vp; 457 struct hpfsnode *hp; 458 struct buf *bp; 459 struct thread *td = curthread; /* XXX */ 460 int error; 461 462 dprintf(("hpfs_vget(0x%x): ",ino)); 463 464 *vpp = NULL; 465 hp = NULL; 466 vp = NULL; 467 468 if ((error = hpfs_hphashvget(hpmp->hpm_dev, ino, flags, vpp, td)) != 0) 469 return (error); 470 if (*vpp != NULL) { 471 dprintf(("hashed\n")); 472 return (0); 473 } 474 475 /* 476 * We have to lock node creation for a while, 477 * but then we have to call getnewvnode(), 478 * this may cause hpfs_reclaim() to be called, 479 * this may need to VOP_VGET() parent dir for 480 * update reasons, and if parent is not in 481 * hash, we have to lock node creation... 482 * To solve this, we MALLOC, getnewvnode and init while 483 * not locked (probability of node appearence 484 * at that time is little, and anyway - we'll 485 * check for it). 486 */ 487 MALLOC(hp, struct hpfsnode *, sizeof(struct hpfsnode), 488 M_HPFSNO, M_WAITOK); 489 490 error = getnewvnode("hpfs", hpmp->hpm_mp, hpfs_vnodeop_p, &vp); 491 if (error) { 492 printf("hpfs_vget: can't get new vnode\n"); 493 FREE(hp, M_HPFSNO); 494 return (error); 495 } 496 497 dprintf(("prenew ")); 498 499 vp->v_data = hp; 500 501 if (ino == (ino_t)hpmp->hpm_su.su_rootfno) 502 vp->v_vflag |= VV_ROOT; 503 504 505 mtx_init(&hp->h_interlock, "hpfsnode interlock", NULL, MTX_DEF); 506 507 hp->h_flag = H_INVAL; 508 hp->h_vp = vp; 509 hp->h_hpmp = hpmp; 510 hp->h_no = ino; 511 hp->h_dev = hpmp->hpm_dev; 512 hp->h_uid = hpmp->hpm_uid; 513 hp->h_gid = hpmp->hpm_uid; 514 hp->h_mode = hpmp->hpm_mode; 515 hp->h_devvp = hpmp->hpm_devvp; 516 VREF(hp->h_devvp); 517 518 error = vn_lock(vp, LK_EXCLUSIVE, td); 519 if (error) { 520 vput(vp); 521 return (error); 522 } 523 524 do { 525 if ((error = 526 hpfs_hphashvget(hpmp->hpm_dev, ino, flags, vpp, td))) { 527 vput(vp); 528 return (error); 529 } 530 if (*vpp != NULL) { 531 dprintf(("hashed2\n")); 532 vput(vp); 533 return (0); 534 } 535 } while(lockmgr(&hpfs_hphash_lock,LK_EXCLUSIVE|LK_SLEEPFAIL,NULL,NULL)); 536 537 hpfs_hphashins(hp); 538 539 lockmgr(&hpfs_hphash_lock, LK_RELEASE, NULL, NULL); 540 541 error = bread(hpmp->hpm_devvp, ino, FNODESIZE, NOCRED, &bp); 542 if (error) { 543 printf("hpfs_vget: can't read ino %d\n",ino); 544 vput(vp); 545 return (error); 546 } 547 bcopy(bp->b_data, &hp->h_fn, sizeof(struct fnode)); 548 brelse(bp); 549 550 if (hp->h_fn.fn_magic != FN_MAGIC) { 551 printf("hpfs_vget: MAGIC DOESN'T MATCH\n"); 552 vput(vp); 553 return (EINVAL); 554 } 555 556 vp->v_type = hp->h_fn.fn_flag ? VDIR:VREG; 557 hp->h_flag &= ~H_INVAL; 558 559 *vpp = vp; 560 561 return (0); 562} 563 564static struct vfsops hpfs_vfsops = { 565 .vfs_fhtovp = hpfs_fhtovp, 566 .vfs_init = hpfs_init, 567 .vfs_omount = hpfs_omount, 568 .vfs_root = hpfs_root, 569 .vfs_statfs = hpfs_statfs, 570 .vfs_uninit = hpfs_uninit, 571 .vfs_unmount = hpfs_unmount, 572 .vfs_vget = hpfs_vget, 573 .vfs_vptofh = hpfs_vptofh, 574}; 575VFS_SET(hpfs_vfsops, hpfs, 0); 576