[gfs2-utils] 01/01: gfs2-utils: Add fscan
by git repository hosting
This is an automated email from the git hooks/post-receive script.
andyp pushed a commit to branch andyp-fscan
in repository gfs2-utils.
commit 6639ddf5ad69db823b67f374cb7711b0713e1f92
Author: Andrew Price <anprice(a)redhat.com>
Date: Wed Jun 7 16:11:26 2017 +0100
gfs2-utils: Add fscan
Add Steve Whitehouse's experimental fscan program/framework which is
intended to be the base for a possible new design of fsck.gfs2 that
tries to maximize i/o throughput from the outset.
Tweaks added to the original code to use libaio and the existing device
limits gathering code and byteswapping macros in libgfs2, along with
some general tidying.
Signed-off-by: Andrew Price <anprice(a)redhat.com>
---
.gitignore | 1 +
gfs2/fsck/Makefile.am | 14 ++
gfs2/fsck/fscan.c | 562 ++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 577 insertions(+)
diff --git a/.gitignore b/.gitignore
index b615b87..e09cbdc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -39,6 +39,7 @@ gfs2/libgfs2/parser.h
gfs2/libgfs2/lexer.c
gfs2/libgfs2/lexer.h
gfs2/fsck/fsck.gfs2
+gfs2/fsck/fscan
gfs2/glocktop/glocktop
gfs2/mkfs/mkfs.gfs2
gfs2/mkfs/gfs2_grow
diff --git a/gfs2/fsck/Makefile.am b/gfs2/fsck/Makefile.am
index 97fcd40..dfacaed 100644
--- a/gfs2/fsck/Makefile.am
+++ b/gfs2/fsck/Makefile.am
@@ -1,6 +1,7 @@
MAINTAINERCLEANFILES = Makefile.in
sbin_PROGRAMS = fsck.gfs2
+noinst_PROGRAMS = fscan
noinst_HEADERS = \
afterpass1_common.h \
@@ -39,3 +40,16 @@ fsck_gfs2_LDADD = \
$(top_builddir)/gfs2/libgfs2/libgfs2.la
fsck_gfs2_LDFLAGS = \
$(uuid_LIBS)
+
+fscan_SOURCES = \
+ fscan.c
+fscan_CPPFLAGS = \
+ -D_FILE_OFFSET_BITS=64 \
+ -I$(top_srcdir)/gfs2/include \
+ -I$(top_srcdir)/gfs2/libgfs2
+fscan_LDADD = \
+ $(top_builddir)/gfs2/libgfs2/libgfs2.la
+fscan_LDFLAGS = \
+ $(blkid_LIBS) \
+ -laio \
+ -lm
diff --git a/gfs2/fsck/fscan.c b/gfs2/fsck/fscan.c
new file mode 100644
index 0000000..76212bc
--- /dev/null
+++ b/gfs2/fsck/fscan.c
@@ -0,0 +1,562 @@
+#include "clusterautoconfig.h"
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <time.h>
+#include <math.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <libaio.h>
+
+#include <libgfs2.h>
+
+#define NR_EVENTS 128 /* io_in_flight must be less than this */
+#define NR_VEC 16
+
+#define NR_BUCKETS 100
+static unsigned long io_buckets[NR_BUCKETS]; /* For I/O latency */
+static unsigned long pr_buckets[NR_BUCKETS]; /* For processing time */
+
+struct io_info {
+ struct iocb cb; /* Must remain first element of io_info */
+ struct iovec iov[NR_VEC];
+ struct timespec ts;
+ void *buf;
+ size_t bsize;
+};
+
+struct rgrp {
+ u_int64_t start;
+ unsigned rb_count;
+ u_int32_t estminlen;
+};
+
+static struct rgrp **rgrps;
+static unsigned nr_rgrps = 0;
+static unsigned rg_bsize = 0;
+static unsigned fsbsize = 0;
+static unsigned long bytes_read = 0;
+static int found_rg = 0;
+static unsigned long linear_offset = 0; /* Next offset to read (in bytes) */
+static unsigned long target_in_flight = 8; /* Number of I/Os we try to keep in flight */
+static unsigned long io_in_flight = 0; /* Number of I/Os actually in flight */
+static unsigned long io_size = 8 * 1024 * 1024; /* I/O size & alignment */
+static struct lgfs2_dev_info dev_info;
+static u_int64_t master_inode = 0;
+static u_int64_t root_inode = 0;
+
+static void zero_stats(unsigned long buckets[])
+{
+ unsigned i;
+
+ for (i = 0; i < NR_BUCKETS; i++)
+ buckets[i] = 0;
+}
+
+static void record_stats(unsigned long buckets[], double t)
+{
+ double dbucket = floor(10*log10(t*1e9));
+ unsigned bucket = (unsigned)dbucket;
+
+ if (bucket > NR_BUCKETS) {
+ printf("erk!");
+ exit(-1);
+ }
+
+ buckets[bucket]++;
+}
+
+static void print_stats(unsigned long buckets[], const char *fname)
+{
+ unsigned i;
+ FILE *fp;
+
+ fp = popen("/usr/bin/gnuplot", "w");
+ if (fp == NULL) {
+ perror("gnuplot");
+ return;
+ }
+
+ fprintf(fp, "set terminal png size 800,600 linewidth 2 font \"Helvitica,16\"\n"
+ "set encoding utf8\n"
+ "set output '%s'\n"
+ "set xrange [1e-9:1e3]\n"
+ "set format x \"%%.1e\"\n"
+ "set xtics out nomirror 1e-9,1000,1e3\n"
+ "set xlabel \"Read Latency (Seconds)\"\n"
+ "set yrange [.1:10000]\n"
+ "set ylabel \"Time (Seconds)\"\n"
+ "set logscale\n"
+ "plot \"-\" using 1:2 notitle with boxes fill solid border -1\n", fname);
+
+ for (i = 0; i < NR_BUCKETS; i++) {
+ double top, bottom, centre;
+ top = bottom = (double)i;
+ top++;
+ top /= 10;
+ bottom /= 10;
+ top = exp10(top);
+ bottom = exp10(bottom);
+ centre = ((top - bottom)/2 + bottom) * 1e-9;
+ fprintf(fp, "%le %lf\n", centre, centre * (double)buckets[i]);
+ }
+
+ fclose(fp);
+
+}
+
+static struct rgrp *new_rgrp(u_int64_t where)
+{
+ struct rgrp *r = calloc(1, sizeof(struct rgrp));
+ size_t nsize;
+
+ r->start = where;
+
+ if (nr_rgrps >= rg_bsize) {
+ nsize = rg_bsize ? rg_bsize*2 : getpagesize();
+ rgrps = realloc(rgrps, nsize*sizeof(void*));
+ if (rgrps == NULL) {
+ exit(-1);
+ }
+ rg_bsize = nsize;
+ }
+
+ rgrps[nr_rgrps++] = r;
+ found_rg = 1;
+ return r;
+}
+
+static void new_rb(u_int64_t where)
+{
+ if (nr_rgrps == 0)
+ return;
+ rgrps[nr_rgrps-1]->rb_count++;
+}
+
+static void est_rg_size(void)
+{
+ struct rgrp *r = rgrps[nr_rgrps-1];
+ if (r->rb_count)
+ r->estminlen = (r->rb_count - 1) * ((fsbsize - sizeof(struct gfs2_meta_header))/GFS2_NBBY) * fsbsize;
+ found_rg = 0;
+}
+
+static struct timespec timespec_diff(struct timespec start, struct timespec end)
+{
+ struct timespec tmp;
+
+ if ((end.tv_nsec - start.tv_nsec) < 0) {
+ tmp.tv_sec = end.tv_sec - start.tv_sec - 1;
+ tmp.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec;
+ } else {
+ tmp.tv_sec = end.tv_sec - start.tv_sec;
+ tmp.tv_nsec = end.tv_nsec - start.tv_nsec;
+ }
+
+ return tmp;
+}
+
+static struct iocb *new_cb(int fd, loff_t offset)
+{
+ struct io_info *info = calloc(1, sizeof(struct io_info));
+ struct iocb *cb = &info->cb;
+ size_t pgsize = getpagesize();
+ size_t bsize = io_size;
+ void *buf = NULL;
+ struct iovec *iov;
+
+ if (info == NULL)
+ return NULL;
+
+ if (posix_memalign(&buf, pgsize, bsize) != 0) {
+ perror("posix_memalign");
+ free(info);
+ return NULL;
+ }
+ memset(buf, 0, bsize);
+
+ iov = info->iov;
+ iov->iov_base = buf;
+ iov->iov_len = bsize;
+
+ io_prep_preadv(cb, fd, iov, 1, offset);
+
+ info->buf = buf;
+ info->bsize = bsize;
+
+ clock_gettime(CLOCK_MONOTONIC, &info->ts);
+ return cb;
+}
+
+static inline int gfs2_dirent_sentinel(const struct gfs2_dirent *dent)
+{
+ return dent->de_inum.no_addr == 0 || dent->de_inum.no_formal_ino == 0;
+}
+
+static void do_dentries(const void *bufp, unsigned size)
+{
+ const struct gfs2_dirent *de;
+ const char *buf = bufp;
+ unsigned pos = 0;
+ u_int16_t esize = 0;
+ char name[256];
+ u_int16_t nlen;
+
+ while (size) {
+ de = (struct gfs2_dirent *)(buf + pos);
+ size -= esize;
+ esize = be16_to_cpu(de->de_rec_len);
+ if (esize < sizeof(struct gfs2_dirent))
+ break;
+ pos += esize;
+ if (esize > size) {
+ /* Error in dirent */
+ break;
+ }
+ if (gfs2_dirent_sentinel(de))
+ continue;
+ nlen = be16_to_cpu(de->de_name_len);
+ if (nlen > 255)
+ nlen = 255;
+ memcpy(name, (de+1), nlen);
+ name[nlen] = 0;
+ printf("de: %s %lu\n", name, be64_to_cpu(de->de_inum.no_addr));
+ }
+
+}
+
+static void new_leaf(const struct gfs2_leaf *lf)
+{
+ do_dentries((lf+1), fsbsize - sizeof(struct gfs2_leaf));
+}
+
+static void new_extent(u_int64_t where, u_int64_t start, unsigned len)
+{
+// printf("ext: in block %lu starting at %lu for %u blocks\n",
+// where/fsbsize, start, len);
+}
+
+static void new_indir(const void *buf, u_int64_t where, unsigned len)
+{
+ const u_int64_t *ptr = buf;
+ unsigned i;
+ u_int64_t estart = 0;
+ unsigned elen = 0;
+
+ len /= sizeof(u_int64_t);
+
+// printf("in: %lu\n", where);
+
+ for (i = 0; i < len; i++) {
+ if ((estart + elen) == be64_to_cpu(*ptr)) {
+ ptr++;
+ elen++;
+ continue;
+ }
+ if (elen) {
+ new_extent(where, estart, elen);
+ elen = 0;
+ }
+ if (*ptr) {
+ estart = be64_to_cpu(*ptr);
+ elen = 1;
+ }
+ ptr++;
+ }
+
+ if (elen)
+ new_extent(where, estart, elen);
+}
+
+static int is_zero32(const void *ptr)
+{
+ const u_int64_t *p = ptr;
+
+ if (p[0] | p[1] | p[2] | p[3])
+ return 0;
+ return 1;
+}
+
+static void check_rindex(const void *bufp, u_int64_t where, unsigned len)
+{
+ unsigned i;
+ unsigned zeros = 0;
+ unsigned ricount = 0;
+ const char *buf = bufp;
+
+ len -= 31;
+
+ for (i = 0; i < len; i += 32) {
+ const struct gfs2_rindex *ri = (struct gfs2_rindex *)(buf+i);
+ if (is_zero32(buf+i)) {
+ zeros++;
+ continue;
+ }
+ if (i && ((zeros == 0) || (zeros > 2)))
+ return;
+ zeros = 0;
+ if (ri->ri_addr == 0 ||
+ ri->ri_length == 0 ||
+ ri->ri_data0 == 0 ||
+ ri->ri_data == 0 ||
+ ri->ri_bitbytes == 0)
+ return;
+ if (ri->__pad != 0)
+ return;
+ ricount++;
+ }
+
+ if (ricount == 0)
+ return;
+
+// printf("rindex: %lu\n", where/fsbsize);
+}
+
+static void new_inode(const struct gfs2_dinode *di, u_int64_t where)
+{
+ u_int32_t mode = be32_to_cpu(di->di_mode);
+ u_int32_t flags = be32_to_cpu(di->di_flags);
+ u_int16_t depth;
+ u_int16_t height = be16_to_cpu(di->di_height);
+
+// printf("di: %lu mode: %0x flags: %0x nlink:%u height %hu\n", where/fsbsize, mode, flags, be32_to_cpu(di->di_nlink), height);
+
+ switch(mode & S_IFMT) {
+ case S_IFREG:
+// printf("reg: size %lu\n", be64_to_cpu(di->di_size));
+ if ((flags & GFS2_DIF_SYSTEM) && (di->di_height == 0)) {
+ check_rindex((di+1), where, fsbsize - sizeof(struct gfs2_dinode));
+ }
+ break;
+ case S_IFDIR:
+ depth = be16_to_cpu(di->di_depth);
+// printf("dir: depth %hu entries %u\n", depth, be32_to_cpu(di->di_entries));
+ if (depth == 0)
+ do_dentries((di+1), fsbsize - sizeof(struct gfs2_dinode));
+ break;
+ default:
+ return;
+ }
+
+ if (height)
+ new_indir((di+1), where, fsbsize - sizeof(struct gfs2_dinode));
+}
+
+static void process_block(const void *buf, loff_t where)
+{
+ const struct gfs2_meta_header *mh = buf;
+ const struct gfs2_sb *sb = buf;
+ const struct gfs2_dinode *di = buf;
+ const struct gfs2_leaf *lf = buf;
+ u_int32_t mh_type = be32_to_cpu(mh->mh_type);
+
+ if (mh->mh_magic != cpu_to_be32(GFS2_MAGIC)) {
+ if (found_rg)
+ est_rg_size();
+// if (fsbsize)
+// check_rindex(buf, where, fsbsize);
+ return;
+ }
+
+ if (!fsbsize && (mh_type != GFS2_METATYPE_SB))
+ return;
+
+ switch(mh_type) {
+ case GFS2_METATYPE_SB:
+ if (where != (GFS2_SB_ADDR * GFS2_BASIC_BLOCK))
+ break;
+ if (be32_to_cpu(mh->mh_format) != GFS2_FORMAT_SB)
+ break;
+ fsbsize = be32_to_cpu(sb->sb_bsize);
+ master_inode = be64_to_cpu(sb->sb_master_dir.no_addr);
+ root_inode = be64_to_cpu(sb->sb_root_dir.no_addr);
+// printf("sb: bsize %u\n", fsbsize);
+ break;
+ case GFS2_METATYPE_RG:
+ if (be32_to_cpu(mh->mh_format) != GFS2_FORMAT_RG)
+ break;
+ if (found_rg)
+ break;
+// printf("rg: %lu flags %08x free %u dinodes %u\n",
+// where,
+// be32_to_cpu(rg->rg_flags),
+// be32_to_cpu(rg->rg_free),
+// be32_to_cpu(rg->rg_dinodes));
+ new_rgrp(where);
+ return;
+ case GFS2_METATYPE_RB:
+ if (be32_to_cpu(mh->mh_format) != GFS2_FORMAT_RB)
+ break;
+ new_rb(where);
+// printf("rb\n");
+ return;
+ case GFS2_METATYPE_DI:
+ if (be32_to_cpu(mh->mh_format) != GFS2_FORMAT_DI)
+ break;
+ if (be64_to_cpu(di->di_num.no_addr) * fsbsize != where)
+ break;
+ new_inode(di, where);
+ break;
+ case GFS2_METATYPE_IN:
+ if (be32_to_cpu(mh->mh_format) != GFS2_FORMAT_IN)
+ break;
+ new_indir((mh+1), where, fsbsize - sizeof(struct gfs2_meta_header));
+ break;
+ case GFS2_METATYPE_LF:
+ if (be32_to_cpu(mh->mh_format) != GFS2_FORMAT_LF)
+ break;
+// printf("lf\n");
+ new_leaf(lf);
+ break;
+ case GFS2_METATYPE_EA:
+ if (be32_to_cpu(mh->mh_format) != GFS2_FORMAT_EA)
+ break;
+// printf("ea\n");
+ break;
+ case GFS2_METATYPE_ED:
+ if (be32_to_cpu(mh->mh_format) != GFS2_FORMAT_QC)
+ break;
+// printf("ed\n");
+ break;
+ case GFS2_METATYPE_JD:
+ if (be32_to_cpu(mh->mh_format) != GFS2_FORMAT_JD)
+ break;
+// printf("jd\n");
+ break;
+ }
+
+// fflush(stdout);
+ if (found_rg)
+ est_rg_size();
+}
+
+static double ts2sec(const struct timespec ts)
+{
+ return (double)ts.tv_sec + ((double)ts.tv_nsec / 1e9);
+}
+
+static int process_event(io_context_t ctx, const struct io_event *e)
+{
+ struct io_info *info = (struct io_info *)e->obj;
+ struct iocb *cb = &info->cb;
+ struct iocb **ncb;
+ struct iocb **cblist;
+ struct timespec now, pstart, pend;
+ struct timespec df;
+ unsigned nr_ios;
+ double t, mbs;
+ int i;
+
+ assert(io_in_flight >= 1);
+ io_in_flight--;
+
+ if (e->res == info->bsize) {
+
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ df = timespec_diff(info->ts, now);
+ t = ts2sec(df);
+ record_stats(io_buckets, t);
+ mbs = info->bsize / t;
+ mbs /= (1024*1024);
+ bytes_read += e->res;
+
+ if ((target_in_flight > io_in_flight) &&
+ (linear_offset < dev_info.size)) {
+ nr_ios = target_in_flight - io_in_flight;
+ cblist = alloca(nr_ios * sizeof(struct iocb *));
+ ncb = cblist;
+ for (i = 0; i < nr_ios; i++){
+ *ncb = new_cb(cb->aio_fildes, linear_offset);
+ linear_offset += io_size;
+ if (*ncb == NULL)
+ break;
+ ncb++;
+ if (linear_offset >= dev_info.size)
+ break;
+ }
+ io_submit(ctx, i, cblist);
+ io_in_flight += i;
+ }
+ }
+
+ clock_gettime(CLOCK_MONOTONIC, &pstart);
+ for (i = 0; i < info->bsize; i += (fsbsize ? fsbsize : 4096))
+ process_block((char *)info->buf + i, cb->u.c.offset + i);
+
+ free(info->buf);
+ free(info);
+ clock_gettime(CLOCK_MONOTONIC, &pend);
+ df = timespec_diff(pstart, pend);
+ t = ts2sec(df);
+ record_stats(pr_buckets, t);
+
+ return (io_in_flight == 0) ? 1 : 0;
+}
+
+int main(int argc, char *argv[])
+{
+ struct io_event events[NR_EVENTS];
+ struct timespec begin, end, df;
+ io_context_t ctx = 0;
+ struct iocb *cb;
+ int ret;
+ double t;
+ int fd;
+ int i;
+
+ zero_stats(io_buckets);
+ zero_stats(pr_buckets);
+
+ clock_gettime(CLOCK_MONOTONIC, &begin);
+
+ fd = open(argv[1], O_RDONLY|O_EXCL|O_DIRECT|O_CLOEXEC|O_NOATIME);
+ if (fd < 0) {
+ perror(argv[1]);
+ exit(-1);
+ }
+
+ lgfs2_get_dev_info(fd, &dev_info);
+
+ io_setup(NR_EVENTS, &ctx);
+
+ cb = new_cb(fd, linear_offset);
+ linear_offset += io_size;
+ io_submit(ctx, 1, &cb);
+ io_in_flight++;
+
+ do {
+ ret = io_getevents(ctx, 1, NR_EVENTS, events, NULL);
+ for (i = 0; i < ret; i++) {
+ if (process_event(ctx, &events[i]))
+ goto out;
+ }
+
+ } while (ret > 0);
+out:
+ io_destroy(ctx);
+
+ if (ret < 0)
+ perror("io_getevents");
+
+ clock_gettime(CLOCK_MONOTONIC, &end);
+ df = timespec_diff(begin, end);
+ t = ts2sec(df);
+ printf("%lf secs, %lfMB/sec\n", t, bytes_read / (1024*1024) / t);
+
+ for (i = 0; i < nr_rgrps; i++) {
+ printf("Rgrp: %i at %lu with %u rb\n", i, rgrps[i]->start, rgrps[i]->rb_count);
+ }
+
+ print_stats(io_buckets, "fscan-io.png");
+ print_stats(pr_buckets, "fscan-pr.png");
+
+ return 0;
+}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
6 years, 2 months
[gfs2-utils] 01/01: Add basic support for v2 log headers
by git repository hosting
This is an automated email from the git hooks/post-receive script.
andyp pushed a commit to branch master
in repository gfs2-utils.
commit d78d57479c6aecf6b0aba749af714cc2d42ce484
Author: Andrew Price <anprice(a)redhat.com>
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 <anprice(a)redhat.com>
---
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 | 13 ++-
gfs2/libgfs2/ondisk.c | 62 ++++++++++++-
gfs2/libgfs2/recovery.c | 11 ++-
gfs2/libgfs2/structures.c | 66 ++++++++++++--
gfs2/mkfs/main_jadd.c | 58 ++++++++++--
10 files changed, 427 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 <austin.zhang(a)intel.com>
+ *
+ * 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..a828946 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,18 @@ 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)
+#endif
};
#undef STRUCT
diff --git a/gfs2/libgfs2/ondisk.c b/gfs2/libgfs2/ondisk.c
index dfb99d1..9de568c 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,26 @@ 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);
+#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 +599,32 @@ 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);
+#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 +634,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);
+#ifdef GFS2_HAS_LH_V2
+ 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, "%lld", "0x%llx");
+ pv(lh, lh_local_free, "%lld", "0x%llx");
+ pv(lh, lh_local_dinodes, "%lld", "0x%llx");
+#endif
+}
+
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..2d30018 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,27 @@ 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 + 4, bsize - v1_end - 4);
+#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 +134,27 @@ 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_tail = 0,
+ .lh_blkno = 0,
+ .lh_hash = 0,
+#ifdef GFS2_HAS_LH_V2
+ .lh_flags = GFS2_LOG_HEAD_UNMOUNT | GFS2_LOG_HEAD_USERSPACE,
+ .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,
+#else
.lh_flags = GFS2_LOG_HEAD_UNMOUNT,
+#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_be64(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_flags |= GFS2_LOG_HEAD_USERSPACE;
+ lh.lh_jinode = jnl->i_di.di_num.no_addr;
+#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_be64(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..543070d 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,37 @@ close:
opts->orig_journals = existing_journals;
}
+#ifdef GFS2_HAS_LH_V2
+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;
+}
+#endif
+
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 +466,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 +484,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_flags |= GFS2_LOG_HEAD_USERSPACE;
+ lh.lh_jinode = addr;
+#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 +509,7 @@ static void add_j(struct gfs2_sbd *sdp, struct jadd_opts *opts)
if (++seq == blocks)
seq = 0;
+ off += sdp->bsize;
}
error = fsync(fd);
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
6 years, 2 months
[gfs2-utils] 01/01: libgfs2: Remove references to .lh_log_origin
and .__pad
by git repository hosting
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 e8bd6f2ae603475ca330b94702485318b3694bfb
Author: Andrew Price <anprice(a)redhat.com>
Date: Mon Jan 22 21:03:14 2018 +0000
libgfs2: Remove references to .lh_log_origin and .__pad
Updates to match the latest patch version, plus fix a build failure
caused by a typo.
Signed-off-by: Andrew Price <anprice(a)redhat.com>
---
gfs2/libgfs2/meta.c | 2 --
gfs2/libgfs2/ondisk.c | 6 ------
gfs2/libgfs2/structures.c | 3 +--
3 files changed, 1 insertion(+), 10 deletions(-)
diff --git a/gfs2/libgfs2/meta.c b/gfs2/libgfs2/meta.c
index be79428..a828946 100644
--- a/gfs2/libgfs2/meta.c
+++ b/gfs2/libgfs2/meta.c
@@ -373,8 +373,6 @@ 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
};
diff --git a/gfs2/libgfs2/ondisk.c b/gfs2/libgfs2/ondisk.c
index ec52be3..d529a0b 100644
--- a/gfs2/libgfs2/ondisk.c
+++ b/gfs2/libgfs2/ondisk.c
@@ -584,8 +584,6 @@ void gfs2_log_header_in(struct gfs2_log_header *lh, struct gfs2_buffer_head *bh)
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
}
@@ -617,8 +615,6 @@ void gfs2_log_header_out(struct gfs2_log_header *lh, char *buf)
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
}
@@ -651,8 +647,6 @@ void gfs2_log_header_print(const struct gfs2_log_header *lh)
pv(lh, lh_local_total, "%lld", "0x%llx");
pv(lh, lh_local_free, "%lld", "0x%llx");
pv(lh, lh_local_dinodes, "%lld", "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,
diff --git a/gfs2/libgfs2/structures.c b/gfs2/libgfs2/structures.c
index 9631df1..0c5133a 100644
--- a/gfs2/libgfs2/structures.c
+++ b/gfs2/libgfs2/structures.c
@@ -138,7 +138,7 @@ int lgfs2_write_journal_data(struct gfs2_inode *ip)
.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 | GFS2_LOG_HEAD_USERSPACE;
+ .lh_flags = GFS2_LOG_HEAD_UNMOUNT | GFS2_LOG_HEAD_USERSPACE,
.lh_tail = 0,
.lh_blkno = 0,
.lh_hash = 0,
@@ -152,7 +152,6 @@ int lgfs2_write_journal_data(struct gfs2_inode *ip)
.lh_local_total = 0,
.lh_local_free = 0,
.lh_local_dinodes = 0,
- .lh_log_origin = 0;
#endif
};
struct gfs2_buffer_head *bh;
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
6 years, 2 months
[gfs2-utils] 01/01: libgfs2: Use GFS2_LOG_HEAD_USERSPACE with the
correct field
by git repository hosting
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 23045e71f3c22bf45bd11c7497fbce7157223366
Author: Andrew Price <anprice(a)redhat.com>
Date: Mon Jan 22 19:14:21 2018 +0000
libgfs2: Use GFS2_LOG_HEAD_USERSPACE with the correct field
Signed-off-by: Andrew Price <anprice(a)redhat.com>
---
gfs2/libgfs2/structures.c | 7 +++----
gfs2/mkfs/main_jadd.c | 3 +--
2 files changed, 4 insertions(+), 6 deletions(-)
diff --git a/gfs2/libgfs2/structures.c b/gfs2/libgfs2/structures.c
index dd1d962..9631df1 100644
--- a/gfs2/libgfs2/structures.c
+++ b/gfs2/libgfs2/structures.c
@@ -138,7 +138,7 @@ int lgfs2_write_journal_data(struct gfs2_inode *ip)
.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_flags = GFS2_LOG_HEAD_UNMOUNT | GFS2_LOG_HEAD_USERSPACE;
.lh_tail = 0,
.lh_blkno = 0,
.lh_hash = 0,
@@ -152,7 +152,7 @@ int lgfs2_write_journal_data(struct gfs2_inode *ip)
.lh_local_total = 0,
.lh_local_free = 0,
.lh_local_dinodes = 0,
- .lh_log_origin = GFS2_LOG_HEAD_USERSPACE
+ .lh_log_origin = 0;
#endif
};
struct gfs2_buffer_head *bh;
@@ -210,10 +210,9 @@ int write_journal(struct gfs2_inode *jnl, unsigned bsize, unsigned int blocks)
lh.lh_header.mh_magic = GFS2_MAGIC;
lh.lh_header.mh_type = GFS2_METATYPE_LH;
lh.lh_header.mh_format = GFS2_FORMAT_LH;
- lh.lh_flags = GFS2_LOG_HEAD_UNMOUNT;
+ lh.lh_flags = GFS2_LOG_HEAD_UNMOUNT | GFS2_LOG_HEAD_USERSPACE;
#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);
diff --git a/gfs2/mkfs/main_jadd.c b/gfs2/mkfs/main_jadd.c
index 764019a..7f8174d 100644
--- a/gfs2/mkfs/main_jadd.c
+++ b/gfs2/mkfs/main_jadd.c
@@ -481,10 +481,9 @@ static void add_j(struct gfs2_sbd *sdp, struct jadd_opts *opts)
lh.lh_header.mh_magic = GFS2_MAGIC;
lh.lh_header.mh_type = GFS2_METATYPE_LH;
lh.lh_header.mh_format = GFS2_FORMAT_LH;
- lh.lh_flags = GFS2_LOG_HEAD_UNMOUNT;
+ lh.lh_flags = GFS2_LOG_HEAD_UNMOUNT | GFS2_LOG_HEAD_USERSPACE;
#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;
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
6 years, 2 months
[gfs2-utils] 01/01: libgfs2: Format lh_local_* fields as signed
values
by git repository hosting
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 402f57b749ea5199caef2563dbaf0b0479b025f1
Author: Andrew Price <anprice(a)redhat.com>
Date: Mon Jan 22 16:07:20 2018 +0000
libgfs2: Format lh_local_* fields as signed values
They represent statfs changes.
Signed-off-by: Andrew Price <anprice(a)redhat.com>
---
gfs2/libgfs2/ondisk.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/gfs2/libgfs2/ondisk.c b/gfs2/libgfs2/ondisk.c
index 83c5dad..ec52be3 100644
--- a/gfs2/libgfs2/ondisk.c
+++ b/gfs2/libgfs2/ondisk.c
@@ -648,9 +648,9 @@ void gfs2_log_header_print(const struct gfs2_log_header *lh)
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_local_total, "%lld", "0x%llx");
+ pv(lh, lh_local_free, "%lld", "0x%llx");
+ pv(lh, lh_local_dinodes, "%lld", "0x%llx");
pv(lh, lh_log_origin, "0x%.8X", NULL);
pv(lh, __pad, "0x%.8X", NULL);
}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
6 years, 2 months
[gfs2-utils] 01/01: libgfs2: Don't use messy sizeof()s for
calculating crc offsets
by git repository hosting
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 e4fa506b8ef9a562af464f1c8f72d6b8ad76b700
Author: Andrew Price <anprice(a)redhat.com>
Date: Mon Jan 22 12:45:35 2018 +0000
libgfs2: Don't use messy sizeof()s for calculating crc offsets
Signed-off-by: Andrew Price <anprice(a)redhat.com>
---
gfs2/libgfs2/structures.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/gfs2/libgfs2/structures.c b/gfs2/libgfs2/structures.c
index f6abd89..dd1d962 100644
--- a/gfs2/libgfs2/structures.c
+++ b/gfs2/libgfs2/structures.c
@@ -118,8 +118,7 @@ uint32_t lgfs2_log_header_crc(char *buf, unsigned bsize)
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));
+ return crc32c(~0, lb + v1_end + 4, bsize - v1_end - 4);
#else
return 0;
#endif
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
6 years, 2 months
[gfs2-utils] 01/01: libgfs2: Use the correct byteswap function for
lh_addr
by git repository hosting
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 3f766bd9528b3e0e87185eba602e0e1ef51ea60c
Author: Andrew Price <anprice(a)redhat.com>
Date: Mon Jan 22 11:59:47 2018 +0000
libgfs2: Use the correct byteswap function for lh_addr
Signed-off-by: Andrew Price <anprice(a)redhat.com>
---
gfs2/libgfs2/structures.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/gfs2/libgfs2/structures.c b/gfs2/libgfs2/structures.c
index 8cb55d2..f6abd89 100644
--- a/gfs2/libgfs2/structures.c
+++ b/gfs2/libgfs2/structures.c
@@ -176,7 +176,7 @@ int lgfs2_write_journal_data(struct gfs2_inode *ip)
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_addr = cpu_to_be64(bh->b_blocknr);
buflh->lh_crc = cpu_to_be32(lgfs2_log_header_crc(bh->b_data, sdp->bsize));
#endif
@@ -236,7 +236,7 @@ int write_journal(struct gfs2_inode *jnl, unsigned bsize, unsigned int blocks)
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);
+ ((struct gfs2_log_header *)bh->b_data)->lh_addr = cpu_to_be64(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
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
6 years, 2 months
[gfs2-utils] 01/01: Add basic support for v2 log headers
by git repository hosting
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 <anprice(a)redhat.com>
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 <anprice(a)redhat.com>
---
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 <austin.zhang(a)intel.com>
+ *
+ * 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));
+#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);
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
6 years, 3 months
[gfs2-utils] 01/01: Add basic support for v2 log headers
by git repository hosting
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 741fad296ebf93b3d519f5f2f16fee26c3384f38
Author: Andrew Price <anprice(a)redhat.com>
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 <anprice(a)redhat.com>
---
configure.ac | 2 ++
gfs2/libgfs2/libgfs2.h | 8 ++++--
gfs2/libgfs2/meta.c | 13 ++++++++++
gfs2/libgfs2/ondisk.c | 63 ++++++++++++++++++++++++++++++++++++++++++++---
gfs2/libgfs2/recovery.c | 11 ++++++---
gfs2/libgfs2/structures.c | 62 ++++++++++++++++++++++++++++++++++++++++------
gfs2/mkfs/main_jadd.c | 30 ++++++++++++++++------
7 files changed, 165 insertions(+), 24 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/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..e7a2226 100644
--- a/gfs2/libgfs2/meta.c
+++ b/gfs2/libgfs2/meta.c
@@ -363,6 +363,19 @@ 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)
+#endif
};
#undef STRUCT
diff --git a/gfs2/libgfs2/ondisk.c b/gfs2/libgfs2/ondisk.c
index dfb99d1..000decf 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,27 @@ 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);
+#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 +600,33 @@ 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);
+#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 +636,22 @@ 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);
+}
+
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..99765bf 100644
--- a/gfs2/libgfs2/structures.c
+++ b/gfs2/libgfs2/structures.c
@@ -102,6 +102,27 @@ 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;
+
+ return gfs2_disk_hash(buf + v1_end + sizeof(((struct gfs2_log_header*)0)->lh_crc),
+ bsize - v1_end - sizeof(((struct gfs2_log_header*)0)->lh_crc));
+#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 +133,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;
@@ -130,11 +165,17 @@ int lgfs2_write_journal_data(struct gfs2_inode *ip)
return -1;
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 +209,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)
@@ -185,9 +229,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..a77d97c 100644
--- a/gfs2/mkfs/main_jadd.c
+++ b/gfs2/mkfs/main_jadd.c
@@ -238,7 +238,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 +259,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 +275,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 +305,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 +335,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];
@@ -424,8 +430,9 @@ 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];
@@ -451,16 +458,23 @@ 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_addr = 0; /* Don't know this value here, should be ok to leave it 0 */
+ 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
+ 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);
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
6 years, 3 months
[gfs2-utils] 08/08: libgfs2: Add support for rg_crc
by git repository hosting
This is an automated email from the git hooks/post-receive script.
andyp pushed a commit to branch master
in repository gfs2-utils.
commit 579e13ded9df7aaf525969f727e94fb78d5c850e
Author: Andrew Price <anprice(a)redhat.com>
Date: Thu Dec 7 10:19:24 2017 +0000
libgfs2: Add support for rg_crc
This new field in the resource group headers is set on write and checked
on read so that fsck.gfs2 now considers a resource group with a bad,
non-zero crc to be corrupted. gfs2_grow, gfs2_edit, and mkfs.gfs2 all
now support the rg_crc field, including save/restoremeta.
Signed-off-by: Andrew Price <anprice(a)redhat.com>
---
gfs2/libgfs2/libgfs2.h | 2 ++
gfs2/libgfs2/meta.c | 1 +
gfs2/libgfs2/ondisk.c | 7 ++++--
gfs2/libgfs2/rgrp.c | 55 +++++++++++++++++++++++++++++++++++++++++++-----
tests/rgrifieldscheck.sh | 3 +++
5 files changed, 61 insertions(+), 7 deletions(-)
diff --git a/gfs2/libgfs2/libgfs2.h b/gfs2/libgfs2/libgfs2.h
index 50dc3f5..2221af8 100644
--- a/gfs2/libgfs2/libgfs2.h
+++ b/gfs2/libgfs2/libgfs2.h
@@ -667,6 +667,8 @@ extern int clean_journal(struct gfs2_inode *ip, struct gfs2_log_header *head);
/* rgrp.c */
extern int gfs2_compute_bitstructs(const uint32_t bsize, struct rgrp_tree *rgd);
extern struct rgrp_tree *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, uint64_t blk);
+extern int lgfs2_rgrp_crc_check(char *buf);
+extern void lgfs2_rgrp_crc_set(char *buf);
extern uint64_t gfs2_rgrp_read(struct gfs2_sbd *sdp, struct rgrp_tree *rgd);
extern void gfs2_rgrp_relse(struct rgrp_tree *rgd);
extern struct rgrp_tree *rgrp_insert(struct osi_root *rgtree,
diff --git a/gfs2/libgfs2/meta.c b/gfs2/libgfs2/meta.c
index 1b771f3..82c8c6b 100644
--- a/gfs2/libgfs2/meta.c
+++ b/gfs2/libgfs2/meta.c
@@ -211,6 +211,7 @@ F(rg_igeneration)
FP(rg_data0, .points_to = ANY_GFS2_BLOCK|(1 << LGFS2_MT_FREE))
F(rg_data, .flags = LGFS2_MFF_FSBLOCKS)
F(rg_bitbytes, .flags = LGFS2_MFF_BYTES)
+F(rg_crc, .flags = LGFS2_MFF_CHECK)
#endif
RF(rg_reserved)
};
diff --git a/gfs2/libgfs2/ondisk.c b/gfs2/libgfs2/ondisk.c
index fd25a86..dfb99d1 100644
--- a/gfs2/libgfs2/ondisk.c
+++ b/gfs2/libgfs2/ondisk.c
@@ -237,7 +237,8 @@ void gfs2_rgrp_in(struct gfs2_rgrp *rg, struct gfs2_buffer_head *bh)
CPIN_64(rg, str, rg_data0);
CPIN_32(rg, str, rg_data);
CPIN_32(rg, str, rg_bitbytes);
- CPIN_08(rg, str, rg_reserved, 64);
+ CPIN_32(rg, str, rg_crc);
+ CPIN_08(rg, str, rg_reserved, 60);
#else
CPIN_08(rg, str, rg_reserved, 80);
#endif
@@ -261,7 +262,8 @@ void gfs2_rgrp_out(const struct gfs2_rgrp *rg, char *buf)
CPOUT_64(rg, str, rg_data0);
CPOUT_32(rg, str, rg_data);
CPOUT_32(rg, str, rg_bitbytes);
- CPOUT_08(rg, str, rg_reserved, 64);
+ CPOUT_08(rg, str, rg_reserved, 60);
+ lgfs2_rgrp_crc_set(buf);
#else
CPOUT_08(rg, str, rg_reserved, 80);
#endif
@@ -289,6 +291,7 @@ void gfs2_rgrp_print(const struct gfs2_rgrp *rg)
pv(rg, rg_data0, "%llu", "0x%llx");
pv(rg, rg_data, "%u", "0x%x");
pv(rg, rg_bitbytes, "%u", "0x%x");
+ pv(rg, rg_crc, "%u", "0x%x");
#endif
}
diff --git a/gfs2/libgfs2/rgrp.c b/gfs2/libgfs2/rgrp.c
index 17178bd..6d9d8e7 100644
--- a/gfs2/libgfs2/rgrp.c
+++ b/gfs2/libgfs2/rgrp.c
@@ -158,6 +158,43 @@ void lgfs2_rgrp_bitbuf_free(lgfs2_rgrp_t rg)
}
/**
+ * Check a resource group's crc
+ * Returns 0 on success, non-zero if crc is bad
+ */
+int lgfs2_rgrp_crc_check(char *buf)
+{
+ int ret = 0;
+#ifdef GFS2_HAS_RG_RI_FIELDS
+ struct gfs2_rgrp *rg = (struct gfs2_rgrp *)buf;
+ uint32_t crc = rg->rg_crc;
+
+ if (crc == 0)
+ return 0;
+
+ rg->rg_crc = 0;
+ if (be32_to_cpu(crc) != gfs2_disk_hash(buf, sizeof(struct gfs2_rgrp)))
+ ret = 1;
+ rg->rg_crc = crc;
+#endif
+ return ret;
+}
+
+/**
+ * Set the crc of an on-disk resource group
+ */
+void lgfs2_rgrp_crc_set(char *buf)
+{
+#ifdef GFS2_HAS_RG_RI_FIELDS
+ struct gfs2_rgrp *rg = (struct gfs2_rgrp *)buf;
+ uint32_t crc;
+
+ rg->rg_crc = 0;
+ crc = gfs2_disk_hash(buf, sizeof(struct gfs2_rgrp));
+ rg->rg_crc = cpu_to_be32(crc);
+#endif
+}
+
+/**
* gfs2_rgrp_read - read in the resource group information from disk.
* @rgd - resource group structure
* returns: 0 if no error, otherwise the block number that failed
@@ -194,11 +231,18 @@ uint64_t gfs2_rgrp_read(struct gfs2_sbd *sdp, struct rgrp_tree *rgd)
return rgd->ri.ri_addr + err;
}
}
- if (x > 0) {
- if (sdp->gfs1)
- gfs_rgrp_in((struct gfs_rgrp *)&rgd->rg, rgd->bits[0].bi_bh);
- else
- gfs2_rgrp_in(&rgd->rg, rgd->bits[0].bi_bh);
+ if (x <= 0) {
+ free(bhs);
+ return 0;
+ }
+ if (sdp->gfs1)
+ gfs_rgrp_in((struct gfs_rgrp *)&rgd->rg, rgd->bits[0].bi_bh);
+ else {
+ if (lgfs2_rgrp_crc_check(rgd->bits[0].bi_bh->b_data)) {
+ free(bhs);
+ return rgd->ri.ri_addr;
+ }
+ gfs2_rgrp_in(&rgd->rg, rgd->bits[0].bi_bh);
}
free(bhs);
return 0;
@@ -623,6 +667,7 @@ lgfs2_rgrp_t lgfs2_rgrps_append(lgfs2_rgrps_t rgs, struct gfs2_rindex *entry, ui
rg->rg.rg_data0 = rg->ri.ri_data0;
rg->rg.rg_data = rg->ri.ri_data;
rg->rg.rg_bitbytes = rg->ri.ri_bitbytes;
+ rg->rg.rg_crc = 0;
#endif
compute_bitmaps(rg, rgs->sdp->bsize);
rg->rgrps = rgs;
diff --git a/tests/rgrifieldscheck.sh b/tests/rgrifieldscheck.sh
index c99470a..85f6408 100755
--- a/tests/rgrifieldscheck.sh
+++ b/tests/rgrifieldscheck.sh
@@ -1,6 +1,9 @@
#!/bin/sh
dev=$1
i=0
+gfs2_edit -p rg 0 $dev | grep rg_data0 > /dev/null 2>&1
+# New fields not present in /usr/include/linux/gfs2_ondisk.h
+test $? = 0 || exit 0
gfs2_edit -p rindex $dev | while read field rival unused
do
test $field = ri_data0 -o $field = ri_data -o $field = ri_bitbytes || continue
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
6 years, 3 months