mkjournal.c revision 31dbecd482405e0d3a67eb58e1a1c8cb9f2ad83e
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 42static void init_journal_superblock(journal_superblock_t *jsb, 43 __u32 blocksize, __u32 size, int flags) 44{ 45 memset (jsb, 0, sizeof(*jsb)); 46 47 jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER); 48 if (flags & EXT2_MKJOURNAL_V1_SUPER) 49 jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V1); 50 else 51 jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2); 52 jsb->s_blocksize = htonl(blocksize); 53 jsb->s_maxlen = htonl(size); 54 jsb->s_first = htonl(1); 55 jsb->s_sequence = htonl(1); 56} 57 58/* 59 * This function writes a journal using POSIX routines. It is used 60 * for creating external journals and creating journals on live 61 * filesystems. 62 */ 63static errcode_t write_journal_file(ext2_filsys fs, char *device, 64 blk_t size, int flags) 65{ 66 errcode_t retval; 67 char *buf = 0; 68 journal_superblock_t jsb; 69 int i, fd, ret_size; 70 71 init_journal_superblock(&jsb, fs->blocksize, size, flags); 72 73 /* Create a block buffer */ 74 buf = malloc(fs->blocksize); 75 if (!buf) 76 return ENOMEM; 77 78 /* Open the device */ 79 if ((fd = open(device, O_WRONLY)) < 0) { 80 retval = errno; 81 goto errout; 82 } 83 84 /* Write the superblock out */ 85 memset(buf, 0, fs->blocksize); 86 memcpy(buf, &jsb, sizeof(jsb)); 87 retval = EXT2_ET_SHORT_WRITE; 88 ret_size = write(fd, buf, fs->blocksize); 89 if (ret_size < 0) { 90 errno = retval; 91 goto errout; 92 } 93 if (ret_size != fs->blocksize) 94 goto errout; 95 memset(buf, 0, fs->blocksize); 96 97 for (i = 1; i < size; i++) { 98 ret_size = write(fd, buf, fs->blocksize); 99 if (ret_size < 0) { 100 retval = errno; 101 goto errout; 102 } 103 if (ret_size != fs->blocksize) 104 goto errout; 105 } 106 close(fd); 107 108 retval = 0; 109errout: 110 free(buf); 111 return retval; 112} 113 114/* 115 * Helper function for creating the journal using direct I/O routines 116 */ 117struct mkjournal_struct { 118 int num_blocks; 119 int newblocks; 120 char *buf; 121 errcode_t err; 122}; 123 124static int mkjournal_proc(ext2_filsys fs, 125 blk_t *blocknr, 126 e2_blkcnt_t blockcnt, 127 blk_t ref_block, 128 int ref_offset, 129 void *priv_data) 130{ 131 struct mkjournal_struct *es = (struct mkjournal_struct *) priv_data; 132 blk_t new_blk; 133 static blk_t last_blk = 0; 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, ext2_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 return 0; 268} 269 270/* 271 * This function adds a journal inode to a filesystem, using either 272 * POSIX routines if the filesystem is mounted, or using direct I/O 273 * functions if it is not. 274 */ 275errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t size, int flags) 276{ 277 errcode_t retval; 278 ext2_ino_t journal_ino; 279 struct stat st; 280 char jfile[1024]; 281 int fd, mount_flags; 282 283 if ((retval = ext2fs_check_mount_point(fs->device_name, &mount_flags, 284 jfile, sizeof(jfile)-10))) 285 return retval; 286 287 if (mount_flags & EXT2_MF_MOUNTED) { 288 strcat(jfile, "/.journal"); 289 290 /* Create the journal file */ 291 if ((fd = open(jfile, O_CREAT|O_WRONLY, 0600)) < 0) 292 return errno; 293 close(fd); 294 295 if ((retval = write_journal_file(fs, jfile, size, flags))) 296 return retval; 297 298 /* Get inode number of the journal file */ 299 if (stat(jfile, &st) < 0) 300 return errno; 301 302 if ((retval = fsetflags(jfile, 303 EXT2_NODUMP_FL | EXT2_IMMUTABLE_FL))) 304 return retval; 305 306 journal_ino = st.st_ino; 307 } else { 308 journal_ino = EXT2_JOURNAL_INO; 309 if ((retval = write_journal_inode(fs, journal_ino, 310 size, flags))) 311 return retval; 312 } 313 314 fs->super->s_journal_inum = journal_ino; 315 fs->super->s_journal_dev = 0; 316 memset(fs->super->s_journal_uuid, 0, 317 sizeof(fs->super->s_journal_uuid)); 318 fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL; 319 320 ext2fs_mark_super_dirty(fs); 321 return 0; 322} 323 324#ifdef DEBUG 325main(int argc, char **argv) 326{ 327 errcode_t retval; 328 char *device_name; 329 ext2_filsys fs; 330 331 if (argc < 2) { 332 fprintf(stderr, "Usage: %s filesystem\n", argv[0]); 333 exit(1); 334 } 335 device_name = argv[1]; 336 337 retval = ext2fs_open (device_name, EXT2_FLAG_RW, 0, 0, 338 unix_io_manager, &fs); 339 if (retval) { 340 com_err(argv[0], retval, "while opening %s", device_name); 341 exit(1); 342 } 343 344 retval = ext2fs_add_journal_inode(fs, 1024); 345 if (retval) { 346 com_err(argv[0], retval, "while adding journal to %s", 347 device_name); 348 exit(1); 349 } 350 retval = ext2fs_flush(fs); 351 if (retval) { 352 printf("Warning, had trouble writing out superblocks.\n"); 353 } 354 ext2fs_close(fs); 355 exit(0); 356 357} 358#endif 359