mkjournal.c revision d3cd93cabeac8c153c8ae7b1b7358d6ced86b15e
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 29#if EXT2_FLAT_INCLUDES 30#include "ext2_fs.h" 31#else 32#include <linux/ext2_fs.h> 33#endif 34 35#include "ext2fs.h" 36#include "jfs_dat.h" 37 38static void init_journal_superblock(journal_superblock_t *jsb, 39 __u32 blocksize, __u32 size) 40{ 41 jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER); 42 jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK); 43 jsb->s_header.h_sequence = 0; 44 jsb->s_blocksize = htonl(blocksize); 45 jsb->s_maxlen = htonl(size); 46 jsb->s_first = htonl(1); 47 jsb->s_sequence = htonl(1); 48 jsb->s_start = 0; 49} 50 51/* 52 * This function adds a journal device to a filesystem 53 */ 54errcode_t ext2fs_add_journal_device(ext2_filsys fs, char *device, 55 blk_t size) 56{ 57 journal_superblock_t jsb; 58 struct stat st; 59 errcode_t retval; 60 char *buf = 0; 61 blk_t dev_size; 62 int i, fd, ret_size; 63 64 /* Make sure the device exists and is a block device */ 65 if (stat(device, &st) < 0) 66 return errno; 67 if (!S_ISBLK(st.st_mode)) 68 return EXT2_JOURNAL_NOT_BLOCK; /* Must be a block device */ 69 70 /* Get the size of the device */ 71 if ((retval = ext2fs_get_device_size(device, fs->blocksize, 72 &dev_size))) 73 return retval; 74 75 if (!size) 76 size = dev_size; /* Default to the size of the device */ 77 else if (size > dev_size) 78 return EINVAL; /* Requested size bigger than device */ 79 80 init_journal_superblock(&jsb, fs->blocksize, size); 81 82 /* Create a block buffer */ 83 buf = malloc(fs->blocksize); 84 if (!buf) 85 return ENOMEM; 86 87 /* Open the device */ 88 if ((fd = open(device, O_WRONLY)) < 0) { 89 retval = errno; 90 goto errout; 91 } 92 93 /* Write the superblock out */ 94 memset(buf, 0, fs->blocksize); 95 memcpy(buf, &jsb, sizeof(jsb)); 96 retval = EXT2_ET_SHORT_WRITE; 97 ret_size = write(fd, buf, fs->blocksize); 98 if (ret_size < 0) { 99 errno = retval; 100 goto errout; 101 } 102 if (ret_size != fs->blocksize) 103 goto errout; 104 memset(buf, 0, fs->blocksize); 105 106 for (i=1; i < size; i++) { 107 ret_size = write(fd, buf, fs->blocksize); 108 if (ret_size < 0) { 109 retval = errno; 110 goto errout; 111 } 112 if (ret_size != fs->blocksize) 113 goto errout; 114 } 115 close(fd); 116 117 fs->super->s_journal_dev = st.st_rdev; 118 fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL; 119 ext2fs_mark_super_dirty(fs); 120 121 return 0; 122errout: 123 if (buf) 124 free(buf); 125 return retval; 126} 127 128/* 129 * Helper function for creating the journal in the filesystem 130 */ 131struct mkjournal_struct { 132 int num_blocks; 133 int newblocks; 134 char *buf; 135 errcode_t err; 136}; 137 138static int mkjournal_proc(ext2_filsys fs, 139 blk_t *blocknr, 140 e2_blkcnt_t blockcnt, 141 blk_t ref_block, 142 int ref_offset, 143 void *priv_data) 144{ 145 struct mkjournal_struct *es = (struct mkjournal_struct *) priv_data; 146 blk_t new_blk; 147 static blk_t last_blk = 0; 148 char *block; 149 errcode_t retval; 150 int group; 151 152 if (*blocknr) { 153 last_blk = *blocknr; 154 return 0; 155 } 156 retval = ext2fs_new_block(fs, last_blk, 0, &new_blk); 157 if (retval) { 158 es->err = retval; 159 return BLOCK_ABORT; 160 } 161 if (blockcnt > 0) 162 es->num_blocks--; 163 164 es->newblocks++; 165 retval = io_channel_write_blk(fs->io, new_blk, 1, es->buf); 166 167 if (blockcnt == 0) 168 memset(es->buf, 0, fs->blocksize); 169 170 if (retval) { 171 es->err = retval; 172 return BLOCK_ABORT; 173 } 174 *blocknr = new_blk; 175 ext2fs_mark_block_bitmap(fs->block_map, new_blk); 176 ext2fs_mark_bb_dirty(fs); 177 group = ext2fs_group_of_blk(fs, new_blk); 178 fs->group_desc[group].bg_free_blocks_count--; 179 fs->super->s_free_blocks_count--; 180 ext2fs_mark_super_dirty(fs); 181 182 if (es->num_blocks == 0) 183 return (BLOCK_CHANGED | BLOCK_ABORT); 184 else 185 return BLOCK_CHANGED; 186 187} 188 189/* 190 * This function adds a journal inode to a filesystem 191 */ 192errcode_t ext2fs_add_journal_fs(ext2_filsys fs, blk_t size) 193{ 194 journal_superblock_t jsb; 195 errcode_t retval; 196 struct ext2_inode inode; 197 struct mkjournal_struct es; 198 char *buf; 199 200 init_journal_superblock(&jsb, fs->blocksize, size); 201 202 if ((retval = ext2fs_read_bitmaps(fs))) 203 return retval; 204 205 if ((retval = ext2fs_read_inode(fs, EXT2_JOURNAL_INO, &inode))) 206 return retval; 207 208 if (inode.i_blocks > 0) 209 return EEXIST; 210 211 /* Create the block buffer */ 212 buf = malloc(fs->blocksize); 213 if (!buf) 214 return ENOMEM; 215 216 memset(buf, 0, fs->blocksize); 217 memcpy(buf, &jsb, sizeof(jsb)); 218 219 es.num_blocks = size; 220 es.newblocks = 0; 221 es.buf = buf; 222 es.err = 0; 223 224 retval = ext2fs_block_iterate2(fs, EXT2_JOURNAL_INO, BLOCK_FLAG_APPEND, 225 0, mkjournal_proc, &es); 226 free(buf); 227 if (es.err) 228 return es.err; 229 230 if ((retval = ext2fs_read_inode(fs, EXT2_JOURNAL_INO, &inode))) 231 return retval; 232 233 inode.i_size += fs->blocksize * size; 234 inode.i_blocks += (fs->blocksize / 512) * es.newblocks; 235 inode.i_mtime = inode.i_ctime = time(0); 236 inode.i_links_count = 1; 237 inode.i_mode = LINUX_S_IFREG | 0600; 238 239 if ((retval = ext2fs_write_inode(fs, EXT2_JOURNAL_INO, &inode))) 240 return retval; 241 242 fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL; 243 fs->super->s_journal_inum = EXT2_JOURNAL_INO; 244 245 ext2fs_mark_super_dirty(fs); 246 return 0; 247} 248 249#ifdef DEBUG 250main(int argc, char **argv) 251{ 252 errcode_t retval; 253 char *device_name; 254 ext2_filsys fs; 255 256 if (argc < 2) { 257 fprintf(stderr, "Usage: %s filesystem\n", argv[0]); 258 exit(1); 259 } 260 device_name = argv[1]; 261 262 retval = ext2fs_open (device_name, EXT2_FLAG_RW, 0, 0, 263 unix_io_manager, &fs); 264 if (retval) { 265 com_err(argv[0], retval, "while opening %s", device_name); 266 exit(1); 267 } 268 269 retval = ext2fs_add_journal_fs(fs, 1024); 270 if (retval) { 271 com_err(argv[0], retval, "while adding journal to %s", 272 device_name); 273 exit(1); 274 } 275 retval = ext2fs_flush(fs); 276 if (retval) { 277 printf("Warning, had trouble writing out superblocks.\n"); 278 } 279 ext2fs_close(fs); 280 exit(0); 281 282} 283#endif 284