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