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