busybox/e2fsprogs/old_e2fsprogs/ext2fs/mkjournal.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * mkjournal.c --- make a journal for a filesystem
   4 *
   5 * Copyright (C) 2000 Theodore Ts'o.
   6 *
   7 * %Begin-Header%
   8 * This file may be redistributed under the terms of the GNU Public
   9 * License.
  10 * %End-Header%
  11 */
  12
  13#include <stdio.h>
  14#include <string.h>
  15#if HAVE_UNISTD_H
  16#include <unistd.h>
  17#endif
  18#if HAVE_ERRNO_H
  19#include <errno.h>
  20#endif
  21#include <fcntl.h>
  22#include <time.h>
  23#if HAVE_SYS_STAT_H
  24#include <sys/stat.h>
  25#endif
  26#if HAVE_SYS_TYPES_H
  27#include <sys/types.h>
  28#endif
  29#if HAVE_SYS_IOCTL_H
  30#include <sys/ioctl.h>
  31#endif
  32#if HAVE_NETINET_IN_H
  33#include <netinet/in.h>
  34#endif
  35
  36#include "ext2_fs.h"
  37#include "../e2p/e2p.h"
  38#include "../e2fsck.h"
  39#include "ext2fs.h"
  40#include "kernel-jbd.h"
  41
  42/*
  43 * This function automatically sets up the journal superblock and
  44 * returns it as an allocated block.
  45 */
  46errcode_t ext2fs_create_journal_superblock(ext2_filsys fs,
  47                                           __u32 size, int flags,
  48                                           char  **ret_jsb)
  49{
  50        errcode_t               retval;
  51        journal_superblock_t    *jsb;
  52
  53        if (size < 1024)
  54                return EXT2_ET_JOURNAL_TOO_SMALL;
  55
  56        if ((retval = ext2fs_get_mem(fs->blocksize, &jsb)))
  57                return retval;
  58
  59        memset (jsb, 0, fs->blocksize);
  60
  61        jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER);
  62        if (flags & EXT2_MKJOURNAL_V1_SUPER)
  63                jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V1);
  64        else
  65                jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2);
  66        jsb->s_blocksize = htonl(fs->blocksize);
  67        jsb->s_maxlen = htonl(size);
  68        jsb->s_nr_users = htonl(1);
  69        jsb->s_first = htonl(1);
  70        jsb->s_sequence = htonl(1);
  71        memcpy(jsb->s_uuid, fs->super->s_uuid, sizeof(fs->super->s_uuid));
  72        /*
  73         * If we're creating an external journal device, we need to
  74         * adjust these fields.
  75         */
  76        if (fs->super->s_feature_incompat &
  77            EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
  78                jsb->s_nr_users = 0;
  79                if (fs->blocksize == 1024)
  80                        jsb->s_first = htonl(3);
  81                else
  82                        jsb->s_first = htonl(2);
  83        }
  84
  85        *ret_jsb = (char *) jsb;
  86        return 0;
  87}
  88
  89/*
  90 * This function writes a journal using POSIX routines.  It is used
  91 * for creating external journals and creating journals on live
  92 * filesystems.
  93 */
  94static errcode_t write_journal_file(ext2_filsys fs, char *filename,
  95                                    blk_t size, int flags)
  96{
  97        errcode_t       retval;
  98        char            *buf = NULL;
  99        int             fd, ret_size;
 100        blk_t           i;
 101
 102        if ((retval = ext2fs_create_journal_superblock(fs, size, flags, &buf)))
 103                return retval;
 104
 105        /* Open the device or journal file */
 106        if ((fd = open(filename, O_WRONLY)) < 0) {
 107                retval = errno;
 108                goto errout;
 109        }
 110
 111        /* Write the superblock out */
 112        retval = EXT2_ET_SHORT_WRITE;
 113        ret_size = write(fd, buf, fs->blocksize);
 114        if (ret_size < 0) {
 115                retval = errno;
 116                goto errout;
 117        }
 118        if (ret_size != (int) fs->blocksize)
 119                goto errout;
 120        memset(buf, 0, fs->blocksize);
 121
 122        for (i = 1; i < size; i++) {
 123                ret_size = write(fd, buf, fs->blocksize);
 124                if (ret_size < 0) {
 125                        retval = errno;
 126                        goto errout;
 127                }
 128                if (ret_size != (int) fs->blocksize)
 129                        goto errout;
 130        }
 131        close(fd);
 132
 133        retval = 0;
 134errout:
 135        ext2fs_free_mem(&buf);
 136        return retval;
 137}
 138
 139/*
 140 * Helper function for creating the journal using direct I/O routines
 141 */
 142struct mkjournal_struct {
 143        int             num_blocks;
 144        int             newblocks;
 145        char            *buf;
 146        errcode_t       err;
 147};
 148
 149static int mkjournal_proc(ext2_filsys   fs,
 150                           blk_t        *blocknr,
 151                           e2_blkcnt_t  blockcnt,
 152                           blk_t        ref_block EXT2FS_ATTR((unused)),
 153                           int          ref_offset EXT2FS_ATTR((unused)),
 154                           void         *priv_data)
 155{
 156        struct mkjournal_struct *es = (struct mkjournal_struct *) priv_data;
 157        blk_t   new_blk;
 158        static blk_t    last_blk = 0;
 159        errcode_t       retval;
 160
 161        if (*blocknr) {
 162                last_blk = *blocknr;
 163                return 0;
 164        }
 165        retval = ext2fs_new_block(fs, last_blk, 0, &new_blk);
 166        if (retval) {
 167                es->err = retval;
 168                return BLOCK_ABORT;
 169        }
 170        if (blockcnt > 0)
 171                es->num_blocks--;
 172
 173        es->newblocks++;
 174        retval = io_channel_write_blk(fs->io, new_blk, 1, es->buf);
 175
 176        if (blockcnt == 0)
 177                memset(es->buf, 0, fs->blocksize);
 178
 179        if (retval) {
 180                es->err = retval;
 181                return BLOCK_ABORT;
 182        }
 183        *blocknr = new_blk;
 184        last_blk = new_blk;
 185        ext2fs_block_alloc_stats(fs, new_blk, +1);
 186
 187        if (es->num_blocks == 0)
 188                return (BLOCK_CHANGED | BLOCK_ABORT);
 189        else
 190                return BLOCK_CHANGED;
 191}
 192
 193/*
 194 * This function creates a journal using direct I/O routines.
 195 */
 196static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino,
 197                                     blk_t size, int flags)
 198{
 199        char                    *buf;
 200        errcode_t               retval;
 201        struct ext2_inode       inode;
 202        struct mkjournal_struct es;
 203
 204        if ((retval = ext2fs_create_journal_superblock(fs, size, flags, &buf)))
 205                return retval;
 206
 207        if ((retval = ext2fs_read_bitmaps(fs)))
 208                return retval;
 209
 210        if ((retval = ext2fs_read_inode(fs, journal_ino, &inode)))
 211                return retval;
 212
 213        if (inode.i_blocks > 0)
 214                return EEXIST;
 215
 216        es.num_blocks = size;
 217        es.newblocks = 0;
 218        es.buf = buf;
 219        es.err = 0;
 220
 221        retval = ext2fs_block_iterate2(fs, journal_ino, BLOCK_FLAG_APPEND,
 222                                       0, mkjournal_proc, &es);
 223        if (es.err) {
 224                retval = es.err;
 225                goto errout;
 226        }
 227
 228        if ((retval = ext2fs_read_inode(fs, journal_ino, &inode)))
 229                goto errout;
 230
 231        inode.i_size += fs->blocksize * size;
 232        inode.i_blocks += (fs->blocksize / 512) * es.newblocks;
 233        inode.i_mtime = inode.i_ctime = time(NULL);
 234        inode.i_links_count = 1;
 235        inode.i_mode = LINUX_S_IFREG | 0600;
 236
 237        if ((retval = ext2fs_write_inode(fs, journal_ino, &inode)))
 238                goto errout;
 239        retval = 0;
 240
 241        memcpy(fs->super->s_jnl_blocks, inode.i_block, EXT2_N_BLOCKS*4);
 242        fs->super->s_jnl_blocks[16] = inode.i_size;
 243        fs->super->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS;
 244        ext2fs_mark_super_dirty(fs);
 245
 246errout:
 247        ext2fs_free_mem(&buf);
 248        return retval;
 249}
 250
 251/*
 252 * This function adds a journal device to a filesystem
 253 */
 254errcode_t ext2fs_add_journal_device(ext2_filsys fs, ext2_filsys journal_dev)
 255{
 256        struct stat     st;
 257        errcode_t       retval;
 258        char            buf[1024];
 259        journal_superblock_t    *jsb;
 260        int             start;
 261        __u32           i, nr_users;
 262
 263        /* Make sure the device exists and is a block device */
 264        if (stat(journal_dev->device_name, &st) < 0)
 265                return errno;
 266
 267        if (!S_ISBLK(st.st_mode))
 268                return EXT2_ET_JOURNAL_NOT_BLOCK; /* Must be a block device */
 269
 270        /* Get the journal superblock */
 271        start = 1;
 272        if (journal_dev->blocksize == 1024)
 273                start++;
 274        if ((retval = io_channel_read_blk(journal_dev->io, start, -1024, buf)))
 275                return retval;
 276
 277        jsb = (journal_superblock_t *) buf;
 278        if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) ||
 279            (jsb->s_header.h_blocktype != (unsigned) ntohl(JFS_SUPERBLOCK_V2)))
 280                return EXT2_ET_NO_JOURNAL_SB;
 281
 282        if (ntohl(jsb->s_blocksize) != (unsigned long) fs->blocksize)
 283                return EXT2_ET_UNEXPECTED_BLOCK_SIZE;
 284
 285        /* Check and see if this filesystem has already been added */
 286        nr_users = ntohl(jsb->s_nr_users);
 287        for (i=0; i < nr_users; i++) {
 288                if (memcmp(fs->super->s_uuid,
 289                           &jsb->s_users[i*16], 16) == 0)
 290                        break;
 291        }
 292        if (i >= nr_users) {
 293                memcpy(&jsb->s_users[nr_users*16],
 294                       fs->super->s_uuid, 16);
 295                jsb->s_nr_users = htonl(nr_users+1);
 296        }
 297
 298        /* Writeback the journal superblock */
 299        if ((retval = io_channel_write_blk(journal_dev->io, start, -1024, buf)))
 300                return retval;
 301
 302        fs->super->s_journal_inum = 0;
 303        fs->super->s_journal_dev = st.st_rdev;
 304        memcpy(fs->super->s_journal_uuid, jsb->s_uuid,
 305               sizeof(fs->super->s_journal_uuid));
 306        fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
 307        ext2fs_mark_super_dirty(fs);
 308        return 0;
 309}
 310
 311/*
 312 * This function adds a journal inode to a filesystem, using either
 313 * POSIX routines if the filesystem is mounted, or using direct I/O
 314 * functions if it is not.
 315 */
 316errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t size, int flags)
 317{
 318        errcode_t               retval;
 319        ext2_ino_t              journal_ino;
 320        struct stat             st;
 321        char                    jfile[1024];
 322        int                     fd, mount_flags, f;
 323
 324        retval = ext2fs_check_mount_point(fs->device_name, &mount_flags,
 325                                               jfile, sizeof(jfile)-10);
 326        if (retval)
 327                return retval;
 328
 329        if (mount_flags & EXT2_MF_MOUNTED) {
 330                strcat(jfile, "/.journal");
 331
 332                /*
 333                 * If .../.journal already exists, make sure any
 334                 * immutable or append-only flags are cleared.
 335                 */
 336#if defined(HAVE_CHFLAGS) && defined(UF_NODUMP)
 337                (void) chflags (jfile, 0);
 338#else
 339#if HAVE_EXT2_IOCTLS
 340                fd = open(jfile, O_RDONLY);
 341                if (fd >= 0) {
 342                        f = 0;
 343                        ioctl(fd, EXT2_IOC_SETFLAGS, &f);
 344                        close(fd);
 345                }
 346#endif
 347#endif
 348
 349                /* Create the journal file */
 350                if ((fd = open(jfile, O_CREAT|O_WRONLY, 0600)) < 0)
 351                        return errno;
 352
 353                if ((retval = write_journal_file(fs, jfile, size, flags)))
 354                        goto errout;
 355
 356                /* Get inode number of the journal file */
 357                if (fstat(fd, &st) < 0)
 358                        goto errout;
 359
 360#if defined(HAVE_CHFLAGS) && defined(UF_NODUMP)
 361                retval = fchflags (fd, UF_NODUMP|UF_IMMUTABLE);
 362#else
 363#if HAVE_EXT2_IOCTLS
 364                f = EXT2_NODUMP_FL | EXT2_IMMUTABLE_FL;
 365                retval = ioctl(fd, EXT2_IOC_SETFLAGS, &f);
 366#endif
 367#endif
 368                if (retval)
 369                        goto errout;
 370
 371                close(fd);
 372                journal_ino = st.st_ino;
 373        } else {
 374                journal_ino = EXT2_JOURNAL_INO;
 375                if ((retval = write_journal_inode(fs, journal_ino,
 376                                                  size, flags)))
 377                        return retval;
 378        }
 379
 380        fs->super->s_journal_inum = journal_ino;
 381        fs->super->s_journal_dev = 0;
 382        memset(fs->super->s_journal_uuid, 0,
 383               sizeof(fs->super->s_journal_uuid));
 384        fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
 385
 386        ext2fs_mark_super_dirty(fs);
 387        return 0;
 388errout:
 389        close(fd);
 390        return retval;
 391}
 392
 393#ifdef DEBUG
 394main(int argc, char **argv)
 395{
 396        errcode_t       retval;
 397        char            *device_name;
 398        ext2_filsys     fs;
 399
 400        if (argc < 2) {
 401                fprintf(stderr, "Usage: %s filesystem\n", argv[0]);
 402                exit(1);
 403        }
 404        device_name = argv[1];
 405
 406        retval = ext2fs_open (device_name, EXT2_FLAG_RW, 0, 0,
 407                              unix_io_manager, &fs);
 408        if (retval) {
 409                com_err(argv[0], retval, "while opening %s", device_name);
 410                exit(1);
 411        }
 412
 413        retval = ext2fs_add_journal_inode(fs, 1024);
 414        if (retval) {
 415                com_err(argv[0], retval, "while adding journal to %s",
 416                        device_name);
 417                exit(1);
 418        }
 419        retval = ext2fs_flush(fs);
 420        if (retval) {
 421                printf("Warning, had trouble writing out superblocks.\n");
 422        }
 423        ext2fs_close(fs);
 424        exit(0);
 425}
 426#endif
 427