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