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