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