1 /* $Id: msdosfs_vfsops.c,v 1.5 1994/10/02 17:48:21 phk Exp $ */ 2 /* $NetBSD: msdosfs_vfsops.c,v 1.19 1994/08/21 18:44:10 ws Exp $ */ 3 4 /*- 5 * Copyright (C) 1994 Wolfgang Solfrank. 6 * Copyright (C) 1994 TooLs GmbH. 7 * All rights reserved. 8 * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by TooLs GmbH. 21 * 4. The name of TooLs GmbH may not be used to endorse or promote products 22 * derived from this software without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 29 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 30 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 31 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 33 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 */ 35 /* 36 * Written by Paul Popelka (paulp@uts.amdahl.com) 37 * 38 * You can do anything you want with this software, just don't say you wrote 39 * it, and don't remove this notice. 40 * 41 * This software is provided "as is". 42 * 43 * The author supplies this software to be publicly redistributed on the 44 * understanding that the author is not responsible for the correct 45 * functioning of this software in any circumstances and is not liable for 46 * any damages caused by this software. 47 * 48 * October 1992 49 */ 50 51 #include <sys/param.h> 52 #include <sys/systm.h> 53 #include <sys/namei.h> 54 #include <sys/proc.h> 55 #include <sys/kernel.h> 56 #include <sys/vnode.h> 57 #include <miscfs/specfs/specdev.h> /* XXX */ /* defines v_rdev */ 58 #include <sys/mount.h> 59 #include <sys/buf.h> 60 #include <sys/file.h> 61 #include <sys/malloc.h> 62 63 #include <msdosfs/bpb.h> 64 #include <msdosfs/bootsect.h> 65 #include <msdosfs/direntry.h> 66 #include <msdosfs/denode.h> 67 #include <msdosfs/msdosfsmount.h> 68 #include <msdosfs/fat.h> 69 70 int msdosfsdoforce = 1; /* 1 = force unmount */ 71 72 /* 73 * mp - path - addr in user space of mount point (ie /usr or whatever) 74 * data - addr in user space of mount params including the name of the block 75 * special file to treat as a filesystem. 76 */ 77 int 78 msdosfs_mount(mp, path, data, ndp, p) 79 struct mount *mp; 80 char *path; 81 caddr_t data; 82 struct nameidata *ndp; 83 struct proc *p; 84 { 85 struct vnode *devvp; /* vnode for blk device to mount */ 86 struct msdosfs_args args; /* will hold data from mount request */ 87 struct msdosfsmount *pmp; /* msdosfs specific mount control block */ 88 int error, flags; 89 u_int size; 90 struct ucred *cred, *scred; 91 struct vattr va; 92 93 /* 94 * Copy in the args for the mount request. 95 */ 96 error = copyin(data, (caddr_t) & args, sizeof(struct msdosfs_args)); 97 if (error) 98 return error; 99 100 /* 101 * If they just want to update then be sure we can do what is 102 * asked. Can't change a filesystem from read/write to read only. 103 * Why? And if they've supplied a new device file name then we 104 * continue, otherwise return. 105 */ 106 if (mp->mnt_flag & MNT_UPDATE) { 107 pmp = (struct msdosfsmount *) mp->mnt_data; 108 error = 0; 109 if (pmp->pm_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { 110 flags = WRITECLOSE; 111 if (mp->mnt_flag & MNT_FORCE) 112 flags |= FORCECLOSE; 113 if (vfs_busy(mp)) 114 return EBUSY; 115 error = vflush(mp, NULLVP, flags); 116 vfs_unbusy(mp); 117 } 118 if (!error && (mp->mnt_flag & MNT_RELOAD)) 119 /* not yet implemented */ 120 error = EINVAL; 121 if (error) 122 return error; 123 if (pmp->pm_ronly && (mp->mnt_flag & MNT_RDONLY) == 0) 124 pmp->pm_ronly = 0; 125 if (args.fspec == 0) { 126 /* 127 * Process export requests. 128 */ 129 return vfs_export(mp, &pmp->pm_export, &args.export); 130 } 131 } else 132 pmp = NULL; 133 134 /* 135 * check to see that the user in owns the target directory. 136 * Note the very XXX trick to make sure we're checking as the 137 * real user -- were mount() executable by anyone, this wouldn't 138 * be a problem. 139 * 140 * XXX there should be one consistent error out. 141 */ 142 cred = crdup(p->p_ucred); /* XXX */ 143 cred->cr_uid = p->p_cred->p_ruid; /* XXX */ 144 error = VOP_GETATTR(mp->mnt_vnodecovered, &va, cred, p); 145 if (error) { 146 crfree(cred); /* XXX */ 147 return error; 148 } 149 if (cred->cr_uid != 0) { 150 if (va.va_uid != cred->cr_uid) { 151 error = EACCES; 152 crfree(cred); /* XXX */ 153 return error; 154 } 155 156 /* a user mounted it; we'll verify permissions when unmounting */ 157 mp->mnt_flag |= MNT_USER; 158 } 159 160 /* 161 * Now, lookup the name of the block device this mount or name 162 * update request is to apply to. 163 */ 164 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p); 165 scred = p->p_ucred; /* XXX */ 166 p->p_ucred = cred; /* XXX */ 167 error = namei(ndp); 168 p->p_ucred = scred; /* XXX */ 169 crfree(cred); /* XXX */ 170 if (error != 0) 171 return error; 172 173 /* 174 * Be sure they've given us a block device to treat as a 175 * filesystem. And, that its major number is within the bdevsw 176 * table. 177 */ 178 devvp = ndp->ni_vp; 179 if (devvp->v_type != VBLK) { 180 vrele(devvp); 181 return ENOTBLK; 182 } 183 if (major(devvp->v_rdev) >= nblkdev) { 184 vrele(devvp); 185 return ENXIO; 186 } 187 188 /* 189 * If this is an update, then make sure the vnode for the block 190 * special device is the same as the one our filesystem is in. 191 */ 192 if (mp->mnt_flag & MNT_UPDATE) { 193 if (devvp != pmp->pm_devvp) 194 error = EINVAL; 195 else 196 vrele(devvp); 197 } else { 198 199 /* 200 * Well, it's not an update, it's a real mount request. 201 * Time to get dirty. 202 */ 203 error = mountmsdosfs(devvp, mp, p); 204 } 205 if (error) { 206 vrele(devvp); 207 return error; 208 } 209 210 /* 211 * Copy in the name of the directory the filesystem is to be 212 * mounted on. Then copy in the name of the block special file 213 * representing the filesystem being mounted. And we clear the 214 * remainder of the character strings to be tidy. Set up the 215 * user id/group id/mask as specified by the user. Then, we try to 216 * fill in the filesystem stats structure as best we can with 217 * whatever applies from a dos file system. 218 */ 219 pmp = (struct msdosfsmount *) mp->mnt_data; 220 copyinstr(path, (caddr_t) mp->mnt_stat.f_mntonname, 221 sizeof(mp->mnt_stat.f_mntonname) - 1, &size); 222 bzero(mp->mnt_stat.f_mntonname + size, 223 sizeof(mp->mnt_stat.f_mntonname) - size); 224 copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size); 225 bzero(mp->mnt_stat.f_mntfromname + size, 226 MNAMELEN - size); 227 pmp->pm_mounter = p->p_cred->p_ruid; 228 pmp->pm_gid = args.gid; 229 pmp->pm_uid = args.uid; 230 pmp->pm_mask = args.mask; 231 (void) msdosfs_statfs(mp, &mp->mnt_stat, p); 232 #ifdef MSDOSFS_DEBUG 233 printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap); 234 #endif 235 return 0; 236 } 237 238 int 239 mountmsdosfs(devvp, mp, p) 240 struct vnode *devvp; 241 struct mount *mp; 242 struct proc *p; 243 { 244 int i; 245 int bpc; 246 int bit; 247 int error; 248 int needclose; 249 int ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 250 dev_t dev = devvp->v_rdev; 251 union bootsector *bsp; 252 struct msdosfsmount *pmp = NULL; 253 struct buf *bp0 = NULL; 254 struct byte_bpb33 *b33; 255 struct byte_bpb50 *b50; 256 257 /* 258 * Multiple mounts of the same block special file aren't allowed. 259 * Make sure no one else has the special file open. And flush any 260 * old buffers from this filesystem. Presumably this prevents us 261 * from running into buffers that are the wrong blocksize. 262 */ 263 error = vfs_mountedon(devvp); 264 if (error) 265 return error; 266 if (vcount(devvp) > 1) 267 return EBUSY; 268 error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0); 269 if (error) 270 return error; 271 272 /* 273 * Now open the block special file. 274 */ 275 error = VOP_OPEN(devvp, ronly ? FREAD : FREAD | FWRITE, FSCRED, p); 276 if (error) 277 return error; 278 needclose = 1; 279 #ifdef HDSUPPORT 280 /* 281 * Put this in when we support reading dos filesystems from 282 * partitioned harddisks. 283 */ 284 if (VOP_IOCTL(devvp, DIOCGPART, &msdosfspart, FREAD, NOCRED, p) == 0) { 285 } 286 #endif 287 288 /* 289 * Read the boot sector of the filesystem, and then check the boot 290 * signature. If not a dos boot sector then error out. We could 291 * also add some checking on the bsOemName field. So far I've seen 292 * the following values: "IBM 3.3" "MSDOS3.3" "MSDOS5.0" 293 */ 294 error = bread(devvp, 0, 512, NOCRED, &bp0); 295 if (error) 296 goto error_exit; 297 bp0->b_flags |= B_AGE; 298 bsp = (union bootsector *) bp0->b_data; 299 b33 = (struct byte_bpb33 *) bsp->bs33.bsBPB; 300 b50 = (struct byte_bpb50 *) bsp->bs50.bsBPB; 301 #ifdef MSDOSFS_CHECKSIG 302 if (bsp->bs50.bsBootSectSig != BOOTSIG) { 303 error = EINVAL; 304 goto error_exit; 305 } 306 #endif 307 if ( bsp->bs50.bsJump[0] != 0xe9 && 308 (bsp->bs50.bsJump[0] != 0xeb || bsp->bs50.bsJump[2] != 0x90)) { 309 error = EINVAL; 310 goto error_exit; 311 } 312 313 pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK); 314 bzero((caddr_t)pmp, sizeof *pmp); 315 pmp->pm_mountp = mp; 316 317 /* 318 * Compute several useful quantities from the bpb in the 319 * bootsector. Copy in the dos 5 variant of the bpb then fix up 320 * the fields that are different between dos 5 and dos 3.3. 321 */ 322 pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec); 323 pmp->pm_SectPerClust = b50->bpbSecPerClust; 324 pmp->pm_ResSectors = getushort(b50->bpbResSectors); 325 pmp->pm_FATs = b50->bpbFATs; 326 pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts); 327 pmp->pm_Sectors = getushort(b50->bpbSectors); 328 pmp->pm_Media = b50->bpbMedia; 329 pmp->pm_FATsecs = getushort(b50->bpbFATsecs); 330 pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack); 331 pmp->pm_Heads = getushort(b50->bpbHeads); 332 333 /* XXX - We should probably check more values here */ 334 if (!pmp->pm_BytesPerSec || !pmp->pm_SectPerClust || 335 !pmp->pm_Heads || pmp->pm_Heads > 255 || 336 !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 63) { 337 error = EINVAL; 338 goto error_exit; 339 } 340 341 if (pmp->pm_Sectors == 0) { 342 pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs); 343 pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors); 344 } else { 345 pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs); 346 pmp->pm_HugeSectors = pmp->pm_Sectors; 347 } 348 pmp->pm_fatblk = pmp->pm_ResSectors; 349 pmp->pm_rootdirblk = pmp->pm_fatblk + 350 (pmp->pm_FATs * pmp->pm_FATsecs); 351 pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry)) 352 / 353 pmp->pm_BytesPerSec;/* in sectors */ 354 pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize; 355 pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) / 356 pmp->pm_SectPerClust; 357 pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1; 358 pmp->pm_fatsize = pmp->pm_FATsecs * pmp->pm_BytesPerSec; 359 if (FAT12(pmp)) 360 /* 361 * This will usually be a floppy disk. This size makes sure 362 * that one fat entry will not be split across multiple 363 * blocks. 364 */ 365 pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec; 366 else 367 /* 368 * This will usually be a hard disk. Reading or writing one 369 * block should be quite fast. 370 */ 371 pmp->pm_fatblocksize = MAXBSIZE; 372 pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec; 373 374 375 if ((pmp->pm_rootdirsize % pmp->pm_SectPerClust) != 0) 376 printf("mountmsdosfs(): root directory is not a multiple of the clustersize in length\n"); 377 378 /* 379 * Compute mask and shift value for isolating cluster relative byte 380 * offsets and cluster numbers from a file offset. 381 */ 382 bpc = pmp->pm_SectPerClust * pmp->pm_BytesPerSec; 383 pmp->pm_bpcluster = bpc; 384 pmp->pm_depclust = bpc / sizeof(struct direntry); 385 pmp->pm_crbomask = bpc - 1; 386 if (bpc == 0) { 387 error = EINVAL; 388 goto error_exit; 389 } 390 bit = 1; 391 for (i = 0; i < 32; i++) { 392 if (bit & bpc) { 393 if (bit ^ bpc) { 394 error = EINVAL; 395 goto error_exit; 396 } 397 pmp->pm_cnshift = i; 398 break; 399 } 400 bit <<= 1; 401 } 402 403 pmp->pm_brbomask = 0x01ff; /* 512 byte blocks only (so far) */ 404 pmp->pm_bnshift = 9; /* shift right 9 bits to get bn */ 405 406 /* 407 * Release the bootsector buffer. 408 */ 409 brelse(bp0); 410 bp0 = NULL; 411 412 /* 413 * Allocate memory for the bitmap of allocated clusters, and then 414 * fill it in. 415 */ 416 pmp->pm_inusemap = malloc(((pmp->pm_maxcluster + N_INUSEBITS - 1) 417 / N_INUSEBITS) 418 * sizeof(*pmp->pm_inusemap), 419 M_MSDOSFSFAT, M_WAITOK); 420 421 /* 422 * fillinusemap() needs pm_devvp. 423 */ 424 pmp->pm_dev = dev; 425 pmp->pm_devvp = devvp; 426 427 /* 428 * Have the inuse map filled in. 429 */ 430 error = fillinusemap(pmp); 431 if (error) 432 goto error_exit; 433 434 /* 435 * If they want fat updates to be synchronous then let them suffer 436 * the performance degradation in exchange for the on disk copy of 437 * the fat being correct just about all the time. I suppose this 438 * would be a good thing to turn on if the kernel is still flakey. 439 */ 440 pmp->pm_waitonfat = mp->mnt_flag & MNT_SYNCHRONOUS; 441 442 /* 443 * Finish up. 444 */ 445 pmp->pm_ronly = ronly; 446 if (ronly == 0) 447 pmp->pm_fmod = 1; 448 mp->mnt_data = (qaddr_t) pmp; 449 mp->mnt_stat.f_fsid.val[0] = (long)dev; 450 mp->mnt_stat.f_fsid.val[1] = MOUNT_MSDOS; 451 mp->mnt_flag |= MNT_LOCAL; 452 #ifdef QUOTA 453 /* 454 * If we ever do quotas for DOS filesystems this would be a place 455 * to fill in the info in the msdosfsmount structure. You dolt, 456 * quotas on dos filesystems make no sense because files have no 457 * owners on dos filesystems. of course there is some empty space 458 * in the directory entry where we could put uid's and gid's. 459 */ 460 #endif 461 devvp->v_specflags |= SI_MOUNTEDON; 462 463 return 0; 464 465 error_exit:; 466 if (bp0) 467 brelse(bp0); 468 if (needclose) 469 (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD | FWRITE, 470 NOCRED, p); 471 if (pmp) { 472 if (pmp->pm_inusemap) 473 free((caddr_t) pmp->pm_inusemap, M_MSDOSFSFAT); 474 free((caddr_t) pmp, M_MSDOSFSMNT); 475 mp->mnt_data = (qaddr_t) 0; 476 } 477 return error; 478 } 479 480 int 481 msdosfs_start(mp, flags, p) 482 struct mount *mp; 483 int flags; 484 struct proc *p; 485 { 486 return 0; 487 } 488 489 /* 490 * Unmount the filesystem described by mp. 491 */ 492 int 493 msdosfs_unmount(mp, mntflags, p) 494 struct mount *mp; 495 int mntflags; 496 struct proc *p; 497 { 498 int flags = 0; 499 int error; 500 struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data; 501 502 /* only the mounter, or superuser can unmount */ 503 if ((p->p_cred->p_ruid != pmp->pm_mounter) && 504 (error = suser(p->p_ucred, &p->p_acflag))) 505 return error; 506 507 if (mntflags & MNT_FORCE) { 508 if (!msdosfsdoforce) 509 return EINVAL; 510 flags |= FORCECLOSE; 511 } 512 #ifdef QUOTA 513 #endif 514 error = vflush(mp, NULLVP, flags); 515 if (error) 516 return error; 517 pmp->pm_devvp->v_specflags &= ~SI_MOUNTEDON; 518 error = VOP_CLOSE(pmp->pm_devvp, pmp->pm_ronly ? FREAD : FREAD | FWRITE, 519 NOCRED, p); 520 vrele(pmp->pm_devvp); 521 free((caddr_t) pmp->pm_inusemap, M_MSDOSFSFAT); 522 free((caddr_t) pmp, M_MSDOSFSMNT); 523 mp->mnt_data = (qaddr_t) 0; 524 mp->mnt_flag &= ~MNT_LOCAL; 525 return error; 526 } 527 528 int 529 msdosfs_root(mp, vpp) 530 struct mount *mp; 531 struct vnode **vpp; 532 { 533 struct denode *ndep; 534 struct msdosfsmount *pmp = (struct msdosfsmount *) (mp->mnt_data); 535 int error; 536 537 error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, NULL, &ndep); 538 #ifdef MSDOSFS_DEBUG 539 printf("msdosfs_root(); mp %p, pmp %p, ndep %p, vp %p\n", 540 mp, pmp, ndep, DETOV(ndep)); 541 #endif 542 if (error == 0) 543 *vpp = DETOV(ndep); 544 return error; 545 } 546 547 int 548 msdosfs_quotactl(mp, cmds, uid, arg, p) 549 struct mount *mp; 550 int cmds; 551 uid_t uid; 552 caddr_t arg; 553 struct proc *p; 554 { 555 #ifdef QUOTA 556 return EOPNOTSUPP; 557 #else 558 return EOPNOTSUPP; 559 #endif 560 } 561 562 int 563 msdosfs_statfs(mp, sbp, p) 564 struct mount *mp; 565 struct statfs *sbp; 566 struct proc *p; 567 { 568 struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data; 569 570 /* 571 * Fill in the stat block. 572 */ 573 sbp->f_type = MOUNT_MSDOS; 574 sbp->f_bsize = pmp->pm_bpcluster; 575 sbp->f_iosize = pmp->pm_bpcluster; 576 sbp->f_blocks = pmp->pm_nmbrofclusters; 577 sbp->f_bfree = pmp->pm_freeclustercount; 578 sbp->f_bavail = pmp->pm_freeclustercount; 579 sbp->f_files = pmp->pm_RootDirEnts; /* XXX */ 580 sbp->f_ffree = 0; /* what to put in here? */ 581 582 /* 583 * Copy the mounted on and mounted from names into the passed in 584 * stat block, if it is not the one in the mount structure. 585 */ 586 if (sbp != &mp->mnt_stat) { 587 bcopy((caddr_t) mp->mnt_stat.f_mntonname, 588 (caddr_t) & sbp->f_mntonname[0], MNAMELEN); 589 bcopy((caddr_t) mp->mnt_stat.f_mntfromname, 590 (caddr_t) & sbp->f_mntfromname[0], MNAMELEN); 591 } 592 #if 0 593 strncpy(&sbp->f_fstypename[0], mp->mnt_op->vfs_name, MFSNAMELEN); 594 sbp->f_fstypename[MFSNAMELEN] = '\0'; 595 #endif 596 return 0; 597 } 598 599 int 600 msdosfs_sync(mp, waitfor, cred, p) 601 struct mount *mp; 602 int waitfor; 603 struct ucred *cred; 604 struct proc *p; 605 { 606 struct vnode *vp; 607 struct denode *dep; 608 struct msdosfsmount *pmp; 609 int error; 610 int allerror = 0; 611 612 pmp = (struct msdosfsmount *) mp->mnt_data; 613 614 /* 615 * If we ever switch to not updating all of the fats all the time, 616 * this would be the place to update them from the first one. 617 */ 618 if (pmp->pm_fmod) 619 if (pmp->pm_ronly) 620 panic("msdosfs_sync: rofs mod"); 621 else { 622 /* update fats here */ 623 } 624 625 /* 626 * Go thru in memory denodes and write them out along with 627 * unwritten file blocks. 628 */ 629 loop: 630 for (vp = mp->mnt_vnodelist.lh_first; vp; 631 vp = vp->v_mntvnodes.le_next) { 632 if (vp->v_mount != mp) /* not ours anymore */ 633 goto loop; 634 if (VOP_ISLOCKED(vp)) /* file is busy */ 635 continue; 636 dep = VTODE(vp); 637 if ((dep->de_flag & (DE_MODIFIED | DE_UPDATE)) == 0 && 638 vp->v_dirtyblkhd.lh_first == NULL) 639 continue; 640 if (vget(vp, 1)) /* not there anymore? */ 641 goto loop; 642 error = VOP_FSYNC(vp, cred, waitfor, p); 643 if (error) 644 allerror = error; 645 vput(vp); /* done with this one */ 646 } 647 648 /* 649 * Flush filesystem control info. 650 */ 651 error = VOP_FSYNC(pmp->pm_devvp, cred, waitfor, p); 652 if (error) 653 allerror = error; 654 return allerror; 655 } 656 657 int 658 msdosfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) 659 struct mount *mp; 660 struct fid *fhp; 661 struct mbuf *nam; 662 struct vnode **vpp; 663 int *exflagsp; 664 struct ucred **credanonp; 665 { 666 struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data; 667 struct defid *defhp = (struct defid *) fhp; 668 struct denode *dep; 669 struct netcred *np; 670 int error; 671 672 np = vfs_export_lookup(mp, &pmp->pm_export, nam); 673 if (np == NULL) 674 return EACCES; 675 error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, 676 NULL, &dep); 677 if (error) { 678 *vpp = NULLVP; 679 return error; 680 } 681 *vpp = DETOV(dep); 682 *exflagsp = np->netc_exflags; 683 *credanonp = &np->netc_anon; 684 return 0; 685 } 686 687 688 int 689 msdosfs_vptofh(vp, fhp) 690 struct vnode *vp; 691 struct fid *fhp; 692 { 693 struct denode *dep = VTODE(vp); 694 struct defid *defhp = (struct defid *) fhp; 695 696 defhp->defid_len = sizeof(struct defid); 697 defhp->defid_dirclust = dep->de_dirclust; 698 defhp->defid_dirofs = dep->de_diroffset; 699 /* defhp->defid_gen = ip->i_gen; */ 700 return 0; 701 } 702 703 int 704 msdosfs_vget(mp, ino, vpp) 705 struct mount *mp; 706 ino_t ino; 707 struct vnode **vpp; 708 { 709 return EOPNOTSUPP; 710 } 711 712 struct vfsops msdosfs_vfsops = { 713 msdosfs_mount, 714 msdosfs_start, 715 msdosfs_unmount, 716 msdosfs_root, 717 msdosfs_quotactl, 718 msdosfs_statfs, 719 msdosfs_sync, 720 msdosfs_vget, 721 msdosfs_fhtovp, 722 msdosfs_vptofh, 723 msdosfs_init 724 }; 725 726 VFS_SET(msdosfs_vfsops, msdos, MOUNT_MSDOS, 0); 727