bb_inode.c revision 8f82ef9860339039b54a324be137fbc09b762358
12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/*
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * bb_inode.c --- routines to update the bad block inode.
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * WARNING: This routine modifies a lot of state in the filesystem; if
5a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch * this routine returns an error, the bad block inode may be in an
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * inconsistent state.
7b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) *
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Copyright (C) 1994, 1995 Theodore Ts'o.
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * %Begin-Header%
1190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * This file may be redistributed under the terms of the GNU Public
12ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * License.
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * %End-Header%
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include <stdio.h>
177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include <string.h>
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if HAVE_UNISTD_H
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <unistd.h>
20a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#endif
21a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include <fcntl.h>
22a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include <time.h>
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if HAVE_SYS_STAT_H
243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include <sys/stat.h>
253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#endif
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if HAVE_SYS_TYPES_H
27effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include <sys/types.h>
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ext2_fs.h"
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ext2fs.h"
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)struct set_badblock_record {
347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	ext2_badblocks_iterate	bb_iter;
357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	int		bad_block_count;
367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	blk_t		*ind_blocks;
37a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch	int		max_ind_blocks;
38ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	int		ind_blocks_size;
393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)	int		ind_blocks_ptr;
407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	char		*block_buf;
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	errcode_t	err;
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)static int set_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)			      e2_blkcnt_t blockcnt,
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)			      blk_t ref_block, int ref_offset,
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)			      void *priv_data);
487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)static int clear_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)				e2_blkcnt_t blockcnt,
50a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)				blk_t ref_block, int ref_offset,
51f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)				void *priv_data);
52f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
53f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)/*
54f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * Given a bad blocks bitmap, update the bad blocks inode to reflect
55f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * the map.
56f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) */
57a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)errcode_t ext2fs_update_bb_inode(ext2_filsys fs, ext2_badblocks_list bb_list)
58a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles){
59a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)	errcode_t			retval;
607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	struct set_badblock_record 	rec;
617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	struct ext2_inode		inode;
627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)	if (!fs->block_map)
66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)		return EXT2_ET_NO_BLOCK_BITMAP;
6768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
6868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	rec.bad_block_count = 0;
6968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	rec.ind_blocks_size = rec.ind_blocks_ptr = 0;
7068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	rec.max_ind_blocks = 10;
7168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	retval = ext2fs_get_array(rec.max_ind_blocks, sizeof(blk_t),
7268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)				&rec.ind_blocks);
734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)	if (retval)
744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)		return retval;
754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)	memset(rec.ind_blocks, 0, rec.max_ind_blocks * sizeof(blk_t));
764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)	retval = ext2fs_get_mem(fs->blocksize, &rec.block_buf);
774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)	if (retval)
784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)		goto cleanup;
794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)	memset(rec.block_buf, 0, fs->blocksize);
804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)	rec.err = 0;
814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	/*
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	 * First clear the old bad blocks (while saving the indirect blocks)
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	 */
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO,
8668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)				       BLOCK_FLAG_DEPTH_TRAVERSE, 0,
8768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)				       clear_bad_block_proc, &rec);
887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	if (retval)
897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)		goto cleanup;
907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch	if (rec.err) {
917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch		retval = rec.err;
927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch		goto cleanup;
937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch	}
947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	/*
967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	 * Now set the bad blocks!
971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)	 *
987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	 * First, mark the bad blocks as used.  This prevents a bad
997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	 * block from being used as an indirecto block for the bad
100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)	 * block inode (!).
101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)	 */
102a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)	if (bb_list) {
1037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)		retval = ext2fs_badblocks_list_iterate_begin(bb_list,
1047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)							     &rec.bb_iter);
1058bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)		if (retval)
1068bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)			goto cleanup;
1078bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)		retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO,
1088bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)					       BLOCK_FLAG_APPEND, 0,
1097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)					       set_bad_block_proc, &rec);
1104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)		ext2fs_badblocks_list_iterate_end(rec.bb_iter);
111f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)		if (retval)
1124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)			goto cleanup;
1134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)		if (rec.err) {
1144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)			retval = rec.err;
1158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)			goto cleanup;
1168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)		}
1178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)	}
1188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)	/*
1204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)	 * Update the bad block inode's mod time and block count
1217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	 * field.
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	 */
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	retval = ext2fs_read_inode(fs, EXT2_BAD_INO, &inode);
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	if (retval)
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)		goto cleanup;
1267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	inode.i_atime = inode.i_mtime = fs->now ? fs->now : time(0);
1287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	if (!inode.i_ctime)
1297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)		inode.i_ctime = fs->now ? fs->now : time(0);
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	ext2fs_iblk_set(fs, &inode, rec.bad_block_count);
131424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)	inode.i_size = rec.bad_block_count * fs->blocksize;
132ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
133ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	retval = ext2fs_write_inode(fs, EXT2_BAD_INO, &inode);
13458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)	if (retval)
135424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)		goto cleanup;
1367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
137424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)cleanup:
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	ext2fs_free_mem(&rec.ind_blocks);
1397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	ext2fs_free_mem(&rec.block_buf);
1404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)	return retval;
1414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)/*
1447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) * Helper function for update_bb_inode()
1451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) *
1461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) * Clear the bad blocks in the bad block inode, while saving the
1471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) * indirect blocks.
1481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) */
1497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#ifdef __TURBOC__
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) #pragma argsused
1511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#endif
1521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)static int clear_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
1531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)				e2_blkcnt_t blockcnt,
1541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)				blk_t ref_block EXT2FS_ATTR((unused)),
1554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)				int ref_offset EXT2FS_ATTR((unused)),
1561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)				void *priv_data)
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){
1581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)	struct set_badblock_record *rec = (struct set_badblock_record *)
1591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)		priv_data;
1601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)	errcode_t	retval;
1611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)	unsigned long 	old_size;
1627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	if (!*block_nr)
1647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)		return 0;
165eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	/*
1673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)	 * If the block number is outrageous, clear it and ignore it.
1681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)	 */
1693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)	if (*block_nr >= fs->super->s_blocks_count ||
1703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)	    *block_nr < fs->super->s_first_data_block) {
1713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)		*block_nr = 0;
1723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)		return BLOCK_CHANGED;
173eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	}
1741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)	if (blockcnt < 0) {
1761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)		if (rec->ind_blocks_size >= rec->max_ind_blocks) {
1773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)			old_size = rec->max_ind_blocks * sizeof(blk_t);
1783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)			rec->max_ind_blocks += 10;
1791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)			retval = ext2fs_resize_mem(old_size,
1801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)				   rec->max_ind_blocks * sizeof(blk_t),
181a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)				   &rec->ind_blocks);
182c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch			if (retval) {
1831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)				rec->max_ind_blocks -= 10;
1841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)				rec->err = retval;
1851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)				return BLOCK_ABORT;
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)			}
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)		}
188a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)		rec->ind_blocks[rec->ind_blocks_size++] = *block_nr;
189a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)	}
1903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	/*
1927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	 * Mark the block as unused, and update accounting information
193a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)	 */
194a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)	ext2fs_block_alloc_stats(fs, *block_nr, -1);
195a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
196a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)	*block_nr = 0;
197ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	return BLOCK_CHANGED;
198a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
199a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
200a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
201a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)/*
202ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * Helper function for update_bb_inode()
203ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch *
204ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch * Set the block list in the bad block inode, using the supplied bitmap.
205ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch */
206ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#ifdef __TURBOC__
207ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch #pragma argsused
208ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#endif
20958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)static int set_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
21058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)			      e2_blkcnt_t blockcnt,
21158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)			      blk_t ref_block EXT2FS_ATTR((unused)),
21258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)			      int ref_offset EXT2FS_ATTR((unused)),
21358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)			      void *priv_data)
21458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles){
21558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)	struct set_badblock_record *rec = (struct set_badblock_record *)
21658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)		priv_data;
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	errcode_t	retval;
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	blk_t		blk;
219a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	if (blockcnt >= 0) {
221a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch		/*
2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)		 * Get the next bad block.
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)		 */
224a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)		if (!ext2fs_badblocks_list_iterate(rec->bb_iter, &blk))
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)			return BLOCK_ABORT;
2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)		rec->bad_block_count++;
2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	} else {
2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)		/*
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)		 * An indirect block; fetch a block from the
230a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch		 * previously used indirect block list.  The block
2313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)		 * most be not marked as used; if so, get another one.
2323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)		 * If we run out of reserved indirect blocks, allocate
233a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch		 * a new one.
234a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch		 */
235424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)	retry:
236424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)		if (rec->ind_blocks_ptr < rec->ind_blocks_size) {
237a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch			blk = rec->ind_blocks[rec->ind_blocks_ptr++];
238a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch			if (ext2fs_test_block_bitmap2(fs->block_map, blk))
2393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)				goto retry;
240424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)		} else {
241a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch			retval = ext2fs_new_block(fs, 0, 0, &blk);
242a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch			if (retval) {
243a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch				rec->err = retval;
2448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)				return BLOCK_ABORT;
2458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)			}
2468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)		}
2478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)		retval = io_channel_write_blk(fs->io, blk, 1, rec->block_buf);
2488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)		if (retval) {
2498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)			rec->err = retval;
250a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch			return BLOCK_ABORT;
251424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)		}
252a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch	}
253a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	/*
255a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch	 * Update block counts
256a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch	 */
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	ext2fs_block_alloc_stats(fs, blk, +1);
2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	*block_nr = blk;
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	return BLOCK_CHANGED;
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
264a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
265a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
266a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
267a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
268a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch