On 22/01/18 12:25, Andreas Gruenbacher wrote:
Andy,

this is looking quite good (apart from what you've just fixed).

Thanks for the review. It's still missing some important parts, like the ability for fsck to discern between v1 and v2 headers, but it should be good for testing in v2-only environments now.

On 19 January 2018 at 23:09, git repository hosting <[email protected]> wrote:
This is an automated email from the git hooks/post-receive script.

andyp pushed a commit to branch andyp-lhv2
in repository gfs2-utils.

commit 637bf11085b20726f48d66bb2d7302aca8548c7a
Author: Andrew Price <[email protected]>
Date:   Fri Jan 19 14:21:23 2018 +0000

     Add basic support for v2 log headers

     mkfs.gfs2 now writes v2 log headers, fsck.gfs2 checks the crc as well as
     the hash, gfs2_edit includes the new fields when printing log blocks and
     gfs2_jadd now writes v2 log headers.

     Signed-off-by: Andrew Price <[email protected]>
---
  configure.ac              |   2 +
  gfs2/libgfs2/Makefile.am  |   2 +
  gfs2/libgfs2/crc32c.c     | 221 ++++++++++++++++++++++++++++++++++++++++++++++
  gfs2/libgfs2/crc32c.h     |   9 ++
  gfs2/libgfs2/libgfs2.h    |   8 +-
  gfs2/libgfs2/meta.c       |  15 +++-
  gfs2/libgfs2/ondisk.c     |  66 +++++++++++++-
  gfs2/libgfs2/recovery.c   |  11 ++-
  gfs2/libgfs2/structures.c |  66 ++++++++++++--
  gfs2/mkfs/main_jadd.c     |  56 ++++++++++--
  10 files changed, 431 insertions(+), 25 deletions(-)

diff --git a/configure.ac b/configure.ac
index 4e8518c..2fb5e0b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -141,6 +141,8 @@ AC_CHECK_MEMBER([struct 
gfs2_rgrp.rg_skip],[AC_DEFINE([GFS2_HAS_RG_SKIP],[],[Nex
                  [], [[#include <linux/gfs2_ondisk.h>]])
  AC_CHECK_MEMBER([struct 
gfs2_rgrp.rg_data0],[AC_DEFINE([GFS2_HAS_RG_RI_FIELDS],[],[Resource group 
fields duplicated from the rindex])],
                  [], [[#include <linux/gfs2_ondisk.h>]])
+AC_CHECK_MEMBER([struct 
gfs2_log_header.lh_crc],[AC_DEFINE([GFS2_HAS_LH_V2],[],[v2 log header format])],
+                [], [[#include <linux/gfs2_ondisk.h>]])

  # libuuid is only required if struct gfs2_sb.sb_uuid exists
  if test "$sb_has_uuid" = "yes" -a "$have_uuid" = "no"; then
diff --git a/gfs2/libgfs2/Makefile.am b/gfs2/libgfs2/Makefile.am
index 4321a67..749da85 100644
--- a/gfs2/libgfs2/Makefile.am
+++ b/gfs2/libgfs2/Makefile.am
@@ -15,6 +15,7 @@ AM_YFLAGS = -d

  noinst_HEADERS = \
         libgfs2.h \
+       crc32c.h \
         lang.h \
         config.h \
         rgrp.h
@@ -24,6 +25,7 @@ noinst_LTLIBRARIES = libgfs2.la
  noinst_PROGRAMS = gfs2l

  libgfs2_la_SOURCES = \
+       crc32c.c \
         block_list.c \
         fs_bits.c \
         gfs1.c \
diff --git a/gfs2/libgfs2/crc32c.c b/gfs2/libgfs2/crc32c.c
new file mode 100644
index 0000000..e04c611
--- /dev/null
+++ b/gfs2/libgfs2/crc32c.c
@@ -0,0 +1,221 @@
+/*
+ * Copied from btrfs-progs, kernel-lib/crc32c.c, which was:
+ * Copied from the kernel source code, lib/libcrc32c.c.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+#include <stdlib.h>
+#include <inttypes.h>
+#include "crc32c.h"
+
+static uint32_t __crc32c_le(uint32_t crc, unsigned char const *data, size_t 
length);
+static uint32_t (*crc_function)(uint32_t crc, unsigned char const *data, 
size_t length) = __crc32c_le;
+
+#ifdef __x86_64__
+
+/*
+ * Based on a posting to lkml by Austin Zhang <[email protected]>
+ *
+ * Using hardware provided CRC32 instruction to accelerate the CRC32 disposal.
+ * CRC32C polynomial:0x1EDC6F41(BE)/0x82F63B78(LE)
+ * CRC32 is a new instruction in Intel SSE4.2, the reference can be found at:
+ * http://www.intel.com/products/processor/manuals/
+ * Intel(R) 64 and IA-32 Architectures Software Developer's Manual
+ * Volume 2A: Instruction Set Reference, A-M
+ */
+#if  __SIZEOF_LONG__ == 8
+#define REX_PRE "0x48, "
+#define SCALE_F 8
+#else
+#define REX_PRE
+#define SCALE_F 4
+#endif
+
+static int crc32c_probed = 0;
+static int crc32c_intel_available = 0;
+
+static uint32_t crc32c_intel_le_hw_byte(uint32_t crc, unsigned char const 
*data,
+                                       unsigned long length)
+{
+       while (length--) {
+               __asm__ __volatile__(
+                       ".byte 0xf2, 0xf, 0x38, 0xf0, 0xf1"
+                       :"=S"(crc)
+                       :"0"(crc), "c"(*data)
+               );
+               data++;
+       }
+
+       return crc;
+}
+
+/*
+ * Steps through buffer one byte at at time, calculates reflected
+ * crc using table.
+ */
+static uint32_t crc32c_intel(uint32_t crc, unsigned char const *data, unsigned 
long length)
+{
+       unsigned int iquotient = length / SCALE_F;
+       unsigned int iremainder = length % SCALE_F;
+       unsigned long *ptmp = (unsigned long *)data;
+
+       while (iquotient--) {
+               __asm__ __volatile__(
+                       ".byte 0xf2, " REX_PRE "0xf, 0x38, 0xf1, 0xf1;"
+                       :"=S"(crc)
+                       :"0"(crc), "c"(*ptmp)
+               );
+               ptmp++;
+       }
+
+       if (iremainder)
+               crc = crc32c_intel_le_hw_byte(crc, (unsigned char *)ptmp,
+                                iremainder);
+
+       return crc;
+}
+
+static void do_cpuid(unsigned int *eax, unsigned int *ebx, unsigned int *ecx,
+                    unsigned int *edx)
+{
+       int id = *eax;
+
+       asm("movl %4, %%eax;"
+           "cpuid;"
+           "movl %%eax, %0;"
+           "movl %%ebx, %1;"
+           "movl %%ecx, %2;"
+           "movl %%edx, %3;"
+               : "=r" (*eax), "=r" (*ebx), "=r" (*ecx), "=r" (*edx)
+               : "r" (id)
+               : "eax", "ebx", "ecx", "edx");
+}
+
+static void crc32c_intel_probe(void)
+{
+       if (!crc32c_probed) {
+               unsigned int eax, ebx, ecx, edx;
+
+               eax = 1;
+
+               do_cpuid(&eax, &ebx, &ecx, &edx);
+               crc32c_intel_available = (ecx & (1 << 20)) != 0;
+               crc32c_probed = 1;
+       }
+}
+
+void crc32c_optimization_init(void)
+{
+       crc32c_intel_probe();
+       if (crc32c_intel_available)
+               crc_function = crc32c_intel;
+}
+#else
+
+void crc32c_optimization_init(void)
+{
+}
+
+#endif /* __x86_64__ */
+
+/*
+ * This is the CRC-32C table
+ * Generated with:
+ * width = 32 bits
+ * poly = 0x1EDC6F41
+ * reflect input bytes = true
+ * reflect output bytes = true
+ */
+
+static const uint32_t crc32c_table[256] = {
+       0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
+       0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
+       0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
+       0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,
+       0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
+       0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,
+       0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,
+       0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,
+       0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
+       0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
+       0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,
+       0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,
+       0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,
+       0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,
+       0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
+       0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,
+       0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,
+       0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
+       0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,
+       0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
+       0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,
+       0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,
+       0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,
+       0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,
+       0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
+       0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,
+       0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
+       0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,
+       0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,
+       0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
+       0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,
+       0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,
+       0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,
+       0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,
+       0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
+       0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
+       0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,
+       0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,
+       0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,
+       0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
+       0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,
+       0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,
+       0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,
+       0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,
+       0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
+       0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,
+       0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,
+       0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,
+       0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,
+       0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
+       0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,
+       0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,
+       0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,
+       0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
+       0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
+       0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,
+       0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,
+       0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,
+       0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,
+       0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
+       0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,
+       0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,
+       0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
+       0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L
+};
+
+/*
+ * Steps through buffer one byte at at time, calculates reflected
+ * crc using table.
+ */
+
+static uint32_t __crc32c_le(uint32_t crc, unsigned char const *data, size_t 
length)
+{
+       while (length--)
+               crc =
+                   crc32c_table[(crc ^ *data++) & 0xFFL] ^ (crc >> 8);
+       return crc;
+}
+
+uint32_t crc32c(uint32_t crc, unsigned char const *data, size_t length)
+{
+       /* Use by-byte access for unaligned buffers */
+       if ((unsigned long)data % sizeof(unsigned long))
+               return __crc32c_le(crc, data, length);
+
+       return crc_function(crc, data, length);
+}
diff --git a/gfs2/libgfs2/crc32c.h b/gfs2/libgfs2/crc32c.h
new file mode 100644
index 0000000..ad06df4
--- /dev/null
+++ b/gfs2/libgfs2/crc32c.h
@@ -0,0 +1,9 @@
+#ifndef CRC32C_H
+#define CRC32C_H
+#include <stdlib.h>
+#include <inttypes.h>
+
+uint32_t crc32c(uint32_t seed, unsigned char const *data, size_t length);
+void crc32c_optimization_init(void);
+
+#endif
diff --git a/gfs2/libgfs2/libgfs2.h b/gfs2/libgfs2/libgfs2.h
index 2221af8..85ac74c 100644
--- a/gfs2/libgfs2/libgfs2.h
+++ b/gfs2/libgfs2/libgfs2.h
@@ -469,6 +469,8 @@ extern unsigned int calc_tree_height(struct gfs2_inode *ip, 
uint64_t size);
  extern int write_journal(struct gfs2_inode *jnl, unsigned bsize, unsigned 
blocks);
  extern int lgfs2_write_journal_data(struct gfs2_inode *ip);
  extern int lgfs2_write_filemeta(struct gfs2_inode *ip);
+extern uint32_t lgfs2_log_header_hash(char *buf);
+extern uint32_t lgfs2_log_header_crc(char *buf, unsigned bsize);

  /* gfs1.c - GFS1 backward compatibility structures and functions */

@@ -743,8 +745,9 @@ extern void gfs2_dirent_out(struct gfs2_dirent *de, char 
*buf);
  extern void gfs2_leaf_in(struct gfs2_leaf *lf, struct gfs2_buffer_head *bh);
  extern void gfs2_leaf_out(struct gfs2_leaf *lf, struct gfs2_buffer_head *bh);
  extern void gfs2_ea_header_in(struct gfs2_ea_header *ea, char *buf);
-extern void gfs2_log_header_in(struct gfs2_log_header *lh,
-                              struct gfs2_buffer_head *bh);
+extern void gfs2_log_header_v1_in(struct gfs2_log_header *lh, struct 
gfs2_buffer_head *bh);
+extern void gfs2_log_header_in(struct gfs2_log_header *lh, struct 
gfs2_buffer_head *bh);
+extern void gfs2_log_header_v1_out(struct gfs2_log_header *lh, char *buf);
  extern void gfs2_log_header_out(struct gfs2_log_header *lh, char *buf);
  extern void gfs2_log_header_out_bh(struct gfs2_log_header *lh, struct 
gfs2_buffer_head *bh);
  extern void gfs2_log_descriptor_in(struct gfs2_log_descriptor *ld,
@@ -769,6 +772,7 @@ extern void gfs2_quota_print(const struct gfs2_quota *qu);
  extern void gfs2_dinode_print(const struct gfs2_dinode *di);
  extern void gfs2_leaf_print(const struct gfs2_leaf *lf);
  extern void gfs2_ea_header_print(const struct gfs2_ea_header *ea, char *name);
+extern void gfs2_log_header_v1_print(const struct gfs2_log_header *lh);
  extern void gfs2_log_header_print(const struct gfs2_log_header *lh);
  extern void gfs2_log_descriptor_print(const struct gfs2_log_descriptor *ld);
  extern void gfs2_statfs_change_print(const struct gfs2_statfs_change *sc);
diff --git a/gfs2/libgfs2/meta.c b/gfs2/libgfs2/meta.c
index 82c8c6b..be79428 100644
--- a/gfs2/libgfs2/meta.c
+++ b/gfs2/libgfs2/meta.c
@@ -118,7 +118,6 @@ const unsigned int lgfs2_ld1_type_size = 
ARRAY_SIZE(lgfs2_ld1_types);

  #define INR(f,...) RF(f.no_formal_ino) \
                    RFP(f.no_addr, __VA_ARGS__)
-
  #define ANY_COMMON_BLOCK (1 << LGFS2_MT_DIR_LEAF) | \
                          (1 << LGFS2_MT_JRNL_DATA) | \
                          (1 << LGFS2_MT_EA_ATTR) | \
@@ -363,6 +362,20 @@ F(lh_flags)
  F(lh_tail)
  F(lh_blkno)
  F(lh_hash, .flags = LGFS2_MFF_CHECK)
+#ifdef GFS2_HAS_LH_V2
+F(lh_crc, .flags = LGFS2_MFF_CHECK)
+F(lh_nsec, .flags = LGFS2_MFF_NSECS)
+F(lh_sec, .flags = LGFS2_MFF_SECS)
+FP(lh_addr, .points_to = (1 << LGFS2_MT_GFS2_LOG_BLOCK))
+FP(lh_jinode, .points_to = (1 << LGFS2_MT_GFS2_DINODE))
+FP(lh_statfs_addr, .points_to = (1 << LGFS2_MT_GFS2_DINODE))
+FP(lh_quota_addr, .points_to = (1 << LGFS2_MT_GFS2_DINODE))
+F(lh_local_total, .flags = LGFS2_MFF_FSBLOCKS)
+F(lh_local_free, .flags = LGFS2_MFF_FSBLOCKS)
+F(lh_local_dinodes, .flags = LGFS2_MFF_FSBLOCKS)
+F(lh_log_origin)
+RF(__pad)
+#endif
  };

  #undef STRUCT
diff --git a/gfs2/libgfs2/ondisk.c b/gfs2/libgfs2/ondisk.c
index dfb99d1..83c5dad 100644
--- a/gfs2/libgfs2/ondisk.c
+++ b/gfs2/libgfs2/ondisk.c
@@ -556,8 +556,7 @@ void gfs2_ea_header_print(const struct gfs2_ea_header *ea, 
char *name)
         print_it("  name", "%s", NULL, buf);
  }

-void gfs2_log_header_in(struct gfs2_log_header *lh,
-                       struct gfs2_buffer_head *bh)
+void gfs2_log_header_v1_in(struct gfs2_log_header *lh, struct gfs2_buffer_head 
*bh)
  {
         struct gfs2_log_header *str = (struct gfs2_log_header *)bh->b_data;

@@ -569,7 +568,28 @@ void gfs2_log_header_in(struct gfs2_log_header *lh,
         CPIN_32(lh, str, lh_hash);
  }

-void gfs2_log_header_out(struct gfs2_log_header *lh, char *buf)
+void gfs2_log_header_in(struct gfs2_log_header *lh, struct gfs2_buffer_head 
*bh)
+{
+       struct gfs2_log_header *str = (struct gfs2_log_header *)bh->b_data;
+
+       gfs2_log_header_v1_in(lh, bh);
+#ifdef GFS2_HAS_LH_V2
+       CPIN_32(lh, str, lh_crc);
+       CPIN_32(lh, str, lh_nsec);
+       CPIN_64(lh, str, lh_sec);
+       CPIN_64(lh, str, lh_addr);
+       CPIN_64(lh, str, lh_jinode);
+       CPIN_64(lh, str, lh_statfs_addr);
+       CPIN_64(lh, str, lh_quota_addr);
+       CPIN_64(lh, str, lh_local_total);
+       CPIN_64(lh, str, lh_local_free);
+       CPIN_64(lh, str, lh_local_dinodes);
+       CPIN_32(lh, str, lh_log_origin);
+       CPIN_32(lh, str, __pad);
+#endif
+}
+
+void gfs2_log_header_v1_out(struct gfs2_log_header *lh, char *buf)
  {
         struct gfs2_log_header *str = (struct gfs2_log_header *)buf;

@@ -581,13 +601,34 @@ void gfs2_log_header_out(struct gfs2_log_header *lh, char 
*buf)
         CPOUT_32(lh, str, lh_hash);
  }

+void gfs2_log_header_out(struct gfs2_log_header *lh, char *buf)
+{
+       struct gfs2_log_header *str = (struct gfs2_log_header *)buf;
+
+       gfs2_log_header_v1_out(lh, buf);
+#ifdef GFS2_HAS_LH_V2
+       CPOUT_32(lh, str, lh_crc);
+       CPOUT_32(lh, str, lh_nsec);
+       CPOUT_64(lh, str, lh_sec);
+       CPOUT_64(lh, str, lh_addr);
+       CPOUT_64(lh, str, lh_jinode);
+       CPOUT_64(lh, str, lh_statfs_addr);
+       CPOUT_64(lh, str, lh_quota_addr);
+       CPOUT_64(lh, str, lh_local_total);
+       CPOUT_64(lh, str, lh_local_free);
+       CPOUT_64(lh, str, lh_local_dinodes);
+       CPOUT_32(lh, str, lh_log_origin);
+       CPOUT_32(lh, str, __pad);
+#endif
+}
+
  void gfs2_log_header_out_bh(struct gfs2_log_header *lh, struct 
gfs2_buffer_head *bh)
  {
         gfs2_log_header_out(lh, bh->iov.iov_base);
         bmodified(bh);
  }

-void gfs2_log_header_print(const struct gfs2_log_header *lh)
+void gfs2_log_header_v1_print(const struct gfs2_log_header *lh)
  {
         gfs2_meta_header_print(&lh->lh_header);
         pv(lh, lh_sequence, "%llu", "0x%llx");
@@ -597,6 +638,23 @@ void gfs2_log_header_print(const struct gfs2_log_header 
*lh)
         pv(lh, lh_hash, "0x%.8X", NULL);
  }

+void gfs2_log_header_print(const struct gfs2_log_header *lh)
+{
+       gfs2_log_header_v1_print(lh);
+       pv(lh, lh_crc, "0x%.8X", NULL);
+       pv(lh, lh_nsec, "%u", "0x%x");
+       pv(lh, lh_sec, "%llu", "0x%llx");
+       pv(lh, lh_addr, "%llu", "0x%llx");
+       pv(lh, lh_jinode, "%llu", "0x%llx");
+       pv(lh, lh_statfs_addr, "%llu", "0x%llx");
+       pv(lh, lh_quota_addr, "%llu", "0x%llx");
+       pv(lh, lh_local_total, "%llu", "0x%llx");
+       pv(lh, lh_local_free, "%llu", "0x%llx");
+       pv(lh, lh_local_dinodes, "%llu", "0x%llx");
+       pv(lh, lh_log_origin, "0x%.8X", NULL);
+       pv(lh, __pad, "0x%.8X", NULL);
+}
+
  void gfs2_log_descriptor_in(struct gfs2_log_descriptor *ld,
                             struct gfs2_buffer_head *bh)
  {
diff --git a/gfs2/libgfs2/recovery.c b/gfs2/libgfs2/recovery.c
index cad723f..51d210e 100644
--- a/gfs2/libgfs2/recovery.c
+++ b/gfs2/libgfs2/recovery.c
@@ -57,6 +57,8 @@ int get_log_header(struct gfs2_inode *ip, unsigned int blk,
         struct gfs2_buffer_head *bh;
         struct gfs2_log_header lh, *tmp;
         uint32_t hash, saved_hash;
+       uint32_t lh_crc = 0;
+       uint32_t crc;
         int error;

         error = gfs2_replay_read_block(ip, blk, &bh);
@@ -66,12 +68,15 @@ int get_log_header(struct gfs2_inode *ip, unsigned int blk,
         tmp = (struct gfs2_log_header *)bh->b_data;
         saved_hash = tmp->lh_hash;
         tmp->lh_hash = 0;
-       hash = gfs2_disk_hash(bh->b_data, sizeof(struct gfs2_log_header));
+       hash = lgfs2_log_header_hash(bh->b_data);
         tmp->lh_hash = saved_hash;
+       crc = lgfs2_log_header_crc(bh->b_data, ip->i_sbd->bsize);
         gfs2_log_header_in(&lh, bh);
         brelse(bh);
-
-       if (error || lh.lh_blkno != blk || lh.lh_hash != hash)
+#ifdef GFS2_HAS_LH_V2
+       lh_crc = lh.lh_crc;
+#endif
+       if (error || lh.lh_blkno != blk || lh.lh_hash != hash || lh_crc != crc)
                 return 1;

         *head = lh;
diff --git a/gfs2/libgfs2/structures.c b/gfs2/libgfs2/structures.c
index 2d97dab..8cb55d2 100644
--- a/gfs2/libgfs2/structures.c
+++ b/gfs2/libgfs2/structures.c
@@ -15,6 +15,7 @@

  #include "libgfs2.h"
  #include "config.h"
+#include "crc32c.h"

  #ifdef GFS2_HAS_UUID
  #include <uuid.h>
@@ -102,6 +103,28 @@ out_buf:
         return err;
  }

+uint32_t lgfs2_log_header_hash(char *buf)
+{
+       /* lh_hash only CRCs the fields in the old lh, which ends where lh_crc 
is now */
+       const off_t v1_end = offsetof(struct gfs2_log_header, lh_hash) + 4;
+
+       return gfs2_disk_hash(buf, v1_end);
+}
+
+uint32_t lgfs2_log_header_crc(char *buf, unsigned bsize)
+{
+#ifdef GFS2_HAS_LH_V2
+       /* lh_crc CRCs the rest of the block starting after lh_crc */
+       const off_t v1_end = offsetof(struct gfs2_log_header, lh_hash) + 4;
+       const unsigned char *lb = (const unsigned char *)buf;
+
+       return crc32c(~0, lb + v1_end + sizeof(((struct 
gfs2_log_header*)0)->lh_crc),
+                      bsize - v1_end - sizeof(((struct 
gfs2_log_header*)0)->lh_crc));

You could as well just have put in 4 instead of sizeof(((struct
gfs2_log_header*)0)->lh_crc) above, crc32c is fundamentally 4 bytes
long.

Yes. I usually prefer sizeof() to help make code self-documenting but since this is in crc32c() I guess it's pretty easy for readers to guess what the 4 means.

Cheers,
Andy

+#else
+       return 0;
+#endif
+}
+
  /**
   * Intialise and write the data blocks for a new journal as a contiguous
   * extent. The indirect blocks pointing to these data blocks should have been
@@ -112,12 +135,26 @@ out_buf:
   */
  int lgfs2_write_journal_data(struct gfs2_inode *ip)
  {
-       uint32_t hash;
         struct gfs2_log_header lh = {
                 .lh_header.mh_magic = GFS2_MAGIC,
                 .lh_header.mh_type = GFS2_METATYPE_LH,
                 .lh_header.mh_format = GFS2_FORMAT_LH,
                 .lh_flags = GFS2_LOG_HEAD_UNMOUNT,
+               .lh_tail = 0,
+               .lh_blkno = 0,
+               .lh_hash = 0,
+#ifdef GFS2_HAS_LH_V2
+               .lh_crc = 0,
+               .lh_nsec = 0,
+               .lh_sec = 0,
+               .lh_jinode = ip->i_di.di_num.no_addr,
+               .lh_statfs_addr = 0,
+               .lh_quota_addr = 0,
+               .lh_local_total = 0,
+               .lh_local_free = 0,
+               .lh_local_dinodes = 0,
+               .lh_log_origin = GFS2_LOG_HEAD_USERSPACE
+#endif
         };
         struct gfs2_buffer_head *bh;
         struct gfs2_sbd *sdp = ip->i_sbd;
@@ -129,12 +166,19 @@ int lgfs2_write_journal_data(struct gfs2_inode *ip)
         if (bh == NULL)
                 return -1;

+       crc32c_optimization_init();
         do {
+               struct gfs2_log_header *buflh = (struct gfs2_log_header 
*)bh->b_data;
+
                 lh.lh_sequence = seq;
                 lh.lh_blkno = bh->b_blocknr - jext0;
-               gfs2_log_header_out_bh(&lh, bh);
-               hash = gfs2_disk_hash(bh->b_data, sizeof(struct 
gfs2_log_header));
-               ((struct gfs2_log_header *)bh->b_data)->lh_hash = 
cpu_to_be32(hash);
+               gfs2_log_header_out(&lh, bh->b_data);
+
+               buflh->lh_hash = cpu_to_be32(lgfs2_log_header_hash(bh->b_data));
+#ifdef GFS2_HAS_LH_V2
+               buflh->lh_addr = cpu_to_be32(bh->b_blocknr);
+               buflh->lh_crc = cpu_to_be32(lgfs2_log_header_crc(bh->b_data, 
sdp->bsize));
+#endif

                 if (bwrite(bh)) {
                         free(bh);
@@ -168,7 +212,10 @@ int write_journal(struct gfs2_inode *jnl, unsigned bsize, 
unsigned int blocks)
         lh.lh_header.mh_type = GFS2_METATYPE_LH;
         lh.lh_header.mh_format = GFS2_FORMAT_LH;
         lh.lh_flags = GFS2_LOG_HEAD_UNMOUNT;
-
+#ifdef GFS2_HAS_LH_V2
+       lh.lh_jinode = jnl->i_di.di_num.no_addr;
+       lh.lh_log_origin = GFS2_LOG_HEAD_USERSPACE;
+#endif
         for (x = 0; x < blocks; x++) {
                 struct gfs2_buffer_head *bh = get_file_buf(jnl, x, TRUE);
                 if (!bh)
@@ -176,6 +223,7 @@ int write_journal(struct gfs2_inode *jnl, unsigned bsize, 
unsigned int blocks)
                 bmodified(bh);
                 brelse(bh);
         }
+       crc32c_optimization_init();
         for (x = 0; x < blocks; x++) {
                 struct gfs2_buffer_head *bh = get_file_buf(jnl, x, FALSE);
                 if (!bh)
@@ -185,9 +233,13 @@ int write_journal(struct gfs2_inode *jnl, unsigned bsize, 
unsigned int blocks)
                 lh.lh_sequence = seq;
                 lh.lh_blkno = x;
                 gfs2_log_header_out_bh(&lh, bh);
-               hash = gfs2_disk_hash(bh->b_data, sizeof(struct 
gfs2_log_header));
+               hash = lgfs2_log_header_hash(bh->b_data);
                 ((struct gfs2_log_header *)bh->b_data)->lh_hash = 
cpu_to_be32(hash);
-
+#ifdef GFS2_HAS_LH_V2
+               ((struct gfs2_log_header *)bh->b_data)->lh_addr = 
cpu_to_be32(bh->b_blocknr);
+               hash = lgfs2_log_header_crc(bh->b_data, bsize);
+               ((struct gfs2_log_header *)bh->b_data)->lh_hash = 
cpu_to_be32(hash);
+#endif
                 bmodified(bh);
                 brelse(bh);

diff --git a/gfs2/mkfs/main_jadd.c b/gfs2/mkfs/main_jadd.c
index 3681b90..764019a 100644
--- a/gfs2/mkfs/main_jadd.c
+++ b/gfs2/mkfs/main_jadd.c
@@ -21,6 +21,8 @@
  #define _(String) gettext(String)

  #include <linux/types.h>
+#include <linux/fiemap.h>
+#include <linux/fs.h>
  #include "libgfs2.h"
  #include "gfs2_mkfs.h"
  #include "metafs.h"
@@ -238,7 +240,7 @@ static void print_results(struct jadd_opts *opts)
         printf( _("New journals: %u\n"), opts->journals);
  }

-static int create_new_inode(struct jadd_opts *opts)
+static int create_new_inode(struct jadd_opts *opts, uint64_t *addr)
  {
         char *name = opts->new_inode;
         int fd;
@@ -259,6 +261,12 @@ static int create_new_inode(struct jadd_opts *opts)
                         exit(EXIT_FAILURE);
                 }
         }
+       if (addr != NULL) {
+               struct stat st;
+
+               fstat(fd, &st);
+               *addr = st.st_ino;
+       }

         return fd;
  }
@@ -269,7 +277,7 @@ static void add_ir(struct jadd_opts *opts)
         char new_name[256];
         int error;

-       fd = create_new_inode(opts);
+       fd = create_new_inode(opts, NULL);

         {
                 struct gfs2_inum_range ir;
@@ -299,7 +307,7 @@ static void add_sc(struct jadd_opts *opts)
         char new_name[256];
         int error;

-       fd = create_new_inode(opts);
+       fd = create_new_inode(opts, NULL);

         {
                 struct gfs2_statfs_change sc;
@@ -329,7 +337,7 @@ static void add_qc(struct gfs2_sbd *sdp, struct jadd_opts 
*opts)
         char new_name[256];
         int error;

-       fd = create_new_inode(opts);
+       fd = create_new_inode(opts, NULL);

         {
                 char buf[sdp->bsize];
@@ -419,13 +427,35 @@ close:
         opts->orig_journals = existing_journals;
  }

+static uint64_t find_block_address(int fd, off_t offset, unsigned bsize)
+{
+       struct {
+               struct fiemap fm;
+               struct fiemap_extent fe;
+       } fme;
+       int ret;
+
+       fme.fm.fm_start = offset;
+       fme.fm.fm_length = 1;
+       fme.fm.fm_flags = FIEMAP_FLAG_SYNC;
+       fme.fm.fm_extent_count = 1;
+
+       ret = ioctl(fd, FS_IOC_FIEMAP, &fme.fm);
+       if (ret != 0 || fme.fm.fm_mapped_extents != 1) {
+               fprintf(stderr, "Failed to find log header block address\n");
+               return 0;
+       }
+       return fme.fe.fe_physical / bsize;
+}
+
  static void add_j(struct gfs2_sbd *sdp, struct jadd_opts *opts)
  {
         int fd;
         char new_name[256];
         int error;
+       uint64_t addr;

-       fd = create_new_inode(opts);
+       fd = create_new_inode(opts, &addr);

         {
                 char buf[sdp->bsize];
@@ -434,6 +464,7 @@ static void add_j(struct gfs2_sbd *sdp, struct jadd_opts 
*opts)
                 unsigned int x;
                 struct gfs2_log_header lh;
                 uint64_t seq = RANDOM(blocks);
+               off_t off = 0;

                 set_flags(fd, JA_FL_CLEAR, FS_JOURNAL_DATA_FL);
                 memset(buf, 0, sdp->bsize);
@@ -451,16 +482,24 @@ static void add_j(struct gfs2_sbd *sdp, struct jadd_opts 
*opts)
                 lh.lh_header.mh_type = GFS2_METATYPE_LH;
                 lh.lh_header.mh_format = GFS2_FORMAT_LH;
                 lh.lh_flags = GFS2_LOG_HEAD_UNMOUNT;
-
+#ifdef GFS2_HAS_LH_V2
+               lh.lh_jinode = addr;
+               lh.lh_log_origin = GFS2_LOG_HEAD_USERSPACE;
+#endif
                 for (x=0; x<blocks; x++) {
                         uint32_t hash;

                         lh.lh_sequence = seq;
                         lh.lh_blkno = x;
                         gfs2_log_header_out(&lh, buf);
-                       hash = gfs2_disk_hash(buf, sizeof(struct 
gfs2_log_header));
+                       hash = lgfs2_log_header_hash(buf);
                         ((struct gfs2_log_header *)buf)->lh_hash = 
cpu_to_be32(hash);
-
+#ifdef GFS2_HAS_LH_V2
+                       ((struct gfs2_log_header *)buf)->lh_addr = cpu_to_be64(
+                                                  find_block_address(fd, off, 
sdp->bsize));
+                       hash = lgfs2_log_header_crc(buf, sdp->bsize);
+                       ((struct gfs2_log_header *)buf)->lh_crc = 
cpu_to_be32(hash);
+#endif
                         if (write(fd, buf, sdp->bsize) != sdp->bsize) {
                                 perror("add_j");
                                 exit(EXIT_FAILURE);
@@ -468,6 +507,7 @@ static void add_j(struct gfs2_sbd *sdp, struct jadd_opts 
*opts)

                         if (++seq == blocks)
                                 seq = 0;
+                       off += sdp->bsize;
                 }

                 error = fsync(fd);

Thanks,
Andreas


Reply via email to