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