hpfs_vfsops.c revision 233120
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: stable/9/sys/fs/hpfs/hpfs_vfsops.c 233120 2012-03-18 15:03:02Z kevlo $ 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; 71 72static int 73hpfs_cmount ( 74 struct mntarg *ma, 75 void *data, 76 uint64_t flags) 77{ 78 struct hpfs_args args; 79 struct export_args exp; 80 int error; 81 82 error = copyin(data, (caddr_t)&args, sizeof (struct hpfs_args)); 83 if (error) 84 return (error); 85 vfs_oexport_conv(&args.export, &exp); 86 87 ma = mount_argsu(ma, "from", args.fspec, MAXPATHLEN); 88 ma = mount_arg(ma, "export", &exp, sizeof(exp)); 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 (struct mount *mp) 108{ 109 int err = 0, error; 110 struct vnode *devvp; 111 struct thread *td; 112 struct nameidata ndp; 113 struct export_args export; 114 char *from; 115 116 td = curthread; 117 dprintf(("hpfs_omount():\n")); 118 /* 119 *** 120 * Mounting non-root filesystem or updating a filesystem 121 *** 122 */ 123 if (vfs_filteropt(mp->mnt_optnew, hpfs_opts)) 124 return (EINVAL); 125 126 from = vfs_getopts(mp->mnt_optnew, "from", &error); 127 if (error) 128 return (error); 129 130 /* 131 * If updating, check whether changing from read-only to 132 * read/write; if there is no device name, that's all we do. 133 */ 134 if (mp->mnt_flag & MNT_UPDATE) { 135 dprintf(("hpfs_omount: MNT_UPDATE: ")); 136 137 if (from == NULL) { 138 error = vfs_copyopt(mp->mnt_optnew, "export", 139 &export, sizeof export); 140 if (error) 141 return (error); 142 dprintf(("export 0x%x\n",args.export.ex_flags)); 143 err = vfs_export(mp, &export); 144 if (err) { 145 printf("hpfs_omount: vfs_export failed %d\n", 146 err); 147 } 148 goto success; 149 } else { 150 dprintf(("name [FAILED]\n")); 151 err = EINVAL; 152 goto success; 153 } 154 dprintf(("\n")); 155 } 156 157 /* 158 * Not an update, or updating the name: look up the name 159 * and verify that it refers to a sensible block device. 160 */ 161 NDINIT(&ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, from, td); 162 err = namei(&ndp); 163 if (err) { 164 /* can't get devvp!*/ 165 goto error_1; 166 } 167 168 devvp = ndp.ni_vp; 169 170 if (!vn_isdisk(devvp, &err)) { 171 vput(devvp); 172 return (err); 173 } 174 175 /* 176 ******************** 177 * NEW MOUNT 178 ******************** 179 */ 180 181 /* 182 * Since this is a new mount, we want the names for 183 * the device and the mount point copied in. If an 184 * error occurs, the mountpoint is discarded by the 185 * upper level code. Note that vfs_omount() handles 186 * copying the mountpoint f_mntonname for us, so we 187 * don't have to do it here unless we want to set it 188 * to something other than "path" for some rason. 189 */ 190 /* Save "mounted from" info for mount point (NULL pad)*/ 191 vfs_mountedfrom(mp, from); 192 193 err = hpfs_mountfs(devvp, mp, td); 194 if (err) { 195 vrele(devvp); 196 goto error_1; 197 } 198 199 goto success; 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, td) 213 register struct vnode *devvp; 214 struct mount *mp; 215 struct thread *td; 216{ 217 int error, ronly, v; 218 struct sublock *sup; 219 struct spblock *spp; 220 struct hpfsmount *hpmp; 221 struct buf *bp = NULL; 222 struct vnode *vp; 223 struct cdev *dev = devvp->v_rdev; 224 struct g_consumer *cp; 225 struct bufobj *bo; 226 227 if (mp->mnt_flag & MNT_ROOTFS) 228 return (EOPNOTSUPP); 229 dprintf(("hpfs_mountfs():\n")); 230 ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 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); 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 = hpmp; 283 hpmp->hpm_devvp = devvp; 284 hpmp->hpm_dev = devvp->v_rdev; 285 hpmp->hpm_mp = mp; 286 if (vfs_scanopt(mp->mnt_optnew, "uid", "%d", &v) == 1) 287 hpmp->hpm_uid = v; 288 if (vfs_scanopt(mp->mnt_optnew, "gid", "%d", &v) == 1) 289 hpmp->hpm_gid = v; 290 if (vfs_scanopt(mp->mnt_optnew, "mode", "%d", &v) == 1) 291 hpmp->hpm_mode = v; 292 293 error = hpfs_bminit(hpmp); 294 if (error) 295 goto failed; 296 297 error = hpfs_cpinit(mp, hpmp); 298 if (error) { 299 hpfs_bmdeinit(hpmp); 300 goto failed; 301 } 302 303 error = hpfs_root(mp, LK_EXCLUSIVE, &vp); 304 if (error) { 305 hpfs_cpdeinit(hpmp); 306 hpfs_bmdeinit(hpmp); 307 goto failed; 308 } 309 310 vput(vp); 311 312 mp->mnt_stat.f_fsid.val[0] = (long)dev2udev(dev); 313 mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 314 mp->mnt_maxsymlinklen = 0; 315 MNT_ILOCK(mp); 316 mp->mnt_flag |= MNT_LOCAL; 317 MNT_IUNLOCK(mp); 318 return (0); 319 320failed: 321 if (bp) 322 brelse (bp); 323 mp->mnt_data = NULL; 324 DROP_GIANT(); 325 g_topology_lock(); 326 g_vfs_close(cp); 327 g_topology_unlock(); 328 PICKUP_GIANT(); 329 return (error); 330} 331 332static int 333hpfs_unmount( 334 struct mount *mp, 335 int mntflags) 336{ 337 int error, flags; 338 register struct hpfsmount *hpmp = VFSTOHPFS(mp); 339 340 dprintf(("hpfs_unmount():\n")); 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, curthread); 349 if (error) { 350 printf("hpfs_unmount: vflush failed: %d\n",error); 351 return (error); 352 } 353 354 vinvalbuf(hpmp->hpm_devvp, V_SAVE, 0, 0); 355 DROP_GIANT(); 356 g_topology_lock(); 357 g_vfs_close(hpmp->hpm_cp); 358 g_topology_unlock(); 359 PICKUP_GIANT(); 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 = NULL; 366 MNT_ILOCK(mp); 367 mp->mnt_flag &= ~MNT_LOCAL; 368 MNT_IUNLOCK(mp); 369 free(hpmp, M_HPFSMNT); 370 371 return (0); 372} 373 374static int 375hpfs_root( 376 struct mount *mp, 377 int flags, 378 struct vnode **vpp) 379{ 380 int error = 0; 381 struct hpfsmount *hpmp = VFSTOHPFS(mp); 382 383 dprintf(("hpfs_root():\n")); 384 error = VFS_VGET(mp, (ino_t)hpmp->hpm_su.su_rootfno, LK_EXCLUSIVE, vpp); 385 if(error) { 386 printf("hpfs_root: VFS_VGET failed: %d\n",error); 387 return (error); 388 } 389 390 return (error); 391} 392 393static int 394hpfs_statfs( 395 struct mount *mp, 396 struct statfs *sbp) 397{ 398 struct hpfsmount *hpmp = VFSTOHPFS(mp); 399 400 dprintf(("hpfs_statfs(): HPFS%d.%d\n", 401 hpmp->hpm_su.su_hpfsver, hpmp->hpm_su.su_fnctver)); 402 403 sbp->f_type = mp->mnt_vfc->vfc_typenum; 404 sbp->f_bsize = DEV_BSIZE; 405 sbp->f_iosize = DEV_BSIZE; 406 sbp->f_blocks = hpmp->hpm_su.su_btotal; 407 sbp->f_bfree = sbp->f_bavail = hpmp->hpm_bavail; 408 sbp->f_ffree = 0; 409 sbp->f_files = 0; 410 sbp->f_flags = mp->mnt_flag; 411 412 return (0); 413} 414 415/*ARGSUSED*/ 416static int 417hpfs_fhtovp( 418 struct mount *mp, 419 struct fid *fhp, 420 int flags, 421 struct vnode **vpp) 422{ 423 struct vnode *nvp; 424 struct hpfid *hpfhp = (struct hpfid *)fhp; 425 int error; 426 427 if ((error = VFS_VGET(mp, hpfhp->hpfid_ino, LK_EXCLUSIVE, &nvp)) != 0) { 428 *vpp = NULLVP; 429 return (error); 430 } 431 /* XXX as unlink/rmdir/mkdir/creat are not currently possible 432 * with HPFS, we don't need to check anything else for now */ 433 *vpp = nvp; 434 435 return (0); 436} 437 438static int 439hpfs_vget( 440 struct mount *mp, 441 ino_t ino, 442 int flags, 443 struct vnode **vpp) 444{ 445 struct hpfsmount *hpmp = VFSTOHPFS(mp); 446 struct vnode *vp; 447 struct hpfsnode *hp; 448 struct buf *bp; 449 int error; 450 451 dprintf(("hpfs_vget(0x%x): ",ino)); 452 453 error = vfs_hash_get(mp, ino, flags, curthread, vpp, NULL, NULL); 454 if (error || *vpp != NULL) 455 return (error); 456 457 *vpp = NULL; 458 hp = NULL; 459 vp = NULL; 460 461 /* 462 * We have to lock node creation for a while, 463 * but then we have to call getnewvnode(), 464 * this may cause hpfs_reclaim() to be called, 465 * this may need to VOP_VGET() parent dir for 466 * update reasons, and if parent is not in 467 * hash, we have to lock node creation... 468 * To solve this, we MALLOC, getnewvnode and init while 469 * not locked (probability of node appearence 470 * at that time is little, and anyway - we'll 471 * check for it). 472 */ 473 hp = malloc(sizeof(struct hpfsnode), 474 M_HPFSNO, M_WAITOK); 475 476 error = getnewvnode("hpfs", mp, &hpfs_vnodeops, &vp); 477 if (error) { 478 printf("hpfs_vget: can't get new vnode\n"); 479 free(hp, M_HPFSNO); 480 return (error); 481 } 482 483 dprintf(("prenew ")); 484 485 vp->v_data = hp; 486 487 if (ino == (ino_t)hpmp->hpm_su.su_rootfno) 488 vp->v_vflag |= VV_ROOT; 489 490 491 mtx_init(&hp->h_interlock, "hpfsnode interlock", NULL, MTX_DEF); 492 493 hp->h_flag = H_INVAL; 494 hp->h_vp = vp; 495 hp->h_hpmp = hpmp; 496 hp->h_no = ino; 497 hp->h_dev = hpmp->hpm_dev; 498 hp->h_uid = hpmp->hpm_uid; 499 hp->h_gid = hpmp->hpm_uid; 500 hp->h_mode = hpmp->hpm_mode; 501 hp->h_devvp = hpmp->hpm_devvp; 502 503 lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL); 504 error = insmntque(vp, mp); 505 if (error != 0) { 506 free(hp, M_HPFSNO); 507 return (error); 508 } 509 error = vfs_hash_insert(vp, ino, flags, curthread, vpp, NULL, NULL); 510 if (error || *vpp != NULL) 511 return (error); 512 513 error = bread(hpmp->hpm_devvp, ino, FNODESIZE, NOCRED, &bp); 514 if (error) { 515 printf("hpfs_vget: can't read ino %d\n",ino); 516 vput(vp); 517 return (error); 518 } 519 bcopy(bp->b_data, &hp->h_fn, sizeof(struct fnode)); 520 brelse(bp); 521 522 if (hp->h_fn.fn_magic != FN_MAGIC) { 523 printf("hpfs_vget: MAGIC DOESN'T MATCH\n"); 524 vput(vp); 525 return (EINVAL); 526 } 527 528 vp->v_type = hp->h_fn.fn_flag ? VDIR:VREG; 529 hp->h_flag &= ~H_INVAL; 530 531 *vpp = vp; 532 533 return (0); 534} 535 536static struct vfsops hpfs_vfsops = { 537 .vfs_fhtovp = hpfs_fhtovp, 538 .vfs_cmount = hpfs_cmount, 539 .vfs_mount = hpfs_mount, 540 .vfs_root = hpfs_root, 541 .vfs_statfs = hpfs_statfs, 542 .vfs_unmount = hpfs_unmount, 543 .vfs_vget = hpfs_vget, 544}; 545VFS_SET(hpfs_vfsops, hpfs, 0); 546