blob: c636a9757d7746a8ac3c8cf4cf7e1709ba88ed0a [file] [log] [blame]
Theodore Ts'od3cd93c2000-10-24 18:33:16 +00001/*
2 * mkjournal.c --- make a journal for a filesystem
3 *
4 * Copyright (C) 2000 Theodore Ts'o.
Theodore Ts'oefc6f622008-08-27 23:07:54 -04005 *
Theodore Ts'od3cd93c2000-10-24 18:33:16 +00006 * %Begin-Header%
Theodore Ts'o543547a2010-05-17 21:31:56 -04007 * This file may be redistributed under the terms of the GNU Library
8 * General Public License, version 2.
Theodore Ts'od3cd93c2000-10-24 18:33:16 +00009 * %End-Header%
10 */
11
Theodore Ts'od1154eb2011-09-18 17:34:37 -040012#include "config.h"
Theodore Ts'od3cd93c2000-10-24 18:33:16 +000013#include <stdio.h>
14#include <string.h>
15#if HAVE_UNISTD_H
16#include <unistd.h>
17#endif
18#if HAVE_ERRNO_H
19#include <errno.h>
20#endif
21#include <fcntl.h>
22#include <time.h>
23#if HAVE_SYS_STAT_H
24#include <sys/stat.h>
25#endif
26#if HAVE_SYS_TYPES_H
27#include <sys/types.h>
28#endif
Theodore Ts'o349a4842001-06-11 00:49:29 +000029#if HAVE_SYS_IOCTL_H
30#include <sys/ioctl.h>
31#endif
Theodore Ts'o17ee8b12000-10-26 20:45:58 +000032#if HAVE_NETINET_IN_H
33#include <netinet/in.h>
34#endif
Theodore Ts'od3cd93c2000-10-24 18:33:16 +000035
Theodore Ts'od3cd93c2000-10-24 18:33:16 +000036#include "ext2_fs.h"
Theodore Ts'ocdaf1fa2001-01-05 22:23:22 +000037#include "e2p/e2p.h"
Theodore Ts'od3cd93c2000-10-24 18:33:16 +000038#include "ext2fs.h"
Theodore Ts'o58618732000-12-09 05:47:45 +000039#include "jfs_user.h"
Theodore Ts'od3cd93c2000-10-24 18:33:16 +000040
Theodore Ts'oa1128472001-01-16 06:56:14 +000041/*
42 * This function automatically sets up the journal superblock and
43 * returns it as an allocated block.
44 */
45errcode_t ext2fs_create_journal_superblock(ext2_filsys fs,
Andreas Dilger931b58e2011-06-11 12:17:29 -040046 __u32 num_blocks, int flags,
Theodore Ts'oa1128472001-01-16 06:56:14 +000047 char **ret_jsb)
Theodore Ts'od3cd93c2000-10-24 18:33:16 +000048{
Theodore Ts'oa1128472001-01-16 06:56:14 +000049 errcode_t retval;
50 journal_superblock_t *jsb;
Theodore Ts'o03603942001-04-17 00:53:25 +000051
Andreas Dilger931b58e2011-06-11 12:17:29 -040052 if (num_blocks < 1024)
Theodore Ts'o03603942001-04-17 00:53:25 +000053 return EXT2_ET_JOURNAL_TOO_SMALL;
54
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -040055 if ((retval = ext2fs_get_mem(fs->blocksize, &jsb)))
Theodore Ts'oa1128472001-01-16 06:56:14 +000056 return retval;
57
58 memset (jsb, 0, fs->blocksize);
Theodore Ts'o58618732000-12-09 05:47:45 +000059
Theodore Ts'od3cd93c2000-10-24 18:33:16 +000060 jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER);
Theodore Ts'o4e246702000-12-09 14:39:16 +000061 if (flags & EXT2_MKJOURNAL_V1_SUPER)
62 jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V1);
63 else
64 jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2);
Theodore Ts'oa1128472001-01-16 06:56:14 +000065 jsb->s_blocksize = htonl(fs->blocksize);
Andreas Dilger931b58e2011-06-11 12:17:29 -040066 jsb->s_maxlen = htonl(num_blocks);
Theodore Ts'od23042a2001-02-08 03:37:16 +000067 jsb->s_nr_users = htonl(1);
Theodore Ts'od3cd93c2000-10-24 18:33:16 +000068 jsb->s_first = htonl(1);
69 jsb->s_sequence = htonl(1);
Theodore Ts'oa1128472001-01-16 06:56:14 +000070 memcpy(jsb->s_uuid, fs->super->s_uuid, sizeof(fs->super->s_uuid));
Theodore Ts'oa1128472001-01-16 06:56:14 +000071 /*
Theodore Ts'od23042a2001-02-08 03:37:16 +000072 * If we're creating an external journal device, we need to
73 * adjust these fields.
Theodore Ts'oa1128472001-01-16 06:56:14 +000074 */
75 if (fs->super->s_feature_incompat &
Theodore Ts'o4e40f6c2001-07-27 23:33:40 -040076 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
Theodore Ts'oa1128472001-01-16 06:56:14 +000077 jsb->s_nr_users = 0;
Theodore Ts'o4e40f6c2001-07-27 23:33:40 -040078 if (fs->blocksize == 1024)
79 jsb->s_first = htonl(3);
80 else
81 jsb->s_first = htonl(2);
82 }
Theodore Ts'oa1128472001-01-16 06:56:14 +000083
84 *ret_jsb = (char *) jsb;
85 return 0;
Theodore Ts'od3cd93c2000-10-24 18:33:16 +000086}
Theodore Ts'o4becab62001-01-03 19:22:42 +000087
Theodore Ts'od3cd93c2000-10-24 18:33:16 +000088/*
Theodore Ts'o4becab62001-01-03 19:22:42 +000089 * This function writes a journal using POSIX routines. It is used
90 * for creating external journals and creating journals on live
91 * filesystems.
Theodore Ts'od3cd93c2000-10-24 18:33:16 +000092 */
Theodore Ts'oa1128472001-01-16 06:56:14 +000093static errcode_t write_journal_file(ext2_filsys fs, char *filename,
Andreas Dilger931b58e2011-06-11 12:17:29 -040094 blk_t num_blocks, int flags)
Theodore Ts'od3cd93c2000-10-24 18:33:16 +000095{
Theodore Ts'od3cd93c2000-10-24 18:33:16 +000096 errcode_t retval;
97 char *buf = 0;
Theodore Ts'o54434922003-12-07 01:28:50 -050098 int fd, ret_size;
99 blk_t i;
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000100
Andreas Dilger931b58e2011-06-11 12:17:29 -0400101 if ((retval = ext2fs_create_journal_superblock(fs, num_blocks, flags,
102 &buf)))
Theodore Ts'oa1128472001-01-16 06:56:14 +0000103 return retval;
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000104
Theodore Ts'oa1128472001-01-16 06:56:14 +0000105 /* Open the device or journal file */
106 if ((fd = open(filename, O_WRONLY)) < 0) {
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000107 retval = errno;
Andreas Dilger6c546892011-06-11 12:17:29 -0400108 goto errfree;
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000109 }
110
111 /* Write the superblock out */
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000112 retval = EXT2_ET_SHORT_WRITE;
113 ret_size = write(fd, buf, fs->blocksize);
114 if (ret_size < 0) {
Theodore Ts'oa1128472001-01-16 06:56:14 +0000115 retval = errno;
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000116 goto errout;
117 }
Theodore Ts'o54434922003-12-07 01:28:50 -0500118 if (ret_size != (int) fs->blocksize)
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000119 goto errout;
120 memset(buf, 0, fs->blocksize);
Theodore Ts'o4becab62001-01-03 19:22:42 +0000121
Andreas Dilger6c546892011-06-11 12:17:29 -0400122 if (flags & EXT2_MKJOURNAL_LAZYINIT)
123 goto success;
124
Andreas Dilger931b58e2011-06-11 12:17:29 -0400125 for (i = 1; i < num_blocks; i++) {
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000126 ret_size = write(fd, buf, fs->blocksize);
127 if (ret_size < 0) {
128 retval = errno;
129 goto errout;
130 }
Theodore Ts'o54434922003-12-07 01:28:50 -0500131 if (ret_size != (int) fs->blocksize)
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000132 goto errout;
133 }
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000134
Andreas Dilger6c546892011-06-11 12:17:29 -0400135success:
Theodore Ts'o4becab62001-01-03 19:22:42 +0000136 retval = 0;
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000137errout:
Andreas Dilger6c546892011-06-11 12:17:29 -0400138 close(fd);
139errfree:
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -0400140 ext2fs_free_mem(&buf);
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000141 return retval;
142}
143
144/*
Theodore Ts'oc8608502008-04-27 16:10:32 -0400145 * Convenience function which zeros out _num_ blocks starting at
146 * _blk_. In case of an error, the details of the error is returned
147 * via _ret_blk_ and _ret_count_ if they are non-NULL pointers.
148 * Returns 0 on success, and an error code on an error.
149 *
150 * As a special case, if the first argument is NULL, then it will
151 * attempt to free the static zeroizing buffer. (This is to keep
152 * programs that check for memory leaks happy.)
153 */
154#define STRIDE_LENGTH 8
Jose R. Santos73d0c4c2009-06-01 16:15:40 -0400155errcode_t ext2fs_zero_blocks2(ext2_filsys fs, blk64_t blk, int num,
156 blk64_t *ret_blk, int *ret_count)
Theodore Ts'oc8608502008-04-27 16:10:32 -0400157{
158 int j, count;
159 static char *buf;
160 errcode_t retval;
161
162 /* If fs is null, clean up the static buffer and return */
163 if (!fs) {
164 if (buf) {
165 free(buf);
166 buf = 0;
167 }
168 return 0;
169 }
170 /* Allocate the zeroizing buffer if necessary */
171 if (!buf) {
172 buf = malloc(fs->blocksize * STRIDE_LENGTH);
173 if (!buf)
174 return ENOMEM;
175 memset(buf, 0, fs->blocksize * STRIDE_LENGTH);
176 }
177 /* OK, do the write loop */
178 j=0;
179 while (j < num) {
Theodore Ts'obc507e32008-06-17 00:18:58 -0400180 if (blk % STRIDE_LENGTH) {
Theodore Ts'oc8608502008-04-27 16:10:32 -0400181 count = STRIDE_LENGTH - (blk % STRIDE_LENGTH);
Theodore Ts'obc507e32008-06-17 00:18:58 -0400182 if (count > (num - j))
183 count = num - j;
184 } else {
Theodore Ts'oc8608502008-04-27 16:10:32 -0400185 count = num - j;
186 if (count > STRIDE_LENGTH)
187 count = STRIDE_LENGTH;
188 }
Jose R. Santos73d0c4c2009-06-01 16:15:40 -0400189 retval = io_channel_write_blk64(fs->io, blk, count, buf);
Theodore Ts'oc8608502008-04-27 16:10:32 -0400190 if (retval) {
191 if (ret_count)
192 *ret_count = count;
193 if (ret_blk)
194 *ret_blk = blk;
195 return retval;
196 }
197 j += count; blk += count;
198 }
199 return 0;
200}
201
Jose R. Santos73d0c4c2009-06-01 16:15:40 -0400202errcode_t ext2fs_zero_blocks(ext2_filsys fs, blk_t blk, int num,
203 blk_t *ret_blk, int *ret_count)
204{
205 blk64_t ret_blk2;
206 errcode_t retval;
207
208 retval = ext2fs_zero_blocks2(fs, blk, num, &ret_blk2, ret_count);
209 if (retval)
210 *ret_blk = (blk_t) ret_blk2;
211 return retval;
212}
213
Theodore Ts'oc8608502008-04-27 16:10:32 -0400214/*
Theodore Ts'o4becab62001-01-03 19:22:42 +0000215 * Helper function for creating the journal using direct I/O routines
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000216 */
217struct mkjournal_struct {
218 int num_blocks;
219 int newblocks;
Valerie Aurora Henson6d8b37f2010-06-13 11:00:00 -0400220 blk64_t goal;
221 blk64_t blk_to_zero;
Theodore Ts'oc8608502008-04-27 16:10:32 -0400222 int zero_count;
Andreas Dilger6c546892011-06-11 12:17:29 -0400223 int flags;
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000224 char *buf;
225 errcode_t err;
226};
227
Theodore Ts'o54434922003-12-07 01:28:50 -0500228static int mkjournal_proc(ext2_filsys fs,
Valerie Aurora Henson6d8b37f2010-06-13 11:00:00 -0400229 blk64_t *blocknr,
230 e2_blkcnt_t blockcnt,
231 blk64_t ref_block EXT2FS_ATTR((unused)),
232 int ref_offset EXT2FS_ATTR((unused)),
233 void *priv_data)
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000234{
235 struct mkjournal_struct *es = (struct mkjournal_struct *) priv_data;
Valerie Aurora Henson6d8b37f2010-06-13 11:00:00 -0400236 blk64_t new_blk;
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000237 errcode_t retval;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400238
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000239 if (*blocknr) {
Theodore Ts'o1af01e92008-08-27 15:11:28 -0400240 es->goal = *blocknr;
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000241 return 0;
242 }
Theodore Ts'o4a2a9b72011-06-10 18:54:53 -0400243 if (blockcnt &&
244 (EXT2FS_B2C(fs, es->goal) == EXT2FS_B2C(fs, es->goal+1)))
245 new_blk = es->goal+1;
246 else {
247 es->goal &= ~EXT2FS_CLUSTER_MASK(fs);
248 retval = ext2fs_new_block2(fs, es->goal, 0, &new_blk);
249 if (retval) {
250 es->err = retval;
251 return BLOCK_ABORT;
252 }
Theodore Ts'ob2e6c862011-06-16 10:12:43 -0400253 es->newblocks++;
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000254 }
Theodore Ts'o674c0cc2008-08-27 16:23:30 -0400255 if (blockcnt >= 0)
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000256 es->num_blocks--;
257
Theodore Ts'oc8608502008-04-27 16:10:32 -0400258 retval = 0;
259 if (blockcnt <= 0)
Valerie Aurora Henson24a117a2009-09-07 21:14:24 -0400260 retval = io_channel_write_blk64(fs->io, new_blk, 1, es->buf);
Andreas Dilger6c546892011-06-11 12:17:29 -0400261 else if (!(es->flags & EXT2_MKJOURNAL_LAZYINIT)) {
Theodore Ts'oc8608502008-04-27 16:10:32 -0400262 if (es->zero_count) {
263 if ((es->blk_to_zero + es->zero_count == new_blk) &&
264 (es->zero_count < 1024))
265 es->zero_count++;
266 else {
Valerie Aurora Henson6d8b37f2010-06-13 11:00:00 -0400267 retval = ext2fs_zero_blocks2(fs,
268 es->blk_to_zero,
269 es->zero_count,
270 0, 0);
Theodore Ts'oc8608502008-04-27 16:10:32 -0400271 es->zero_count = 0;
272 }
273 }
274 if (es->zero_count == 0) {
275 es->blk_to_zero = new_blk;
276 es->zero_count = 1;
277 }
278 }
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000279
280 if (blockcnt == 0)
281 memset(es->buf, 0, fs->blocksize);
282
283 if (retval) {
284 es->err = retval;
285 return BLOCK_ABORT;
286 }
Theodore Ts'o1af01e92008-08-27 15:11:28 -0400287 *blocknr = es->goal = new_blk;
Valerie Aurora Henson48f23052009-10-25 21:46:58 -0400288 ext2fs_block_alloc_stats2(fs, new_blk, +1);
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000289
290 if (es->num_blocks == 0)
291 return (BLOCK_CHANGED | BLOCK_ABORT);
292 else
293 return BLOCK_CHANGED;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400294
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000295}
296
297/*
Theodore Ts'o4becab62001-01-03 19:22:42 +0000298 * This function creates a journal using direct I/O routines.
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000299 */
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000300static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino,
Andreas Dilger931b58e2011-06-11 12:17:29 -0400301 blk_t num_blocks, int flags)
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000302{
Theodore Ts'oa1128472001-01-16 06:56:14 +0000303 char *buf;
Theodore Ts'ob55d7392008-08-28 10:20:43 -0400304 dgrp_t group, start, end, i, log_flex;
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000305 errcode_t retval;
306 struct ext2_inode inode;
Andreas Dilger931b58e2011-06-11 12:17:29 -0400307 unsigned long long inode_size;
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000308 struct mkjournal_struct es;
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000309
Andreas Dilger931b58e2011-06-11 12:17:29 -0400310 if ((retval = ext2fs_create_journal_superblock(fs, num_blocks, flags,
311 &buf)))
Theodore Ts'oa1128472001-01-16 06:56:14 +0000312 return retval;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400313
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000314 if ((retval = ext2fs_read_bitmaps(fs)))
315 return retval;
316
Theodore Ts'o4becab62001-01-03 19:22:42 +0000317 if ((retval = ext2fs_read_inode(fs, journal_ino, &inode)))
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000318 return retval;
319
320 if (inode.i_blocks > 0)
321 return EEXIST;
322
Andreas Dilger931b58e2011-06-11 12:17:29 -0400323 es.num_blocks = num_blocks;
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000324 es.newblocks = 0;
325 es.buf = buf;
326 es.err = 0;
Andreas Dilger6c546892011-06-11 12:17:29 -0400327 es.flags = flags;
Theodore Ts'oc8608502008-04-27 16:10:32 -0400328 es.zero_count = 0;
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000329
Theodore Ts'o961306d2008-08-27 15:50:44 -0400330 if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) {
331 inode.i_flags |= EXT4_EXTENTS_FL;
332 if ((retval = ext2fs_write_inode(fs, journal_ino, &inode)))
333 return retval;
334 }
335
Theodore Ts'o1af01e92008-08-27 15:11:28 -0400336 /*
337 * Set the initial goal block to be roughly at the middle of
338 * the filesystem. Pick a group that has the largest number
339 * of free blocks.
340 */
Theodore Ts'o6493f8e2009-10-25 20:50:15 -0400341 group = ext2fs_group_of_blk2(fs, (ext2fs_blocks_count(fs->super) -
Theodore Ts'o1af01e92008-08-27 15:11:28 -0400342 fs->super->s_first_data_block) / 2);
Theodore Ts'ob55d7392008-08-28 10:20:43 -0400343 log_flex = 1 << fs->super->s_log_groups_per_flex;
344 if (fs->super->s_log_groups_per_flex && (group > log_flex)) {
345 group = group & ~(log_flex - 1);
346 while ((group < fs->group_desc_count) &&
Valerie Aurora Hensond7cca6b2009-10-25 21:43:47 -0400347 ext2fs_bg_free_blocks_count(fs, group) == 0)
Theodore Ts'ob55d7392008-08-28 10:20:43 -0400348 group++;
349 if (group == fs->group_desc_count)
350 group = 0;
351 start = group;
352 } else
353 start = (group > 0) ? group-1 : group;
Theodore Ts'o1af01e92008-08-27 15:11:28 -0400354 end = ((group+1) < fs->group_desc_count) ? group+1 : group;
355 group = start;
356 for (i=start+1; i <= end; i++)
Valerie Aurora Hensond7cca6b2009-10-25 21:43:47 -0400357 if (ext2fs_bg_free_blocks_count(fs, i) >
358 ext2fs_bg_free_blocks_count(fs, group))
Theodore Ts'o1af01e92008-08-27 15:11:28 -0400359 group = i;
360
Theodore Ts'o027b0572013-01-03 13:42:38 -0500361 es.goal = ext2fs_group_first_block2(fs, group);
Valerie Aurora Henson6d8b37f2010-06-13 11:00:00 -0400362 retval = ext2fs_block_iterate3(fs, journal_ino, BLOCK_FLAG_APPEND,
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000363 0, mkjournal_proc, &es);
Theodore Ts'oa1128472001-01-16 06:56:14 +0000364 if (es.err) {
365 retval = es.err;
366 goto errout;
367 }
Theodore Ts'oc8608502008-04-27 16:10:32 -0400368 if (es.zero_count) {
Valerie Aurora Henson6d8b37f2010-06-13 11:00:00 -0400369 retval = ext2fs_zero_blocks2(fs, es.blk_to_zero,
Theodore Ts'oc8608502008-04-27 16:10:32 -0400370 es.zero_count, 0, 0);
371 if (retval)
372 goto errout;
373 }
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000374
Theodore Ts'o4becab62001-01-03 19:22:42 +0000375 if ((retval = ext2fs_read_inode(fs, journal_ino, &inode)))
Theodore Ts'oa1128472001-01-16 06:56:14 +0000376 goto errout;
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000377
Andreas Dilger931b58e2011-06-11 12:17:29 -0400378 inode_size = (unsigned long long)fs->blocksize * num_blocks;
379 inode.i_size = inode_size & 0xFFFFFFFF;
380 inode.i_size_high = (inode_size >> 32) & 0xFFFFFFFF;
381 if (inode.i_size_high)
382 fs->super->s_feature_ro_compat |=
383 EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
Theodore Ts'o1ca10592008-04-09 11:39:11 -0400384 ext2fs_iblk_add_blocks(fs, &inode, es.newblocks);
Theodore Ts'o32138182005-09-24 20:14:51 -0400385 inode.i_mtime = inode.i_ctime = fs->now ? fs->now : time(0);
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000386 inode.i_links_count = 1;
387 inode.i_mode = LINUX_S_IFREG | 0600;
388
Eric Sandeen827c1882009-06-16 21:50:53 -0500389 if ((retval = ext2fs_write_new_inode(fs, journal_ino, &inode)))
Theodore Ts'oa1128472001-01-16 06:56:14 +0000390 goto errout;
391 retval = 0;
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000392
Theodore Ts'oa435ec32003-08-21 00:40:26 -0400393 memcpy(fs->super->s_jnl_blocks, inode.i_block, EXT2_N_BLOCKS*4);
Andreas Dilger931b58e2011-06-11 12:17:29 -0400394 fs->super->s_jnl_blocks[15] = inode.i_size_high;
Theodore Ts'oa435ec32003-08-21 00:40:26 -0400395 fs->super->s_jnl_blocks[16] = inode.i_size;
396 fs->super->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS;
397 ext2fs_mark_super_dirty(fs);
398
Theodore Ts'oa1128472001-01-16 06:56:14 +0000399errout:
Namhyung Kim91dc3f02010-11-29 17:55:16 +0900400 ext2fs_zero_blocks2(0, 0, 0, 0, 0);
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -0400401 ext2fs_free_mem(&buf);
Theodore Ts'oa1128472001-01-16 06:56:14 +0000402 return retval;
Theodore Ts'o4becab62001-01-03 19:22:42 +0000403}
404
405/*
Theodore Ts'o56d12362007-06-21 11:59:06 -0400406 * Find a reasonable journal file size (in blocks) given the number of blocks
407 * in the filesystem. For very small filesystems, it is not reasonable to
408 * have a journal that fills more than half of the filesystem.
409 */
Andreas Dilger931b58e2011-06-11 12:17:29 -0400410int ext2fs_default_journal_size(__u64 num_blocks)
Theodore Ts'o56d12362007-06-21 11:59:06 -0400411{
Andreas Dilger931b58e2011-06-11 12:17:29 -0400412 if (num_blocks < 2048)
Theodore Ts'o56d12362007-06-21 11:59:06 -0400413 return -1;
Andreas Dilger931b58e2011-06-11 12:17:29 -0400414 if (num_blocks < 32768)
Theodore Ts'o56d12362007-06-21 11:59:06 -0400415 return (1024);
Andreas Dilger931b58e2011-06-11 12:17:29 -0400416 if (num_blocks < 256*1024)
Theodore Ts'o56d12362007-06-21 11:59:06 -0400417 return (4096);
Andreas Dilger931b58e2011-06-11 12:17:29 -0400418 if (num_blocks < 512*1024)
Theodore Ts'o56d12362007-06-21 11:59:06 -0400419 return (8192);
Andreas Dilger931b58e2011-06-11 12:17:29 -0400420 if (num_blocks < 1024*1024)
Theodore Ts'o56d12362007-06-21 11:59:06 -0400421 return (16384);
422 return 32768;
423}
424
425/*
Theodore Ts'o4becab62001-01-03 19:22:42 +0000426 * This function adds a journal device to a filesystem
427 */
Theodore Ts'oa1128472001-01-16 06:56:14 +0000428errcode_t ext2fs_add_journal_device(ext2_filsys fs, ext2_filsys journal_dev)
Theodore Ts'o4becab62001-01-03 19:22:42 +0000429{
430 struct stat st;
431 errcode_t retval;
Theodore Ts'oa1128472001-01-16 06:56:14 +0000432 char buf[1024];
433 journal_superblock_t *jsb;
Theodore Ts'o54434922003-12-07 01:28:50 -0500434 int start;
435 __u32 i, nr_users;
Theodore Ts'o4becab62001-01-03 19:22:42 +0000436
437 /* Make sure the device exists and is a block device */
Theodore Ts'o02088862001-01-18 01:44:19 +0000438 if (stat(journal_dev->device_name, &st) < 0)
Theodore Ts'o4becab62001-01-03 19:22:42 +0000439 return errno;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400440
Theodore Ts'o4becab62001-01-03 19:22:42 +0000441 if (!S_ISBLK(st.st_mode))
Theodore Ts'o03603942001-04-17 00:53:25 +0000442 return EXT2_ET_JOURNAL_NOT_BLOCK; /* Must be a block device */
Theodore Ts'o4becab62001-01-03 19:22:42 +0000443
Theodore Ts'oa1128472001-01-16 06:56:14 +0000444 /* Get the journal superblock */
Theodore Ts'o36131b32001-07-26 23:44:39 -0400445 start = 1;
446 if (journal_dev->blocksize == 1024)
447 start++;
Valerie Aurora Henson24a117a2009-09-07 21:14:24 -0400448 if ((retval = io_channel_read_blk64(journal_dev->io, start, -1024,
449 buf)))
Theodore Ts'o4becab62001-01-03 19:22:42 +0000450 return retval;
451
Theodore Ts'oa1128472001-01-16 06:56:14 +0000452 jsb = (journal_superblock_t *) buf;
453 if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) ||
454 (jsb->s_header.h_blocktype != (unsigned) ntohl(JFS_SUPERBLOCK_V2)))
Theodore Ts'o03603942001-04-17 00:53:25 +0000455 return EXT2_ET_NO_JOURNAL_SB;
Theodore Ts'o4becab62001-01-03 19:22:42 +0000456
Theodore Ts'o54434922003-12-07 01:28:50 -0500457 if (ntohl(jsb->s_blocksize) != (unsigned long) fs->blocksize)
Theodore Ts'oa1128472001-01-16 06:56:14 +0000458 return EXT2_ET_UNEXPECTED_BLOCK_SIZE;
459
460 /* Check and see if this filesystem has already been added */
461 nr_users = ntohl(jsb->s_nr_users);
462 for (i=0; i < nr_users; i++) {
463 if (memcmp(fs->super->s_uuid,
464 &jsb->s_users[i*16], 16) == 0)
465 break;
466 }
467 if (i >= nr_users) {
468 memcpy(&jsb->s_users[nr_users*16],
469 fs->super->s_uuid, 16);
470 jsb->s_nr_users = htonl(nr_users+1);
471 }
472
473 /* Writeback the journal superblock */
Valerie Aurora Henson24a117a2009-09-07 21:14:24 -0400474 if ((retval = io_channel_write_blk64(journal_dev->io, start, -1024, buf)))
Theodore Ts'o4becab62001-01-03 19:22:42 +0000475 return retval;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400476
Theodore Ts'o4becab62001-01-03 19:22:42 +0000477 fs->super->s_journal_inum = 0;
478 fs->super->s_journal_dev = st.st_rdev;
Theodore Ts'oa1128472001-01-16 06:56:14 +0000479 memcpy(fs->super->s_journal_uuid, jsb->s_uuid,
Theodore Ts'o4becab62001-01-03 19:22:42 +0000480 sizeof(fs->super->s_journal_uuid));
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000481 fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
Theodore Ts'o4becab62001-01-03 19:22:42 +0000482 ext2fs_mark_super_dirty(fs);
Theodore Ts'ocdaf1fa2001-01-05 22:23:22 +0000483 return 0;
Theodore Ts'o4becab62001-01-03 19:22:42 +0000484}
485
486/*
487 * This function adds a journal inode to a filesystem, using either
488 * POSIX routines if the filesystem is mounted, or using direct I/O
489 * functions if it is not.
490 */
Andreas Dilger931b58e2011-06-11 12:17:29 -0400491errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t num_blocks, int flags)
Theodore Ts'o4becab62001-01-03 19:22:42 +0000492{
493 errcode_t retval;
Theodore Ts'o31dbecd2001-01-11 04:54:39 +0000494 ext2_ino_t journal_ino;
Theodore Ts'o4becab62001-01-03 19:22:42 +0000495 struct stat st;
496 char jfile[1024];
Andreas Dilger1d6fd6d2012-11-29 05:47:52 -0700497 int mount_flags;
Theodore Ts'o9b9a7802005-12-10 21:50:30 -0500498 int fd = -1;
Theodore Ts'o4becab62001-01-03 19:22:42 +0000499
Theodore Ts'o304e11c2012-04-05 12:30:02 -0700500 if (flags & EXT2_MKJOURNAL_NO_MNT_CHECK)
501 mount_flags = 0;
502 else if ((retval = ext2fs_check_mount_point(fs->device_name,
503 &mount_flags,
504 jfile, sizeof(jfile)-10)))
Theodore Ts'o4becab62001-01-03 19:22:42 +0000505 return retval;
506
507 if (mount_flags & EXT2_MF_MOUNTED) {
Andreas Dilger1d6fd6d2012-11-29 05:47:52 -0700508#if HAVE_EXT2_IOCTLS
509 int f = 0;
510#endif
Theodore Ts'o4becab62001-01-03 19:22:42 +0000511 strcat(jfile, "/.journal");
512
Theodore Ts'o5bc28df2001-11-09 17:34:54 -0500513 /*
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400514 * If .../.journal already exists, make sure any
Theodore Ts'o5bc28df2001-11-09 17:34:54 -0500515 * immutable or append-only flags are cleared.
516 */
517#if defined(HAVE_CHFLAGS) && defined(UF_NODUMP)
518 (void) chflags (jfile, 0);
519#else
520#if HAVE_EXT2_IOCTLS
521 fd = open(jfile, O_RDONLY);
522 if (fd >= 0) {
Theodore Ts'o5bc28df2001-11-09 17:34:54 -0500523 ioctl(fd, EXT2_IOC_SETFLAGS, &f);
524 close(fd);
525 }
526#endif
527#endif
528
Theodore Ts'o4becab62001-01-03 19:22:42 +0000529 /* Create the journal file */
530 if ((fd = open(jfile, O_CREAT|O_WRONLY, 0600)) < 0)
531 return errno;
Theodore Ts'o4becab62001-01-03 19:22:42 +0000532
Andreas Dilger6c546892011-06-11 12:17:29 -0400533 /* Note that we can't do lazy journal initialization for mounted
534 * filesystems, since the zero writing is also allocating the
535 * journal blocks. We could use fallocate, but not all kernels
536 * support that, and creating a journal on a mounted ext2
537 * filesystems is extremely rare these days... Ignore it. */
538 flags &= ~EXT2_MKJOURNAL_LAZYINIT;
539
Andreas Dilger931b58e2011-06-11 12:17:29 -0400540 if ((retval = write_journal_file(fs, jfile, num_blocks, flags)))
Theodore Ts'ob23520d2001-06-22 21:52:14 -0400541 goto errout;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400542
Theodore Ts'o4becab62001-01-03 19:22:42 +0000543 /* Get inode number of the journal file */
Theodore Ts'o8bafedb2009-08-25 10:07:16 -0400544 if (fstat(fd, &st) < 0) {
545 retval = errno;
Theodore Ts'ob23520d2001-06-22 21:52:14 -0400546 goto errout;
Theodore Ts'o8bafedb2009-08-25 10:07:16 -0400547 }
Theodore Ts'o4becab62001-01-03 19:22:42 +0000548
Theodore Ts'o78332622001-06-22 21:20:47 -0400549#if defined(HAVE_CHFLAGS) && defined(UF_NODUMP)
Theodore Ts'o349a4842001-06-11 00:49:29 +0000550 retval = fchflags (fd, UF_NODUMP|UF_IMMUTABLE);
551#else
552#if HAVE_EXT2_IOCTLS
Theodore Ts'o8bafedb2009-08-25 10:07:16 -0400553 if (ioctl(fd, EXT2_IOC_GETFLAGS, &f) < 0) {
554 retval = errno;
555 goto errout;
556 }
557 f |= EXT2_NODUMP_FL | EXT2_IMMUTABLE_FL;
Theodore Ts'o349a4842001-06-11 00:49:29 +0000558 retval = ioctl(fd, EXT2_IOC_SETFLAGS, &f);
559#endif
560#endif
Theodore Ts'o8bafedb2009-08-25 10:07:16 -0400561 if (retval) {
562 retval = errno;
Theodore Ts'ob23520d2001-06-22 21:52:14 -0400563 goto errout;
Theodore Ts'o8bafedb2009-08-25 10:07:16 -0400564 }
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400565
Theodore Ts'o8bafedb2009-08-25 10:07:16 -0400566 if (close(fd) < 0) {
567 retval = errno;
568 fd = -1;
569 goto errout;
570 }
Theodore Ts'o4becab62001-01-03 19:22:42 +0000571 journal_ino = st.st_ino;
572 } else {
Theodore Ts'ocef2ac12006-04-04 19:23:41 -0400573 if ((mount_flags & EXT2_MF_BUSY) &&
574 !(fs->flags & EXT2_FLAG_EXCLUSIVE)) {
Theodore Ts'o29af3142005-07-19 15:04:22 -0500575 retval = EBUSY;
576 goto errout;
577 }
Theodore Ts'o4becab62001-01-03 19:22:42 +0000578 journal_ino = EXT2_JOURNAL_INO;
579 if ((retval = write_journal_inode(fs, journal_ino,
Andreas Dilger931b58e2011-06-11 12:17:29 -0400580 num_blocks, flags)))
Theodore Ts'o4becab62001-01-03 19:22:42 +0000581 return retval;
582 }
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400583
Theodore Ts'o4becab62001-01-03 19:22:42 +0000584 fs->super->s_journal_inum = journal_ino;
585 fs->super->s_journal_dev = 0;
586 memset(fs->super->s_journal_uuid, 0,
587 sizeof(fs->super->s_journal_uuid));
588 fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000589
590 ext2fs_mark_super_dirty(fs);
591 return 0;
Theodore Ts'ob23520d2001-06-22 21:52:14 -0400592errout:
Theodore Ts'o9b9a7802005-12-10 21:50:30 -0500593 if (fd > 0)
594 close(fd);
Theodore Ts'ob23520d2001-06-22 21:52:14 -0400595 return retval;
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000596}
597
598#ifdef DEBUG
599main(int argc, char **argv)
600{
601 errcode_t retval;
602 char *device_name;
Andreas Dilger931b58e2011-06-11 12:17:29 -0400603 ext2_filsys fs;
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000604
605 if (argc < 2) {
606 fprintf(stderr, "Usage: %s filesystem\n", argv[0]);
607 exit(1);
608 }
609 device_name = argv[1];
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400610
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000611 retval = ext2fs_open (device_name, EXT2_FLAG_RW, 0, 0,
612 unix_io_manager, &fs);
613 if (retval) {
614 com_err(argv[0], retval, "while opening %s", device_name);
615 exit(1);
616 }
617
Theodore Ts'o304e11c2012-04-05 12:30:02 -0700618 retval = ext2fs_add_journal_inode(fs, 1024, 0);
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000619 if (retval) {
620 com_err(argv[0], retval, "while adding journal to %s",
621 device_name);
622 exit(1);
623 }
624 retval = ext2fs_flush(fs);
625 if (retval) {
626 printf("Warning, had trouble writing out superblocks.\n");
627 }
628 ext2fs_close(fs);
629 exit(0);
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400630
Theodore Ts'od3cd93c2000-10-24 18:33:16 +0000631}
632#endif