mkjournal.c revision 89a6ebd524891f332aad8ca0281935159ddc1217
1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * mkjournal.c --- make a journal for a filesystem
3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *
4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * Copyright (C) 2000 Theodore Ts'o.
5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *
6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * %Begin-Header%
7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * This file may be redistributed under the terms of the GNU Public
8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * License.
9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * %End-Header%
10ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */
11436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <stdio.h>
13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <string.h>
14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if HAVE_UNISTD_H
15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <unistd.h>
16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if HAVE_ERRNO_H
18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <errno.h>
19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <fcntl.h>
21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <time.h>
22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if HAVE_SYS_STAT_H
23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <sys/stat.h>
24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if HAVE_SYS_TYPES_H
26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <sys/types.h>
27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if HAVE_SYS_IOCTL_H
29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <sys/ioctl.h>
30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if HAVE_NETINET_IN_H
32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <netinet/in.h>
33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "ext2_fs.h"
36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "e2p/e2p.h"
37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "ext2fs.h"
38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "jfs_user.h"
39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * This function automatically sets up the journal superblock and
42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * returns it as an allocated block.
43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */
44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownerrcode_t ext2fs_create_journal_superblock(ext2_filsys fs,
45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown					   __u32 size, int flags,
46436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov					   char  **ret_jsb)
47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	errcode_t		retval;
49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	journal_superblock_t	*jsb;
50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if (size < 1024)
52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		return EXT2_ET_JOURNAL_TOO_SMALL;
53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if ((retval = ext2fs_get_mem(fs->blocksize, (void **) &jsb)))
55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		return retval;
56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	memset (jsb, 0, fs->blocksize);
58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER);
60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if (flags & EXT2_MKJOURNAL_V1_SUPER)
61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V1);
62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	else
63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2);
64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	jsb->s_blocksize = htonl(fs->blocksize);
65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	jsb->s_maxlen = htonl(size);
66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	jsb->s_nr_users = htonl(1);
67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	jsb->s_first = htonl(1);
68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	jsb->s_sequence = htonl(1);
69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	memcpy(jsb->s_uuid, fs->super->s_uuid, sizeof(fs->super->s_uuid));
70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	/*
71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 * If we're creating an external journal device, we need to
72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 * adjust these fields.
73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 */
74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if (fs->super->s_feature_incompat &
75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		jsb->s_nr_users = 0;
77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		if (fs->blocksize == 1024)
78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			jsb->s_first = htonl(3);
79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		else
80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			jsb->s_first = htonl(2);
81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	}
82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	*ret_jsb = (char *) jsb;
84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	return 0;
85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * This function writes a journal using POSIX routines.  It is used
89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * for creating external journals and creating journals on live
90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * filesystems.
91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */
92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic errcode_t write_journal_file(ext2_filsys fs, char *filename,
93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown				    blk_t size, int flags)
94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	errcode_t	retval;
96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	char		*buf = 0;
97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	int		i, fd, ret_size;
98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if ((retval = ext2fs_create_journal_superblock(fs, size, flags, &buf)))
100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		return retval;
101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	/* Open the device or journal file */
103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if ((fd = open(filename, O_WRONLY)) < 0) {
104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		retval = errno;
105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		goto errout;
106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	}
107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	/* Write the superblock out */
109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	retval = EXT2_ET_SHORT_WRITE;
110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	ret_size = write(fd, buf, fs->blocksize);
111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if (ret_size < 0) {
112663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng		retval = errno;
113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		goto errout;
114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	}
115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if (ret_size != fs->blocksize)
116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		goto errout;
117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	memset(buf, 0, fs->blocksize);
118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	for (i = 1; i < size; i++) {
120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		ret_size = write(fd, buf, fs->blocksize);
121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		if (ret_size < 0) {
122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			retval = errno;
123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			goto errout;
124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		}
125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		if (ret_size != fs->blocksize)
126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			goto errout;
127663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng	}
128663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng	close(fd);
129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	retval = 0;
131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownerrout:
132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	ext2fs_free_mem((void **) &buf);
133663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng	return retval;
134663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng}
135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
136436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/*
137436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov * Helper function for creating the journal using direct I/O routines
138436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov */
139436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstruct mkjournal_struct {
140436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	int		num_blocks;
141436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	int		newblocks;
142436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	char		*buf;
143436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	errcode_t	err;
144436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov};
145436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
146436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic int mkjournal_proc(ext2_filsys		fs,
147436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov			   blk_t		*blocknr,
148436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov			   e2_blkcnt_t		blockcnt,
149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			   blk_t		ref_block,
150436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov			   int			ref_offset,
151436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov			   void			*priv_data)
152436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	struct mkjournal_struct *es = (struct mkjournal_struct *) priv_data;
154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	blk_t	new_blk;
155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	static blk_t	last_blk = 0;
156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	errcode_t	retval;
157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	int		group;
158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
159436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	if (*blocknr) {
160436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov		last_blk = *blocknr;
161436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov		return 0;
162436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	}
163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	retval = ext2fs_new_block(fs, last_blk, 0, &new_blk);
164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if (retval) {
165436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov		es->err = retval;
166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		return BLOCK_ABORT;
167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	}
168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if (blockcnt > 0)
169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		es->num_blocks--;
170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	es->newblocks++;
172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	retval = io_channel_write_blk(fs->io, new_blk, 1, es->buf);
173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if (blockcnt == 0)
175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		memset(es->buf, 0, fs->blocksize);
176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if (retval) {
178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		es->err = retval;
179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		return BLOCK_ABORT;
180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	}
181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	*blocknr = new_blk;
182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	last_blk = new_blk;
183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	ext2fs_mark_block_bitmap(fs->block_map, new_blk);
184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	ext2fs_mark_bb_dirty(fs);
185436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	group = ext2fs_group_of_blk(fs, new_blk);
186436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	fs->group_desc[group].bg_free_blocks_count--;
187436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	fs->super->s_free_blocks_count--;
188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	ext2fs_mark_super_dirty(fs);
189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
190436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	if (es->num_blocks == 0)
191436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov		return (BLOCK_CHANGED | BLOCK_ABORT);
192436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	else
193436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov		return BLOCK_CHANGED;
194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * This function creates a journal using direct I/O routines.
199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */
200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino,
201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown				     blk_t size, int flags)
202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	char			*buf;
204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	errcode_t		retval;
205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	struct ext2_inode	inode;
206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	struct mkjournal_struct	es;
207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if ((retval = ext2fs_create_journal_superblock(fs, size, flags, &buf)))
209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		return retval;
210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if ((retval = ext2fs_read_bitmaps(fs)))
212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		return retval;
213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if ((retval = ext2fs_read_inode(fs, journal_ino, &inode)))
215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		return retval;
216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if (inode.i_blocks > 0)
218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		return EEXIST;
219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	es.num_blocks = size;
221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	es.newblocks = 0;
222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	es.buf = buf;
223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	es.err = 0;
224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	retval = ext2fs_block_iterate2(fs, journal_ino, BLOCK_FLAG_APPEND,
226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown				       0, mkjournal_proc, &es);
227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if (es.err) {
228436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov		retval = es.err;
229436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov		goto errout;
230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	}
231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
232436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	if ((retval = ext2fs_read_inode(fs, journal_ino, &inode)))
233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		goto errout;
234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
235436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov 	inode.i_size += fs->blocksize * size;
236436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	inode.i_blocks += (fs->blocksize / 512) * es.newblocks;
237436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	inode.i_mtime = inode.i_ctime = time(0);
238436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	inode.i_links_count = 1;
239436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	inode.i_mode = LINUX_S_IFREG | 0600;
240436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if ((retval = ext2fs_write_inode(fs, journal_ino, &inode)))
242436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov		goto errout;
243436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	retval = 0;
244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownerrout:
246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	ext2fs_free_mem((void **) &buf);
247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	return retval;
248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * This function adds a journal device to a filesystem
252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */
253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownerrcode_t ext2fs_add_journal_device(ext2_filsys fs, ext2_filsys journal_dev)
254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
255436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	struct stat	st;
256436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	errcode_t	retval;
257436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	char		buf[1024];
258436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	journal_superblock_t	*jsb;
259436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	int		i, start;
260436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	__u32		nr_users;
261663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
262663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng	/* Make sure the device exists and is a block device */
263663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng	if (stat(journal_dev->device_name, &st) < 0)
264663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng		return errno;
265663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
266663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng	if (!S_ISBLK(st.st_mode))
267663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng		return EXT2_ET_JOURNAL_NOT_BLOCK; /* Must be a block device */
268663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
269663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng	/* Get the journal superblock */
270663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng	start = 1;
271663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng	if (journal_dev->blocksize == 1024)
272663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng		start++;
273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if ((retval = io_channel_read_blk(journal_dev->io, start, -1024, buf)))
274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		return retval;
275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	jsb = (journal_superblock_t *) buf;
277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) ||
278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    (jsb->s_header.h_blocktype != (unsigned) ntohl(JFS_SUPERBLOCK_V2)))
279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		return EXT2_ET_NO_JOURNAL_SB;
280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if (ntohl(jsb->s_blocksize) != fs->blocksize)
282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		return EXT2_ET_UNEXPECTED_BLOCK_SIZE;
283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
284663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng	/* Check and see if this filesystem has already been added */
285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	nr_users = ntohl(jsb->s_nr_users);
286663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng	for (i=0; i < nr_users; i++) {
287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		if (memcmp(fs->super->s_uuid,
288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			   &jsb->s_users[i*16], 16) == 0)
289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			break;
290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	}
291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if (i >= nr_users) {
292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		memcpy(&jsb->s_users[nr_users*16],
293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		       fs->super->s_uuid, 16);
294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		jsb->s_nr_users = htonl(nr_users+1);
295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	}
296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	/* Writeback the journal superblock */
298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if ((retval = io_channel_write_blk(journal_dev->io, start, -1024, buf)))
299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		return retval;
300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	fs->super->s_journal_inum = 0;
302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	fs->super->s_journal_dev = st.st_rdev;
303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	memcpy(fs->super->s_journal_uuid, jsb->s_uuid,
304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	       sizeof(fs->super->s_journal_uuid));
305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	ext2fs_mark_super_dirty(fs);
307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	return 0;
308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * This function adds a journal inode to a filesystem, using either
312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * POSIX routines if the filesystem is mounted, or using direct I/O
313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * functions if it is not.
314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */
315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownerrcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t size, int flags)
316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	errcode_t		retval;
318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	ext2_ino_t		journal_ino;
319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	struct stat		st;
320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	char			jfile[1024];
321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	int			fd, mount_flags, f;
322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if ((retval = ext2fs_check_mount_point(fs->device_name, &mount_flags,
324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown					       jfile, sizeof(jfile)-10)))
325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		return retval;
326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if (mount_flags & EXT2_MF_MOUNTED) {
328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		strcat(jfile, "/.journal");
329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		/* Create the journal file */
331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		if ((fd = open(jfile, O_CREAT|O_WRONLY, 0600)) < 0)
332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			return errno;
333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		if ((retval = write_journal_file(fs, jfile, size, flags)))
335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			goto errout;
336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		/* Get inode number of the journal file */
338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		if (fstat(fd, &st) < 0)
339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			goto errout;
340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(HAVE_CHFLAGS) && defined(UF_NODUMP)
342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		retval = fchflags (fd, UF_NODUMP|UF_IMMUTABLE);
343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#else
344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if HAVE_EXT2_IOCTLS
345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		f = EXT2_NODUMP_FL | EXT2_IMMUTABLE_FL;;
346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		retval = ioctl(fd, EXT2_IOC_SETFLAGS, &f);
347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		if (retval)
350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			goto errout;
351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		close(fd);
353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		journal_ino = st.st_ino;
354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	} else {
355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		journal_ino = EXT2_JOURNAL_INO;
356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		if ((retval = write_journal_inode(fs, journal_ino,
357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown						  size, flags)))
358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			return retval;
359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	}
360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	fs->super->s_journal_inum = journal_ino;
362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	fs->super->s_journal_dev = 0;
363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	memset(fs->super->s_journal_uuid, 0,
364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	       sizeof(fs->super->s_journal_uuid));
365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	ext2fs_mark_super_dirty(fs);
368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	return 0;
369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownerrout:
370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	close(fd);
371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	return retval;
372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifdef DEBUG
375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmain(int argc, char **argv)
376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	errcode_t	retval;
378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	char		*device_name;
379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	ext2_filsys 	fs;
380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if (argc < 2) {
382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		fprintf(stderr, "Usage: %s filesystem\n", argv[0]);
383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		exit(1);
384663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng	}
385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	device_name = argv[1];
386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	retval = ext2fs_open (device_name, EXT2_FLAG_RW, 0, 0,
388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			      unix_io_manager, &fs);
389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if (retval) {
390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		com_err(argv[0], retval, "while opening %s", device_name);
391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		exit(1);
392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	}
393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	retval = ext2fs_add_journal_inode(fs, 1024);
395b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov	if (retval) {
396436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov		com_err(argv[0], retval, "while adding journal to %s",
397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			device_name);
398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		exit(1);
399436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	}
400436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	retval = ext2fs_flush(fs);
401436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	if (retval) {
402436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov		printf("Warning, had trouble writing out superblocks.\n");
403436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	}
404436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	ext2fs_close(fs);
405436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov	exit(0);
406b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
407b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
408b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#endif
409b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov