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