]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blame - lib/ext2fs/bb_inode.c
Merge remote-tracking branch 'josch/libarchive' into josch-libarchive
[thirdparty/e2fsprogs.git] / lib / ext2fs / bb_inode.c
CommitLineData
3839e657
TT
1/*
2 * bb_inode.c --- routines to update the bad block inode.
efc6f628 3 *
3839e657
TT
4 * WARNING: This routine modifies a lot of state in the filesystem; if
5 * this routine returns an error, the bad block inode may be in an
6 * inconsistent state.
efc6f628 7 *
21c84b71 8 * Copyright (C) 1994, 1995 Theodore Ts'o.
efc6f628 9 *
21c84b71 10 * %Begin-Header%
543547a5
TT
11 * This file may be redistributed under the terms of the GNU Library
12 * General Public License, version 2.
21c84b71 13 * %End-Header%
3839e657
TT
14 */
15
d1154eb4 16#include "config.h"
3839e657
TT
17#include <stdio.h>
18#include <string.h>
4cbe8af4 19#if HAVE_UNISTD_H
3839e657 20#include <unistd.h>
4cbe8af4 21#endif
3839e657
TT
22#include <fcntl.h>
23#include <time.h>
1d2ff46a 24#if HAVE_SYS_STAT_H
3839e657 25#include <sys/stat.h>
1d2ff46a
TT
26#endif
27#if HAVE_SYS_TYPES_H
3839e657 28#include <sys/types.h>
1d2ff46a 29#endif
3839e657 30
b5abe6fa 31#include "ext2_fs.h"
3839e657
TT
32#include "ext2fs.h"
33
34struct set_badblock_record {
21c84b71 35 ext2_badblocks_iterate bb_iter;
3839e657
TT
36 int bad_block_count;
37 blk_t *ind_blocks;
38 int max_ind_blocks;
39 int ind_blocks_size;
40 int ind_blocks_ptr;
41 char *block_buf;
42 errcode_t err;
43};
44
36a43d67 45static int set_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
03673dbb 46 e2_blkcnt_t blockcnt,
b5abe6fa
TT
47 blk_t ref_block, int ref_offset,
48 void *priv_data);
36a43d67 49static int clear_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
03673dbb 50 e2_blkcnt_t blockcnt,
21c84b71 51 blk_t ref_block, int ref_offset,
b5abe6fa 52 void *priv_data);
efc6f628 53
3839e657
TT
54/*
55 * Given a bad blocks bitmap, update the bad blocks inode to reflect
56 * the map.
57 */
21c84b71 58errcode_t ext2fs_update_bb_inode(ext2_filsys fs, ext2_badblocks_list bb_list)
3839e657
TT
59{
60 errcode_t retval;
ca8bc924 61 struct set_badblock_record rec;
3839e657 62 struct ext2_inode inode;
ca8bc924 63 time_t now;
efc6f628 64
f3db3566
TT
65 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
66
3839e657
TT
67 if (!fs->block_map)
68 return EXT2_ET_NO_BLOCK_BITMAP;
efc6f628 69
2150278f 70 memset(&rec, 0, sizeof(rec));
3839e657 71 rec.max_ind_blocks = 10;
ee01079a 72 retval = ext2fs_get_array(rec.max_ind_blocks, sizeof(blk_t),
c4e3d3f3 73 &rec.ind_blocks);
7b4e4534
TT
74 if (retval)
75 return retval;
3839e657 76 memset(rec.ind_blocks, 0, rec.max_ind_blocks * sizeof(blk_t));
c4e3d3f3 77 retval = ext2fs_get_mem(fs->blocksize, &rec.block_buf);
7b4e4534 78 if (retval)
3839e657 79 goto cleanup;
3839e657
TT
80 memset(rec.block_buf, 0, fs->blocksize);
81 rec.err = 0;
efc6f628 82
3839e657 83 /*
efc6f628 84 * First clear the old bad blocks (while saving the indirect blocks)
3839e657 85 */
21c84b71
TT
86 retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO,
87 BLOCK_FLAG_DEPTH_TRAVERSE, 0,
88 clear_bad_block_proc, &rec);
3839e657
TT
89 if (retval)
90 goto cleanup;
91 if (rec.err) {
92 retval = rec.err;
93 goto cleanup;
94 }
efc6f628 95
3839e657
TT
96 /*
97 * Now set the bad blocks!
f3db3566
TT
98 *
99 * First, mark the bad blocks as used. This prevents a bad
055866d8 100 * block from being used as an indirect block for the bad
f3db3566 101 * block inode (!).
3839e657
TT
102 */
103 if (bb_list) {
21c84b71
TT
104 retval = ext2fs_badblocks_list_iterate_begin(bb_list,
105 &rec.bb_iter);
3839e657
TT
106 if (retval)
107 goto cleanup;
21c84b71
TT
108 retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO,
109 BLOCK_FLAG_APPEND, 0,
110 set_bad_block_proc, &rec);
111 ext2fs_badblocks_list_iterate_end(rec.bb_iter);
efc6f628 112 if (retval)
3839e657
TT
113 goto cleanup;
114 if (rec.err) {
115 retval = rec.err;
116 goto cleanup;
117 }
118 }
efc6f628 119
3839e657
TT
120 /*
121 * Update the bad block inode's mod time and block count
efc6f628 122 * field.
3839e657
TT
123 */
124 retval = ext2fs_read_inode(fs, EXT2_BAD_INO, &inode);
125 if (retval)
126 goto cleanup;
efc6f628 127
ca8bc924
AD
128 now = fs->now ? fs->now : time(0);
129 ext2fs_inode_xtime_set(&inode, i_atime, now);
130 if (!ext2fs_inode_xtime_get(&inode, i_ctime))
131 ext2fs_inode_xtime_set(&inode, i_ctime, now);
132 ext2fs_inode_xtime_set(&inode, i_mtime, now);
1ca1059f 133 ext2fs_iblk_set(fs, &inode, rec.bad_block_count);
97c607b1
DW
134 retval = ext2fs_inode_size_set(fs, &inode,
135 rec.bad_block_count * fs->blocksize);
136 if (retval)
137 goto cleanup;
3839e657
TT
138
139 retval = ext2fs_write_inode(fs, EXT2_BAD_INO, &inode);
140 if (retval)
141 goto cleanup;
efc6f628 142
3839e657 143cleanup:
c4e3d3f3
TT
144 ext2fs_free_mem(&rec.ind_blocks);
145 ext2fs_free_mem(&rec.block_buf);
3839e657
TT
146 return retval;
147}
148
149/*
150 * Helper function for update_bb_inode()
151 *
152 * Clear the bad blocks in the bad block inode, while saving the
153 * indirect blocks.
154 */
4cbe8af4 155#ifdef __TURBOC__
31dbecd4 156 #pragma argsused
4cbe8af4 157#endif
36a43d67 158static int clear_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
03673dbb 159 e2_blkcnt_t blockcnt,
54434927
TT
160 blk_t ref_block EXT2FS_ATTR((unused)),
161 int ref_offset EXT2FS_ATTR((unused)),
b5abe6fa 162 void *priv_data)
3839e657
TT
163{
164 struct set_badblock_record *rec = (struct set_badblock_record *)
b5abe6fa 165 priv_data;
7b4e4534 166 errcode_t retval;
76f875da 167 unsigned long old_size;
3839e657
TT
168
169 if (!*block_nr)
170 return 0;
171
f3db3566
TT
172 /*
173 * If the block number is outrageous, clear it and ignore it.
174 */
4efbac6f 175 if (*block_nr >= ext2fs_blocks_count(fs->super) ||
f3db3566
TT
176 *block_nr < fs->super->s_first_data_block) {
177 *block_nr = 0;
178 return BLOCK_CHANGED;
179 }
180
3839e657
TT
181 if (blockcnt < 0) {
182 if (rec->ind_blocks_size >= rec->max_ind_blocks) {
76f875da 183 old_size = rec->max_ind_blocks * sizeof(blk_t);
3839e657 184 rec->max_ind_blocks += 10;
efc6f628 185 retval = ext2fs_resize_mem(old_size,
76f875da 186 rec->max_ind_blocks * sizeof(blk_t),
c4e3d3f3 187 &rec->ind_blocks);
7b4e4534 188 if (retval) {
76f875da 189 rec->max_ind_blocks -= 10;
7b4e4534 190 rec->err = retval;
3839e657
TT
191 return BLOCK_ABORT;
192 }
193 }
194 rec->ind_blocks[rec->ind_blocks_size++] = *block_nr;
195 }
196
197 /*
198 * Mark the block as unused, and update accounting information
199 */
48f23054 200 ext2fs_block_alloc_stats2(fs, *block_nr, -1);
efc6f628 201
3839e657
TT
202 *block_nr = 0;
203 return BLOCK_CHANGED;
204}
205
efc6f628 206
3839e657
TT
207/*
208 * Helper function for update_bb_inode()
209 *
210 * Set the block list in the bad block inode, using the supplied bitmap.
211 */
4cbe8af4 212#ifdef __TURBOC__
31dbecd4 213 #pragma argsused
4cbe8af4 214#endif
3839e657 215static int set_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
54434927
TT
216 e2_blkcnt_t blockcnt,
217 blk_t ref_block EXT2FS_ATTR((unused)),
218 int ref_offset EXT2FS_ATTR((unused)),
219 void *priv_data)
3839e657
TT
220{
221 struct set_badblock_record *rec = (struct set_badblock_record *)
b5abe6fa 222 priv_data;
3839e657
TT
223 errcode_t retval;
224 blk_t blk;
3839e657
TT
225
226 if (blockcnt >= 0) {
227 /*
228 * Get the next bad block.
229 */
21c84b71 230 if (!ext2fs_badblocks_list_iterate(rec->bb_iter, &blk))
3839e657
TT
231 return BLOCK_ABORT;
232 rec->bad_block_count++;
f3db3566 233 } else {
3839e657
TT
234 /*
235 * An indirect block; fetch a block from the
f3db3566
TT
236 * previously used indirect block list. The block
237 * most be not marked as used; if so, get another one.
238 * If we run out of reserved indirect blocks, allocate
239 * a new one.
3839e657 240 */
f3db3566
TT
241 retry:
242 if (rec->ind_blocks_ptr < rec->ind_blocks_size) {
243 blk = rec->ind_blocks[rec->ind_blocks_ptr++];
8f82ef98 244 if (ext2fs_test_block_bitmap2(fs->block_map, blk))
f3db3566
TT
245 goto retry;
246 } else {
247 retval = ext2fs_new_block(fs, 0, 0, &blk);
248 if (retval) {
249 rec->err = retval;
250 return BLOCK_ABORT;
251 }
3839e657 252 }
24a117ab 253 retval = io_channel_write_blk64(fs->io, blk, 1, rec->block_buf);
3839e657
TT
254 if (retval) {
255 rec->err = retval;
256 return BLOCK_ABORT;
257 }
258 }
efc6f628 259
3839e657 260 /*
f3db3566 261 * Update block counts
3839e657 262 */
48f23054 263 ext2fs_block_alloc_stats2(fs, blk, +1);
efc6f628 264
3839e657
TT
265 *block_nr = blk;
266 return BLOCK_CHANGED;
267}
268
269
270
271
272
273