bb_inode.c 6.1 KB

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