2 /* $NetBSD: msdosfs_fat.c,v 1.28 1997/11/17 15:36:49 ws Exp $ */
5 * SPDX-License-Identifier: BSD-4-Clause
7 * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
8 * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
10 * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
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.
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.
38 * Written by Paul Popelka (paulp@uts.amdahl.com)
40 * You can do anything you want with this software, just don't say you wrote
41 * it, and don't remove this notice.
43 * This software is provided "as is".
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.
53 #include <sys/param.h>
54 #include <sys/systm.h>
56 #include <sys/mount.h>
57 #include <sys/vnode.h>
61 #include <vfs/msdosfs/bpb.h>
62 #include <vfs/msdosfs/direntry.h>
63 #include <vfs/msdosfs/denode.h>
64 #include <vfs/msdosfs/fat.h>
65 #include <vfs/msdosfs/msdosfsmount.h>
67 #define FULL_RUN ((u_int)0xffffffff)
69 static void fc_lookup(struct denode
*dep
, u_long findcn
, u_long
*frcnp
,
71 static int clusteralloc1(struct msdosfsmount
*pmp
, u_long start
,
72 u_long count
, u_long fillwith
, u_long
*retcluster
,
76 * Given a byte offset `ofs` within FAT, return block number in backing device,
77 * block size, and byte offset within a block in FAT.
80 fatblock(struct msdosfsmount
*pmp
, u_long ofs
, u_long
*bnp
, u_long
*sizep
,
85 bn
= ofs
/ pmp
->pm_fatblocksize
* pmp
->pm_fatblocksec
;
86 size
= min(pmp
->pm_fatblocksec
, pmp
->pm_FATsecs
- bn
) * DEV_BSIZE
;
87 bn
+= pmp
->pm_fatblk
+ pmp
->pm_curfat
* pmp
->pm_FATsecs
;
94 *bop
= ofs
% pmp
->pm_fatblocksize
;
98 * Map the logical cluster number of a file into a physical disk sector
99 * that is filesystem relative.
101 * dep - address of denode representing the file of interest
102 * findcn - file relative cluster whose filesystem relative cluster number
103 * and/or block number are/is to be found
104 * bnp - address of where to place the filesystem relative block number.
105 * If this pointer is null then don't return this quantity.
106 * cnp - address of where to place the filesystem relative cluster number.
107 * If this pointer is null then don't return this quantity.
108 * sp - pointer to returned block size
110 * NOTE: Either bnp or cnp must be non-null.
111 * This function has one side effect. If the requested file relative cluster
112 * is beyond the end of file, then the actual number of clusters in the file
113 * is returned in *cnp. This is useful for determining how long a directory is.
114 * If cnp is null, nothing is returned.
117 pcbmap(struct denode
*dep
, u_long findcn
, daddr_t
*bnp
, u_long
*cnp
, int *sp
)
122 u_long prevcn
= 0; /* XXX: prevcn could be used unititialized */
126 struct buf
*bp
= NULL
;
128 struct msdosfsmount
*pmp
= dep
->de_pmp
;
131 KASSERT(bnp
!= NULL
|| cnp
!= NULL
|| sp
!= NULL
,
132 ("pcbmap: extra call"));
133 ASSERT_VOP_ELOCKED(DETOV(dep
), "pcbmap");
135 cn
= dep
->de_StartCluster
;
137 * The "file" that makes up the root directory is contiguous,
138 * permanently allocated, of fixed size, and is not made up of
139 * clusters. If the cluster number is beyond the end of the root
140 * directory, then return the number of clusters in the file.
142 if (cn
== MSDOSFSROOT
) {
143 if (dep
->de_Attributes
& ATTR_DIRECTORY
) {
144 if (de_cn2off(pmp
, findcn
) >= dep
->de_FileSize
) {
147 pmp
->pm_rootdirsize
);
151 *bnp
= pmp
->pm_rootdirblk
+
152 de_cn2bn(pmp
, findcn
);
156 *sp
= min(pmp
->pm_bpcluster
,
157 dep
->de_FileSize
- de_cn2off(pmp
, findcn
));
159 } else { /* just an empty file */
167 * All other files do I/O in cluster sized blocks
170 *sp
= pmp
->pm_bpcluster
;
173 * Rummage around in the FAT cache, maybe we can avoid tromping
174 * through every FAT entry for the file. And, keep track of how far
175 * off the cache was from where we wanted to be.
178 fc_lookup(dep
, findcn
, &i
, &cn
);
181 * Handle all other files or directories the normal way.
183 for (; i
< findcn
; i
++) {
185 * Stop with all reserved clusters, not just with EOF.
187 if ((cn
| ~pmp
->pm_fatmask
) >= CLUST_RSRVD
)
189 byteoffset
= FATOFS(pmp
, cn
);
190 fatblock(pmp
, byteoffset
, &bn
, &bsize
, &bo
);
194 error
= bread(pmp
->pm_devvp
, de_bn2doff(pmp
, bn
),
209 cn
= getulong(bp
->b_data
+ bo
);
211 cn
= getushort(bp
->b_data
+ bo
);
212 if (FAT12(pmp
) && (prevcn
& 1))
214 cn
&= pmp
->pm_fatmask
;
217 * Force the special cluster numbers
218 * to be the same for all cluster sizes
219 * to let the rest of msdosfs handle
220 * all cases the same.
222 if ((cn
| ~pmp
->pm_fatmask
) >= CLUST_RSRVD
)
223 cn
|= ~pmp
->pm_fatmask
;
226 if (!MSDOSFSEOF(pmp
, cn
)) {
230 *bnp
= cntobn(pmp
, cn
);
233 fc_setcache(dep
, FC_LASTMAP
, i
, cn
);
242 /* update last file cluster entry in the FAT cache */
243 fc_setcache(dep
, FC_LASTFC
, i
- 1, prevcn
);
248 * Find the closest entry in the FAT cache to the cluster we are looking
252 fc_lookup(struct denode
*dep
, u_long findcn
, u_long
*frcnp
, u_long
*fsrcnp
)
256 struct fatcache
*closest
= NULL
;
258 ASSERT_VOP_LOCKED(DETOV(dep
), "fc_lookup");
260 for (i
= 0; i
< FC_SIZE
; i
++) {
261 cn
= dep
->de_fc
[i
].fc_frcn
;
262 if (cn
!= FCE_EMPTY
&& cn
<= findcn
) {
263 if (closest
== NULL
|| cn
> closest
->fc_frcn
)
264 closest
= &dep
->de_fc
[i
];
268 *frcnp
= closest
->fc_frcn
;
269 *fsrcnp
= closest
->fc_fsrcn
;
274 * Purge the FAT cache in denode dep of all entries relating to file
275 * relative cluster frcn and beyond.
278 fc_purge(struct denode
*dep
, u_int frcn
)
281 struct fatcache
*fcp
;
283 ASSERT_VOP_ELOCKED(DETOV(dep
), "fc_purge");
286 for (i
= 0; i
< FC_SIZE
; i
++, fcp
++) {
287 if (fcp
->fc_frcn
>= frcn
)
288 fcp
->fc_frcn
= FCE_EMPTY
;
294 * If mirroring the FAT, update all copies, with the first copy as last.
295 * Else update only the current FAT (ignoring the others).
297 * pmp - msdosfsmount structure for filesystem to update
298 * bp - addr of modified FAT block
299 * fatbn - block number relative to begin of filesystem of the modified FAT block.
302 updatefats(struct msdosfsmount
*pmp
, struct buf
*bp
, u_long fatbn
)
307 mprintf("updatefats(pmp %p, bp %p, fatbn %lu)\n", pmp
, bp
, fatbn
);
309 if (pmp
->pm_flags
& MSDOSFS_FATMIRROR
) {
311 * Now copy the block(s) of the modified FAT to the other copies of
312 * the FAT and write them out. This is faster than reading in the
313 * other FATs and then writing them back out. This could tie up
314 * the FAT for quite a while. Preventing others from accessing it.
315 * To prevent us from going after the FAT quite so much we use
316 * delayed writes, unless they specified "synchronous" when the
317 * filesystem was mounted. If synch is asked for then use
318 * bwrite()'s and really slow things down.
320 if (fatbn
!= pmp
->pm_fatblk
|| FAT12(pmp
))
326 for (i
= 1; i
< pmp
->pm_FATs
; i
++) {
327 fatbn
+= pmp
->pm_FATsecs
;
328 /* getblk() never fails */
329 bpn
= getblk(pmp
->pm_devvp
, de_bn2doff(pmp
, fatbn
),
331 memcpy(bpn
->b_data
, bp
->b_data
, bp
->b_bcount
);
332 /* Force the clean bit on in the other copies. */
334 ((uint8_t *)bpn
->b_data
)[3] |= 0x80;
335 else if (cleanfat
== 32)
336 ((uint8_t *)bpn
->b_data
)[7] |= 0x08;
337 if (pmp
->pm_mountp
->mnt_flag
& MNT_SYNCHRONOUS
)
345 * Write out the first (or current) FAT last.
347 if (pmp
->pm_mountp
->mnt_flag
& MNT_SYNCHRONOUS
)
354 * Updating entries in 12 bit FATs is a pain in the butt.
356 * The following picture shows where nibbles go when moving from a 12 bit
357 * cluster number into the appropriate bytes in the FAT.
359 * byte m byte m+1 byte m+2
360 * +----+----+ +----+----+ +----+----+
361 * | 0 1 | | 2 3 | | 4 5 | FAT bytes
362 * +----+----+ +----+----+ +----+----+
364 * +----+----+----+ +----+----+----+
365 * | 3 0 1 | | 4 5 2 |
366 * +----+----+----+ +----+----+----+
367 * cluster n cluster n+1
369 * Where n is even. m = n + (n >> 2)
373 usemap_alloc(struct msdosfsmount
*pmp
, u_long cn
)
375 MSDOSFS_ASSERT_MP_LOCKED(pmp
);
377 KASSERT(cn
<= pmp
->pm_maxcluster
, ("cn too large %lu %lu", cn
,
378 pmp
->pm_maxcluster
));
379 KASSERT((pmp
->pm_flags
& MSDOSFSMNT_RONLY
) == 0,
380 ("usemap_alloc on ro msdosfs mount"));
381 KASSERT((pmp
->pm_inusemap
[cn
/ N_INUSEBITS
] &
382 (1U << (cn
% N_INUSEBITS
))) == 0,
383 ("Allocating used sector %ld %ld %x", cn
, cn
% N_INUSEBITS
,
384 (unsigned)pmp
->pm_inusemap
[cn
/ N_INUSEBITS
]));
385 pmp
->pm_inusemap
[cn
/ N_INUSEBITS
] |= 1U << (cn
% N_INUSEBITS
);
386 KASSERT(pmp
->pm_freeclustercount
> 0, ("usemap_alloc: too little"));
387 pmp
->pm_freeclustercount
--;
388 pmp
->pm_flags
|= MSDOSFS_FSIMOD
;
392 usemap_free(struct msdosfsmount
*pmp
, u_long cn
)
394 MSDOSFS_ASSERT_MP_LOCKED(pmp
);
396 KASSERT(cn
<= pmp
->pm_maxcluster
, ("cn too large %lu %lu", cn
,
397 pmp
->pm_maxcluster
));
398 KASSERT((pmp
->pm_flags
& MSDOSFSMNT_RONLY
) == 0,
399 ("usemap_free on ro msdosfs mount"));
400 if ((pmp
->pm_inusemap
[cn
/ N_INUSEBITS
] &
401 (1U << (cn
% N_INUSEBITS
))) == 0) {
402 kprintf("%s: Freeing unused sector %ld %ld %x\n",
403 pmp
->pm_mountp
->mnt_stat
.f_mntonname
, cn
, cn
% N_INUSEBITS
,
404 (unsigned)pmp
->pm_inusemap
[cn
/ N_INUSEBITS
]);
407 pmp
->pm_freeclustercount
++;
408 pmp
->pm_flags
|= MSDOSFS_FSIMOD
;
409 pmp
->pm_inusemap
[cn
/ N_INUSEBITS
] &= ~(1U << (cn
% N_INUSEBITS
));
414 clusterfree(struct msdosfsmount
*pmp
, u_long cluster
)
419 error
= fatentry(FAT_GET_AND_SET
, pmp
, cluster
, &oldcn
, MSDOSFSFREE
);
423 * If the cluster was successfully marked free, then update
424 * the count of free clusters, and turn off the "allocated"
425 * bit in the "in use" cluster bit map.
427 MSDOSFS_LOCK_MP(pmp
);
428 error
= usemap_free(pmp
, cluster
);
429 MSDOSFS_UNLOCK_MP(pmp
);
433 * Get or Set or 'Get and Set' the cluster'th entry in the FAT.
435 * function - whether to get or set a FAT entry
436 * pmp - address of the msdosfsmount structure for the filesystem
437 * whose FAT is to be manipulated.
438 * cn - which cluster is of interest
439 * oldcontents - address of a word that is to receive the contents of the
440 * cluster'th entry if this is a get function
441 * newcontents - the new value to be written into the cluster'th element of
442 * the FAT if this is a set function.
444 * This function can also be used to free a cluster by setting the FAT entry
445 * for a cluster to 0.
447 * All copies of the FAT are updated if this is a set function. NOTE: If
448 * fatentry() marks a cluster as free it does not update the inusemap in
449 * the msdosfsmount structure. This is left to the caller.
452 fatentry(int function
, struct msdosfsmount
*pmp
, u_long cn
, u_long
*oldcontents
,
457 u_long bn
, bo
, bsize
, byteoffset
;
460 mprintf("fatentry(func %d, pmp %p, clust %lu, oldcon %p, newcon %lx)\n",
461 function
, pmp
, cn
, oldcontents
, newcontents
);
465 * Be sure they asked us to do something.
467 if ((function
& (FAT_SET
| FAT_GET
)) == 0) {
468 kprintf("fatentry(): function code doesn't specify get or set\n");
473 * If they asked us to return a cluster number but didn't tell us
474 * where to put it, give them an error.
476 if ((function
& FAT_GET
) && oldcontents
== NULL
) {
477 kprintf("fatentry(): get function with no place to put result\n");
483 * Be sure the requested cluster is in the filesystem.
485 if (cn
< CLUST_FIRST
|| cn
> pmp
->pm_maxcluster
)
488 byteoffset
= FATOFS(pmp
, cn
);
489 fatblock(pmp
, byteoffset
, &bn
, &bsize
, &bo
);
490 error
= bread(pmp
->pm_devvp
, de_bn2doff(pmp
, bn
), bsize
, &bp
);
496 if (function
& FAT_GET
) {
498 readcn
= getulong(bp
->b_data
+ bo
);
500 readcn
= getushort(bp
->b_data
+ bo
);
501 if (FAT12(pmp
) & (cn
& 1))
503 readcn
&= pmp
->pm_fatmask
;
504 /* map reserved FAT entries to same values for all FATs */
505 if ((readcn
| ~pmp
->pm_fatmask
) >= CLUST_RSRVD
)
506 readcn
|= ~pmp
->pm_fatmask
;
507 *oldcontents
= readcn
;
509 if (function
& FAT_SET
) {
510 switch (pmp
->pm_fatmask
) {
512 readcn
= getushort(bp
->b_data
+ bo
);
515 readcn
|= newcontents
<< 4;
518 readcn
|= newcontents
& 0xfff;
520 putushort(bp
->b_data
+ bo
, readcn
);
523 putushort(bp
->b_data
+ bo
, newcontents
);
527 * According to spec we have to retain the
528 * high order bits of the FAT entry.
530 readcn
= getulong(bp
->b_data
+ bo
);
531 readcn
&= ~FAT32_MASK
;
532 readcn
|= newcontents
& FAT32_MASK
;
533 putulong(bp
->b_data
+ bo
, readcn
);
536 updatefats(pmp
, bp
, bn
);
546 * Update a contiguous cluster chain
549 * start - first cluster of chain
550 * count - number of clusters in chain
551 * fillwith - what to write into FAT entry of last cluster
554 fatchain(struct msdosfsmount
*pmp
, u_long start
, u_long count
, u_long fillwith
)
557 u_long bn
, bo
, bsize
, byteoffset
, readcn
, newc
;
560 mprintf("fatchain(pmp %p, start %lu, count %lu, fillwith %lx)\n",
561 pmp
, start
, count
, fillwith
);
563 * Be sure the clusters are in the filesystem.
565 if (start
< CLUST_FIRST
|| start
+ count
- 1 > pmp
->pm_maxcluster
)
569 byteoffset
= FATOFS(pmp
, start
);
570 fatblock(pmp
, byteoffset
, &bn
, &bsize
, &bo
);
571 error
= bread(pmp
->pm_devvp
, de_bn2doff(pmp
, bn
), bsize
, &bp
);
577 start
++; /* Callers must guarantee contiguous free
579 newc
= --count
> 0 ? start
: fillwith
;
580 switch (pmp
->pm_fatmask
) {
582 readcn
= getushort(bp
->b_data
+ bo
);
585 readcn
|= newc
& 0xfff;
590 putushort(bp
->b_data
+ bo
, readcn
);
596 putushort(bp
->b_data
+ bo
, newc
);
600 readcn
= getulong(bp
->b_data
+ bo
);
601 readcn
&= ~pmp
->pm_fatmask
;
602 readcn
|= newc
& pmp
->pm_fatmask
;
603 putulong(bp
->b_data
+ bo
, readcn
);
610 updatefats(pmp
, bp
, bn
);
617 * Check the length of a free cluster chain starting at start.
620 * start - start of chain
621 * count - maximum interesting length
624 chainlength(struct msdosfsmount
*pmp
, u_long start
, u_long count
)
630 MSDOSFS_ASSERT_MP_LOCKED(pmp
);
632 if (start
> pmp
->pm_maxcluster
)
634 max_idx
= pmp
->pm_maxcluster
/ N_INUSEBITS
;
635 idx
= start
/ N_INUSEBITS
;
636 start
%= N_INUSEBITS
;
637 map
= pmp
->pm_inusemap
[idx
];
638 map
&= ~((1U << start
) - 1);
640 len
= ffs(map
) - 1 - start
;
641 len
= MIN(len
, count
);
642 if (start
+ len
> pmp
->pm_maxcluster
)
643 len
= pmp
->pm_maxcluster
- start
+ 1;
646 len
= N_INUSEBITS
- start
;
649 if (start
+ len
> pmp
->pm_maxcluster
)
650 len
= pmp
->pm_maxcluster
- start
+ 1;
653 while (++idx
<= max_idx
) {
656 map
= pmp
->pm_inusemap
[idx
];
663 len
= MIN(len
, count
);
664 if (start
+ len
> pmp
->pm_maxcluster
)
665 len
= pmp
->pm_maxcluster
- start
+ 1;
670 * Allocate contigous free clusters.
673 * start - start of cluster chain.
674 * count - number of clusters to allocate.
675 * fillwith - put this value into the FAT entry for the
676 * last allocated cluster.
677 * retcluster - put the first allocated cluster's number here.
678 * got - how many clusters were actually allocated.
681 chainalloc(struct msdosfsmount
*pmp
, u_long start
, u_long count
,
682 u_long fillwith
, u_long
*retcluster
, u_long
*got
)
687 MSDOSFS_ASSERT_MP_LOCKED(pmp
);
688 KASSERT((pmp
->pm_flags
& MSDOSFSMNT_RONLY
) == 0,
689 ("chainalloc on ro msdosfs mount"));
691 for (cl
= start
, n
= count
; n
-- > 0;)
692 usemap_alloc(pmp
, cl
++);
694 pmp
->pm_nxtfree
= start
+ count
;
695 if (pmp
->pm_nxtfree
> pmp
->pm_maxcluster
)
696 pmp
->pm_nxtfree
= CLUST_FIRST
;
697 pmp
->pm_flags
|= MSDOSFS_FSIMOD
;
699 error
= fatchain(pmp
, start
, count
, fillwith
);
701 for (cl
= start
, n
= count
; n
-- > 0;)
702 (void)usemap_free(pmp
, cl
++);
705 mprintf("clusteralloc(): allocated cluster chain at %lu (%lu clusters)\n",
715 * Allocate contiguous free clusters.
718 * start - preferred start of cluster chain.
719 * count - number of clusters requested.
720 * fillwith - put this value into the FAT entry for the
721 * last allocated cluster.
722 * retcluster - put the first allocated cluster's number here.
723 * got - how many clusters were actually allocated.
726 clusteralloc(struct msdosfsmount
*pmp
, u_long start
, u_long count
,
727 u_long fillwith
, u_long
*retcluster
, u_long
*got
)
731 MSDOSFS_LOCK_MP(pmp
);
732 error
= clusteralloc1(pmp
, start
, count
, fillwith
, retcluster
, got
);
733 MSDOSFS_UNLOCK_MP(pmp
);
738 clusteralloc1(struct msdosfsmount
*pmp
, u_long start
, u_long count
,
739 u_long fillwith
, u_long
*retcluster
, u_long
*got
)
742 u_long len
, newst
, foundl
, cn
, l
;
743 u_long foundcn
= 0; /* XXX: foundcn could be used unititialized */
746 MSDOSFS_ASSERT_MP_LOCKED(pmp
);
748 mprintf("clusteralloc(): find %lu clusters\n",count
);
750 if ((len
= chainlength(pmp
, start
, count
)) >= count
)
751 return (chainalloc(pmp
, start
, count
, fillwith
,
756 newst
= pmp
->pm_nxtfree
;
759 for (cn
= newst
; cn
<= pmp
->pm_maxcluster
;) {
760 idx
= cn
/ N_INUSEBITS
;
761 map
= pmp
->pm_inusemap
[idx
];
762 map
|= (1U << (cn
% N_INUSEBITS
)) - 1;
763 if (map
!= FULL_RUN
) {
764 cn
= idx
* N_INUSEBITS
+ ffs(map
^ FULL_RUN
) - 1;
765 if ((l
= chainlength(pmp
, cn
, count
)) >= count
)
766 return (chainalloc(pmp
, cn
, count
, fillwith
,
775 cn
+= N_INUSEBITS
- cn
% N_INUSEBITS
;
777 for (cn
= 0; cn
< newst
;) {
778 idx
= cn
/ N_INUSEBITS
;
779 map
= pmp
->pm_inusemap
[idx
];
780 map
|= (1U << (cn
% N_INUSEBITS
)) - 1;
781 if (map
!= FULL_RUN
) {
782 cn
= idx
* N_INUSEBITS
+ ffs(map
^ FULL_RUN
) - 1;
783 if ((l
= chainlength(pmp
, cn
, count
)) >= count
)
784 return (chainalloc(pmp
, cn
, count
, fillwith
,
793 cn
+= N_INUSEBITS
- cn
% N_INUSEBITS
;
800 return (chainalloc(pmp
, start
, len
, fillwith
, retcluster
, got
));
802 return (chainalloc(pmp
, foundcn
, foundl
, fillwith
, retcluster
,
807 * Free a chain of clusters.
809 * pmp - address of the msdosfs mount structure for the filesystem
810 * containing the cluster chain to be freed.
811 * startcluster - number of the 1st cluster in the chain of clusters to be
815 freeclusterchain(struct msdosfsmount
*pmp
, u_long cluster
)
818 struct buf
*bp
= NULL
;
819 u_long bn
, bo
, bsize
, byteoffset
;
820 u_long readcn
, lbn
= -1;
822 MSDOSFS_LOCK_MP(pmp
);
823 while (cluster
>= CLUST_FIRST
&& cluster
<= pmp
->pm_maxcluster
) {
824 byteoffset
= FATOFS(pmp
, cluster
);
825 fatblock(pmp
, byteoffset
, &bn
, &bsize
, &bo
);
828 updatefats(pmp
, bp
, lbn
);
829 error
= bread(pmp
->pm_devvp
, de_bn2doff(pmp
, bn
),
833 MSDOSFS_UNLOCK_MP(pmp
);
838 error
= usemap_free(pmp
, cluster
);
840 updatefats(pmp
, bp
, lbn
);
841 MSDOSFS_UNLOCK_MP(pmp
);
844 switch (pmp
->pm_fatmask
) {
846 readcn
= getushort(bp
->b_data
+ bo
);
848 cluster
= readcn
>> 4;
850 readcn
|= MSDOSFSFREE
<< 4;
854 readcn
|= MSDOSFSFREE
& 0xfff;
856 putushort(bp
->b_data
+ bo
, readcn
);
859 cluster
= getushort(bp
->b_data
+ bo
);
860 putushort(bp
->b_data
+ bo
, MSDOSFSFREE
);
863 cluster
= getulong(bp
->b_data
+ bo
);
864 putulong(bp
->b_data
+ bo
,
865 (MSDOSFSFREE
& FAT32_MASK
) |
866 (cluster
& ~FAT32_MASK
));
869 cluster
&= pmp
->pm_fatmask
;
870 if ((cluster
| ~pmp
->pm_fatmask
) >= CLUST_RSRVD
)
871 cluster
|= pmp
->pm_fatmask
;
874 updatefats(pmp
, bp
, bn
);
875 MSDOSFS_UNLOCK_MP(pmp
);
880 * Read in FAT blocks looking for free clusters. For every free cluster
881 * found turn off its corresponding bit in the pm_inusemap.
884 fillinusemap(struct msdosfsmount
*pmp
)
887 u_long bn
, bo
, bsize
, byteoffset
, cn
, readcn
;
890 MSDOSFS_ASSERT_MP_LOCKED(pmp
);
894 * Mark all clusters in use, we mark the free ones in the FAT scan
897 for (cn
= 0; cn
< (pmp
->pm_maxcluster
+ N_INUSEBITS
) / N_INUSEBITS
; cn
++)
898 pmp
->pm_inusemap
[cn
] = FULL_RUN
;
901 * Figure how many free clusters are in the filesystem by ripping
902 * through the FAT counting the number of entries whose content is
903 * zero. These represent free clusters.
905 pmp
->pm_freeclustercount
= 0;
906 for (cn
= 0; cn
<= pmp
->pm_maxcluster
; cn
++) {
907 byteoffset
= FATOFS(pmp
, cn
);
908 bo
= byteoffset
% pmp
->pm_fatblocksize
;
910 /* Read new FAT block */
913 fatblock(pmp
, byteoffset
, &bn
, &bsize
, NULL
);
914 error
= bread(pmp
->pm_devvp
, de_bn2doff(pmp
, bn
),
922 readcn
= getulong(bp
->b_data
+ bo
);
924 readcn
= getushort(bp
->b_data
+ bo
);
925 if (FAT12(pmp
) && (cn
& 1))
927 readcn
&= pmp
->pm_fatmask
;
930 * Check if the FAT ID matches the BPB's media descriptor and
931 * all other bits are set to 1.
933 if (cn
== 0 && readcn
!= ((pmp
->pm_fatmask
& 0xffffff00) |
934 pmp
->pm_bpb
.bpbMedia
)) {
935 mprintf("fillinusemap(): Media descriptor in BPB "
936 "does not match FAT ID\n");
939 } else if (readcn
== CLUST_FREE
) {
940 error
= usemap_free(pmp
, cn
);
950 for (cn
= pmp
->pm_maxcluster
+ 1; cn
< (pmp
->pm_maxcluster
+
951 N_INUSEBITS
) / N_INUSEBITS
; cn
++)
952 pmp
->pm_inusemap
[cn
/ N_INUSEBITS
] |= 1U << (cn
% N_INUSEBITS
);
958 * Allocate a new cluster and chain it onto the end of the file.
960 * dep - the file to extend
961 * count - number of clusters to allocate
962 * bpp - where to return the address of the buf header for the first new
964 * ncp - where to put cluster number of the first newly allocated cluster
965 * If this pointer is 0, do not return the cluster number.
968 * NOTE: This function is not responsible for turning on the DE_UPDATE bit of
969 * the de_flag field of the denode and it does not change the de_FileSize
970 * field. This is left for the caller to do.
973 extendfile(struct denode
*dep
, u_long count
, struct buf
**bpp
, u_long
*ncp
,
979 struct msdosfsmount
*pmp
= dep
->de_pmp
;
983 * Don't try to extend the root directory
985 if (dep
->de_StartCluster
== MSDOSFSROOT
986 && (dep
->de_Attributes
& ATTR_DIRECTORY
)) {
987 kprintf("extendfile(): attempt to extend root directory\n");
992 * If the "file's last cluster" cache entry is empty, and the file
993 * is not empty, then fill the cache entry by calling pcbmap().
995 if (dep
->de_fc
[FC_LASTFC
].fc_frcn
== FCE_EMPTY
&&
996 dep
->de_StartCluster
!= 0) {
997 error
= pcbmap(dep
, 0xffff, NULL
, &cn
, NULL
);
998 /* we expect it to return E2BIG */
1003 dep
->de_fc
[FC_NEXTTOLASTFC
].fc_frcn
=
1004 dep
->de_fc
[FC_LASTFC
].fc_frcn
;
1005 dep
->de_fc
[FC_NEXTTOLASTFC
].fc_fsrcn
=
1006 dep
->de_fc
[FC_LASTFC
].fc_fsrcn
;
1009 * Allocate a new cluster chain and cat onto the end of the
1010 * file. If the file is empty we make de_StartCluster point
1011 * to the new block. Note that de_StartCluster being 0 is
1012 * sufficient to be sure the file is empty since we exclude
1013 * attempts to extend the root directory above, and the root
1014 * dir is the only file with a startcluster of 0 that has
1015 * blocks allocated (sort of).
1017 if (dep
->de_StartCluster
== 0)
1020 cn
= dep
->de_fc
[FC_LASTFC
].fc_fsrcn
+ 1;
1021 error
= clusteralloc(pmp
, cn
, count
, CLUST_EOFE
, &cn
, &got
);
1028 * Give them the filesystem relative cluster number if they want
1036 if (dep
->de_StartCluster
== 0) {
1037 dep
->de_StartCluster
= cn
;
1040 error
= fatentry(FAT_SET
, pmp
,
1041 dep
->de_fc
[FC_LASTFC
].fc_fsrcn
,
1044 clusterfree(pmp
, cn
);
1047 frcn
= dep
->de_fc
[FC_LASTFC
].fc_frcn
+ 1;
1051 * Update the "last cluster of the file" entry in the
1052 * denode's FAT cache.
1054 fc_setcache(dep
, FC_LASTFC
, frcn
+ got
- 1, cn
+ got
- 1);
1056 if (flags
& DE_CLEAR
) {
1059 * Get the buf header for the new block of the file.
1061 if (dep
->de_Attributes
& ATTR_DIRECTORY
) {
1062 bp
= getblk(pmp
->pm_devvp
,
1063 de_bn2doff(pmp
, cntobn(pmp
, cn
)),
1064 pmp
->pm_bpcluster
, 0, 0);
1070 bp
= getblk(DETOV(dep
),
1071 de_cn2doff(pmp
, frcn
),
1072 pmp
->pm_bpcluster
, 0, 0);
1075 * Convert bio1 offset to file relative
1078 findcn
= de_bn2cn(pmp
,
1079 (daddr_t
)(bp
->b_bio1
.bio_offset
>>
1082 * Do the bmap now, as in msdosfs_write
1084 if (pcbmap(dep
, findcn
, &dblkno
, NULL
,
1086 bp
->b_bio2
.bio_offset
= NOOFFSET
;
1088 bp
->b_bio2
.bio_offset
= de_bn2doff(pmp
, dblkno
);
1090 if (bp
->b_bio2
.bio_offset
== NOOFFSET
)
1091 panic("extendfile: pcbmap");
1108 * Routine to mark a FAT16 or FAT32 volume as "clean" or "dirty" by
1109 * manipulating the upper bit of the FAT entry for cluster 1. Note that
1110 * this bit is not defined for FAT12 volumes, which are always assumed to
1113 * The fatentry() routine only works on cluster numbers that a file could
1114 * occupy, so it won't manipulate the entry for cluster 1. So we have to do
1115 * it here. The code was stolen from fatentry() and tailored for cluster 1.
1118 * pmp The MS-DOS volume to mark
1119 * dirty Non-zero if the volume should be marked dirty; zero if it
1120 * should be marked clean
1124 * EROFS Volume is read-only
1125 * ? (other errors from called routines)
1128 markvoldirty_upgrade(struct msdosfsmount
*pmp
, bool dirty
, bool rw_upgrade
)
1131 u_long bn
, bo
, bsize
, byteoffset
, fatval
;
1135 * FAT12 does not support a "clean" bit, so don't do anything for
1142 * Can't change the bit on a read-only filesystem, except as part of
1145 if ((pmp
->pm_flags
& MSDOSFSMNT_RONLY
) != 0 && !rw_upgrade
)
1149 * Fetch the block containing the FAT entry. It is given by the
1152 byteoffset
= FATOFS(pmp
, 1);
1153 fatblock(pmp
, byteoffset
, &bn
, &bsize
, &bo
);
1154 error
= bread(pmp
->pm_devvp
, de_bn2doff(pmp
, bn
), bsize
, &bp
);
1159 * Get the current value of the FAT entry and set/clear the relevant
1160 * bit. Dirty means clear the "clean" bit; clean means set the
1164 /* FAT32 uses bit 27. */
1165 fatval
= getulong(&bp
->b_data
[bo
]);
1167 fatval
&= 0xF7FFFFFF;
1169 fatval
|= 0x08000000;
1170 putulong(&bp
->b_data
[bo
], fatval
);
1172 /* Must be FAT16; use bit 15. */
1173 fatval
= getushort(&bp
->b_data
[bo
]);
1178 putushort(&bp
->b_data
[bo
], fatval
);
1182 * The concern here is that a devvp may be readonly, without reporting
1183 * itself as such through the usual channels. In that case, we'd like
1184 * it if attempting to mount msdosfs rw didn't panic the system.
1186 * markvoldirty is invoked as the first write on backing devvps when
1187 * either msdosfs is mounted for the first time, or a ro mount is
1190 * In either event, if a write error occurs dirtying the volume:
1191 * - No user data has been permitted to be written to cache yet.
1192 * - We can abort the high-level operation (mount, or ro->rw) safely.
1193 * - We don't derive any benefit from leaving a zombie dirty buf in
1194 * the cache that can not be cleaned or evicted.
1196 * So, mark B_INVALONERR to have bwrite() -> brelse() detect that
1197 * condition and force-invalidate our write to the block if it occurs.
1199 * PR 210316 provides more context on the discovery and diagnosis of
1200 * the problem, as well as earlier attempts to solve it.
1202 bp
->b_flags
|= B_INVALONERR
;
1204 /* Write out the modified FAT block synchronously. */
1205 return (bwrite(bp
));