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