mkjournal.c revision 7a34cb01a97d39842c610dd609b525eadd0a1de2
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 "e2p/e2p.h" 39#include "ext2fs.h" 40#include "jfs_user.h" 41 42/* 43 * This function automatically sets up the journal superblock and 44 * returns it as an allocated block. 45 */ 46errcode_t ext2fs_create_journal_superblock(ext2_filsys fs, 47 __u32 size, int flags, 48 char **ret_jsb) 49{ 50 errcode_t retval; 51 journal_superblock_t *jsb; 52 53 if (size < 1024) 54 return EXT2_ET_JOURNAL_TOO_SMALL; 55 56 if ((retval = ext2fs_get_mem(fs->blocksize, (void **) &jsb))) 57 return retval; 58 59 memset (jsb, 0, fs->blocksize); 60 61 jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER); 62 if (flags & EXT2_MKJOURNAL_V1_SUPER) 63 jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V1); 64 else 65 jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2); 66 jsb->s_blocksize = htonl(fs->blocksize); 67 jsb->s_maxlen = htonl(size); 68 jsb->s_nr_users = htonl(1); 69 jsb->s_first = htonl(1); 70 jsb->s_sequence = htonl(1); 71 memcpy(jsb->s_uuid, fs->super->s_uuid, sizeof(fs->super->s_uuid)); 72 /* 73 * If we're creating an external journal device, we need to 74 * adjust these fields. 75 */ 76 if (fs->super->s_feature_incompat & 77 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) 78 jsb->s_nr_users = 0; 79 80 *ret_jsb = (char *) jsb; 81 return 0; 82} 83 84/* 85 * This function writes a journal using POSIX routines. It is used 86 * for creating external journals and creating journals on live 87 * filesystems. 88 */ 89static errcode_t write_journal_file(ext2_filsys fs, char *filename, 90 blk_t size, int flags) 91{ 92 errcode_t retval; 93 char *buf = 0; 94 int i, fd, ret_size; 95 96 if ((retval = ext2fs_create_journal_superblock(fs, size, flags, &buf))) 97 return retval; 98 99 /* Open the device or journal file */ 100 if ((fd = open(filename, O_WRONLY)) < 0) { 101 retval = errno; 102 goto errout; 103 } 104 105 /* Write the superblock out */ 106 retval = EXT2_ET_SHORT_WRITE; 107 ret_size = write(fd, buf, fs->blocksize); 108 if (ret_size < 0) { 109 retval = errno; 110 goto errout; 111 } 112 if (ret_size != fs->blocksize) 113 goto errout; 114 memset(buf, 0, fs->blocksize); 115 116 for (i = 1; i < size; i++) { 117 ret_size = write(fd, buf, fs->blocksize); 118 if (ret_size < 0) { 119 retval = errno; 120 goto errout; 121 } 122 if (ret_size != fs->blocksize) 123 goto errout; 124 } 125 close(fd); 126 127 retval = 0; 128errout: 129 ext2fs_free_mem((void **) &buf); 130 return retval; 131} 132 133/* 134 * Helper function for creating the journal using direct I/O routines 135 */ 136struct mkjournal_struct { 137 int num_blocks; 138 int newblocks; 139 char *buf; 140 errcode_t err; 141}; 142 143static int mkjournal_proc(ext2_filsys fs, 144 blk_t *blocknr, 145 e2_blkcnt_t blockcnt, 146 blk_t ref_block, 147 int ref_offset, 148 void *priv_data) 149{ 150 struct mkjournal_struct *es = (struct mkjournal_struct *) priv_data; 151 blk_t new_blk; 152 static blk_t last_blk = 0; 153 errcode_t retval; 154 int group; 155 156 if (*blocknr) { 157 last_blk = *blocknr; 158 return 0; 159 } 160 retval = ext2fs_new_block(fs, last_blk, 0, &new_blk); 161 if (retval) { 162 es->err = retval; 163 return BLOCK_ABORT; 164 } 165 if (blockcnt > 0) 166 es->num_blocks--; 167 168 es->newblocks++; 169 retval = io_channel_write_blk(fs->io, new_blk, 1, es->buf); 170 171 if (blockcnt == 0) 172 memset(es->buf, 0, fs->blocksize); 173 174 if (retval) { 175 es->err = retval; 176 return BLOCK_ABORT; 177 } 178 *blocknr = new_blk; 179 ext2fs_mark_block_bitmap(fs->block_map, new_blk); 180 ext2fs_mark_bb_dirty(fs); 181 group = ext2fs_group_of_blk(fs, new_blk); 182 fs->group_desc[group].bg_free_blocks_count--; 183 fs->super->s_free_blocks_count--; 184 ext2fs_mark_super_dirty(fs); 185 186 if (es->num_blocks == 0) 187 return (BLOCK_CHANGED | BLOCK_ABORT); 188 else 189 return BLOCK_CHANGED; 190 191} 192 193/* 194 * This function creates a journal using direct I/O routines. 195 */ 196static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino, 197 blk_t size, int flags) 198{ 199 char *buf; 200 errcode_t retval; 201 struct ext2_inode inode; 202 struct mkjournal_struct es; 203 204 if ((retval = ext2fs_create_journal_superblock(fs, size, flags, &buf))) 205 return retval; 206 207 if ((retval = ext2fs_read_bitmaps(fs))) 208 return retval; 209 210 if ((retval = ext2fs_read_inode(fs, journal_ino, &inode))) 211 return retval; 212 213 if (inode.i_blocks > 0) 214 return EEXIST; 215 216 es.num_blocks = size; 217 es.newblocks = 0; 218 es.buf = buf; 219 es.err = 0; 220 221 retval = ext2fs_block_iterate2(fs, journal_ino, BLOCK_FLAG_APPEND, 222 0, mkjournal_proc, &es); 223 if (es.err) { 224 retval = es.err; 225 goto errout; 226 } 227 228 if ((retval = ext2fs_read_inode(fs, journal_ino, &inode))) 229 goto errout; 230 231 inode.i_size += fs->blocksize * size; 232 inode.i_blocks += (fs->blocksize / 512) * es.newblocks; 233 inode.i_mtime = inode.i_ctime = time(0); 234 inode.i_links_count = 1; 235 inode.i_mode = LINUX_S_IFREG | 0600; 236 237 if ((retval = ext2fs_write_inode(fs, journal_ino, &inode))) 238 goto errout; 239 retval = 0; 240 241errout: 242 ext2fs_free_mem((void **) &buf); 243 return retval; 244} 245 246/* 247 * This function adds a journal device to a filesystem 248 */ 249errcode_t ext2fs_add_journal_device(ext2_filsys fs, ext2_filsys journal_dev) 250{ 251 struct stat st; 252 errcode_t retval; 253 char buf[1024]; 254 journal_superblock_t *jsb; 255 int i; 256 __u32 nr_users; 257 258 /* Make sure the device exists and is a block device */ 259 if (stat(journal_dev->device_name, &st) < 0) 260 return errno; 261 262 if (!S_ISBLK(st.st_mode)) 263 return EXT2_ET_JOURNAL_NOT_BLOCK; /* Must be a block device */ 264 265 /* Get the journal superblock */ 266 if ((retval = io_channel_read_blk(journal_dev->io, 1, -1024, buf))) 267 return retval; 268 269 jsb = (journal_superblock_t *) buf; 270 if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) || 271 (jsb->s_header.h_blocktype != (unsigned) ntohl(JFS_SUPERBLOCK_V2))) 272 return EXT2_ET_NO_JOURNAL_SB; 273 274 if (ntohl(jsb->s_blocksize) != fs->blocksize) 275 return EXT2_ET_UNEXPECTED_BLOCK_SIZE; 276 277 /* Check and see if this filesystem has already been added */ 278 nr_users = ntohl(jsb->s_nr_users); 279 for (i=0; i < nr_users; i++) { 280 if (memcmp(fs->super->s_uuid, 281 &jsb->s_users[i*16], 16) == 0) 282 break; 283 } 284 if (i >= nr_users) { 285 memcpy(&jsb->s_users[nr_users*16], 286 fs->super->s_uuid, 16); 287 jsb->s_nr_users = htonl(nr_users+1); 288 } 289 290 /* Writeback the journal superblock */ 291 if ((retval = io_channel_write_blk(journal_dev->io, 1, -1024, buf))) 292 return retval; 293 294 fs->super->s_journal_inum = 0; 295 fs->super->s_journal_dev = st.st_rdev; 296 memcpy(fs->super->s_journal_uuid, jsb->s_uuid, 297 sizeof(fs->super->s_journal_uuid)); 298 fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL; 299 ext2fs_mark_super_dirty(fs); 300 return 0; 301} 302 303/* 304 * This function adds a journal inode to a filesystem, using either 305 * POSIX routines if the filesystem is mounted, or using direct I/O 306 * functions if it is not. 307 */ 308errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t size, int flags) 309{ 310 errcode_t retval; 311 ext2_ino_t journal_ino; 312 struct stat st; 313 char jfile[1024]; 314 int fd, mount_flags; 315 316 if ((retval = ext2fs_check_mount_point(fs->device_name, &mount_flags, 317 jfile, sizeof(jfile)-10))) 318 return retval; 319 320 if (mount_flags & EXT2_MF_MOUNTED) { 321 strcat(jfile, "/.journal"); 322 323 /* Create the journal file */ 324 if ((fd = open(jfile, O_CREAT|O_WRONLY, 0600)) < 0) 325 return errno; 326 close(fd); 327 328 if ((retval = write_journal_file(fs, jfile, size, flags))) 329 return retval; 330 331 /* Get inode number of the journal file */ 332 if (stat(jfile, &st) < 0) 333 return errno; 334 335 if ((retval = fsetflags(jfile, 336 EXT2_NODUMP_FL | EXT2_IMMUTABLE_FL))) 337 return retval; 338 339 journal_ino = st.st_ino; 340 } else { 341 journal_ino = EXT2_JOURNAL_INO; 342 if ((retval = write_journal_inode(fs, journal_ino, 343 size, flags))) 344 return retval; 345 } 346 347 fs->super->s_journal_inum = journal_ino; 348 fs->super->s_journal_dev = 0; 349 memset(fs->super->s_journal_uuid, 0, 350 sizeof(fs->super->s_journal_uuid)); 351 fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL; 352 353 ext2fs_mark_super_dirty(fs); 354 return 0; 355} 356 357#ifdef DEBUG 358main(int argc, char **argv) 359{ 360 errcode_t retval; 361 char *device_name; 362 ext2_filsys fs; 363 364 if (argc < 2) { 365 fprintf(stderr, "Usage: %s filesystem\n", argv[0]); 366 exit(1); 367 } 368 device_name = argv[1]; 369 370 retval = ext2fs_open (device_name, EXT2_FLAG_RW, 0, 0, 371 unix_io_manager, &fs); 372 if (retval) { 373 com_err(argv[0], retval, "while opening %s", device_name); 374 exit(1); 375 } 376 377 retval = ext2fs_add_journal_inode(fs, 1024); 378 if (retval) { 379 com_err(argv[0], retval, "while adding journal to %s", 380 device_name); 381 exit(1); 382 } 383 retval = ext2fs_flush(fs); 384 if (retval) { 385 printf("Warning, had trouble writing out superblocks.\n"); 386 } 387 ext2fs_close(fs); 388 exit(0); 389 390} 391#endif 392