mkjournal.c revision 9b9a780f5a5823865f62f0c9fd194d262f63a06f
15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/* 253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) * mkjournal.c --- make a journal for a filesystem 35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2000 Theodore Ts'o. 55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * %Begin-Header% 75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * This file may be redistributed under the terms of the GNU Public 85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * License. 95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * %End-Header% 105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */ 115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <stdio.h> 135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <string.h> 145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#if HAVE_UNISTD_H 155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <unistd.h> 165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#endif 175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#if HAVE_ERRNO_H 185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <errno.h> 195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#endif 205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <fcntl.h> 215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <time.h> 225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#if HAVE_SYS_STAT_H 235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <sys/stat.h> 245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#endif 255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#if HAVE_SYS_TYPES_H 265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <sys/types.h> 275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#endif 285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#if HAVE_SYS_IOCTL_H 295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <sys/ioctl.h> 305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#endif 31521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)#if HAVE_NETINET_IN_H 32591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch#include <netinet/in.h> 335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#endif 341e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) 35a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch#include "ext2_fs.h" 365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "e2p/e2p.h" 37c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)#include "ext2fs.h" 385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "jfs_user.h" 39591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch 40521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)/* 41521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles) * This function automatically sets up the journal superblock and 425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * returns it as an allocated block. 43591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch */ 44521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)errcode_t ext2fs_create_journal_superblock(ext2_filsys fs, 45591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch __u32 size, int flags, 46521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles) char **ret_jsb) 475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 48d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) errcode_t retval; 49521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles) journal_superblock_t *jsb; 50d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) 51521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles) if (size < 1024) 52591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch return EXT2_ET_JOURNAL_TOO_SMALL; 53d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) 54521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles) if ((retval = ext2fs_get_mem(fs->blocksize, &jsb))) 55d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) return retval; 56521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles) 5753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) memset (jsb, 0, fs->blocksize); 58a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch 59521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles) jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER); 60d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) if (flags & EXT2_MKJOURNAL_V1_SUPER) 61521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles) jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V1); 625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) else 63a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2); 64521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles) jsb->s_blocksize = htonl(fs->blocksize); 65521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles) jsb->s_maxlen = htonl(size); 66a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch jsb->s_nr_users = htonl(1); 67521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles) jsb->s_first = htonl(1); 6853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) jsb->s_sequence = htonl(1); 695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) memcpy(jsb->s_uuid, fs->super->s_uuid, sizeof(fs->super->s_uuid)); 70d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) /* 71d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) * If we're creating an external journal device, we need to 72d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) * adjust these fields. 73323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles) */ 74d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) if (fs->super->s_feature_incompat & 75d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) { 76c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles) 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 fd, ret_size; 98 blk_t i; 99 100 if ((retval = ext2fs_create_journal_superblock(fs, size, flags, &buf))) 101 return retval; 102 103 /* Open the device or journal file */ 104 if ((fd = open(filename, O_WRONLY)) < 0) { 105 retval = errno; 106 goto errout; 107 } 108 109 /* Write the superblock out */ 110 retval = EXT2_ET_SHORT_WRITE; 111 ret_size = write(fd, buf, fs->blocksize); 112 if (ret_size < 0) { 113 retval = errno; 114 goto errout; 115 } 116 if (ret_size != (int) fs->blocksize) 117 goto errout; 118 memset(buf, 0, fs->blocksize); 119 120 for (i = 1; i < size; i++) { 121 ret_size = write(fd, buf, fs->blocksize); 122 if (ret_size < 0) { 123 retval = errno; 124 goto errout; 125 } 126 if (ret_size != (int) fs->blocksize) 127 goto errout; 128 } 129 close(fd); 130 131 retval = 0; 132errout: 133 ext2fs_free_mem(&buf); 134 return retval; 135} 136 137/* 138 * Helper function for creating the journal using direct I/O routines 139 */ 140struct mkjournal_struct { 141 int num_blocks; 142 int newblocks; 143 char *buf; 144 errcode_t err; 145}; 146 147static int mkjournal_proc(ext2_filsys fs, 148 blk_t *blocknr, 149 e2_blkcnt_t blockcnt, 150 blk_t ref_block EXT2FS_ATTR((unused)), 151 int ref_offset EXT2FS_ATTR((unused)), 152 void *priv_data) 153{ 154 struct mkjournal_struct *es = (struct mkjournal_struct *) priv_data; 155 blk_t new_blk; 156 static blk_t last_blk = 0; 157 errcode_t retval; 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_block_alloc_stats(fs, new_blk, +1); 184 185 if (es->num_blocks == 0) 186 return (BLOCK_CHANGED | BLOCK_ABORT); 187 else 188 return BLOCK_CHANGED; 189 190} 191 192/* 193 * This function creates a journal using direct I/O routines. 194 */ 195static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino, 196 blk_t size, int flags) 197{ 198 char *buf; 199 errcode_t retval; 200 struct ext2_inode inode; 201 struct mkjournal_struct es; 202 203 if ((retval = ext2fs_create_journal_superblock(fs, size, flags, &buf))) 204 return retval; 205 206 if ((retval = ext2fs_read_bitmaps(fs))) 207 return retval; 208 209 if ((retval = ext2fs_read_inode(fs, journal_ino, &inode))) 210 return retval; 211 212 if (inode.i_blocks > 0) 213 return EEXIST; 214 215 es.num_blocks = size; 216 es.newblocks = 0; 217 es.buf = buf; 218 es.err = 0; 219 220 retval = ext2fs_block_iterate2(fs, journal_ino, BLOCK_FLAG_APPEND, 221 0, mkjournal_proc, &es); 222 if (es.err) { 223 retval = es.err; 224 goto errout; 225 } 226 227 if ((retval = ext2fs_read_inode(fs, journal_ino, &inode))) 228 goto errout; 229 230 inode.i_size += fs->blocksize * size; 231 inode.i_blocks += (fs->blocksize / 512) * es.newblocks; 232 inode.i_mtime = inode.i_ctime = fs->now ? fs->now : time(0); 233 inode.i_links_count = 1; 234 inode.i_mode = LINUX_S_IFREG | 0600; 235 236 if ((retval = ext2fs_write_inode(fs, journal_ino, &inode))) 237 goto errout; 238 retval = 0; 239 240 memcpy(fs->super->s_jnl_blocks, inode.i_block, EXT2_N_BLOCKS*4); 241 fs->super->s_jnl_blocks[16] = inode.i_size; 242 fs->super->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS; 243 ext2fs_mark_super_dirty(fs); 244 245errout: 246 ext2fs_free_mem(&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 start; 260 __u32 i, 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) != (unsigned long) 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 mount_flags, f; 322 int fd = -1; 323 324 if ((retval = ext2fs_check_mount_point(fs->device_name, &mount_flags, 325 jfile, sizeof(jfile)-10))) 326 return retval; 327 328 if (mount_flags & EXT2_MF_MOUNTED) { 329 strcat(jfile, "/.journal"); 330 331 /* 332 * If .../.journal already exists, make sure any 333 * immutable or append-only flags are cleared. 334 */ 335#if defined(HAVE_CHFLAGS) && defined(UF_NODUMP) 336 (void) chflags (jfile, 0); 337#else 338#if HAVE_EXT2_IOCTLS 339 fd = open(jfile, O_RDONLY); 340 if (fd >= 0) { 341 f = 0; 342 ioctl(fd, EXT2_IOC_SETFLAGS, &f); 343 close(fd); 344 } 345#endif 346#endif 347 348 /* Create the journal file */ 349 if ((fd = open(jfile, O_CREAT|O_WRONLY, 0600)) < 0) 350 return errno; 351 352 if ((retval = write_journal_file(fs, jfile, size, flags))) 353 goto errout; 354 355 /* Get inode number of the journal file */ 356 if (fstat(fd, &st) < 0) 357 goto errout; 358 359#if defined(HAVE_CHFLAGS) && defined(UF_NODUMP) 360 retval = fchflags (fd, UF_NODUMP|UF_IMMUTABLE); 361#else 362#if HAVE_EXT2_IOCTLS 363 f = EXT2_NODUMP_FL | EXT2_IMMUTABLE_FL; 364 retval = ioctl(fd, EXT2_IOC_SETFLAGS, &f); 365#endif 366#endif 367 if (retval) 368 goto errout; 369 370 close(fd); 371 journal_ino = st.st_ino; 372 } else { 373 if (mount_flags & EXT2_MF_BUSY) { 374 retval = EBUSY; 375 goto errout; 376 } 377 journal_ino = EXT2_JOURNAL_INO; 378 if ((retval = write_journal_inode(fs, journal_ino, 379 size, flags))) 380 return retval; 381 } 382 383 fs->super->s_journal_inum = journal_ino; 384 fs->super->s_journal_dev = 0; 385 memset(fs->super->s_journal_uuid, 0, 386 sizeof(fs->super->s_journal_uuid)); 387 fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL; 388 389 ext2fs_mark_super_dirty(fs); 390 return 0; 391errout: 392 if (fd > 0) 393 close(fd); 394 return retval; 395} 396 397#ifdef DEBUG 398main(int argc, char **argv) 399{ 400 errcode_t retval; 401 char *device_name; 402 ext2_filsys fs; 403 404 if (argc < 2) { 405 fprintf(stderr, "Usage: %s filesystem\n", argv[0]); 406 exit(1); 407 } 408 device_name = argv[1]; 409 410 retval = ext2fs_open (device_name, EXT2_FLAG_RW, 0, 0, 411 unix_io_manager, &fs); 412 if (retval) { 413 com_err(argv[0], retval, "while opening %s", device_name); 414 exit(1); 415 } 416 417 retval = ext2fs_add_journal_inode(fs, 1024); 418 if (retval) { 419 com_err(argv[0], retval, "while adding journal to %s", 420 device_name); 421 exit(1); 422 } 423 retval = ext2fs_flush(fs); 424 if (retval) { 425 printf("Warning, had trouble writing out superblocks.\n"); 426 } 427 ext2fs_close(fs); 428 exit(0); 429 430} 431#endif 432