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