bmove.c 3.5 KB

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