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