mkjournal.c revision 31a17b36d5f7d875f9de8e86501eaf2338f94d2b
1/*
2 * mkjournal.c --- make a journal for a filesystem
3 *
4 * Copyright (C) 2000 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#include <string.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17#if HAVE_ERRNO_H
18#include <errno.h>
19#endif
20#include <fcntl.h>
21#include <time.h>
22#if HAVE_SYS_STAT_H
23#include <sys/stat.h>
24#endif
25#if HAVE_SYS_TYPES_H
26#include <sys/types.h>
27#endif
28#if HAVE_NETINET_IN_H
29#include <netinet/in.h>
30#endif
31
32#if EXT2_FLAT_INCLUDES
33#include "ext2_fs.h"
34#else
35#include <linux/ext2_fs.h>
36#endif
37
38#include "ext2fs.h"
39#include "jfs_user.h"
40
41static void init_journal_superblock(journal_superblock_t *jsb,
42				    __u32 blocksize, __u32 size, int flags)
43{
44	memset (jsb, 0, sizeof(*jsb));
45
46	jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER);
47	if (flags & EXT2_MKJOURNAL_V1_SUPER)
48		jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V1);
49	else
50		jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2);
51	jsb->s_blocksize = htonl(blocksize);
52	jsb->s_maxlen = htonl(size);
53	jsb->s_first = htonl(1);
54	jsb->s_sequence = htonl(1);
55}
56
57/*
58 * This function adds a journal device to a filesystem
59 */
60errcode_t ext2fs_add_journal_device(ext2_filsys fs, char *device,
61				    blk_t size, int flags)
62{
63	journal_superblock_t	jsb;
64	struct stat	st;
65	errcode_t	retval;
66	char		*buf = 0;
67	blk_t		dev_size;
68	int		i, fd, ret_size;
69
70	/* Make sure the device exists and is a block device */
71	if (stat(device, &st) < 0)
72		return errno;
73	if (!S_ISBLK(st.st_mode))
74		return EXT2_JOURNAL_NOT_BLOCK;	/* Must be a block device */
75
76	/* Get the size of the device */
77	if ((retval = ext2fs_get_device_size(device, fs->blocksize,
78					     &dev_size)))
79		return retval;
80
81	if (!size)
82		size = dev_size; /* Default to the size of the device */
83	else if (size > dev_size)
84		return EINVAL;	/* Requested size bigger than device */
85
86	init_journal_superblock(&jsb, fs->blocksize, size, flags);
87
88	/* Create a block buffer */
89	buf = malloc(fs->blocksize);
90	if (!buf)
91		return ENOMEM;
92
93	/* Open the device */
94	if ((fd = open(device, O_WRONLY)) < 0) {
95		retval = errno;
96		goto errout;
97	}
98
99	/* Write the superblock out */
100	memset(buf, 0, fs->blocksize);
101	memcpy(buf, &jsb, sizeof(jsb));
102	retval = EXT2_ET_SHORT_WRITE;
103	ret_size = write(fd, buf, fs->blocksize);
104	if (ret_size < 0) {
105		errno = retval;
106		goto errout;
107	}
108	if (ret_size != fs->blocksize)
109		goto errout;
110	memset(buf, 0, fs->blocksize);
111
112	for (i=1; i < size; i++) {
113		ret_size = write(fd, buf, fs->blocksize);
114		if (ret_size < 0) {
115			retval = errno;
116			goto errout;
117		}
118		if (ret_size != fs->blocksize)
119			goto errout;
120	}
121	close(fd);
122
123	fs->super->s_journal_dev = st.st_rdev;
124	fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
125	ext2fs_mark_super_dirty(fs);
126
127	return 0;
128errout:
129	if (buf)
130		free(buf);
131	return retval;
132}
133
134/*
135 * Helper function for creating the journal in the filesystem
136 */
137struct mkjournal_struct {
138	int		num_blocks;
139	int		newblocks;
140	char		*buf;
141	errcode_t	err;
142};
143
144static int mkjournal_proc(ext2_filsys		fs,
145			   blk_t		*blocknr,
146			   e2_blkcnt_t		blockcnt,
147			   blk_t		ref_block,
148			   int			ref_offset,
149			   void			*priv_data)
150{
151	struct mkjournal_struct *es = (struct mkjournal_struct *) priv_data;
152	blk_t	new_blk;
153	static blk_t	last_blk = 0;
154	char		*block;
155	errcode_t	retval;
156	int		group;
157
158	if (*blocknr) {
159		last_blk = *blocknr;
160		return 0;
161	}
162	retval = ext2fs_new_block(fs, last_blk, 0, &new_blk);
163	if (retval) {
164		es->err = retval;
165		return BLOCK_ABORT;
166	}
167	if (blockcnt > 0)
168		es->num_blocks--;
169
170	es->newblocks++;
171	retval = io_channel_write_blk(fs->io, new_blk, 1, es->buf);
172
173	if (blockcnt == 0)
174		memset(es->buf, 0, fs->blocksize);
175
176	if (retval) {
177		es->err = retval;
178		return BLOCK_ABORT;
179	}
180	*blocknr = new_blk;
181	ext2fs_mark_block_bitmap(fs->block_map, new_blk);
182	ext2fs_mark_bb_dirty(fs);
183	group = ext2fs_group_of_blk(fs, new_blk);
184	fs->group_desc[group].bg_free_blocks_count--;
185	fs->super->s_free_blocks_count--;
186	ext2fs_mark_super_dirty(fs);
187
188	if (es->num_blocks == 0)
189		return (BLOCK_CHANGED | BLOCK_ABORT);
190	else
191		return BLOCK_CHANGED;
192
193}
194
195/*
196 * This function adds a journal inode to a filesystem
197 */
198errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t size, int flags)
199{
200	journal_superblock_t	jsb;
201	errcode_t		retval;
202	struct ext2_inode	inode;
203	struct mkjournal_struct	es;
204	char			*buf;
205
206	init_journal_superblock(&jsb, fs->blocksize, size, flags);
207
208	if ((retval = ext2fs_read_bitmaps(fs)))
209		return retval;
210
211	if ((retval = ext2fs_read_inode(fs, EXT2_JOURNAL_INO, &inode)))
212		return retval;
213
214	if (inode.i_blocks > 0)
215		return EEXIST;
216
217	/* Create the block buffer */
218	buf = malloc(fs->blocksize);
219	if (!buf)
220		return ENOMEM;
221
222	memset(buf, 0, fs->blocksize);
223	memcpy(buf, &jsb, sizeof(jsb));
224
225	es.num_blocks = size;
226	es.newblocks = 0;
227	es.buf = buf;
228	es.err = 0;
229
230	retval = ext2fs_block_iterate2(fs, EXT2_JOURNAL_INO, BLOCK_FLAG_APPEND,
231				       0, mkjournal_proc, &es);
232	free(buf);
233	if (es.err)
234		return es.err;
235
236	if ((retval = ext2fs_read_inode(fs, EXT2_JOURNAL_INO, &inode)))
237		return retval;
238
239 	inode.i_size += fs->blocksize * size;
240	inode.i_blocks += (fs->blocksize / 512) * es.newblocks;
241	inode.i_mtime = inode.i_ctime = time(0);
242	inode.i_links_count = 1;
243	inode.i_mode = LINUX_S_IFREG | 0600;
244
245	if ((retval = ext2fs_write_inode(fs, EXT2_JOURNAL_INO, &inode)))
246		return retval;
247
248	fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
249	fs->super->s_journal_inum = EXT2_JOURNAL_INO;
250
251	ext2fs_mark_super_dirty(fs);
252	return 0;
253}
254
255#ifdef DEBUG
256main(int argc, char **argv)
257{
258	errcode_t	retval;
259	char		*device_name;
260	ext2_filsys 	fs;
261
262	if (argc < 2) {
263		fprintf(stderr, "Usage: %s filesystem\n", argv[0]);
264		exit(1);
265	}
266	device_name = argv[1];
267
268	retval = ext2fs_open (device_name, EXT2_FLAG_RW, 0, 0,
269			      unix_io_manager, &fs);
270	if (retval) {
271		com_err(argv[0], retval, "while opening %s", device_name);
272		exit(1);
273	}
274
275	retval = ext2fs_add_journal_inode(fs, 1024);
276	if (retval) {
277		com_err(argv[0], retval, "while adding journal to %s",
278			device_name);
279		exit(1);
280	}
281	retval = ext2fs_flush(fs);
282	if (retval) {
283		printf("Warning, had trouble writing out superblocks.\n");
284	}
285	ext2fs_close(fs);
286	exit(0);
287
288}
289#endif
290