msdosfs_vfsops.c revision 31132
1/* $Id: msdosfs_vfsops.c,v 1.22 1997/10/12 20:25:01 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/fcntl.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 70MALLOC_DEFINE(M_MSDOSFSMNT, "MSDOSFS mount", "MSDOSFS mount structure"); 71static MALLOC_DEFINE(M_MSDOSFSFAT, "MSDOSFS FAT", "MSDOSFS file allocation table"); 72 73static int mountmsdosfs __P((struct vnode *devvp, struct mount *mp, 74 struct proc *p)); 75static int msdosfs_fhtovp __P((struct mount *, struct fid *, 76 struct sockaddr *, struct vnode **, int *, 77 struct ucred **)); 78static int msdosfs_mount __P((struct mount *, char *, caddr_t, 79 struct nameidata *, struct proc *)); 80static int msdosfs_quotactl __P((struct mount *, int, uid_t, caddr_t, 81 struct proc *)); 82static int msdosfs_root __P((struct mount *, struct vnode **)); 83static int msdosfs_start __P((struct mount *, int, struct proc *)); 84static int msdosfs_statfs __P((struct mount *, struct statfs *, 85 struct proc *)); 86static int msdosfs_sync __P((struct mount *, int, struct ucred *, 87 struct proc *)); 88static int msdosfs_unmount __P((struct mount *, int, struct proc *)); 89static int msdosfs_vget __P((struct mount *mp, ino_t ino, 90 struct vnode **vpp)); 91static int msdosfs_vptofh __P((struct vnode *, struct fid *)); 92 93/* 94 * mp - path - addr in user space of mount point (ie /usr or whatever) 95 * data - addr in user space of mount params including the name of the block 96 * special file to treat as a filesystem. 97 */ 98static int 99msdosfs_mount(mp, path, data, ndp, p) 100 struct mount *mp; 101 char *path; 102 caddr_t data; 103 struct nameidata *ndp; 104 struct proc *p; 105{ 106 struct vnode *devvp; /* vnode for blk device to mount */ 107 struct msdosfs_args args; /* will hold data from mount request */ 108 struct msdosfsmount *pmp; /* msdosfs specific mount control block */ 109 int error, flags; 110 u_int size; 111 struct ucred *cred, *scred; 112 struct vattr va; 113 114 /* 115 * Copy in the args for the mount request. 116 */ 117 error = copyin(data, (caddr_t) & args, sizeof(struct msdosfs_args)); 118 if (error) 119 return error; 120 121 /* 122 * If they just want to update then be sure we can do what is 123 * asked. Can't change a filesystem from read/write to read only. 124 * Why? And if they've supplied a new device file name then we 125 * continue, otherwise return. 126 */ 127 if (mp->mnt_flag & MNT_UPDATE) { 128 pmp = (struct msdosfsmount *) mp->mnt_data; 129 error = 0; 130 if (pmp->pm_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { 131 flags = WRITECLOSE; 132 if (mp->mnt_flag & MNT_FORCE) 133 flags |= FORCECLOSE; 134 error = vflush(mp, NULLVP, flags); 135 } 136 if (!error && (mp->mnt_flag & MNT_RELOAD)) 137 /* not yet implemented */ 138 error = EINVAL; 139 if (error) 140 return error; 141 if (pmp->pm_ronly && (mp->mnt_kern_flag & MNTK_WANTRDWR)) 142 pmp->pm_ronly = 0; 143 if (args.fspec == 0) { 144 /* 145 * Process export requests. 146 */ 147 return vfs_export(mp, &pmp->pm_export, &args.export); 148 } 149 } else 150 pmp = NULL; 151 152 /* 153 * check to see that the user in owns the target directory. 154 * Note the very XXX trick to make sure we're checking as the 155 * real user -- were mount() executable by anyone, this wouldn't 156 * be a problem. 157 * 158 * XXX there should be one consistent error out. 159 */ 160 cred = crdup(p->p_ucred); /* XXX */ 161 cred->cr_uid = p->p_cred->p_ruid; /* XXX */ 162 error = VOP_GETATTR(mp->mnt_vnodecovered, &va, cred, p); 163 if (error) { 164 crfree(cred); /* XXX */ 165 return error; 166 } 167 if (cred->cr_uid != 0) { 168 if (va.va_uid != cred->cr_uid) { 169 error = EACCES; 170 crfree(cred); /* XXX */ 171 return error; 172 } 173 174 /* a user mounted it; we'll verify permissions when unmounting */ 175 mp->mnt_flag |= MNT_USER; 176 } 177 178 /* 179 * Now, lookup the name of the block device this mount or name 180 * update request is to apply to. 181 */ 182 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p); 183 scred = p->p_ucred; /* XXX */ 184 p->p_ucred = cred; /* XXX */ 185 error = namei(ndp); 186 p->p_ucred = scred; /* XXX */ 187 crfree(cred); /* XXX */ 188 if (error != 0) 189 return error; 190 191 /* 192 * Be sure they've given us a block device to treat as a 193 * filesystem. And, that its major number is within the bdevsw 194 * table. 195 */ 196 devvp = ndp->ni_vp; 197 if (devvp->v_type != VBLK) { 198 vrele(devvp); 199 return ENOTBLK; 200 } 201 if (major(devvp->v_rdev) >= nblkdev) { 202 vrele(devvp); 203 return ENXIO; 204 } 205 206 /* 207 * If this is an update, then make sure the vnode for the block 208 * special device is the same as the one our filesystem is in. 209 */ 210 if (mp->mnt_flag & MNT_UPDATE) { 211 if (devvp != pmp->pm_devvp) 212 error = EINVAL; 213 else 214 vrele(devvp); 215 } else { 216 217 /* 218 * Well, it's not an update, it's a real mount request. 219 * Time to get dirty. 220 */ 221 error = mountmsdosfs(devvp, mp, p); 222 } 223 if (error) { 224 vrele(devvp); 225 return error; 226 } 227 228 /* 229 * Copy in the name of the directory the filesystem is to be 230 * mounted on. Then copy in the name of the block special file 231 * representing the filesystem being mounted. And we clear the 232 * remainder of the character strings to be tidy. Set up the 233 * user id/group id/mask as specified by the user. Then, we try to 234 * fill in the filesystem stats structure as best we can with 235 * whatever applies from a dos file system. 236 */ 237 pmp = (struct msdosfsmount *) mp->mnt_data; 238 copyinstr(path, (caddr_t) mp->mnt_stat.f_mntonname, 239 sizeof(mp->mnt_stat.f_mntonname) - 1, &size); 240 bzero(mp->mnt_stat.f_mntonname + size, 241 sizeof(mp->mnt_stat.f_mntonname) - size); 242 copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size); 243 bzero(mp->mnt_stat.f_mntfromname + size, 244 MNAMELEN - size); 245 pmp->pm_mounter = p->p_cred->p_ruid; 246 pmp->pm_gid = args.gid; 247 pmp->pm_uid = args.uid; 248 pmp->pm_mask = args.mask; 249 (void) msdosfs_statfs(mp, &mp->mnt_stat, p); 250#ifdef MSDOSFS_DEBUG 251 printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap); 252#endif 253 return 0; 254} 255 256static int 257mountmsdosfs(devvp, mp, p) 258 struct vnode *devvp; 259 struct mount *mp; 260 struct proc *p; 261{ 262 int i; 263 int bpc; 264 int bit; 265 int error; 266 int needclose; 267 int ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 268 dev_t dev = devvp->v_rdev; 269 union bootsector *bsp; 270 struct msdosfsmount *pmp = NULL; 271 struct buf *bp0 = NULL; 272 struct byte_bpb33 *b33; 273 struct byte_bpb50 *b50; 274#ifdef PC98 275 u_int pc98_wrk; 276 u_int Phy_Sector_Size; 277#endif 278 279 /* 280 * Multiple mounts of the same block special file aren't allowed. 281 * Make sure no one else has the special file open. And flush any 282 * old buffers from this filesystem. Presumably this prevents us 283 * from running into buffers that are the wrong blocksize. 284 */ 285 error = vfs_mountedon(devvp); 286 if (error) 287 return error; 288 if (vcount(devvp) > 1) 289 return EBUSY; 290 error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0); 291 if (error) 292 return error; 293 294 /* 295 * Now open the block special file. 296 */ 297 error = VOP_OPEN(devvp, ronly ? FREAD : FREAD | FWRITE, FSCRED, p); 298 if (error) 299 return error; 300 needclose = 1; 301#ifdef HDSUPPORT 302 /* 303 * Put this in when we support reading dos filesystems from 304 * partitioned harddisks. 305 */ 306 if (VOP_IOCTL(devvp, DIOCGPART, &msdosfspart, FREAD, NOCRED, p) == 0) { 307 } 308#endif 309 310 /* 311 * Read the boot sector of the filesystem, and then check the boot 312 * signature. If not a dos boot sector then error out. We could 313 * also add some checking on the bsOemName field. So far I've seen 314 * the following values: "IBM 3.3" "MSDOS3.3" "MSDOS5.0" 315 */ 316#ifdef PC98 317 devvp->v_flag &= 0xffff; 318 error = bread(devvp, 0, 1024, NOCRED, &bp0); 319#else 320 error = bread(devvp, 0, 512, NOCRED, &bp0); 321#endif 322 if (error) 323 goto error_exit; 324 bp0->b_flags |= B_AGE; 325 bsp = (union bootsector *) bp0->b_data; 326 b33 = (struct byte_bpb33 *) bsp->bs33.bsBPB; 327 b50 = (struct byte_bpb50 *) bsp->bs50.bsBPB; 328#ifdef MSDOSFS_CHECKSIG 329#ifdef PC98 330 if (bsp->bs50.bsBootSectSig != BOOTSIG && 331 bsp->bs50.bsBootSectSig != 0 && /* PC98 DOS 3.3x */ 332 bsp->bs50.bsBootSectSig != 15760 && /* PC98 DOS 5.0 */ 333 bsp->bs50.bsBootSectSig != 64070) { /* PC98 DOS 3.3B */ 334#else 335 if (bsp->bs50.bsBootSectSig != BOOTSIG) { 336#endif 337 error = EINVAL; 338 goto error_exit; 339 } 340#endif 341 if ( bsp->bs50.bsJump[0] != 0xe9 && 342 (bsp->bs50.bsJump[0] != 0xeb || bsp->bs50.bsJump[2] != 0x90)) { 343 error = EINVAL; 344 goto error_exit; 345 } 346 347 pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK); 348 bzero((caddr_t)pmp, sizeof *pmp); 349 pmp->pm_mountp = mp; 350 351 /* 352 * Compute several useful quantities from the bpb in the 353 * bootsector. Copy in the dos 5 variant of the bpb then fix up 354 * the fields that are different between dos 5 and dos 3.3. 355 */ 356 pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec); 357 pmp->pm_SectPerClust = b50->bpbSecPerClust; 358 pmp->pm_ResSectors = getushort(b50->bpbResSectors); 359 pmp->pm_FATs = b50->bpbFATs; 360 pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts); 361 pmp->pm_Sectors = getushort(b50->bpbSectors); 362 pmp->pm_Media = b50->bpbMedia; 363 pmp->pm_FATsecs = getushort(b50->bpbFATsecs); 364 pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack); 365 pmp->pm_Heads = getushort(b50->bpbHeads); 366 367 /* XXX - We should probably check more values here */ 368 if (!pmp->pm_BytesPerSec || !pmp->pm_SectPerClust || 369 !pmp->pm_Heads || pmp->pm_Heads > 255 || 370#ifdef PC98 371 !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 255) { 372#else 373 !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 63) { 374#endif 375 error = EINVAL; 376 goto error_exit; 377 } 378 379 if (pmp->pm_Sectors == 0) { 380 pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs); 381 pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors); 382 } else { 383 pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs); 384 pmp->pm_HugeSectors = pmp->pm_Sectors; 385 } 386#ifdef PC98 /* for PC98 added Satoshi Yasuda */ 387 Phy_Sector_Size = 512; 388 if ((devvp->v_rdev>>8) == 2) { /* floppy check */ 389 if (((devvp->v_rdev&077) == 2) && (pmp->pm_HugeSectors == 1232)) { 390 Phy_Sector_Size = 1024; /* 2HD */ 391 /* 392 * 1024byte/sector support 393 */ 394 devvp->v_flag |= 0x10000; 395 } else { 396 if ((((devvp->v_rdev&077) == 3) /* 2DD 8 or 9 sector */ 397 && (pmp->pm_HugeSectors == 1440)) /* 9 sector */ 398 || (((devvp->v_rdev&077) == 4) 399 && (pmp->pm_HugeSectors == 1280)) /* 8 sector */ 400 || (((devvp->v_rdev&077) == 5) 401 && (pmp->pm_HugeSectors == 2880))) { /* 1.44M */ 402 Phy_Sector_Size = 512; 403 } else { 404 if (((devvp->v_rdev&077) != 1) 405 && ((devvp->v_rdev&077) != 0)) { /* 2HC */ 406 error = EINVAL; 407 goto error_exit; 408 } 409 } 410 } 411 } 412 pc98_wrk = pmp->pm_BytesPerSec / Phy_Sector_Size; 413 pmp->pm_BytesPerSec = Phy_Sector_Size; 414 pmp->pm_SectPerClust = pmp->pm_SectPerClust * pc98_wrk; 415 pmp->pm_HugeSectors = pmp->pm_HugeSectors * pc98_wrk; 416 pmp->pm_ResSectors = pmp->pm_ResSectors * pc98_wrk; 417 pmp->pm_FATsecs = pmp->pm_FATsecs * pc98_wrk; 418 pmp->pm_SecPerTrack = pmp->pm_SecPerTrack * pc98_wrk; 419 pmp->pm_HiddenSects = pmp->pm_HiddenSects * pc98_wrk; 420#endif /* */ 421 pmp->pm_fatblk = pmp->pm_ResSectors; 422 pmp->pm_rootdirblk = pmp->pm_fatblk + 423 (pmp->pm_FATs * pmp->pm_FATsecs); 424 pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry)) 425 / 426 pmp->pm_BytesPerSec;/* in sectors */ 427 pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize; 428 pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) / 429 pmp->pm_SectPerClust; 430 pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1; 431 pmp->pm_fatsize = pmp->pm_FATsecs * pmp->pm_BytesPerSec; 432 if (FAT12(pmp)) 433 /* 434 * This will usually be a floppy disk. This size makes sure 435 * that one fat entry will not be split across multiple 436 * blocks. 437 */ 438 pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec; 439 else 440 /* 441 * This will usually be a hard disk. Reading or writing one 442 * block should be quite fast. 443 */ 444 pmp->pm_fatblocksize = MAXBSIZE; 445 pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec; 446 447 448 if ((pmp->pm_rootdirsize % pmp->pm_SectPerClust) != 0) 449 printf("mountmsdosfs(): Warning: root directory is not a multiple of the clustersize in length\n"); 450 451 /* 452 * Compute mask and shift value for isolating cluster relative byte 453 * offsets and cluster numbers from a file offset. 454 */ 455 bpc = pmp->pm_SectPerClust * pmp->pm_BytesPerSec; 456 pmp->pm_bpcluster = bpc; 457 pmp->pm_depclust = bpc / sizeof(struct direntry); 458 pmp->pm_crbomask = bpc - 1; 459 if (bpc == 0) { 460 error = EINVAL; 461 goto error_exit; 462 } 463 bit = 1; 464 for (i = 0; i < 32; i++) { 465 if (bit & bpc) { 466 if (bit ^ bpc) { 467 error = EINVAL; 468 goto error_exit; 469 } 470 pmp->pm_cnshift = i; 471 break; 472 } 473 bit <<= 1; 474 } 475 476#ifdef PC98 477 if (Phy_Sector_Size == 512) { 478 pmp->pm_brbomask = 0x01ff; /* 512 byte blocks only (so far) */ 479 pmp->pm_bnshift = 9; /* shift right 9 bits to get bn */ 480 } else { 481 pmp->pm_brbomask = 0x03ff; 482 pmp->pm_bnshift = 10; 483 } 484#else 485 pmp->pm_brbomask = 0x01ff; /* 512 byte blocks only (so far) */ 486 pmp->pm_bnshift = 9; /* shift right 9 bits to get bn */ 487#endif 488 489 /* 490 * Release the bootsector buffer. 491 */ 492 brelse(bp0); 493 bp0 = NULL; 494 495 /* 496 * Allocate memory for the bitmap of allocated clusters, and then 497 * fill it in. 498 */ 499 pmp->pm_inusemap = malloc(((pmp->pm_maxcluster + N_INUSEBITS - 1) 500 / N_INUSEBITS) 501 * sizeof(*pmp->pm_inusemap), 502 M_MSDOSFSFAT, M_WAITOK); 503 504 /* 505 * fillinusemap() needs pm_devvp. 506 */ 507 pmp->pm_dev = dev; 508 pmp->pm_devvp = devvp; 509 510 /* 511 * Have the inuse map filled in. 512 */ 513 error = fillinusemap(pmp); 514 if (error) 515 goto error_exit; 516 517 /* 518 * If they want fat updates to be synchronous then let them suffer 519 * the performance degradation in exchange for the on disk copy of 520 * the fat being correct just about all the time. I suppose this 521 * would be a good thing to turn on if the kernel is still flakey. 522 */ 523 pmp->pm_waitonfat = mp->mnt_flag & MNT_SYNCHRONOUS; 524 525 /* 526 * Finish up. 527 */ 528 pmp->pm_ronly = ronly; 529 if (ronly == 0) 530 pmp->pm_fmod = 1; 531 mp->mnt_data = (qaddr_t) pmp; 532 mp->mnt_stat.f_fsid.val[0] = (long)dev; 533 mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 534 mp->mnt_flag |= MNT_LOCAL; 535 devvp->v_specflags |= SI_MOUNTEDON; 536 537 return 0; 538 539error_exit:; 540 if (bp0) 541 brelse(bp0); 542 if (needclose) 543 (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD | FWRITE, 544 NOCRED, p); 545 if (pmp) { 546 if (pmp->pm_inusemap) 547 free((caddr_t) pmp->pm_inusemap, M_MSDOSFSFAT); 548 free((caddr_t) pmp, M_MSDOSFSMNT); 549 mp->mnt_data = (qaddr_t) 0; 550 } 551 return error; 552} 553 554static int 555msdosfs_start(mp, flags, p) 556 struct mount *mp; 557 int flags; 558 struct proc *p; 559{ 560 return 0; 561} 562 563/* 564 * Unmount the filesystem described by mp. 565 */ 566static int 567msdosfs_unmount(mp, mntflags, p) 568 struct mount *mp; 569 int mntflags; 570 struct proc *p; 571{ 572 int flags = 0; 573 int error; 574 struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data; 575 576 /* only the mounter, or superuser can unmount */ 577 if ((p->p_cred->p_ruid != pmp->pm_mounter) && 578 (error = suser(p->p_ucred, &p->p_acflag))) 579 return error; 580 581 if (mntflags & MNT_FORCE) { 582 flags |= FORCECLOSE; 583 } 584 error = vflush(mp, NULLVP, flags); 585 if (error) 586 return error; 587 pmp->pm_devvp->v_specflags &= ~SI_MOUNTEDON; 588 error = VOP_CLOSE(pmp->pm_devvp, pmp->pm_ronly ? FREAD : FREAD | FWRITE, 589 NOCRED, p); 590 vrele(pmp->pm_devvp); 591 free((caddr_t) pmp->pm_inusemap, M_MSDOSFSFAT); 592 free((caddr_t) pmp, M_MSDOSFSMNT); 593 mp->mnt_data = (qaddr_t) 0; 594 mp->mnt_flag &= ~MNT_LOCAL; 595 return error; 596} 597 598static int 599msdosfs_root(mp, vpp) 600 struct mount *mp; 601 struct vnode **vpp; 602{ 603 struct denode *ndep; 604 struct msdosfsmount *pmp = (struct msdosfsmount *) (mp->mnt_data); 605 int error; 606 607 error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, NULL, &ndep); 608#ifdef MSDOSFS_DEBUG 609 printf("msdosfs_root(); mp %p, pmp %p, ndep %p, vp %p\n", 610 mp, pmp, ndep, DETOV(ndep)); 611#endif 612 if (error == 0) 613 *vpp = DETOV(ndep); 614 return error; 615} 616 617static int 618msdosfs_quotactl(mp, cmds, uid, arg, p) 619 struct mount *mp; 620 int cmds; 621 uid_t uid; 622 caddr_t arg; 623 struct proc *p; 624{ 625 return EOPNOTSUPP; 626} 627 628static int 629msdosfs_statfs(mp, sbp, p) 630 struct mount *mp; 631 struct statfs *sbp; 632 struct proc *p; 633{ 634 struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data; 635 636 /* 637 * Fill in the stat block. 638 */ 639 sbp->f_bsize = pmp->pm_bpcluster; 640 sbp->f_iosize = pmp->pm_bpcluster; 641 sbp->f_blocks = pmp->pm_nmbrofclusters; 642 sbp->f_bfree = pmp->pm_freeclustercount; 643 sbp->f_bavail = pmp->pm_freeclustercount; 644 sbp->f_files = pmp->pm_RootDirEnts; /* XXX */ 645 sbp->f_ffree = 0; /* what to put in here? */ 646 647 /* 648 * Copy the mounted on and mounted from names into the passed in 649 * stat block, if it is not the one in the mount structure. 650 */ 651 if (sbp != &mp->mnt_stat) { 652 sbp->f_type = mp->mnt_vfc->vfc_typenum; 653 bcopy((caddr_t) mp->mnt_stat.f_mntonname, 654 (caddr_t) & sbp->f_mntonname[0], MNAMELEN); 655 bcopy((caddr_t) mp->mnt_stat.f_mntfromname, 656 (caddr_t) & sbp->f_mntfromname[0], MNAMELEN); 657 } 658#if 0 659 strncpy(&sbp->f_fstypename[0], mp->mnt_op->vfs_name, MFSNAMELEN); 660 sbp->f_fstypename[MFSNAMELEN] = '\0'; 661#endif 662 return 0; 663} 664 665static int 666msdosfs_sync(mp, waitfor, cred, p) 667 struct mount *mp; 668 int waitfor; 669 struct ucred *cred; 670 struct proc *p; 671{ 672 struct vnode *vp; 673 struct denode *dep; 674 struct msdosfsmount *pmp; 675 int error; 676 int allerror = 0; 677 678 pmp = (struct msdosfsmount *) mp->mnt_data; 679 680 /* 681 * If we ever switch to not updating all of the fats all the time, 682 * this would be the place to update them from the first one. 683 */ 684 if (pmp->pm_fmod) 685 if (pmp->pm_ronly) 686 panic("msdosfs_sync: rofs mod"); 687 else { 688 /* update fats here */ 689 } 690 691 /* 692 * Go thru in memory denodes and write them out along with 693 * unwritten file blocks. 694 */ 695 simple_lock(&mntvnode_slock); 696loop: 697 for (vp = mp->mnt_vnodelist.lh_first; vp; 698 vp = vp->v_mntvnodes.le_next) { 699 if (vp->v_mount != mp) /* not ours anymore */ 700 goto loop; 701 simple_lock(&vp->v_interlock); 702 dep = VTODE(vp); 703 if ((dep->de_flag & (DE_MODIFIED | DE_UPDATE)) == 0 && 704 vp->v_dirtyblkhd.lh_first == NULL) { 705 simple_unlock(&vp->v_interlock); 706 continue; 707 } 708 simple_unlock(&mntvnode_slock); 709 error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p); 710 if (error) { 711 simple_lock(&mntvnode_slock); 712 if (error == ENOENT) 713 goto loop; 714 continue; 715 } 716 error = VOP_FSYNC(vp, cred, waitfor, p); 717 if (error) 718 allerror = error; 719 VOP_UNLOCK(vp, 0, p); 720 vrele(vp); /* done with this one */ 721 simple_lock(&mntvnode_slock); 722 } 723 simple_unlock(&mntvnode_slock); 724 725 /* 726 * Flush filesystem control info. 727 */ 728 error = VOP_FSYNC(pmp->pm_devvp, cred, waitfor, p); 729 if (error) 730 allerror = error; 731 return allerror; 732} 733 734static int 735msdosfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) 736 struct mount *mp; 737 struct fid *fhp; 738 struct sockaddr *nam; 739 struct vnode **vpp; 740 int *exflagsp; 741 struct ucred **credanonp; 742{ 743 struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data; 744 struct defid *defhp = (struct defid *) fhp; 745 struct denode *dep; 746 struct netcred *np; 747 int error; 748 749 np = vfs_export_lookup(mp, &pmp->pm_export, nam); 750 if (np == NULL) 751 return EACCES; 752 error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, 753 NULL, &dep); 754 if (error) { 755 *vpp = NULLVP; 756 return error; 757 } 758 *vpp = DETOV(dep); 759 *exflagsp = np->netc_exflags; 760 *credanonp = &np->netc_anon; 761 return 0; 762} 763 764 765static int 766msdosfs_vptofh(vp, fhp) 767 struct vnode *vp; 768 struct fid *fhp; 769{ 770 struct denode *dep = VTODE(vp); 771 struct defid *defhp = (struct defid *) fhp; 772 773 defhp->defid_len = sizeof(struct defid); 774 defhp->defid_dirclust = dep->de_dirclust; 775 defhp->defid_dirofs = dep->de_diroffset; 776 /* defhp->defid_gen = ip->i_gen; */ 777 return 0; 778} 779 780static int 781msdosfs_vget(mp, ino, vpp) 782 struct mount *mp; 783 ino_t ino; 784 struct vnode **vpp; 785{ 786 return EOPNOTSUPP; 787} 788 789static struct vfsops msdosfs_vfsops = { 790 msdosfs_mount, 791 msdosfs_start, 792 msdosfs_unmount, 793 msdosfs_root, 794 msdosfs_quotactl, 795 msdosfs_statfs, 796 msdosfs_sync, 797 msdosfs_vget, 798 msdosfs_fhtovp, 799 msdosfs_vptofh, 800 msdosfs_init 801}; 802 803VFS_SET(msdosfs_vfsops, msdos, MOUNT_MSDOS, 0); 804