1 /* $FreeBSD$ */ 2 /* $NetBSD: msdosfs_fat.c,v 1.28 1997/11/17 15:36:49 ws Exp $ */ 3 4 /*- 5 * SPDX-License-Identifier: BSD-4-Clause 6 * 7 * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. 8 * Copyright (C) 1994, 1995, 1997 TooLs GmbH. 9 * All rights reserved. 10 * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by TooLs GmbH. 23 * 4. The name of TooLs GmbH may not be used to endorse or promote products 24 * derived from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 27 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 28 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 29 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 31 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 32 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 33 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 34 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 35 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 */ 37 /*- 38 * Written by Paul Popelka (paulp@uts.amdahl.com) 39 * 40 * You can do anything you want with this software, just don't say you wrote 41 * it, and don't remove this notice. 42 * 43 * This software is provided "as is". 44 * 45 * The author supplies this software to be publicly redistributed on the 46 * understanding that the author is not responsible for the correct 47 * functioning of this software in any circumstances and is not liable for 48 * any damages caused by this software. 49 * 50 * October 1992 51 */ 52 53 #include <sys/param.h> 54 #include <sys/systm.h> 55 #include <sys/buf.h> 56 #include <sys/mount.h> 57 #include <sys/vmmeter.h> 58 #include <sys/vnode.h> 59 60 #include <fs/msdosfs/bpb.h> 61 #include <fs/msdosfs/direntry.h> 62 #include <fs/msdosfs/denode.h> 63 #include <fs/msdosfs/fat.h> 64 #include <fs/msdosfs/msdosfsmount.h> 65 66 #define FULL_RUN ((u_int)0xffffffff) 67 68 static int chainalloc(struct msdosfsmount *pmp, u_long start, 69 u_long count, u_long fillwith, u_long *retcluster, 70 u_long *got); 71 static int chainlength(struct msdosfsmount *pmp, u_long start, 72 u_long count); 73 static void fatblock(struct msdosfsmount *pmp, u_long ofs, u_long *bnp, 74 u_long *sizep, u_long *bop); 75 static int fatchain(struct msdosfsmount *pmp, u_long start, u_long count, 76 u_long fillwith); 77 static void fc_lookup(struct denode *dep, u_long findcn, u_long *frcnp, 78 u_long *fsrcnp); 79 static void updatefats(struct msdosfsmount *pmp, struct buf *bp, 80 u_long fatbn); 81 static __inline void 82 usemap_alloc(struct msdosfsmount *pmp, u_long cn); 83 static int usemap_free(struct msdosfsmount *pmp, u_long cn); 84 static int clusteralloc1(struct msdosfsmount *pmp, u_long start, 85 u_long count, u_long fillwith, u_long *retcluster, 86 u_long *got); 87 88 static void 89 fatblock(struct msdosfsmount *pmp, u_long ofs, u_long *bnp, u_long *sizep, 90 u_long *bop) 91 { 92 u_long bn, size, fatblocksec; 93 94 fatblocksec = pmp->pm_fatblocksec; 95 if (FAT12(pmp) && fatblocksec % 3 != 0) { 96 fatblocksec *= 3; 97 if (fatblocksec % 6 == 0) 98 fatblocksec /= 2; 99 } 100 bn = ofs / pmp->pm_fatblocksize * pmp->pm_fatblocksec; 101 size = roundup(min(fatblocksec, pmp->pm_FATsecs - bn) * DEV_BSIZE, 102 pmp->pm_BlkPerSec * DEV_BSIZE); 103 bn += pmp->pm_fatblk + pmp->pm_curfat * pmp->pm_FATsecs; 104 105 if (bnp) 106 *bnp = bn; 107 if (sizep) 108 *sizep = size; 109 if (bop) 110 *bop = ofs % pmp->pm_fatblocksize; 111 } 112 113 /* 114 * Map the logical cluster number of a file into a physical disk sector 115 * that is filesystem relative. 116 * 117 * dep - address of denode representing the file of interest 118 * findcn - file relative cluster whose filesystem relative cluster number 119 * and/or block number are/is to be found 120 * bnp - address of where to place the filesystem relative block number. 121 * If this pointer is null then don't return this quantity. 122 * cnp - address of where to place the filesystem relative cluster number. 123 * If this pointer is null then don't return this quantity. 124 * sp - pointer to returned block size 125 * 126 * NOTE: Either bnp or cnp must be non-null. 127 * This function has one side effect. If the requested file relative cluster 128 * is beyond the end of file, then the actual number of clusters in the file 129 * is returned in *cnp. This is useful for determining how long a directory is. 130 * If cnp is null, nothing is returned. 131 */ 132 int 133 pcbmap(struct denode *dep, u_long findcn, daddr_t *bnp, u_long *cnp, int *sp) 134 { 135 int error; 136 u_long i; 137 u_long cn; 138 u_long prevcn = 0; /* XXX: prevcn could be used unititialized */ 139 u_long byteoffset; 140 u_long bn; 141 u_long bo; 142 struct buf *bp = NULL; 143 u_long bp_bn = -1; 144 struct msdosfsmount *pmp = dep->de_pmp; 145 u_long bsize; 146 147 KASSERT(bnp != NULL || cnp != NULL || sp != NULL, 148 ("pcbmap: extra call")); 149 ASSERT_VOP_ELOCKED(DETOV(dep), "pcbmap"); 150 151 cn = dep->de_StartCluster; 152 /* 153 * The "file" that makes up the root directory is contiguous, 154 * permanently allocated, of fixed size, and is not made up of 155 * clusters. If the cluster number is beyond the end of the root 156 * directory, then return the number of clusters in the file. 157 */ 158 if (cn == MSDOSFSROOT) { 159 if (dep->de_Attributes & ATTR_DIRECTORY) { 160 if (de_cn2off(pmp, findcn) >= dep->de_FileSize) { 161 if (cnp) 162 *cnp = de_bn2cn(pmp, pmp->pm_rootdirsize); 163 return (E2BIG); 164 } 165 if (bnp) 166 *bnp = pmp->pm_rootdirblk + de_cn2bn(pmp, findcn); 167 if (cnp) 168 *cnp = MSDOSFSROOT; 169 if (sp) 170 *sp = min(pmp->pm_bpcluster, 171 dep->de_FileSize - de_cn2off(pmp, findcn)); 172 return (0); 173 } else { /* just an empty file */ 174 if (cnp) 175 *cnp = 0; 176 return (E2BIG); 177 } 178 } 179 180 /* 181 * All other files do I/O in cluster sized blocks 182 */ 183 if (sp) 184 *sp = pmp->pm_bpcluster; 185 186 /* 187 * Rummage around in the FAT cache, maybe we can avoid tromping 188 * through every FAT entry for the file. And, keep track of how far 189 * off the cache was from where we wanted to be. 190 */ 191 i = 0; 192 fc_lookup(dep, findcn, &i, &cn); 193 194 /* 195 * Handle all other files or directories the normal way. 196 */ 197 for (; i < findcn; i++) { 198 /* 199 * Stop with all reserved clusters, not just with EOF. 200 */ 201 if ((cn | ~pmp->pm_fatmask) >= CLUST_RSRVD) 202 goto hiteof; 203 byteoffset = FATOFS(pmp, cn); 204 fatblock(pmp, byteoffset, &bn, &bsize, &bo); 205 if (bn != bp_bn) { 206 if (bp) 207 brelse(bp); 208 error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp); 209 if (error) { 210 return (error); 211 } 212 bp_bn = bn; 213 } 214 prevcn = cn; 215 if (bo >= bsize) { 216 if (bp) 217 brelse(bp); 218 return (EIO); 219 } 220 if (FAT32(pmp)) 221 cn = getulong(bp->b_data + bo); 222 else 223 cn = getushort(bp->b_data + bo); 224 if (FAT12(pmp) && (prevcn & 1)) 225 cn >>= 4; 226 cn &= pmp->pm_fatmask; 227 228 /* 229 * Force the special cluster numbers 230 * to be the same for all cluster sizes 231 * to let the rest of msdosfs handle 232 * all cases the same. 233 */ 234 if ((cn | ~pmp->pm_fatmask) >= CLUST_RSRVD) 235 cn |= ~pmp->pm_fatmask; 236 } 237 238 if (!MSDOSFSEOF(pmp, cn)) { 239 if (bp) 240 brelse(bp); 241 if (bnp) 242 *bnp = cntobn(pmp, cn); 243 if (cnp) 244 *cnp = cn; 245 fc_setcache(dep, FC_LASTMAP, i, cn); 246 return (0); 247 } 248 249 hiteof:; 250 if (cnp) 251 *cnp = i; 252 if (bp) 253 brelse(bp); 254 /* update last file cluster entry in the FAT cache */ 255 fc_setcache(dep, FC_LASTFC, i - 1, prevcn); 256 return (E2BIG); 257 } 258 259 /* 260 * Find the closest entry in the FAT cache to the cluster we are looking 261 * for. 262 */ 263 static void 264 fc_lookup(struct denode *dep, u_long findcn, u_long *frcnp, u_long *fsrcnp) 265 { 266 int i; 267 u_long cn; 268 struct fatcache *closest = NULL; 269 270 ASSERT_VOP_LOCKED(DETOV(dep), "fc_lookup"); 271 272 for (i = 0; i < FC_SIZE; i++) { 273 cn = dep->de_fc[i].fc_frcn; 274 if (cn != FCE_EMPTY && cn <= findcn) { 275 if (closest == NULL || cn > closest->fc_frcn) 276 closest = &dep->de_fc[i]; 277 } 278 } 279 if (closest) { 280 *frcnp = closest->fc_frcn; 281 *fsrcnp = closest->fc_fsrcn; 282 } 283 } 284 285 /* 286 * Purge the FAT cache in denode dep of all entries relating to file 287 * relative cluster frcn and beyond. 288 */ 289 void 290 fc_purge(struct denode *dep, u_int frcn) 291 { 292 int i; 293 struct fatcache *fcp; 294 295 ASSERT_VOP_ELOCKED(DETOV(dep), "fc_purge"); 296 297 fcp = dep->de_fc; 298 for (i = 0; i < FC_SIZE; i++, fcp++) { 299 if (fcp->fc_frcn >= frcn) 300 fcp->fc_frcn = FCE_EMPTY; 301 } 302 } 303 304 /* 305 * Update the FAT. 306 * If mirroring the FAT, update all copies, with the first copy as last. 307 * Else update only the current FAT (ignoring the others). 308 * 309 * pmp - msdosfsmount structure for filesystem to update 310 * bp - addr of modified FAT block 311 * fatbn - block number relative to begin of filesystem of the modified FAT block. 312 */ 313 static void 314 updatefats(struct msdosfsmount *pmp, struct buf *bp, u_long fatbn) 315 { 316 struct buf *bpn; 317 int cleanfat, i; 318 319 #ifdef MSDOSFS_DEBUG 320 printf("updatefats(pmp %p, bp %p, fatbn %lu)\n", pmp, bp, fatbn); 321 #endif 322 323 if (pmp->pm_flags & MSDOSFS_FATMIRROR) { 324 /* 325 * Now copy the block(s) of the modified FAT to the other copies of 326 * the FAT and write them out. This is faster than reading in the 327 * other FATs and then writing them back out. This could tie up 328 * the FAT for quite a while. Preventing others from accessing it. 329 * To prevent us from going after the FAT quite so much we use 330 * delayed writes, unless they specified "synchronous" when the 331 * filesystem was mounted. If synch is asked for then use 332 * bwrite()'s and really slow things down. 333 */ 334 if (fatbn != pmp->pm_fatblk || FAT12(pmp)) 335 cleanfat = 0; 336 else if (FAT16(pmp)) 337 cleanfat = 16; 338 else 339 cleanfat = 32; 340 for (i = 1; i < pmp->pm_FATs; i++) { 341 fatbn += pmp->pm_FATsecs; 342 /* getblk() never fails */ 343 bpn = getblk(pmp->pm_devvp, fatbn, bp->b_bcount, 344 0, 0, 0); 345 memcpy(bpn->b_data, bp->b_data, bp->b_bcount); 346 /* Force the clean bit on in the other copies. */ 347 if (cleanfat == 16) 348 ((uint8_t *)bpn->b_data)[3] |= 0x80; 349 else if (cleanfat == 32) 350 ((uint8_t *)bpn->b_data)[7] |= 0x08; 351 if (pmp->pm_mountp->mnt_flag & MNT_SYNCHRONOUS) 352 bwrite(bpn); 353 else 354 bdwrite(bpn); 355 } 356 } 357 358 /* 359 * Write out the first (or current) FAT last. 360 */ 361 if (pmp->pm_mountp->mnt_flag & MNT_SYNCHRONOUS) 362 bwrite(bp); 363 else 364 bdwrite(bp); 365 } 366 367 /* 368 * Updating entries in 12 bit FATs is a pain in the butt. 369 * 370 * The following picture shows where nibbles go when moving from a 12 bit 371 * cluster number into the appropriate bytes in the FAT. 372 * 373 * byte m byte m+1 byte m+2 374 * +----+----+ +----+----+ +----+----+ 375 * | 0 1 | | 2 3 | | 4 5 | FAT bytes 376 * +----+----+ +----+----+ +----+----+ 377 * 378 * +----+----+----+ +----+----+----+ 379 * | 3 0 1 | | 4 5 2 | 380 * +----+----+----+ +----+----+----+ 381 * cluster n cluster n+1 382 * 383 * Where n is even. m = n + (n >> 2) 384 * 385 */ 386 static __inline void 387 usemap_alloc(struct msdosfsmount *pmp, u_long cn) 388 { 389 390 MSDOSFS_ASSERT_MP_LOCKED(pmp); 391 392 KASSERT(cn <= pmp->pm_maxcluster, ("cn too large %lu %lu", cn, 393 pmp->pm_maxcluster)); 394 KASSERT((pmp->pm_flags & MSDOSFSMNT_RONLY) == 0, 395 ("usemap_alloc on ro msdosfs mount")); 396 KASSERT((pmp->pm_inusemap[cn / N_INUSEBITS] & 397 (1U << (cn % N_INUSEBITS))) == 0, 398 ("Allocating used sector %ld %ld %x", cn, cn % N_INUSEBITS, 399 (unsigned)pmp->pm_inusemap[cn / N_INUSEBITS])); 400 pmp->pm_inusemap[cn / N_INUSEBITS] |= 1U << (cn % N_INUSEBITS); 401 KASSERT(pmp->pm_freeclustercount > 0, ("usemap_alloc: too little")); 402 pmp->pm_freeclustercount--; 403 pmp->pm_flags |= MSDOSFS_FSIMOD; 404 } 405 406 static int 407 usemap_free(struct msdosfsmount *pmp, u_long cn) 408 { 409 410 MSDOSFS_ASSERT_MP_LOCKED(pmp); 411 412 KASSERT(cn <= pmp->pm_maxcluster, ("cn too large %lu %lu", cn, 413 pmp->pm_maxcluster)); 414 KASSERT((pmp->pm_flags & MSDOSFSMNT_RONLY) == 0, 415 ("usemap_free on ro msdosfs mount")); 416 if ((pmp->pm_inusemap[cn / N_INUSEBITS] & 417 (1U << (cn % N_INUSEBITS))) == 0) { 418 printf("%s: Freeing unused sector %ld %ld %x\n", 419 pmp->pm_mountp->mnt_stat.f_mntonname, cn, cn % N_INUSEBITS, 420 (unsigned)pmp->pm_inusemap[cn / N_INUSEBITS]); 421 msdosfs_integrity_error(pmp); 422 return (EINTEGRITY); 423 } 424 pmp->pm_freeclustercount++; 425 pmp->pm_flags |= MSDOSFS_FSIMOD; 426 pmp->pm_inusemap[cn / N_INUSEBITS] &= ~(1U << (cn % N_INUSEBITS)); 427 return (0); 428 } 429 430 void 431 clusterfree(struct msdosfsmount *pmp, u_long cluster) 432 { 433 int error; 434 u_long oldcn; 435 436 error = fatentry(FAT_GET_AND_SET, pmp, cluster, &oldcn, MSDOSFSFREE); 437 if (error != 0) 438 return; 439 /* 440 * If the cluster was successfully marked free, then update 441 * the count of free clusters, and turn off the "allocated" 442 * bit in the "in use" cluster bit map. 443 */ 444 MSDOSFS_LOCK_MP(pmp); 445 error = usemap_free(pmp, cluster); 446 MSDOSFS_UNLOCK_MP(pmp); 447 } 448 449 /* 450 * Get or Set or 'Get and Set' the cluster'th entry in the FAT. 451 * 452 * function - whether to get or set a FAT entry 453 * pmp - address of the msdosfsmount structure for the filesystem 454 * whose FAT is to be manipulated. 455 * cn - which cluster is of interest 456 * oldcontents - address of a word that is to receive the contents of the 457 * cluster'th entry if this is a get function 458 * newcontents - the new value to be written into the cluster'th element of 459 * the FAT if this is a set function. 460 * 461 * This function can also be used to free a cluster by setting the FAT entry 462 * for a cluster to 0. 463 * 464 * All copies of the FAT are updated if this is a set function. NOTE: If 465 * fatentry() marks a cluster as free it does not update the inusemap in 466 * the msdosfsmount structure. This is left to the caller. 467 */ 468 int 469 fatentry(int function, struct msdosfsmount *pmp, u_long cn, u_long *oldcontents, 470 u_long newcontents) 471 { 472 int error; 473 u_long readcn; 474 u_long bn, bo, bsize, byteoffset; 475 struct buf *bp; 476 477 #ifdef MSDOSFS_DEBUG 478 printf("fatentry(func %d, pmp %p, clust %lu, oldcon %p, newcon %lx)\n", 479 function, pmp, cn, oldcontents, newcontents); 480 #endif 481 482 #ifdef DIAGNOSTIC 483 /* 484 * Be sure they asked us to do something. 485 */ 486 if ((function & (FAT_SET | FAT_GET)) == 0) { 487 #ifdef MSDOSFS_DEBUG 488 printf("fatentry(): function code doesn't specify get or set\n"); 489 #endif 490 return (EINVAL); 491 } 492 493 /* 494 * If they asked us to return a cluster number but didn't tell us 495 * where to put it, give them an error. 496 */ 497 if ((function & FAT_GET) && oldcontents == NULL) { 498 #ifdef MSDOSFS_DEBUG 499 printf("fatentry(): get function with no place to put result\n"); 500 #endif 501 return (EINVAL); 502 } 503 #endif 504 505 /* 506 * Be sure the requested cluster is in the filesystem. 507 */ 508 if (cn < CLUST_FIRST || cn > pmp->pm_maxcluster) 509 return (EINVAL); 510 511 byteoffset = FATOFS(pmp, cn); 512 fatblock(pmp, byteoffset, &bn, &bsize, &bo); 513 error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp); 514 if (error) { 515 return (error); 516 } 517 518 if (function & FAT_GET) { 519 if (FAT32(pmp)) 520 readcn = getulong(bp->b_data + bo); 521 else 522 readcn = getushort(bp->b_data + bo); 523 if (FAT12(pmp) & (cn & 1)) 524 readcn >>= 4; 525 readcn &= pmp->pm_fatmask; 526 /* map reserved FAT entries to same values for all FATs */ 527 if ((readcn | ~pmp->pm_fatmask) >= CLUST_RSRVD) 528 readcn |= ~pmp->pm_fatmask; 529 *oldcontents = readcn; 530 } 531 if (function & FAT_SET) { 532 switch (pmp->pm_fatmask) { 533 case FAT12_MASK: 534 readcn = getushort(bp->b_data + bo); 535 if (cn & 1) { 536 readcn &= 0x000f; 537 readcn |= newcontents << 4; 538 } else { 539 readcn &= 0xf000; 540 readcn |= newcontents & 0xfff; 541 } 542 putushort(bp->b_data + bo, readcn); 543 break; 544 case FAT16_MASK: 545 putushort(bp->b_data + bo, newcontents); 546 break; 547 case FAT32_MASK: 548 /* 549 * According to spec we have to retain the 550 * high order bits of the FAT entry. 551 */ 552 readcn = getulong(bp->b_data + bo); 553 readcn &= ~FAT32_MASK; 554 readcn |= newcontents & FAT32_MASK; 555 putulong(bp->b_data + bo, readcn); 556 break; 557 } 558 updatefats(pmp, bp, bn); 559 bp = NULL; 560 pmp->pm_fmod = 1; 561 } 562 if (bp) 563 brelse(bp); 564 return (0); 565 } 566 567 /* 568 * Update a contiguous cluster chain 569 * 570 * pmp - mount point 571 * start - first cluster of chain 572 * count - number of clusters in chain 573 * fillwith - what to write into FAT entry of last cluster 574 */ 575 static int 576 fatchain(struct msdosfsmount *pmp, u_long start, u_long count, u_long fillwith) 577 { 578 int error; 579 u_long bn, bo, bsize, byteoffset, readcn, newc; 580 struct buf *bp; 581 582 #ifdef MSDOSFS_DEBUG 583 printf("fatchain(pmp %p, start %lu, count %lu, fillwith %lx)\n", 584 pmp, start, count, fillwith); 585 #endif 586 /* 587 * Be sure the clusters are in the filesystem. 588 */ 589 if (start < CLUST_FIRST || start + count - 1 > pmp->pm_maxcluster) 590 return (EINVAL); 591 592 while (count > 0) { 593 byteoffset = FATOFS(pmp, start); 594 fatblock(pmp, byteoffset, &bn, &bsize, &bo); 595 error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp); 596 if (error) { 597 return (error); 598 } 599 while (count > 0) { 600 start++; 601 newc = --count > 0 ? start : fillwith; 602 switch (pmp->pm_fatmask) { 603 case FAT12_MASK: 604 readcn = getushort(bp->b_data + bo); 605 if (start & 1) { 606 readcn &= 0xf000; 607 readcn |= newc & 0xfff; 608 } else { 609 readcn &= 0x000f; 610 readcn |= newc << 4; 611 } 612 putushort(bp->b_data + bo, readcn); 613 bo++; 614 if (!(start & 1)) 615 bo++; 616 break; 617 case FAT16_MASK: 618 putushort(bp->b_data + bo, newc); 619 bo += 2; 620 break; 621 case FAT32_MASK: 622 readcn = getulong(bp->b_data + bo); 623 readcn &= ~pmp->pm_fatmask; 624 readcn |= newc & pmp->pm_fatmask; 625 putulong(bp->b_data + bo, readcn); 626 bo += 4; 627 break; 628 } 629 if (bo >= bsize) 630 break; 631 } 632 updatefats(pmp, bp, bn); 633 } 634 pmp->pm_fmod = 1; 635 return (0); 636 } 637 638 /* 639 * Check the length of a free cluster chain starting at start. 640 * 641 * pmp - mount point 642 * start - start of chain 643 * count - maximum interesting length 644 */ 645 static int 646 chainlength(struct msdosfsmount *pmp, u_long start, u_long count) 647 { 648 u_long idx, max_idx; 649 u_int map; 650 u_long len; 651 652 MSDOSFS_ASSERT_MP_LOCKED(pmp); 653 654 if (start > pmp->pm_maxcluster) 655 return (0); 656 max_idx = pmp->pm_maxcluster / N_INUSEBITS; 657 idx = start / N_INUSEBITS; 658 start %= N_INUSEBITS; 659 map = pmp->pm_inusemap[idx]; 660 map &= ~((1U << start) - 1); 661 if (map) { 662 len = ffs(map) - 1 - start; 663 len = MIN(len, count); 664 if (start + len > pmp->pm_maxcluster) 665 len = pmp->pm_maxcluster - start + 1; 666 return (len); 667 } 668 len = N_INUSEBITS - start; 669 if (len >= count) { 670 len = count; 671 if (start + len > pmp->pm_maxcluster) 672 len = pmp->pm_maxcluster - start + 1; 673 return (len); 674 } 675 while (++idx <= max_idx) { 676 if (len >= count) 677 break; 678 map = pmp->pm_inusemap[idx]; 679 if (map) { 680 len += ffs(map) - 1; 681 break; 682 } 683 len += N_INUSEBITS; 684 } 685 len = MIN(len, count); 686 if (start + len > pmp->pm_maxcluster) 687 len = pmp->pm_maxcluster - start + 1; 688 return (len); 689 } 690 691 /* 692 * Allocate contigous free clusters. 693 * 694 * pmp - mount point. 695 * start - start of cluster chain. 696 * count - number of clusters to allocate. 697 * fillwith - put this value into the FAT entry for the 698 * last allocated cluster. 699 * retcluster - put the first allocated cluster's number here. 700 * got - how many clusters were actually allocated. 701 */ 702 static int 703 chainalloc(struct msdosfsmount *pmp, u_long start, u_long count, 704 u_long fillwith, u_long *retcluster, u_long *got) 705 { 706 int error; 707 u_long cl, n; 708 709 MSDOSFS_ASSERT_MP_LOCKED(pmp); 710 KASSERT((pmp->pm_flags & MSDOSFSMNT_RONLY) == 0, 711 ("chainalloc on ro msdosfs mount")); 712 713 for (cl = start, n = count; n-- > 0;) 714 usemap_alloc(pmp, cl++); 715 pmp->pm_nxtfree = start + count; 716 if (pmp->pm_nxtfree > pmp->pm_maxcluster) 717 pmp->pm_nxtfree = CLUST_FIRST; 718 pmp->pm_flags |= MSDOSFS_FSIMOD; 719 error = fatchain(pmp, start, count, fillwith); 720 if (error != 0) { 721 for (cl = start, n = count; n-- > 0;) 722 (void)usemap_free(pmp, cl++); 723 return (error); 724 } 725 #ifdef MSDOSFS_DEBUG 726 printf("clusteralloc(): allocated cluster chain at %lu (%lu clusters)\n", 727 start, count); 728 #endif 729 if (retcluster) 730 *retcluster = start; 731 if (got) 732 *got = count; 733 return (0); 734 } 735 736 /* 737 * Allocate contiguous free clusters. 738 * 739 * pmp - mount point. 740 * start - preferred start of cluster chain. 741 * count - number of clusters requested. 742 * fillwith - put this value into the FAT entry for the 743 * last allocated cluster. 744 * retcluster - put the first allocated cluster's number here. 745 * got - how many clusters were actually allocated. 746 */ 747 int 748 clusteralloc(struct msdosfsmount *pmp, u_long start, u_long count, 749 u_long fillwith, u_long *retcluster, u_long *got) 750 { 751 int error; 752 753 MSDOSFS_LOCK_MP(pmp); 754 error = clusteralloc1(pmp, start, count, fillwith, retcluster, got); 755 MSDOSFS_UNLOCK_MP(pmp); 756 return (error); 757 } 758 759 static int 760 clusteralloc1(struct msdosfsmount *pmp, u_long start, u_long count, 761 u_long fillwith, u_long *retcluster, u_long *got) 762 { 763 u_long idx; 764 u_long len, newst, foundl, cn, l; 765 u_long foundcn = 0; /* XXX: foundcn could be used unititialized */ 766 u_int map; 767 768 MSDOSFS_ASSERT_MP_LOCKED(pmp); 769 770 #ifdef MSDOSFS_DEBUG 771 printf("clusteralloc(): find %lu clusters\n", count); 772 #endif 773 if (start) { 774 if ((len = chainlength(pmp, start, count)) >= count) 775 return (chainalloc(pmp, start, count, fillwith, retcluster, got)); 776 } else 777 len = 0; 778 779 newst = pmp->pm_nxtfree; 780 foundl = 0; 781 782 for (cn = newst; cn <= pmp->pm_maxcluster;) { 783 idx = cn / N_INUSEBITS; 784 map = pmp->pm_inusemap[idx]; 785 map |= (1U << (cn % N_INUSEBITS)) - 1; 786 if (map != FULL_RUN) { 787 cn = idx * N_INUSEBITS + ffs(map ^ FULL_RUN) - 1; 788 if ((l = chainlength(pmp, cn, count)) >= count) 789 return (chainalloc(pmp, cn, count, fillwith, retcluster, got)); 790 if (l > foundl) { 791 foundcn = cn; 792 foundl = l; 793 } 794 cn += l + 1; 795 continue; 796 } 797 cn += N_INUSEBITS - cn % N_INUSEBITS; 798 } 799 for (cn = 0; cn < newst;) { 800 idx = cn / N_INUSEBITS; 801 map = pmp->pm_inusemap[idx]; 802 map |= (1U << (cn % N_INUSEBITS)) - 1; 803 if (map != FULL_RUN) { 804 cn = idx * N_INUSEBITS + ffs(map ^ FULL_RUN) - 1; 805 if ((l = chainlength(pmp, cn, count)) >= count) 806 return (chainalloc(pmp, cn, count, fillwith, retcluster, got)); 807 if (l > foundl) { 808 foundcn = cn; 809 foundl = l; 810 } 811 cn += l + 1; 812 continue; 813 } 814 cn += N_INUSEBITS - cn % N_INUSEBITS; 815 } 816 817 if (!foundl) 818 return (ENOSPC); 819 820 if (len) 821 return (chainalloc(pmp, start, len, fillwith, retcluster, got)); 822 else 823 return (chainalloc(pmp, foundcn, foundl, fillwith, retcluster, got)); 824 } 825 826 /* 827 * Free a chain of clusters. 828 * 829 * pmp - address of the msdosfs mount structure for the filesystem 830 * containing the cluster chain to be freed. 831 * startcluster - number of the 1st cluster in the chain of clusters to be 832 * freed. 833 */ 834 int 835 freeclusterchain(struct msdosfsmount *pmp, u_long cluster) 836 { 837 int error; 838 struct buf *bp = NULL; 839 u_long bn, bo, bsize, byteoffset; 840 u_long readcn, lbn = -1; 841 842 MSDOSFS_LOCK_MP(pmp); 843 while (cluster >= CLUST_FIRST && cluster <= pmp->pm_maxcluster) { 844 byteoffset = FATOFS(pmp, cluster); 845 fatblock(pmp, byteoffset, &bn, &bsize, &bo); 846 if (lbn != bn) { 847 if (bp) 848 updatefats(pmp, bp, lbn); 849 error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp); 850 if (error) { 851 MSDOSFS_UNLOCK_MP(pmp); 852 return (error); 853 } 854 lbn = bn; 855 } 856 error = usemap_free(pmp, cluster); 857 if (error != 0) { 858 updatefats(pmp, bp, lbn); 859 MSDOSFS_UNLOCK_MP(pmp); 860 return (error); 861 } 862 switch (pmp->pm_fatmask) { 863 case FAT12_MASK: 864 readcn = getushort(bp->b_data + bo); 865 if (cluster & 1) { 866 cluster = readcn >> 4; 867 readcn &= 0x000f; 868 readcn |= MSDOSFSFREE << 4; 869 } else { 870 cluster = readcn; 871 readcn &= 0xf000; 872 readcn |= MSDOSFSFREE & 0xfff; 873 } 874 putushort(bp->b_data + bo, readcn); 875 break; 876 case FAT16_MASK: 877 cluster = getushort(bp->b_data + bo); 878 putushort(bp->b_data + bo, MSDOSFSFREE); 879 break; 880 case FAT32_MASK: 881 cluster = getulong(bp->b_data + bo); 882 putulong(bp->b_data + bo, 883 (MSDOSFSFREE & FAT32_MASK) | (cluster & ~FAT32_MASK)); 884 break; 885 } 886 cluster &= pmp->pm_fatmask; 887 if ((cluster | ~pmp->pm_fatmask) >= CLUST_RSRVD) 888 cluster |= pmp->pm_fatmask; 889 } 890 if (bp) 891 updatefats(pmp, bp, bn); 892 MSDOSFS_UNLOCK_MP(pmp); 893 return (0); 894 } 895 896 /* 897 * Read in FAT blocks looking for free clusters. For every free cluster 898 * found turn off its corresponding bit in the pm_inusemap. 899 */ 900 int 901 fillinusemap(struct msdosfsmount *pmp) 902 { 903 struct buf *bp; 904 u_long bn, bo, bsize, byteoffset, cn, readcn; 905 int error; 906 907 MSDOSFS_ASSERT_MP_LOCKED(pmp); 908 bp = NULL; 909 910 /* 911 * Mark all clusters in use, we mark the free ones in the FAT scan 912 * loop further down. 913 */ 914 for (cn = 0; cn < (pmp->pm_maxcluster + N_INUSEBITS) / N_INUSEBITS; cn++) 915 pmp->pm_inusemap[cn] = FULL_RUN; 916 917 /* 918 * Figure how many free clusters are in the filesystem by ripping 919 * through the FAT counting the number of entries whose content is 920 * zero. These represent free clusters. 921 */ 922 pmp->pm_freeclustercount = 0; 923 for (cn = 0; cn <= pmp->pm_maxcluster; cn++) { 924 byteoffset = FATOFS(pmp, cn); 925 bo = byteoffset % pmp->pm_fatblocksize; 926 if (bo == 0) { 927 /* Read new FAT block */ 928 if (bp != NULL) 929 brelse(bp); 930 fatblock(pmp, byteoffset, &bn, &bsize, NULL); 931 error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp); 932 if (error != 0) 933 return (error); 934 } 935 if (FAT32(pmp)) 936 readcn = getulong(bp->b_data + bo); 937 else 938 readcn = getushort(bp->b_data + bo); 939 if (FAT12(pmp) && (cn & 1)) 940 readcn >>= 4; 941 readcn &= pmp->pm_fatmask; 942 943 /* 944 * Check if the FAT ID matches the BPB's media descriptor and 945 * all other bits are set to 1. 946 */ 947 if (cn == 0 && readcn != ((pmp->pm_fatmask & 0xffffff00) | 948 pmp->pm_bpb.bpbMedia)) { 949 #ifdef MSDOSFS_DEBUG 950 printf("mountmsdosfs(): Media descriptor in BPB" 951 "does not match FAT ID\n"); 952 #endif 953 brelse(bp); 954 return (EINVAL); 955 } else if (readcn == CLUST_FREE) { 956 error = usemap_free(pmp, cn); 957 if (error != 0) { 958 brelse(bp); 959 return (error); 960 } 961 } 962 } 963 if (bp != NULL) 964 brelse(bp); 965 966 for (cn = pmp->pm_maxcluster + 1; cn < (pmp->pm_maxcluster + 967 N_INUSEBITS) / N_INUSEBITS; cn++) 968 pmp->pm_inusemap[cn / N_INUSEBITS] |= 1U << (cn % N_INUSEBITS); 969 970 return (0); 971 } 972 973 /* 974 * Allocate a new cluster and chain it onto the end of the file. 975 * 976 * dep - the file to extend 977 * count - number of clusters to allocate 978 * bpp - where to return the address of the buf header for the first new 979 * file block 980 * ncp - where to put cluster number of the first newly allocated cluster 981 * If this pointer is 0, do not return the cluster number. 982 * flags - see fat.h 983 * 984 * NOTE: This function is not responsible for turning on the DE_UPDATE bit of 985 * the de_flag field of the denode and it does not change the de_FileSize 986 * field. This is left for the caller to do. 987 */ 988 int 989 extendfile(struct denode *dep, u_long count, struct buf **bpp, u_long *ncp, 990 int flags) 991 { 992 int error; 993 u_long frcn; 994 u_long cn, got; 995 struct msdosfsmount *pmp = dep->de_pmp; 996 struct buf *bp; 997 daddr_t blkno; 998 999 /* 1000 * Don't try to extend the root directory 1001 */ 1002 if (dep->de_StartCluster == MSDOSFSROOT 1003 && (dep->de_Attributes & ATTR_DIRECTORY)) { 1004 #ifdef MSDOSFS_DEBUG 1005 printf("extendfile(): attempt to extend root directory\n"); 1006 #endif 1007 return (ENOSPC); 1008 } 1009 1010 /* 1011 * If the "file's last cluster" cache entry is empty, and the file 1012 * is not empty, then fill the cache entry by calling pcbmap(). 1013 */ 1014 if (dep->de_fc[FC_LASTFC].fc_frcn == FCE_EMPTY && 1015 dep->de_StartCluster != 0) { 1016 error = pcbmap(dep, 0xffff, 0, &cn, 0); 1017 /* we expect it to return E2BIG */ 1018 if (error != E2BIG) 1019 return (error); 1020 } 1021 1022 dep->de_fc[FC_NEXTTOLASTFC].fc_frcn = 1023 dep->de_fc[FC_LASTFC].fc_frcn; 1024 dep->de_fc[FC_NEXTTOLASTFC].fc_fsrcn = 1025 dep->de_fc[FC_LASTFC].fc_fsrcn; 1026 while (count > 0) { 1027 /* 1028 * Allocate a new cluster chain and cat onto the end of the 1029 * file. If the file is empty we make de_StartCluster point 1030 * to the new block. Note that de_StartCluster being 0 is 1031 * sufficient to be sure the file is empty since we exclude 1032 * attempts to extend the root directory above, and the root 1033 * dir is the only file with a startcluster of 0 that has 1034 * blocks allocated (sort of). 1035 */ 1036 if (dep->de_StartCluster == 0) 1037 cn = 0; 1038 else 1039 cn = dep->de_fc[FC_LASTFC].fc_fsrcn + 1; 1040 error = clusteralloc(pmp, cn, count, CLUST_EOFE, &cn, &got); 1041 if (error) 1042 return (error); 1043 1044 count -= got; 1045 1046 /* 1047 * Give them the filesystem relative cluster number if they want 1048 * it. 1049 */ 1050 if (ncp) { 1051 *ncp = cn; 1052 ncp = NULL; 1053 } 1054 1055 if (dep->de_StartCluster == 0) { 1056 dep->de_StartCluster = cn; 1057 frcn = 0; 1058 } else { 1059 error = fatentry(FAT_SET, pmp, 1060 dep->de_fc[FC_LASTFC].fc_fsrcn, 1061 0, cn); 1062 if (error) { 1063 clusterfree(pmp, cn); 1064 return (error); 1065 } 1066 frcn = dep->de_fc[FC_LASTFC].fc_frcn + 1; 1067 } 1068 1069 /* 1070 * Update the "last cluster of the file" entry in the 1071 * denode's FAT cache. 1072 */ 1073 fc_setcache(dep, FC_LASTFC, frcn + got - 1, cn + got - 1); 1074 1075 if (flags & DE_CLEAR) { 1076 while (got-- > 0) { 1077 /* 1078 * Get the buf header for the new block of the file. 1079 */ 1080 if (dep->de_Attributes & ATTR_DIRECTORY) 1081 bp = getblk(pmp->pm_devvp, 1082 cntobn(pmp, cn++), 1083 pmp->pm_bpcluster, 0, 0, 0); 1084 else { 1085 bp = getblk(DETOV(dep), 1086 frcn++, 1087 pmp->pm_bpcluster, 0, 0, 0); 1088 /* 1089 * Do the bmap now, as in msdosfs_write 1090 */ 1091 if (pcbmap(dep, 1092 bp->b_lblkno, 1093 &blkno, 0, 0)) 1094 bp->b_blkno = -1; 1095 if (bp->b_blkno == -1) 1096 panic("extendfile: pcbmap"); 1097 else 1098 bp->b_blkno = blkno; 1099 } 1100 clrbuf(bp); 1101 if (bpp) { 1102 *bpp = bp; 1103 bpp = NULL; 1104 } else { 1105 bdwrite(bp); 1106 } 1107 if (vm_page_count_severe() || 1108 buf_dirty_count_severe()) 1109 vn_fsync_buf(DETOV(dep), MNT_WAIT); 1110 } 1111 } 1112 } 1113 1114 return (0); 1115 } 1116 1117 /*- 1118 * Routine to mark a FAT16 or FAT32 volume as "clean" or "dirty" by 1119 * manipulating the upper bit of the FAT entry for cluster 1. Note that 1120 * this bit is not defined for FAT12 volumes, which are always assumed to 1121 * be clean. 1122 * 1123 * The fatentry() routine only works on cluster numbers that a file could 1124 * occupy, so it won't manipulate the entry for cluster 1. So we have to do 1125 * it here. The code was stolen from fatentry() and tailored for cluster 1. 1126 * 1127 * Inputs: 1128 * pmp The MS-DOS volume to mark 1129 * dirty Non-zero if the volume should be marked dirty; zero if it 1130 * should be marked clean 1131 * 1132 * Result: 1133 * 0 Success 1134 * EROFS Volume is read-only 1135 * ? (other errors from called routines) 1136 */ 1137 int 1138 markvoldirty_upgrade(struct msdosfsmount *pmp, bool dirty, bool rw_upgrade) 1139 { 1140 struct buf *bp; 1141 u_long bn, bo, bsize, byteoffset, fatval; 1142 int error; 1143 1144 /* 1145 * FAT12 does not support a "clean" bit, so don't do anything for 1146 * FAT12. 1147 */ 1148 if (FAT12(pmp)) 1149 return (0); 1150 1151 /* 1152 * Can't change the bit on a read-only filesystem, except as part of 1153 * ro->rw upgrade. 1154 */ 1155 if ((pmp->pm_flags & MSDOSFSMNT_RONLY) != 0 && !rw_upgrade) 1156 return (EROFS); 1157 1158 /* 1159 * Fetch the block containing the FAT entry. It is given by the 1160 * pseudo-cluster 1. 1161 */ 1162 byteoffset = FATOFS(pmp, 1); 1163 fatblock(pmp, byteoffset, &bn, &bsize, &bo); 1164 error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp); 1165 if (error) 1166 return (error); 1167 1168 /* 1169 * Get the current value of the FAT entry and set/clear the relevant 1170 * bit. Dirty means clear the "clean" bit; clean means set the 1171 * "clean" bit. 1172 */ 1173 if (FAT32(pmp)) { 1174 /* FAT32 uses bit 27. */ 1175 fatval = getulong(&bp->b_data[bo]); 1176 if (dirty) 1177 fatval &= 0xF7FFFFFF; 1178 else 1179 fatval |= 0x08000000; 1180 putulong(&bp->b_data[bo], fatval); 1181 } else { 1182 /* Must be FAT16; use bit 15. */ 1183 fatval = getushort(&bp->b_data[bo]); 1184 if (dirty) 1185 fatval &= 0x7FFF; 1186 else 1187 fatval |= 0x8000; 1188 putushort(&bp->b_data[bo], fatval); 1189 } 1190 1191 /* 1192 * The concern here is that a devvp may be readonly, without reporting 1193 * itself as such through the usual channels. In that case, we'd like 1194 * it if attempting to mount msdosfs rw didn't panic the system. 1195 * 1196 * markvoldirty is invoked as the first write on backing devvps when 1197 * either msdosfs is mounted for the first time, or a ro mount is 1198 * upgraded to rw. 1199 * 1200 * In either event, if a write error occurs dirtying the volume: 1201 * - No user data has been permitted to be written to cache yet. 1202 * - We can abort the high-level operation (mount, or ro->rw) safely. 1203 * - We don't derive any benefit from leaving a zombie dirty buf in 1204 * the cache that can not be cleaned or evicted. 1205 * 1206 * So, mark B_INVALONERR to have bwrite() -> brelse() detect that 1207 * condition and force-invalidate our write to the block if it occurs. 1208 * 1209 * PR 210316 provides more context on the discovery and diagnosis of 1210 * the problem, as well as earlier attempts to solve it. 1211 */ 1212 bp->b_flags |= B_INVALONERR; 1213 1214 /* Write out the modified FAT block synchronously. */ 1215 return (bwrite(bp)); 1216 } 1217