2 * Copyright (c) 2000-2001,2005,2008 Silicon Graphics, Inc.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 #include "err_protos.h"
24 * Track the logical to physical block mapping for inodes.
26 * Repair only processes one inode at a given time per thread, and the
27 * block map does not have to outlive the processing of a single inode.
29 * The combination of those factors means we can use pthreads thread-local
30 * storage to store the block map, and we can re-use the allocation over
34 pthread_key_t dblkmap_key
;
35 pthread_key_t ablkmap_key
;
45 ASSERT(whichfork
== XFS_DATA_FORK
|| whichfork
== XFS_ATTR_FORK
);
50 #if (BITS_PER_LONG == 32) /* on 64-bit platforms this is never true */
51 if (nex
> BLKMAP_NEXTS_MAX
) {
53 _("Number of extents requested in blkmap_alloc (%d) overflows 32 bits.\n"
54 "If this is not a corruption, then you will need a 64 bit system\n"
55 "to repair this filesystem.\n"),
61 key
= whichfork
? ablkmap_key
: dblkmap_key
;
62 blkmap
= pthread_getspecific(key
);
63 if (!blkmap
|| blkmap
->naexts
< nex
) {
64 blkmap
= realloc(blkmap
, BLKMAP_SIZE(nex
));
66 do_warn(_("malloc failed in blkmap_alloc (%zu bytes)\n"),
70 pthread_setspecific(key
, blkmap
);
81 * If the map is a large, uncommon size (say for hundreds of thousands of
82 * extents) then free it to release the memory. This prevents us from pinning
83 * large tracts of memory due to corrupted fork values or one-off fragmented
84 * files. Otherwise we have nothing to do but keep the memory around for the
86 * When the thread is done, it should do an unconditional, final free.
95 /* consider more than 100k extents rare */
96 if (blkmap
->naexts
< 100 * 1024)
99 if (blkmap
== pthread_getspecific(dblkmap_key
))
100 pthread_setspecific(dblkmap_key
, NULL
);
102 pthread_setspecific(ablkmap_key
, NULL
);
108 blkmap_free_final(void)
112 blkmap
= pthread_getspecific(dblkmap_key
);
113 pthread_setspecific(dblkmap_key
, NULL
);
116 blkmap
= pthread_getspecific(ablkmap_key
);
117 pthread_setspecific(ablkmap_key
, NULL
);
122 * Get one entry from a block map.
129 bmap_ext_t
*ext
= blkmap
->exts
;
132 for (i
= 0; i
< blkmap
->nexts
; i
++, ext
++) {
133 if (o
>= ext
->startoff
&& o
< ext
->startoff
+ ext
->blockcount
)
134 return ext
->startblock
+ (o
- ext
->startoff
);
140 * Get a chunk of entries from a block map - only used for reading dirv2 blocks
148 bmap_ext_t
*bmpp_single
)
150 bmap_ext_t
*bmp
= NULL
;
157 * in the common case, when mp->m_dirblkfsbs == 1,
158 * avoid additional malloc/free overhead
160 bmpp_single
->startblock
= blkmap_get(blkmap
, o
);
165 for (i
= 0; i
< blkmap
->nexts
; i
++, ext
++) {
167 if (ext
->startoff
>= o
+ nb
)
169 if (ext
->startoff
+ ext
->blockcount
<= o
)
173 * if all the requested blocks are in one extent (also common),
174 * use the bmpp_single option as well
176 if (!bmp
&& o
>= ext
->startoff
&&
177 o
+ nb
<= ext
->startoff
+ ext
->blockcount
) {
178 bmpp_single
->startblock
=
179 ext
->startblock
+ (o
- ext
->startoff
);
184 * rare case - multiple extents for a single dir block
187 bmp
= malloc(nb
* sizeof(bmap_ext_t
));
189 do_error(_("blkmap_getn malloc failed (%" PRIu64
" bytes)\n"),
190 nb
* sizeof(bmap_ext_t
));
192 bmp
[nex
].startblock
= ext
->startblock
+ (o
- ext
->startoff
);
193 bmp
[nex
].blockcount
= MIN(nb
, ext
->blockcount
-
194 (bmp
[nex
].startblock
- ext
->startblock
));
195 o
+= bmp
[nex
].blockcount
;
196 nb
-= bmp
[nex
].blockcount
;
203 bmpp_single
->blockcount
= nb
;
204 bmpp_single
->startoff
= 0; /* not even used by caller! */
206 return (bmpp_single
->startblock
!= NULLFSBLOCK
) ? 1 : 0;
210 * Return the last offset in a block map.
220 ext
= blkmap
->exts
+ blkmap
->nexts
- 1;
221 return ext
->startoff
+ ext
->blockcount
;
225 * blkmap_next_off - Return next logical block offset in a block map.
226 * @blkmap: blockmap to use
227 * @o: current file logical block number
228 * @t: current extent index into blockmap (in/out)
230 * Given a logical block offset in a file, return the next mapped logical offset
231 * The map index "t" tracks the current extent number in the block map, and
232 * is updated automatically if the returned offset resides within the next
235 * If the blockmap contains no extents, or no more logical offsets are mapped,
236 * or the extent index exceeds the number of extents in the map,
237 * return NULLFILEOFF.
239 * If offset o is beyond extent index t, the first offset in the next extent
240 * after extent t will be returned.
242 * Intended to be called starting with offset 0, index 0, and iterated.
254 if (o
== NULLFILEOFF
) {
256 return blkmap
->exts
[0].startoff
;
258 if (*t
>= blkmap
->nexts
)
260 ext
= blkmap
->exts
+ *t
;
261 if (o
< ext
->startoff
+ ext
->blockcount
- 1)
263 if (*t
== blkmap
->nexts
- 1)
266 return ext
[1].startoff
;
270 * Make a block map larger.
276 pthread_key_t key
= dblkmap_key
;
277 blkmap_t
*new_blkmap
;
280 /* reduce the number of reallocations for large files */
281 if (blkmap
->naexts
< 1000)
282 new_naexts
= blkmap
->naexts
+ 4;
283 else if (blkmap
->naexts
< 10000)
284 new_naexts
= blkmap
->naexts
+ 100;
286 new_naexts
= blkmap
->naexts
+ 1000;
288 if (pthread_getspecific(key
) != blkmap
) {
290 ASSERT(pthread_getspecific(key
) == blkmap
);
293 #if (BITS_PER_LONG == 32) /* on 64-bit platforms this is never true */
294 if (new_naexts
> BLKMAP_NEXTS_MAX
) {
296 _("Number of extents requested in blkmap_grow (%d) overflows 32 bits.\n"
297 "You need a 64 bit system to repair this filesystem.\n"),
302 if (new_naexts
<= 0) {
304 _("Number of extents requested in blkmap_grow (%d) overflowed the\n"
305 "maximum number of supported extents (%d).\n"),
306 new_naexts
, BLKMAP_NEXTS_MAX
);
310 new_blkmap
= realloc(blkmap
, BLKMAP_SIZE(new_naexts
));
312 do_error(_("realloc failed in blkmap_grow\n"));
315 new_blkmap
->naexts
= new_naexts
;
316 pthread_setspecific(key
, new_blkmap
);
321 * Set an extent into a block map.
323 * If this function fails, it leaves the blkmapp untouched so the caller can
324 * handle the error and free the blkmap appropriately.
333 blkmap_t
*blkmap
= *blkmapp
;
336 if (blkmap
->nexts
== blkmap
->naexts
) {
337 blkmap
= blkmap_grow(blkmap
);
343 ASSERT(blkmap
->nexts
< blkmap
->naexts
);
345 if (blkmap
->nexts
== 0) {
351 * The most common insert pattern comes from an ascending offset order
352 * bmapbt scan. In this case, the extent being added will end up at the
353 * end of the array. Hence do a reverse order search for the insertion
354 * point so we don't needlessly scan the entire array on every
357 * Also, use "plus 1" indexing for the loop counter so when we break out
358 * of the loop we are at the correct index for insertion.
360 for (i
= blkmap
->nexts
; i
> 0; i
--) {
361 if (blkmap
->exts
[i
- 1].startoff
< o
)
365 /* make space for the new extent */
366 memmove(blkmap
->exts
+ i
+ 1,
368 sizeof(bmap_ext_t
) * (blkmap
->nexts
- i
));
371 blkmap
->exts
[i
].startoff
= o
;
372 blkmap
->exts
[i
].startblock
= b
;
373 blkmap
->exts
[i
].blockcount
= c
;