bmove.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * bmove.c --- Move blocks around to make way for a particular
  4. * filesystem structure.
  5. *
  6. * Copyright (C) 1997 Theodore Ts'o. This file may be redistributed
  7. * under the terms of the GNU Public License.
  8. */
  9. #include <stdio.h>
  10. #include <string.h>
  11. #if HAVE_UNISTD_H
  12. #include <unistd.h>
  13. #endif
  14. #if HAVE_SYS_TYPES_H
  15. #include <sys/types.h>
  16. #endif
  17. #include "ext2_fs.h"
  18. #include "ext2fsP.h"
  19. struct process_block_struct {
  20. ext2_ino_t ino;
  21. struct ext2_inode * inode;
  22. ext2fs_block_bitmap reserve;
  23. ext2fs_block_bitmap alloc_map;
  24. errcode_t error;
  25. char *buf;
  26. int add_dir;
  27. int flags;
  28. };
  29. static int process_block(ext2_filsys fs, blk_t *block_nr,
  30. e2_blkcnt_t blockcnt, blk_t ref_block,
  31. int ref_offset, void *priv_data)
  32. {
  33. struct process_block_struct *pb;
  34. errcode_t retval;
  35. int ret;
  36. blk_t block, orig;
  37. pb = (struct process_block_struct *) priv_data;
  38. block = orig = *block_nr;
  39. ret = 0;
  40. /*
  41. * Let's see if this is one which we need to relocate
  42. */
  43. if (ext2fs_test_block_bitmap(pb->reserve, block)) {
  44. do {
  45. if (++block >= fs->super->s_blocks_count)
  46. block = fs->super->s_first_data_block;
  47. if (block == orig) {
  48. pb->error = EXT2_ET_BLOCK_ALLOC_FAIL;
  49. return BLOCK_ABORT;
  50. }
  51. } while (ext2fs_test_block_bitmap(pb->reserve, block) ||
  52. ext2fs_test_block_bitmap(pb->alloc_map, block));
  53. retval = io_channel_read_blk(fs->io, orig, 1, pb->buf);
  54. if (retval) {
  55. pb->error = retval;
  56. return BLOCK_ABORT;
  57. }
  58. retval = io_channel_write_blk(fs->io, block, 1, pb->buf);
  59. if (retval) {
  60. pb->error = retval;
  61. return BLOCK_ABORT;
  62. }
  63. *block_nr = block;
  64. ext2fs_mark_block_bitmap(pb->alloc_map, block);
  65. ret = BLOCK_CHANGED;
  66. if (pb->flags & EXT2_BMOVE_DEBUG)
  67. printf("ino=%ld, blockcnt=%lld, %d->%d\n", pb->ino,
  68. blockcnt, orig, block);
  69. }
  70. if (pb->add_dir) {
  71. retval = ext2fs_add_dir_block(fs->dblist, pb->ino,
  72. block, (int) blockcnt);
  73. if (retval) {
  74. pb->error = retval;
  75. ret |= BLOCK_ABORT;
  76. }
  77. }
  78. return ret;
  79. }
  80. errcode_t ext2fs_move_blocks(ext2_filsys fs,
  81. ext2fs_block_bitmap reserve,
  82. ext2fs_block_bitmap alloc_map,
  83. int flags)
  84. {
  85. ext2_ino_t ino;
  86. struct ext2_inode inode;
  87. errcode_t retval;
  88. struct process_block_struct pb;
  89. ext2_inode_scan scan;
  90. char *block_buf;
  91. retval = ext2fs_open_inode_scan(fs, 0, &scan);
  92. if (retval)
  93. return retval;
  94. pb.reserve = reserve;
  95. pb.error = 0;
  96. pb.alloc_map = alloc_map ? alloc_map : fs->block_map;
  97. pb.flags = flags;
  98. retval = ext2fs_get_mem(fs->blocksize * 4, &block_buf);
  99. if (retval)
  100. return retval;
  101. pb.buf = block_buf + fs->blocksize * 3;
  102. /*
  103. * If GET_DBLIST is set in the flags field, then we should
  104. * gather directory block information while we're doing the
  105. * block move.
  106. */
  107. if (flags & EXT2_BMOVE_GET_DBLIST) {
  108. ext2fs_free_dblist(fs->dblist);
  109. fs->dblist = NULL;
  110. retval = ext2fs_init_dblist(fs, 0);
  111. if (retval)
  112. return retval;
  113. }
  114. retval = ext2fs_get_next_inode(scan, &ino, &inode);
  115. if (retval)
  116. return retval;
  117. while (ino) {
  118. if ((inode.i_links_count == 0) ||
  119. !ext2fs_inode_has_valid_blocks(&inode))
  120. goto next;
  121. pb.ino = ino;
  122. pb.inode = &inode;
  123. pb.add_dir = (LINUX_S_ISDIR(inode.i_mode) &&
  124. flags & EXT2_BMOVE_GET_DBLIST);
  125. retval = ext2fs_block_iterate2(fs, ino, 0, block_buf,
  126. process_block, &pb);
  127. if (retval)
  128. return retval;
  129. if (pb.error)
  130. return pb.error;
  131. next:
  132. retval = ext2fs_get_next_inode(scan, &ino, &inode);
  133. if (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE)
  134. goto next;
  135. }
  136. return 0;
  137. }