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