home *** CD-ROM | disk | FTP | other *** search
/ PC-Online 1998 February / PCOnline_02_1998.iso / filesbbs / win95 / ext2tool.exe / EXT2FS / BB_INODE.C < prev    next >
C/C++ Source or Header  |  1995-05-10  |  6KB  |  254 lines

  1. /*
  2.  * bb_inode.c --- routines to update the bad block inode.
  3.  * 
  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.
  7.  * 
  8.  * Copyright (C) 1994 Theodore Ts'o.  This file may be redistributed
  9.  * under the terms of the GNU Public License.
  10.  */
  11.  
  12. #include <stdio.h>
  13. #include <string.h>
  14. #include <unistd.h>
  15. #include <stdlib.h>
  16. #include <fcntl.h>
  17. #include <time.h>
  18. #include <errno.h>
  19. #include <sys/stat.h>
  20. #include <sys/types.h>
  21.  
  22. #include <linux/ext2_fs.h>
  23.  
  24. #include "ext2fs.h"
  25.  
  26. struct set_badblock_record {
  27.     badblocks_iterate    bb_iter;
  28.     int        bad_block_count;
  29.     blk_t        *ind_blocks;
  30.     int        max_ind_blocks;
  31.     int        ind_blocks_size;
  32.     int        ind_blocks_ptr;
  33.     char        *block_buf;
  34.     errcode_t    err;
  35. };
  36.  
  37. static int set_bad_block_proc(ext2_filsys fs, blk_t *block_nr, int blockcnt,
  38.                   void *private);
  39. static int clear_bad_block_proc(ext2_filsys fs, blk_t *block_nr, int blockcnt,
  40.                  void *private);
  41.     
  42. /*
  43.  * Given a bad blocks bitmap, update the bad blocks inode to reflect
  44.  * the map.
  45.  */
  46. errcode_t ext2fs_update_bb_inode(ext2_filsys fs, badblocks_list bb_list)
  47. {
  48.     errcode_t            retval;
  49.     struct set_badblock_record     rec;
  50.     struct ext2_inode        inode;
  51.     blk_t                blk;
  52.     
  53.     EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
  54.  
  55.     if (!fs->block_map)
  56.         return EXT2_ET_NO_BLOCK_BITMAP;
  57.     
  58.     rec.bad_block_count = 0;
  59.     rec.ind_blocks_size = rec.ind_blocks_ptr = 0;
  60.     rec.max_ind_blocks = 10;
  61.     rec.ind_blocks = malloc(rec.max_ind_blocks * sizeof(blk_t));
  62.     if (!rec.ind_blocks)
  63.         return ENOMEM;
  64.     memset(rec.ind_blocks, 0, rec.max_ind_blocks * sizeof(blk_t));
  65.     rec.block_buf = malloc(fs->blocksize);
  66.     if (!rec.block_buf) {
  67.         retval = ENOMEM;
  68.         goto cleanup;
  69.     }
  70.     memset(rec.block_buf, 0, fs->blocksize);
  71.     rec.err = 0;
  72.     
  73.     /*
  74.      * First clear the old bad blocks (while saving the indirect blocks) 
  75.      */
  76.     retval = ext2fs_block_iterate(fs, EXT2_BAD_INO,
  77.                       BLOCK_FLAG_DEPTH_TRAVERSE, 0,
  78.                       clear_bad_block_proc, &rec);
  79.     if (retval)
  80.         goto cleanup;
  81.     if (rec.err) {
  82.         retval = rec.err;
  83.         goto cleanup;
  84.     }
  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 = badblocks_list_iterate_begin(bb_list, &rec.bb_iter);
  95.         if (retval)
  96.             goto cleanup;
  97.         while (badblocks_list_iterate(rec.bb_iter, &blk)) {
  98.             ext2fs_mark_block_bitmap(fs->block_map, blk); 
  99.         }
  100.         badblocks_list_iterate_end(rec.bb_iter);
  101.         ext2fs_mark_bb_dirty(fs);
  102.         
  103.         retval = badblocks_list_iterate_begin(bb_list, &rec.bb_iter);
  104.         if (retval)
  105.             goto cleanup;
  106.         retval = ext2fs_block_iterate(fs, EXT2_BAD_INO,
  107.                           BLOCK_FLAG_APPEND, 0,
  108.                           set_bad_block_proc, &rec);
  109.         badblocks_list_iterate_end(rec.bb_iter);
  110.         if (retval) 
  111.             goto cleanup;
  112.         if (rec.err) {
  113.             retval = rec.err;
  114.             goto cleanup;
  115.         }
  116.     }
  117.     
  118.     /*
  119.      * Update the bad block inode's mod time and block count
  120.      * field.  
  121.      */
  122.     retval = ext2fs_read_inode(fs, EXT2_BAD_INO, &inode);
  123.     if (retval)
  124.         goto cleanup;
  125.     
  126.     inode.i_atime = inode.i_mtime = time(0);
  127.     if (!inode.i_ctime)
  128.         inode.i_ctime = time(0);
  129.     inode.i_blocks = rec.bad_block_count * (fs->blocksize / 512);
  130.     inode.i_size = rec.bad_block_count * fs->blocksize;
  131.  
  132.     retval = ext2fs_write_inode(fs, EXT2_BAD_INO, &inode);
  133.     if (retval)
  134.         goto cleanup;
  135.     
  136. cleanup:
  137.     free(rec.ind_blocks);
  138.     free(rec.block_buf);
  139.     return retval;
  140. }
  141.  
  142. /*
  143.  * Helper function for update_bb_inode()
  144.  *
  145.  * Clear the bad blocks in the bad block inode, while saving the
  146.  * indirect blocks.
  147.  */
  148. static int clear_bad_block_proc(ext2_filsys fs, blk_t *block_nr, int blockcnt,
  149.                 void *private)
  150. {
  151.     struct set_badblock_record *rec = (struct set_badblock_record *)
  152.         private;
  153.     int    group;
  154.  
  155.     if (!*block_nr)
  156.         return 0;
  157.  
  158.     if (blockcnt < 0) {
  159.         if (rec->ind_blocks_size >= rec->max_ind_blocks) {
  160.             rec->max_ind_blocks += 10;
  161.             rec->ind_blocks = realloc(rec->ind_blocks,
  162.                           rec->max_ind_blocks *
  163.                           sizeof(blk_t));
  164.             if (!rec->ind_blocks) {
  165.                 rec->err = ENOMEM;
  166.                 return BLOCK_ABORT;
  167.             }
  168.         }
  169.         rec->ind_blocks[rec->ind_blocks_size++] = *block_nr;
  170.     }
  171.  
  172.     /*
  173.      * Mark the block as unused, and update accounting information
  174.      */
  175.     ext2fs_unmark_block_bitmap(fs->block_map, *block_nr);
  176.     ext2fs_mark_bb_dirty(fs);
  177.     group = ext2fs_group_of_blk(fs, *block_nr);
  178.     fs->group_desc[group].bg_free_blocks_count++;
  179.     fs->super->s_free_blocks_count++;
  180.     ext2fs_mark_super_dirty(fs);
  181.     
  182.     *block_nr = 0;
  183.     return BLOCK_CHANGED;
  184. }
  185.  
  186.     
  187. /*
  188.  * Helper function for update_bb_inode()
  189.  *
  190.  * Set the block list in the bad block inode, using the supplied bitmap.
  191.  */
  192. static int set_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
  193.              int blockcnt, void *private)
  194. {
  195.     struct set_badblock_record *rec = (struct set_badblock_record *)
  196.         private;
  197.     errcode_t    retval;
  198.     blk_t        blk;
  199.     int        group;
  200.  
  201.     if (blockcnt >= 0) {
  202.         /*
  203.          * Get the next bad block.
  204.          */
  205.         if (!badblocks_list_iterate(rec->bb_iter, &blk))
  206.             return BLOCK_ABORT;
  207.         rec->bad_block_count++;
  208.     } else {
  209.         /*
  210.          * An indirect block; fetch a block from the
  211.          * previously used indirect block list.  The block
  212.          * most be not marked as used; if so, get another one.
  213.          * If we run out of reserved indirect blocks, allocate
  214.          * a new one.
  215.          */
  216.     retry:
  217.         if (rec->ind_blocks_ptr < rec->ind_blocks_size) {
  218.             blk = rec->ind_blocks[rec->ind_blocks_ptr++];
  219.             if (ext2fs_test_block_bitmap(fs->block_map, blk))
  220.                 goto retry;
  221.         } else {
  222.             retval = ext2fs_new_block(fs, 0, 0, &blk);
  223.             if (retval) {
  224.                 rec->err = retval;
  225.                 return BLOCK_ABORT;
  226.             }
  227.         }
  228.         retval = io_channel_write_blk(fs->io, blk, 1, rec->block_buf);
  229.         if (retval) {
  230.             rec->err = retval;
  231.             return BLOCK_ABORT;
  232.         }
  233.         ext2fs_mark_block_bitmap(fs->block_map, blk); 
  234.         ext2fs_mark_bb_dirty(fs);
  235.     }
  236.     
  237.     /*
  238.      * Update block counts
  239.      */
  240.     group = ext2fs_group_of_blk(fs, blk);
  241.     fs->group_desc[group].bg_free_blocks_count--;
  242.     fs->super->s_free_blocks_count--;
  243.     ext2fs_mark_super_dirty(fs);
  244.     
  245.     *block_nr = blk;
  246.     return BLOCK_CHANGED;
  247. }
  248.  
  249.  
  250.  
  251.  
  252.  
  253.  
  254.