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