Whamcloud - gitweb
ext2fs: check if Lustre filesystem is mounted
[tools/e2fsprogs.git] / lib / ext2fs / undo_io.c
index 4213320..267fa38 100644 (file)
@@ -94,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) */
 };
 
@@ -114,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 {
@@ -145,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;
@@ -218,6 +234,11 @@ static errcode_t write_undo_indexes(struct undo_private_data *data, int flush)
        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));
@@ -308,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;
 
@@ -361,25 +381,24 @@ static errcode_t undo_write_tdb(io_channel channel,
                 * 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) {
@@ -400,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;
@@ -417,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 {
@@ -433,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);
                }
@@ -444,7 +457,7 @@ 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;
@@ -571,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? */
@@ -680,6 +698,8 @@ static errcode_t undo_open(const char *name, int flags, io_channel *channel)
        int             undo_fd = -1;
        errcode_t       retval;
 
+       /* We don't support multi-threading, at least for now */
+       flags &= ~IO_FLAG_THREADS;
        if (name == 0)
                return EXT2_ET_BAD_DEVICE_NAME;
        retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
@@ -1002,6 +1022,24 @@ static errcode_t undo_flush(io_channel channel)
        return retval;
 }
 
+/*
+ * Flush data buffers to disk and cleanup the cache.
+ */
+static errcode_t undo_flush_cleanup(io_channel channel)
+{
+       errcode_t       retval = 0;
+       struct undo_private_data *data;
+
+       EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+       data = (struct undo_private_data *) channel->private_data;
+       EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
+
+       if (data->real)
+               retval = io_channel_flush_cleanup(data->real);
+
+       return retval;
+}
+
 static errcode_t undo_set_option(io_channel channel, const char *option,
                                 const char *arg)
 {
@@ -1073,6 +1111,7 @@ static struct struct_io_manager struct_undo_manager = {
        .read_blk       = undo_read_blk,
        .write_blk      = undo_write_blk,
        .flush          = undo_flush,
+       .flush_cleanup  = undo_flush_cleanup,
        .write_byte     = undo_write_byte,
        .set_option     = undo_set_option,
        .get_stats      = undo_get_stats,