blob: f9480c888f480e6c937ddbb6dc887a3ad5c592d6 [file] [log] [blame]
Theodore Ts'o1e1da291997-06-09 14:51:29 +00001/*
2 * bmove.c --- Move blocks around to make way for a particular
3 * filesystem structure.
4 *
Theodore Ts'o543547a2010-05-17 21:31:56 -04005 * Copyright (C) 1997 Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Library
9 * General Public License, version 2.
10 * %End-Header%
Theodore Ts'o1e1da291997-06-09 14:51:29 +000011 */
12
13#include <stdio.h>
14#include <string.h>
Theodore Ts'o4cbe8af1997-08-10 23:07:40 +000015#if HAVE_UNISTD_H
Theodore Ts'o1e1da291997-06-09 14:51:29 +000016#include <unistd.h>
Theodore Ts'o4cbe8af1997-08-10 23:07:40 +000017#endif
Theodore Ts'o1d2ff461997-10-19 23:00:21 +000018#if HAVE_SYS_TYPES_H
Theodore Ts'o1e1da291997-06-09 14:51:29 +000019#include <sys/types.h>
Theodore Ts'o1d2ff461997-10-19 23:00:21 +000020#endif
21#if HAVE_SYS_TIME_H
Theodore Ts'o1e1da291997-06-09 14:51:29 +000022#include <sys/time.h>
Theodore Ts'o1d2ff461997-10-19 23:00:21 +000023#endif
Theodore Ts'o1e1da291997-06-09 14:51:29 +000024
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000025#include "ext2_fs.h"
Theodore Ts'o9abd2ce1998-02-16 22:00:37 +000026#include "ext2fsP.h"
Theodore Ts'o1e1da291997-06-09 14:51:29 +000027
28struct process_block_struct {
Theodore Ts'o31dbecd2001-01-11 04:54:39 +000029 ext2_ino_t ino;
Theodore Ts'o1e1da291997-06-09 14:51:29 +000030 struct ext2_inode * inode;
31 ext2fs_block_bitmap reserve;
Theodore Ts'o9941fb71997-06-11 22:27:41 +000032 ext2fs_block_bitmap alloc_map;
Theodore Ts'o1e1da291997-06-09 14:51:29 +000033 errcode_t error;
34 char *buf;
35 int add_dir;
Theodore Ts'o36f21431997-06-14 07:25:40 +000036 int flags;
Theodore Ts'o1e1da291997-06-09 14:51:29 +000037};
38
JP Abgralle0ed7402014-03-19 19:08:39 -070039static int process_block(ext2_filsys fs, blk64_t *block_nr,
40 e2_blkcnt_t blockcnt, blk64_t ref_block,
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000041 int ref_offset, void *priv_data)
Theodore Ts'o1e1da291997-06-09 14:51:29 +000042{
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000043 struct process_block_struct *pb;
Theodore Ts'o1e1da291997-06-09 14:51:29 +000044 errcode_t retval;
45 int ret;
JP Abgralle0ed7402014-03-19 19:08:39 -070046 blk64_t block, orig;
Theodore Ts'o1e1da291997-06-09 14:51:29 +000047
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000048 pb = (struct process_block_struct *) priv_data;
Theodore Ts'o1e1da291997-06-09 14:51:29 +000049 block = orig = *block_nr;
50 ret = 0;
Theodore Ts'oefc6f622008-08-27 23:07:54 -040051
Theodore Ts'o1e1da291997-06-09 14:51:29 +000052 /*
53 * Let's see if this is one which we need to relocate
54 */
JP Abgralle0ed7402014-03-19 19:08:39 -070055 if (ext2fs_test_block_bitmap2(pb->reserve, block)) {
Theodore Ts'o1e1da291997-06-09 14:51:29 +000056 do {
JP Abgralle0ed7402014-03-19 19:08:39 -070057 if (++block >= ext2fs_blocks_count(fs->super))
Theodore Ts'o1e1da291997-06-09 14:51:29 +000058 block = fs->super->s_first_data_block;
59 if (block == orig) {
Theodore Ts'o1f0b6c11997-10-31 06:07:47 +000060 pb->error = EXT2_ET_BLOCK_ALLOC_FAIL;
Theodore Ts'o1e1da291997-06-09 14:51:29 +000061 return BLOCK_ABORT;
62 }
JP Abgralle0ed7402014-03-19 19:08:39 -070063 } while (ext2fs_test_block_bitmap2(pb->reserve, block) ||
64 ext2fs_test_block_bitmap2(pb->alloc_map, block));
Theodore Ts'o1e1da291997-06-09 14:51:29 +000065
JP Abgralle0ed7402014-03-19 19:08:39 -070066 retval = io_channel_read_blk64(fs->io, orig, 1, pb->buf);
Theodore Ts'o1e1da291997-06-09 14:51:29 +000067 if (retval) {
68 pb->error = retval;
69 return BLOCK_ABORT;
70 }
JP Abgralle0ed7402014-03-19 19:08:39 -070071 retval = io_channel_write_blk64(fs->io, block, 1, pb->buf);
Theodore Ts'o1e1da291997-06-09 14:51:29 +000072 if (retval) {
73 pb->error = retval;
74 return BLOCK_ABORT;
75 }
76 *block_nr = block;
JP Abgralle0ed7402014-03-19 19:08:39 -070077 ext2fs_mark_block_bitmap2(pb->alloc_map, block);
Theodore Ts'o1e1da291997-06-09 14:51:29 +000078 ret = BLOCK_CHANGED;
Theodore Ts'o36f21431997-06-14 07:25:40 +000079 if (pb->flags & EXT2_BMOVE_DEBUG)
JP Abgralle0ed7402014-03-19 19:08:39 -070080 printf("ino=%u, blockcnt=%lld, %llu->%llu\n",
81 (unsigned) pb->ino, blockcnt,
82 (unsigned long long) orig,
83 (unsigned long long) block);
Theodore Ts'o1e1da291997-06-09 14:51:29 +000084 }
85 if (pb->add_dir) {
JP Abgralle0ed7402014-03-19 19:08:39 -070086 retval = ext2fs_add_dir_block2(fs->dblist, pb->ino,
87 block, blockcnt);
Theodore Ts'o1e1da291997-06-09 14:51:29 +000088 if (retval) {
89 pb->error = retval;
90 ret |= BLOCK_ABORT;
91 }
92 }
93 return ret;
94}
95
96errcode_t ext2fs_move_blocks(ext2_filsys fs,
97 ext2fs_block_bitmap reserve,
Theodore Ts'o9941fb71997-06-11 22:27:41 +000098 ext2fs_block_bitmap alloc_map,
Theodore Ts'o1e1da291997-06-09 14:51:29 +000099 int flags)
100{
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000101 ext2_ino_t ino;
Theodore Ts'o1e1da291997-06-09 14:51:29 +0000102 struct ext2_inode inode;
103 errcode_t retval;
104 struct process_block_struct pb;
105 ext2_inode_scan scan;
106 char *block_buf;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400107
Theodore Ts'o1e1da291997-06-09 14:51:29 +0000108 retval = ext2fs_open_inode_scan(fs, 0, &scan);
109 if (retval)
110 return retval;
111
112 pb.reserve = reserve;
113 pb.error = 0;
Theodore Ts'o9941fb71997-06-11 22:27:41 +0000114 pb.alloc_map = alloc_map ? alloc_map : fs->block_map;
Theodore Ts'o36f21431997-06-14 07:25:40 +0000115 pb.flags = flags;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400116
Theodore Ts'oee010792007-11-09 19:01:06 -0500117 retval = ext2fs_get_array(4, fs->blocksize, &block_buf);
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000118 if (retval)
119 return retval;
Theodore Ts'o1e1da291997-06-09 14:51:29 +0000120 pb.buf = block_buf + fs->blocksize * 3;
121
122 /*
123 * If GET_DBLIST is set in the flags field, then we should
124 * gather directory block information while we're doing the
125 * block move.
126 */
127 if (flags & EXT2_BMOVE_GET_DBLIST) {
128 if (fs->dblist) {
129 ext2fs_free_dblist(fs->dblist);
130 fs->dblist = NULL;
131 }
132 retval = ext2fs_init_dblist(fs, 0);
133 if (retval)
134 return retval;
135 }
136
137 retval = ext2fs_get_next_inode(scan, &ino, &inode);
138 if (retval)
139 return retval;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400140
Theodore Ts'o1e1da291997-06-09 14:51:29 +0000141 while (ino) {
142 if ((inode.i_links_count == 0) ||
JP Abgralle0ed7402014-03-19 19:08:39 -0700143 !ext2fs_inode_has_valid_blocks2(fs, &inode))
Theodore Ts'o1e1da291997-06-09 14:51:29 +0000144 goto next;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400145
Theodore Ts'o1e1da291997-06-09 14:51:29 +0000146 pb.ino = ino;
147 pb.inode = &inode;
148
149 pb.add_dir = (LINUX_S_ISDIR(inode.i_mode) &&
150 flags & EXT2_BMOVE_GET_DBLIST);
151
JP Abgralle0ed7402014-03-19 19:08:39 -0700152 retval = ext2fs_block_iterate3(fs, ino, 0, block_buf,
153 process_block, &pb);
Theodore Ts'o1e1da291997-06-09 14:51:29 +0000154 if (retval)
155 return retval;
156 if (pb.error)
157 return pb.error;
158
159 next:
160 retval = ext2fs_get_next_inode(scan, &ino, &inode);
161 if (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE)
162 goto next;
163 }
164 return 0;
165}
166