hpfs_vfsops.c revision 111119
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 111119 2003-02-19 05:47:46Z imp $ 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_root(struct mount *, struct vnode **); 59static int hpfs_statfs(struct mount *, struct statfs *, struct thread *); 60static int hpfs_unmount(struct mount *, int, struct thread *); 61static int hpfs_vget(struct mount *mp, ino_t ino, int flags, 62 struct vnode **vpp); 63static int hpfs_mountfs(register struct vnode *, struct mount *, 64 struct hpfs_args *, struct thread *); 65static int hpfs_vptofh(struct vnode *, struct fid *); 66static int hpfs_fhtovp(struct mount *, struct fid *, struct vnode **); 67static int hpfs_mount(struct mount *, char *, caddr_t, 68 struct nameidata *, struct thread *); 69static int hpfs_init(struct vfsconf *); 70static int hpfs_uninit(struct vfsconf *); 71 72static int 73hpfs_init ( 74 struct vfsconf *vcp ) 75{ 76 dprintf(("hpfs_init():\n")); 77 78 hpfs_hphashinit(); 79 return 0; 80} 81 82static int 83hpfs_uninit (vfsp) 84 struct vfsconf *vfsp; 85{ 86 hpfs_hphashdestroy(); 87 return 0;; 88} 89 90static int 91hpfs_mount ( 92 struct mount *mp, 93 char *path, 94 caddr_t data, 95 struct nameidata *ndp, 96 struct thread *td ) 97{ 98 size_t size; 99 int err = 0; 100 struct vnode *devvp; 101 struct hpfs_args args; 102 struct hpfsmount *hpmp = 0; 103 104 dprintf(("hpfs_mount():\n")); 105 /* 106 *** 107 * Mounting non-root filesystem or updating a filesystem 108 *** 109 */ 110 111 /* copy in user arguments*/ 112 err = copyin(data, (caddr_t)&args, sizeof (struct hpfs_args)); 113 if (err) 114 goto error_1; /* can't get arguments*/ 115 116 /* 117 * If updating, check whether changing from read-only to 118 * read/write; if there is no device name, that's all we do. 119 */ 120 if (mp->mnt_flag & MNT_UPDATE) { 121 dprintf(("hpfs_mount: MNT_UPDATE: ")); 122 123 hpmp = VFSTOHPFS(mp); 124 125 if (args.fspec == 0) { 126 dprintf(("export 0x%x\n",args.export.ex_flags)); 127 err = vfs_export(mp, &args.export); 128 if (err) { 129 printf("hpfs_mount: vfs_export failed %d\n", 130 err); 131 } 132 goto success; 133 } else { 134 dprintf(("name [FAILED]\n")); 135 err = EINVAL; 136 goto success; 137 } 138 dprintf(("\n")); 139 } 140 141 /* 142 * Not an update, or updating the name: look up the name 143 * and verify that it refers to a sensible block device. 144 */ 145 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, td); 146 err = namei(ndp); 147 if (err) { 148 /* can't get devvp!*/ 149 goto error_1; 150 } 151 152 devvp = ndp->ni_vp; 153 154 if (!vn_isdisk(devvp, &err)) 155 goto error_2; 156 157 /* 158 ******************** 159 * NEW MOUNT 160 ******************** 161 */ 162 163 /* 164 * Since this is a new mount, we want the names for 165 * the device and the mount point copied in. If an 166 * error occurs, the mountpoint is discarded by the 167 * upper level code. Note that vfs_mount() handles 168 * copying the mountpoint f_mntonname for us, so we 169 * don't have to do it here unless we want to set it 170 * to something other than "path" for some rason. 171 */ 172 /* Save "mounted from" info for mount point (NULL pad)*/ 173 copyinstr( args.fspec, /* device name*/ 174 mp->mnt_stat.f_mntfromname, /* save area*/ 175 MNAMELEN - 1, /* max size*/ 176 &size); /* real size*/ 177 bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 178 179 err = hpfs_mountfs(devvp, mp, &args, td); 180 if (err) 181 goto error_2; 182 183 /* 184 * Initialize FS stat information in mount struct; uses both 185 * mp->mnt_stat.f_mntonname and mp->mnt_stat.f_mntfromname 186 * 187 * This code is common to root and non-root mounts 188 */ 189 (void)VFS_STATFS(mp, &mp->mnt_stat, td); 190 191 goto success; 192 193 194error_2: /* error with devvp held*/ 195 196 /* release devvp before failing*/ 197 vrele(devvp); 198 199error_1: /* no state to back out*/ 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 dev_t 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 && devvp != rootvp) 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); 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); 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); 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{ 377 int error = 0; 378 struct hpfsmount *hpmp = VFSTOHPFS(mp); 379 380 dprintf(("hpfs_root():\n")); 381 error = VFS_VGET(mp, (ino_t)hpmp->hpm_su.su_rootfno, LK_EXCLUSIVE, vpp); 382 if(error) { 383 printf("hpfs_root: VFS_VGET failed: %d\n",error); 384 return (error); 385 } 386 387 return (error); 388} 389 390static int 391hpfs_statfs( 392 struct mount *mp, 393 struct statfs *sbp, 394 struct thread *td) 395{ 396 struct hpfsmount *hpmp = VFSTOHPFS(mp); 397 398 dprintf(("hpfs_statfs(): HPFS%d.%d\n", 399 hpmp->hpm_su.su_hpfsver, hpmp->hpm_su.su_fnctver)); 400 401 sbp->f_type = mp->mnt_vfc->vfc_typenum; 402 sbp->f_bsize = DEV_BSIZE; 403 sbp->f_iosize = DEV_BSIZE; 404 sbp->f_blocks = hpmp->hpm_su.su_btotal; 405 sbp->f_bfree = sbp->f_bavail = hpmp->hpm_bavail; 406 sbp->f_ffree = 0; 407 sbp->f_files = 0; 408 if (sbp != &mp->mnt_stat) { 409 bcopy((caddr_t)mp->mnt_stat.f_mntonname, 410 (caddr_t)&sbp->f_mntonname[0], MNAMELEN); 411 bcopy((caddr_t)mp->mnt_stat.f_mntfromname, 412 (caddr_t)&sbp->f_mntfromname[0], MNAMELEN); 413 } 414 sbp->f_flags = mp->mnt_flag; 415 416 return (0); 417} 418 419/*ARGSUSED*/ 420static int 421hpfs_fhtovp( 422 struct mount *mp, 423 struct fid *fhp, 424 struct vnode **vpp) 425{ 426 struct vnode *nvp; 427 struct hpfid *hpfhp = (struct hpfid *)fhp; 428 int error; 429 430 if ((error = VFS_VGET(mp, hpfhp->hpfid_ino, LK_EXCLUSIVE, &nvp)) != 0) { 431 *vpp = NULLVP; 432 return (error); 433 } 434 /* XXX as unlink/rmdir/mkdir/creat are not currently possible 435 * with HPFS, we don't need to check anything else for now */ 436 *vpp = nvp; 437 438 return (0); 439} 440 441static int 442hpfs_vptofh( 443 struct vnode *vp, 444 struct fid *fhp) 445{ 446 register struct hpfsnode *hpp; 447 register struct hpfid *hpfhp; 448 449 hpp = VTOHP(vp); 450 hpfhp = (struct hpfid *)fhp; 451 hpfhp->hpfid_len = sizeof(struct hpfid); 452 hpfhp->hpfid_ino = hpp->h_no; 453 /* hpfhp->hpfid_gen = hpp->h_gen; */ 454 return (0); 455} 456 457static int 458hpfs_vget( 459 struct mount *mp, 460 ino_t ino, 461 int flags, 462 struct vnode **vpp) 463{ 464 struct hpfsmount *hpmp = VFSTOHPFS(mp); 465 struct vnode *vp; 466 struct hpfsnode *hp; 467 struct buf *bp; 468 struct thread *td = curthread; /* XXX */ 469 int error; 470 471 dprintf(("hpfs_vget(0x%x): ",ino)); 472 473 *vpp = NULL; 474 hp = NULL; 475 vp = NULL; 476 477 if ((error = hpfs_hphashvget(hpmp->hpm_dev, ino, flags, vpp, td)) != 0) 478 return (error); 479 if (*vpp != NULL) { 480 dprintf(("hashed\n")); 481 return (0); 482 } 483 484 /* 485 * We have to lock node creation for a while, 486 * but then we have to call getnewvnode(), 487 * this may cause hpfs_reclaim() to be called, 488 * this may need to VOP_VGET() parent dir for 489 * update reasons, and if parent is not in 490 * hash, we have to lock node creation... 491 * To solve this, we MALLOC, getnewvnode and init while 492 * not locked (probability of node appearence 493 * at that time is little, and anyway - we'll 494 * check for it). 495 */ 496 MALLOC(hp, struct hpfsnode *, sizeof(struct hpfsnode), 497 M_HPFSNO, M_WAITOK); 498 499 error = getnewvnode("hpfs", hpmp->hpm_mp, hpfs_vnodeop_p, &vp); 500 if (error) { 501 printf("hpfs_vget: can't get new vnode\n"); 502 FREE(hp, M_HPFSNO); 503 return (error); 504 } 505 506 dprintf(("prenew ")); 507 508 vp->v_data = hp; 509 510 if (ino == (ino_t)hpmp->hpm_su.su_rootfno) 511 vp->v_vflag |= VV_ROOT; 512 513 514 mtx_init(&hp->h_interlock, "hpfsnode interlock", NULL, MTX_DEF); 515 516 hp->h_flag = H_INVAL; 517 hp->h_vp = vp; 518 hp->h_hpmp = hpmp; 519 hp->h_no = ino; 520 hp->h_dev = hpmp->hpm_dev; 521 hp->h_uid = hpmp->hpm_uid; 522 hp->h_gid = hpmp->hpm_uid; 523 hp->h_mode = hpmp->hpm_mode; 524 hp->h_devvp = hpmp->hpm_devvp; 525 VREF(hp->h_devvp); 526 527 error = vn_lock(vp, LK_EXCLUSIVE, td); 528 if (error) { 529 vput(vp); 530 return (error); 531 } 532 533 do { 534 if ((error = 535 hpfs_hphashvget(hpmp->hpm_dev, ino, flags, vpp, td))) { 536 vput(vp); 537 return (error); 538 } 539 if (*vpp != NULL) { 540 dprintf(("hashed2\n")); 541 vput(vp); 542 return (0); 543 } 544 } while(lockmgr(&hpfs_hphash_lock,LK_EXCLUSIVE|LK_SLEEPFAIL,NULL,NULL)); 545 546 hpfs_hphashins(hp); 547 548 lockmgr(&hpfs_hphash_lock, LK_RELEASE, NULL, NULL); 549 550 error = bread(hpmp->hpm_devvp, ino, FNODESIZE, NOCRED, &bp); 551 if (error) { 552 printf("hpfs_vget: can't read ino %d\n",ino); 553 vput(vp); 554 return (error); 555 } 556 bcopy(bp->b_data, &hp->h_fn, sizeof(struct fnode)); 557 brelse(bp); 558 559 if (hp->h_fn.fn_magic != FN_MAGIC) { 560 printf("hpfs_vget: MAGIC DOESN'T MATCH\n"); 561 vput(vp); 562 return (EINVAL); 563 } 564 565 vp->v_type = hp->h_fn.fn_flag ? VDIR:VREG; 566 hp->h_flag &= ~H_INVAL; 567 568 *vpp = vp; 569 570 return (0); 571} 572 573static struct vfsops hpfs_vfsops = { 574 hpfs_mount, 575 vfs_stdstart, 576 hpfs_unmount, 577 hpfs_root, 578 vfs_stdquotactl, 579 hpfs_statfs, 580 vfs_stdsync, 581 hpfs_vget, 582 hpfs_fhtovp, 583 vfs_stdcheckexp, 584 hpfs_vptofh, 585 hpfs_init, 586 hpfs_uninit, 587 vfs_stdextattrctl, 588}; 589VFS_SET(hpfs_vfsops, hpfs, 0); 590