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