Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=8ed638b27a…
Commit: 8ed638b27a21dfa1776f55709592a453974c5d90
Parent: 982979702a7f23b069e31f171cc38fc4c87a018a
Author: Andrew Price <anprice(a)redhat.com>
AuthorDate: Thu May 30 12:12:08 2013 +0100
Committer: Andrew Price <anprice(a)redhat.com>
CommitterDate: Thu May 30 12:22:23 2013 +0100
gfs2-utils: Remove some unused build files
This removes some build files which are either no longer used or are
generated by autoconf and needn't have been committed.
Signed-off-by: Andrew Price <anprice(a)redhat.com>
---
.gitignore | 7 +
Makefile.am | 2 +-
Makefile.new | 126 ---------
README.build | 12 +-
config.rpath | 672 ------------------------------------------------
po/Makefile.in.in | 444 --------------------------------
po/Rules-quot | 47 ----
po/boldquot.sed | 10 -
po/insert-header.sin | 23 --
po/quot.sed | 6 -
po/remove-potcdate.sin | 19 --
11 files changed, 9 insertions(+), 1359 deletions(-)
diff --git a/.gitignore b/.gitignore
index a1eadd0..f8f8a82 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,6 +11,7 @@ config.guess
config.log
config.sub
config.status
+config.rpath
Makefile
depcomp
install-sh
@@ -50,3 +51,9 @@ po/Makevars.template
po/POTFILES
po/stamp-po
po/remove-potcdate.sed
+po/Makefile.in.in
+po/Rules-quot
+po/boldquot.sed
+po/insert-header.sin
+po/quot.sed
+po/remove-potcdate.sin
diff --git a/Makefile.am b/Makefile.am
index 210ab15..1eea44c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,4 +1,4 @@
-EXTRA_DIST = config.rpath m4/ChangeLog autogen.sh
+EXTRA_DIST = autogen.sh
AUTOMAKE_OPTIONS = foreign
diff --git a/Makefile.new b/Makefile.new
deleted file mode 100644
index 1534c87..0000000
--- a/Makefile.new
+++ /dev/null
@@ -1,126 +0,0 @@
-#
-# Makefile for gfs2-utils
-#
-.PHONY: all install clean test testprog testlib libraries programs strings
-.SUFFIXES: .po .pot .d
-
-subdir = $(patsubst %/target.mk,%,$(word $(words $(MAKEFILE_LIST)), $(MAKEFILE_LIST)))
-
-# $(call make-binary, name, libs)
-#
-# This is used to make a binary from all the sources in a
-# directory. The name should be that of the final installed
-# binary.
-#
-define make-binary
- $(eval local_bin = $(subdir)/$(notdir $(strip $1)))
- $(eval local_src = $(wildcard $(subdir)/*.c))
-
- programs += $(local_bin)
- install += install-$(local_bin)
- sources += $(local_src)
-
-$(local_bin): $2 $(subst .c,.o,$(local_src))
- $(LINK.c) $$^ $2 -o $$@
-install-$(local_bin): $(local_bin)
- $(INSTALL) -m 0755 $(local_bin) $(strip $1)
-endef
-
-# $(call make-trans-binary,name,libs)
-#
-# As above, but binary has translatable strings
-#
-define make-trans-binary
- $(call make-binary,$1,$2)
- posources += $(wildcard $(subdir)/*.c)
-endef
-
-# $(call make-library, name)
-#
-# This is called to make a library from all the sources
-# in a directory/
-#
-define make-library
- $(eval local_libs = $(subdir)/$(notdir $(strip $1)))
- $(eval local_src = $(wildcard $(subdir)/*.c))
- $(eval local_objs = $(subst .c,.o,$(local_src)))
- libraries += $(local_libs)
- sources += $(local_src)
-
-$(local_libs): $(local_objs)
- $(AR) $(ARFLAGS) $$@ $$^
-$(local_objs): %.o: %.c
- $(COMPILE.c) -fPIC $$< -o $$@
-endef
-
-
-CC=gcc
-LD=gcc
-AR=ar
-SED=sed
-MV=mv
-GT=xgettext
-INSTALL=install
-CFLAGS=-O2 -Wall -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -fno-strict-aliasing -Werror -DVERSION=\"3.1.0\"
-LDFLAGS=
-ARFLAGS=rcs
-
-# Programs
-programs :=
-# Install
-install :=
-# All source files
-sources :=
-# All source files from which translatable strings are extracted
-posources :=
-# All libraries
-libraries :=
-# All man pages
-manpages :=
-
-# These are created automatically from the above
-objects = $(subst .c,.o,$(sources))
-dependencies = $(subst .o,.d,$(objects))
-
-#
-# Need to trim down the list of include dirs to something more reasonable
-#
-include_dirs := gfs2/include gfs2/libgfs2 group/include group/libgfscontrol make group/gfs_controld
-CFLAGS += $(addprefix -I ,$(include_dirs))
-vpath %.h $(include_dirs)
-
-
-all:
-include $(shell find . -mindepth 2 -type f -name target.mk -print)
-all: $(programs)
-
-libraries: $(libraries)
-programs: $(programs)
-strings: po/gfs2-utils.pot
-po/gfs2-utils.pot: $(posources)
- $(GT) -k_ -o po/gfs2-utils.pot $^
-install: $(install)
-
-clean:
- rm -f $(objects) $(programs) $(libraries) $(dependencies)
-
-test: progtest libtest
-progtest: $(programs)
-libtest: $(libraries)
-
-ifneq "$(MAKECMDGOALS)" "clean"
--include $(dependencies)
-endif
-
-%.po: %.pot
- mv %< $(basename %<).pp
- msgmerge -o %< ($basename %<).pp $(basename %<).pot
- rm -f $(basename %<).pp
-
-%.d: %.c
- $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -M $< | \
- $(SED) 's,\($(nodir $*)\.o\) *:,$(dir $@)\1 $@: ,' > $@.tmp
- $(MV) $@.tmp $@
-
-%: %.o
- $(LINK.c) $(LDLIBS) $^ -o $@
diff --git a/README.build b/README.build
index 7832e2b..1f73b1d 100644
--- a/README.build
+++ b/README.build
@@ -38,14 +38,4 @@ To install gfs2-utils, run:
make install
-There is also an alternative (experimental, but eventually will take over
-from the current build system) build system which requires only GNU make.
-To use that build system, simply run:
-
-make -f Makefile.new <target>
-
-Where <target> is all, install, etc.
-
-Both build systems are designed to run alongside each other for the time
-being.
-
+See also README.contributing for details on submitting patches.
diff --git a/config.rpath b/config.rpath
deleted file mode 100755
index 17298f2..0000000
--- a/config.rpath
+++ /dev/null
@@ -1,672 +0,0 @@
-#! /bin/sh
-# Output a system dependent set of variables, describing how to set the
-# run time search path of shared libraries in an executable.
-#
-# Copyright 1996-2010 Free Software Foundation, Inc.
-# Taken from GNU libtool, 2001
-# Originally by Gordon Matzigkeit <gord(a)gnu.ai.mit.edu>, 1996
-#
-# This file is free software; the Free Software Foundation gives
-# unlimited permission to copy and/or distribute it, with or without
-# modifications, as long as this notice is preserved.
-#
-# The first argument passed to this file is the canonical host specification,
-# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
-# or
-# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
-# The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld
-# should be set by the caller.
-#
-# The set of defined variables is at the end of this script.
-
-# Known limitations:
-# - On IRIX 6.5 with CC="cc", the run time search patch must not be longer
-# than 256 bytes, otherwise the compiler driver will dump core. The only
-# known workaround is to choose shorter directory names for the build
-# directory and/or the installation directory.
-
-# All known linkers require a `.a' archive for static linking (except MSVC,
-# which needs '.lib').
-libext=a
-shrext=.so
-
-host="$1"
-host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
-host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
-host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
-
-# Code taken from libtool.m4's _LT_CC_BASENAME.
-
-for cc_temp in $CC""; do
- case $cc_temp in
- compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
- distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
- \-*) ;;
- *) break;;
- esac
-done
-cc_basename=`echo "$cc_temp" | sed -e 's%^.*/%%'`
-
-# Code taken from libtool.m4's _LT_COMPILER_PIC.
-
-wl=
-if test "$GCC" = yes; then
- wl='-Wl,'
-else
- case "$host_os" in
- aix*)
- wl='-Wl,'
- ;;
- darwin*)
- case $cc_basename in
- xlc*)
- wl='-Wl,'
- ;;
- esac
- ;;
- mingw* | cygwin* | pw32* | os2* | cegcc*)
- ;;
- hpux9* | hpux10* | hpux11*)
- wl='-Wl,'
- ;;
- irix5* | irix6* | nonstopux*)
- wl='-Wl,'
- ;;
- newsos6)
- ;;
- linux* | k*bsd*-gnu)
- case $cc_basename in
- ecc*)
- wl='-Wl,'
- ;;
- icc* | ifort*)
- wl='-Wl,'
- ;;
- lf95*)
- wl='-Wl,'
- ;;
- pgcc | pgf77 | pgf90)
- wl='-Wl,'
- ;;
- ccc*)
- wl='-Wl,'
- ;;
- como)
- wl='-lopt='
- ;;
- *)
- case `$CC -V 2>&1 | sed 5q` in
- *Sun\ C*)
- wl='-Wl,'
- ;;
- esac
- ;;
- esac
- ;;
- osf3* | osf4* | osf5*)
- wl='-Wl,'
- ;;
- rdos*)
- ;;
- solaris*)
- wl='-Wl,'
- ;;
- sunos4*)
- wl='-Qoption ld '
- ;;
- sysv4 | sysv4.2uw2* | sysv4.3*)
- wl='-Wl,'
- ;;
- sysv4*MP*)
- ;;
- sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
- wl='-Wl,'
- ;;
- unicos*)
- wl='-Wl,'
- ;;
- uts4*)
- ;;
- esac
-fi
-
-# Code taken from libtool.m4's _LT_LINKER_SHLIBS.
-
-hardcode_libdir_flag_spec=
-hardcode_libdir_separator=
-hardcode_direct=no
-hardcode_minus_L=no
-
-case "$host_os" in
- cygwin* | mingw* | pw32* | cegcc*)
- # FIXME: the MSVC++ port hasn't been tested in a loooong time
- # When not using gcc, we currently assume that we are using
- # Microsoft Visual C++.
- if test "$GCC" != yes; then
- with_gnu_ld=no
- fi
- ;;
- interix*)
- # we just hope/assume this is gcc and not c89 (= MSVC++)
- with_gnu_ld=yes
- ;;
- openbsd*)
- with_gnu_ld=no
- ;;
-esac
-
-ld_shlibs=yes
-if test "$with_gnu_ld" = yes; then
- # Set some defaults for GNU ld with shared library support. These
- # are reset later if shared libraries are not supported. Putting them
- # here allows them to be overridden if necessary.
- # Unlike libtool, we use -rpath here, not --rpath, since the documented
- # option of GNU ld is called -rpath, not --rpath.
- hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
- case "$host_os" in
- aix[3-9]*)
- # On AIX/PPC, the GNU linker is very broken
- if test "$host_cpu" != ia64; then
- ld_shlibs=no
- fi
- ;;
- amigaos*)
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_minus_L=yes
- # Samuel A. Falvo II <kc5tja(a)dolphin.openprojects.net> reports
- # that the semantics of dynamic libraries on AmigaOS, at least up
- # to version 4, is to share data among multiple programs linked
- # with the same dynamic library. Since this doesn't match the
- # behavior of shared libraries on other platforms, we cannot use
- # them.
- ld_shlibs=no
- ;;
- beos*)
- if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
- :
- else
- ld_shlibs=no
- fi
- ;;
- cygwin* | mingw* | pw32* | cegcc*)
- # hardcode_libdir_flag_spec is actually meaningless, as there is
- # no search path for DLLs.
- hardcode_libdir_flag_spec='-L$libdir'
- if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
- :
- else
- ld_shlibs=no
- fi
- ;;
- interix[3-9]*)
- hardcode_direct=no
- hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
- ;;
- gnu* | linux* | k*bsd*-gnu)
- if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
- :
- else
- ld_shlibs=no
- fi
- ;;
- netbsd*)
- ;;
- solaris*)
- if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
- ld_shlibs=no
- elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
- :
- else
- ld_shlibs=no
- fi
- ;;
- sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
- case `$LD -v 2>&1` in
- *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
- ld_shlibs=no
- ;;
- *)
- if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
- hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`'
- else
- ld_shlibs=no
- fi
- ;;
- esac
- ;;
- sunos4*)
- hardcode_direct=yes
- ;;
- *)
- if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
- :
- else
- ld_shlibs=no
- fi
- ;;
- esac
- if test "$ld_shlibs" = no; then
- hardcode_libdir_flag_spec=
- fi
-else
- case "$host_os" in
- aix3*)
- # Note: this linker hardcodes the directories in LIBPATH if there
- # are no directories specified by -L.
- hardcode_minus_L=yes
- if test "$GCC" = yes; then
- # Neither direct hardcoding nor static linking is supported with a
- # broken collect2.
- hardcode_direct=unsupported
- fi
- ;;
- aix[4-9]*)
- if test "$host_cpu" = ia64; then
- # On IA64, the linker does run time linking by default, so we don't
- # have to do anything special.
- aix_use_runtimelinking=no
- else
- aix_use_runtimelinking=no
- # Test if we are trying to use run time linking or normal
- # AIX style linking. If -brtl is somewhere in LDFLAGS, we
- # need to do runtime linking.
- case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
- for ld_flag in $LDFLAGS; do
- if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
- aix_use_runtimelinking=yes
- break
- fi
- done
- ;;
- esac
- fi
- hardcode_direct=yes
- hardcode_libdir_separator=':'
- if test "$GCC" = yes; then
- case $host_os in aix4.[012]|aix4.[012].*)
- collect2name=`${CC} -print-prog-name=collect2`
- if test -f "$collect2name" && \
- strings "$collect2name" | grep resolve_lib_name >/dev/null
- then
- # We have reworked collect2
- :
- else
- # We have old collect2
- hardcode_direct=unsupported
- hardcode_minus_L=yes
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_libdir_separator=
- fi
- ;;
- esac
- fi
- # Begin _LT_AC_SYS_LIBPATH_AIX.
- echo 'int main () { return 0; }' > conftest.c
- ${CC} ${LDFLAGS} conftest.c -o conftest
- aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
-}'`
- if test -z "$aix_libpath"; then
- aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
-}'`
- fi
- if test -z "$aix_libpath"; then
- aix_libpath="/usr/lib:/lib"
- fi
- rm -f conftest.c conftest
- # End _LT_AC_SYS_LIBPATH_AIX.
- if test "$aix_use_runtimelinking" = yes; then
- hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
- else
- if test "$host_cpu" = ia64; then
- hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
- else
- hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
- fi
- fi
- ;;
- amigaos*)
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_minus_L=yes
- # see comment about different semantics on the GNU ld section
- ld_shlibs=no
- ;;
- bsdi[45]*)
- ;;
- cygwin* | mingw* | pw32* | cegcc*)
- # When not using gcc, we currently assume that we are using
- # Microsoft Visual C++.
- # hardcode_libdir_flag_spec is actually meaningless, as there is
- # no search path for DLLs.
- hardcode_libdir_flag_spec=' '
- libext=lib
- ;;
- darwin* | rhapsody*)
- hardcode_direct=no
- if test "$GCC" = yes ; then
- :
- else
- case $cc_basename in
- xlc*)
- ;;
- *)
- ld_shlibs=no
- ;;
- esac
- fi
- ;;
- dgux*)
- hardcode_libdir_flag_spec='-L$libdir'
- ;;
- freebsd1*)
- ld_shlibs=no
- ;;
- freebsd2.2*)
- hardcode_libdir_flag_spec='-R$libdir'
- hardcode_direct=yes
- ;;
- freebsd2*)
- hardcode_direct=yes
- hardcode_minus_L=yes
- ;;
- freebsd* | dragonfly*)
- hardcode_libdir_flag_spec='-R$libdir'
- hardcode_direct=yes
- ;;
- hpux9*)
- hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
- hardcode_libdir_separator=:
- hardcode_direct=yes
- # hardcode_minus_L: Not really in the search PATH,
- # but as the default location of the library.
- hardcode_minus_L=yes
- ;;
- hpux10*)
- if test "$with_gnu_ld" = no; then
- hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
- hardcode_libdir_separator=:
- hardcode_direct=yes
- # hardcode_minus_L: Not really in the search PATH,
- # but as the default location of the library.
- hardcode_minus_L=yes
- fi
- ;;
- hpux11*)
- if test "$with_gnu_ld" = no; then
- hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
- hardcode_libdir_separator=:
- case $host_cpu in
- hppa*64*|ia64*)
- hardcode_direct=no
- ;;
- *)
- hardcode_direct=yes
- # hardcode_minus_L: Not really in the search PATH,
- # but as the default location of the library.
- hardcode_minus_L=yes
- ;;
- esac
- fi
- ;;
- irix5* | irix6* | nonstopux*)
- hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
- hardcode_libdir_separator=:
- ;;
- netbsd*)
- hardcode_libdir_flag_spec='-R$libdir'
- hardcode_direct=yes
- ;;
- newsos6)
- hardcode_direct=yes
- hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
- hardcode_libdir_separator=:
- ;;
- openbsd*)
- if test -f /usr/libexec/ld.so; then
- hardcode_direct=yes
- if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
- hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
- else
- case "$host_os" in
- openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
- hardcode_libdir_flag_spec='-R$libdir'
- ;;
- *)
- hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
- ;;
- esac
- fi
- else
- ld_shlibs=no
- fi
- ;;
- os2*)
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_minus_L=yes
- ;;
- osf3*)
- hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
- hardcode_libdir_separator=:
- ;;
- osf4* | osf5*)
- if test "$GCC" = yes; then
- hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
- else
- # Both cc and cxx compiler support -rpath directly
- hardcode_libdir_flag_spec='-rpath $libdir'
- fi
- hardcode_libdir_separator=:
- ;;
- solaris*)
- hardcode_libdir_flag_spec='-R$libdir'
- ;;
- sunos4*)
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_direct=yes
- hardcode_minus_L=yes
- ;;
- sysv4)
- case $host_vendor in
- sni)
- hardcode_direct=yes # is this really true???
- ;;
- siemens)
- hardcode_direct=no
- ;;
- motorola)
- hardcode_direct=no #Motorola manual says yes, but my tests say they lie
- ;;
- esac
- ;;
- sysv4.3*)
- ;;
- sysv4*MP*)
- if test -d /usr/nec; then
- ld_shlibs=yes
- fi
- ;;
- sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
- ;;
- sysv5* | sco3.2v5* | sco5v6*)
- hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`'
- hardcode_libdir_separator=':'
- ;;
- uts4*)
- hardcode_libdir_flag_spec='-L$libdir'
- ;;
- *)
- ld_shlibs=no
- ;;
- esac
-fi
-
-# Check dynamic linker characteristics
-# Code taken from libtool.m4's _LT_SYS_DYNAMIC_LINKER.
-# Unlike libtool.m4, here we don't care about _all_ names of the library, but
-# only about the one the linker finds when passed -lNAME. This is the last
-# element of library_names_spec in libtool.m4, or possibly two of them if the
-# linker has special search rules.
-library_names_spec= # the last element of library_names_spec in libtool.m4
-libname_spec='lib$name'
-case "$host_os" in
- aix3*)
- library_names_spec='$libname.a'
- ;;
- aix[4-9]*)
- library_names_spec='$libname$shrext'
- ;;
- amigaos*)
- library_names_spec='$libname.a'
- ;;
- beos*)
- library_names_spec='$libname$shrext'
- ;;
- bsdi[45]*)
- library_names_spec='$libname$shrext'
- ;;
- cygwin* | mingw* | pw32* | cegcc*)
- shrext=.dll
- library_names_spec='$libname.dll.a $libname.lib'
- ;;
- darwin* | rhapsody*)
- shrext=.dylib
- library_names_spec='$libname$shrext'
- ;;
- dgux*)
- library_names_spec='$libname$shrext'
- ;;
- freebsd1*)
- ;;
- freebsd* | dragonfly*)
- case "$host_os" in
- freebsd[123]*)
- library_names_spec='$libname$shrext$versuffix' ;;
- *)
- library_names_spec='$libname$shrext' ;;
- esac
- ;;
- gnu*)
- library_names_spec='$libname$shrext'
- ;;
- hpux9* | hpux10* | hpux11*)
- case $host_cpu in
- ia64*)
- shrext=.so
- ;;
- hppa*64*)
- shrext=.sl
- ;;
- *)
- shrext=.sl
- ;;
- esac
- library_names_spec='$libname$shrext'
- ;;
- interix[3-9]*)
- library_names_spec='$libname$shrext'
- ;;
- irix5* | irix6* | nonstopux*)
- library_names_spec='$libname$shrext'
- case "$host_os" in
- irix5* | nonstopux*)
- libsuff= shlibsuff=
- ;;
- *)
- case $LD in
- *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;;
- *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;;
- *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;;
- *) libsuff= shlibsuff= ;;
- esac
- ;;
- esac
- ;;
- linux*oldld* | linux*aout* | linux*coff*)
- ;;
- linux* | k*bsd*-gnu)
- library_names_spec='$libname$shrext'
- ;;
- knetbsd*-gnu)
- library_names_spec='$libname$shrext'
- ;;
- netbsd*)
- library_names_spec='$libname$shrext'
- ;;
- newsos6)
- library_names_spec='$libname$shrext'
- ;;
- nto-qnx*)
- library_names_spec='$libname$shrext'
- ;;
- openbsd*)
- library_names_spec='$libname$shrext$versuffix'
- ;;
- os2*)
- libname_spec='$name'
- shrext=.dll
- library_names_spec='$libname.a'
- ;;
- osf3* | osf4* | osf5*)
- library_names_spec='$libname$shrext'
- ;;
- rdos*)
- ;;
- solaris*)
- library_names_spec='$libname$shrext'
- ;;
- sunos4*)
- library_names_spec='$libname$shrext$versuffix'
- ;;
- sysv4 | sysv4.3*)
- library_names_spec='$libname$shrext'
- ;;
- sysv4*MP*)
- library_names_spec='$libname$shrext'
- ;;
- sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
- library_names_spec='$libname$shrext'
- ;;
- uts4*)
- library_names_spec='$libname$shrext'
- ;;
-esac
-
-sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
-escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"`
-shlibext=`echo "$shrext" | sed -e 's,^\.,,'`
-escaped_libname_spec=`echo "X$libname_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
-escaped_library_names_spec=`echo "X$library_names_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
-escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
-
-LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' <<EOF
-
-# How to pass a linker flag through the compiler.
-wl="$escaped_wl"
-
-# Static library suffix (normally "a").
-libext="$libext"
-
-# Shared library suffix (normally "so").
-shlibext="$shlibext"
-
-# Format of library name prefix.
-libname_spec="$escaped_libname_spec"
-
-# Library names that the linker finds when passed -lNAME.
-library_names_spec="$escaped_library_names_spec"
-
-# Flag to hardcode \$libdir into a binary during linking.
-# This must work even if \$libdir does not exist.
-hardcode_libdir_flag_spec="$escaped_hardcode_libdir_flag_spec"
-
-# Whether we need a single -rpath flag with a separated argument.
-hardcode_libdir_separator="$hardcode_libdir_separator"
-
-# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the
-# resulting binary.
-hardcode_direct="$hardcode_direct"
-
-# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
-# resulting binary.
-hardcode_minus_L="$hardcode_minus_L"
-
-EOF
diff --git a/po/Makefile.in.in b/po/Makefile.in.in
deleted file mode 100644
index 83d8838..0000000
--- a/po/Makefile.in.in
+++ /dev/null
@@ -1,444 +0,0 @@
-# Makefile for PO directory in any package using GNU gettext.
-# Copyright (C) 1995-1997, 2000-2007, 2009-2010 by Ulrich Drepper <drepper(a)gnu.ai.mit.edu>
-#
-# This file can be copied and used freely without restrictions. It can
-# be used in projects which are not available under the GNU General Public
-# License but which still want to provide support for the GNU gettext
-# functionality.
-# Please note that the actual code of GNU gettext is covered by the GNU
-# General Public License and is *not* in the public domain.
-#
-# Origin: gettext-0.18
-GETTEXT_MACRO_VERSION = 0.18
-
-PACKAGE = @PACKAGE@
-VERSION = @VERSION@
-PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
-
-SHELL = /bin/sh
-@SET_MAKE@
-
-srcdir = @srcdir@
-top_srcdir = @top_srcdir@
-VPATH = @srcdir@
-
-prefix = @prefix@
-exec_prefix = @exec_prefix@
-datarootdir = @datarootdir@
-datadir = @datadir@
-localedir = @localedir@
-gettextsrcdir = $(datadir)/gettext/po
-
-INSTALL = @INSTALL@
-INSTALL_DATA = @INSTALL_DATA@
-
-# We use $(mkdir_p).
-# In automake <= 1.9.x, $(mkdir_p) is defined either as "mkdir -p --" or as
-# "$(mkinstalldirs)" or as "$(install_sh) -d". For these automake versions,
-# @install_sh@ does not start with $(SHELL), so we add it.
-# In automake >= 1.10, @mkdir_p@ is derived from ${MKDIR_P}, which is defined
-# either as "/path/to/mkdir -p" or ".../install-sh -c -d". For these automake
-# versions, $(mkinstalldirs) and $(install_sh) are unused.
-mkinstalldirs = $(SHELL) @install_sh@ -d
-install_sh = $(SHELL) @install_sh@
-MKDIR_P = @MKDIR_P@
-mkdir_p = @mkdir_p@
-
-GMSGFMT_ = @GMSGFMT@
-GMSGFMT_no = @GMSGFMT@
-GMSGFMT_yes = @GMSGFMT_015@
-GMSGFMT = $(GMSGFMT_$(USE_MSGCTXT))
-MSGFMT_ = @MSGFMT@
-MSGFMT_no = @MSGFMT@
-MSGFMT_yes = @MSGFMT_015@
-MSGFMT = $(MSGFMT_$(USE_MSGCTXT))
-XGETTEXT_ = @XGETTEXT@
-XGETTEXT_no = @XGETTEXT@
-XGETTEXT_yes = @XGETTEXT_015@
-XGETTEXT = $(XGETTEXT_$(USE_MSGCTXT))
-MSGMERGE = msgmerge
-MSGMERGE_UPDATE = @MSGMERGE@ --update
-MSGINIT = msginit
-MSGCONV = msgconv
-MSGFILTER = msgfilter
-
-POFILES = @POFILES@
-GMOFILES = @GMOFILES@
-UPDATEPOFILES = @UPDATEPOFILES@
-DUMMYPOFILES = @DUMMYPOFILES@
-DISTFILES.common = Makefile.in.in remove-potcdate.sin \
-$(DISTFILES.common.extra1) $(DISTFILES.common.extra2) $(DISTFILES.common.extra3)
-DISTFILES = $(DISTFILES.common) Makevars POTFILES.in \
-$(POFILES) $(GMOFILES) \
-$(DISTFILES.extra1) $(DISTFILES.extra2) $(DISTFILES.extra3)
-
-POTFILES = \
-
-CATALOGS = @CATALOGS@
-
-# Makevars gets inserted here. (Don't remove this line!)
-
-.SUFFIXES:
-.SUFFIXES: .po .gmo .mo .sed .sin .nop .po-create .po-update
-
-.po.mo:
- @echo "$(MSGFMT) -c -o $@ $<"; \
- $(MSGFMT) -c -o t-$@ $< && mv t-$@ $@
-
-.po.gmo:
- @lang=`echo $* | sed -e 's,.*/,,'`; \
- test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \
- echo "$${cdcmd}rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics --verbose -o $${lang}.gmo $${lang}.po"; \
- cd $(srcdir) && rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics --verbose -o t-$${lang}.gmo $${lang}.po && mv t-$${lang}.gmo $${lang}.gmo
-
-.sin.sed:
- sed -e '/^#/d' $< > t-$@
- mv t-$@ $@
-
-
-all: check-macro-version all-@USE_NLS@
-
-all-yes: stamp-po
-all-no:
-
-# Ensure that the gettext macros and this Makefile.in.in are in sync.
-check-macro-version:
- @test "$(GETTEXT_MACRO_VERSION)" = "@GETTEXT_MACRO_VERSION@" \
- || { echo "*** error: gettext infrastructure mismatch: using a Makefile.in.in from gettext version $(GETTEXT_MACRO_VERSION) but the autoconf macros are from gettext version @GETTEXT_MACRO_VERSION@" 1>&2; \
- exit 1; \
- }
-
-# $(srcdir)/$(DOMAIN).pot is only created when needed. When xgettext finds no
-# internationalized messages, no $(srcdir)/$(DOMAIN).pot is created (because
-# we don't want to bother translators with empty POT files). We assume that
-# LINGUAS is empty in this case, i.e. $(POFILES) and $(GMOFILES) are empty.
-# In this case, stamp-po is a nop (i.e. a phony target).
-
-# stamp-po is a timestamp denoting the last time at which the CATALOGS have
-# been loosely updated. Its purpose is that when a developer or translator
-# checks out the package via CVS, and the $(DOMAIN).pot file is not in CVS,
-# "make" will update the $(DOMAIN).pot and the $(CATALOGS), but subsequent
-# invocations of "make" will do nothing. This timestamp would not be necessary
-# if updating the $(CATALOGS) would always touch them; however, the rule for
-# $(POFILES) has been designed to not touch files that don't need to be
-# changed.
-stamp-po: $(srcdir)/$(DOMAIN).pot
- test ! -f $(srcdir)/$(DOMAIN).pot || \
- test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES)
- @test ! -f $(srcdir)/$(DOMAIN).pot || { \
- echo "touch stamp-po" && \
- echo timestamp > stamp-poT && \
- mv stamp-poT stamp-po; \
- }
-
-# Note: Target 'all' must not depend on target '$(DOMAIN).pot-update',
-# otherwise packages like GCC can not be built if only parts of the source
-# have been downloaded.
-
-# This target rebuilds $(DOMAIN).pot; it is an expensive operation.
-# Note that $(DOMAIN).pot is not touched if it doesn't need to be changed.
-$(DOMAIN).pot-update: $(POTFILES) $(srcdir)/POTFILES.in remove-potcdate.sed
- if LC_ALL=C grep 'GNU @PACKAGE@' $(top_srcdir)/* 2>/dev/null | grep -v 'libtool:' >/dev/null; then \
- package_gnu='GNU '; \
- else \
- package_gnu=''; \
- fi; \
- if test -n '$(MSGID_BUGS_ADDRESS)' || test '$(PACKAGE_BUGREPORT)' = '@'PACKAGE_BUGREPORT'@'; then \
- msgid_bugs_address='$(MSGID_BUGS_ADDRESS)'; \
- else \
- msgid_bugs_address='$(PACKAGE_BUGREPORT)'; \
- fi; \
- case `$(XGETTEXT) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \
- '' | 0.[0-9] | 0.[0-9].* | 0.1[0-5] | 0.1[0-5].* | 0.16 | 0.16.[0-1]*) \
- $(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \
- --add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) @XGETTEXT_EXTRA_OPTIONS@ \
- --files-from=$(srcdir)/POTFILES.in \
- --copyright-holder='$(COPYRIGHT_HOLDER)' \
- --msgid-bugs-address="$$msgid_bugs_address" \
- ;; \
- *) \
- $(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \
- --add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) @XGETTEXT_EXTRA_OPTIONS@ \
- --files-from=$(srcdir)/POTFILES.in \
- --copyright-holder='$(COPYRIGHT_HOLDER)' \
- --package-name="$${package_gnu}@PACKAGE@" \
- --package-version='@VERSION@' \
- --msgid-bugs-address="$$msgid_bugs_address" \
- ;; \
- esac
- test ! -f $(DOMAIN).po || { \
- if test -f $(srcdir)/$(DOMAIN).pot; then \
- sed -f remove-potcdate.sed < $(srcdir)/$(DOMAIN).pot > $(DOMAIN).1po && \
- sed -f remove-potcdate.sed < $(DOMAIN).po > $(DOMAIN).2po && \
- if cmp $(DOMAIN).1po $(DOMAIN).2po >/dev/null 2>&1; then \
- rm -f $(DOMAIN).1po $(DOMAIN).2po $(DOMAIN).po; \
- else \
- rm -f $(DOMAIN).1po $(DOMAIN).2po $(srcdir)/$(DOMAIN).pot && \
- mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot; \
- fi; \
- else \
- mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot; \
- fi; \
- }
-
-# This rule has no dependencies: we don't need to update $(DOMAIN).pot at
-# every "make" invocation, only create it when it is missing.
-# Only "make $(DOMAIN).pot-update" or "make dist" will force an update.
-$(srcdir)/$(DOMAIN).pot:
- $(MAKE) $(DOMAIN).pot-update
-
-# This target rebuilds a PO file if $(DOMAIN).pot has changed.
-# Note that a PO file is not touched if it doesn't need to be changed.
-$(POFILES): $(srcdir)/$(DOMAIN).pot
- @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \
- if test -f "$(srcdir)/$${lang}.po"; then \
- test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \
- echo "$${cdcmd}$(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) --lang=$${lang} $${lang}.po $(DOMAIN).pot"; \
- cd $(srcdir) \
- && { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \
- '' | 0.[0-9] | 0.[0-9].* | 0.1[0-7] | 0.1[0-7].*) \
- $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \
- *) \
- $(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) --lang=$${lang} $${lang}.po $(DOMAIN).pot;; \
- esac; \
- }; \
- else \
- $(MAKE) $${lang}.po-create; \
- fi
-
-
-install: install-exec install-data
-install-exec:
-install-data: install-data-@USE_NLS@
- if test "$(PACKAGE)" = "gettext-tools"; then \
- $(mkdir_p) $(DESTDIR)$(gettextsrcdir); \
- for file in $(DISTFILES.common) Makevars.template; do \
- $(INSTALL_DATA) $(srcdir)/$$file \
- $(DESTDIR)$(gettextsrcdir)/$$file; \
- done; \
- for file in Makevars; do \
- rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \
- done; \
- else \
- : ; \
- fi
-install-data-no: all
-install-data-yes: all
- @catalogs='$(CATALOGS)'; \
- for cat in $$catalogs; do \
- cat=`basename $$cat`; \
- lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \
- dir=$(localedir)/$$lang/LC_MESSAGES; \
- $(mkdir_p) $(DESTDIR)$$dir; \
- if test -r $$cat; then realcat=$$cat; else realcat=$(srcdir)/$$cat; fi; \
- $(INSTALL_DATA) $$realcat $(DESTDIR)$$dir/$(DOMAIN).mo; \
- echo "installing $$realcat as $(DESTDIR)$$dir/$(DOMAIN).mo"; \
- for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \
- if test -n "$$lc"; then \
- if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \
- link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \
- mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \
- mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \
- (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \
- for file in *; do \
- if test -f $$file; then \
- ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \
- fi; \
- done); \
- rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \
- else \
- if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \
- :; \
- else \
- rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \
- mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \
- fi; \
- fi; \
- rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \
- ln -s ../LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \
- ln $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \
- cp -p $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \
- echo "installing $$realcat link as $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo"; \
- fi; \
- done; \
- done
-
-install-strip: install
-
-installdirs: installdirs-exec installdirs-data
-installdirs-exec:
-installdirs-data: installdirs-data-@USE_NLS@
- if test "$(PACKAGE)" = "gettext-tools"; then \
- $(mkdir_p) $(DESTDIR)$(gettextsrcdir); \
- else \
- : ; \
- fi
-installdirs-data-no:
-installdirs-data-yes:
- @catalogs='$(CATALOGS)'; \
- for cat in $$catalogs; do \
- cat=`basename $$cat`; \
- lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \
- dir=$(localedir)/$$lang/LC_MESSAGES; \
- $(mkdir_p) $(DESTDIR)$$dir; \
- for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \
- if test -n "$$lc"; then \
- if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \
- link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \
- mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \
- mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \
- (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \
- for file in *; do \
- if test -f $$file; then \
- ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \
- fi; \
- done); \
- rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \
- else \
- if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \
- :; \
- else \
- rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \
- mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \
- fi; \
- fi; \
- fi; \
- done; \
- done
-
-# Define this as empty until I found a useful application.
-installcheck:
-
-uninstall: uninstall-exec uninstall-data
-uninstall-exec:
-uninstall-data: uninstall-data-@USE_NLS@
- if test "$(PACKAGE)" = "gettext-tools"; then \
- for file in $(DISTFILES.common) Makevars.template; do \
- rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \
- done; \
- else \
- : ; \
- fi
-uninstall-data-no:
-uninstall-data-yes:
- catalogs='$(CATALOGS)'; \
- for cat in $$catalogs; do \
- cat=`basename $$cat`; \
- lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \
- for lc in LC_MESSAGES $(EXTRA_LOCALE_CATEGORIES); do \
- rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \
- done; \
- done
-
-check: all
-
-info dvi ps pdf html tags TAGS ctags CTAGS ID:
-
-mostlyclean:
- rm -f remove-potcdate.sed
- rm -f stamp-poT
- rm -f core core.* $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po
- rm -fr *.o
-
-clean: mostlyclean
-
-distclean: clean
- rm -f Makefile Makefile.in POTFILES *.mo
-
-maintainer-clean: distclean
- @echo "This command is intended for maintainers to use;"
- @echo "it deletes files that may require special tools to rebuild."
- rm -f stamp-po $(GMOFILES)
-
-distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
-dist distdir:
- $(MAKE) update-po
- @$(MAKE) dist2
-# This is a separate target because 'update-po' must be executed before.
-dist2: stamp-po $(DISTFILES)
- dists="$(DISTFILES)"; \
- if test "$(PACKAGE)" = "gettext-tools"; then \
- dists="$$dists Makevars.template"; \
- fi; \
- if test -f $(srcdir)/$(DOMAIN).pot; then \
- dists="$$dists $(DOMAIN).pot stamp-po"; \
- fi; \
- if test -f $(srcdir)/ChangeLog; then \
- dists="$$dists ChangeLog"; \
- fi; \
- for i in 0 1 2 3 4 5 6 7 8 9; do \
- if test -f $(srcdir)/ChangeLog.$$i; then \
- dists="$$dists ChangeLog.$$i"; \
- fi; \
- done; \
- if test -f $(srcdir)/LINGUAS; then dists="$$dists LINGUAS"; fi; \
- for file in $$dists; do \
- if test -f $$file; then \
- cp -p $$file $(distdir) || exit 1; \
- else \
- cp -p $(srcdir)/$$file $(distdir) || exit 1; \
- fi; \
- done
-
-update-po: Makefile
- $(MAKE) $(DOMAIN).pot-update
- test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES)
- $(MAKE) update-gmo
-
-# General rule for creating PO files.
-
-.nop.po-create:
- @lang=`echo $@ | sed -e 's/\.po-create$$//'`; \
- echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \
- exit 1
-
-# General rule for updating PO files.
-
-.nop.po-update:
- @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \
- if test "$(PACKAGE)" = "gettext-tools"; then PATH=`pwd`/../src:$$PATH; fi; \
- tmpdir=`pwd`; \
- echo "$$lang:"; \
- test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \
- echo "$${cdcmd}$(MSGMERGE) $(MSGMERGE_OPTIONS) --lang=$$lang $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \
- cd $(srcdir); \
- if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \
- '' | 0.[0-9] | 0.[0-9].* | 0.1[0-7] | 0.1[0-7].*) \
- $(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \
- *) \
- $(MSGMERGE) $(MSGMERGE_OPTIONS) --lang=$$lang -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \
- esac; \
- }; then \
- if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \
- rm -f $$tmpdir/$$lang.new.po; \
- else \
- if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \
- :; \
- else \
- echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \
- exit 1; \
- fi; \
- fi; \
- else \
- echo "msgmerge for $$lang.po failed!" 1>&2; \
- rm -f $$tmpdir/$$lang.new.po; \
- fi
-
-$(DUMMYPOFILES):
-
-update-gmo: Makefile $(GMOFILES)
- @:
-
-# Recreate Makefile by invoking config.status. Explicitly invoke the shell,
-# because execution permission bits may not work on the current file system.
-# Use @SHELL@, which is the shell determined by autoconf for the use by its
-# scripts, not $(SHELL) which is hardwired to /bin/sh and may be deficient.
-Makefile: Makefile.in.in Makevars $(top_builddir)/config.status @POMAKEFILEDEPS@
- cd $(top_builddir) \
- && @SHELL@ ./config.status $(subdir)/$@.in po-directories
-
-force:
-
-# Tell versions [3.59,3.63) of GNU make not to export all variables.
-# Otherwise a system limit (for SysV at least) may be exceeded.
-.NOEXPORT:
diff --git a/po/Rules-quot b/po/Rules-quot
deleted file mode 100644
index af52487..0000000
--- a/po/Rules-quot
+++ /dev/null
@@ -1,47 +0,0 @@
-# Special Makefile rules for English message catalogs with quotation marks.
-
-DISTFILES.common.extra1 = quot.sed boldquot.sed en(a)quot.header en(a)boldquot.header insert-header.sin Rules-quot
-
-.SUFFIXES: .insert-header .po-update-en
-
-en(a)quot.po-create:
- $(MAKE) en(a)quot.po-update
-en(a)boldquot.po-create:
- $(MAKE) en(a)boldquot.po-update
-
-en(a)quot.po-update: en(a)quot.po-update-en
-en(a)boldquot.po-update: en(a)boldquot.po-update-en
-
-.insert-header.po-update-en:
- @lang=`echo $@ | sed -e 's/\.po-update-en$$//'`; \
- if test "$(PACKAGE)" = "gettext"; then PATH=`pwd`/../src:$$PATH; GETTEXTLIBDIR=`cd $(top_srcdir)/src && pwd`; export GETTEXTLIBDIR; fi; \
- tmpdir=`pwd`; \
- echo "$$lang:"; \
- ll=`echo $$lang | sed -e 's/@.*//'`; \
- LC_ALL=C; export LC_ALL; \
- cd $(srcdir); \
- if $(MSGINIT) -i $(DOMAIN).pot --no-translator -l $$lang -o - 2>/dev/null | sed -f $$tmpdir/$$lang.insert-header | $(MSGCONV) -t UTF-8 | $(MSGFILTER) sed -f `echo $$lang | sed -e 's/.*@//'`.sed 2>/dev/null > $$tmpdir/$$lang.new.po; then \
- if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \
- rm -f $$tmpdir/$$lang.new.po; \
- else \
- if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \
- :; \
- else \
- echo "creation of $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \
- exit 1; \
- fi; \
- fi; \
- else \
- echo "creation of $$lang.po failed!" 1>&2; \
- rm -f $$tmpdir/$$lang.new.po; \
- fi
-
-en(a)quot.insert-header: insert-header.sin
- sed -e '/^#/d' -e 's/HEADER/en(a)quot.header/g' $(srcdir)/insert-header.sin > en(a)quot.insert-header
-
-en(a)boldquot.insert-header: insert-header.sin
- sed -e '/^#/d' -e 's/HEADER/en(a)boldquot.header/g' $(srcdir)/insert-header.sin > en(a)boldquot.insert-header
-
-mostlyclean: mostlyclean-quot
-mostlyclean-quot:
- rm -f *.insert-header
diff --git a/po/boldquot.sed b/po/boldquot.sed
deleted file mode 100644
index 4b937aa..0000000
--- a/po/boldquot.sed
+++ /dev/null
@@ -1,10 +0,0 @@
-s/"\([^"]*\)"/“\1”/g
-s/`\([^`']*\)'/‘\1’/g
-s/ '\([^`']*\)' / ‘\1’ /g
-s/ '\([^`']*\)'$/ ‘\1’/g
-s/^'\([^`']*\)' /‘\1’ /g
-s/“”/""/g
-s/“/“[1m/g
-s/”/[0m”/g
-s/‘/‘[1m/g
-s/’/[0m’/g
diff --git a/po/insert-header.sin b/po/insert-header.sin
deleted file mode 100644
index b26de01..0000000
--- a/po/insert-header.sin
+++ /dev/null
@@ -1,23 +0,0 @@
-# Sed script that inserts the file called HEADER before the header entry.
-#
-# At each occurrence of a line starting with "msgid ", we execute the following
-# commands. At the first occurrence, insert the file. At the following
-# occurrences, do nothing. The distinction between the first and the following
-# occurrences is achieved by looking at the hold space.
-/^msgid /{
-x
-# Test if the hold space is empty.
-s/m/m/
-ta
-# Yes it was empty. First occurrence. Read the file.
-r HEADER
-# Output the file's contents by reading the next line. But don't lose the
-# current line while doing this.
-g
-N
-bb
-:a
-# The hold space was nonempty. Following occurrences. Do nothing.
-x
-:b
-}
diff --git a/po/quot.sed b/po/quot.sed
deleted file mode 100644
index 0122c46..0000000
--- a/po/quot.sed
+++ /dev/null
@@ -1,6 +0,0 @@
-s/"\([^"]*\)"/“\1”/g
-s/`\([^`']*\)'/‘\1’/g
-s/ '\([^`']*\)' / ‘\1’ /g
-s/ '\([^`']*\)'$/ ‘\1’/g
-s/^'\([^`']*\)' /‘\1’ /g
-s/“”/""/g
diff --git a/po/remove-potcdate.sin b/po/remove-potcdate.sin
deleted file mode 100644
index 2436c49..0000000
--- a/po/remove-potcdate.sin
+++ /dev/null
@@ -1,19 +0,0 @@
-# Sed script that remove the POT-Creation-Date line in the header entry
-# from a POT file.
-#
-# The distinction between the first and the following occurrences of the
-# pattern is achieved by looking at the hold space.
-/^"POT-Creation-Date: .*"$/{
-x
-# Test if the hold space is empty.
-s/P/P/
-ta
-# Yes it was empty. First occurrence. Remove the line.
-g
-d
-bb
-:a
-# The hold space was nonempty. Following occurrences. Do nothing.
-x
-:b
-}
Gitweb: http://git.fedorahosted.org/git/?p=fence-agents.git;a=commitdiff;h=d6504496…
Commit: d6504496b019dcd6bd066dd398b898b87d4ddd49
Parent: cda15e4940779111aa69aa29da705ae91b789a83
Author: Marek 'marx' Grac <mgrac(a)redhat.com>
AuthorDate: Mon May 27 15:19:59 2013 +0200
Committer: Marek 'marx' Grac <mgrac(a)redhat.com>
CommitterDate: Mon May 27 15:19:59 2013 +0200
fence_scsi: Add 'unfence' to manual page
Resolves: rhbz#887349
---
fence/agents/scsi/fence_scsi.8 | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/fence/agents/scsi/fence_scsi.8 b/fence/agents/scsi/fence_scsi.8
index 0d70930..da2e451 100644
--- a/fence/agents/scsi/fence_scsi.8
+++ b/fence/agents/scsi/fence_scsi.8
@@ -21,7 +21,8 @@ registrants only" reservation on the device(s). The result is that
only registered nodes may write to the device(s). When a node failure
occurs, the fence_scsi agent will remove the key belonging to the
failed node from the device(s). The failed node will no longer be able
-to write to the device(s). A manual reboot is required.
+to write to the device(s). A manual reboot is required. In the cluster
+environment unfence action should be configured also.
Keys are either be specified manually (see -k option) or generated
automatically (see -n option). Automatic key generation requires that
Gitweb: http://git.fedorahosted.org/git/?p=fence-agents.git;a=commitdiff;h=cda15e49…
Commit: cda15e4940779111aa69aa29da705ae91b789a83
Parent: a503b8a48236b63ba156d773aa60a41561c8f082
Author: Marek 'marx' Grac <mgrac(a)redhat.com>
AuthorDate: Fri May 24 16:17:12 2013 +0200
Committer: Marek 'marx' Grac <mgrac(a)redhat.com>
CommitterDate: Fri May 24 16:17:12 2013 +0200
fencing: Validation if password/password_script or identity file is used was not processed
Resolves: rhbz#959490
---
fence/agents/lib/fencing.py.py | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/fence/agents/lib/fencing.py.py b/fence/agents/lib/fencing.py.py
index b14c329..b7ea3d9 100644
--- a/fence/agents/lib/fencing.py.py
+++ b/fence/agents/lib/fencing.py.py
@@ -675,9 +675,9 @@ def check_input(device_opt, opt):
if 0 == device_opt.count("identity_file"):
if 0 == (options.has_key("--password") or options.has_key("--password-script")):
fail_usage("Failed: You have to enter password or password script")
- else:
- if 0 == (options.has_key("--password") or options.has_key("--password-script") or options.has_key("--identity-file")):
- fail_usage("Failed: You have to enter password, password script or identity file")
+ else:
+ if 0 == (options.has_key("--password") or options.has_key("--password-script") or options.has_key("--identity-file")):
+ fail_usage("Failed: You have to enter password, password script or identity file")
if 0 == options.has_key("--ssh") and 1 == options.has_key("--identity-file"):
fail_usage("Failed: You have to use identity file together with ssh connection (-x)")
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=4a662b42cd195…
Commit: 4a662b42cd19598f3a2d7e8b4a15306489baccd8
Parent: 78c9f0a7eaa2c2aecb7ecbef518fb53a2bb6a871
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Tue May 14 09:51:28 2013 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri May 17 15:33:42 2013 -0500
fsck.gfs2: delete all duplicates from unrecoverable damaged dinodes
When pass1 encounters a dinode with unrecoverable damage, it tries
to "undo" the metadata and data block designations it marked in the
blockmap prior to finding the damage. That's all fine, but if the
damaged dinode has a duplicate reference, we also need to delete that
from the duplicate reference list. Otherwise pass1b may try to
resolve the duplicate reference and reinstate the damaged dinode.
rhbz#902920
---
gfs2/fsck/metawalk.c | 5 ++++
gfs2/fsck/pass1b.c | 60 --------------------------------------------------
gfs2/fsck/util.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++
gfs2/fsck/util.h | 2 +
4 files changed, 66 insertions(+), 60 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 1d56490..84366a2 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -1529,6 +1529,11 @@ undo_metalist:
brelse(bh);
}
}
+ /* There may be leftover duplicate records, so we need to delete them.
+ For example, if a metadata block was found to be a duplicate, we
+ may not have added it to the metalist, which means it's not there
+ to undo. */
+ delete_all_dups(ip);
/* Set the dinode as "bad" so it gets deleted */
fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
_("corrupt"), gfs2_block_free);
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index 224a5d0..e15d6b2 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -50,66 +50,6 @@ static void log_inode_reference(struct duptree *dt, osi_list_t *tmp, int inval)
}
/* delete_all_dups - delete all duplicate records for a given inode */
-static void delete_all_dups(struct gfs2_inode *ip)
-{
- struct osi_node *n, *next;
- struct duptree *dt;
- osi_list_t *tmp, *x;
- struct inode_with_dups *id;
- int found;
-
- for (n = osi_first(&dup_blocks); n; n = next) {
- next = osi_next(n);
- dt = (struct duptree *)n;
-
- found = 0;
- id = NULL;
-
- osi_list_foreach_safe(tmp, &dt->ref_invinode_list, x) {
- id = osi_list_entry(tmp, struct inode_with_dups, list);
- if (id->block_no == ip->i_di.di_num.no_addr) {
- dup_listent_delete(dt, id);
- found = 1;
- }
- }
- osi_list_foreach_safe(tmp, &dt->ref_inode_list, x) {
- id = osi_list_entry(tmp, struct inode_with_dups, list);
- if (id->block_no == ip->i_di.di_num.no_addr) {
- dup_listent_delete(dt, id);
- found = 1;
- }
- }
- if (!found)
- continue;
-
- if (dt->refs == 0) {
- log_debug(_("This was the last reference: 0x%llx is "
- "no longer a duplicate.\n"),
- (unsigned long long)dt->block);
- dup_delete(dt); /* not duplicate now */
- } else {
- log_debug(_("%d references remain to 0x%llx\n"),
- dt->refs, (unsigned long long)dt->block);
- if (dt->refs > 1)
- continue;
-
- id = NULL;
- osi_list_foreach(tmp, &dt->ref_invinode_list)
- id = osi_list_entry(tmp,
- struct inode_with_dups,
- list);
- osi_list_foreach(tmp, &dt->ref_inode_list)
- id = osi_list_entry(tmp,
- struct inode_with_dups,
- list);
- if (id)
- log_debug("Last reference is from inode "
- "0x%llx\n",
- (unsigned long long)id->block_no);
- }
- }
-}
-
/*
* resolve_dup_references - resolve all but the last dinode that has a
* duplicate reference to a given block.
diff --git a/gfs2/fsck/util.c b/gfs2/fsck/util.c
index d4d9034..7ee49be 100644
--- a/gfs2/fsck/util.c
+++ b/gfs2/fsck/util.c
@@ -643,3 +643,62 @@ uint64_t *get_dir_hash(struct gfs2_inode *ip)
return tbl;
}
+void delete_all_dups(struct gfs2_inode *ip)
+{
+ struct osi_node *n, *next;
+ struct duptree *dt;
+ osi_list_t *tmp, *x;
+ struct inode_with_dups *id;
+ int found;
+
+ for (n = osi_first(&dup_blocks); n; n = next) {
+ next = osi_next(n);
+ dt = (struct duptree *)n;
+
+ found = 0;
+ id = NULL;
+
+ osi_list_foreach_safe(tmp, &dt->ref_invinode_list, x) {
+ id = osi_list_entry(tmp, struct inode_with_dups, list);
+ if (id->block_no == ip->i_di.di_num.no_addr) {
+ dup_listent_delete(dt, id);
+ found = 1;
+ }
+ }
+ osi_list_foreach_safe(tmp, &dt->ref_inode_list, x) {
+ id = osi_list_entry(tmp, struct inode_with_dups, list);
+ if (id->block_no == ip->i_di.di_num.no_addr) {
+ dup_listent_delete(dt, id);
+ found = 1;
+ }
+ }
+ if (!found)
+ continue;
+
+ if (dt->refs == 0) {
+ log_debug(_("This was the last reference: 0x%llx is "
+ "no longer a duplicate.\n"),
+ (unsigned long long)dt->block);
+ dup_delete(dt); /* not duplicate now */
+ } else {
+ log_debug(_("%d references remain to 0x%llx\n"),
+ dt->refs, (unsigned long long)dt->block);
+ if (dt->refs > 1)
+ continue;
+
+ id = NULL;
+ osi_list_foreach(tmp, &dt->ref_invinode_list)
+ id = osi_list_entry(tmp,
+ struct inode_with_dups,
+ list);
+ osi_list_foreach(tmp, &dt->ref_inode_list)
+ id = osi_list_entry(tmp,
+ struct inode_with_dups,
+ list);
+ if (id)
+ log_debug("Last reference is from inode "
+ "0x%llx\n",
+ (unsigned long long)id->block_no);
+ }
+ }
+}
diff --git a/gfs2/fsck/util.h b/gfs2/fsck/util.h
index 940f500..fe3fd6a 100644
--- a/gfs2/fsck/util.h
+++ b/gfs2/fsck/util.h
@@ -183,4 +183,6 @@ extern int gfs2_blockmap_set(struct gfs2_bmap *il, uint64_t block,
extern int set_ip_blockmap(struct gfs2_inode *ip, int instree);
extern uint64_t find_free_blk(struct gfs2_sbd *sdp);
extern uint64_t *get_dir_hash(struct gfs2_inode *ip);
+extern void delete_all_dups(struct gfs2_inode *ip);
+
#endif /* __UTIL_H__ */
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=78c9f0a7eaa2c…
Commit: 78c9f0a7eaa2c2aecb7ecbef518fb53a2bb6a871
Parent: bf9a851204b747f850a3a95a907cd8101bc2b726
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Fri Apr 19 09:25:51 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri May 17 15:33:36 2013 -0500
fsck.gfs2: take hash table start boundaries into account
When checking the hash table in pass2, we can't just keep doubling
the length for each consecutive check because the number of pointer
copies (aka length) is also tied to the starting offset. If the
starting offset is invalid for the length, it might treat a chunk of
the hash table as bigger than it should, eventually overwriting good
entries. Along the same lines, while we're trying to determine the
length, it's not good enough to double the length and check if the
hash table entry matches. The reason is: there can be several values
overwritten with the same value, 0x00, that indicates places where
pass1 found an invalid leaf block pointer. To avoid that, we need to
check intermediate values as well, and stop if we find a gap.
rhbz#902920
---
gfs2/fsck/metawalk.c | 5 +++--
gfs2/fsck/pass2.c | 43 ++++++++++++++++++++++++++++++++++---------
2 files changed, 37 insertions(+), 11 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 78047ec..1d56490 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -471,11 +471,12 @@ static int check_entries(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
if ((char *)dent + de.de_rec_len >= bh_end){
log_debug( _("Last entry processed for %lld->%lld "
- "(0x%llx->0x%llx).\n"),
+ "(0x%llx->0x%llx), di_blocks=%llu.\n"),
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)bh->b_blocknr,
(unsigned long long)ip->i_di.di_num.no_addr,
- (unsigned long long)bh->b_blocknr);
+ (unsigned long long)bh->b_blocknr,
+ (unsigned long long)ip->i_di.di_blocks);
break;
}
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index 4b3a5c0..4b3efd9 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -368,9 +368,10 @@ static int wrong_leaf(struct gfs2_inode *ip, struct gfs2_inum *entry,
gfs2_get_leaf_nr(ip, hash_index, &real_leaf);
if (real_leaf != planned_leaf) {
log_err(_("The planned leaf was split. The new leaf "
- "is: %llu (0x%llx)"),
+ "is: %llu (0x%llx). di_blocks=%llu\n"),
(unsigned long long)real_leaf,
- (unsigned long long)real_leaf);
+ (unsigned long long)real_leaf,
+ (unsigned long long)ip->i_di.di_blocks);
fsck_blockmap_set(ip, real_leaf, _("split leaf"),
gfs2_indir_blk);
}
@@ -1030,6 +1031,7 @@ static int basic_check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
log_err( _("Bad directory entry '%s' cleared.\n"), tmp_name);
return 1;
} else {
+ (*count)++;
return 0;
}
}
@@ -1148,11 +1150,13 @@ static int fix_hashtable(struct gfs2_inode *ip, uint64_t *tbl, unsigned hsize,
/* Look at the first dirent and check its hash value to see if it's
at the proper starting offset. */
hash_index = hash_table_index(dentry.de_hash, ip);
+ /* Need to use len here, not *proper_len because the leaf block may
+ be valid within the range, but starts too soon in the hash table. */
if (hash_index < lindex || hash_index > lindex + len) {
log_err(_("This leaf block has hash index %d, which is out of "
"bounds for where it appears in the hash table "
"(%d - %d)\n"),
- hash_index, lindex, lindex + len);
+ hash_index, lindex, lindex + *proper_len);
error = lost_leaf(ip, tbl, leafblk, len, lindex, lbh);
brelse(lbh);
return error;
@@ -1289,6 +1293,8 @@ static int check_hash_tbl(struct gfs2_inode *ip, uint64_t *tbl,
struct gfs2_buffer_head *lbh;
int factor;
uint32_t proper_start;
+ uint32_t next_proper_start;
+ int anomaly;
lindex = 0;
while (lindex < hsize) {
@@ -1297,10 +1303,23 @@ static int check_hash_tbl(struct gfs2_inode *ip, uint64_t *tbl,
len = 1;
factor = 0;
leafblk = be64_to_cpu(tbl[lindex]);
+ next_proper_start = lindex;
+ anomaly = 0;
while (lindex + (len << 1) - 1 < hsize) {
if (be64_to_cpu(tbl[lindex + (len << 1) - 1]) !=
leafblk)
break;
+ next_proper_start = (lindex & ~((len << 1) - 1));
+ if (lindex != next_proper_start)
+ anomaly = 1;
+ /* Check if there are other values written between
+ here and the next factor. */
+ for (i = len; !anomaly && i + lindex < hsize &&
+ i < (len << 1); i++)
+ if (be64_to_cpu(tbl[lindex + i]) != leafblk)
+ anomaly = 1;
+ if (anomaly)
+ break;
len <<= 1;
factor++;
}
@@ -1342,8 +1361,10 @@ static int check_hash_tbl(struct gfs2_inode *ip, uint64_t *tbl,
proper_start = (lindex & ~(proper_len - 1));
if (lindex != proper_start) {
log_debug(_("lindex 0x%llx is not a proper starting "
- "point for this leaf: 0x%llx\n"),
+ "point for leaf %llu (0x%llx): 0x%llx\n"),
(unsigned long long)lindex,
+ (unsigned long long)leafblk,
+ (unsigned long long)leafblk,
(unsigned long long)proper_start);
changes = fix_hashtable(ip, tbl, hsize, leafblk,
lindex, proper_start, len,
@@ -1366,9 +1387,11 @@ static int check_hash_tbl(struct gfs2_inode *ip, uint64_t *tbl,
depth, and adjust the hash table accordingly. */
if (len != proper_len) {
log_err(_("Length %d (0x%x) is not a proper length "
- "for this leaf. Valid boundary assumed to "
- "be %d (0x%x).\n"),
- len, len, proper_len, proper_len);
+ "for leaf %llu (0x%llx). Valid boundary "
+ "assumed to be %d (0x%x).\n"), len, len,
+ (unsigned long long)leafblk,
+ (unsigned long long)leafblk,
+ proper_len, proper_len);
lbh = bread(ip->i_sbd, leafblk);
gfs2_leaf_in(&leaf, lbh);
if (gfs2_check_meta(lbh, GFS2_METATYPE_LF) ||
@@ -1417,8 +1440,10 @@ static int check_hash_tbl(struct gfs2_inode *ip, uint64_t *tbl,
proper_len = 1 << (ip->i_di.di_depth - leaf.lf_depth);
if (proper_len != len) {
log_debug(_("Length 0x%x is not proper for "
- "this leaf: 0x%x"),
- len, proper_len);
+ "leaf %llu (0x%llx): 0x%x"),
+ len, (unsigned long long)leafblk,
+ (unsigned long long)leafblk,
+ proper_len);
changes = fix_hashtable(ip, tbl, hsize,
leafblk, lindex,
lindex, len,
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=bf9a851204b74…
Commit: bf9a851204b747f850a3a95a907cd8101bc2b726
Parent: 100e0e1961e7f26c72ae59b57f5c86873053eb2f
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Wed Apr 17 14:09:30 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri May 17 15:33:01 2013 -0500
fsck.gfs2: Don't allocate leaf blocks in pass1
Before this patch, if leaf blocks were found to be corrupt, pass1
tried to fix them by allocating new leaf blocks in place of the bad
ones. That's a bad idea, because pass1 populates the blockmap and
sets the bitmap accordingly. In other words, it's dynamically changing.
Say, for example, that you're checking a directory a dinode 0x1234, and
it has a corrupt hash table, and needs new leaf blocks inserted.
Now suppose you have a second directory that occurs later in the bitmap,
say at block 0x2345, and it references leaf block 0x2346, but for some
reason that block (0x2346) is improperly set to "free" in the bitmap.
If pass1 goes out looking for a free block in order to allocate a new
leaf for 0x1234, it will naturally find block 0x2346, because it's
marked free. It writes a new leaf at that block and adds a new
reference in the hash table of 0x1234. Later, when pass1 processes
directory 0x2345, it discovers the reference to 0x2346. Not only has
it wiped out the perfectly good leaf block, it has also created a
duplicate block reference that it needs to sort out in pass1b, which
will likely keep the replaced reference and throw the good one we
had. Thus, we introduced corruption into the file system when we
should have kept the only good reference to 0x2346 and fixed the
bitmap.
The solution provided by this patch is to simply zero out the bad
hash table entries when pass1 comes across them. Later, when pass2
discovers the zero leaf blocks, it can safely allocate new blocks
(since pass1 synced the bitmap according to the blockmap) for the new
leaf blocks and replace the zeros with valid block references.
rhbz#902920
---
gfs2/fsck/metawalk.c | 31 ++++++++++++++++++++++++++++++-
gfs2/fsck/metawalk.h | 2 +-
gfs2/fsck/pass1.c | 9 ++-------
gfs2/fsck/pass2.c | 2 +-
4 files changed, 34 insertions(+), 10 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 37b2d4b..78047ec 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -1954,7 +1954,7 @@ int write_new_leaf(struct gfs2_inode *dip, int start_lindex, int num_copies,
* leaf a bit, but it's better than deleting the whole directory,
* which is what used to happen before. */
int repair_leaf(struct gfs2_inode *ip, uint64_t *leaf_no, int lindex,
- int ref_count, const char *msg)
+ int ref_count, const char *msg, int allow_alloc)
{
int new_leaf_blks = 0, error, refs;
uint64_t bn = 0;
@@ -1969,6 +1969,35 @@ int repair_leaf(struct gfs2_inode *ip, uint64_t *leaf_no, int lindex,
log_err( _("Bad leaf left in place.\n"));
goto out;
}
+ if (!allow_alloc) {
+ uint64_t *cpyptr;
+ char *padbuf;
+ int pad_size, i;
+
+ padbuf = malloc(ref_count * sizeof(uint64_t));
+ cpyptr = (uint64_t *)padbuf;
+ for (i = 0; i < ref_count; i++) {
+ *cpyptr = 0;
+ cpyptr++;
+ }
+ pad_size = ref_count * sizeof(uint64_t);
+ log_err(_("Writing zeros to the hash table of directory %lld "
+ "(0x%llx) at index: 0x%x for 0x%x pointers.\n"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ lindex, ref_count);
+ if (ip->i_sbd->gfs1)
+ gfs1_writei(ip, padbuf, lindex * sizeof(uint64_t),
+ pad_size);
+ else
+ gfs2_writei(ip, padbuf, lindex * sizeof(uint64_t),
+ pad_size);
+ free(padbuf);
+ log_err( _("Directory Inode %llu (0x%llx) patched.\n"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr);
+ goto out;
+ }
/* We can only write leafs in quantities that are factors of
two, since leaves are doubled, not added sequentially.
So if we have a hole that's not a factor of 2, we have to
diff --git a/gfs2/fsck/metawalk.h b/gfs2/fsck/metawalk.h
index aacb962..a5a51c2 100644
--- a/gfs2/fsck/metawalk.h
+++ b/gfs2/fsck/metawalk.h
@@ -61,7 +61,7 @@ extern int write_new_leaf(struct gfs2_inode *dip, int start_lindex,
int num_copies, const char *before_or_after,
uint64_t *bn);
extern int repair_leaf(struct gfs2_inode *ip, uint64_t *leaf_no, int lindex,
- int ref_count, const char *msg);
+ int ref_count, const char *msg, int allow_alloc);
#define is_duplicate(dblock) ((dupfind(dblock)) ? 1 : 0)
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index 2355de2..7208335 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -83,13 +83,8 @@ static int pass1_repair_leaf(struct gfs2_inode *ip, uint64_t *leaf_no,
int lindex, int ref_count, const char *msg,
void *private)
{
- struct block_count *bc = (struct block_count *)private;
- int new_leaf_blks;
-
- new_leaf_blks = repair_leaf(ip, leaf_no, lindex, ref_count, msg);
- bc->indir_count += new_leaf_blks;
-
- return new_leaf_blks;
+ repair_leaf(ip, leaf_no, lindex, ref_count, msg, 0);
+ return 0;
}
struct metawalk_fxns pass1_fxns = {
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index 02fa577..4b3a5c0 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -1038,7 +1038,7 @@ static int pass2_repair_leaf(struct gfs2_inode *ip, uint64_t *leaf_no,
int lindex, int ref_count, const char *msg,
void *private)
{
- return repair_leaf(ip, leaf_no, lindex, ref_count, msg);
+ return repair_leaf(ip, leaf_no, lindex, ref_count, msg, 1);
}
/* The purpose of leafck_fxns is to provide a means for function fix_hashtable
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=3cb08a8cf18e5…
Commit: 3cb08a8cf18e513cae007d987edc39fb3b1ef61f
Parent: 47739c96de94d8de07ee1e8d92cf845d083cb422
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Thu Apr 11 13:45:39 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri May 17 15:30:57 2013 -0500
fsck.gfs2: double-check transitions from dinode to data
If a corrupt dinode references a bunch of blocks as data blocks,
and those blocks occur later in the bitmap (as is usually the case)
but they're really dinodes, we have a problem. Before it finds the
corruption, it can change the bitmap markings from 'dinode' to 'data'
blocks. Later, when it determines the dinode is corrupt. It tries
to "undo" all those data blocks, but since pass1 hasn't processed
them yet, it marks them as 'free' in the bitmap, and we've lost the
fact that they're dinodes. The result is that the files/dinodes
being improperly referenced are deleted by mistake.
This patch adds a check for bitmap transitions in pass1 from 'dinode'
to 'data', where the block hasn't been checked yet. We don't care about
transitions from dinode to free because that's a normal delete of a
dinode. We also don't care about transitions between dinode to
metadata, because all those checks validate that the metadata type is
the correct type of metadata, so we know we're making the right
decision. So the only issue are data blocks referencing dinodes.
What this patch does is: when the bitmap is making a transition from
'dinode' to 'data' in pass1, it basically puts up a red flag.
The block is read in and checked to see if it really looks like a
dinode. We have to be careful here, because customer data is allowed
to look like a dinode. If the block really seems to be a dinode, we
DO NOT want to treat it as a data block and assume the duplicate
reference handler in pass1b will handle it, because the dinode's
metadata blocks will not have been checked in pass1.
Instead, we want to flag it as corruption in the referencing file
dinode, not change the bitmap or blockmap, and allow pass1 to treat
it properly as a dinode when it gets there. The corrupt dinode
referencing the dinode as 'data' should be deleted and the work done
thusfar should be backed out by the pass1 'undo' functions.
rhbz#902920
---
gfs2/fsck/metawalk.c | 21 +++++++++++++---
gfs2/fsck/metawalk.h | 14 +++++++----
gfs2/fsck/pass1.c | 65 +++++++++++++++++++++++++++++++++++++++++++++----
gfs2/fsck/pass1b.c | 2 +-
gfs2/fsck/pass2.c | 2 +-
gfs2/fsck/pass3.c | 4 +-
6 files changed, 89 insertions(+), 19 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 15bdf7a..8fc445e 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -25,7 +25,7 @@
is used to set the latter. The two must be kept in sync, otherwise
you'll get bitmap mismatches. This function checks the status of the
bitmap whenever the blockmap changes, and fixes it accordingly. */
-int check_n_fix_bitmap(struct gfs2_sbd *sdp, uint64_t blk,
+int check_n_fix_bitmap(struct gfs2_sbd *sdp, uint64_t blk, int error_on_dinode,
enum gfs2_mark_block new_blockmap_state)
{
int old_bitmap_state, new_bitmap_state;
@@ -47,6 +47,16 @@ int check_n_fix_bitmap(struct gfs2_sbd *sdp, uint64_t blk,
/* gfs1 descriptions: */
{"free", "data", "free meta", "metadata", "reserved"}};
+ if (error_on_dinode && old_bitmap_state == GFS2_BLKST_DINODE &&
+ new_bitmap_state != GFS2_BLKST_FREE) {
+ log_debug(_("Reference as '%s' to block %llu (0x%llx) "
+ "which was marked as dinode. Needs "
+ "further investigation.\n"),
+ allocdesc[sdp->gfs1][new_bitmap_state],
+ (unsigned long long)blk,
+ (unsigned long long)blk);
+ return 1;
+ }
/* Keep these messages as short as possible, or the output
gets to be huge and unmanageable. */
log_err( _("Block %llu (0x%llx) was '%s', should be %s.\n"),
@@ -104,6 +114,7 @@ int check_n_fix_bitmap(struct gfs2_sbd *sdp, uint64_t blk,
*/
int _fsck_blockmap_set(struct gfs2_inode *ip, uint64_t bblock,
const char *btype, enum gfs2_mark_block mark,
+ int error_on_dinode,
const char *caller, int fline)
{
int error;
@@ -162,9 +173,11 @@ int _fsck_blockmap_set(struct gfs2_inode *ip, uint64_t bblock,
/* First, check the rgrp bitmap against what we think it should be.
If that fails, it's an invalid block--part of an rgrp. */
- error = check_n_fix_bitmap(ip->i_sbd, bblock, mark);
+ error = check_n_fix_bitmap(ip->i_sbd, bblock, error_on_dinode, mark);
if (error) {
- log_err( _("This block is not represented in the bitmap.\n"));
+ if (error < 0)
+ log_err( _("This block is not represented in the "
+ "bitmap.\n"));
return error;
}
@@ -515,7 +528,7 @@ int check_leaf(struct gfs2_inode *ip, int lindex, struct metawalk_fxns *pass,
if (pass->check_leaf) {
error = pass->check_leaf(ip, *leaf_no, pass->private);
- if (error) {
+ if (error == -EEXIST) {
log_info(_("Previous reference to leaf %lld (0x%llx) "
"has already checked it; skipping.\n"),
(unsigned long long)*leaf_no,
diff --git a/gfs2/fsck/metawalk.h b/gfs2/fsck/metawalk.h
index 56f57d9..aacb962 100644
--- a/gfs2/fsck/metawalk.h
+++ b/gfs2/fsck/metawalk.h
@@ -45,10 +45,12 @@ extern int delete_eattr_extentry(struct gfs2_inode *ip, uint64_t *ea_data_ptr,
void *private);
extern int _fsck_blockmap_set(struct gfs2_inode *ip, uint64_t bblock,
- const char *btype, enum gfs2_mark_block mark,
- const char *caller, int line);
+ const char *btype, enum gfs2_mark_block mark,
+ int error_on_dinode,
+ const char *caller, int line);
extern int check_n_fix_bitmap(struct gfs2_sbd *sdp, uint64_t blk,
- enum gfs2_mark_block new_blockmap_state);
+ int error_on_dinode,
+ enum gfs2_mark_block new_blockmap_state);
extern void reprocess_inode(struct gfs2_inode *ip, const char *desc);
extern struct duptree *dupfind(uint64_t block);
extern struct gfs2_inode *fsck_system_inode(struct gfs2_sbd *sdp,
@@ -63,8 +65,10 @@ extern int repair_leaf(struct gfs2_inode *ip, uint64_t *leaf_no, int lindex,
#define is_duplicate(dblock) ((dupfind(dblock)) ? 1 : 0)
-#define fsck_blockmap_set(ip, b, bt, m) _fsck_blockmap_set(ip, b, bt, m, \
- __FUNCTION__, __LINE__)
+#define fsck_blockmap_set(ip, b, bt, m) \
+ _fsck_blockmap_set(ip, b, bt, m, 0, __FUNCTION__, __LINE__)
+#define fsck_blkmap_set_noino(ip, b, bt, m) \
+ _fsck_blockmap_set(ip, b, bt, m, 1, __FUNCTION__, __LINE__)
enum meta_check_rc {
meta_error = -1,
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index 90e3829..fbeca0b 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -149,7 +149,7 @@ static int resuscitate_metalist(struct gfs2_inode *ip, uint64_t block,
if (fsck_system_inode(ip->i_sbd, block))
fsck_blockmap_set(ip, block, _("system file"), gfs2_indir_blk);
else
- check_n_fix_bitmap(ip->i_sbd, block, gfs2_indir_blk);
+ check_n_fix_bitmap(ip->i_sbd, block, 0, gfs2_indir_blk);
bc->indir_count++;
return meta_is_good;
}
@@ -203,7 +203,7 @@ static int resuscitate_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
if (fsck_system_inode(sdp, block))
fsck_blockmap_set(ip, block, _("system file"), dinode_type);
else
- check_n_fix_bitmap(sdp, block, dinode_type);
+ check_n_fix_bitmap(sdp, block, 0, dinode_type);
/* Return the number of leaf entries so metawalk doesn't flag this
leaf as having none. */
*count = be16_to_cpu(((struct gfs2_leaf *)bh->b_data)->lf_entries);
@@ -338,6 +338,8 @@ static int undo_reference(struct gfs2_inode *ip, uint64_t block, int meta,
struct block_count *bc = (struct block_count *)private;
struct duptree *dt;
struct inode_with_dups *id;
+ int old_bitmap_state = 0;
+ struct rgrp_tree *rgd;
if (!valid_block(ip->i_sbd, block)) { /* blk outside of FS */
fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
@@ -366,6 +368,12 @@ static int undo_reference(struct gfs2_inode *ip, uint64_t block, int meta,
return 1;
}
}
+ if (!meta) {
+ rgd = gfs2_blk2rgrpd(ip->i_sbd, block);
+ old_bitmap_state = gfs2_get_bitmap(ip->i_sbd, block, rgd);
+ if (old_bitmap_state == GFS2_BLKST_DINODE)
+ return -1;
+ }
fsck_blockmap_set(ip, block,
meta ? _("bad indirect") : _("referenced data"),
gfs2_block_free);
@@ -384,6 +392,51 @@ static int undo_check_data(struct gfs2_inode *ip, uint64_t block,
return undo_reference(ip, block, 0, private);
}
+/* blockmap_set_as_data - set block as 'data' in the blockmap, if not dinode
+ *
+ * This function tries to set a block that's referenced as data as 'data'
+ * in the fsck blockmap. But if that block is marked as 'dinode' in the
+ * rgrp bitmap, it does additional checks to see if it looks like a dinode.
+ * Note that previous checks were done for duplicate references, so this
+ * is checking for dinodes that we haven't processed yet.
+ */
+static int blockmap_set_as_data(struct gfs2_inode *ip, uint64_t block)
+{
+ int error;
+ struct gfs2_buffer_head *bh;
+ struct gfs2_dinode *di;
+
+ error = fsck_blkmap_set_noino(ip, block, _("data"), gfs2_block_used);
+ if (!error)
+ return 0;
+
+ error = 0;
+ /* The bitmap says it's a dinode, but a block reference begs to differ.
+ So which is it? */
+ bh = bread(ip->i_sbd, block);
+ if (gfs2_check_meta(bh, GFS2_METATYPE_DI) != 0)
+ goto out;
+
+ /* The meta header agrees it's a dinode. But it might be data in
+ disguise, so do some extra checks. */
+ di = (struct gfs2_dinode *)bh->b_data;
+ if (be64_to_cpu(di->di_num.no_addr) != block)
+ goto out;
+
+ log_err(_("Inode %lld (0x%llx) has a reference to block %lld (0x%llx) "
+ "as a data block, but it appears to be a dinode we "
+ "haven't checked yet.\n"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)block, (unsigned long long)block);
+ error = -1;
+out:
+ if (!error)
+ fsck_blockmap_set(ip, block, _("data"), gfs2_block_used);
+ brelse(bh);
+ return error;
+}
+
static int check_data(struct gfs2_inode *ip, uint64_t metablock,
uint64_t block, void *private)
{
@@ -468,7 +521,7 @@ static int check_data(struct gfs2_inode *ip, uint64_t metablock,
(unsigned long long)block, (unsigned long long)block);
fsck_blockmap_set(ip, block, _("jdata"), gfs2_jdata);
} else
- fsck_blockmap_set(ip, block, _("data"), gfs2_block_used);
+ return blockmap_set_as_data(ip, block);
return 0;
}
@@ -1195,7 +1248,7 @@ static int check_system_inode(struct gfs2_sbd *sdp,
(unsigned long long)iblock,
(unsigned long long)iblock);
gfs2_blockmap_set(bl, iblock, gfs2_block_free);
- check_n_fix_bitmap(sdp, iblock, gfs2_block_free);
+ check_n_fix_bitmap(sdp, iblock, 0, gfs2_block_free);
inode_put(sysinode);
}
}
@@ -1442,7 +1495,7 @@ int pass1(struct gfs2_sbd *sdp)
}
/* rgrps and bitmaps don't have bits to represent
their blocks, so don't do this:
- check_n_fix_bitmap(sdp, rgd->ri.ri_addr + i,
+ check_n_fix_bitmap(sdp, rgd->ri.ri_addr + i, 0,
gfs2_meta_rgrp);*/
}
@@ -1556,7 +1609,7 @@ int pass1(struct gfs2_sbd *sdp)
"block #%llu (0x%llx)\n"),
(unsigned long long)block,
(unsigned long long)block);
- check_n_fix_bitmap(sdp, block,
+ check_n_fix_bitmap(sdp, block, 0,
gfs2_block_free);
}
} else if (handle_di(sdp, bh) < 0) {
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index bf26c2c..224a5d0 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -499,7 +499,7 @@ static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *dt)
dup_delete(dh.dt);
/* Now fix the block type of the block in question. */
gfs2_blockmap_set(bl, dup_blk, gfs2_block_free);
- check_n_fix_bitmap(sdp, dup_blk, gfs2_block_free);
+ check_n_fix_bitmap(sdp, dup_blk, 0, gfs2_block_free);
}
}
return 0;
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index 99481c9..02fa577 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -1706,7 +1706,7 @@ int pass2(struct gfs2_sbd *sdp)
/* Can't use fsck_blockmap_set here because we don't
have an inode in memory. */
gfs2_blockmap_set(bl, dirblk, gfs2_inode_invalid);
- check_n_fix_bitmap(sdp, dirblk, gfs2_inode_invalid);
+ check_n_fix_bitmap(sdp, dirblk, 0, gfs2_inode_invalid);
}
ip = fsck_load_inode(sdp, dirblk);
if (!ds.dotdir) {
diff --git a/gfs2/fsck/pass3.c b/gfs2/fsck/pass3.c
index f5f38c5..6a6305a 100644
--- a/gfs2/fsck/pass3.c
+++ b/gfs2/fsck/pass3.c
@@ -273,7 +273,7 @@ int pass3(struct gfs2_sbd *sdp)
gfs2_blockmap_set(bl, di->dinode.no_addr,
gfs2_block_free);
check_n_fix_bitmap(sdp, di->dinode.no_addr,
- gfs2_block_free);
+ 0, gfs2_block_free);
break;
} else
log_err( _("Unlinked directory with bad block remains\n"));
@@ -297,7 +297,7 @@ int pass3(struct gfs2_sbd *sdp)
because we don't have ip */
gfs2_blockmap_set(bl, di->dinode.no_addr,
gfs2_block_free);
- check_n_fix_bitmap(sdp, di->dinode.no_addr,
+ check_n_fix_bitmap(sdp, di->dinode.no_addr, 0,
gfs2_block_free);
log_err( _("The block was cleared\n"));
break;
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=73cd9def968ad…
Commit: 73cd9def968ad89bc28e02a8c8f8d630e1114c5b
Parent: ebf7e17895b0ba7b4bf97af9714e52d7ea63efa0
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Wed Apr 3 10:50:24 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri May 17 15:30:23 2013 -0500
fsck.gfs2: major duplicate reference reform
This patch is a large set of changes designed to rework how pass1b
resolves duplicate block references. There are basically two major
changes with this patch:
First, the metawalk functions were trying to attribute too much
information to the return codes of its callback functions: (1) Was
there an error? (2) Was the inode valid? (3) Was a duplicate block
reference encountered? (4) Should we keep going and process more of
its metadata? This often led to bad decisions made by metawalk:
For example, it would stop processing metadata when it should have
continued, thereby forgetting to mark blocks free that were no longer
in use. This patch introduces two new variables to the metatree
functions, *is_valid and *was_duplicate. The first one indicates
whether the dinode was valid or whether there is good cause to
delete it. The second indicates whether a duplicate block reference
was encountered. With this patch, the return code indicates simply
whether metadata processing should be skipped or not, and nothing
more. This is especially useful in pass1. For example, if it
encounters major corruption in a dinode, it doesn't do any good to
mark all its blocks as duplicates and have the undo functions try
to reverse all those decisions.
The second major change with this patch has to do with the
philosophy of how duplicate references are resolved. Before, pass1
would flag the duplicates and pass1b would try to resolve them all,
marking dinodes that should be deleted as "bad", and pass2 would
delete the bad dinodes. This becomes very problematic and messy
in pass1b, especially in cases where you have a number of duplicate
references that are common between multiple dinodes. For example,
suppose files A, B and C share some of the same blocks, but not
others:
A - 0x3000 0x3001 0x1233 0x1234 0x3004
B - 0x4000 0x4001 0x4002 0x1234 0x1235
C - 0x1231 0x1232 0x1233 0x1234 0x1235
The old strategy that got us into trouble was to log the three
duplicate blocks, delete invalid dinodes A and B, but leave the
duplicate reference structure around for 0x1233, 0x1234 and 0x1235
so that C would be left intact with the only references to all five
blocks. But in cleaning up the leftover duplicate structure often
led to bad decisions where C wouldn't have all its blocks marked
as referenced. Often, you would end up with blocks that were marked
as free which were still in use, and blocks that were marked as
in use that should have been freed, and it was all due to the
existence of those duplicate structures that were still on the list
until pass2.
The new strategy is to resolve-as-you-go. In other words, pass1b
considers the three duplicate blocks, but when it decides that
file A should be deleted, it removes all its references from the
list, thereby making the decision between B and C easier: it no
longer has to worry about block 1233, and there's only one thing
to consider about block 0x1234 and 0x1235. When B is deleted, it
removes all its duplicate references, so block 0x1235 is no longer
considered to be in conflict. Once a file is deleted, all its
duplicate reference structures are removed so as not to confuse
other duplicates being resolved. The duplicate handler structure,
struct dup_handler, is revised with every reference that's resolved
so it's not working off a long list of possibles, most of
which were already taken care of by previous actions.
rhbz#902920
---
gfs2/fsck/fsck.h | 2 -
gfs2/fsck/initialize.c | 2 +-
gfs2/fsck/metawalk.c | 217 +++++++++----
gfs2/fsck/metawalk.h | 31 ++-
gfs2/fsck/pass1.c | 101 ++++---
gfs2/fsck/pass1b.c | 808 ++++++++++++++++++++----------------------------
gfs2/fsck/pass2.c | 60 ----
gfs2/fsck/util.c | 37 ++-
gfs2/fsck/util.h | 3 +-
9 files changed, 611 insertions(+), 650 deletions(-)
diff --git a/gfs2/fsck/fsck.h b/gfs2/fsck/fsck.h
index 87d0a04..cc86268 100644
--- a/gfs2/fsck/fsck.h
+++ b/gfs2/fsck/fsck.h
@@ -112,11 +112,9 @@ extern int pass4(struct gfs2_sbd *sdp);
extern int pass5(struct gfs2_sbd *sdp);
extern int rg_repair(struct gfs2_sbd *sdp, int trust_lvl, int *rg_count,
int *sane);
-extern void gfs2_dup_free(void);
extern int fsck_query(const char *format, ...)
__attribute__((format(printf,1,2)));
extern struct dir_info *dirtree_find(uint64_t block);
-extern void dup_listent_delete(struct inode_with_dups *id);
extern void dup_delete(struct duptree *dt);
extern void dirtree_delete(struct dir_info *b);
diff --git a/gfs2/fsck/initialize.c b/gfs2/fsck/initialize.c
index 79e295b..0676426 100644
--- a/gfs2/fsck/initialize.c
+++ b/gfs2/fsck/initialize.c
@@ -64,7 +64,7 @@ static int block_mounters(struct gfs2_sbd *sdp, int block_em)
return 0;
}
-void gfs2_dup_free(void)
+static void gfs2_dup_free(void)
{
struct osi_node *n;
struct duptree *dt;
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 7ce8524..15bdf7a 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -948,7 +948,8 @@ int delete_block(struct gfs2_inode *ip, uint64_t block,
/**
* find_remove_dup - find out if this is a duplicate ref. If so, remove it.
- * Returns: 0 if not a duplicate reference, 1 if it is.
+ *
+ * Returns: 1 if there are any remaining references to this block, else 0.
*/
int find_remove_dup(struct gfs2_inode *ip, uint64_t block, const char *btype)
{
@@ -962,41 +963,18 @@ int find_remove_dup(struct gfs2_inode *ip, uint64_t block, const char *btype)
/* remove the inode reference id structure for this reference. */
id = find_dup_ref_inode(dt, ip);
if (!id)
- return 0;
+ goto more_refs;
- dup_listent_delete(id);
- log_err( _("Removing duplicate status of block %llu (0x%llx) "
- "referenced as %s by dinode %llu (0x%llx)\n"),
- (unsigned long long)block, (unsigned long long)block,
- btype, (unsigned long long)ip->i_di.di_num.no_addr,
- (unsigned long long)ip->i_di.di_num.no_addr);
- dt->refs--; /* one less reference */
- if (dt->refs == 1) {
- log_info( _("This leaves only one reference: it's "
- "no longer a duplicate.\n"));
+ dup_listent_delete(dt, id);
+ if (dt->refs == 0) {
+ log_info( _("This was the last reference: it's no longer a "
+ "duplicate.\n"));
dup_delete(dt); /* not duplicate now */
- } else
- log_info( _("%d block reference(s) remain.\n"),
- dt->refs);
- return 1; /* but the original ref still exists so do not free it. */
-}
-
-/**
- * free_block_if_notdup - free blocks associated with an inode, but if it's a
- * duplicate, just remove that designation instead.
- * Returns: 1 if the block was freed, 0 if a duplicate reference was removed
- * Note: The return code is handled this way because there are places in
- * metawalk.c that assume "1" means "change was made" and "0" means
- * change was not made.
- */
-int free_block_if_notdup(struct gfs2_inode *ip, uint64_t block,
- const char *btype)
-{
- if (!find_remove_dup(ip, block, btype)) { /* not a dup */
- fsck_blockmap_set(ip, block, btype, gfs2_block_free);
- return meta_skip_further;
+ return 0;
}
- return meta_is_good;
+more_refs:
+ log_info( _("%d block reference(s) remain.\n"), dt->refs);
+ return 1; /* references still exist so do not free the block. */
}
/**
@@ -1008,7 +986,8 @@ int free_block_if_notdup(struct gfs2_inode *ip, uint64_t block,
*/
static int delete_block_if_notdup(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head **bh,
- const char *btype, void *private)
+ const char *btype, int *was_duplicate,
+ void *private)
{
uint8_t q;
@@ -1025,7 +1004,19 @@ static int delete_block_if_notdup(struct gfs2_inode *ip, uint64_t block,
(unsigned long long)ip->i_di.di_num.no_addr);
return meta_is_good;
}
- return free_block_if_notdup(ip, block, btype);
+ if (find_remove_dup(ip, block, btype)) { /* a dup */
+ if (was_duplicate)
+ *was_duplicate = 1;
+ log_err( _("Not clearing duplicate reference in inode "
+ "at block #%llu (0x%llx) to block #%llu (0x%llx) "
+ "because it's referenced by another inode.\n"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)block, (unsigned long long)block);
+ } else {
+ fsck_blockmap_set(ip, block, btype, gfs2_block_free);
+ }
+ return meta_is_good;
}
/**
@@ -1195,7 +1186,7 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
osi_list_t *prev_list, *cur_list, *tmp;
int h, head_size, iblk_type;
uint64_t *ptr, block;
- int error = 0, err;
+ int error, was_duplicate, is_valid;
osi_list_add(&metabh->b_altlist, &mlp[0]);
@@ -1209,7 +1200,7 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
/* if (<there are no indirect blocks to check>) */
if (height < 2)
- return 0;
+ return meta_is_good;
for (h = 1; h < height; h++) {
if (h > 1) {
if (is_dir(&ip->i_di, ip->i_sbd->gfs1) &&
@@ -1241,7 +1232,7 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
ptr++) {
if (skip_this_pass || fsck_abort) {
free_metalist(ip, mlp);
- return FSCK_OK;
+ return meta_is_good;
}
nbh = NULL;
@@ -1249,19 +1240,41 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
continue;
block = be64_to_cpu(*ptr);
- err = pass->check_metalist(ip, block, &nbh, h,
- pass->private);
+ was_duplicate = 0;
+ error = pass->check_metalist(ip, block, &nbh,
+ h, &is_valid,
+ &was_duplicate,
+ pass->private);
/* check_metalist should hold any buffers
it gets with "bread". */
- if (err == meta_error) {
+ if (error == meta_error) {
stack;
- error = err;
+ log_info(_("\nSerious metadata "
+ "error on block %llu "
+ "(0x%llx).\n"),
+ (unsigned long long)block,
+ (unsigned long long)block);
return error;
}
- if (err == meta_skip_further) {
- if (!error)
- error = err;
- log_debug( _("Skipping block %llu (0x%llx)\n"),
+ if (error == meta_skip_further) {
+ log_info(_("\nUnrecoverable metadata "
+ "error on block %llu "
+ "(0x%llx). Further metadata"
+ " will be skipped.\n"),
+ (unsigned long long)block,
+ (unsigned long long)block);
+ return error;
+ }
+ if (!is_valid) {
+ log_debug( _("Skipping rejected block "
+ "%llu (0x%llx)\n"),
+ (unsigned long long)block,
+ (unsigned long long)block);
+ continue;
+ }
+ if (was_duplicate) {
+ log_debug( _("Skipping duplicate %llu "
+ "(0x%llx)\n"),
(unsigned long long)block,
(unsigned long long)block);
continue;
@@ -1589,34 +1602,52 @@ int remove_dentry_from_dir(struct gfs2_sbd *sdp, uint64_t dir,
}
int delete_metadata(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, int h, void *private)
+ struct gfs2_buffer_head **bh, int h, int *is_valid,
+ int *was_duplicate, void *private)
{
- return delete_block_if_notdup(ip, block, bh, _("metadata"), private);
+ *is_valid = 1;
+ *was_duplicate = 0;
+ return delete_block_if_notdup(ip, block, bh, _("metadata"),
+ was_duplicate, private);
}
int delete_leaf(struct gfs2_inode *ip, uint64_t block, void *private)
{
- return delete_block_if_notdup(ip, block, NULL, _("leaf"), private);
+ return delete_block_if_notdup(ip, block, NULL, _("leaf"), NULL,
+ private);
}
int delete_data(struct gfs2_inode *ip, uint64_t metablock,
uint64_t block, void *private)
{
- return delete_block_if_notdup(ip, block, NULL, _("data"), private);
+ return delete_block_if_notdup(ip, block, NULL, _("data"), NULL,
+ private);
}
-int delete_eattr_indir(struct gfs2_inode *ip, uint64_t block, uint64_t parent,
- struct gfs2_buffer_head **bh, void *private)
+static int del_eattr_generic(struct gfs2_inode *ip, uint64_t block,
+ uint64_t parent, struct gfs2_buffer_head **bh,
+ void *private, const char *eatype)
{
- int ret;
+ int ret = 0;
+ int was_free = 0;
+ uint8_t q;
- ret = delete_block_if_notdup(ip, block, NULL,
- _("indirect extended attribute"),
- private);
+ if (valid_block(ip->i_sbd, block)) {
+ q = block_type(block);
+ if (q == gfs2_block_free)
+ was_free = 1;
+ ret = delete_block_if_notdup(ip, block, NULL, eatype,
+ NULL, private);
+ if (!ret) {
+ *bh = bread(ip->i_sbd, block);
+ if (!was_free)
+ ip->i_di.di_blocks--;
+ bmodified(ip->i_bh);
+ }
+ }
/* Even if it's a duplicate reference, we want to eliminate the
reference itself, and adjust di_blocks accordingly. */
if (ip->i_di.di_eattr) {
- ip->i_di.di_blocks--;
if (block == ip->i_di.di_eattr)
ip->i_di.di_eattr = 0;
bmodified(ip->i_bh);
@@ -1624,24 +1655,74 @@ int delete_eattr_indir(struct gfs2_inode *ip, uint64_t block, uint64_t parent,
return ret;
}
+int delete_eattr_indir(struct gfs2_inode *ip, uint64_t block, uint64_t parent,
+ struct gfs2_buffer_head **bh, void *private)
+{
+ return del_eattr_generic(ip, block, parent, bh, private,
+ _("extended attribute"));
+}
+
int delete_eattr_leaf(struct gfs2_inode *ip, uint64_t block, uint64_t parent,
struct gfs2_buffer_head **bh, void *private)
{
- int ret;
+ return del_eattr_generic(ip, block, parent, bh, private,
+ _("indirect extended attribute"));
+}
- ret = delete_block_if_notdup(ip, block, NULL, _("extended attribute"),
- private);
- if (ip->i_di.di_eattr) {
- ip->i_di.di_blocks--;
- if (block == ip->i_di.di_eattr)
- ip->i_di.di_eattr = 0;
- bmodified(ip->i_bh);
+int delete_eattr_entry(struct gfs2_inode *ip, struct gfs2_buffer_head *leaf_bh,
+ struct gfs2_ea_header *ea_hdr,
+ struct gfs2_ea_header *ea_hdr_prev, void *private)
+{
+ struct gfs2_sbd *sdp = ip->i_sbd;
+ char ea_name[256];
+ uint32_t avail_size;
+ int max_ptrs;
+
+ if (!ea_hdr->ea_name_len){
+ /* Skip this entry for now */
+ return 1;
}
- return ret;
+
+ memset(ea_name, 0, sizeof(ea_name));
+ strncpy(ea_name, (char *)ea_hdr + sizeof(struct gfs2_ea_header),
+ ea_hdr->ea_name_len);
+
+ if (!GFS2_EATYPE_VALID(ea_hdr->ea_type) &&
+ ((ea_hdr_prev) || (!ea_hdr_prev && ea_hdr->ea_type))){
+ /* Skip invalid entry */
+ return 1;
+ }
+
+ if (!ea_hdr->ea_num_ptrs)
+ return 0;
+
+ avail_size = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_meta_header);
+ max_ptrs = (be32_to_cpu(ea_hdr->ea_data_len) + avail_size - 1) /
+ avail_size;
+
+ if (max_ptrs > ea_hdr->ea_num_ptrs)
+ return 1;
+
+ log_debug( _(" Pointers Required: %d\n Pointers Reported: %d\n"),
+ max_ptrs, ea_hdr->ea_num_ptrs);
+
+ return 0;
+}
+
+int delete_eattr_extentry(struct gfs2_inode *ip, uint64_t *ea_data_ptr,
+ struct gfs2_buffer_head *leaf_bh,
+ struct gfs2_ea_header *ea_hdr,
+ struct gfs2_ea_header *ea_hdr_prev, void *private)
+{
+ uint64_t block = be64_to_cpu(*ea_data_ptr);
+
+ return delete_block_if_notdup(ip, block, NULL, _("extended attribute"),
+ NULL, private);
}
static int alloc_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, int h, void *private)
+ struct gfs2_buffer_head **bh, int h, int *is_valid,
+ int *was_duplicate, void *private)
{
uint8_t q;
const char *desc = (const char *)private;
@@ -1649,6 +1730,8 @@ static int alloc_metalist(struct gfs2_inode *ip, uint64_t block,
/* No need to range_check here--if it was added, it's in range. */
/* We can't check the bitmap here because this function is called
after the bitmap has been set but before the blockmap has. */
+ *is_valid = 1;
+ *was_duplicate = 0;
*bh = bread(ip->i_sbd, block);
q = block_type(block);
if (blockmap_to_bitmap(q, ip->i_sbd->gfs1) == GFS2_BLKST_FREE) {
diff --git a/gfs2/fsck/metawalk.h b/gfs2/fsck/metawalk.h
index 49217cc..56f57d9 100644
--- a/gfs2/fsck/metawalk.h
+++ b/gfs2/fsck/metawalk.h
@@ -24,7 +24,8 @@ extern int delete_block(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head **bh, const char *btype,
void *private);
extern int delete_metadata(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, int h, void *private);
+ struct gfs2_buffer_head **bh, int h, int *is_valid,
+ int *was_duplicate, void *private);
extern int delete_leaf(struct gfs2_inode *ip, uint64_t block, void *private);
extern int delete_data(struct gfs2_inode *ip, uint64_t metablock,
uint64_t block, void *private);
@@ -32,6 +33,17 @@ extern int delete_eattr_indir(struct gfs2_inode *ip, uint64_t block, uint64_t pa
struct gfs2_buffer_head **bh, void *private);
extern int delete_eattr_leaf(struct gfs2_inode *ip, uint64_t block, uint64_t parent,
struct gfs2_buffer_head **bh, void *private);
+extern int delete_eattr_entry(struct gfs2_inode *ip,
+ struct gfs2_buffer_head *leaf_bh,
+ struct gfs2_ea_header *ea_hdr,
+ struct gfs2_ea_header *ea_hdr_prev,
+ void *private);
+extern int delete_eattr_extentry(struct gfs2_inode *ip, uint64_t *ea_data_ptr,
+ struct gfs2_buffer_head *leaf_bh,
+ struct gfs2_ea_header *ea_hdr,
+ struct gfs2_ea_header *ea_hdr_prev,
+ void *private);
+
extern int _fsck_blockmap_set(struct gfs2_inode *ip, uint64_t bblock,
const char *btype, enum gfs2_mark_block mark,
const char *caller, int line);
@@ -48,8 +60,6 @@ extern int write_new_leaf(struct gfs2_inode *dip, int start_lindex,
uint64_t *bn);
extern int repair_leaf(struct gfs2_inode *ip, uint64_t *leaf_no, int lindex,
int ref_count, const char *msg);
-extern int free_block_if_notdup(struct gfs2_inode *ip, uint64_t block,
- const char *btype);
#define is_duplicate(dblock) ((dupfind(dblock)) ? 1 : 0)
@@ -83,8 +93,23 @@ struct metawalk_fxns {
int ref_count, struct gfs2_buffer_head *lbh);
int (*check_leaf) (struct gfs2_inode *ip, uint64_t block,
void *private);
+ /* parameters to the check_metalist sub-functions:
+ ip: incore inode pointer
+ block: block number of the metadata block to be checked
+ bh: buffer_head to be returned
+ h: height
+ is_valid: returned as 1 if the metadata block is valid and should
+ be added to the metadata list for further processing.
+ was_duplicate: returns as 1 if the metadata block was determined
+ to be a duplicate reference, in which case we want to
+ skip adding it to the metadata list.
+ private: Pointer to pass-specific data
+ returns: 0 - everything is good, but there may be duplicates
+ 1 - skip further processing
+ */
int (*check_metalist) (struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head **bh, int h,
+ int *is_valid, int *was_duplicate,
void *private);
int (*check_data) (struct gfs2_inode *ip, uint64_t metablock,
uint64_t block, void *private);
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index 564f75d..85ad49a 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -36,7 +36,8 @@ struct block_count {
static int p1check_leaf(struct gfs2_inode *ip, uint64_t block, void *private);
static int check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, int h, void *private);
+ struct gfs2_buffer_head **bh, int h, int *is_valid,
+ int *was_duplicate, void *private);
static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
int h, void *private);
static int check_data(struct gfs2_inode *ip, uint64_t metablock,
@@ -63,6 +64,7 @@ static int finish_eattr_indir(struct gfs2_inode *ip, int leaf_pointers,
int leaf_pointer_errors, void *private);
static int invalidate_metadata(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head **bh, int h,
+ int *is_valid, int *was_duplicate,
void *private);
static int invalidate_leaf(struct gfs2_inode *ip, uint64_t block,
void *private);
@@ -126,10 +128,13 @@ struct metawalk_fxns invalidate_fxns = {
*/
static int resuscitate_metalist(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head **bh, int h,
+ int *is_valid, int *was_duplicate,
void *private)
{
struct block_count *bc = (struct block_count *)private;
+ *is_valid = 1;
+ *was_duplicate = 0;
*bh = NULL;
if (!valid_block(ip->i_sbd, block)){ /* blk outside of FS */
fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
@@ -138,7 +143,8 @@ static int resuscitate_metalist(struct gfs2_inode *ip, uint64_t block,
"range) found in system inode %lld (0x%llx).\n"),
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
- return meta_skip_further;
+ *is_valid = 0;
+ return meta_is_good;
}
if (fsck_system_inode(ip->i_sbd, block))
fsck_blockmap_set(ip, block, _("system file"), gfs2_indir_blk);
@@ -240,16 +246,19 @@ static int p1check_leaf(struct gfs2_inode *ip, uint64_t block, void *private)
}
static int check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, int h, void *private)
+ struct gfs2_buffer_head **bh, int h, int *is_valid,
+ int *was_duplicate, void *private)
{
uint8_t q;
- int found_dup = 0, iblk_type;
+ int iblk_type;
struct gfs2_buffer_head *nbh;
struct block_count *bc = (struct block_count *)private;
const char *blktypedesc;
*bh = NULL;
+ *was_duplicate = 0;
+ *is_valid = 0;
if (!valid_block(ip->i_sbd, block)) { /* blk outside of FS */
/* The bad dinode should be invalidated later due to
"unrecoverable" errors. The inode itself should be
@@ -281,12 +290,13 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr, q,
block_type_string(q));
- add_duplicate_ref(ip, block, ref_as_meta, 0, INODE_VALID);
- found_dup = 1;
+ *was_duplicate = 1;
}
nbh = bread(ip->i_sbd, block);
- if (gfs2_check_meta(nbh, iblk_type)){
+ *is_valid = (gfs2_check_meta(nbh, iblk_type) == 0);
+
+ if (!(*is_valid)) {
log_err( _("Inode %lld (0x%llx) has a bad indirect block "
"pointer %lld (0x%llx) (points to something "
"that is not %s).\n"),
@@ -294,31 +304,23 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)block,
(unsigned long long)block, blktypedesc);
- if (!found_dup) {
- fsck_blockmap_set(ip, block, _("bad indirect"),
- gfs2_meta_inval);
- brelse(nbh);
- nbh = NULL;
- return meta_skip_further;
- }
brelse(nbh);
- nbh = NULL;
- } else /* blk check ok */
- *bh = nbh;
+ return meta_skip_further;
+ }
bc->indir_count++;
- if (found_dup) {
- if (nbh) {
- brelse(nbh);
- nbh = NULL;
- *bh = NULL;
- }
- return meta_skip_further; /* don't process the metadata again */
- } else
- fsck_blockmap_set(ip, block, _("indirect"),
- gfs2_indir_blk);
+ if (*was_duplicate) {
+ add_duplicate_ref(ip, block, ref_as_meta, 0,
+ *is_valid ? INODE_VALID : INODE_INVALID);
+ brelse(nbh);
+ } else {
+ *bh = nbh;
+ fsck_blockmap_set(ip, block, _("indirect"), gfs2_indir_blk);
+ }
- return meta_is_good;
+ if (*is_valid)
+ return meta_is_good;
+ return meta_skip_further;
}
/* undo_reference - undo previously processed data or metadata
@@ -353,7 +355,7 @@ static int undo_reference(struct gfs2_inode *ip, uint64_t block, int meta,
if (!id)
break;
- dup_listent_delete(id);
+ dup_listent_delete(dt, id);
} while (id);
if (dt->refs) {
@@ -826,7 +828,8 @@ static int check_eattr_entries(struct gfs2_inode *ip,
* delete_block_if_notdup.
*/
static int mark_block_invalid(struct gfs2_inode *ip, uint64_t block,
- enum dup_ref_type reftype, const char *btype)
+ enum dup_ref_type reftype, const char *btype,
+ int *is_valid, int *was_duplicate)
{
uint8_t q;
@@ -837,11 +840,20 @@ static int mark_block_invalid(struct gfs2_inode *ip, uint64_t block,
* referenced elsewhere (duplicates) won't be flagged as such,
* and as a result, they'll be freed when this dinode is deleted,
* despite being used by another dinode as a valid block. */
- if (!valid_block(ip->i_sbd, block))
+ if (is_valid)
+ *is_valid = 1;
+ if (was_duplicate)
+ *was_duplicate = 0;
+ if (!valid_block(ip->i_sbd, block)) {
+ if (is_valid)
+ *is_valid = 0;
return meta_is_good;
+ }
q = block_type(block);
if (q != gfs2_block_free) {
+ if (was_duplicate)
+ *was_duplicate = 1;
add_duplicate_ref(ip, block, reftype, 0, INODE_INVALID);
log_info( _("%s block %lld (0x%llx), part of inode "
"%lld (0x%llx), was previously referenced so "
@@ -858,21 +870,27 @@ static int mark_block_invalid(struct gfs2_inode *ip, uint64_t block,
static int invalidate_metadata(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head **bh, int h,
+ int *is_valid, int *was_duplicate,
void *private)
{
- return mark_block_invalid(ip, block, ref_as_meta, _("metadata"));
+ *is_valid = 1;
+ *was_duplicate = 0;
+ return mark_block_invalid(ip, block, ref_as_meta, _("metadata"),
+ is_valid, was_duplicate);
}
static int invalidate_leaf(struct gfs2_inode *ip, uint64_t block,
void *private)
{
- return mark_block_invalid(ip, block, ref_as_meta, _("leaf"));
+ return mark_block_invalid(ip, block, ref_as_meta, _("leaf"),
+ NULL, NULL);
}
static int invalidate_data(struct gfs2_inode *ip, uint64_t metablock,
uint64_t block, void *private)
{
- return mark_block_invalid(ip, block, ref_as_data, _("data"));
+ return mark_block_invalid(ip, block, ref_as_data, _("data"),
+ NULL, NULL);
}
static int invalidate_eattr_indir(struct gfs2_inode *ip, uint64_t block,
@@ -880,7 +898,8 @@ static int invalidate_eattr_indir(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head **bh, void *private)
{
return mark_block_invalid(ip, block, ref_as_ea,
- _("indirect extended attribute"));
+ _("indirect extended attribute"),
+ NULL, NULL);
}
static int invalidate_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
@@ -888,7 +907,8 @@ static int invalidate_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
void *private)
{
return mark_block_invalid(ip, block, ref_as_ea,
- _("extended attribute"));
+ _("extended attribute"),
+ NULL, NULL);
}
/**
@@ -923,7 +943,7 @@ static int rangecheck_block(struct gfs2_inode *ip, uint64_t block,
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
if ((*bad_pointers) <= BAD_POINTER_TOLERANCE)
- return meta_skip_further;
+ return meta_is_good;
else
return meta_error; /* Exits check_metatree quicker */
}
@@ -938,7 +958,7 @@ static int rangecheck_block(struct gfs2_inode *ip, uint64_t block,
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
if ((*bad_pointers) <= BAD_POINTER_TOLERANCE)
- return meta_skip_further;
+ return meta_is_good;
else
return meta_error; /* Exits check_metatree quicker */
}
@@ -947,8 +967,11 @@ static int rangecheck_block(struct gfs2_inode *ip, uint64_t block,
static int rangecheck_metadata(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head **bh, int h,
+ int *is_valid, int *was_duplicate,
void *private)
{
+ *is_valid = 1;
+ *was_duplicate = 0;
return rangecheck_block(ip, block, bh, btype_meta, private);
}
@@ -1047,7 +1070,7 @@ static int handle_ip(struct gfs2_sbd *sdp, struct gfs2_inode *ip)
/* We there was an error, we return 0 because we want fsck to continue
and analyze the other dinodes as well. */
- if (fsck_abort || error != 0)
+ if (fsck_abort)
return 0;
error = check_inode_eattr(ip, &pass1_fxns);
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index 03e47ec..c7889f6 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -21,384 +21,10 @@ struct fxn_info {
struct dup_handler {
struct duptree *dt;
- struct inode_with_dups *id;
int ref_inode_count;
int ref_count;
};
-static int check_leaf_refs(struct gfs2_inode *ip, uint64_t block, void *private);
-static int check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, int h, void *private);
-static int check_data(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private);
-static int check_eattr_indir(struct gfs2_inode *ip, uint64_t block,
- uint64_t parent, struct gfs2_buffer_head **bh,
- void *private);
-static int check_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
- uint64_t parent, struct gfs2_buffer_head **bh,
- void *private);
-static int check_eattr_entry(struct gfs2_inode *ip,
- struct gfs2_buffer_head *leaf_bh,
- struct gfs2_ea_header *ea_hdr,
- struct gfs2_ea_header *ea_hdr_prev,
- void *private);
-static int check_eattr_extentry(struct gfs2_inode *ip, uint64_t *ea_data_ptr,
- struct gfs2_buffer_head *leaf_bh,
- struct gfs2_ea_header *ea_hdr,
- struct gfs2_ea_header *ea_hdr_prev,
- void *private);
-static int find_dentry(struct gfs2_inode *ip, struct gfs2_dirent *de,
- struct gfs2_dirent *prev, struct gfs2_buffer_head *bh,
- char *filename, uint32_t *count, int lindex,
- void *priv);
-
-struct metawalk_fxns find_refs = {
- .private = NULL,
- .check_leaf = check_leaf_refs,
- .check_metalist = check_metalist,
- .check_data = check_data,
- .check_eattr_indir = check_eattr_indir,
- .check_eattr_leaf = check_eattr_leaf,
- .check_dentry = NULL,
- .check_eattr_entry = check_eattr_entry,
- .check_eattr_extentry = check_eattr_extentry,
-};
-
-struct metawalk_fxns find_dirents = {
- .private = NULL,
- .check_leaf = NULL,
- .check_metalist = NULL,
- .check_data = NULL,
- .check_eattr_indir = NULL,
- .check_eattr_leaf = NULL,
- .check_dentry = find_dentry,
- .check_eattr_entry = NULL,
- .check_eattr_extentry = NULL,
-};
-
-static int check_leaf_refs(struct gfs2_inode *ip, uint64_t block, void *private)
-{
- return add_duplicate_ref(ip, block, ref_as_meta, 1, INODE_VALID);
-}
-
-static int check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, int h, void *private)
-{
- return add_duplicate_ref(ip, block, ref_as_meta, 1, INODE_VALID);
-}
-
-static int check_data(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private)
-{
- return add_duplicate_ref(ip, block, ref_as_data, 1, INODE_VALID);
-}
-
-static int check_eattr_indir(struct gfs2_inode *ip, uint64_t block,
- uint64_t parent, struct gfs2_buffer_head **bh,
- void *private)
-{
- struct gfs2_sbd *sdp = ip->i_sbd;
- int error;
-
- error = add_duplicate_ref(ip, block, ref_as_ea, 1, INODE_VALID);
- if (!error)
- *bh = bread(sdp, block);
-
- return error;
-}
-
-static int check_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
- uint64_t parent, struct gfs2_buffer_head **bh,
- void *private)
-{
- struct gfs2_sbd *sdp = ip->i_sbd;
- int error;
-
- error = add_duplicate_ref(ip, block, ref_as_ea, 1, INODE_VALID);
- if (!error)
- *bh = bread(sdp, block);
- return error;
-}
-
-static int check_eattr_entry(struct gfs2_inode *ip,
- struct gfs2_buffer_head *leaf_bh,
- struct gfs2_ea_header *ea_hdr,
- struct gfs2_ea_header *ea_hdr_prev, void *private)
-{
- return 0;
-}
-
-static int check_eattr_extentry(struct gfs2_inode *ip, uint64_t *ea_data_ptr,
- struct gfs2_buffer_head *leaf_bh,
- struct gfs2_ea_header *ea_hdr,
- struct gfs2_ea_header *ea_hdr_prev,
- void *private)
-{
- uint64_t block = be64_to_cpu(*ea_data_ptr);
-
- return add_duplicate_ref(ip, block, ref_as_ea, 1, INODE_VALID);
-}
-
-/*
- * check_dir_dup_ref - check for a directory entry duplicate reference
- * and if found, set the name into the id.
- * Returns: 1 if filename was found, otherwise 0
- */
-static int check_dir_dup_ref(struct gfs2_inode *ip, struct gfs2_dirent *de,
- osi_list_t *tmp2, char *filename)
-{
- struct inode_with_dups *id;
-
- id = osi_list_entry(tmp2, struct inode_with_dups, list);
- if (id->name)
- /* We can only have one parent of inodes that contain duplicate
- * blocks...no need to keep looking for this one. */
- return 1;
- if (id->block_no == de->de_inum.no_addr) {
- id->name = strdup(filename);
- id->parent = ip->i_di.di_num.no_addr;
- log_debug( _("Duplicate block %llu (0x%llx"
- ") is in file or directory %llu"
- " (0x%llx) named %s\n"),
- (unsigned long long)id->block_no,
- (unsigned long long)id->block_no,
- (unsigned long long)ip->i_di.di_num.no_addr,
- (unsigned long long)ip->i_di.di_num.no_addr,
- filename);
- /* If there are duplicates of duplicates, I guess we'll miss
- them here. */
- return 1;
- }
- return 0;
-}
-
-static int find_dentry(struct gfs2_inode *ip, struct gfs2_dirent *de,
- struct gfs2_dirent *prev,
- struct gfs2_buffer_head *bh, char *filename,
- uint32_t *count, int lindex, void *priv)
-{
- struct osi_node *n, *next = NULL;
- osi_list_t *tmp2;
- struct duptree *dt;
- int found;
-
- for (n = osi_first(&dup_blocks); n; n = next) {
- next = osi_next(n);
- dt = (struct duptree *)n;
- found = 0;
- osi_list_foreach(tmp2, &dt->ref_invinode_list) {
- if (check_dir_dup_ref(ip, de, tmp2, filename)) {
- found = 1;
- break;
- }
- }
- if (!found) {
- osi_list_foreach(tmp2, &dt->ref_inode_list) {
- if (check_dir_dup_ref(ip, de, tmp2, filename))
- break;
- }
- }
- }
- /* Return the number of leaf entries so metawalk doesn't flag this
- leaf as having none. */
- *count = be16_to_cpu(((struct gfs2_leaf *)bh->b_data)->lf_entries);
- return 0;
-}
-
-static int clear_dup_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, int h,
- void *private)
-{
- struct dup_handler *dh = (struct dup_handler *) private;
- struct duptree *dt;
-
- if (!valid_block(ip->i_sbd, block))
- return meta_is_good;
-
- /* This gets tricky. We're traversing a metadata tree trying to
- delete an inode based on it having a duplicate block reference
- somewhere in its metadata. We know this block is listed as data
- or metadata for this inode, but it may or may not be one of the
- actual duplicate references that caused the problem. If it's not
- a duplicate, it's normal metadata that isn't referenced anywhere
- else, but we're deleting the inode out from under it, so we need
- to delete it altogether. If the block is a duplicate referenced
- block, we need to keep its type intact and let the caller sort
- it out once we're down to a single reference. */
- dt = dupfind(block);
- if (!dt) {
- fsck_blockmap_set(ip, block, _("no longer valid"),
- gfs2_block_free);
- return meta_is_good;
- }
- /* This block, having failed the above test, is duplicated somewhere */
- if (block == dh->dt->block) {
- log_err( _("Not clearing duplicate reference in inode \"%s\" "
- "at block #%llu (0x%llx) to block #%llu (0x%llx) "
- "because it's valid for another inode.\n"),
- dh->id->name ? dh->id->name : _("unknown name"),
- (unsigned long long)ip->i_di.di_num.no_addr,
- (unsigned long long)ip->i_di.di_num.no_addr,
- (unsigned long long)block, (unsigned long long)block);
- log_err( _("Inode %s is in directory %"PRIu64" (0x%" PRIx64 ")\n"),
- dh->id->name ? dh->id->name : "", dh->id->parent,
- dh->id->parent);
- }
- /* We return 1 not 0 because we need build_and_check_metalist to
- bypass adding the metadata below it to the metalist. If that
- were to happen, all the indirect blocks pointed to by the
- duplicate block would be processed twice, which means it might
- be mistakenly freed as "no longer valid" (in this function above)
- even though it's valid metadata for a different inode. Returning
- 1 ensures that the metadata isn't processed again. */
- return meta_skip_further;
-}
-
-static int clear_dup_data(struct gfs2_inode *ip, uint64_t metablock,
- uint64_t block, void *private)
-{
- return clear_dup_metalist(ip, block, NULL, 0, private);
-}
-
-static int clear_leaf(struct gfs2_inode *ip, uint64_t block, void *private)
-{
- return clear_dup_metalist(ip, block, NULL, 0, private);
-}
-
-static int clear_dup_eattr_indir(struct gfs2_inode *ip, uint64_t block,
- uint64_t parent, struct gfs2_buffer_head **bh,
- void *private)
-{
- return clear_dup_metalist(ip, block, NULL, 0, private);
-}
-
-static int clear_dup_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
- uint64_t parent, struct gfs2_buffer_head **bh,
- void *private)
-{
- return clear_dup_metalist(ip, block, NULL, 0, private);
-}
-
-static int clear_eattr_entry (struct gfs2_inode *ip,
- struct gfs2_buffer_head *leaf_bh,
- struct gfs2_ea_header *ea_hdr,
- struct gfs2_ea_header *ea_hdr_prev,
- void *private)
-{
- struct gfs2_sbd *sdp = ip->i_sbd;
- char ea_name[256];
-
- if (!ea_hdr->ea_name_len){
- /* Skip this entry for now */
- return 1;
- }
-
- memset(ea_name, 0, sizeof(ea_name));
- strncpy(ea_name, (char *)ea_hdr + sizeof(struct gfs2_ea_header),
- ea_hdr->ea_name_len);
-
- if (!GFS2_EATYPE_VALID(ea_hdr->ea_type) &&
- ((ea_hdr_prev) || (!ea_hdr_prev && ea_hdr->ea_type))){
- /* Skip invalid entry */
- return 1;
- }
-
- if (ea_hdr->ea_num_ptrs){
- uint32_t avail_size;
- int max_ptrs;
-
- avail_size = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_meta_header);
- max_ptrs = (be32_to_cpu(ea_hdr->ea_data_len) + avail_size - 1) /
- avail_size;
-
- if (max_ptrs > ea_hdr->ea_num_ptrs)
- return 1;
- else {
- log_debug( _(" Pointers Required: %d\n Pointers Reported: %d\n"),
- max_ptrs, ea_hdr->ea_num_ptrs);
- }
- }
- return 0;
-}
-
-static int clear_eattr_extentry(struct gfs2_inode *ip, uint64_t *ea_data_ptr,
- struct gfs2_buffer_head *leaf_bh,
- struct gfs2_ea_header *ea_hdr,
- struct gfs2_ea_header *ea_hdr_prev,
- void *private)
-{
- uint64_t block = be64_to_cpu(*ea_data_ptr);
-
- return clear_dup_metalist(ip, block, NULL, 0, private);
-}
-
-/* Finds all references to duplicate blocks in the metadata */
-static int find_block_ref(struct gfs2_sbd *sdp, uint64_t inode)
-{
- struct gfs2_inode *ip;
- int error = 0;
-
- ip = fsck_load_inode(sdp, inode); /* bread, inode_get */
- /* double-check the meta header just to be sure it's metadata */
- if (ip->i_di.di_header.mh_magic != GFS2_MAGIC ||
- ip->i_di.di_header.mh_type != GFS2_METATYPE_DI) {
- log_debug( _("Block %lld (0x%llx) is not gfs2 metadata.\n"),
- (unsigned long long)inode,
- (unsigned long long)inode);
- return 1;
- }
- /* Check to see if this inode was referenced by another by mistake */
- add_duplicate_ref(ip, inode, ref_is_inode, 1, INODE_VALID);
-
- /* Check this dinode's metadata for references to known duplicates */
- error = check_metatree(ip, &find_refs);
- if (error < 0) {
- stack;
- fsck_inode_put(&ip); /* out, brelse, free */
- return error;
- }
-
- /* Exhash dir leafs will be checked by check_metatree (right after
- the "end:" label.) But if this is a linear directory we need to
- check the dir with check_linear_dir. */
- if (is_dir(&ip->i_di, sdp->gfs1) &&
- !(ip->i_di.di_flags & GFS2_DIF_EXHASH))
- error = check_linear_dir(ip, ip->i_bh, &find_dirents);
-
- /* Check for ea references in the inode */
- if (!error)
- error = check_inode_eattr(ip, &find_refs);
-
- fsck_inode_put(&ip); /* out, brelse, free */
-
- return error;
-}
-
-/* get_ref_type - figure out if all duplicate references from this inode
- are the same type, and if so, return the type. */
-static enum dup_ref_type get_ref_type(struct inode_with_dups *id)
-{
- enum dup_ref_type t, i;
- int found_type_with_ref;
- int found_other_types;
-
- for (t = ref_as_data; t < ref_types; t++) {
- found_type_with_ref = 0;
- found_other_types = 0;
- for (i = ref_as_data; i < ref_types; i++) {
- if (id->reftypecount[i]) {
- if (t == i)
- found_type_with_ref = 1;
- else
- found_other_types = 1;
- }
- }
- if (found_type_with_ref)
- return found_other_types ? ref_types : t;
- }
- return ref_types;
-}
-
static void log_inode_reference(struct duptree *dt, osi_list_t *tmp, int inval)
{
char reftypestring[32];
@@ -422,12 +48,74 @@ static void log_inode_reference(struct duptree *dt, osi_list_t *tmp, int inval)
(unsigned long long)dt->block,
(unsigned long long)dt->block, reftypestring);
}
+
+/* delete_all_dups - delete all duplicate records for a given inode */
+static void delete_all_dups(struct gfs2_inode *ip)
+{
+ struct osi_node *n, *next;
+ struct duptree *dt;
+ osi_list_t *tmp, *x;
+ struct inode_with_dups *id;
+ int found;
+
+ for (n = osi_first(&dup_blocks); n; n = next) {
+ next = osi_next(n);
+ dt = (struct duptree *)n;
+
+ found = 0;
+ id = NULL;
+
+ osi_list_foreach_safe(tmp, &dt->ref_invinode_list, x) {
+ id = osi_list_entry(tmp, struct inode_with_dups, list);
+ if (id->block_no == ip->i_di.di_num.no_addr) {
+ dup_listent_delete(dt, id);
+ found = 1;
+ }
+ }
+ osi_list_foreach_safe(tmp, &dt->ref_inode_list, x) {
+ id = osi_list_entry(tmp, struct inode_with_dups, list);
+ if (id->block_no == ip->i_di.di_num.no_addr) {
+ dup_listent_delete(dt, id);
+ found = 1;
+ }
+ }
+ if (!found)
+ continue;
+
+ if (dt->refs == 0) {
+ log_debug(_("This was the last reference: 0x%llx is "
+ "no longer a duplicate.\n"),
+ (unsigned long long)dt->block);
+ dup_delete(dt); /* not duplicate now */
+ } else {
+ log_debug(_("%d references remain to 0x%llx\n"),
+ dt->refs, (unsigned long long)dt->block);
+ if (dt->refs > 1)
+ continue;
+
+ id = NULL;
+ osi_list_foreach(tmp, &dt->ref_invinode_list)
+ id = osi_list_entry(tmp,
+ struct inode_with_dups,
+ list);
+ osi_list_foreach(tmp, &dt->ref_inode_list)
+ id = osi_list_entry(tmp,
+ struct inode_with_dups,
+ list);
+ if (id)
+ log_debug("Last reference is from inode "
+ "0x%llx\n",
+ (unsigned long long)id->block_no);
+ }
+ }
+}
+
/*
* resolve_dup_references - resolve all but the last dinode that has a
* duplicate reference to a given block.
*
* @sdp - pointer to the superblock structure
- * @b - pointer to the duplicate reference rbtree to use
+ * @dt - pointer to the duplicate reference rbtree to use
* @ref_list - list of duplicate references to be resolved (invalid or valid)
* @dh - duplicate handler
* inval - The references on this ref_list are invalid. We prefer to delete
@@ -435,40 +123,42 @@ static void log_inode_reference(struct duptree *dt, osi_list_t *tmp, int inval)
* acceptable_ref - Delete dinodes that reference the given block as anything
* _but_ this type. Try to save references as this type.
*/
-static int resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *dt,
- osi_list_t *ref_list, struct dup_handler *dh,
- int inval, int acceptable_ref)
+static void resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *dt,
+ osi_list_t *ref_list,
+ struct dup_handler *dh,
+ int inval, int acceptable_ref)
{
struct gfs2_inode *ip;
struct inode_with_dups *id;
osi_list_t *tmp, *x;
- struct metawalk_fxns clear_dup_fxns = {
+ struct metawalk_fxns pass1b_fxns_delete = {
.private = NULL,
- .check_leaf = clear_leaf,
- .check_metalist = clear_dup_metalist,
- .check_data = clear_dup_data,
- .check_eattr_indir = clear_dup_eattr_indir,
- .check_eattr_leaf = clear_dup_eattr_leaf,
- .check_dentry = NULL,
- .check_eattr_entry = clear_eattr_entry,
- .check_eattr_extentry = clear_eattr_extentry,
+ .check_metalist = delete_metadata,
+ .check_data = delete_data,
+ .check_leaf = delete_leaf,
+ .check_eattr_indir = delete_eattr_indir,
+ .check_eattr_leaf = delete_eattr_leaf,
+ .check_eattr_entry = delete_eattr_entry,
+ .check_eattr_extentry = delete_eattr_extentry,
};
enum dup_ref_type this_ref;
struct inode_info *ii;
int found_good_ref = 0;
+ uint64_t dup_block;
+ uint8_t q;
osi_list_foreach_safe(tmp, ref_list, x) {
if (skip_this_pass || fsck_abort)
- return FSCK_OK;
+ return;
id = osi_list_entry(tmp, struct inode_with_dups, list);
dh->dt = dt;
- dh->id = id;
if (dh->ref_inode_count == 1) /* down to the last reference */
- return 1;
+ return;
this_ref = get_ref_type(id);
+ q = block_type(id->block_no);
if (inval)
log_warn( _("Invalid "));
/* FIXME: If we already found an acceptable reference to this
@@ -480,11 +170,8 @@ static int resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *dt,
type and */
this_ref == acceptable_ref && /* this ref is acceptable */
!found_good_ref) { /* We haven't found a good reference */
- uint8_t q;
-
/* If this is an invalid inode, but not on the invalid
list, it's better to delete it. */
- q = block_type(id->block_no);
if (q != gfs2_inode_invalid) {
found_good_ref = 1;
log_warn( _("Inode %s (%lld/0x%llx)'s "
@@ -522,69 +209,124 @@ static int resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *dt,
(unsigned long long)id->block_no))) {
log_warn( _("The bad inode was not cleared."));
/* delete the list entry so we don't leak memory but
- leave the reference count. If the decrement the
+ leave the reference count. If we decrement the
ref count, we could get down to 1 and the dinode
would be changed without a 'Yes' answer. */
/* (dh->ref_inode_count)--;*/
- dup_listent_delete(id);
+ dup_listent_delete(dt, id);
continue;
}
- log_warn( _("Clearing inode %lld (0x%llx)...\n"),
- (unsigned long long)id->block_no,
- (unsigned long long)id->block_no);
-
+ if (q == gfs2_block_free)
+ log_warn( _("Inode %lld (0x%llx) was previously "
+ "deleted.\n"),
+ (unsigned long long)id->block_no,
+ (unsigned long long)id->block_no);
+ else
+ log_warn(_("Pass1b is deleting inode %lld (0x%llx).\n"),
+ (unsigned long long)id->block_no,
+ (unsigned long long)id->block_no);
+
+ dup_block = id->block_no;
ip = fsck_load_inode(sdp, id->block_no);
- if (id->reftypecount[ref_as_data] ||
- id->reftypecount[ref_as_meta]) {
- ii = inodetree_find(ip->i_di.di_num.no_addr);
- if (ii)
- inodetree_delete(ii);
- }
- clear_dup_fxns.private = (void *) dh;
- /* Clear the EAs for the inode first */
- check_inode_eattr(ip, &clear_dup_fxns);
- /* If the dup was in data or metadata, clear the dinode */
- if (id->reftypecount[ref_as_data] ||
- id->reftypecount[ref_as_meta]) {
- check_metatree(ip, &clear_dup_fxns);
- fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
- _("duplicate referencing bad"),
- gfs2_inode_invalid);
+ /* If we've already deleted this dinode, don't try to delete
+ it again. That could free blocks that used to be duplicate
+ references that are now resolved (and gone). */
+ if (q != gfs2_block_free) {
+ /* Clear the EAs for the inode first */
+ check_inode_eattr(ip, &pass1b_fxns_delete);
+ /* If the reference was as metadata or data, we've got
+ a corrupt dinode that will be deleted. */
+ if (inval || id->reftypecount[ref_as_data] ||
+ id->reftypecount[ref_as_meta]) {
+ /* Remove the inode from the inode tree */
+ ii = inodetree_find(ip->i_di.di_num.no_addr);
+ if (ii)
+ inodetree_delete(ii);
+ fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
+ _("duplicate referencing bad"),
+ gfs2_inode_invalid);
+ /* We delete the dup_handler inode count and
+ duplicate id BEFORE clearing the metadata,
+ because if this is the last reference to
+ this metadata block, we need to traverse the
+ tree and free the data blocks it references.
+ However, we don't want to delete other
+ duplicates that may be used by other
+ dinodes. */
+ (dh->ref_inode_count)--;
+ /* FIXME: other option should be to duplicate
+ the block for each duplicate and point the
+ metadata at the cloned blocks */
+ check_metatree(ip, &pass1b_fxns_delete);
+ }
}
+ /* Now we've got to go through an delete any other duplicate
+ references from this dinode we're deleting. If we don't,
+ pass1b will discover the other duplicate record, try to
+ delete this dinode a second time, and this time its earlier
+ duplicate references won't be seen as duplicates anymore
+ (because they were eliminated earlier in pass1b). And so
+ the blocks will be mistakenly freed, when, in fact, they're
+ still being referenced by a valid dinode. */
+ delete_all_dups(ip);
fsck_inode_put(&ip); /* out, brelse, free */
- (dh->ref_inode_count)--;
- /* FIXME: other option should be to duplicate the
- * block for each duplicate and point the metadata at
- * the cloned blocks */
- dup_listent_delete(id);
}
- if (dh->ref_inode_count == 1) /* down to the last reference */
- return 1;
- return 0;
+ return;
}
-static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *dt)
+/* revise_dup_handler - get current information about a duplicate reference
+ *
+ * Function resolve_dup_references can delete dinodes that reference blocks
+ * which may have duplicate references. Therefore, the duplicate tree is
+ * constantly being changed. This function revises the duplicate handler so
+ * that it accurately matches what's in the duplicate tree regarding this block
+ */
+static void revise_dup_handler(uint64_t dup_blk, struct dup_handler *dh)
{
- struct gfs2_inode *ip;
osi_list_t *tmp;
+ struct duptree *dt;
struct inode_with_dups *id;
- struct dup_handler dh = {0};
- int last_reference = 0;
- struct gfs2_buffer_head *bh;
- uint32_t cmagic, ctype;
- enum dup_ref_type acceptable_ref;
+ dh->ref_inode_count = 0;
+ dh->ref_count = 0;
+ dh->dt = NULL;
+
+ dt = dupfind(dup_blk);
+ if (!dt)
+ return;
+
+ dh->dt = dt;
/* Count the duplicate references, both valid and invalid */
osi_list_foreach(tmp, &dt->ref_invinode_list) {
id = osi_list_entry(tmp, struct inode_with_dups, list);
- dh.ref_inode_count++;
- dh.ref_count += id->dup_count;
+ dh->ref_inode_count++;
+ dh->ref_count += id->dup_count;
}
osi_list_foreach(tmp, &dt->ref_inode_list) {
id = osi_list_entry(tmp, struct inode_with_dups, list);
- dh.ref_inode_count++;
- dh.ref_count += id->dup_count;
+ dh->ref_inode_count++;
+ dh->ref_count += id->dup_count;
}
+}
+
+/* handle_dup_blk - handle a duplicate block reference.
+ *
+ * This function should resolve and delete the duplicate block reference given,
+ * iow dt.
+ */
+static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *dt)
+{
+ osi_list_t *tmp;
+ struct gfs2_inode *ip;
+ struct inode_with_dups *id;
+ struct dup_handler dh = {0};
+ struct gfs2_buffer_head *bh;
+ uint32_t cmagic, ctype;
+ enum dup_ref_type acceptable_ref;
+ uint64_t dup_blk;
+
+ dup_blk = dt->block;
+ revise_dup_handler(dup_blk, &dh);
/* Log the duplicate references */
log_notice( _("Block %llu (0x%llx) has %d inodes referencing it"
@@ -638,77 +380,67 @@ static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *dt)
invalidated for other reasons, such as bad pointers. So we need to
make sure at this point that any inode deletes reverse out any
duplicate reference before we get to this point. */
- if (dh.ref_count == 1)
- last_reference = 1;
/* Step 1 - eliminate references from inodes that are not valid.
* This may be because they were deleted due to corruption.
* All block types are unacceptable, so we use ref_types.
*/
- if (!last_reference) {
+ if (dh.ref_count > 1) {
log_debug( _("----------------------------------------------\n"
"Step 1: Eliminate references to block %llu "
"(0x%llx) that were previously marked "
"invalid.\n"),
(unsigned long long)dt->block,
(unsigned long long)dt->block);
- last_reference = resolve_dup_references(sdp, dt,
- &dt->ref_invinode_list,
- &dh, 1, ref_types);
+ resolve_dup_references(sdp, dt, &dt->ref_invinode_list,
+ &dh, 1, ref_types);
+ revise_dup_handler(dup_blk, &dh);
}
/* Step 2 - eliminate reference from inodes that reference it as the
* wrong type. For example, a data file referencing it as
* a data block, but it's really a metadata block. Or a
* directory inode referencing a data block as a leaf block.
*/
- if (!last_reference) {
+ if (dh.ref_count > 1) {
log_debug( _("----------------------------------------------\n"
"Step 2: Eliminate references to block %llu "
"(0x%llx) that need the wrong block type.\n"),
(unsigned long long)dt->block,
(unsigned long long)dt->block);
- last_reference = resolve_dup_references(sdp, dt,
- &dt->ref_inode_list,
- &dh, 0,
- acceptable_ref);
+ resolve_dup_references(sdp, dt, &dt->ref_inode_list, &dh, 0,
+ acceptable_ref);
+ revise_dup_handler(dup_blk, &dh);
}
/* Step 3 - We have multiple dinodes referencing it as the correct
* type. Just blast one of them.
* All block types are fair game, so we use ref_types.
*/
- if (!last_reference) {
+ if (dh.ref_count > 1) {
log_debug( _("----------------------------------------------\n"
"Step 3: Choose one reference to block %llu "
"(0x%llx) to keep.\n"),
(unsigned long long)dt->block,
(unsigned long long)dt->block);
- last_reference = resolve_dup_references(sdp, dt,
- &dt->ref_inode_list,
- &dh, 0, ref_types);
- }
- /* Now fix the block type of the block in question. */
- if (osi_list_empty(&dt->ref_inode_list)) {
- log_notice( _("Block %llu (0x%llx) has no more references; "
- "Marking as 'free'.\n"),
- (unsigned long long)dt->block,
- (unsigned long long)dt->block);
- gfs2_blockmap_set(bl, dt->block, gfs2_block_free);
- check_n_fix_bitmap(sdp, dt->block, gfs2_block_free);
- return 0;
+ resolve_dup_references(sdp, dt, &dt->ref_inode_list, &dh, 0,
+ ref_types);
+ revise_dup_handler(dup_blk, &dh);
}
- if (last_reference) {
+ /* If there's still a last remaining reference, and it's a valid
+ reference, use it to determine the correct block type for our
+ blockmap and bitmap. */
+ if (dh.ref_count == 1 && !osi_list_empty(&dt->ref_inode_list)) {
uint8_t q;
log_notice( _("Block %llu (0x%llx) has only one remaining "
- "reference.\n"),
- (unsigned long long)dt->block,
- (unsigned long long)dt->block);
+ "valid reference.\n"),
+ (unsigned long long)dup_blk,
+ (unsigned long long)dup_blk);
/* If we're down to a single reference (and not all references
deleted, which may be the case of an inode that has only
itself and a reference), we need to reset the block type
from invalid to data or metadata. Start at the first one
in the list, not the structure's place holder. */
- tmp = (&dt->ref_inode_list)->next;
+ tmp = dt->ref_inode_list.next;
id = osi_list_entry(tmp, struct inode_with_dups, list);
log_debug( _("----------------------------------------------\n"
"Step 4. Set block type based on the remaining "
@@ -749,13 +481,147 @@ static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *dt)
"attribute"),
gfs2_meta_eattr);
fsck_inode_put(&ip); /* out, brelse, free */
+ log_debug(_("Done with duplicate reference to block 0x%llx\n"),
+ (unsigned long long)dt->block);
+ dup_delete(dt);
} else {
/* They may have answered no and not fixed all references. */
- log_debug( _("All duplicate references were processed.\n"));
+ log_debug( _("All duplicate references to block 0x%llx were "
+ "processed.\n"), (unsigned long long)dup_blk);
+ if (dh.ref_count) {
+ log_debug(_("Done with duplicate reference to block "
+ "0x%llx, but %d references remain.\n"),
+ (unsigned long long)dup_blk, dh.ref_count);
+ } else {
+ log_notice( _("Block %llu (0x%llx) has no more "
+ "references; Marking as 'free'.\n"),
+ (unsigned long long)dup_blk,
+ (unsigned long long)dup_blk);
+ if (dh.dt)
+ dup_delete(dh.dt);
+ /* Now fix the block type of the block in question. */
+ gfs2_blockmap_set(bl, dup_blk, gfs2_block_free);
+ check_n_fix_bitmap(sdp, dup_blk, gfs2_block_free);
+ }
}
return 0;
}
+static int check_leaf_refs(struct gfs2_inode *ip, uint64_t block,
+ void *private)
+{
+ return add_duplicate_ref(ip, block, ref_as_meta, 1, INODE_VALID);
+}
+
+static int check_metalist_refs(struct gfs2_inode *ip, uint64_t block,
+ struct gfs2_buffer_head **bh, int h,
+ int *is_valid, int *was_duplicate,
+ void *private)
+{
+ *was_duplicate = 0;
+ *is_valid = 1;
+ return add_duplicate_ref(ip, block, ref_as_meta, 1, INODE_VALID);
+}
+
+static int check_data_refs(struct gfs2_inode *ip, uint64_t metablock,
+ uint64_t block, void *private)
+{
+ return add_duplicate_ref(ip, block, ref_as_data, 1, INODE_VALID);
+}
+
+static int check_eattr_indir_refs(struct gfs2_inode *ip, uint64_t block,
+ uint64_t parent,
+ struct gfs2_buffer_head **bh, void *private)
+{
+ struct gfs2_sbd *sdp = ip->i_sbd;
+ int error;
+
+ error = add_duplicate_ref(ip, block, ref_as_ea, 1, INODE_VALID);
+ if (!error)
+ *bh = bread(sdp, block);
+
+ return error;
+}
+
+static int check_eattr_leaf_refs(struct gfs2_inode *ip, uint64_t block,
+ uint64_t parent, struct gfs2_buffer_head **bh,
+ void *private)
+{
+ struct gfs2_sbd *sdp = ip->i_sbd;
+ int error;
+
+ error = add_duplicate_ref(ip, block, ref_as_ea, 1, INODE_VALID);
+ if (!error)
+ *bh = bread(sdp, block);
+ return error;
+}
+
+static int check_eattr_entry_refs(struct gfs2_inode *ip,
+ struct gfs2_buffer_head *leaf_bh,
+ struct gfs2_ea_header *ea_hdr,
+ struct gfs2_ea_header *ea_hdr_prev,
+ void *private)
+{
+ return 0;
+}
+
+static int check_eattr_extentry_refs(struct gfs2_inode *ip,
+ uint64_t *ea_data_ptr,
+ struct gfs2_buffer_head *leaf_bh,
+ struct gfs2_ea_header *ea_hdr,
+ struct gfs2_ea_header *ea_hdr_prev,
+ void *private)
+{
+ uint64_t block = be64_to_cpu(*ea_data_ptr);
+
+ return add_duplicate_ref(ip, block, ref_as_ea, 1, INODE_VALID);
+}
+
+/* Finds all references to duplicate blocks in the metadata */
+/* Finds all references to duplicate blocks in the metadata */
+static int find_block_ref(struct gfs2_sbd *sdp, uint64_t inode)
+{
+ struct gfs2_inode *ip;
+ int error = 0;
+ struct metawalk_fxns find_refs = {
+ .private = NULL,
+ .check_leaf = check_leaf_refs,
+ .check_metalist = check_metalist_refs,
+ .check_data = check_data_refs,
+ .check_eattr_indir = check_eattr_indir_refs,
+ .check_eattr_leaf = check_eattr_leaf_refs,
+ .check_eattr_entry = check_eattr_entry_refs,
+ .check_eattr_extentry = check_eattr_extentry_refs,
+ };
+
+ ip = fsck_load_inode(sdp, inode); /* bread, inode_get */
+
+ /* double-check the meta header just to be sure it's metadata */
+ if (ip->i_di.di_header.mh_magic != GFS2_MAGIC ||
+ ip->i_di.di_header.mh_type != GFS2_METATYPE_DI) {
+ log_debug( _("Block %lld (0x%llx) is not gfs2 metadata.\n"),
+ (unsigned long long)inode,
+ (unsigned long long)inode);
+ error = 1;
+ goto out;
+ }
+ /* Check to see if this inode was referenced by another by mistake */
+ add_duplicate_ref(ip, inode, ref_is_inode, 1, INODE_VALID);
+
+ /* Check this dinode's metadata for references to known duplicates */
+ error = check_metatree(ip, &find_refs);
+ if (error < 0)
+ stack;
+
+ /* Check for ea references in the inode */
+ if (!error)
+ error = check_inode_eattr(ip, &find_refs);
+
+out:
+ fsck_inode_put(&ip); /* out, brelse, free */
+ return error;
+}
+
/* Pass 1b handles finding the previous inode for a duplicate block
* When found, store the inodes pointing to the duplicate block for
* use in pass2 */
@@ -764,7 +630,7 @@ int pass1b(struct gfs2_sbd *sdp)
struct duptree *dt;
uint64_t i;
uint8_t q;
- struct osi_node *n, *next = NULL;
+ struct osi_node *n;
int rc = FSCK_OK;
log_info( _("Looking for duplicate blocks...\n"));
@@ -815,17 +681,11 @@ int pass1b(struct gfs2_sbd *sdp)
* it later */
log_info( _("Handling duplicate blocks\n"));
out:
- for (n = osi_first(&dup_blocks); n; n = next) {
- next = osi_next(n);
+ /* Resolve all duplicates by clearing out the dup tree */
+ while ((n = osi_first(&dup_blocks))) {
dt = (struct duptree *)n;
if (!skip_this_pass && !rc) /* no error & not asked to skip the rest */
handle_dup_blk(sdp, dt);
- /* Do not attempt to free the dup_blocks list or its parts
- here because any func that calls check_metatree needs
- to check duplicate status based on this linked list.
- This is especially true for pass2 where it may delete "bad"
- inodes, and we can't delete an inode's indirect block if
- it was a duplicate (therefore in use by another dinode). */
}
return rc;
}
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index 81d4710..11ceab9 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -167,59 +167,6 @@ static int check_file_type(uint8_t de_type, uint8_t blk_type, int gfs1)
return 0;
}
-static int delete_eattr_entry (struct gfs2_inode *ip,
- struct gfs2_buffer_head *leaf_bh,
- struct gfs2_ea_header *ea_hdr,
- struct gfs2_ea_header *ea_hdr_prev,
- void *private)
-{
- struct gfs2_sbd *sdp = ip->i_sbd;
- char ea_name[256];
-
- if (!ea_hdr->ea_name_len){
- /* Skip this entry for now */
- return 1;
- }
-
- memset(ea_name, 0, sizeof(ea_name));
- strncpy(ea_name, (char *)ea_hdr + sizeof(struct gfs2_ea_header),
- ea_hdr->ea_name_len);
-
- if (!GFS2_EATYPE_VALID(ea_hdr->ea_type) &&
- ((ea_hdr_prev) || (!ea_hdr_prev && ea_hdr->ea_type))){
- /* Skip invalid entry */
- return 1;
- }
-
- if (ea_hdr->ea_num_ptrs){
- uint32_t avail_size;
- int max_ptrs;
-
- avail_size = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_meta_header);
- max_ptrs = (be32_to_cpu(ea_hdr->ea_data_len) + avail_size - 1) /
- avail_size;
-
- if (max_ptrs > ea_hdr->ea_num_ptrs)
- return 1;
- else {
- log_debug( _(" Pointers Required: %d\n Pointers Reported: %d\n"),
- max_ptrs, ea_hdr->ea_num_ptrs);
- }
- }
- return 0;
-}
-
-static int delete_eattr_extentry(struct gfs2_inode *ip, uint64_t *ea_data_ptr,
- struct gfs2_buffer_head *leaf_bh,
- struct gfs2_ea_header *ea_hdr,
- struct gfs2_ea_header *ea_hdr_prev,
- void *private)
-{
- uint64_t block = be64_to_cpu(*ea_data_ptr);
-
- return delete_metadata(ip, block, NULL, 0, private);
-}
-
struct metawalk_fxns pass2_fxns_delete = {
.private = NULL,
.check_metalist = delete_metadata,
@@ -1829,12 +1776,5 @@ int pass2(struct gfs2_sbd *sdp)
}
fsck_inode_put(&ip); /* does a gfs2_dinode_out, brelse */
}
- /* Now that we've deleted the inodes marked "bad" we can safely
- get rid of the duplicate block list. If we do it any sooner,
- we won't discover that a given block is a duplicate and avoid
- deleting it from both inodes referencing it. Note: The other
- returns from this function are premature exits of the program
- and gfs2_block_list_destroy should get rid of the list for us. */
- gfs2_dup_free();
return FSCK_OK;
}
diff --git a/gfs2/fsck/util.c b/gfs2/fsck/util.c
index f40aeb3..d4d9034 100644
--- a/gfs2/fsck/util.c
+++ b/gfs2/fsck/util.c
@@ -384,8 +384,39 @@ struct dir_info *dirtree_find(uint64_t block)
return NULL;
}
-void dup_listent_delete(struct inode_with_dups *id)
+/* get_ref_type - figure out if all duplicate references from this inode
+ are the same type, and if so, return the type. */
+enum dup_ref_type get_ref_type(struct inode_with_dups *id)
{
+ enum dup_ref_type t, i;
+ int found_type_with_ref;
+ int found_other_types;
+
+ for (t = ref_as_data; t < ref_types; t++) {
+ found_type_with_ref = 0;
+ found_other_types = 0;
+ for (i = ref_as_data; i < ref_types; i++) {
+ if (id->reftypecount[i]) {
+ if (t == i)
+ found_type_with_ref = 1;
+ else
+ found_other_types = 1;
+ }
+ }
+ if (found_type_with_ref)
+ return found_other_types ? ref_types : t;
+ }
+ return ref_types;
+}
+
+void dup_listent_delete(struct duptree *dt, struct inode_with_dups *id)
+{
+ log_err( _("Removing duplicate reference to block %llu (0x%llx) "
+ "referenced as %s by dinode %llu (0x%llx)\n"),
+ (unsigned long long)dt->block, (unsigned long long)dt->block,
+ reftypes[get_ref_type(id)], (unsigned long long)id->block_no,
+ (unsigned long long)id->block_no);
+ dt->refs--; /* one less reference */
if (id->name)
free(id->name);
osi_list_del(&id->list);
@@ -400,12 +431,12 @@ void dup_delete(struct duptree *dt)
while (!osi_list_empty(&dt->ref_invinode_list)) {
tmp = (&dt->ref_invinode_list)->next;
id = osi_list_entry(tmp, struct inode_with_dups, list);
- dup_listent_delete(id);
+ dup_listent_delete(dt, id);
}
while (!osi_list_empty(&dt->ref_inode_list)) {
tmp = (&dt->ref_inode_list)->next;
id = osi_list_entry(tmp, struct inode_with_dups, list);
- dup_listent_delete(id);
+ dup_listent_delete(dt, id);
}
osi_erase(&dt->node, &dup_blocks);
free(dt);
diff --git a/gfs2/fsck/util.h b/gfs2/fsck/util.h
index a4ff437..940f500 100644
--- a/gfs2/fsck/util.h
+++ b/gfs2/fsck/util.h
@@ -19,7 +19,7 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block,
enum dup_ref_type reftype, int first, int inode_valid);
extern struct inode_with_dups *find_dup_ref_inode(struct duptree *dt,
struct gfs2_inode *ip);
-extern void dup_listent_delete(struct inode_with_dups *id);
+extern void dup_listent_delete(struct duptree *dt, struct inode_with_dups *id);
extern const char *reftypes[ref_types + 1];
@@ -174,6 +174,7 @@ static inline uint32_t gfs_to_gfs2_mode(struct gfs2_inode *ip)
}
}
+extern enum dup_ref_type get_ref_type(struct inode_with_dups *id);
extern struct gfs2_bmap *gfs2_bmap_create(struct gfs2_sbd *sdp, uint64_t size,
uint64_t *addl_mem_needed);
extern void *gfs2_bmap_destroy(struct gfs2_sbd *sdp, struct gfs2_bmap *il);
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=ebf7e17895b0b…
Commit: ebf7e17895b0ba7b4bf97af9714e52d7ea63efa0
Parent: 8c4b34b4afcb4b51d927f5e2dfebeb0a60ece4cb
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Wed Apr 3 10:03:49 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri May 17 15:29:20 2013 -0500
fsck.gfs2: When flagging a duplicate reference, show valid or invalid
This patch changes the logging when duplicate block references are
flagged. The idea is to print whether or not the inode with the reference
is valid or invalid, which helps in diagnosing problems when duplicate
block references are resolved.
rhbz#902920
---
gfs2/fsck/util.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/gfs2/fsck/util.c b/gfs2/fsck/util.c
index 48c4b33..f40aeb3 100644
--- a/gfs2/fsck/util.c
+++ b/gfs2/fsck/util.c
@@ -317,9 +317,10 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block,
id->reftypecount[reftype]++;
id->dup_count++;
log_info( _("Found %d reference(s) to block %llu"
- " (0x%llx) as %s in inode #%llu (0x%llx)\n"),
+ " (0x%llx) as %s in %s inode #%llu (0x%llx)\n"),
id->dup_count, (unsigned long long)block,
(unsigned long long)block, reftypes[reftype],
+ inode_valid ? _("valid") : _("invalid"),
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
if (first)
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=8c4b34b4afcb4…
Commit: 8c4b34b4afcb4b51d927f5e2dfebeb0a60ece4cb
Parent: 7e2edea6c24a396abd88ea92e8cc405f5f03cf82
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Wed Apr 3 09:47:31 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri May 17 15:29:16 2013 -0500
fsck.gfs2: check for duplicate first references
Before this patch, fsck.gfs2 could get into situations where it's
in pass1b searching for the first reference to a block that it knows
has been referenced twice. However, for one reason or another, the
first reference has been deleted. It may seem unlikely because pass1
tries to "undo" its references when it deletes a bad dinode. But
it can still happen, for example, when pass1b decides to delete a
dinode because of a _different_ duplicate reference within the same
dinode. If the first reference was deleted prior to searching for the
original reference, pass1b won't find the original reference. So
prior to this patch, it would just keep on looking, until it found
the second reference. In other words, it would mistake the second
reference for the first reference. Then it would get confused and
treat the reference as a duplicate of itself. Later, it would choose
which reference to delete, and delete its dinode. But since they're
the same reference, it could delete a dinode with a perfectly good
reference (the first invalid reference having already been deleted).
The solution that this patch implements is to check if the first
reference we found is actually the second reference, and if so,
treat it as a first reference. That way, it avoids creating a
second duplicate reference structure, and later when it resolves
the references, it finds there's only one, and it doesn't need to
delete the valid dinode.
rhbz#902920
---
gfs2/fsck/util.c | 24 ++++++++++++++++++++++--
1 files changed, 22 insertions(+), 2 deletions(-)
diff --git a/gfs2/fsck/util.c b/gfs2/fsck/util.c
index 2111684..48c4b33 100644
--- a/gfs2/fsck/util.c
+++ b/gfs2/fsck/util.c
@@ -248,6 +248,28 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block,
if (dt->first_ref_found)
return meta_is_good;
+ /* Check for a previous reference to this duplicate */
+ id = find_dup_ref_inode(dt, ip);
+
+ /* We have to be careful here. The original referencing dinode may have
+ deemed to be bad and deleted/freed in pass1. In that case, pass1b
+ wouldn't discover the correct [deleted] original reference. In
+ that case, we don't want to be confused and consider this second
+ reference the same as the first. If we do, we'll never be able to
+ resolve it. The first reference can't be the second reference. */
+ if (id && first && !dt->first_ref_found) {
+ log_info(_("Original reference to block %llu (0x%llx) was "
+ "previously found to be bad and deleted.\n"),
+ (unsigned long long)block,
+ (unsigned long long)block);
+ log_info(_("I'll consider the reference from inode %llu "
+ "(0x%llx) the first reference.\n"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr);
+ dt->first_ref_found = 1;
+ return meta_is_good;
+ }
+
/* The first time this is called from pass1 is actually the second
reference. When we go back in pass1b looking for the original
reference, we don't want to increment the reference count because
@@ -259,8 +281,6 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block,
dt->refs++;
}
- /* Check for a previous reference to this duplicate */
- id = find_dup_ref_inode(dt, ip);
if (id == NULL) {
/* Check for the inode on the invalid inode reference list. */
uint8_t q;
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=7e2edea6c24a3…
Commit: 7e2edea6c24a396abd88ea92e8cc405f5f03cf82
Parent: dcbe98785dec9af82e198175016197044b03d19d
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Wed Apr 3 09:28:09 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri May 17 15:29:10 2013 -0500
fsck.gfs2: don't invalidate files with duplicate data block refs
Before this patch, whenever pass1 encountered a duplicated data block
pointer, it would mark the file as invalid. But if reason the block
was duplicated was due to a different bad inode, the inode with the
valid data block reference was still punished and deleted.
This patch adds an additional check to see if the previous reference
to the data block was as a _valid_ metadata block. If the previous
reference was as metadata, and the metadata checked out okay, then
it can't possibly be a data block for the second reference. In that
case, we know for a fact that the second reference is invalid. But
if the previous reference was also as data, the inode might be okay
and duplicate resolving in pass1b might sort it out and leave this
inode as the only valid reference. In that case, we should treat the
inode as valid, not invalid. So this patch basically treats duplicate
data block references as "innocent until proven guilty" rather than
just the opposite.
rhbz#902920
---
gfs2/fsck/pass1.c | 20 +++++++++++++++++---
1 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index ffa36b9..564f75d 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -424,18 +424,32 @@ static int check_data(struct gfs2_inode *ip, uint64_t metablock,
log_err(_("from metadata block %llu (0x%llx)\n"),
(unsigned long long)metablock,
(unsigned long long)metablock);
-
+
+ if (q >= gfs2_indir_blk && q <= gfs2_jdata) {
+ log_info(_("The block was processed earlier as valid "
+ "metadata, so it can't possibly be "
+ "data.\n"));
+ /* We still need to add a duplicate record here because
+ when check_metatree tries to delete the inode, we
+ can't have the "undo" functions freeing the block
+ out from other the original referencing inode. */
+ add_duplicate_ref(ip, block, ref_as_data, 0,
+ INODE_VALID);
+ return 1;
+ }
if (q != gfs2_meta_inval) {
log_info( _("Seems to be a normal duplicate; I'll "
"sort it out in pass1b.\n"));
add_duplicate_ref(ip, block, ref_as_data, 0,
INODE_VALID);
- return 1;
+ /* This inode references the block as data. So if this
+ all is validated, we want to keep this count. */
+ return 0;
}
log_info( _("The block was invalid as metadata but might be "
"okay as data. I'll sort it out in pass1b.\n"));
add_duplicate_ref(ip, block, ref_as_data, 0, INODE_VALID);
- return 1;
+ return 0;
}
/* In gfs1, rgrp indirect blocks are marked in the bitmap as "meta".
In gfs2, "meta" is only for dinodes. So here we dummy up the
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=dcbe98785dec9…
Commit: dcbe98785dec9af82e198175016197044b03d19d
Parent: f4ebc1f1534ea1c3ba413dadb971d1e7063bde67
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Wed Apr 3 08:55:00 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri May 17 15:29:05 2013 -0500
fsck.gfs2: standardize check_metatree return codes
This patch aims to not change functionality at all. What it does is
adds a standard set of three return codes with the following meanings:
meta_is_good - all is well, keep processing metadata normally
meta_skip_further - an non-fatal error occurred, so further metadata
processing for this inode should be skipped.
meta_error - a fatal error occurred in this metadata, so we need to
abort processing.
rhbz#902920
---
gfs2/fsck/metawalk.c | 14 +++++++-------
gfs2/fsck/metawalk.h | 6 ++++++
gfs2/fsck/pass1.c | 28 ++++++++++++++--------------
gfs2/fsck/pass1b.c | 6 +++---
gfs2/fsck/util.c | 12 ++++++------
5 files changed, 36 insertions(+), 30 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index a9fce81..7ce8524 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -994,9 +994,9 @@ int free_block_if_notdup(struct gfs2_inode *ip, uint64_t block,
{
if (!find_remove_dup(ip, block, btype)) { /* not a dup */
fsck_blockmap_set(ip, block, btype, gfs2_block_free);
- return 1;
+ return meta_skip_further;
}
- return 0;
+ return meta_is_good;
}
/**
@@ -1013,7 +1013,7 @@ static int delete_block_if_notdup(struct gfs2_inode *ip, uint64_t block,
uint8_t q;
if (!valid_block(ip->i_sbd, block))
- return -EFAULT;
+ return meta_error;
q = block_type(block);
if (q == gfs2_block_free) {
@@ -1023,7 +1023,7 @@ static int delete_block_if_notdup(struct gfs2_inode *ip, uint64_t block,
(unsigned long long)block,
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
- return 0;
+ return meta_is_good;
}
return free_block_if_notdup(ip, block, btype);
}
@@ -1253,12 +1253,12 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
pass->private);
/* check_metalist should hold any buffers
it gets with "bread". */
- if (err < 0) {
+ if (err == meta_error) {
stack;
error = err;
return error;
}
- if (err > 0) {
+ if (err == meta_skip_further) {
if (!error)
error = err;
log_debug( _("Skipping block %llu (0x%llx)\n"),
@@ -1658,7 +1658,7 @@ static int alloc_metalist(struct gfs2_inode *ip, uint64_t block,
(unsigned long long)block);
gfs2_blockmap_set(bl, block, gfs2_indir_blk);
}
- return 0;
+ return meta_is_good;
}
static int alloc_data(struct gfs2_inode *ip, uint64_t metablock,
diff --git a/gfs2/fsck/metawalk.h b/gfs2/fsck/metawalk.h
index 2ba0d72..49217cc 100644
--- a/gfs2/fsck/metawalk.h
+++ b/gfs2/fsck/metawalk.h
@@ -56,6 +56,12 @@ extern int free_block_if_notdup(struct gfs2_inode *ip, uint64_t block,
#define fsck_blockmap_set(ip, b, bt, m) _fsck_blockmap_set(ip, b, bt, m, \
__FUNCTION__, __LINE__)
+enum meta_check_rc {
+ meta_error = -1,
+ meta_is_good = 0,
+ meta_skip_further = 1,
+};
+
/* metawalk_fxns: function pointers to check various parts of the fs
*
* The functions should return -1 on fatal errors, 1 if the block
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index 0cf4373..ffa36b9 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -138,14 +138,14 @@ static int resuscitate_metalist(struct gfs2_inode *ip, uint64_t block,
"range) found in system inode %lld (0x%llx).\n"),
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
- return 1;
+ return meta_skip_further;
}
if (fsck_system_inode(ip->i_sbd, block))
fsck_blockmap_set(ip, block, _("system file"), gfs2_indir_blk);
else
check_n_fix_bitmap(ip->i_sbd, block, gfs2_indir_blk);
bc->indir_count++;
- return 0;
+ return meta_is_good;
}
/*
@@ -262,7 +262,7 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
- return 1;
+ return meta_skip_further;
}
if (is_dir(&ip->i_di, ip->i_sbd->gfs1) && h == ip->i_di.di_height) {
iblk_type = GFS2_METATYPE_JD;
@@ -299,7 +299,7 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
gfs2_meta_inval);
brelse(nbh);
nbh = NULL;
- return 1;
+ return meta_skip_further;
}
brelse(nbh);
nbh = NULL;
@@ -313,12 +313,12 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
nbh = NULL;
*bh = NULL;
}
- return 1; /* don't process the metadata again */
+ return meta_skip_further; /* don't process the metadata again */
} else
fsck_blockmap_set(ip, block, _("indirect"),
gfs2_indir_blk);
- return 0;
+ return meta_is_good;
}
/* undo_reference - undo previously processed data or metadata
@@ -824,7 +824,7 @@ static int mark_block_invalid(struct gfs2_inode *ip, uint64_t block,
* and as a result, they'll be freed when this dinode is deleted,
* despite being used by another dinode as a valid block. */
if (!valid_block(ip->i_sbd, block))
- return 0;
+ return meta_is_good;
q = block_type(block);
if (q != gfs2_block_free) {
@@ -836,10 +836,10 @@ static int mark_block_invalid(struct gfs2_inode *ip, uint64_t block,
(unsigned long long)block,
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
- return 0;
+ return meta_is_good;
}
fsck_blockmap_set(ip, block, btype, gfs2_meta_inval);
- return 0;
+ return meta_is_good;
}
static int invalidate_metadata(struct gfs2_inode *ip, uint64_t block,
@@ -909,9 +909,9 @@ static int rangecheck_block(struct gfs2_inode *ip, uint64_t block,
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
if ((*bad_pointers) <= BAD_POINTER_TOLERANCE)
- return ENOENT;
+ return meta_skip_further;
else
- return -ENOENT; /* Exits check_metatree quicker */
+ return meta_error; /* Exits check_metatree quicker */
}
/* See how many duplicate blocks it has */
q = block_type(block);
@@ -924,11 +924,11 @@ static int rangecheck_block(struct gfs2_inode *ip, uint64_t block,
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
if ((*bad_pointers) <= BAD_POINTER_TOLERANCE)
- return ENOENT;
+ return meta_skip_further;
else
- return -ENOENT; /* Exits check_metatree quicker */
+ return meta_error; /* Exits check_metatree quicker */
}
- return 0;
+ return meta_is_good;
}
static int rangecheck_metadata(struct gfs2_inode *ip, uint64_t block,
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index 7680bc1..03e47ec 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -213,7 +213,7 @@ static int clear_dup_metalist(struct gfs2_inode *ip, uint64_t block,
struct duptree *dt;
if (!valid_block(ip->i_sbd, block))
- return 0;
+ return meta_is_good;
/* This gets tricky. We're traversing a metadata tree trying to
delete an inode based on it having a duplicate block reference
@@ -229,7 +229,7 @@ static int clear_dup_metalist(struct gfs2_inode *ip, uint64_t block,
if (!dt) {
fsck_blockmap_set(ip, block, _("no longer valid"),
gfs2_block_free);
- return 0;
+ return meta_is_good;
}
/* This block, having failed the above test, is duplicated somewhere */
if (block == dh->dt->block) {
@@ -251,7 +251,7 @@ static int clear_dup_metalist(struct gfs2_inode *ip, uint64_t block,
be mistakenly freed as "no longer valid" (in this function above)
even though it's valid metadata for a different inode. Returning
1 ensures that the metadata isn't processed again. */
- return 1;
+ return meta_skip_further;
}
static int clear_dup_data(struct gfs2_inode *ip, uint64_t metablock,
diff --git a/gfs2/fsck/util.c b/gfs2/fsck/util.c
index 78d4e79..2111684 100644
--- a/gfs2/fsck/util.c
+++ b/gfs2/fsck/util.c
@@ -234,19 +234,19 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block,
struct duptree *dt;
if (!valid_block(ip->i_sbd, block))
- return 0;
+ return meta_is_good;
/* If this is not the first reference (i.e. all calls from pass1) we
need to create the duplicate reference. If this is pass1b, we want
to ignore references that aren't found. */
dt = gfs2_dup_set(block, !first);
if (!dt) /* If this isn't a duplicate */
- return 0;
+ return meta_is_good;
/* If we found the duplicate reference but we've already discovered
the first reference (in pass1b) and the other references in pass1,
we don't need to count it, so just return. */
if (dt->first_ref_found)
- return 0;
+ return meta_is_good;
/* The first time this is called from pass1 is actually the second
reference. When we go back in pass1b looking for the original
@@ -268,12 +268,12 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block,
if (!(id = malloc(sizeof(*id)))) {
log_crit( _("Unable to allocate "
"inode_with_dups structure\n"));
- return -1;
+ return meta_error;
}
if (!(memset(id, 0, sizeof(*id)))) {
log_crit( _("Unable to zero inode_with_dups "
"structure\n"));
- return -1;
+ return meta_error;
}
id->block_no = ip->i_di.di_num.no_addr;
q = block_type(ip->i_di.di_num.no_addr);
@@ -307,7 +307,7 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block,
else
log_info( _("This brings the total to: %d duplicate "
"references\n"), dt->refs);
- return 0;
+ return meta_is_good;
}
struct dir_info *dirtree_insert(struct gfs2_inum inum)
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=f4ebc1f1534ea…
Commit: f4ebc1f1534ea1c3ba413dadb971d1e7063bde67
Parent: c525fe7e12a59d5e09491dd0de48eadbb56b6a75
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Wed Apr 3 07:25:00 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri May 17 15:28:58 2013 -0500
fsck.gfs2 pass2: check leaf blocks when fixing hash table
Before this patch, pass2 would attempt to fix the hash table without
first checking the basic integrity of the leaf blocks it was checking.
A misplaced leaf might have its entries relocated as a matter of course.
But if that leaf block had a problem, it could cause all kinds of
errors, including segfaults. This patch gives the hash table repair
function the ability to do basic integrity checks on the leaf block,
and perform repairs if necessary.
rhbz#902920
---
gfs2/fsck/pass2.c | 100 +++++++++++++++++++++++++++++++++++++++++-----------
1 files changed, 79 insertions(+), 21 deletions(-)
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index 9f477b8..81d4710 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -1048,6 +1048,66 @@ static int lost_leaf(struct gfs2_inode *ip, uint64_t *tbl, uint64_t leafno,
return 1;
}
+static int basic_check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
+ struct gfs2_dirent *prev_de,
+ struct gfs2_buffer_head *bh, char *filename,
+ uint32_t *count, int lindex, void *priv)
+{
+ uint8_t q = 0;
+ char tmp_name[MAX_FILENAME];
+ struct gfs2_inum entry;
+ struct dir_status *ds = (struct dir_status *) priv;
+ struct gfs2_dirent dentry, *de;
+ int error;
+
+ memset(&dentry, 0, sizeof(struct gfs2_dirent));
+ gfs2_dirent_in(&dentry, (char *)dent);
+ de = &dentry;
+
+ entry.no_addr = de->de_inum.no_addr;
+ entry.no_formal_ino = de->de_inum.no_formal_ino;
+
+ /* Start of checks */
+ memset(tmp_name, 0, MAX_FILENAME);
+ if (de->de_name_len < MAX_FILENAME)
+ strncpy(tmp_name, filename, de->de_name_len);
+ else
+ strncpy(tmp_name, filename, MAX_FILENAME - 1);
+
+ error = basic_dentry_checks(ip, dent, &entry, tmp_name, count, de,
+ ds, &q, bh);
+ if (error) {
+ dirent2_del(ip, bh, prev_de, dent);
+ log_err( _("Bad directory entry '%s' cleared.\n"), tmp_name);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static int pass2_repair_leaf(struct gfs2_inode *ip, uint64_t *leaf_no,
+ int lindex, int ref_count, const char *msg,
+ void *private)
+{
+ return repair_leaf(ip, leaf_no, lindex, ref_count, msg);
+}
+
+/* The purpose of leafck_fxns is to provide a means for function fix_hashtable
+ * to do basic sanity checks on leaf blocks before manipulating them, for
+ * example, splitting them. If they're corrupt, splitting them or trying to
+ * move their contents can cause a segfault. We can't really use the standard
+ * pass2_fxns because that will do things we don't want. For example, it will
+ * find '.' and '..' and increment the directory link count, which would be
+ * done a second time when the dirent is really checked in pass2_fxns.
+ * We don't want it to do the "wrong leaf" thing, or set_parent_dir either.
+ * We just want a basic sanity check on pointers and lengths.
+ */
+struct metawalk_fxns leafck_fxns = {
+ .check_leaf_depth = check_leaf_depth,
+ .check_dentry = basic_check_dentry,
+ .repair_leaf = pass2_repair_leaf,
+};
+
/* fix_hashtable - fix a corrupt hash table
*
* The main intent of this function is to sort out hash table problems.
@@ -1077,10 +1137,11 @@ static int fix_hashtable(struct gfs2_inode *ip, uint64_t *tbl, unsigned hsize,
int len, int *proper_len, int factor)
{
struct gfs2_buffer_head *lbh;
- struct gfs2_leaf *leaf;
+ struct gfs2_leaf leaf;
struct gfs2_dirent dentry, *de;
int changes = 0, error, i, extras, hash_index;
uint64_t new_leaf_blk;
+ uint64_t leaf_no;
uint32_t leaf_proper_start;
*proper_len = len;
@@ -1094,14 +1155,20 @@ static int fix_hashtable(struct gfs2_inode *ip, uint64_t *tbl, unsigned hsize,
return 0;
}
+ memset(&leaf, 0, sizeof(leaf));
+ leaf_no = leafblk;
+ error = check_leaf(ip, lindex, &leafck_fxns, &leaf_no, &leaf, &len);
+ if (error) {
+ log_debug("Leaf repaired while fixing the hash table.\n");
+ error = 0;
+ }
lbh = bread(ip->i_sbd, leafblk);
- leaf = (struct gfs2_leaf *)lbh->b_data;
/* If the leaf's depth is out of range for this dinode, it's obviously
attached to the wrong dinode. Move the dirents to lost+found. */
- if (be16_to_cpu(leaf->lf_depth) > ip->i_di.di_depth) {
+ if (leaf.lf_depth > ip->i_di.di_depth) {
log_err(_("This leaf block's depth (%d) is too big for this "
"dinode's depth (%d)\n"),
- be16_to_cpu(leaf->lf_depth), ip->i_di.di_depth);
+ leaf.lf_depth, ip->i_di.di_depth);
error = lost_leaf(ip, tbl, leafblk, len, lindex, lbh);
brelse(lbh);
return error;
@@ -1127,7 +1194,7 @@ static int fix_hashtable(struct gfs2_inode *ip, uint64_t *tbl, unsigned hsize,
}
/* Calculate the proper number of pointers based on the leaf depth. */
- *proper_len = 1 << (ip->i_di.di_depth - be16_to_cpu(leaf->lf_depth));
+ *proper_len = 1 << (ip->i_di.di_depth - leaf.lf_depth);
/* Look at the first dirent and check its hash value to see if it's
at the proper starting offset. */
@@ -1160,7 +1227,7 @@ static int fix_hashtable(struct gfs2_inode *ip, uint64_t *tbl, unsigned hsize,
already at its maximum depth. */
if ((leaf_proper_start < proper_start) ||
((*proper_len > len || lindex > leaf_proper_start) &&
- be16_to_cpu(leaf->lf_depth) == ip->i_di.di_depth)) {
+ leaf.lf_depth == ip->i_di.di_depth)) {
log_err(_("Leaf block should start at 0x%x, but it appears at "
"0x%x in the hash table.\n"), leaf_proper_start,
proper_start);
@@ -1175,24 +1242,22 @@ static int fix_hashtable(struct gfs2_inode *ip, uint64_t *tbl, unsigned hsize,
later than they should, we can split the leaf to give it a smaller
footprint in the hash table. */
if ((*proper_len > len || lindex > leaf_proper_start) &&
- ip->i_di.di_depth > be16_to_cpu(leaf->lf_depth)) {
+ ip->i_di.di_depth > leaf.lf_depth) {
log_err(_("For depth %d, length %d, the proper start is: "
"0x%x.\n"), factor, len, proper_start);
changes++;
new_leaf_blk = find_free_blk(ip->i_sbd);
dir_split_leaf(ip, lindex, leafblk, lbh);
/* re-read the leaf to pick up dir_split_leaf's changes */
- gfs2_leaf_in(leaf, lbh);
- *proper_len = 1 << (ip->i_di.di_depth -
- be16_to_cpu(leaf->lf_depth));
+ gfs2_leaf_in(&leaf, lbh);
+ *proper_len = 1 << (ip->i_di.di_depth - leaf.lf_depth);
log_err(_("Leaf block %llu (0x%llx) was split from length "
"%d to %d\n"), (unsigned long long)leafblk,
(unsigned long long)leafblk, len, *proper_len);
if (*proper_len < 0) {
log_err(_("Programming error: proper_len=%d, "
"di_depth = %d, lf_depth = %d.\n"),
- *proper_len, ip->i_di.di_depth,
- be16_to_cpu(leaf->lf_depth));
+ *proper_len, ip->i_di.di_depth, leaf.lf_depth);
exit(FSCK_ERROR);
}
log_err(_("New split-off leaf block was allocated at %lld "
@@ -1217,8 +1282,8 @@ static int fix_hashtable(struct gfs2_inode *ip, uint64_t *tbl, unsigned hsize,
if (*proper_len < len) {
log_err(_("There are %d pointers, but leaf 0x%llx's "
"depth, %d, only allows %d\n"),
- len, (unsigned long long)leafblk,
- be16_to_cpu(leaf->lf_depth), *proper_len);
+ len, (unsigned long long)leafblk, leaf.lf_depth,
+ *proper_len);
}
brelse(lbh);
/* At this point, lindex should be at the proper end of the pointers.
@@ -1420,13 +1485,6 @@ static int check_hash_tbl(struct gfs2_inode *ip, uint64_t *tbl,
return error;
}
-static int pass2_repair_leaf(struct gfs2_inode *ip, uint64_t *leaf_no,
- int lindex, int ref_count, const char *msg,
- void *private)
-{
- return repair_leaf(ip, leaf_no, lindex, ref_count, msg);
-}
-
struct metawalk_fxns pass2_fxns = {
.private = NULL,
.check_leaf_depth = check_leaf_depth,
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=54904ce52d565…
Commit: 54904ce52d5658debffe92d8f1cdc5ab15ce96c3
Parent: 84d59ca4ac7e0c1479c5a9718f622bcbcbd09adb
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Tue Apr 2 13:19:35 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri May 17 15:28:04 2013 -0500
fsck.gfs2: Don't flag GFS1 non-dinode blocks as duplicates
Before this patch, fsck.gfs2 could get into problems when processing
a GFS1 file system. The issue goes back to the fact that all GFS1
metadata is marked as "Meta" in the bitmap, whereas that bitmap
designation is reserved for dinodes in GFS2. For example, take a
GFS1 file of height 2, which looks like this:
Block
------
0x1234 dinode
0x1235 |----> indirect meta
0x1236 |---->data at offset 0 of the file
Before this patch, fsck.gfs2 would:
1. Encounter the dinode at 0x1234 and mark it as "dinode" in the
blockmap.
2. Process its metadata, see block 0x1235, mark it as "indirect meta"
in the blockmap.
3. Process the metadata's data, see block 0x1236, mark it as "data".
4. When it's done with the dinode, it moves on to the next dinode.
But since GFS1 doesn't distinguish dinodes from other metadata,
the next block in the bitmap that has that designation is block
0x1235.
5. Since block 0x1235 was previously marked "indirect meta" pass1
gets confused and thinks the block is a duplicate reference,
and it's invalid as a dinode. This is a non-problem that's
treated as a problem, and it makes bad decisions based on it,
deleting what it perceives to be corruption.
This patch adds special checks for this problem and assumes the block
is just normal GFS1 non-dinode metadata.
rhbz#902920
---
gfs2/fsck/pass1.c | 89 +++++++++++++++++++++++++++++++++-------------------
1 files changed, 56 insertions(+), 33 deletions(-)
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index 90b865f..e10e4ce 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -1083,22 +1083,11 @@ bad_dinode:
*/
static int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh)
{
- uint8_t q;
int error = 0;
uint64_t block = bh->b_blocknr;
struct gfs2_inode *ip;
ip = fsck_inode_get(sdp, bh);
- q = block_type(block);
- if (q != gfs2_block_free) {
- log_err( _("Found a duplicate inode block at #%llu"
- " (0x%llx) previously marked as a %s\n"),
- (unsigned long long)block,
- (unsigned long long)block, block_type_string(q));
- add_duplicate_ref(ip, block, ref_as_meta, 0, INODE_VALID);
- fsck_inode_put(&ip);
- return 0;
- }
if (ip->i_di.di_num.no_addr != block) {
log_err( _("Inode #%llu (0x%llx): Bad inode address found: %llu "
@@ -1367,11 +1356,13 @@ int pass1(struct gfs2_sbd *sdp)
{
struct osi_node *n, *next = NULL;
struct gfs2_buffer_head *bh;
+ struct gfs2_inode *ip;
uint64_t block = 0;
struct rgrp_tree *rgd;
int first;
uint64_t i;
uint64_t rg_count = 0;
+ uint8_t q;
osi_list_init(&gfs1_rindex_blks.list);
@@ -1417,6 +1408,9 @@ int pass1(struct gfs2_sbd *sdp)
first = 1;
while (1) {
+ int is_inode;
+ uint32_t check_magic;
+
/* "block" is relative to the entire file system */
/* Get the next dinode in the file system, according
to the bitmap. This should ONLY be dinodes unless
@@ -1451,12 +1445,55 @@ int pass1(struct gfs2_sbd *sdp)
first = 0;
continue;
}
+
bh = bread(sdp, block);
+ is_inode = 0;
+ if (gfs2_check_meta(bh, GFS2_METATYPE_DI) == 0)
+ is_inode = 1;
+
+ check_magic = ((struct gfs2_meta_header *)
+ (bh->b_data))->mh_magic;
+
+ q = block_type(block);
+ if (q != gfs2_block_free) {
+ if (be32_to_cpu(check_magic) == GFS2_MAGIC &&
+ sdp->gfs1 && !is_inode) {
+ log_debug("Block 0x%llx assumed to be "
+ "previously processed GFS1 "
+ "non-dinode metadata.\n",
+ (unsigned long long)block);
+ brelse(bh);
+ first = 0;
+ continue;
+ }
+ log_err( _("Found a duplicate inode block at "
+ "#%llu (0x%llx) previously marked "
+ "as a %s\n"),
+ (unsigned long long)block,
+ (unsigned long long)block,
+ block_type_string(q));
+ ip = fsck_inode_get(sdp, bh);
+ if (is_inode &&
+ ip->i_di.di_num.no_addr == block)
+ add_duplicate_ref(ip, block,
+ ref_is_inode, 0,
+ INODE_VALID);
+ else
+ log_info(_("dinum.no_addr is wrong, "
+ "so I assume the bitmap is "
+ "just wrong.\n"));
+ fsck_inode_put(&ip);
+ brelse(bh);
+ first = 0;
+ continue;
+ }
+
/*log_debug( _("Checking metadata block #%" PRIu64
" (0x%" PRIx64 ")\n"), block, block);*/
- if (gfs2_check_meta(bh, GFS2_METATYPE_DI)) {
+ if (!is_inode) {
+ if (be32_to_cpu(check_magic) == GFS2_MAGIC) {
/* In gfs2, a bitmap mark of 2 means an inode,
but in gfs1 it means any metadata. So if
this is gfs1 and not an inode, it may be
@@ -1464,14 +1501,7 @@ int pass1(struct gfs2_sbd *sdp)
be referenced by an inode, so we need to
skip it here and it will be sorted out
when the referencing inode is checked. */
- if (sdp->gfs1) {
- uint32_t check_magic;
-
- check_magic = ((struct
- gfs2_meta_header *)
- (bh->b_data))->mh_magic;
- if (be32_to_cpu(check_magic) ==
- GFS2_MAGIC) {
+ if (sdp->gfs1) {
log_debug( _("Deferring GFS1 "
"metadata block #"
"%" PRIu64" (0x%"
@@ -1481,20 +1511,13 @@ int pass1(struct gfs2_sbd *sdp)
first = 0;
continue;
}
+ log_err( _("Found invalid inode at "
+ "block #%llu (0x%llx)\n"),
+ (unsigned long long)block,
+ (unsigned long long)block);
+ check_n_fix_bitmap(sdp, block,
+ gfs2_block_free);
}
- log_err( _("Found invalid inode at block #"
- "%llu (0x%llx)\n"),
- (unsigned long long)block,
- (unsigned long long)block);
- if (gfs2_blockmap_set(bl, block,
- gfs2_block_free)) {
- stack;
- brelse(bh);
- gfs2_special_free(&gfs1_rindex_blks);
- return FSCK_ERROR;
- }
- check_n_fix_bitmap(sdp, block,
- gfs2_block_free);
} else if (handle_di(sdp, bh) < 0) {
stack;
brelse(bh);