Whamcloud - gitweb
Fix typos in code comments and developer docs
[tools/e2fsprogs.git] / lib / ext2fs / undo_io.c
index 4a48193..1986241 100644 (file)
  * %End-Header%
  */
 
+#ifndef _LARGEFILE_SOURCE
 #define _LARGEFILE_SOURCE
+#endif
+#ifndef _LARGEFILE64_SOURCE
 #define _LARGEFILE64_SOURCE
+#endif
 
 #include "config.h"
 #include <stdio.h>
@@ -90,10 +94,12 @@ struct undo_header {
        __le32 fs_block_size;   /* block size of the target device */
        __le32 sb_crc;          /* crc32c of the superblock */
        __le32 state;           /* e2undo state flags */
-       __le32 f_compat;        /* compatible features (none so far) */
+       __le32 f_compat;        /* compatible features */
        __le32 f_incompat;      /* incompatible features (none so far) */
        __le32 f_rocompat;      /* ro compatible features (none so far) */
-       __u8 padding[448];      /* padding */
+       __le32 pad32;           /* padding for fs_offset */
+       __le64 fs_offset;       /* filesystem offset */
+       __u8 padding[436];      /* padding */
        __le32 header_crc;      /* crc32c of this header (but not this field) */
 };
 
@@ -110,7 +116,11 @@ struct undo_key_block {
        __le32 crc;             /* block checksum */
        __le64 reserved;        /* zero */
 
+#if __STDC_VERSION__ >= 199901L
+       struct undo_key keys[];         /* keys, which come immediately after */
+#else
        struct undo_key keys[0];        /* keys, which come immediately after */
+#endif
 };
 
 struct undo_private_data {
@@ -141,6 +151,16 @@ struct undo_private_data {
 };
 #define KEYS_PER_BLOCK(d) (((d)->tdb_data_size / sizeof(struct undo_key)) - 1)
 
+#define E2UNDO_FEATURE_COMPAT_FS_OFFSET 0x1    /* the filesystem offset */
+
+static inline void e2undo_set_feature_fs_offset(struct undo_header *header) {
+       header->f_compat |= ext2fs_le32_to_cpu(E2UNDO_FEATURE_COMPAT_FS_OFFSET);
+}
+
+static inline void e2undo_clear_feature_fs_offset(struct undo_header *header) {
+       header->f_compat &= ~ext2fs_le32_to_cpu(E2UNDO_FEATURE_COMPAT_FS_OFFSET);
+}
+
 static io_manager undo_io_backing_manager;
 static char *tdb_file;
 static int actual_size;
@@ -165,7 +185,7 @@ errcode_t set_undo_io_backup_file(char *file_name)
        return 0;
 }
 
-static errcode_t write_undo_indexes(struct undo_private_data *data)
+static errcode_t write_undo_indexes(struct undo_private_data *data, int flush)
 {
        errcode_t retval;
        struct ext2_super_block super;
@@ -187,9 +207,13 @@ static errcode_t write_undo_indexes(struct undo_private_data *data)
                                                1, data->keyb);
                if (retval)
                        return retval;
-               memset(data->keyb, 0, data->tdb_data_size);
-               data->keys_in_block = 0;
-               data->key_blk_num = data->undo_blk_num;
+               /* Move on to the next key block if it's full. */
+               if (data->keys_in_block == KEYS_PER_BLOCK(data)) {
+                       memset(data->keyb, 0, data->tdb_data_size);
+                       data->keys_in_block = 0;
+                       data->key_blk_num = data->undo_blk_num;
+                       data->undo_blk_num++;
+               }
        }
 
        /* Prepare superblock for write */
@@ -210,6 +234,11 @@ static errcode_t write_undo_indexes(struct undo_private_data *data)
        data->hdr.key_offset = ext2fs_cpu_to_le64(data->first_key_blk);
        data->hdr.fs_block_size = ext2fs_cpu_to_le32(block_size);
        data->hdr.sb_crc = ext2fs_cpu_to_le32(sb_crc);
+       data->hdr.fs_offset = ext2fs_cpu_to_le64(data->offset);
+       if (data->offset)
+               e2undo_set_feature_fs_offset(&data->hdr);
+       else
+               e2undo_clear_feature_fs_offset(&data->hdr);
        hdr_crc = ext2fs_crc32c_le(~0, (unsigned char *)&data->hdr,
                                   sizeof(data->hdr) -
                                   sizeof(data->hdr.header_crc));
@@ -230,7 +259,8 @@ static errcode_t write_undo_indexes(struct undo_private_data *data)
        if (retval)
                goto err_out;
 
-       retval = io_channel_flush(data->undo_file);
+       if (flush)
+               retval = io_channel_flush(data->undo_file);
 err_out:
        io_channel_set_blksize(channel, block_size);
        return retval;
@@ -261,7 +291,7 @@ static errcode_t undo_setup_tdb(struct undo_private_data *data)
        retval = ext2fs_get_mem(data->tdb_data_size, &data->keyb);
        if (retval)
                return retval;
-       data->key_blk_num = data->undo_blk_num;
+       data->key_blk_num = data->first_key_blk;
 
        /* Record block size */
        dbg_printf("Undo block size %llu\n", data->tdb_data_size);
@@ -299,7 +329,6 @@ static errcode_t undo_write_tdb(io_channel channel,
        unsigned char *read_ptr;
        unsigned long long end_block;
        unsigned long long data_size;
-       void *data_ptr;
        struct undo_key *key;
        __u32 blk_crc;
 
@@ -348,45 +377,28 @@ static errcode_t undo_write_tdb(io_channel channel,
                }
                ext2fs_mark_block_bitmap2(data->written_block_map, block_num);
 
-               /* Spit out a key block */
-               if (data->keys_in_block == KEYS_PER_BLOCK(data)) {
-                       retval = write_undo_indexes(data);
-                       if (retval)
-                               return retval;
-                       retval = io_channel_write_blk64(data->undo_file,
-                                                       data->key_blk_num, 1,
-                                                       data->keyb);
-                       if (retval)
-                               return retval;
-               }
-
-               /* Allocate new key block */
-               if (data->keys_in_block == 0)
-                       data->undo_blk_num++;
-
                /*
                 * Read one block using the backing I/O manager
                 * The backing I/O manager block size may be
                 * different from the tdb_data_size.
-                * Also we need to recalcuate the block number with respect
+                * Also we need to recalculate the block number with respect
                 * to the backing I/O manager.
                 */
-               offset = block_num * data->tdb_data_size;
+               offset = block_num * data->tdb_data_size +
+                               (data->offset % data->tdb_data_size);
                backing_blk_num = (offset - data->offset) / channel->block_size;
 
-               count = data->tdb_data_size +
-                               ((offset - data->offset) % channel->block_size);
-               retval = ext2fs_get_mem(count, &read_ptr);
+               retval = ext2fs_get_mem(data->tdb_data_size, &read_ptr);
                if (retval) {
                        return retval;
                }
 
-               memset(read_ptr, 0, count);
+               memset(read_ptr, 0, data->tdb_data_size);
                actual_size = 0;
-               if ((count % channel->block_size) == 0)
-                       sz = count / channel->block_size;
+               if ((data->tdb_data_size % channel->block_size) == 0)
+                       sz = data->tdb_data_size / channel->block_size;
                else
-                       sz = -count;
+                       sz = -data->tdb_data_size;
                retval = io_channel_read_blk64(data->real, backing_blk_num,
                                             sz, read_ptr);
                if (retval) {
@@ -407,14 +419,12 @@ static errcode_t undo_write_tdb(io_channel channel,
                        block_num++;
                        continue;
                }
-               dbg_printf("Read %llu bytes from FS block %llu (blk=%llu cnt=%u)\n",
-                      data_size, backing_blk_num, block, count);
+               dbg_printf("Read %llu bytes from FS block %llu (blk=%llu cnt=%llu)\n",
+                      data_size, backing_blk_num, block, data->tdb_data_size);
                if ((data_size % data->undo_file->block_size) == 0)
                        sz = data_size / data->undo_file->block_size;
                else
-                       sz = -actual_size;
-               data_ptr = read_ptr + ((offset - data->offset) %
-                                      data->undo_file->block_size);
+                       sz = -data_size;;
                /* extend this key? */
                if (data->keys_in_block) {
                        key = data->keyb->keys + data->keys_in_block - 1;
@@ -424,15 +434,13 @@ static errcode_t undo_write_tdb(io_channel channel,
                        keysz = 0;
                }
                if (key != NULL &&
-                   ext2fs_le64_to_cpu(key->fsblk) +
-                   ((keysz + data->tdb_data_size - 1) /
-                    data->tdb_data_size) == backing_blk_num &&
+                   (ext2fs_le64_to_cpu(key->fsblk) * channel->block_size +
+                    channel->block_size - 1 +
+                    keysz) / channel->block_size == backing_blk_num &&
                    E2UNDO_MAX_EXTENT_BLOCKS * data->tdb_data_size >
-                   keysz + sz) {
+                   keysz + data_size) {
                        blk_crc = ext2fs_le32_to_cpu(key->blk_crc);
-                       blk_crc = ext2fs_crc32c_le(blk_crc,
-                                                  (unsigned char *)data_ptr,
-                                                  data_size);
+                       blk_crc = ext2fs_crc32c_le(blk_crc, read_ptr, data_size);
                        key->blk_crc = ext2fs_cpu_to_le32(blk_crc);
                        key->size = ext2fs_cpu_to_le32(keysz + data_size);
                } else {
@@ -440,9 +448,7 @@ static errcode_t undo_write_tdb(io_channel channel,
                        key = data->keyb->keys + data->keys_in_block;
                        data->keys_in_block++;
                        key->fsblk = ext2fs_cpu_to_le64(backing_blk_num);
-                       blk_crc = ext2fs_crc32c_le(~0,
-                                                  (unsigned char *)data_ptr,
-                                                  data_size);
+                       blk_crc = ext2fs_crc32c_le(~0, read_ptr, data_size);
                        key->blk_crc = ext2fs_cpu_to_le32(blk_crc);
                        key->size = ext2fs_cpu_to_le32(data_size);
                }
@@ -451,13 +457,19 @@ static errcode_t undo_write_tdb(io_channel channel,
                       data->undo_blk_num,
                       sz, data->num_keys - 1);
                retval = io_channel_write_blk64(data->undo_file,
-                                       data->undo_blk_num, sz, data_ptr);
+                                       data->undo_blk_num, sz, read_ptr);
                if (retval) {
                        free(read_ptr);
                        return retval;
                }
                data->undo_blk_num++;
                free(read_ptr);
+
+               /* Write out the key block */
+               retval = write_undo_indexes(data, 0);
+               if (retval)
+                       return retval;
+
                /* Next block */
                block_num++;
        }
@@ -572,7 +584,12 @@ static errcode_t try_reopen_undo_file(int undo_fd,
        super_block = ext2fs_le64_to_cpu(hdr.super_offset);
        num_keys = ext2fs_le64_to_cpu(hdr.num_keys);
        io_channel_set_blksize(data->undo_file, blocksize);
-       if (hdr.f_compat || hdr.f_incompat || hdr.f_rocompat)
+       /*
+        * Do not compare hdr.f_compat with the available compatible
+        * features set, because a "missing" compatible feature should
+        * not cause any problems.
+        */
+       if (hdr.f_incompat || hdr.f_rocompat)
                goto bad_file;
 
        /* Superblock matches this FS? */
@@ -668,7 +685,7 @@ static void undo_atexit(void *p)
        struct undo_private_data *data = p;
        errcode_t err;
 
-       err = write_undo_indexes(data);
+       err = write_undo_indexes(data, 1);
        io_channel_close(data->undo_file);
 
        com_err(data->tdb_file, err, "while force-closing undo file");
@@ -707,7 +724,8 @@ static errcode_t undo_open(const char *name, int flags, io_channel *channel)
        memset(data, 0, sizeof(struct undo_private_data));
        data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL;
        data->super_blk_num = 1;
-       data->undo_blk_num = data->first_key_blk = 2;
+       data->first_key_blk = 2;
+       data->undo_blk_num = 3;
 
        if (undo_io_backing_manager) {
                retval = undo_io_backing_manager->open(name, flags,
@@ -789,7 +807,7 @@ static errcode_t undo_close(io_channel channel)
        /* Before closing write the file system identity */
        if (!getenv("UNDO_IO_SIMULATE_UNFINISHED"))
                data->hdr.state = ext2fs_cpu_to_le32(E2UNDO_STATE_FINISHED);
-       err = write_undo_indexes(data);
+       err = write_undo_indexes(data, 1);
        ext2fs_remove_exit_fn(undo_atexit, data);
        if (data->real)
                retval = io_channel_close(data->real);