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