1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2000-2001,2005,2008 Silicon Graphics, Inc.
8 #include "err_protos.h"
12 * Track the logical to physical block mapping for inodes.
14 * Repair only processes one inode at a given time per thread, and the
15 * block map does not have to outlive the processing of a single inode.
17 * The combination of those factors means we can use pthreads thread-local
18 * storage to store the block map, and we can re-use the allocation over
22 pthread_key_t dblkmap_key
;
23 pthread_key_t ablkmap_key
;
33 ASSERT(whichfork
== XFS_DATA_FORK
|| whichfork
== XFS_ATTR_FORK
);
38 #if (BITS_PER_LONG == 32) /* on 64-bit platforms this is never true */
39 if (nex
> BLKMAP_NEXTS_MAX
) {
41 _("Number of extents requested in blkmap_alloc (%d) overflows 32 bits.\n"
42 "If this is not a corruption, then you will need a 64 bit system\n"
43 "to repair this filesystem.\n"),
49 key
= whichfork
? ablkmap_key
: dblkmap_key
;
50 blkmap
= pthread_getspecific(key
);
51 if (!blkmap
|| blkmap
->naexts
< nex
) {
52 blkmap
= realloc(blkmap
, BLKMAP_SIZE(nex
));
54 do_warn(_("malloc failed in blkmap_alloc (%zu bytes)\n"),
58 pthread_setspecific(key
, blkmap
);
69 * If the map is a large, uncommon size (say for hundreds of thousands of
70 * extents) then free it to release the memory. This prevents us from pinning
71 * large tracts of memory due to corrupted fork values or one-off fragmented
72 * files. Otherwise we have nothing to do but keep the memory around for the
74 * When the thread is done, it should do an unconditional, final free.
83 /* consider more than 100k extents rare */
84 if (blkmap
->naexts
< 100 * 1024)
87 if (blkmap
== pthread_getspecific(dblkmap_key
))
88 pthread_setspecific(dblkmap_key
, NULL
);
90 pthread_setspecific(ablkmap_key
, NULL
);
96 blkmap_free_final(void)
100 blkmap
= pthread_getspecific(dblkmap_key
);
101 pthread_setspecific(dblkmap_key
, NULL
);
104 blkmap
= pthread_getspecific(ablkmap_key
);
105 pthread_setspecific(ablkmap_key
, NULL
);
110 * Get one entry from a block map.
117 bmap_ext_t
*ext
= blkmap
->exts
;
120 for (i
= 0; i
< blkmap
->nexts
; i
++, ext
++) {
121 if (o
>= ext
->startoff
&& o
< ext
->startoff
+ ext
->blockcount
)
122 return ext
->startblock
+ (o
- ext
->startoff
);
128 * Get a chunk of entries from a block map - only used for reading dirv2 blocks
136 bmap_ext_t
*bmpp_single
)
138 bmap_ext_t
*bmp
= NULL
;
145 * in the common case, when mp->m_dirblkfsbs == 1,
146 * avoid additional malloc/free overhead
148 bmpp_single
->startblock
= blkmap_get(blkmap
, o
);
153 for (i
= 0; i
< blkmap
->nexts
; i
++, ext
++) {
155 if (ext
->startoff
>= o
+ nb
)
157 if (ext
->startoff
+ ext
->blockcount
<= o
)
161 * if all the requested blocks are in one extent (also common),
162 * use the bmpp_single option as well
164 if (!bmp
&& o
>= ext
->startoff
&&
165 o
+ nb
<= ext
->startoff
+ ext
->blockcount
) {
166 bmpp_single
->startblock
=
167 ext
->startblock
+ (o
- ext
->startoff
);
172 * rare case - multiple extents for a single dir block
175 bmp
= malloc(nb
* sizeof(bmap_ext_t
));
177 do_error(_("blkmap_getn malloc failed (%" PRIu64
" bytes)\n"),
178 nb
* sizeof(bmap_ext_t
));
180 bmp
[nex
].startblock
= ext
->startblock
+ (o
- ext
->startoff
);
181 bmp
[nex
].blockcount
= min(nb
, ext
->blockcount
-
182 (bmp
[nex
].startblock
- ext
->startblock
));
183 o
+= bmp
[nex
].blockcount
;
184 nb
-= bmp
[nex
].blockcount
;
191 bmpp_single
->blockcount
= nb
;
192 bmpp_single
->startoff
= 0; /* not even used by caller! */
194 return (bmpp_single
->startblock
!= NULLFSBLOCK
) ? 1 : 0;
198 * Return the last offset in a block map.
208 ext
= blkmap
->exts
+ blkmap
->nexts
- 1;
209 return ext
->startoff
+ ext
->blockcount
;
213 * blkmap_next_off - Return next logical block offset in a block map.
214 * @blkmap: blockmap to use
215 * @o: current file logical block number
216 * @t: current extent index into blockmap (in/out)
218 * Given a logical block offset in a file, return the next mapped logical offset
219 * The map index "t" tracks the current extent number in the block map, and
220 * is updated automatically if the returned offset resides within the next
223 * If the blockmap contains no extents, or no more logical offsets are mapped,
224 * or the extent index exceeds the number of extents in the map,
225 * return NULLFILEOFF.
227 * If offset o is beyond extent index t, the first offset in the next extent
228 * after extent t will be returned.
230 * Intended to be called starting with offset 0, index 0, and iterated.
242 if (o
== NULLFILEOFF
) {
244 return blkmap
->exts
[0].startoff
;
246 if (*t
>= blkmap
->nexts
)
248 ext
= blkmap
->exts
+ *t
;
249 if (o
< ext
->startoff
+ ext
->blockcount
- 1)
251 if (*t
== blkmap
->nexts
- 1)
254 return ext
[1].startoff
;
258 * Make a block map larger.
264 pthread_key_t key
= dblkmap_key
;
265 blkmap_t
*new_blkmap
;
268 /* reduce the number of reallocations for large files */
269 if (blkmap
->naexts
< 1000)
270 new_naexts
= blkmap
->naexts
+ 4;
271 else if (blkmap
->naexts
< 10000)
272 new_naexts
= blkmap
->naexts
+ 100;
274 new_naexts
= blkmap
->naexts
+ 1000;
276 if (pthread_getspecific(key
) != blkmap
) {
278 ASSERT(pthread_getspecific(key
) == blkmap
);
281 #if (BITS_PER_LONG == 32) /* on 64-bit platforms this is never true */
282 if (new_naexts
> BLKMAP_NEXTS_MAX
) {
284 _("Number of extents requested in blkmap_grow (%d) overflows 32 bits.\n"
285 "You need a 64 bit system to repair this filesystem.\n"),
290 if (new_naexts
<= 0) {
292 _("Number of extents requested in blkmap_grow (%d) overflowed the\n"
293 "maximum number of supported extents (%d).\n"),
294 new_naexts
, BLKMAP_NEXTS_MAX
);
298 new_blkmap
= realloc(blkmap
, BLKMAP_SIZE(new_naexts
));
300 do_error(_("realloc failed in blkmap_grow\n"));
303 new_blkmap
->naexts
= new_naexts
;
304 pthread_setspecific(key
, new_blkmap
);
309 * Set an extent into a block map.
311 * If this function fails, it leaves the blkmapp untouched so the caller can
312 * handle the error and free the blkmap appropriately.
321 blkmap_t
*blkmap
= *blkmapp
;
324 if (blkmap
->nexts
== blkmap
->naexts
) {
325 blkmap
= blkmap_grow(blkmap
);
331 ASSERT(blkmap
->nexts
< blkmap
->naexts
);
333 if (blkmap
->nexts
== 0) {
339 * The most common insert pattern comes from an ascending offset order
340 * bmapbt scan. In this case, the extent being added will end up at the
341 * end of the array. Hence do a reverse order search for the insertion
342 * point so we don't needlessly scan the entire array on every
345 * Also, use "plus 1" indexing for the loop counter so when we break out
346 * of the loop we are at the correct index for insertion.
348 for (i
= blkmap
->nexts
; i
> 0; i
--) {
349 if (blkmap
->exts
[i
- 1].startoff
< o
)
353 /* make space for the new extent */
354 memmove(blkmap
->exts
+ i
+ 1,
356 sizeof(bmap_ext_t
) * (blkmap
->nexts
- i
));
359 blkmap
->exts
[i
].startoff
= o
;
360 blkmap
->exts
[i
].startblock
= b
;
361 blkmap
->exts
[i
].blockcount
= c
;