bmove.c revision 9941fb73f530b11d3d1dcc97a585f63449703f5a
11e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o/* 21e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o * bmove.c --- Move blocks around to make way for a particular 31e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o * filesystem structure. 41e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o * 51e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o * Copyright (C) 1997 Theodore Ts'o. This file may be redistributed 61e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o * under the terms of the GNU Public License. 71e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o */ 81e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o 91e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o#include <stdio.h> 101e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o#include <string.h> 111e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o#include <unistd.h> 121e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o#include <stdlib.h> 131e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o#include <sys/types.h> 141e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o#include <sys/time.h> 151e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o 161e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o#include <linux/ext2_fs.h> 171e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o#include "ext2fs/ext2fs.h" 181e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o 191e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'ostruct process_block_struct { 201e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o ino_t ino; 211e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o struct ext2_inode * inode; 221e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o ext2fs_block_bitmap reserve; 239941fb73f530b11d3d1dcc97a585f63449703f5aTheodore Ts'o ext2fs_block_bitmap alloc_map; 241e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o errcode_t error; 251e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o char *buf; 261e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o int add_dir; 271e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o}; 281e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o 291e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'ostatic int process_block(ext2_filsys fs, blk_t *block_nr, 301e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o int blockcnt, blk_t ref_block, 311e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o int ref_offset, void *private) 321e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o{ 331e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o struct process_block_struct *pb = private; 341e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o errcode_t retval; 351e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o int ret; 361e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o blk_t block, orig; 371e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o 381e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o block = orig = *block_nr; 391e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o ret = 0; 401e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o 411e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o /* 421e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o * Let's see if this is one which we need to relocate 431e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o */ 441e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o if (ext2fs_test_block_bitmap(pb->reserve, block)) { 451e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o do { 461e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o if (++block >= fs->super->s_blocks_count) 471e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o block = fs->super->s_first_data_block; 481e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o if (block == orig) { 491e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o pb->error = ENOSPC; 501e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o return BLOCK_ABORT; 511e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o } 521e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o } while (ext2fs_test_block_bitmap(pb->reserve, block) || 539941fb73f530b11d3d1dcc97a585f63449703f5aTheodore Ts'o ext2fs_test_block_bitmap(pb->alloc_map, block)); 541e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o 551e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o retval = io_channel_read_blk(fs->io, orig, 1, pb->buf); 561e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o if (retval) { 571e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o pb->error = retval; 581e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o return BLOCK_ABORT; 591e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o } 601e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o retval = io_channel_write_blk(fs->io, block, 1, pb->buf); 611e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o if (retval) { 621e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o pb->error = retval; 631e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o return BLOCK_ABORT; 641e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o } 651e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o *block_nr = block; 669941fb73f530b11d3d1dcc97a585f63449703f5aTheodore Ts'o ext2fs_mark_block_bitmap(pb->alloc_map, block); 671e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o ret = BLOCK_CHANGED; 681e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o printf("ino=%ld, blockcnt=%d, %ld->%ld\n", pb->ino, 691e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o blockcnt, orig, block); 701e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o } 711e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o if (pb->add_dir) { 721e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o retval = ext2fs_add_dir_block(fs->dblist, pb->ino, 731e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o block, blockcnt); 741e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o if (retval) { 751e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o pb->error = retval; 761e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o ret |= BLOCK_ABORT; 771e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o } 781e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o } 791e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o return ret; 801e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o} 811e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o 821e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'oerrcode_t ext2fs_move_blocks(ext2_filsys fs, 831e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o ext2fs_block_bitmap reserve, 849941fb73f530b11d3d1dcc97a585f63449703f5aTheodore Ts'o ext2fs_block_bitmap alloc_map, 851e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o int flags) 861e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o{ 871e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o ino_t ino; 881e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o struct ext2_inode inode; 891e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o errcode_t retval; 901e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o struct process_block_struct pb; 911e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o ext2_inode_scan scan; 921e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o char *block_buf; 931e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o 941e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o retval = ext2fs_open_inode_scan(fs, 0, &scan); 951e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o if (retval) 961e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o return retval; 971e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o 981e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o pb.reserve = reserve; 991e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o pb.error = 0; 1009941fb73f530b11d3d1dcc97a585f63449703f5aTheodore Ts'o pb.alloc_map = alloc_map ? alloc_map : fs->block_map; 1011e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o 1021e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o block_buf = malloc(fs->blocksize * 4); 1031e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o if (!block_buf) 1041e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o return ENOMEM; 1051e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o pb.buf = block_buf + fs->blocksize * 3; 1061e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o 1071e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o /* 1081e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o * If GET_DBLIST is set in the flags field, then we should 1091e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o * gather directory block information while we're doing the 1101e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o * block move. 1111e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o */ 1121e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o if (flags & EXT2_BMOVE_GET_DBLIST) { 1131e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o if (fs->dblist) { 1141e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o ext2fs_free_dblist(fs->dblist); 1151e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o fs->dblist = NULL; 1161e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o } 1171e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o retval = ext2fs_init_dblist(fs, 0); 1181e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o if (retval) 1191e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o return retval; 1201e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o } 1211e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o 1221e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o retval = ext2fs_get_next_inode(scan, &ino, &inode); 1231e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o if (retval) 1241e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o return retval; 1251e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o 1261e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o while (ino) { 1271e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o if ((inode.i_links_count == 0) || 1281e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o !ext2fs_inode_has_valid_blocks(&inode)) 1291e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o goto next; 1301e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o 1311e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o pb.ino = ino; 1321e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o pb.inode = &inode; 1331e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o 1341e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o pb.add_dir = (LINUX_S_ISDIR(inode.i_mode) && 1351e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o flags & EXT2_BMOVE_GET_DBLIST); 1361e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o 1371e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o retval = ext2fs_block_iterate2(fs, ino, 0, block_buf, 1381e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o process_block, &pb); 1391e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o if (retval) 1401e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o return retval; 1411e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o if (pb.error) 1421e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o return pb.error; 1431e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o 1441e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o next: 1451e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o retval = ext2fs_get_next_inode(scan, &ino, &inode); 1461e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o if (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) 1471e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o goto next; 1481e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o } 1491e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o return 0; 1501e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o} 1511e1da29fbd4204a267ebd7c64d37e1f95a9dad08Theodore Ts'o 152