Initial commit -- seeded with reiserfsprogs 3.x.0j

This commit is contained in:
Jeff Mahoney committed 2012-10-11 11:26:22 -04:00
commit e7102bdb66
77 files changed
+33513

No files matched your search

+11
View File
@@ -0,0 +1,11 @@
sbin_PROGRAMS = reiserfsck
reiserfsck_SOURCES = main.c pass0.c pass1.c pass2.c semantic.c pass4.c lost+found.c \
ubitmap.c uobjectid.c ustree.c ufile.c check.c check_tree.c journal.c info.c segments.c\
fsck.h
man_MANS = reiserfsck.8
EXTRA_DIST = $(man_MANS)
LDADD = ../lib/libmisc.a ../reiserfscore/libcore.a
INCLUDES = -I../include -I.
+358
View File
@@ -0,0 +1,358 @@
# Makefile.in generated automatically by automake 1.4 from Makefile.am
# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
# This Makefile.in 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.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
SHELL = @SHELL@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
sbindir = @sbindir@
libexecdir = @libexecdir@
datadir = @datadir@
sysconfdir = @sysconfdir@
sharedstatedir = @sharedstatedir@
localstatedir = @localstatedir@
libdir = @libdir@
infodir = @infodir@
mandir = @mandir@
includedir = @includedir@
oldincludedir = /usr/include
DESTDIR =
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
top_builddir = ..
ACLOCAL = @ACLOCAL@
AUTOCONF = @AUTOCONF@
AUTOMAKE = @AUTOMAKE@
AUTOHEADER = @AUTOHEADER@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
INSTALL_DATA = @INSTALL_DATA@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
transform = @program_transform_name@
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
CC = @CC@
MAKEINFO = @MAKEINFO@
PACKAGE = @PACKAGE@
RANLIB = @RANLIB@
VERSION = @VERSION@
sbin_PROGRAMS = reiserfsck
reiserfsck_SOURCES = main.c pass0.c pass1.c pass2.c semantic.c pass4.c lost+found.c ubitmap.c uobjectid.c ustree.c ufile.c check.c check_tree.c journal.c info.c segments.c fsck.h
man_MANS = reiserfsck.8
EXTRA_DIST = $(man_MANS)
LDADD = ../lib/libmisc.a ../reiserfscore/libcore.a
INCLUDES = -I../include -I.
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_CLEAN_FILES =
PROGRAMS = $(sbin_PROGRAMS)
DEFS = @DEFS@ -I. -I$(srcdir)
CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
reiserfsck_OBJECTS = main.o pass0.o pass1.o pass2.o semantic.o pass4.o \
lost+found.o ubitmap.o uobjectid.o ustree.o ufile.o check.o \
check_tree.o journal.o info.o segments.o
reiserfsck_LDADD = $(LDADD)
reiserfsck_DEPENDENCIES = ../lib/libmisc.a ../reiserfscore/libcore.a
reiserfsck_LDFLAGS =
CFLAGS = @CFLAGS@
COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC)
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
man8dir = $(mandir)/man8
MANS = $(man_MANS)
NROFF = nroff
DIST_COMMON = Makefile.am Makefile.in
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
TAR = tar
GZIP_ENV = --best
SOURCES = $(reiserfsck_SOURCES)
OBJECTS = $(reiserfsck_OBJECTS)
all: all-redirect
.SUFFIXES:
.SUFFIXES: .S .c .o .s
$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps fsck/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
mostlyclean-sbinPROGRAMS:
clean-sbinPROGRAMS:
-test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS)
distclean-sbinPROGRAMS:
maintainer-clean-sbinPROGRAMS:
install-sbinPROGRAMS: $(sbin_PROGRAMS)
@$(NORMAL_INSTALL)
$(mkinstalldirs) $(DESTDIR)$(sbindir)
@list='$(sbin_PROGRAMS)'; for p in $$list; do \
if test -f $$p; then \
echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \
$(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
else :; fi; \
done
uninstall-sbinPROGRAMS:
@$(NORMAL_UNINSTALL)
list='$(sbin_PROGRAMS)'; for p in $$list; do \
rm -f $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
done
.c.o:
$(COMPILE) -c $<
.s.o:
$(COMPILE) -c $<
.S.o:
$(COMPILE) -c $<
mostlyclean-compile:
-rm -f *.o core *.core
clean-compile:
distclean-compile:
-rm -f *.tab.c
maintainer-clean-compile:
reiserfsck: $(reiserfsck_OBJECTS) $(reiserfsck_DEPENDENCIES)
@rm -f reiserfsck
$(LINK) $(reiserfsck_LDFLAGS) $(reiserfsck_OBJECTS) $(reiserfsck_LDADD) $(LIBS)
install-man8:
$(mkinstalldirs) $(DESTDIR)$(man8dir)
@list='$(man8_MANS)'; \
l2='$(man_MANS)'; for i in $$l2; do \
case "$$i" in \
*.8*) list="$$list $$i" ;; \
esac; \
done; \
for i in $$list; do \
if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
else file=$$i; fi; \
ext=`echo $$i | sed -e 's/^.*\\.//'`; \
inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
inst=`echo $$inst | sed '$(transform)'`.$$ext; \
echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst"; \
$(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst; \
done
uninstall-man8:
@list='$(man8_MANS)'; \
l2='$(man_MANS)'; for i in $$l2; do \
case "$$i" in \
*.8*) list="$$list $$i" ;; \
esac; \
done; \
for i in $$list; do \
ext=`echo $$i | sed -e 's/^.*\\.//'`; \
inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
inst=`echo $$inst | sed '$(transform)'`.$$ext; \
echo " rm -f $(DESTDIR)$(man8dir)/$$inst"; \
rm -f $(DESTDIR)$(man8dir)/$$inst; \
done
install-man: $(MANS)
@$(NORMAL_INSTALL)
$(MAKE) $(AM_MAKEFLAGS) install-man8
uninstall-man:
@$(NORMAL_UNINSTALL)
$(MAKE) $(AM_MAKEFLAGS) uninstall-man8
tags: TAGS
ID: $(HEADERS) $(SOURCES) $(LISP)
list='$(SOURCES) $(HEADERS)'; \
unique=`for i in $$list; do echo $$i; done | \
awk ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
here=`pwd` && cd $(srcdir) \
&& mkid -f$$here/ID $$unique $(LISP)
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
tags=; \
here=`pwd`; \
list='$(SOURCES) $(HEADERS)'; \
unique=`for i in $$list; do echo $$i; done | \
awk ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
|| (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
mostlyclean-tags:
clean-tags:
distclean-tags:
-rm -f TAGS ID
maintainer-clean-tags:
distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
subdir = fsck
distdir: $(DISTFILES)
@for file in $(DISTFILES); do \
d=$(srcdir); \
if test -d $$d/$$file; then \
cp -pr $$/$$file $(distdir)/$$file; \
else \
test -f $(distdir)/$$file \
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \
|| cp -p $$d/$$file $(distdir)/$$file || :; \
fi; \
done
check.o: check.c fsck.h ../include/io.h ../include/misc.h \
../include/reiserfs_lib.h ../include/reiserfs_fs.h
check_tree.o: check_tree.c fsck.h ../include/io.h ../include/misc.h \
../include/reiserfs_lib.h ../include/reiserfs_fs.h
info.o: info.c fsck.h ../include/io.h ../include/misc.h \
../include/reiserfs_lib.h ../include/reiserfs_fs.h
journal.o: journal.c fsck.h ../include/io.h ../include/misc.h \
../include/reiserfs_lib.h ../include/reiserfs_fs.h
lost+found.o: lost+found.c fsck.h ../include/io.h ../include/misc.h \
../include/reiserfs_lib.h ../include/reiserfs_fs.h
main.o: main.c fsck.h ../include/io.h ../include/misc.h \
../include/reiserfs_lib.h ../include/reiserfs_fs.h ../version.h
pass0.o: pass0.c fsck.h ../include/io.h ../include/misc.h \
../include/reiserfs_lib.h ../include/reiserfs_fs.h
pass1.o: pass1.c fsck.h ../include/io.h ../include/misc.h \
../include/reiserfs_lib.h ../include/reiserfs_fs.h
pass2.o: pass2.c fsck.h ../include/io.h ../include/misc.h \
../include/reiserfs_lib.h ../include/reiserfs_fs.h
pass4.o: pass4.c fsck.h ../include/io.h ../include/misc.h \
../include/reiserfs_lib.h ../include/reiserfs_fs.h
segments.o: segments.c fsck.h ../include/io.h ../include/misc.h \
../include/reiserfs_lib.h ../include/reiserfs_fs.h
semantic.o: semantic.c fsck.h ../include/io.h ../include/misc.h \
../include/reiserfs_lib.h ../include/reiserfs_fs.h
ubitmap.o: ubitmap.c fsck.h ../include/io.h ../include/misc.h \
../include/reiserfs_lib.h ../include/reiserfs_fs.h
ufile.o: ufile.c fsck.h ../include/io.h ../include/misc.h \
../include/reiserfs_lib.h ../include/reiserfs_fs.h
uobjectid.o: uobjectid.c fsck.h ../include/io.h ../include/misc.h \
../include/reiserfs_lib.h ../include/reiserfs_fs.h
ustree.o: ustree.c fsck.h ../include/io.h ../include/misc.h \
../include/reiserfs_lib.h ../include/reiserfs_fs.h
info-am:
info: info-am
dvi-am:
dvi: dvi-am
check-am: all-am
check: check-am
installcheck-am:
installcheck: installcheck-am
install-exec-am: install-sbinPROGRAMS
install-exec: install-exec-am
install-data-am: install-man
install-data: install-data-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
install: install-am
uninstall-am: uninstall-sbinPROGRAMS uninstall-man
uninstall: uninstall-am
all-am: Makefile $(PROGRAMS) $(MANS)
all-redirect: all-am
install-strip:
$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
installdirs:
$(mkinstalldirs) $(DESTDIR)$(sbindir) $(DESTDIR)$(mandir)/man8
mostlyclean-generic:
clean-generic:
distclean-generic:
-rm -f Makefile $(CONFIG_CLEAN_FILES)
-rm -f config.cache config.log stamp-h stamp-h[0-9]*
maintainer-clean-generic:
mostlyclean-am: mostlyclean-sbinPROGRAMS mostlyclean-compile \
mostlyclean-tags mostlyclean-generic
mostlyclean: mostlyclean-am
clean-am: clean-sbinPROGRAMS clean-compile clean-tags clean-generic \
mostlyclean-am
clean: clean-am
distclean-am: distclean-sbinPROGRAMS distclean-compile distclean-tags \
distclean-generic clean-am
distclean: distclean-am
maintainer-clean-am: maintainer-clean-sbinPROGRAMS \
maintainer-clean-compile maintainer-clean-tags \
maintainer-clean-generic distclean-am
@echo "This command is intended for maintainers to use;"
@echo "it deletes files that may require special tools to rebuild."
maintainer-clean: maintainer-clean-am
.PHONY: mostlyclean-sbinPROGRAMS distclean-sbinPROGRAMS \
clean-sbinPROGRAMS maintainer-clean-sbinPROGRAMS uninstall-sbinPROGRAMS \
install-sbinPROGRAMS mostlyclean-compile distclean-compile \
clean-compile maintainer-clean-compile install-man8 uninstall-man8 \
install-man uninstall-man tags mostlyclean-tags distclean-tags \
clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \
check-am installcheck-am installcheck install-exec-am install-exec \
install-data-am install-data install-am install uninstall-am uninstall \
all-redirect all-am all installdirs mostlyclean-generic \
distclean-generic clean-generic maintainer-clean-generic clean \
mostlyclean distclean maintainer-clean
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
+329
View File
@@ -0,0 +1,329 @@
/*
* Copyright 1996, 1997 Hans Reiser
*/
#include "fsck.h"
/* this goes through buffers checking delimiting keys
*/
struct buffer_head * g_left = 0;
struct buffer_head * g_right = 0;
struct key * g_dkey = 0;
static void check_directory_item (struct item_head * ih, struct buffer_head * bh)
{
int i;
struct reiserfs_de_head * deh;
for (i = 0, deh = B_I_DEH (bh, ih); i < ih_entry_count (ih) - 1; i ++)
if (deh_offset(&deh[i]) > deh_offset(&deh[i + 1]))
die ("check_directory_item: entries are not sorted properly");
}
static void check_items (struct buffer_head * bh)
{
int i;
struct item_head * ih;
for (i = 0; i < B_NR_ITEMS (bh); i++)
{
ih = B_N_PITEM_HEAD (bh, i);
if (is_direntry_ih (ih))
check_directory_item (ih, bh);
}
}
static void compare_neighboring_leaves_in_pass1 (void)
{
struct key * left = B_N_PKEY (g_left, B_NR_ITEMS (g_left) - 1);
if (comp_keys (left, B_N_PKEY (g_right, 0)) != -1/*SECOND_GREATER*/)
die ("compare_neighboring_leaves_in_pass1: left key is greater, that the right one");
if (/*comp_keys (B_PRIGHT_DELIM_KEY (g_left), g_dkey) == FIRST_GREATER ||*/
comp_keys (g_dkey, B_N_PKEY (g_right, 0))) {
reiserfs_panic (0, "compare_neighboring_leaves_in_pass1: dkey %k, first key in right %k",
g_dkey, B_N_PKEY (g_right, 0));
}
check_items (g_left);
/*&&&&&&&&&&&&&&&&&&&&&&&&&&
for (i = 0, ih = B_N_PITEM_HEAD (g_left, i); i < B_NR_ITEMS (g_left); i ++, ih ++)
if (is_item_accessed (ih) == YES)
die ("compare_neighboring_leaves_in_pass1: item marked as accessed in g_left");
for (i = 0, ih = B_N_PITEM_HEAD (g_right, i); i < B_NR_ITEMS (g_right); i ++, ih ++)
if (is_item_accessed (ih) == YES)
die ("compare_neighboring_leaves_in_pass1: item marked as accessed in g_right");
&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
}
static void is_there_unaccessed_items (struct buffer_head * bh)
{
int i;
struct item_head * ih;
ih = B_N_PITEM_HEAD (bh, 0);
for (i = 0; i < B_NR_ITEMS (bh); i ++, ih ++) {
if (is_objectid_used (fs, ih->ih_key.k_objectid) == 0)
die ("is_there_unaccessed_items: %lu is not marked as used", ih->ih_key.k_objectid);
if (!is_item_reachable (ih)) {
die ("is_there_unaccessed_items: block %lu - unaccessed item found",
bh->b_blocknr);
}
}
}
static void compare_neighboring_leaves_after_all (void)
{
struct item_head * left = B_N_PITEM_HEAD(g_left, B_NR_ITEMS (g_left) - 1);
struct item_head * right = B_N_PITEM_HEAD(g_right, 0);
/* struct key * left = B_N_PKEY (g_left, B_NR_ITEMS (g_left) - 1);
struct key * right = B_N_PKEY (g_right, 0);*/
/*
if (comp_keys (&left->ih_key, B_PRIGHT_DELIM_KEY (g_left)) != SECOND_GREATER)
die ("compare_neighboring_leaves_after_all: invalid right delimiting key");
*/
if (comp_keys (&left->ih_key, B_N_PKEY (g_right, 0)) != -1/*SECOND_GREATER*/)
die ("compare_neighboring_leaves_after_all: left key is greater than the right one");
if (//comp_le_keys (B_PRIGHT_DELIM_KEY (g_left), g_dkey) != KEYS_IDENTICAL ||
comp_keys (g_dkey, B_N_PKEY (g_right, 0))) {
reiserfs_panic (0, "compare_neighboring_leaves_after all: invalid delimiting keys from left to right (%k %k)",
g_dkey, B_N_PKEY (g_right, 0));
}
if (!not_of_one_file (&left->ih_key, &right->ih_key)) {
// items of one file: check offset correctness
if (is_direct_ih (left) || is_indirect_ih (left))
//if (get_offset(&right->ih_key) != get_offset(&left->ih_key) + get_bytes_number (g_left, left /*B_NR_ITEMS (g_left) - 1*/, 0, CHECK_FREE_BYTES))
if (get_offset(&right->ih_key) != get_offset(&left->ih_key) + get_bytes_number (left, g_left->b_size))
die ("compare_neighboring_leaves_after all: hole between items or items are overlapped");
}
is_there_unaccessed_items (g_left);
}
typedef void (check_function_t)(void);
/* only directory item can be fatally bad */
static int is_leaf_bad_xx (struct buffer_head * bh)
{
int i;
struct item_head * ih;
if (!is_leaf_node (bh))
return 0;
for (i = 0, ih = B_N_PITEM_HEAD (bh, 0); i < B_NR_ITEMS (bh); i ++, ih ++)
if (is_bad_item (bh, ih, B_I_PITEM (bh, ih))) {
return 1;
}
return 0;
}
static void reiserfsck_check_tree (int dev, int block, int size, check_function_t comp_func)
{
struct buffer_head * bh;
int what_node;
bh = bread (dev, block, size);
if (bh == 0)
reiserfs_panic("reiserfsck_check_tree: unable to read %lu block on device 0x%x\n",
block, dev);
if (!B_IS_IN_TREE (bh)) {
reiserfs_panic (0, "reiserfsck_check_tree: buffer (%b %z) not in tree", bh, bh);
}
what_node = who_is_this (bh->b_data, bh->b_size);
if (what_node != THE_LEAF && what_node != THE_INTERNAL)
die ("Not formatted node");
if (!is_block_used (bh->b_blocknr))
die ("Not marked as used");
if (is_leaf_node (bh) && is_leaf_bad_xx (bh))
die ("Bad leaf");
if (is_internal_node(bh) && is_internal_bad (bh))
die ("bad internal");
if (is_internal_node (bh)) {
int i;
struct disk_child * dc;
dc = B_N_CHILD (bh, 0);
for (i = 0; i <= B_NR_ITEMS (bh); i ++, dc ++) {
reiserfsck_check_tree (dev, dc->dc_block_number, size, comp_func);
g_dkey = B_N_PDELIM_KEY (bh, i);
}
} else if (is_leaf_node (bh)) {
g_right = bh;
if (g_left != 0 && g_dkey != 0) {
comp_func ();
brelse (g_left);
}
g_left = g_right;
return;
} else {
reiserfs_panic ("reiserfsck_check_tree: block %lu has bad block type (%b)",
bh->b_blocknr, bh);
}
brelse (bh);
}
static void reiserfsck_check_cached_tree (int dev, int block, int size)
{
struct buffer_head * bh;
int what_node;
bh = find_buffer(dev, block, size);
if (bh == 0)
return;
if (!buffer_uptodate (bh)) {
die ("reiserfsck_check_cached_tree: found notuptodate buffer");
}
bh->b_count ++;
if (!B_IS_IN_TREE (bh)) {
die ("reiserfsck_check_cached_tree: buffer (%b %z) not in tree", bh, bh);
}
what_node = who_is_this (bh->b_data, bh->b_size);
if ((what_node != THE_LEAF && what_node != THE_INTERNAL) ||
!is_block_used (bh->b_blocknr) ||
(is_leaf_node (bh) && is_leaf_bad (bh)) ||
(is_internal_node(bh) && is_internal_bad (bh)))
die ("reiserfsck_check_cached_tree: bad node in the tree");
if (is_internal_node (bh)) {
int i;
struct disk_child * dc;
dc = B_N_CHILD (bh, 0);
for (i = 0; i <= B_NR_ITEMS (bh); i ++, dc ++) {
reiserfsck_check_cached_tree (dev, dc->dc_block_number, size);
g_dkey = B_N_PDELIM_KEY (bh, i);
}
} else if (is_leaf_node (bh)) {
brelse (bh);
return;
} else {
reiserfs_panic ("reiserfsck_check_cached_tree: block %lu has bad block type (%b)",
bh->b_blocknr, bh);
}
brelse (bh);
}
void reiserfsck_tree_check (check_function_t how_to_compare_neighbors)
{
g_left = 0;
g_dkey = 0;
reiserfsck_check_tree (fs->s_dev, SB_ROOT_BLOCK(fs), fs->s_blocksize, how_to_compare_neighbors);
brelse (g_right);
}
void reiserfsck_check_pass1 ()
{
/* if (opt_check == 1)*/
reiserfsck_tree_check (compare_neighboring_leaves_in_pass1);
}
void check_cached_tree ()
{
reiserfsck_check_cached_tree (fs->s_dev, SB_ROOT_BLOCK (fs), fs->s_blocksize);
}
void reiserfsck_check_after_all ()
{
reiserfsck_tree_check (compare_neighboring_leaves_after_all);
}
#if 0
static int is_bad_sd (struct item_head * ih, char * item)
{
struct stat_data * sd = (struct stat_data *)item;
if (!S_ISDIR (sd->sd_mode) && !S_ISREG(sd->sd_mode) &&
!S_ISCHR (sd->sd_mode) && !S_ISBLK(sd->sd_mode) &&
!S_ISLNK (sd->sd_mode) && !S_ISFIFO(sd->sd_mode) &&
!S_ISSOCK(sd->sd_mode)) {
fsck_log ("file %k unexpected mode encountered 0%o\n", &ih->ih_key, sd->sd_mode);
}
return 0;
}
#endif
#include <sys/ioctl.h>
#include <sys/mount.h>
int blocks_on_device (int dev, int blocksize)
{
int size;
if (ioctl (dev, BLKGETSIZE, &size) >= 0) {
return size / (blocksize / 512);
}
if (ioctl (dev, BLKGETSIZE, &size) >= 0) {
return size / (blocksize / 512);
} else {
struct stat stat_buf;
memset(&stat_buf, '\0', sizeof(struct stat));
if(fstat(dev, &stat_buf) >= 0) {
return stat_buf.st_size / (blocksize / 512);
} else {
die ("can not calculate device size\n");
}
}
return 0;
}
int is_internal_bad (struct buffer_head * bh)
{
struct key * key;
int i;
if (!is_internal_node(bh))
return 0;
for (i = 0; i < B_NR_ITEMS (bh); i ++) {
key = B_N_PDELIM_KEY (bh, i);
if (//key->k_dir_id >= key->k_objectid ||
key->u.k_offset_v1.k_uniqueness != V1_DIRENTRY_UNIQUENESS && key->u.k_offset_v1.k_uniqueness != V1_DIRECT_UNIQUENESS &&
key->u.k_offset_v1.k_uniqueness != V1_INDIRECT_UNIQUENESS && key->u.k_offset_v1.k_uniqueness != V1_SD_UNIQUENESS &&
key->u.k_offset_v2.k_type != TYPE_DIRENTRY && key->u.k_offset_v2.k_type != TYPE_DIRECT &&
key->u.k_offset_v2.k_type != TYPE_INDIRECT && key->u.k_offset_v2.k_type != TYPE_STAT_DATA //&&
// key->u.k_offset_v1.k_uniqueness != V1_ANY_UNIQUENESS && key->u.k_offset_v2.k_type != TYPE_ANY
)
return 1;
}
return 0;
}
+915
View File
@@ -0,0 +1,915 @@
/*
* Copyright 1999 Hans Reiser
*/
#include "fsck.h"
//
//
// check S+ tree of the file system
//
// check_fs_tree stops and recommends to run fsck --rebuild-tree when:
// 1. read fails
// 2. node of wrong level found in the tree
// 3. something in the tree points to wrong block number
// out of filesystem boundary is pointed by tree
// to block marked as free in bitmap
// the same block is pointed from more than one place
// not data blocks (journal area, super block, bitmaps)
// 4. bad formatted node found
// 5. delimiting keys are incorrect
//
/* mark every block we see in the tree in control bitmap, so, when to make
sure, that no blocks are pointed to from more than one place we use
additional bitmap (control_bitmap). If we see pointer to a block we set
corresponding bit to 1. If it is set already - run fsck with --rebuild-tree */
static reiserfs_bitmap_t control_bitmap;
static int tree_scanning_failed = 0;
/* 1 if block is not marked as used in the bitmap */
static int is_block_free (reiserfs_filsys_t fs, unsigned long block)
{
return !reiserfs_bitmap_test_bit (fsck_disk_bitmap (fs), block);
}
/* we have seen this block in the tree, mark corresponding bit in the
control bitmap */
static void we_met_it (unsigned long block)
{
reiserfs_bitmap_set_bit (control_bitmap, block);
}
/* have we seen this block somewhere in the tree before? */
static int did_we_meet_it (unsigned long block)
{
return reiserfs_bitmap_test_bit (control_bitmap, block);
}
static void init_control_bitmap (reiserfs_filsys_t fs)
{
int i;
control_bitmap = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs));
if (!control_bitmap)
die ("init_control_bitmap: could not create control bitmap");
/* skipped and super block */
for (i = 0; i <= SB_BUFFER_WITH_SB (fs)->b_blocknr; i ++)
we_met_it (i);
/* bitmaps */
for (i = 0; i < SB_BMAP_NR (fs); i ++)
we_met_it (SB_AP_BITMAP (fs)[i]->b_blocknr);
for (i = 0; i < rs_journal_size (fs->s_rs) + 1; i ++)
we_met_it (i + SB_JOURNAL_BLOCK (fs));
}
#if 0
static void show_diff (int n, char * disk, char * control, int bits)
{
int i;
int last_diff = 0;
int from, num;
fsck_log ("bitmap %d does not match to the correct one\n", n);
from = 0;
num = 0;
for (i = 0; i < bits; i ++) {
if (test_bit (i, disk) && !test_bit (i, control)) {
if (last_diff == 1) {
num ++;
continue;
} else if (last_diff == 2) {
fsck_log ("Block [%d-%d] free in disk bitmap, used in control\n", from, from + num - 1);
}
num = 1;
from = n * bits + i;
last_diff = 1;
continue;
}
if (!test_bit (i, disk) && test_bit (i, control)) {
if (last_diff == 2) {
num ++;
continue;
} else if (last_diff == 1) {
fsck_log ("Block [%d-%d] used in disk bitmap, free in control\n", from, from + num - 1);
}
num = 1;
from = n * bits + i;
last_diff = 2;
continue;
}
/* the same bits */
if (last_diff == 1)
fsck_log ("Block [%d-%d] used in disk bitmap, free in control\n", from, from + num - 1);
if (last_diff == 2)
fsck_log ("Block [%d-%d] free in disk bitmap, used in control\n", from, from + num - 1);
num = 0;
from = 0;
last_diff = 0;
continue;
}
}
#endif
/* if we managed to complete tree scanning and if control bitmap and/or proper
amount of free blocks mismatch with bitmap on disk and super block's
s_free_blocks - we can fix that */
static void compare_bitmaps (reiserfs_filsys_t fs)
{
int diff;
if (tree_scanning_failed) {
fsck_progress ("Could not scan whole tree. "
"--rebuild-tree is required\n");
return;
}
fsck_progress ("Comparing bitmaps..");
/* check free block counter */
if (SB_FREE_BLOCKS (fs) != reiserfs_bitmap_zeros (control_bitmap)) {
fsck_log ("free block count %lu mismatches with a correct one %lu. \n",
SB_FREE_BLOCKS (fs), reiserfs_bitmap_zeros (control_bitmap));
#if 0
if (fsck_fix_fixable (fs)) {
set_free_blocks (fs->s_rs, reiserfs_bitmap_zeros (control_bitmap));
mark_buffer_dirty (fs->s_sbh);
mark_filesystem_dirty (fs);
fsck_log ("Fixed\n");
} else {
fsck_log ("Can be fixed by --fix-fixable\n");
}
#endif
}
diff = reiserfs_bitmap_compare (fsck_disk_bitmap (fs), control_bitmap);
if (diff) {
fsck_log ("on-disk bitmap does not match to the correct one. %d bytes differ\n", diff);
#if 0
if (fsck_fix_fixable (fs)) {
reiserfs_flush_bitmap (control_bitmap, fs);
mark_filesystem_dirty (fs);
fsck_log ("Fixed\n");
} else {
fsck_log ("Can be fixed by --fix-fixable\n");
}
#endif
}
fsck_progress ("ok\n");
return;
}
/* is this block legal to be pointed to by some place of the tree? */
static int bad_block_number (struct super_block * s, unsigned long block)
{
if (block >= SB_BLOCK_COUNT (s)) {
/*reiserfs_warning ("block out of filesystem boundary found\n");*/
return 1;
}
if (not_data_block (s, block)) {
/*reiserfs_warning ("not data block (%lu) is used in the tree\n",
block);*/
return 1;
}
if (is_block_free (s, block)) {
fsck_log ("block %lu is not marked as used in the disk bitmap\n", block);
return 0;
}
return 0;
}
static int got_already (struct super_block * s, unsigned long block)
{
if (0/*opt_fsck_mode == FSCK_FAST_REBUILD*/){
if (is_block_used(block)){
fsck_log ("block %lu is in tree already\n", block);
return 1;
}
} else {
if (did_we_meet_it (block)) {
/*fsck_log ("block %lu is in tree already\n", block);*/
return 1;
}
we_met_it (block);
}
return 0;
}
/* 1 if some of fields in the block head of bh look bad */
static int bad_block_head (struct buffer_head * bh)
{
struct block_head * blkh;
blkh = B_BLK_HEAD (bh);
if (le16_to_cpu (blkh->blk_nr_item) > (bh->b_size - BLKH_SIZE) / IH_SIZE) {
fsck_log ("block %lu has wrong blk_nr_items (%z)\n",
bh->b_blocknr, bh);
return 1;
}
if (le16_to_cpu (blkh->blk_free_space) >
bh->b_size - BLKH_SIZE - IH_SIZE * le16_to_cpu (blkh->blk_nr_item)) {
fsck_log ("block %lu has wrong blk_free_space %z\n",
bh->b_blocknr, bh);
return 1;
}
return 0;
}
/* 1 if it does not look like reasonable stat data */
static int bad_stat_data (struct buffer_head * bh, struct item_head * ih)
{
unsigned long objectid;
int pos;
/*
if (opt_fsck_mode == FSCK_FAST_REBUILD)
return 0;
*/
objectid = le32_to_cpu (ih->ih_key.k_objectid);
if (!is_objectid_used (fs, objectid)) {
/* FIXME: this could be cured right here */
fsck_log ("\nbad_stat_data: %lu is marked free, but used by an object %k\n",
objectid, &ih->ih_key);
}
if (is_objectid_really_used (proper_id_map (fs), objectid, &pos)) {
fsck_log ("\nbad_stat_data: %lu is shared by at least two files\n",
objectid);
return 0;
}
mark_objectid_really_used (proper_id_map (fs), objectid);
return 0;
}
/* it looks like we can check item length only */
static int bad_direct_item (struct buffer_head * bh, struct item_head * ih)
{
return 0;
}
/* for each unformatted node pointer: make sure it points to data area and
that it is not in the tree yet */
static int bad_indirect_item (reiserfs_filsys_t fs, struct buffer_head * bh,
struct item_head * ih)
{
int i;
__u32 * ind = (__u32 *)B_I_PITEM (bh, ih);
if (ih_item_len (ih) % 4) {
fsck_log ("bad_indirect_item: block %lu: item (%H) has bad length\n",
bh->b_blocknr, ih);
return 1;
}
for (i = 0; i < I_UNFM_NUM (ih); i ++) {
__u32 unfm_ptr;
unfm_ptr = le32_to_cpu (ind [i]);
if (!unfm_ptr)
continue;
/* check unformatted node pointer and mark it used in the
control bitmap */
if (bad_block_number (fs, unfm_ptr)) {
fsck_log ("bad_indirect_item: block %lu: item %H has bad pointer %d: %lu",
bh->b_blocknr, ih, i, unfm_ptr);
if (fsck_fix_fixable (fs)) {
fsck_log (" - fixed");
ind [i] = 0;
mark_buffer_dirty (bh);
}
fsck_log ("\n");
continue;
}
if (got_already (fs, unfm_ptr)) {
fsck_log ("bad_indirect_item: block %lu: item %H has a pointer %d "
"to the block %lu which is in tree already",
bh->b_blocknr, ih, i, unfm_ptr);
if (fsck_fix_fixable (fs)) {
fsck_log (" - fixed");
ind [i] = 0;
mark_buffer_dirty (bh);
}
fsck_log ("\n");
continue;
}
}
/* delete this check for 3.6 */
if (ih_free_space (ih) > fs->s_blocksize - 1)
fsck_log ("bad_indirect_item: %H has wrong ih_free_space\n", ih);
return 0;
}
/* FIXME: this was is_bad_directory from pass0.c */
static int bad_directory_item (struct buffer_head * bh, struct item_head * ih)
{
int i;
char * name;
int namelen;
struct reiserfs_de_head * deh = B_I_DEH (bh, ih);
int min_entry_size = 1;/* we have no way to understand whether the
filesystem were created in 3.6 format or
converted to it. So, we assume that minimal name
length is 1 */
__u16 state;
/* make sure item looks like a directory */
if (ih_item_len (ih) / (DEH_SIZE + min_entry_size) < ih_entry_count (ih))
/* entry count can not be that big */
return 1;
if (deh[ih_entry_count (ih) - 1].deh_location != DEH_SIZE * ih_entry_count (ih))
/* last entry should start right after array of dir entry headers */
return 1;
/* check name hashing */
for (i = 0; i < ih_entry_count (ih); i ++, deh ++) {
namelen = name_length (ih, deh, i);
name = name_in_entry (deh, i);
if (!is_properly_hashed (fs, name, namelen, deh_offset (deh))) {
return 1;
}
}
deh = B_I_DEH (bh, ih);
state = 0;
set_bit (DEH_Visible, &state);
/* ok, items looks like a directory */
for (i = 0; i < ih_entry_count (ih); i ++, deh ++) {
if (deh_state (deh) != state) {
fsck_log ("bad_directory_item: block %lu: item %H has entry "
"\"%.*s\" with wrong deh_state %o",
bh->b_blocknr, ih, name_length (ih, deh, i),
name_in_entry (deh, i), deh_state (deh));
if (fsck_fix_fixable (fs)) {
deh->deh_state = 0;
mark_de_visible (deh);
mark_buffer_dirty (bh);
fsck_log (" - fixed");
}
fsck_log ("\n");
}
}
return 0;
}
static int bad_item (struct super_block * s, struct buffer_head * bh, int i)
{
struct item_head * ih;
ih = B_N_PITEM_HEAD (bh, i);
if (is_stat_data_ih (ih))
return bad_stat_data (bh, ih);
if (is_direct_ih (ih))
return bad_direct_item (bh, ih);
if (is_indirect_ih(ih))
return bad_indirect_item (s, bh, ih);
return bad_directory_item (bh, ih);
}
/* 1 if i-th and (i-1)-th items can not be neighbors in a leaf */
int bad_pair (struct super_block * s, struct buffer_head * bh, int i)
{
struct item_head * ih;
ih = B_N_PITEM_HEAD (bh, i);
if (comp_keys (&((ih - 1)->ih_key), &ih->ih_key) != -1)
return 1;
if (is_stat_data_ih (ih))
/* left item must be of another object */
if (comp_short_keys (&((ih - 1)->ih_key), &ih->ih_key) != -1)
return 1;
if (is_direct_ih(ih)) {
/* left item must be indirect or stat data item of the same
file */
if (not_of_one_file (&((ih - 1)->ih_key), &ih->ih_key))
return 1;
if (!((is_stat_data_ih (ih - 1) && get_offset (&ih->ih_key) == 1) ||
(is_indirect_ih (ih - 1) &&
get_offset (&(ih - 1)->ih_key) + get_bytes_number (ih-1, bh->b_size) == //get_bytes_number (bh, ih - 1, 0, CHECK_FREE_BYTES) ==
get_offset (&ih->ih_key))))
return 1;
}
if (is_indirect_ih (ih) || is_direntry_ih (ih)) {
/* left item must be stat data of the same object */
if (not_of_one_file (&((ih - 1)->ih_key), &ih->ih_key))
return 1;
if (!is_stat_data_ih (ih - 1))
return 1;
}
return 0;
}
int bad_leaf_2 (struct super_block * s, struct buffer_head * bh)
{
int i;
if (bad_block_head (bh))
return 1;
for (i = 0; i < B_NR_ITEMS (bh); i ++) {
if (i && bad_pair (s, bh, i)) {
fsck_log ("bad_leaf_2: block %lu has wrong order of items\n",
bh->b_blocknr);
return 1;
}
}
return 0;
}
/* 1 if block head or any of items is bad */
static int bad_leaf (struct super_block * s, struct buffer_head * bh)
{
int i;
if (bad_block_head (bh))
return 1;
for (i = 0; i < B_NR_ITEMS (bh); i ++) {
if (bad_item (s, bh, i)) {
fsck_log ("bad_leaf: block %lu has invalid item %d: %H\n",
bh->b_blocknr, i, B_N_PITEM_HEAD (bh, i));
}
if (i && bad_pair (s, bh, i)) {
fsck_log ("bad_leaf: block %lu has wrong order of items\n",
bh->b_blocknr);
}
}
return 0;
}
/* 1 if bh does not look like internal node */
static int bad_internal (struct super_block * s, struct buffer_head * bh)
{
int i;
for (i = 0; i <= B_NR_ITEMS (bh); i ++)
{
if (i != B_NR_ITEMS (bh) && i != B_NR_ITEMS (bh) - 1)
if (comp_keys (B_N_PDELIM_KEY (bh, i), B_N_PDELIM_KEY (bh, i + 1)) != -1)
return 1;
if (bad_block_number(s, child_block_number(bh,i))){
return 1;
}
}
return 0;
}
/* h == 0 for root level. block head's level == 1 for leaf level */
static inline int h_to_level (struct super_block * s, int h)
{
return SB_TREE_HEIGHT (s) - h - 1;
}
/* bh must be formatted node. blk_level must be tree_height - h + 1 */
static int bad_node (struct super_block * s, struct buffer_head ** path,
int h)
{
struct buffer_head ** pbh = &path[h];
if (B_LEVEL (*pbh) != h_to_level (s, h)) {
fsck_log ("node (%lu) with wrong level (%d) found in the tree (should be %d)\n",
(*pbh)->b_blocknr, B_LEVEL (*pbh), h_to_level (s, h));
return 1;
}
if (bad_block_number (s, (*pbh)->b_blocknr)) {
return 1;
}
if (got_already (s, (*pbh)->b_blocknr))
return 1;
if (is_leaf_node (*pbh))
return bad_leaf (s, *pbh);
return bad_internal (s, *pbh);
}
/* internal node bh must point to block */
static int get_pos (struct buffer_head * bh, unsigned long block)
{
int i;
for (i = 0; i <= B_NR_ITEMS (bh); i ++) {
if (child_block_number (bh, i) == block)
return i;
}
die ("get_pos: position for block %lu not found", block);
return 0;
}
/* path[h] - leaf node */
static struct key * lkey (struct buffer_head ** path, int h)
{
int pos;
while (h > 0) {
pos = get_pos (path[h - 1], path[h]->b_blocknr);
if (pos)
return B_N_PDELIM_KEY(path[h - 1], pos - 1);
h --;
}
return 0;
}
/* path[h] - leaf node */
static struct key * rkey (struct buffer_head ** path, int h)
{
int pos;
while (h > 0) {
pos = get_pos (path[h - 1], path[h]->b_blocknr);
if (pos != B_NR_ITEMS (path[h - 1]))
return B_N_PDELIM_KEY (path[h - 1], pos);
h --;
}
return 0;
}
/* are all delimiting keys correct */
static int bad_path (struct super_block * s, struct buffer_head ** path, int h1)
{
int h = 0;
struct key * dk;
while (path[h])
h ++;
h--;
// path[h] is leaf
if (h != h1)
die ("bad_path: wrong path");
dk = lkey (path, h);
if (dk && comp_keys (dk, B_N_PKEY (path[h], 0)))
// left delimiting key must be equal to the key of 0-th item in the
// node
return 1;
dk = rkey (path, h);
if (dk && comp_keys (dk, B_N_PKEY (path[h], node_item_number (path[h]) - 1)) != 1)
// right delimiting key must be bigger than the key of the last item
// in the node
return 1;
return 0;
}
/* pass the S+ tree of filesystem */
void check_fs_tree (struct super_block * s)
{
init_control_bitmap (s);
proper_id_map (s) = init_id_map ();
fsck_progress ("Checking S+tree..");
pass_through_tree (s, bad_node, bad_path);
/* S+ tree is correct (including all objects have correct
sequences of items) */
fsck_progress ("ok\n");
/* compare created bitmap with the original */
compare_bitmaps (s);
free_id_map (&proper_id_map (s));
}
#if 0
void remove_internal_pointer(struct super_block * s, struct buffer_head ** path)
{
int h = 0;
int pos, items;
__u32 block;
while (path[h])
h ++;
h--;
block = path[h]->b_blocknr;
printf("\nremove pointer to (%d) block", block);
brelse(path[h]);
path[h] = 0;
h--;
while (h>=0)
{
if (B_NR_ITEMS(path[h]) <= 1)
{
block = path[h]->b_blocknr;
brelse(path[h]);
path[h] = 0;
mark_block_free(block);
/*unmark_block_formatted(block);*/
used_blocks++;
h --;
continue;
}
pos = get_pos (path[h], block);
if (pos)
{
memmove (B_N_CHILD(path[h],pos), B_N_CHILD(path[h],pos+1),
s->s_blocksize - BLKH_SIZE - B_NR_ITEMS(path[h])*KEY_SIZE - DC_SIZE*(pos+1));
memmove(B_N_PDELIM_KEY(path[h],pos-1), B_N_PDELIM_KEY(path[h],pos),
s->s_blocksize - BLKH_SIZE - (pos)*KEY_SIZE);
}else{
__u32 move_block = path[h]->b_blocknr;
int move_to_pos;
int height = h;
while(--height >= 0)
{
move_to_pos = get_pos (path[height], move_block);
if (move_to_pos == 0){
move_block = path[height]->b_blocknr;
continue;
}
*B_N_PDELIM_KEY(path[height], move_to_pos-1) = *B_N_PDELIM_KEY(path[h], 0);
break;
}
memmove (B_N_CHILD(path[h], 0), B_N_CHILD(path[h], 1),
s->s_blocksize - BLKH_SIZE - B_NR_ITEMS(path[h])*KEY_SIZE - DC_SIZE);
memmove(B_N_PDELIM_KEY(path[h], 0), B_N_PDELIM_KEY(path[h], 1),
s->s_blocksize - BLKH_SIZE - KEY_SIZE);
}
set_node_item_number(path[h], node_item_number(path[h]) - 1);
mark_buffer_dirty(path[h], 1);
break;
}
if (h == -1)
{
SB_DISK_SUPER_BLOCK(s)->s_root_block = ~0;
SB_DISK_SUPER_BLOCK(s)->s_tree_height = ~0;
mark_buffer_dirty(SB_BUFFER_WITH_SB(s), 1);
}
}
void handle_buffer(struct super_block * s, struct buffer_head * bh)
{
int i, j;
struct item_head * ih;
if (is_leaf_node (bh))
{
for (i = 0, ih = B_N_PITEM_HEAD (bh, 0); i < B_NR_ITEMS (bh); i ++, ih ++)
{
if (is_indirect_ih(ih))
for (j = 0; j < I_UNFM_NUM (ih); j ++)
if (B_I_POS_UNFM_POINTER(bh,ih,j)){
/*mark_block_unformatted(le32_to_cpu(B_I_POS_UNFM_POINTER(bh,ih,j)));*/
mark_block_used(le32_to_cpu(B_I_POS_UNFM_POINTER(bh,ih,j)));
used_blocks++;
}
if (is_stat_data_ih (ih)) {
/*add_event (STAT_DATA_ITEMS);*/
if (ih_key_format(ih) == KEY_FORMAT_1)
((struct stat_data_v1 *)B_I_PITEM(bh,ih))->sd_nlink = 0;
else
((struct stat_data *)B_I_PITEM(bh,ih))->sd_nlink = 0;
mark_buffer_dirty(bh, 1);
}
}
}
mark_block_used(bh->b_blocknr);
// we_met_it(s, bh->b_blocknr);
used_blocks++;
}
/* bh must be formatted node. blk_level must be tree_height - h + 1 */
static int handle_node (struct super_block * s, struct buffer_head ** path, int h)
{
if (bad_node(s, path, h)){
remove_internal_pointer(s, path);
return 1;
}
handle_buffer(s, path[h]);
return 0;
}
/* are all delimiting keys correct */
static int handle_path (struct super_block * s, struct buffer_head ** path, int h)
{
if (bad_path(s, path, h)){
remove_internal_pointer(s, path);
return 1;
}
return 0;
}
//return 1 to run rebuild tree from scratch
void check_internal_structure(struct super_block * s)
{
/* control bitmap is used to keep all blocks we should not put into tree again */
/* used bitmap is used to keep all inserted blocks. The same as control bitmap plus unfm blocks */
// init_control_bitmap(s);
printf ("Checking S+tree..");
pass_through_tree (s, handle_node, handle_path);
// compare_bitmaps(s);
printf ("ok\n");
}
#endif
int check_sb (struct super_block * s)
{
int format_sb = 0;
int problem = 0;
struct reiserfs_super_block * rs;
__u32 block_count;
rs = s->s_rs;
// in (REISERFS_DISK_OFFSET_IN_BYTES / 4096) block
if (is_reiser2fs_magic_string (rs) &&
SB_JOURNAL_BLOCK(s) == get_journal_start_must (rs_blocksize (rs)))
{
// 3.6 or >=3.5.22
printf("\t 3.6.x format SB found\n");
format_sb = 1;
goto good_format;
}
if (is_reiserfs_magic_string (rs) &&
SB_JOURNAL_BLOCK(s) == get_journal_start_must (rs_blocksize (rs)))
{
// >3.5.9(10) and <=3.5.21
printf("\t>=3.5.9 format SB found\n");
format_sb = 2;
goto good_format;
}
// in 2 block
if (is_reiser2fs_magic_string (rs) &&
SB_JOURNAL_BLOCK(s) == get_journal_old_start_must (rs))
{
// <3.5.9(10) converted to new format
printf("\t< 3.5.9(10) SB converted to new format found \n");
format_sb = 3;
goto good_format;
}
if (is_reiserfs_magic_string (rs) &&
SB_JOURNAL_BLOCK(s) == get_journal_old_start_must (rs))
{
// <3.5.9(10)
printf("\t< 3.5.9(10) format SB found\n");
format_sb = 4;
goto good_format;
}
else
die("check SB: wrong SB format found\n");
good_format:
printf("\n\t%d-%d\n", SB_BLOCK_COUNT (s), SB_FREE_BLOCKS (s));
if (s->s_blocksize != 4096) {
fsck_log("check SB: specified block size (%d) is not correct must be 4096\n", s->s_blocksize);
problem++;
}
//for 4096 blocksize only
if ((rs_tree_height(rs) < DISK_LEAF_NODE_LEVEL) || (rs_tree_height(rs) > MAX_HEIGHT)){
fsck_log ("check SB: wrong tree height (%d)\n", rs_tree_height(rs));
problem++;
}
block_count = count_blocks ("", s->s_blocksize, s->s_dev);
if (SB_BLOCK_COUNT(s) > block_count){
fsck_log ("check SB: specified block number (%d) is too high\n", SB_BLOCK_COUNT(s));
problem++;
}
if ((rs_root_block(rs) >= block_count) || (rs_root_block(rs) < 0)){
fsck_log ("check SB: specified root block number (%d) is too high\n", rs_root_block(rs));
problem++;
}
if (SB_FREE_BLOCKS(s) > SB_BLOCK_COUNT(s)){
fsck_log ("check SB: specified free block number (%d) is too high\n", SB_FREE_BLOCKS(s));
problem++;
}
if (SB_REISERFS_STATE(s) != REISERFS_VALID_FS){
fsck_log ("check SB: wrong (%d) state\n", SB_REISERFS_STATE(s));
problem++;
}
if ( SB_BMAP_NR(s) != SB_BLOCK_COUNT(s) / (s->s_blocksize * 8) +
((SB_BLOCK_COUNT(s) % (s->s_blocksize * 8)) ? 1 : 0)){
fsck_log("check SB: wrong bitmap number (%d)\n", SB_BMAP_NR(s));
problem++;
}
if (SB_VERSION(s) == REISERFS_VERSION_2 || SB_VERSION(s) == REISERFS_VERSION_1)
{
if (!(SB_VERSION(s) == REISERFS_VERSION_2 && (format_sb == 1 || format_sb == 3)) &&
!(SB_VERSION(s) == REISERFS_VERSION_1 && (format_sb == 2 || format_sb == 4))){
fsck_log("check SB: wrong SB version == %d, format == %d\n", SB_VERSION(s), format_sb);
problem++;
}
}
else{
fsck_log ("check SB: wrong SB version (%d)\n", SB_VERSION(s));
problem++;
}
if (SB_VERSION(s) == REISERFS_VERSION_2 &&
(rs_hash (rs) < 1 || rs_hash (rs) > 3)) {
/* FIXME: */
fsck_log("check SB: wrong hash (%d)\n", rs_hash (rs));
problem++;
}
if ((SB_VERSION(s) == REISERFS_VERSION_2) ?
(rs_objectid_map_max_size (rs) != ((s->s_blocksize - SB_SIZE) / sizeof(__u32) / 2 * 2)) :
(rs_objectid_map_max_size (rs) != ((s->s_blocksize - SB_SIZE_V1) / sizeof(__u32) / 2 * 2))) {
fsck_log("check SB: objectid map corrupted max_size == %d\n", rs_objectid_map_max_size (rs));
problem++;
}
if (rs_objectid_map_size (rs) < 2 ||
rs_objectid_map_size (rs) > rs_objectid_map_max_size (rs)) {
fsck_log("check SB: objectid map corrupted cur_size == %d\n", rs_objectid_map_size (rs));
problem++;
}
if (rs_journal_size(rs) != JOURNAL_BLOCK_COUNT){
fsck_log("check SB: specified journal size (%d) is not correct must be %d\n",
rs_journal_size(rs), JOURNAL_BLOCK_COUNT);
problem++;
}
if (!problem) {
fsck_progress ("\t No problem found\n");
} else if (fsck_log_file (fs) != stderr)
fsck_progress ("Look for super block corruptions in the log file\n");
return format_sb;
}
+425
View File
@@ -0,0 +1,425 @@
/*
* Copyright 1996-2001 Hans Reiser
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <asm/types.h>
#include <sys/vfs.h>
#include <errno.h>
#include <unistd.h>
#include <time.h>
#include <asm/types.h>
#include <assert.h>
#include "io.h"
#include "misc.h"
#include "reiserfs_lib.h"
/* main.c */
extern reiserfs_filsys_t fs;
extern reiserfs_bitmap_t uninsertable_leaf_bitmap;
int main (int argc, char * argv []);
/*
* modes
*/
#define DO_NOTHING 0 /* -a specified */
#define FSCK_CHECK 1
#define FSCK_SB 2
#define FSCK_REBUILD 3
/* temporary */
#define FSCK_ZERO_FILES 4
#define DO_TEST 5
/*
#define FSCK_FAST_REBUILD 4
*/
/*
* options
*/
#define OPT_INTERACTIVE 1
#define OPT_FIX_FIXABLE 2 /* not default yet */
#define OPT_FIX_NON_CRITICAL 4 /* not default yet */
#define OPT_QUIET 8
#define OPT_SAVE_EXTERN_BITMAP 16
#define OPT_SILENT 32
extern int g_blocks_to_read;
/* pass 0 and 1 read the device NR_TO_READ block in time */
#define NR_TO_READ 8
/* pass0.c */
int pass_0 (reiserfs_filsys_t);
int are_there_used_leaves (unsigned long from, int count);
int is_used_leaf (unsigned long block);
int how_many_leaves_were_there (void);
int is_bad_unformatted (unsigned long block);
int is_good_unformatted (unsigned long block);
void mark_good_unformatted (unsigned long block);
int are_there_allocable_blocks (int amout_needed);
unsigned long alloc_block (void);
void make_allocable (unsigned long block);
void register_uninsertable (unsigned long block);
unsigned long how_many_uninsertables_were_there (void);
void register_saved_item (void);
unsigned long how_many_items_were_saved (void);
int still_bad_unfm_ptr_1 (unsigned long block);
int still_bad_unfm_ptr_2 (unsigned long block);
void make_alloc_bitmap (struct super_block * s);
#define __is_marked(name,block) reiserfs_bitmap_test_bit (name##_bitmap, block)
#define __mark(name,block) reiserfs_bitmap_set_bit (name##_bitmap, block)
#define __unmark(name,block) reiserfs_bitmap_clear_bit (name##_bitmap, block)
/* unformatted in tree */
extern reiserfs_bitmap_t bad_unfm_in_tree_once_bitmap;
#define is_bad_unfm_in_tree_once(block) __is_marked (bad_unfm_in_tree_once, block)
#define mark_bad_unfm_in_tree_once(block) __mark (bad_unfm_in_tree_once, block)
/* pass1.c */
void pass_1_pass_2_build_the_tree (void);
struct buffer_head * make_buffer (int dev, int blocknr, int size, char * data);
void build_the_tree (void);
extern int g_unaccessed_items;
int is_item_reachable (struct item_head * ih);
void mark_item_reachable (struct item_head * ih, struct buffer_head * bh);
void mark_item_unreachable (struct item_head * ih);
void rebuild_sb (reiserfs_filsys_t fs);
struct si * remove_saved_item (struct si * si);
/* pass2.c */
void insert_item_separately (struct item_head * ih, char * item,
int was_in_tree);
struct si * save_and_delete_file_item (struct si * si, struct path * path);
void take_bad_blocks_put_into_tree (void);
void rewrite_object (struct item_head * ih, int do_remap);
void pass_2_take_bad_blocks_put_into_tree (void);
/*int is_remapped (struct item_head * ih);*/
void link_relocated_files (void);
void relocate_file (struct item_head * ih, int change_ih);
void relocate_dir (struct item_head * ih, int change_ih);
__u32 objectid_for_relocation (struct key * key);
/* file.c */
struct si {
struct item_head si_ih;
char * si_dnm_data;
struct si * si_next;
__u32 si_blocknr;
// changed by XB;
struct si * last_known;
};
void put_saved_items_into_tree (struct si *);
int reiserfsck_file_write (struct item_head * ih, char * item, int);
int are_file_items_correct (struct key * key, int key_version, __u64 * size, __u32 * blocks, int mark_passed_items,
int symlink, __u64 symlink_size);
/* semantic.c */
extern struct key root_dir_key;
extern struct key parent_root_dir_key;
extern struct key lost_found_dir_key;
void pass_3_semantic (void);
void semantic_check (void);
int check_semantic_tree (struct key * key, struct key * parent, int is_dot_dot, int lost_found, struct item_head * new_ih);
void zero_nlink (struct item_head * ih, void * sd);
int not_a_directory (void * sd);
int is_dot_dot (char * name, int namelen);
int is_dot (char * name, int namelen);
void create_dir_sd (reiserfs_filsys_t fs,
struct path * path, struct key * key);
int rebuild_check_regular_file (struct path * path, void * sd,
struct item_head * new_ih);
int rebuild_semantic_pass (struct key * key, struct key * parent, int is_dot_dot,
struct item_head * new_ih);
/* access to stat data fields */
void get_set_sd_field (int field, struct item_head * ih, void * sd,
void * value, int set);
#define GET_SD_MODE 0
#define GET_SD_SIZE 1
#define GET_SD_NLINK 2
#define GET_SD_BLOCKS 3
#define GET_SD_FIRST_DIRECT_BYTE 4
#define get_sd_mode(ih,sd,pmode) get_set_sd_field (GET_SD_MODE, ih, sd, pmode, 0/*get*/)
#define set_sd_mode(ih,sd,pmode) get_set_sd_field (GET_SD_MODE, ih, sd, pmode, 1/*set*/)
#define get_sd_size(ih,sd,psize) get_set_sd_field (GET_SD_SIZE, ih, sd, psize, 0/*get*/)
#define set_sd_size(ih,sd,psize) get_set_sd_field (GET_SD_SIZE, ih, sd, psize, 1/*set*/)
#define get_sd_blocks(ih,sd,pblocks) get_set_sd_field (GET_SD_BLOCKS, ih, sd, pblocks, 0/*get*/)
#define set_sd_blocks(ih,sd,pblocks) get_set_sd_field (GET_SD_BLOCKS, ih, sd, pblocks, 1/*set*/)
#define get_sd_nlink(ih,sd,pnlink) get_set_sd_field (GET_SD_NLINK, ih, sd, pnlink, 0/*get*/)
#define set_sd_nlink(ih,sd,pnlink) get_set_sd_field (GET_SD_NLINK, ih, sd, pnlink, 1/*set*/)
#define get_sd_first_direct_byte(ih,sd,pfdb) get_set_sd_field (GET_SD_FIRST_DIRECT_BYTE, ih, sd, pfdb, 0/*get*/)
#define set_sd_first_direct_byte(ih,sd,pfdb) get_set_sd_field (GET_SD_FIRST_DIRECT_BYTE, ih, sd, pfdb, 1/*set*/)
/* lost+found.c */
void pass_3a_look_for_lost (reiserfs_filsys_t s);
/* pass4.c */
void get_next_key (struct path * path, int i, struct key * key);
int pass_4_check_unaccessed_items (void);
/* check.c */
int is_leaf_bad (struct buffer_head * bh);
int is_internal_bad (struct buffer_head * bh);
int is_bad_item (struct buffer_head * bh, struct item_head *, char *);
/*int check_file_system (void);*/
void reiserfsck_check_pass1 (void);
void reiserfsck_check_after_all (void);
/*char * bad_name (char * name, int namelen);*/
/* to test result of direcotry item recovering on pass 0 */
int is_bad_directory (struct item_head * ih, char * item, int dev, int blocksize);
//extern int bad_block_number (struct super_block * s, blocknr_t block);
/* check_tree.c */
void check_fs_tree (struct super_block * s);
int check_sb (struct super_block * s);
int bad_pair (struct super_block * s, struct buffer_head * bh, int i);
int bad_leaf_2 (struct super_block * s, struct buffer_head * bh);
/* ustree.c */
void init_tb_struct (struct tree_balance * tb, struct super_block * s, struct path * path, int size);
void reiserfsck_paste_into_item (struct path * path, const char * body, int size);
void reiserfsck_insert_item (struct path * path, struct item_head * ih, const char * body);
void reiserfsck_delete_item (struct path * path, int temporary);
void reiserfsck_cut_from_item (struct path * path, int cut_size);
typedef int (comp_function_t)(void * key1, void * key2);
typedef int (comp3_function_t)(void * key1, void * key2, int version);
/*typedef int (comp_function_t)(struct key * key1, struct key * key2);*/
int ubin_search_id(__u32 * id, __u32 * base, __u32 number, __u32 * pos);
int usearch_by_key (struct super_block * s, struct key * key, struct path * path);
int usearch_by_key_3 (struct super_block * s, struct key * key, struct path * path, int * repeat, int stop_level,
comp3_function_t comp_func, int version);
int usearch_by_entry_key (struct super_block * s, struct key * key, struct path * path);
int usearch_by_position (struct super_block * s, struct key * key, int version, struct path * path);
struct key * uget_lkey (struct path * path);
struct key * uget_rkey (struct path * path);
typedef int do_after_read_t (struct super_block * s, struct buffer_head **, int h);
typedef int do_on_full_path_t (struct super_block * s, struct buffer_head **, int);
void pass_through_tree (struct super_block *, do_after_read_t, do_on_full_path_t);
//int comp_keys_3 (void * key1, void * key2);
//int comp_dir_entries (void * key1, void * key2);
inline int ubin_search (void * key, void * base, int num, int width, __u32 *ppos, comp_function_t comp_func);
/* bitmap.c */
int reiserfsck_reiserfs_new_blocknrs (reiserfs_filsys_t fs,
unsigned long * pblocknrs,
unsigned long start_from,
int amount_needed);
int reiserfsck_reiserfs_free_block (reiserfs_filsys_t fs, unsigned long block);
struct buffer_head * reiserfsck_get_new_buffer (unsigned long start);
int is_block_used (unsigned long block);
int is_to_be_read (reiserfs_filsys_t fs, unsigned long block);
void mark_block_used (unsigned long block);
void mark_block_uninsertable (unsigned long block);
int is_block_uninsertable (unsigned long block);
/* objectid.c */
int is_objectid_used (struct super_block * s, __u32 objectid);
void mark_objectid_as_used (struct super_block * s, __u32 objectid);
void mark_objectid_as_free (struct super_block * s, __u32 objectid);
__u32 get_unused_objectid (struct super_block * s);
struct id_map * init_id_map (void);
void free_id_map (struct id_map **);
int is_objectid_really_used (struct id_map *, __u32 id, int * ppos);
int mark_objectid_really_used (struct id_map *, __u32 id);
void flush_objectid_map (struct id_map * map, reiserfs_filsys_t fs);
void fetch_objectid_map (struct id_map * map, reiserfs_filsys_t fs);
/* segments.c */
struct overwritten_unfm_segment {
int ous_begin;
int ous_end;
struct overwritten_unfm_segment * ous_next;
};
struct overwritten_unfm * look_for_overwritten_unfm (__u32);
struct overwritten_unfm_segment * find_overwritten_unfm (unsigned long unfm, int length, struct overwritten_unfm_segment * segment_to_init);
int get_unoverwritten_segment (struct overwritten_unfm_segment * list_head, struct overwritten_unfm_segment * unoverwritten_segment);
void save_unfm_overwriting (unsigned long unfm, struct item_head * direct_ih);
void free_overwritten_unfms (void);
void mark_formatted_pointed_by_indirect (__u32);
int is_formatted_pointed_by_indirect (__u32);
struct id_map {
__u32 * m_begin; /* pointer to map area */
unsigned long m_used_slots_count;
int m_page_count; /* objectid map expands by one page at
time. This is size of objectid map size in
pages */
unsigned long objectids_marked; /* number of objectids marked used
in a map */
};
struct fsck_data {
unsigned long all_blocks; /* super block's block count */
/* pass 0 */
unsigned long analyzed; /* blocks marked used (not data not included) */
unsigned long free; /* free blocks */
unsigned long not_data; /* super block, bitmap, journal */
unsigned long leaves; /* blocks looking like reiserfs leaves */
unsigned long pointed_leaves;
unsigned long pointed; /* by indirect items */
unsigned long pointed_once;
unsigned long pointed_more_than_once;
unsigned long allocable;
unsigned long wrong_pointers; /* out of range or pointers to free
area */
unsigned long leaves_corrected;
unsigned long all_contents_removed;
/* pass 1, 2 */
unsigned long read_leaves;
unsigned long uninsertable_leaves;
unsigned long inserted_leaves;
unsigned long shared_objectids;
unsigned long saved_on_pass1;
unsigned long relocated;
unsigned long rewritten;
/* stat of semantic pass */
unsigned long regular_files;
unsigned long broken_files; /* files having stat data and broken body */
unsigned long directories;
unsigned long symlinks;
unsigned long others;
unsigned long fixed_sizes;
unsigned long deleted_entries; /* entries pointing to nowhere */
unsigned long oid_sharing; /* files relocated due to objectid sharing */
unsigned long oid_sharing_files_relocated; /* relocated files */
unsigned long oid_sharing_dirs_relocated; /* relocated dirs */
unsigned long lost_found;
unsigned long empty_lost_dirs;
unsigned long lost_found_dirs;
unsigned long dir_recovered;
unsigned long lost_found_files;
/* pass 4 */
unsigned long deleted_items; /* items which were not touched by
semantic pass */
/* objectid maps */
struct id_map * proper_id_map;
struct id_map * semantic_id_map; /* this objectid map is used to
cure objectid sharing problem */
/* bitmaps */
reiserfs_bitmap_t on_disk_bitmap;
reiserfs_bitmap_t new_bitmap;
reiserfs_bitmap_t allocable_bitmap;
char * bitmap_file_name;
char * new_bitmap_file_name;
unsigned short mode;
unsigned long options;
/* log file name and handle */
char * log_file_name;
FILE * log;
/* hash hits stat */
int hash_amount;
unsigned long * hash_hits;
#define USED_BLOCKS 1
#define EXTERN_BITMAP 2
#define ALL_BLOCKS 3
int scan_area;
int test;
};
#define stats(s) ((struct fsck_data *)((s)->s_vp))
#define proper_id_map(s) stats(s)->proper_id_map
#define semantic_id_map(s) stats(s)->semantic_id_map
#define fsck_disk_bitmap(s) stats(s)->on_disk_bitmap
#define fsck_new_bitmap(s) stats(s)->new_bitmap
#define fsck_allocable_bitmap(s) stats(s)->allocable_bitmap
#define fsck_interactive(fs) (stats(fs)->options & OPT_INTERACTIVE)
#define fsck_fix_fixable(fs) (stats(fs)->options & OPT_FIX_FIXABLE)
/* change unknown modes (corrupted) to mode of regular files, fix file
sizes which are bigger than a real file size, relocate files with
shared objectids (this slows fsck down (when there are too many
files sharing the same objectid), it will also remove other names
pointing to this file */
#define fsck_fix_non_critical(fs) (stats(fs)->options & OPT_FIX_NON_CRITICAL)
#define fsck_quiet(fs) (stats(fs)->options & OPT_QUIET)
#define fsck_silent(fs) (stats(fs)->options & OPT_SILENT)
#define fsck_save_leaf_bitmap(fs) (stats(fs)->options & OPT_SAVE_EXTERN_BITMAP)
#define fsck_mode(fs) (stats(fs)->mode)
#define fsck_log_file(fs) (stats(fs)->log)
/* ?? */
extern inline int change_version (int version)
{
return (version == 1)?0:1;
}
int fsck_user_confirmed (reiserfs_filsys_t fs, char * q, char * a, int default_answer);
void stage_report (int, reiserfs_filsys_t fs);
/* journal.c */
int reiserfs_replay_journal (struct super_block * s);
#define fsck_log(fmt, list...) \
{\
if (!fsck_silent (fs))\
reiserfs_warning (fsck_log_file (fs), fmt, ## list);\
}
#define fsck_progress(fmt, list...) \
{\
reiserfs_warning (stderr, fmt, ## list);\
fflush (stderr);\
}
+134
View File
@@ -0,0 +1,134 @@
/*
* Copyright 1996-1999 Hans Reiser
*/
#include "fsck.h"
#include <stdarg.h>
int fsck_user_confirmed (reiserfs_filsys_t fs, char * q, char * a, int default_answer)
{
if (!fsck_interactive (fs))
return default_answer;
return user_confirmed (q, a);
}
void stage_report (int pass, reiserfs_filsys_t fs)
{
FILE * fp;
struct fsck_data * stat;
stat = stats (fs);
fp = stderr;
switch (pass) {
case 0:
fsck_progress ("\tRead blocks (but not data blocks) %lu\n", stat->analyzed);
stat->analyzed = 0;
fsck_progress ("\t\tLeaves among those %lu\n", stat->leaves);
if (stat->leaves_corrected)
fsck_progress ("\t\t\t- corrected leaves %lu\n", stat->leaves_corrected);
if (stat->all_contents_removed)
fsck_progress ("\t\t\t- eaves all contents of which could not be saved and deleted %lu\n", stat->all_contents_removed);
if (stat->pointed_leaves)
fsck_progress ("\t\t\t- leaves pointed by indirect items %lu\n", stat->pointed_leaves);
if (stat->pointed)
fsck_progress ("\t\tBlocks pointed by indirect items %lu\n", stat->pointed);
if (stat->pointed_once)
fsck_progress ("\t\t\t- once %lu\n", stat->pointed_once);
if (stat->pointed_more_than_once)
fsck_progress ("\t\t\t- more than once %lu\n", stat->pointed_more_than_once);
if (stat->wrong_pointers)
fsck_progress ("\t\t\t- pointers to wrong area of filesystem (zeroed) %lu\n", stat->wrong_pointers);
/* pass1 will calculate how many pointers were zeeros there */
stat->wrong_pointers = 0;
fsck_progress ("\t\tObjectids found %lu\n", proper_id_map (fs)->objectids_marked);
/*fsck_progress ("\tblocks marked free %lu\n", stat->free);*/
fsck_progress ("\tallocable %lu blocks\n", stat->allocable);
break;
case 1:
fsck_progress ("\t%lu leaves read\n", stat->analyzed);
fsck_progress ("\t\t%lu inserted\n", stat->inserted_leaves);
if (stat->uninsertable_leaves)
fsck_progress ("\t\t%lu not inserted\n", stat->uninsertable_leaves);
if (stat->saved_on_pass1)
fsck_progress ("\tSaved %lu items\n", stat->saved_on_pass1);
if (stat->wrong_pointers)
fsck_progress ("\tPointers to leaves or non-unique (zeroed) %lu\n",
stat->wrong_pointers);
break;
case 2:
if (stat->shared_objectids)
fsck_progress ("\t%lu shared objectids\n", stat->shared_objectids);
if (stat->relocated)
fsck_progress ("\tFiles relocated because of key conflicts w/ a directory %lu\n",
stat->relocated);
if (stat->rewritten)
fsck_progress ("\tFiles rewritten %lu\n",
stat->rewritten);
return;
case 3: /* semantic pass */
fsck_progress ("\tFiles found: %ld\n", stat->regular_files);
fsck_progress ("\tDirectories found: %ld\n", stat->directories);
if (stat->symlinks)
fsck_progress ("\tSymlinks found: %ld\n", stat->symlinks);
if (stat->others)
fsck_progress ("\tOthers: %ld\n", stat->others);
if (stat->fixed_sizes)
fsck_progress ("\tFiles with fixed size: %ld\n", stat->fixed_sizes);
if (stat->oid_sharing)
fsck_progress ("\tObjects having used objectids: %lu\n", stat->oid_sharing);
if (stat->oid_sharing_files_relocated)
fsck_progress ("\t\tfiles fixed %lu\n", stat->oid_sharing_files_relocated);
if (stat->oid_sharing_dirs_relocated)
fsck_progress ("\t\tdirs fixed %lu\n", stat->oid_sharing_dirs_relocated);
stat->oid_sharing = 0;
stat->oid_sharing_files_relocated = 0;
stat->oid_sharing_dirs_relocated = 0;
break;
case 0x3a: /* looking for lost files */
if (stat->lost_found)
fsck_progress ("\tObjects without names %lu\n",
stat->lost_found);
if (stat->empty_lost_dirs)
fsck_progress ("\tEmpty lost dirs removed %lu\n",
stat->empty_lost_dirs);
if (stat->lost_found_dirs)
fsck_progress ("\tDirs linked to /lost+found: %lu\n",
stat->lost_found_dirs);
if (stat->dir_recovered)
fsck_progress ("\t\tDirs without stat data found %lu\n",
stat->dir_recovered);
if (stat->lost_found_files)
fsck_progress ("\tFiles linked to /lost+found %lu\n",
stat->lost_found_files);
if (stat->oid_sharing)
fsck_progress ("\tObjects having used objectids: %lu\n", stat->oid_sharing);
if (stat->oid_sharing_files_relocated)
fsck_progress ("\t\tfiles fixed %lu\n", stat->oid_sharing_files_relocated);
if (stat->oid_sharing_dirs_relocated)
fsck_progress ("\t\tdirs fixed %lu\n", stat->oid_sharing_dirs_relocated);
break;
case 4: /* removing of unreachable */
if (stat->deleted_items)
fsck_progress ("\tDeleted unreachable items %lu\n",
stat->deleted_items);
break;
}
if (!fsck_user_confirmed (fs, "Continue? (Yes):", "Yes\n", 1)) {
reiserfs_close (fs);
exit (0);
}
}
+219
View File
@@ -0,0 +1,219 @@
/*
* Copyright 2000 Hans Reiser
*/
#include "fsck.h"
#include <limits.h>
/*#include <stdlib.h>*/
#define bh_desc(bh) ((struct reiserfs_journal_desc *)((bh)->b_data))
#define bh_commit(bh) ((struct reiserfs_journal_commit *)((bh)->b_data))
static int next_expected_desc (struct super_block * s, struct buffer_head * d_bh)
{
int offset;
struct reiserfs_journal_desc * desc;
desc = (struct reiserfs_journal_desc *)d_bh->b_data;
offset = d_bh->b_blocknr - SB_JOURNAL_BLOCK (s);
return SB_JOURNAL_BLOCK (s) + ((offset + desc->j_len + 1 + 1) % JOURNAL_BLOCK_COUNT);
}
static int is_valid_transaction (struct super_block * s, struct buffer_head * d_bh)
{
struct buffer_head * c_bh;
int offset;
struct reiserfs_journal_desc *desc = (struct reiserfs_journal_desc *)d_bh->b_data;
struct reiserfs_journal_commit *commit ;
__u32 block, start_block;
offset = d_bh->b_blocknr - SB_JOURNAL_BLOCK (s);
/* ok, we have a journal description block, lets see if the transaction was valid */
block = next_expected_desc (s, d_bh) - 1;
start_block = d_bh->b_blocknr;
while(!(c_bh = bread (s->s_dev, block, s->s_blocksize))){
if (++block == SB_JOURNAL_BLOCK (s) + JOURNAL_BLOCK_COUNT)
block = SB_JOURNAL_BLOCK (s);
if (block == start_block)
return 0;
}
commit = (struct reiserfs_journal_commit *)c_bh->b_data ;
if (does_desc_match_commit (desc, commit)) {
// if (journal_compare_desc_commit (s, desc, commit)) {
/* printf ("desc and commit block do not match\n");*/
brelse (c_bh) ;
return 0;
}
brelse (c_bh);
return 1;
}
int reiserfs_replay_journal (struct super_block * s)
{
struct buffer_head * d_bh, * c_bh, * jh_bh;
struct reiserfs_journal_header * j_head;
struct reiserfs_journal_desc * j_desc;
struct reiserfs_journal_commit * j_commit;
unsigned long latest_mount_id;
unsigned long j_cur;
unsigned long j_start;
unsigned long j_size;
unsigned long mount_id, trans_id;
unsigned long t_first, t_last, t_count, t_flushed;
unsigned long t_offset;
int i;
fsck_progress ("Analyzing journal..");
j_start = SB_JOURNAL_BLOCK (s);
j_cur = 0;
j_size = rs_journal_size (s->s_rs);
t_first = 0;
t_last = 0;
latest_mount_id = 0;
/* look for the transactions with the most recent mount_id */
for (j_cur = 0; j_cur < j_size; ) {
d_bh = bread (s->s_dev, j_start + j_cur, s->s_blocksize);
if (d_bh && who_is_this (d_bh->b_data, d_bh->b_size) == THE_JDESC && is_valid_transaction (s, d_bh)) {
j_desc = (struct reiserfs_journal_desc *)d_bh->b_data;
mount_id = le32_to_cpu (j_desc->j_mount_id);
trans_id = le32_to_cpu (j_desc->j_trans_id);
if (mount_id > latest_mount_id) {
/* more recent mount_id found */
latest_mount_id = mount_id;
t_first = t_last = trans_id;
t_offset = j_cur;
t_count = 1;
} else if (mount_id == latest_mount_id) {
t_count ++;
if (trans_id > t_last)
t_last = trans_id;
if (trans_id < t_first) {
t_first = trans_id;
t_offset = j_cur;
}
}
j_cur += le32_to_cpu (j_desc->j_len) + 1;
}
j_cur ++;
brelse (d_bh);
}
/* replay only if journal header looks resonable */
jh_bh = bread (s->s_dev, j_start + j_size, s->s_blocksize);
j_head = (struct reiserfs_journal_header *)(jh_bh->b_data);
if (latest_mount_id != le32_to_cpu (j_head->j_mount_id)) {
fsck_progress ("nothing to replay (no transactions match to latest mount id)\n");
brelse (jh_bh);
return 0;
}
/* last transaction flushed - which should not be replayed */
t_flushed = le32_to_cpu (j_head->j_last_flush_trans_id);
if (t_flushed >= t_last) {
fsck_progress ("nothing to replay (no transactions older than last flushed one found)\n");
brelse (jh_bh);
return 0;
}
if (t_first > t_flushed + 1) {
if (t_flushed)
fsck_progress ("last flushed trans %lu, the oldest but newer is %lu\n",
t_flushed, t_first);
} else {
/* start replaying with first not flushed transaction */
t_first = t_flushed + 1;
t_offset = le32_to_cpu (j_head->j_first_unflushed_offset);
}
fsck_progress ("last flushed trans %lu, mount_id %lu, "
"will replay from %lu up to %lu:Yes?",
t_flushed, latest_mount_id, t_first, t_last);
if (!fsck_user_confirmed (fs, "", "Yes\n", 1))
die ("");
/* replay transactions we have found */
for (j_cur = t_offset; t_first <= t_last; t_first ++) {
unsigned long offset;
d_bh = bread (s->s_dev, j_start + j_cur, s->s_blocksize);
j_desc = (struct reiserfs_journal_desc *)d_bh->b_data;
if (who_is_this (d_bh->b_data, d_bh->b_size) != THE_JDESC ||
le32_to_cpu (j_desc->j_mount_id) != latest_mount_id ||
le32_to_cpu (j_desc->j_trans_id) != t_first)
die ("reiserfs_replay_journal: desc block not found");
offset = j_cur + 1;
j_cur += le32_to_cpu (j_desc->j_len) + 1;
j_cur %= j_size;
c_bh = bread (s->s_dev, j_start + j_cur, s->s_blocksize);
j_commit = (struct reiserfs_journal_commit *)c_bh->b_data;
if (does_desc_match_commit (j_desc, j_commit))
die ("reiserfs_replay_journal: commit block not found");
fsck_log ("Mount_id %lu, transaction %lu, desc block %lu, commit block %lu: (",
latest_mount_id, t_first, d_bh->b_blocknr, c_bh->b_blocknr);
/* replay one transaction */
for (i = 0; i < le32_to_cpu (j_desc->j_len); i ++) {
struct buffer_head * in_place, * log;
unsigned long block;
log = bread (s->s_dev, j_start + ((offset + i) % j_size), s->s_blocksize);
if (i < JOURNAL_TRANS_HALF) {
block = le32_to_cpu (j_desc->j_realblock[i]);
} else {
block = le32_to_cpu (j_commit->j_realblock[i - JOURNAL_TRANS_HALF]);
}
if (not_journalable (s, block)) {
fsck_log ("transaction %lu, block %d could not be replayed (%lu)\n",
t_first, i, block);
} else {
fsck_log (" %lu", block);
in_place = getblk (s->s_dev, block, s->s_blocksize) ;
memcpy (in_place->b_data, log->b_data, s->s_blocksize);
mark_buffer_dirty (in_place);
mark_buffer_uptodate (in_place, 1);
bwrite (in_place);
brelse (in_place);
}
brelse (log);
}
fsck_log (")\n");
brelse (d_bh);
brelse (c_bh);
j_cur ++;
j_cur %= j_size;
/* update journal header */
j_head->j_last_flush_trans_id = cpu_to_le32 (t_first);
mark_buffer_dirty (jh_bh);
bwrite (jh_bh);
}
brelse (jh_bh);
fsck_progress ("Journal replaied\n");
return 0;
}
+269
View File
@@ -0,0 +1,269 @@
/*
* Copyright 2000-2001 Hans Reiser
*/
#include "fsck.h"
/* fixme: search_by_key is not needed after any add_entry */
static __u64 _look_for_lost (reiserfs_filsys_t fs, int link_lost_dirs)
{
struct key key, prev_key, * rdkey;
INITIALIZE_PATH (path);
int item_pos;
struct buffer_head * bh;
struct item_head * ih;
unsigned long leaves;
int is_it_dir;
static int lost_files = 0; /* looking for lost dirs we calculate amount of
lost files, so that when we will look for
lost files we will be able to stop when
there are no lost files anymore */
int retval;
__u64 size;
key = root_dir_key;
if (!link_lost_dirs && !lost_files) {
/* we have to look for lost files but we know already that there are
no any */
return 0;
}
fsck_progress ("Looking for lost %s:\n", link_lost_dirs ? "directories" : "files");
leaves = 0;
/* total size of added entries */
size = 0;
while (1) {
retval = usearch_by_key (fs, &key, &path);
/* fixme: we assume path ends up with a leaf */
bh = get_bh (&path);
item_pos = get_item_pos (&path);
if (retval != ITEM_FOUND) {
if (item_pos == node_item_number (bh)) {
rdkey = uget_rkey (&path);
if (!rdkey) {
pathrelse (&path);
break;
}
key = *rdkey;
pathrelse (&path);
continue;
}
/* we are on the item in the buffer */
}
/* print ~ how many leaves were scanned and how fast it was */
if (!fsck_quiet (fs))
print_how_fast (0, leaves++, 50);
for (ih = get_ih (&path); item_pos < node_item_number (bh); item_pos ++, ih ++) {
if (is_item_reachable (ih))
continue;
/* found item which can not be reached */
if (!is_direntry_ih (ih) && !is_stat_data_ih (ih)) {
continue;
}
if (is_direntry_ih (ih)) {
/* if this directory has no stat data - try to recover it */
struct key sd;
struct path tmp;
sd = ih->ih_key;
set_type_and_offset (KEY_FORMAT_1, &sd, SD_OFFSET, TYPE_STAT_DATA);
if (usearch_by_key (fs, &sd, &tmp) == ITEM_FOUND) {
/* should not happen - because if there were a stat data -
we would have done with the whole directory */
pathrelse (&tmp);
continue;
}
stats(fs)->dir_recovered ++;
create_dir_sd (fs, &tmp, &sd);
key = sd;
pathrelse (&path);
goto cont;
}
/* stat data marked "not having name" found */
is_it_dir = ((not_a_directory (B_I_PITEM (bh,ih))) ? 0 : 1);
if (is_it_dir) {
struct key tmp_key;
INITIALIZE_PATH (tmp_path);
struct item_head * tmp_ih;
/* there is no need to link empty lost directories into /lost+found */
tmp_key = ih->ih_key;
set_type_and_offset (KEY_FORMAT_1, &tmp_key, 0xffffffff, TYPE_DIRENTRY);
usearch_by_key (fs, &tmp_key, &tmp_path);
tmp_ih = get_ih (&tmp_path);
tmp_ih --;
if (not_of_one_file (&tmp_key, tmp_ih))
reiserfs_panic ("not directory found");
if (!is_direntry_ih (tmp_ih) ||
(deh_offset (B_I_DEH (get_bh (&tmp_path), ih) +
ih_entry_count (tmp_ih) - 1) == DOT_DOT_OFFSET)) {
/* last directory item is either stat data or empty
directory item - do not link this dir into lost+found */
stats(fs)->empty_lost_dirs ++;
pathrelse (&tmp_path);
continue;
}
pathrelse (&tmp_path);
}
if (link_lost_dirs && !is_it_dir) {
/* we are looking for directories and it is not a dir */
lost_files ++;
continue;
}
stats(fs)->lost_found ++;
{
struct key obj_key = {0, 0, {{0, 0},}};
char * lost_name;
struct item_head tmp_ih;
int pos_in_map;
/* key to continue */
key = ih->ih_key;
key.k_objectid ++;
tmp_ih = *ih;
if (is_objectid_really_used (semantic_id_map (fs), ih->ih_key.k_objectid,
&pos_in_map)) {
/* objectid is used, relocate an object */
stats(fs)->oid_sharing ++;
if (fsck_fix_non_critical (fs)) {
if (is_it_dir) {
relocate_dir (&tmp_ih, 1);
stats(fs)->oid_sharing_dirs_relocated ++;
} else {
relocate_file (&tmp_ih, 1);
stats(fs)->oid_sharing_files_relocated ++;
}
}
} else {
if (!is_it_dir)
mark_objectid_really_used (semantic_id_map (fs), ih->ih_key.k_objectid);
}
asprintf (&lost_name, "%u_%u", le32_to_cpu (tmp_ih.ih_key.k_dir_id),
le32_to_cpu (tmp_ih.ih_key.k_objectid));
/* entry in lost+found directory will point to this key */
obj_key.k_dir_id = tmp_ih.ih_key.k_dir_id;
obj_key.k_objectid = tmp_ih.ih_key.k_objectid;
pathrelse (&path);
/* 0 does not mean anyting - item w/ "." and ".." already
exists and reached, so only name will be added */
size += reiserfs_add_entry (fs, &lost_found_dir_key, lost_name, &obj_key, 0/*fsck_need*/);
if (is_it_dir) {
/* fixme: we hope that if we will try to pull all the
directory right now - then there will be less
lost_found things */
fsck_progress ("\tChecking lost dir \"%s\":", lost_name);
rebuild_semantic_pass (&obj_key, &lost_found_dir_key, /*dot_dot*/0, /*reloc_ih*/0);
fsck_progress ("ok\n");
stats(fs)->lost_found_dirs ++;
} else {
if (usearch_by_key (fs, &obj_key, &path) != ITEM_FOUND)
reiserfs_panic ("look_for_lost: lost file stat data %K not found",
&obj_key);
/* check_regular_file does not mark stat data reachable */
mark_item_reachable (get_ih (&path), get_bh (&path));
mark_buffer_dirty (get_bh (&path));
rebuild_check_regular_file (&path, get_item (&path), 0/*reloc_ih*/);
pathrelse (&path);
stats(fs)->lost_found_files ++;
lost_files --;
}
free (lost_name);
goto cont;
}
} /* for */
prev_key = key;
get_next_key (&path, item_pos - 1, &key);
if (comp_keys (&prev_key, &key) != -1)
reiserfs_panic ("pass_3a: key must grow 2: prev=%k next=%k",
&prev_key, &key);
pathrelse (&path);
cont:
if (!link_lost_dirs && !lost_files) {
break;
}
}
pathrelse (&path);
#if 0
/* check names added we just have added to/lost+found. Those names are
marked DEH_Lost_found flag */
fsck_progress ("Checking lost+found directory.."); fflush (stdout);
check_semantic_tree (&lost_found_dir_key, &root_dir_key, 0, 1/* lost+found*/);
fsck_progress ("ok\n");
#endif
if (!link_lost_dirs && lost_files)
fsck_log ("look_for_lost: %d files seem to left not linked to lost+found\n",
lost_files);
return size;
}
void pass_3a_look_for_lost (reiserfs_filsys_t fs)
{
INITIALIZE_PATH (path);
struct item_head * ih;
void * sd;
__u64 size, sd_size;
__u32 blocks;
fsck_progress ("Pass 3a (looking for lost files):\n");
/* when warnings go not to stderr - separate then in the log */
if (fsck_log_file (fs) != stderr)
fsck_log ("####### Pass 3a (lost+found pass) #########\n");
/* look for lost dirs first */
size = _look_for_lost (fs, 1);
/* link files which are still lost */
size += _look_for_lost (fs, 0);
/* update /lost+found sd_size and sd_blocks (nlink is correct already) */
if (usearch_by_key (fs, &lost_found_dir_key, &path) != ITEM_FOUND)
reiserfs_panic ("look_for_lost: /lost+found stat data %K not found",
&lost_found_dir_key);
ih = get_ih (&path);
sd = get_item (&path);
get_sd_size (ih, sd, &sd_size);
size += sd_size;
blocks = dir_size2st_blocks (fs->s_blocksize, size);
set_sd_size (ih, sd, &size);
set_sd_blocks (ih, sd, &blocks);
mark_buffer_dirty (get_bh (&path));
pathrelse (&path);
stage_report (0x3a, fs);
}
+709
View File
@@ -0,0 +1,709 @@
/*
* Copyright 1996-2000 Hans Reiser
*/
#include "fsck.h"
#include <getopt.h>
#include "../version.h"
#define print_usage_and_exit() die ("Usage: %s [options] "\
" device\n"\
"\n"\
"Options:\n\n"\
" --check\t\tconsistency checking (default)\n"\
" --rebuild-sb\t\tsuper block checking and rebuilding if needed\n"\
" --rebuild-tree\tforce fsck to rebuild filesystem from scratch\n"\
" \t\t\t(takes a long time)\n"\
" --interactive, -i\tmake fsck to stop after every stage\n"\
" -l | --logfile logfile\n"\
" \t\t\tmake fsck to complain to specifed file\n"\
" -b | --scan-marked-in-bitmap file\n"\
" \t\t\tbuild tree of blocks marked in the bitmapfile\n"\
" -c | --create-bitmap-file\n"\
" \t\t\tsave bitmap of found leaves\n"\
" -x | --fix-fixable\tfix corruptions which can be fixed w/o --rebuild-tree\n"\
" -o | --fix-non-critical\n"\
" \t\t\tfix strange modes, file sizes to real size and\n"\
" \t\t\trelocate files using busy objectids\n"\
" -q | --quiet\t\tno speed info\n"\
" -n | --nolog\t\t suppresses all logs\n"\
" -V\t\t\tprints version and exits\n"\
" -a\t\t\tmakes fsck to do nothing\n"\
" -p\t\t\tdo nothing, exist for compatibility with fsck(8)\n"\
" -r\n", argv[0]);
/* fsck is called with one non-optional argument - file name of device
containing reiserfs. This function parses other options, sets flags
based on parsing and returns non-optional argument */
static char * parse_options (struct fsck_data * data, int argc, char * argv [])
{
int c;
static int mode = FSCK_CHECK;
data->scan_area = USED_BLOCKS;
while (1) {
static struct option options[] = {
/* modes */
{"check", no_argument, &mode, FSCK_CHECK},
{"rebuild-sb", no_argument, &mode, FSCK_SB},
{"rebuild-tree", no_argument, &mode, FSCK_REBUILD},
/*
{"fast-rebuild", no_argument, &opt_fsck_mode, FSCK_FAST_REBUILD},
*/
/* options */
{"logfile", required_argument, 0, 'l'},
{"interactive", no_argument, 0, 'i'},
{"fix-fixable", no_argument, 0, 'x'},
{"fix-non-critical", no_argument, 0, 'o'},
{"quiet", no_argument, 0, 'q'},
{"nolog", no_argument, 0, 'n'},
/* if file exists ad reiserfs can be load of it - only
blocks marked used in that bitmap will be read */
{"scan-marked-in-bitmap", required_argument, 0, 'b'},
/* */
{"create-leaf-bitmap", required_argument, 0, 'c'},
/* all blocks will be read */
{"scan-whole-partition", no_argument, 0, 'S'},
/* special option: will mark free blocks used, zero all
unformatted node pointers and mark them free */
{"zero-files", no_argument, &mode, FSCK_ZERO_FILES},
{0, 0, 0, 0}
};
int option_index;
c = getopt_long (argc, argv, "iql:b:Sc:xoVaprt:n",
options, &option_index);
if (c == -1)
break;
switch (c) {
case 0:
/* long option specifying fsck mode is found */
break;
case 'i': /* --interactive */
data->options |= OPT_INTERACTIVE;
break;
case 'q': /* --quiet */
data->options |= OPT_QUIET;
break;
case 'l': /* --logfile */
asprintf (&data->log_file_name, "%s", optarg);
data->log = fopen (optarg, "w");
if (!data->log)
fprintf (stderr, "reiserfsck: could not open \'%s\': %m", optarg);
break;
case 'b': /* --scan-marked-in-bitmap */
/* will try to load a bitmap from a file and read only
blocks marked in it. That bitmap could be created by
previous run of reiserfsck with -c */
asprintf (&data->bitmap_file_name, "%s", optarg);
data->scan_area = EXTERN_BITMAP;
break;
case 'S': /* --scan-whole-partition */
data->scan_area = ALL_BLOCKS;
break;
case 'c': /* --create-leaf-bitmap */
asprintf (&data->new_bitmap_file_name, "%s", optarg);
data->options |= OPT_SAVE_EXTERN_BITMAP;
break;
case 'x': /* --fix-fixable */
data->options |= OPT_FIX_FIXABLE;
break;
case 'o': /* --fix-non-critical */
data->options |= OPT_FIX_NON_CRITICAL;
break;
case 'n': /* --nolog */
data->options |= OPT_SILENT;
break;
case 'V':
case 'p': /* these say reiserfsck to do nothing */
case 'r':
case 'a':
mode = DO_NOTHING;
break;
case 't':
mode = DO_TEST;
data->test = atoi (optarg);
break;
default:
print_usage_and_exit();
}
}
if (optind != argc - 1 && mode != DO_NOTHING)
/* only one non-option argument is permitted */
print_usage_and_exit();
data->mode = mode;
if (!data->log)
data->log = stderr;
return argv[optind];
}
reiserfs_filsys_t fs;
static void reset_super_block (reiserfs_filsys_t fs)
{
set_free_blocks (fs->s_rs, SB_BLOCK_COUNT (fs));
set_root_block (fs->s_rs, ~0);
set_tree_height (fs->s_rs, ~0);
/* make file system invalid unless fsck done () */
set_state (fs->s_rs, REISERFS_ERROR_FS);
if (is_reiser2fs_magic_string (fs->s_rs)) {
set_version (fs->s_rs, REISERFS_VERSION_2);
}
if (is_reiserfs_magic_string (fs->s_rs)) {
set_version (fs->s_rs, REISERFS_VERSION_1);
}
/* can be not set yet. If so, hash function will be set when first dir
entry will be found */
fs->s_hash_function = code2func (rs_hash (fs->s_rs));
/* objectid map is not touched */
mark_buffer_dirty (fs->s_sbh);
bwrite (fs->s_sbh);
}
reiserfs_bitmap_t uninsertable_leaf_bitmap;
int g_blocks_to_read;
/* on-disk bitmap is read, fetch it. create new bitmap, mark used blocks which
are always used (skipped, super block, journal area, bitmaps), create other
auxiliary bitmaps */
static void init_bitmaps (reiserfs_filsys_t fs)
{
unsigned long i;
unsigned long block_count;
unsigned long tmp;
block_count = SB_BLOCK_COUNT (fs);
switch (stats (fs)->scan_area) {
case ALL_BLOCKS:
fsck_disk_bitmap (fs) = reiserfs_create_bitmap (block_count);
reiserfs_bitmap_fill (fsck_disk_bitmap (fs));
fsck_progress ("Whole device (%d blocks) is to be scanned\n",
reiserfs_bitmap_ones (fsck_disk_bitmap (fs)));
break;
case USED_BLOCKS:
fsck_progress ("Loading on-disk bitmap .. ");
fsck_disk_bitmap (fs) = reiserfs_create_bitmap (block_count);
reiserfs_fetch_disk_bitmap (fsck_disk_bitmap (fs), fs);
fsck_progress ("%d bits set - done\n",
reiserfs_bitmap_ones (fsck_disk_bitmap (fs)));
break;
case EXTERN_BITMAP:
fsck_disk_bitmap (fs) = reiserfs_bitmap_load (stats (fs)->bitmap_file_name);
if (!fsck_disk_bitmap (fs))
reiserfs_panic ("could not load fitmap from \"%s\"",
stats (fs)->bitmap_file_name);
break;
default:
reiserfs_panic ("No area to scan specified");
}
/* pass 0 will skip super block and journal areas and bitmap blocks, find
how many blocks have to be read */
tmp = 0;
for (i = 0; i <= fs->s_sbh->b_blocknr; i ++) {
if (!reiserfs_bitmap_test_bit (fsck_disk_bitmap (fs), i))
continue;
reiserfs_bitmap_clear_bit (fsck_disk_bitmap (fs), i);
tmp ++;
}
/* unmark bitmaps */
for (i = 0; i < rs_bmap_nr (fs->s_rs); i ++) {
unsigned long block;
block = SB_AP_BITMAP (fs)[i]->b_blocknr;
if (!reiserfs_bitmap_test_bit (fsck_disk_bitmap (fs), block))
continue;
reiserfs_bitmap_clear_bit (fsck_disk_bitmap (fs), block);
tmp ++;
}
/* unmark journal area */
for (i = rs_journal_start (fs->s_rs);
i <= rs_journal_start (fs->s_rs) + rs_journal_size (fs->s_rs); i ++) {
if (!reiserfs_bitmap_test_bit (fsck_disk_bitmap (fs), i))
continue;
reiserfs_bitmap_clear_bit (fsck_disk_bitmap (fs), i);
tmp ++;
}
reiserfs_warning (stderr, "Skipping %d blocks (super block, journal, "
"bitmaps) %d blocks will be read\n",
tmp, reiserfs_bitmap_ones (fsck_disk_bitmap (fs)));
#if 0
{
int tmp = 0;
int tmp2 = 0;
int tmp3 = 0;
int j;
for (i = 0; i < block_count; i += 32) {
if (i + 32 < block_count && !*(int *)&(fsck_disk_bitmap (fs)->bm_map[i/8])) {
tmp2 ++;
continue;
}
tmp3 ++;
for (j = 0; j < 32 && ((i + j) < block_count); j ++) {
if (!reiserfs_bitmap_test_bit (fsck_disk_bitmap (fs), i + j))
continue;
if (not_data_block (fs, i + j)) {
reiserfs_bitmap_clear_bit (fsck_disk_bitmap (fs), i + j);
tmp ++;
continue;
}
}
}
/*
for (i = 0; i < block_count; i ++) {
if (!fsck_disk_bitmap (fs)->bm_map[i / 8])
continue;
if (!reiserfs_bitmap_test_bit (fsck_disk_bitmap (fs), i))
continue;
if (not_data_block (fs, i)) {
if (reiserfs_bitmap_test_bit (fsck_disk_bitmap (fs), i))
tmp ++;
reiserfs_bitmap_clear_bit (fsck_disk_bitmap (fs), i);
continue;
}
}
*/
reiserfs_warning (stderr, "%d not data blocks cleared (skipped %d checked %d)\n", tmp, tmp2, tmp3);
}
#endif
fsck_new_bitmap (fs) = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs));
/* mark_block_used skips 0, ste the bit explicitly */
reiserfs_bitmap_set_bit (fsck_new_bitmap (fs), 0);
/* mark other skipped blocks and super block used */
for (i = 1; i <= SB_BUFFER_WITH_SB (fs)->b_blocknr; i ++)
mark_block_used (i);
/* mark bitmap blocks as used */
for (i = 0; i < SB_BMAP_NR (fs); i ++)
mark_block_used (SB_AP_BITMAP (fs)[i]->b_blocknr);
/* mark journal area as used */
for (i = 0; i < JOURNAL_BLOCK_COUNT + 1; i ++)
mark_block_used (i + SB_JOURNAL_BLOCK (fs));
uninsertable_leaf_bitmap = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs));
reiserfs_bitmap_fill (uninsertable_leaf_bitmap);
fsck_allocable_bitmap (fs) = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs));
reiserfs_bitmap_fill (fsck_allocable_bitmap (fs));
}
#define REBUILD_WARNING \
"\nThis is an experimental version of reiserfsck, MAKE A BACKUP FIRST!\n\
Don't run this program unless something is broken. \n\
Some types of random FS damage can be recovered\n\
from by this program, which basically throws away the internal nodes\n\
of the tree and then reconstructs them. This program is for use only\n\
by the desperate, and is of only beta quality. Email\n\
reiserfs@devlinux.com with bug reports. \nWill rebuild the filesystem tree\n"
/*
warning #2
you seem to be running this automatically. you are almost
certainly doing it by mistake as a result of some script that
doesn't know what it does. doing nothing, rerun without -p if you
really intend to do this. */
void warn_what_will_be_done (struct fsck_data * data)
{
fsck_progress ("\n");
/* warn about fsck mode */
switch (data->mode) {
case FSCK_CHECK:
fsck_progress ("Will read-only check consistency of the partition\n");
if (data->options & OPT_FIX_FIXABLE)
fsck_progress ("\tWill fix what can be fixed w/o --rebuild-tree\n");
break;
case FSCK_SB:
fsck_progress ("Will check SB and rebuild if it is needed\n");
break;
case FSCK_REBUILD:
{
fsck_progress (REBUILD_WARNING);
if (data->options & OPT_INTERACTIVE)
fsck_progress ("\tWill stop after every stage and ask for "
"confirmation before continuing\n");
if (data->options & OPT_SAVE_EXTERN_BITMAP)
fsck_progress ("Will save list of found leaves in '%s'\n",
data->new_bitmap_file_name);
if (data->bitmap_file_name)
fsck_progress ("\tWill try to load bitmap of leaves from file '%s'\n",
data->bitmap_file_name);
if (data->options & OPT_FIX_NON_CRITICAL)
fsck_progress ("\tWill fix following non-critical things:\n"
"\t\tunknown file modes will be set to regular files\n"
"\t\tfile sizes will be set to real file size\n"
"\t\tfiles sharing busy inode number will be relocated\n");
break;
}
case FSCK_ZERO_FILES:
fsck_progress ("Will zero existing files and mark free blocks as used\n");
}
fsck_progress ("Will put log info to '%s'\n", (data->log != stderr) ?
data->log_file_name : "stderr");
if (!user_confirmed ("Do you want to run this program?[N/Yes] (note need to type Yes):", "Yes\n"))
exit (0);
}
static void start_rebuild (reiserfs_filsys_t fs)
{
reset_super_block (fs);
init_bitmaps (fs);
proper_id_map (fs) = init_id_map ();
semantic_id_map (fs) = init_id_map ();
}
/* called before semantic pass starts */
static void end_rebuilding (reiserfs_filsys_t fs)
{
reiserfs_flush_bitmap (fsck_new_bitmap (fs), fs);
flush_objectid_map (proper_id_map (fs), fs);
set_fsck_state (fs->s_rs, TREE_IS_BUILT);
set_free_blocks (fs->s_rs, reiserfs_bitmap_zeros (fsck_new_bitmap (fs)));
mark_buffer_dirty (SB_BUFFER_WITH_SB (fs));
/* write all dirty blocks */
fsck_progress ("Syncing.."); fflush (stdout);
reiserfs_flush (fs);
fsck_progress ("done\n"); fflush (stdout);
/* release what will not be needed */
reiserfs_delete_bitmap (fsck_disk_bitmap (fs));
reiserfs_delete_bitmap (fsck_allocable_bitmap (fs));
/* FIXME: could be not a bitmap */
reiserfs_delete_bitmap (uninsertable_leaf_bitmap);
if (fsck_user_confirmed (fs, "Tree building completed. "
"You can stop now and restart from this point later "
"(this is probably not what you need). Do you want to stop? ",
"Yes\n", 0/*default*/)) {
reiserfs_close (fs);
exit (4);
}
}
static int skip_rebuilding (reiserfs_filsys_t fs)
{
if (fsck_state (fs->s_rs) == TREE_IS_BUILT) {
if (fsck_user_confirmed (fs, "S+ tree of filesystem looks built. Skip rebuilding? ", "Yes\n", 0/*default*/)) {
fsck_new_bitmap (fs) = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs));
reiserfs_fetch_disk_bitmap (fsck_new_bitmap (fs), fs);
proper_id_map (fs) = init_id_map ();
fetch_objectid_map (proper_id_map (fs), fs);
semantic_id_map (fs) = init_id_map ();
return 1;
}
}
return 0;
}
static void start_continuing (reiserfs_filsys_t fs)
{
fsck_allocable_bitmap (fs) = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs));
reiserfs_bitmap_copy (fsck_allocable_bitmap (fs), fsck_new_bitmap (fs));
}
static void the_end (reiserfs_filsys_t fs)
{
reiserfs_flush_bitmap (fsck_new_bitmap (fs), fs);
flush_objectid_map (proper_id_map (fs), fs);
set_fsck_state (fs->s_rs, 0);
set_free_blocks (fs->s_rs, reiserfs_bitmap_zeros (fsck_new_bitmap (fs)));
set_state (fs->s_rs, REISERFS_VALID_FS);
mark_buffer_dirty (SB_BUFFER_WITH_SB (fs));
/* write all dirty blocks */
fsck_progress ("Syncing.."); fflush (stderr);
reiserfs_flush (fs);
sync ();
fsck_progress ("done\n"); fflush (stderr);
reiserfs_delete_bitmap (fsck_new_bitmap (fs));
free_id_map (&proper_id_map(fs));
if (semantic_id_map(fs))
free_id_map (&semantic_id_map(fs));
reiserfs_close (fs);
fsck_progress ("Done\n"); fflush (stderr);
}
static void rebuild_tree (reiserfs_filsys_t fs)
{
if (is_mounted (fs->file_name)) {
fsck_progress ("rebuild_tree: can not rebuild tree of mounted filesystem\n");
return;
}
reiserfs_reopen (fs, O_RDWR);
/* FIXME: for regular file take care of of file size */
/* rebuild starts with journal replaying */
reiserfs_replay_journal (fs);
if (!skip_rebuilding (fs)) {
fsck_progress ("Rebuilding..\n");
start_rebuild (fs);
pass_0 (fs);
/* passes 1 and 2. building of the tree */
pass_1_pass_2_build_the_tree ();
end_rebuilding (fs);
}
/* re-building of filesystem tree is now separated of sematic pass of the
fsck */
start_continuing (fs);
/* 3. semantic pass */
pass_3_semantic ();
/* if --lost+found is set - link unaccessed directories to lost+found
directory */
pass_3a_look_for_lost (fs);
/* 4. look for unaccessed items in the leaves */
pass_4_check_unaccessed_items ();
the_end (fs);
}
static void zero_files (reiserfs_filsys_t fs)
{
init_bitmaps (fs);
reiserfs_reopen (fs, O_RDWR);
pass_0 (fs);
}
/* check umounted or read-only mounted filesystems only */
static void check_fs (reiserfs_filsys_t fs)
{
if (!is_mounted (fs->file_name)) {
/* filesystem is not mounted, replay journal before checking */
reiserfs_reopen (fs, O_RDWR);
reiserfs_replay_journal (fs);
reiserfs_reopen (fs, O_RDONLY);
} else {
/* filesystem seems mounted. we do not check filesystems mounted with
r/w permissions */
if (!is_mounted_read_only (fs->file_name)) {
fsck_progress ("Device %s is mounted w/ write permissions, can not check it\n",
fs->file_name);
reiserfs_close (fs);
exit (0);
}
fsck_progress ("Filesystem seems mounted read-only. Skipping journal replay..\n");
if (fsck_fix_fixable (fs)) {
fsck_progress ("--fix-fixable ignored\n");
stats(fs)->options &= ~OPT_FIX_FIXABLE;
}
}
fsck_disk_bitmap (fs) = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs));
reiserfs_fetch_disk_bitmap (fsck_disk_bitmap (fs), fs);
if (fsck_fix_fixable (fs))
reiserfs_reopen (fs, O_RDWR);
/*proper_id_map (fs) = init_id_map ();*/
semantic_id_map (fs) = init_id_map ();
check_fs_tree (fs);
semantic_check ();
reiserfs_delete_bitmap (fsck_disk_bitmap (fs));
/*free_id_map (proper_id_map (fs));*/
free_id_map (&semantic_id_map (fs));
reiserfs_close (fs);
}
#include <sys/resource.h>
int main (int argc, char * argv [])
{
char * file_name;
struct fsck_data * data;
struct rlimit rlim = {0xffffffff, 0xffffffff};
print_banner ("reiserfsck");
/* this is only needed (and works) when running under 2.4 on regural files */
if (setrlimit (RLIMIT_FSIZE, &rlim) == -1) {
reiserfs_warning (stderr, "could not setrlimit: %m");
}
data = getmem (sizeof (struct fsck_data));
file_name = parse_options (data, argc, argv);
if (data->mode == DO_NOTHING) {
freemem (data);
return 0;
}
warn_what_will_be_done (data); /* and ask confirmation Yes */
fs = reiserfs_open (file_name, O_RDONLY, 0, data);
if (!fs)
die ("reiserfsck: could not open filesystem on \"%s\"", file_name);
if (fsck_mode (fs) == FSCK_SB) {
reiserfs_reopen (fs, O_RDWR);
rebuild_sb (fs);
reiserfs_close (fs);
return 0;
}
if (no_reiserfs_found (fs)) {
fsck_progress ("reiserfsck: --rebuild-sb may restore reiserfs super block\n");
reiserfs_close (fs);
return 0;
}
fs->block_allocator = reiserfsck_reiserfs_new_blocknrs;
fs->block_deallocator = reiserfsck_reiserfs_free_block;
if (fsck_mode (fs) == FSCK_CHECK) {
check_fs (fs);
return 0;
}
#ifdef FAST_REBUILD_READY /* and tested */
if (opt_fsck_mode == FSCK_FAST_REBUILD) {
__u32 root_block = SB_ROOT_BLOCK(fs);
reopen_read_write (file_name);
printf ("Replaying log..");
reiserfs_replay_journal (fs);
printf ("done\n");
if (opt_fsck == 1)
printf ("ReiserFS : checking %s\n",file_name);
else
printf ("Rebuilding..\n");
reset_super_block (fs);
SB_DISK_SUPER_BLOCK(fs)->s_root_block = cpu_to_le32 (root_block);
init_bitmaps (fs);
/* 1,2. building of the tree */
recover_internal_tree(fs);
/* 3. semantic pass */
pass3_semantic ();
/* if --lost+found is set - link unaccessed directories to
lost+found directory */
look_for_lost (fs);
/* 4. look for unaccessed items in the leaves */
pass4_check_unaccessed_items ();
end_fsck ();
}
#endif /* FAST REBUILD READY */
if (fsck_mode (fs) == FSCK_ZERO_FILES)
zero_files (fs);
if (fsck_mode (fs) != FSCK_REBUILD && fsck_mode (fs) != DO_TEST)
return 0;
/* the --rebuild-tree is here */
rebuild_tree (fs);
return 0;
}
+1502
View File
File diff suppressed because it is too large. Load diff
+881
View File
@@ -0,0 +1,881 @@
/*
* Copyright 1996-1999 Hans Reiser
*/
#include "fsck.h"
#include <stdlib.h>
reiserfs_bitmap_t bad_unfm_in_tree_once_bitmap;
//int step = 0; // 0 - find stat_data or any item ; 1 - find item ; 2 - already found
/* allocates buffer head and copy buffer content */
struct buffer_head * make_buffer (int dev, int blocknr, int size, char * data)
{
struct buffer_head * bh;
bh = getblk (dev, blocknr, size);
if (buffer_uptodate (bh))
return bh;
// die ("make_buffer: uptodate buffer found");
memcpy (bh->b_data, data, size);
set_bit (BH_Uptodate, (char *)&bh->b_state);
return bh;
}
int find_not_of_one_file(struct key * to_find, struct key * key)
{
if ((to_find->k_objectid != -1) &&
(to_find->k_objectid != key->k_objectid))
return 1;
if ((to_find->k_dir_id != -1) &&
(to_find->k_dir_id != key->k_dir_id))
return 1;
return 0;
}
int is_item_reachable (struct item_head * ih)
{
return ih_reachable (ih) ? 1 : 0;
}
void mark_item_unreachable (struct item_head * ih)
{
mark_ih_unreachable (ih);
if (is_indirect_ih (ih))
set_free_space (ih, 0);
}
void mark_item_reachable (struct item_head * ih, struct buffer_head * bh)
{
mark_ih_ok (ih);
mark_buffer_dirty (bh);
}
static void stat_data_in_tree (struct buffer_head *bh,
struct item_head * ih)
{
#if 0
__u32 objectid;
objectid = le32_to_cpu (ih->ih_key.k_objectid);
if (mark_objectid_really_used (proper_id_map (fs), objectid)) {
stat_shared_objectid_found (fs);
mark_objectid_really_used (shared_id_map (fs), objectid);
}
#endif
zero_nlink (ih, B_I_PITEM (bh, ih));
}
/* this just marks blocks pointed by an indirect item as used in the
new bitmap */
static void indirect_in_tree (struct buffer_head * bh,
struct item_head * ih)
{
int i;
__u32 * unp;
unsigned long unfm_ptr;
unp = (__u32 *)B_I_PITEM (bh, ih);
for (i = 0; i < I_UNFM_NUM (ih); i ++) {
unfm_ptr = le32_to_cpu (unp[i]);
if (unfm_ptr == 0)
continue;
if (still_bad_unfm_ptr_1 (unfm_ptr))
reiserfs_panic ("mark_unformatted_used: (%lu: %k) "
"still has bad pointer %lu",
bh->b_blocknr, &ih->ih_key, unfm_ptr);
mark_block_used (unfm_ptr);
}
}
static void leaf_is_in_tree_now (struct buffer_head * bh)
{
item_action_t actions[] = {stat_data_in_tree, indirect_in_tree, 0, 0};
mark_block_used ((bh)->b_blocknr);
for_every_item (bh, mark_item_unreachable, actions);
stats(fs)->inserted_leaves ++;
mark_buffer_dirty (bh);
}
static void insert_pointer (struct buffer_head * bh, struct path * path)
{
struct item_head * ih;
char * body;
int zeros_number;
int retval;
struct tree_balance tb;
init_tb_struct (&tb, fs, path, 0x7fff);
/* fix_nodes & do_balance must work for internal nodes only */
ih = 0;
retval = fix_nodes (/*tb.transaction_handle,*/ M_INTERNAL, &tb, ih);
if (retval != CARRY_ON)
die ("insert_pointer: fix_nodes failed with retval == %d", retval);
/* child_pos: we insert after position child_pos: this feature of the insert_child */
/* there is special case: we insert pointer after
(-1)-st key (before 0-th key) in the parent */
if (PATH_LAST_POSITION (path) == 0 && path->pos_in_item == 0)
PATH_H_B_ITEM_ORDER (path, 0) = -1;
else {
if (PATH_H_PPARENT (path, 0) == 0)
PATH_H_B_ITEM_ORDER (path, 0) = 0;
/* PATH_H_B_ITEM_ORDER (path, 0) = PATH_H_PPARENT (path, 0) ? PATH_H_B_ITEM_ORDER (path, 0) : 0;*/
}
ih = 0;
body = (char *)bh;
//memmode = 0;
zeros_number = 0;
do_balance (&tb, ih, body, M_INTERNAL, zeros_number);
leaf_is_in_tree_now (bh);
}
/* return 1 if left and right can be joined. 0 otherwise */
int balance_condition_fails (struct buffer_head * left, struct buffer_head * right)
{
if (B_FREE_SPACE (left) >= B_CHILD_SIZE (right) -
(are_items_mergeable (B_N_PITEM_HEAD (left, B_NR_ITEMS (left) - 1), B_N_PITEM_HEAD (right, 0), left->b_size) ? IH_SIZE : 0))
return 1;
return 0;
}
/* return 1 if new can be joined with last node on the path or with
its right neighbor, 0 otherwise */
int balance_condition_2_fails (struct buffer_head * new, struct path * path)
{
struct buffer_head * bh;
struct key * right_dkey;
int pos, used_space;
bh = PATH_PLAST_BUFFER (path);
if (balance_condition_fails (bh, new))
/* new node can be joined with last buffer on the path */
return 1;
/* new node can not be joined with its left neighbor */
right_dkey = uget_rkey (path);
if (right_dkey == 0)
/* there is no right neighbor */
return 0;
pos = PATH_H_POSITION (path, 1);
if (pos == B_NR_ITEMS (bh = PATH_H_PBUFFER (path, 1))) {
/* we have to read parent of right neighbor. For simplicity we
call search_by_key, which will read right neighbor as well */
INITIALIZE_PATH(path_to_right_neighbor);
if (usearch_by_key (fs, right_dkey, &path_to_right_neighbor) != ITEM_FOUND)
die ("get_right_neighbor_free_space: invalid right delimiting key");
used_space = B_CHILD_SIZE (PATH_PLAST_BUFFER (&path_to_right_neighbor));
pathrelse (&path_to_right_neighbor);
}
else
used_space = B_N_CHILD (bh, pos + 1)->dc_size;
if (B_FREE_SPACE (new) >= used_space -
(are_items_mergeable (B_N_PITEM_HEAD (new, B_NR_ITEMS (new) - 1), (struct item_head *)right_dkey, new->b_size) ? IH_SIZE : 0))
return 1;
return 0;
}
static void get_max_buffer_key (struct buffer_head * bh, struct key * key)
{
struct item_head * ih;
ih = B_N_PITEM_HEAD (bh, B_NR_ITEMS (bh) - 1);
copy_key (key, &(ih->ih_key));
if (is_direntry_key (key)) {
/* copy 3-rd and 4-th key components of the last entry */
//set_le_key_k_offset (ih_version(ih), key, B_I_DEH (bh, ih)[I_ENTRY_COUNT (ih) - 1].deh_offset);
//set_le_key_k_type (ih_version(ih), key, TYPE_DIRENTRY);
set_offset (KEY_FORMAT_1, key,
le32_to_cpu (B_I_DEH (bh, ih)[ih_entry_count (ih) - 1].deh_offset));
} else if (!is_stat_data_key (key))
/* get key of the last byte, which is contained in the item */
set_offset (key_format (key), key, get_offset (key) + get_bytes_number (ih, bh->b_size) - 1);
//set_le_key_k_offset(ih_version(ih), key,
// le_key_k_offset(ih_version(ih), key) + get_bytes_number (bh, ih, 0, CHECK_FREE_BYTES) - 1 );
}
static int tree_is_empty (void)
{
return (SB_ROOT_BLOCK (fs) == ~0) ? 1 : 0;
}
static void make_single_leaf_tree (struct buffer_head * bh)
{
/* tree is empty, make tree root */
set_root_block (fs->s_rs, bh->b_blocknr);
set_tree_height (fs->s_rs, 2);
mark_buffer_dirty (fs->s_sbh);
leaf_is_in_tree_now (bh);
}
/* inserts pointer to leaf into tree if possible. If not, marks node as
uninsertable in special bitmap */
static void try_to_insert_pointer_to_leaf (struct buffer_head * new_bh)
{
INITIALIZE_PATH (path);
struct buffer_head * bh; /* last path buffer */
struct key * first_bh_key, last_bh_key; /* first and last keys of new buffer */
struct key last_path_buffer_last_key, * right_dkey;
int ret_value;
if (tree_is_empty () == 1) {
make_single_leaf_tree (new_bh);
return;
}
first_bh_key = B_N_PKEY (new_bh, 0);
/* try to find place in the tree for the first key of the coming node */
ret_value = usearch_by_key (fs, first_bh_key, &path);
if (ret_value == ITEM_FOUND)
goto cannot_insert;
/* get max key in the new node */
get_max_buffer_key (new_bh, &last_bh_key);
bh = PATH_PLAST_BUFFER (&path);
if (comp_keys (B_N_PKEY (bh, 0), &last_bh_key) == 1/* first is greater*/) {
/* new buffer falls before the leftmost leaf */
if (balance_condition_fails (new_bh, bh))
goto cannot_insert;
if (uget_lkey (&path) != 0 || PATH_LAST_POSITION (&path) != 0)
die ("try_to_insert_pointer_to_leaf: bad search result");
path.pos_in_item = 0;
goto insert;
}
/* get max key of buffer, that is in tree */
get_max_buffer_key (bh, &last_path_buffer_last_key);
if (comp_keys (&last_path_buffer_last_key, first_bh_key) != -1/* second is greater */)
/* first key of new buffer falls in the middle of node that is in tree */
goto cannot_insert;
right_dkey = uget_rkey (&path);
if (right_dkey && comp_keys (right_dkey, &last_bh_key) != 1 /* first is greater */)
goto cannot_insert;
if (balance_condition_2_fails (new_bh, &path))
goto cannot_insert;
insert:
insert_pointer (new_bh, &path);
goto out;
cannot_insert:
/* statistic */
stats (fs)->uninsertable_leaves ++;
mark_block_uninsertable (new_bh->b_blocknr);
out:
pathrelse (&path);
return;
}
/* everything should be correct already in the leaf but contents of indirect
items. So we only
1. zero slots pointing to a leaf
2. zero pointers to blocks which are pointed already
3. what we should do with directory entries hashed by another hash?
they are deleted for now
*/
static void pass1_correct_leaf (reiserfs_filsys_t s,
struct buffer_head * bh)
{
int i, j;
struct item_head * ih;
__u32 * ind_item;
unsigned long unfm_ptr;
int dirty = 0;
ih = B_N_PITEM_HEAD (bh, 0);
for (i = 0; i < B_NR_ITEMS (bh); i ++, ih ++) {
if (is_direntry_ih (ih)) {
struct reiserfs_de_head * deh;
char * name;
int name_len;
int hash_code;
deh = B_I_DEH (bh, ih);
for (j = 0; j < ih_entry_count (ih); j ++) {
name = name_in_entry (deh + j, j);
name_len = name_length (ih, deh + j, j);
if ((j == 0 && is_dot (name, name_len)) ||
(j == 1 && is_dot_dot (name, name_len))) {
continue;
}
hash_code = find_hash_in_use (name, name_len,
GET_HASH_VALUE (deh_offset (deh + j)),
rs_hash (fs->s_rs));
if (hash_code != rs_hash (fs->s_rs)) {
fsck_log ("pass1: block %lu, %H, entry \"%.*s\" "
"hashed with %s whereas proper hash is %s\n",
bh->b_blocknr, ih, name_len, name,
code2name (hash_code), code2name (rs_hash (fs->s_rs)));
if (ih_entry_count (ih) == 1) {
delete_item (fs, bh, i);
i --;
ih --;
break;
} else {
cut_entry (fs, bh, i, j, 1);
j --;
deh = B_I_DEH (bh, ih);
}
}
}
continue;
}
if (!is_indirect_ih (ih))
continue;
/* correct indirect items */
ind_item = (__u32 *)B_I_PITEM (bh, ih);
for (j = 0; j < I_UNFM_NUM (ih); j ++, ind_item ++) {
unfm_ptr = le32_to_cpu (*ind_item);
if (!unfm_ptr)
continue;
/* this corruption of indirect item had to be fixed in pass0 */
if (not_data_block (s, unfm_ptr) || unfm_ptr >= SB_BLOCK_COUNT (s))
/*!was_block_used (unfm_ptr))*/
reiserfs_panic ("pass1_correct_leaf: (%lu: %k), %d-th slot is not fixed",
bh->b_blocknr, &ih->ih_key, j);
/* 1. zero slots pointing to a leaf */
if (is_used_leaf (unfm_ptr)) {
dirty ++;
*ind_item = 0;
stats(fs)->wrong_pointers ++;
continue;
}
/* 2. zero pointers to blocks which are pointed already */
if (is_bad_unformatted (unfm_ptr)) {
/* this unformatted pointed more than once. Did we see it already? */
if (!is_bad_unfm_in_tree_once (unfm_ptr))
/* keep first reference to it and mark about that in
special bitmap */
mark_bad_unfm_in_tree_once (unfm_ptr);
else {
/* Yes, we have seen this pointer already, zero other pointers to it */
dirty ++;
*ind_item = 0;
stats(fs)->wrong_pointers ++;
continue;
}
}
}
}
if (dirty)
mark_buffer_dirty (bh);
}
/*######### has to die ##########*/
/* append item to end of list. Set head if it is 0. For indirect item
set wrong unformatted node pointers to 0 */
void save_item (struct si ** head, struct buffer_head * bh, struct item_head * ih, char * item)
{
struct si * si, * cur;
if (is_bad_item (bh, ih, item/*, fs->s_blocksize, fs->s_dev*/)) {
return;
}
if (is_indirect_ih (ih)) {
fsck_progress ("save_item: %H (should not happen)\n", ih);
}
stats(fs)->saved_on_pass1 ++;
si = getmem (sizeof (*si));
si->si_dnm_data = getmem (ih_item_len(ih));
/*si->si_blocknr = blocknr;*/
memcpy (&(si->si_ih), ih, IH_SIZE);
memcpy (si->si_dnm_data, item, ih_item_len(ih));
// changed by XB
si->last_known = NULL;
if (*head == 0)
*head = si;
else {
cur = *head;
// changed by XB
// while (cur->si_next)
// cur = cur->si_next;
{
int count = 0;
int speedcount = 0;
while (cur->si_next) {
if (cur->last_known!=NULL) {
cur = cur->last_known; // speed up to the end if the chain
speedcount++;
} else {
cur = cur->si_next;
count++;
}
}
if ((*head)!=cur) // no self referencing loop please
(*head)->last_known = cur;
}
cur->si_next = si;
}
return;
}
static void save_items (struct si ** head, struct buffer_head * bh)
{
int i;
struct item_head * ih;
ih = B_N_PITEM_HEAD (bh, 0);
for (i = 0; i < B_NR_ITEMS (bh); i ++, ih ++) {
save_item (head, bh, ih, B_I_PITEM (bh, ih));
}
}
struct si * remove_saved_item (struct si * si)
{
struct si * tmp = si->si_next;
freemem (si->si_dnm_data);
freemem (si);
return tmp;
}
/* insert_item_separately */
static void put_saved_items_into_tree_1 (struct si * si)
{
while (si) {
insert_item_separately (&(si->si_ih), si->si_dnm_data,
0/*was not in tree*/);
si = remove_saved_item (si);
}
}
/* reads the device by set of 8 blocks, takes leaves and tries to
insert them into tree */
void pass_1_pass_2_build_the_tree (void)
{
struct buffer_head * bh;
int i;
int what_node;
unsigned long done = 0, total;
struct si * saved_items = 0;
if (fsck_log_file (fs) != stderr)
fsck_log ("####### Pass 1 #######\n");
bad_unfm_in_tree_once_bitmap = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs));
/* on pass0 we have found that amount of leaves */
total = how_many_leaves_were_there ();
fsck_progress ("\nPass1:\n");
/* read all leaves found on the pass 0 */
for (i = 0; i < SB_BLOCK_COUNT (fs); i ++) {
if (!is_used_leaf (i))
continue;
print_how_far (&done, total, 1, fsck_quiet (fs));
/* at least one of nr_to_read blocks is to be checked */
bh = bread (fs->s_dev, i, fs->s_blocksize);
if (!bh) {
/* we were reading one block at time, and failed, so mark
block bad */
fsck_progress ("pass1: reading block %lu failed\n", i);
continue;
}
what_node = who_is_this (bh->b_data, fs->s_blocksize);
if ( what_node != THE_LEAF ) {
fsck_progress ("build_the_tree: nothing but leaves are expected. "
"Block %lu - %s\n", i,
(what_node == THE_INTERNAL) ? "internal" : "??");
brelse (bh);
continue;
}
if (is_block_used (i))
/* block is in new tree already */
die ("build_the_tree: leaf (%lu) is in tree already\n", i);
/* fprintf (block_list, "leaf %d\n", i + j);*/
stats(fs)->analyzed ++;
/* the leaf may still contain indirect items with wrong
slots. Fix that */
pass1_correct_leaf (fs, bh);
if (node_item_number (bh) == 0) {
/* all items were deleted on pass 0 or pass 1 */
mark_buffer_clean (bh);
brelse (bh);
continue;
}
if (is_leaf_bad (bh)) {
/* FIXME: will die */
fsck_log ("pass1: (is_leaf_bad) bad leaf (%lu)\n", bh->b_blocknr);
/* Save good items only to put them into tree at the
end of this pass */
save_items (&saved_items, bh);
brelse (bh);
continue;
}
try_to_insert_pointer_to_leaf (bh);
brelse (bh);
}
#if 0
/* read all leaves found on the pass 0 */
for (i = 0; i < SB_BLOCK_COUNT (fs); i += nr_to_read) {
to_scan = how_many_to_scan (fs, i, nr_to_read);
if (to_scan) {
print_how_far (&done, total, to_scan, fsck_quiet (fs));
/* at least one of nr_to_read blocks is to be checked */
bbh = bread (fs->s_dev, i / nr_to_read, fs->s_blocksize * nr_to_read);
if (bbh) {
for (j = 0; j < nr_to_read; j ++) {
if (!is_used_leaf (i + j))
continue;
data = bbh->b_data + j * fs->s_blocksize;
what_node = who_is_this (data, fs->s_blocksize);
if ( what_node != THE_LEAF ) {
fsck_progress ("build_the_tree: nothing but leaves are expected. "
"Block %lu - %s\n", i + j,
(what_node == THE_INTERNAL) ? "internal" : "??");
continue;
}
if (is_block_used (i + j))
/* block is in new tree already */
die ("build_the_tree: leaf (%lu) is in tree already\n",
i + j);
/* fprintf (block_list, "leaf %d\n", i + j);*/
bh = make_buffer (fs->s_dev, i + j, fs->s_blocksize, data);
stats(fs)->analyzed ++;
/* the leaf may still contain indirect items with wrong
slots. Fix that */
pass1_correct_leaf (fs, bh);
if (node_item_number (bh) == 0) {
/* all items were deleted on pass 0 or pass 1 */
mark_buffer_clean (bh);
brelse (bh);
continue;
}
if (is_leaf_bad (bh)) {
/* FIXME: will die */
fsck_log ("pass1: (is_leaf_bad) bad leaf (%lu)\n", bh->b_blocknr);
/* Save good items only to put them into tree at the
end of this pass */
save_items (&saved_items, bh);
brelse (bh);
continue;
}
try_to_insert_pointer_to_leaf (bh);
brelse (bh);
}
bforget (bbh);
} else {
done -= to_scan;
/* bread failed */
if (nr_to_read != 1) {
/* we tryied to read bunch of blocks. Try to read them by one */
nr_to_read = 1;
i --;
continue;
} else {
/* we were reading one block at time, and failed, so mark
block bad */
fsck_progress ("pass0: block %lu is bad, marked used\n", i);
}
}
}
if (nr_to_read == 1 && ((i + 1) % NR_TO_READ) == 0) {
/* we have read NR_TO_READ blocks one at time, switch back to
reading NR_TO_READ blocks at time */
i -= (NR_TO_READ - 1);
nr_to_read = NR_TO_READ;
}
}
#endif
fsck_progress ("\n");
/* Pass 1a (this should die) */
/* put saved items into tree. These items were in leaves, those could not
be inserted into tree because some indirect items point to those
leaves. Rather than lookup for corresponding unfm pointers in the tree,
we save items of those leaves and put them into tree separately */
if (how_many_items_were_saved ()) {
fsck_progress ("There were %lu saved items\nPass 1a - ",
how_many_items_were_saved ());
fflush (stdout);
put_saved_items_into_tree_1 (saved_items);
}
stage_report (1, fs);
/* end of pass 1 */
if (SB_ROOT_BLOCK(fs) == -1)
die ("\n\nNo reiserfs metadata found");
/* pass 2 */
pass_2_take_bad_blocks_put_into_tree ();
flush_buffers ();
stage_report (2, fs);
fsck_progress ("Tree is built. Checking it - "); fflush (stdout);
reiserfsck_check_pass1 ();
fsck_progress ("done\n"); fflush (stdout);
reiserfs_delete_bitmap (bad_unfm_in_tree_once_bitmap);
}
#if 0
/* pass the S+ tree of filesystem */
void recover_internal_tree (struct super_block * s)
{
check_internal_structure(s);
build_the_tree();
}
#endif
void rebuild_sb (reiserfs_filsys_t fs)
{
int version;
struct buffer_head * bh;
struct reiserfs_super_block * rs;
__u32 blocks;
if (no_reiserfs_found (fs)) {
char * answer = 0;
size_t n = 0;
printf("\nwhat is version of ReiserFS you use[1-4]\n"
"\t(1) 3.6.x\n"
"\t(2) >=3.5.9\n"
"\t(3) < 3.5.9 converted to new format\n"
"\t(4) < 3.5.9\n"
"\t(X) exit\n");
getline (&answer, &n, stdin);
version = atoi (answer);
if (version < 1 || version > 4)
die ("rebuild_sb: wrong version");
fs->s_blocksize = 4096;
switch(version){
case 1:
case 2:
bh = getblk (fs->s_dev, (REISERFS_DISK_OFFSET_IN_BYTES / fs->s_blocksize),
fs->s_blocksize);
break;
case 3:
case 4:
bh = getblk (fs->s_dev, (2), fs->s_blocksize);
break;
default:
exit(0);
}
if (!bh)
die ("rebuild_sb: can't bread");
rs = (struct reiserfs_super_block *)bh->b_data;
fs->s_rs = rs;
}
else
{
/* reiserfs super block is found */
version = check_sb(fs);
if (!user_confirmed ("\nDo you want to remake your super block\n"
"(say no if you use resizer)[Yes/no]: ", "Yes\n"))
return;
rs = fs->s_rs;
bh = fs->s_sbh;
}
// set block number on the device and number of bitmap blocks needed to
// address all blocks
blocks = (count_blocks ("", fs->s_blocksize, fs->s_dev) / 8) * 8;
set_block_count (rs, blocks);
//rs->s_block_count = cpu_to_le32(blocks);
set_bmap_nr (rs, (blocks + (fs->s_blocksize * 8 - 1)) / (fs->s_blocksize * 8));
set_journal_size(rs, JOURNAL_BLOCK_COUNT);
//rs->s_bmap_nr = cpu_to_le16( blocks / (g_sb.s_blocksize * 8) +
// ((blocks % (g_sb.s_blocksize * 8)) ? 1 : 0) );
switch (version){
case 1:
// super block v2 at 64k offset
set_blocksize (rs, fs->s_blocksize);
strncpy (rs->s_v1.s_magic, REISER2FS_SUPER_MAGIC_STRING,
strlen(REISER2FS_SUPER_MAGIC_STRING));
set_journal_start (rs, get_journal_start_must (fs->s_blocksize));
set_version (rs, REISERFS_VERSION_2);
set_objectid_map_max_size (rs, (fs->s_blocksize - SB_SIZE) / sizeof(__u32) / 2 * 2);
break;
case 2:
// super block v1 at 64k offset
set_blocksize (rs, fs->s_blocksize);
strncpy (rs->s_v1.s_magic, REISERFS_SUPER_MAGIC_STRING,
strlen(REISERFS_SUPER_MAGIC_STRING));
set_journal_start (rs, get_journal_start_must (fs->s_blocksize));
set_version (rs, REISERFS_VERSION_1);
set_objectid_map_max_size (rs, (fs->s_blocksize - SB_SIZE_V1) / sizeof(__u32) / 2 * 2);
break;
case 3:
// super block v2 at 8k offset
set_blocksize (rs, fs->s_blocksize);
strncpy (rs->s_v1.s_magic, REISER2FS_SUPER_MAGIC_STRING,
strlen(REISER2FS_SUPER_MAGIC_STRING));
set_journal_start (rs, get_journal_old_start_must (rs));
set_version (rs, REISERFS_VERSION_2);
set_objectid_map_max_size (rs, (fs->s_blocksize - SB_SIZE) / sizeof(__u32) / 2 * 2);
break;
case 4:
// super block v1 at 8k offset
set_blocksize (rs, fs->s_blocksize);
strncpy (rs->s_v1.s_magic, REISERFS_SUPER_MAGIC_STRING,
strlen(REISERFS_SUPER_MAGIC_STRING));
set_journal_start (rs, get_journal_old_start_must (rs));
set_version (rs, REISERFS_VERSION_1);
set_objectid_map_max_size (rs, (fs->s_blocksize - SB_SIZE_V1) / sizeof(__u32) / 2 * 2);
break;
}
print_block (stderr, fs, bh);
if (user_confirmed ("Is this ok ? [N/Yes]: ", "Yes\n")) {
mark_buffer_uptodate (bh, 1);
mark_buffer_dirty (bh);
bwrite (bh);
fsck_progress ("\nDo not forget to run reiserfsck --rebuild-tree\n\n");
} else
fsck_progress ("Super block was not written\n");
brelse (bh);
}
/*
check_sb and rebuild-sb don't touch these fields:
__u32 s_journal_dev;
__u32 s_journal_trans_max ;
__u32 s_journal_block_count ;
__u32 s_journal_max_batch ;
__u32 s_journal_max_commit_age ;
__u32 s_journal_max_trans_age ;
others are checked and set in either rebuild_sb or rebuild-tree
*/
+485
View File
@@ -0,0 +1,485 @@
/*
* Copyright 1996-2001 Hans Reiser
*/
#include "fsck.h"
/* on pass2 we take leaves which could not be inserted into tree
during pass1 and insert each item separately. It is possible that
items of different objects with the same key can be found. We treat
that in the following way: we put it into tree with new key and
link it into /lost+found directory with name made of dir,oid. When
coming item is a directory - we delete object from the tree, put it
back with different key, link it to /lost+found directory and
insert directory as it is */
/* relocation rules: we have an item (it is taken from "non-insertable"
leaf). It has original key yet. We check to see if object with this
key is remapped. Object can be only remapped if it is not a piece
of directory */
/* in list of this structures we store what has been
relocated. */
struct relocated {
unsigned long old_dir_id;
unsigned long old_objectid;
unsigned long new_objectid;
/*mode_t mode;*/
struct relocated * next;
};
/* all relocated files will be linked into lost+found directory at the
beginning of semantic pass */
struct relocated * relocated_list;
/* return objectid the object has to be remapped with */
__u32 objectid_for_relocation (struct key * key)
{
struct relocated * cur;
cur = relocated_list;
while (cur) {
if (cur->old_dir_id == key->k_dir_id &&
cur->old_objectid == key->k_objectid)
/* object is relocated already */
return cur->new_objectid;
cur = cur->next;
}
cur = getmem (sizeof (struct relocated));
cur->old_dir_id = key->k_dir_id;
cur->old_objectid = key->k_objectid;
cur->new_objectid = get_unused_objectid (fs);
cur->next = relocated_list;
relocated_list = cur;
fsck_log ("relocation: (%K) is relocated to (%lu, %lu)\n",
key, key->k_dir_id, cur->new_objectid);
return cur->new_objectid;
}
/* this item is in tree. All unformatted pointer are correct. Do not
check them */
static void save_item_2 (struct si ** head, struct item_head * ih,
char * item, __u32 blocknr)
{
struct si * si, * cur;
si = getmem (sizeof (*si));
si->si_dnm_data = getmem (ih_item_len(ih));
/*si->si_blocknr = blocknr;*/
memcpy (&(si->si_ih), ih, IH_SIZE);
memcpy (si->si_dnm_data, item, ih_item_len(ih));
if (*head == 0)
*head = si;
else {
cur = *head;
while (cur->si_next)
cur = cur->si_next;
cur->si_next = si;
}
return;
}
struct si * save_and_delete_file_item (struct si * si, struct path * path)
{
struct buffer_head * bh = PATH_PLAST_BUFFER (path);
struct item_head * ih = PATH_PITEM_HEAD (path);
save_item_2 (&si, ih, B_I_PITEM (bh, ih), bh->b_blocknr);
/* delete item temporary - do not free unformatted nodes */
reiserfsck_delete_item (path, 1/*temporary*/);
return si;
}
/* check whether there are any directory items with this key */
static int should_relocate (struct item_head * ih)
{
struct key key;
struct key * rkey;
struct path path;
struct item_head * path_ih;
/* starting with the leftmost item with this key */
key = ih->ih_key;
set_type_and_offset (KEY_FORMAT_1, &key, SD_OFFSET, TYPE_STAT_DATA);
while (1) {
usearch_by_key (fs, &key, &path);
if (get_item_pos (&path) == B_NR_ITEMS (get_bh (&path))) {
rkey = uget_rkey (&path);
if (rkey && !not_of_one_file (&key, rkey)) {
/* file continues in the right neighbor */
key = *rkey;
pathrelse (&path);
continue;
}
/* there is no more items with this key */
pathrelse (&path);
break;
}
path_ih = get_ih (&path);
if (not_of_one_file (&key, &(path_ih->ih_key))) {
/* there are no more item with this key */
pathrelse (&path);
break;
}
/* ok, item found, but make sure that it is not a directory one */
if ((is_stat_data_ih (path_ih) && !not_a_directory (get_item (&path))) ||
(is_direntry_ih (path_ih))) {
/* item of directory found. so, we have to relocate the file */
pathrelse (&path);
return 1;
}
key = path_ih->ih_key;
set_offset (KEY_FORMAT_1, &key, get_offset (&key) + 1);
pathrelse (&path);
}
return 0;
}
/* delete all items (but directory ones) with the same key 'ih' has
(including stat data of not a directory) and put them back at the
other place */
void relocate_file (struct item_head * ih, int change_ih)
{
struct key key;
struct key * rkey;
struct path path;
struct item_head * path_ih;
struct si * si;
__u32 new_objectid;
/* starting with the leftmost one - look for all items of file,
store them and delete */
key = ih->ih_key;
set_type_and_offset (KEY_FORMAT_1, &key, SD_OFFSET, TYPE_STAT_DATA);
si = 0;
while (1) {
usearch_by_key (fs, &key, &path);
if (get_item_pos (&path) == B_NR_ITEMS (get_bh (&path))) {
rkey = uget_rkey (&path);
if (rkey && !not_of_one_file (&key, rkey)) {
/* file continues in the right neighbor */
key = *rkey;
pathrelse (&path);
continue;
}
/* there is no more items with this key */
pathrelse (&path);
break;
}
path_ih = get_ih (&path);
if (not_of_one_file (&key, &(path_ih->ih_key))) {
/* there are no more item with this key */
pathrelse (&path);
break;
}
/* ok, item found, but make sure that it is not a directory one */
if ((is_stat_data_ih (path_ih) && !not_a_directory (get_item (&path))) ||
(is_direntry_ih (path_ih))) {
/* item of directory found. Leave it in the tree */
key = path_ih->ih_key;
set_offset (KEY_FORMAT_1, &key, get_offset (&key) + 1);
pathrelse (&path);
continue;
}
si = save_and_delete_file_item (si, &path);
}
if (si || change_ih) {
int moved_items;
struct key old, new;
/* get new objectid for relocation or get objectid with which file
was relocated already */
new_objectid = objectid_for_relocation (&ih->ih_key);
if (change_ih)
ih->ih_key.k_objectid = new_objectid;
moved_items = 0;
/* put all items removed back into tree */
while (si) {
/*fsck_log ("relocate_file: move %H to ", &si->si_ih);*/
old = si->si_ih.ih_key;
si->si_ih.ih_key.k_objectid = new_objectid;
new = si->si_ih.ih_key;
/*fsck_log ("%H\n", &si->si_ih);*/
insert_item_separately (&(si->si_ih), si->si_dnm_data, 1/*was in tree*/);
si = remove_saved_item (si);
moved_items ++;
}
if (moved_items)
fsck_log ("relocate_file: %d items of file %K moved to %K\n",
moved_items, &old, &new);
}
}
/* this works for both new and old stat data */
#define st_mode(sd) le16_to_cpu(((struct stat_data *)(sd))->sd_mode)
#define st_mtime_v1(sd) le32_to_cpu(((struct stat_data_v1 *)(sd))->sd_mtime)
#define st_mtime_v2(sd) le32_to_cpu(((struct stat_data *)(sd))->sd_mtime)
static void overwrite_stat_data (struct item_head * new_ih,
void * new_item, struct path * path)
{
if (stat_data_v1 (new_ih)) {
if (st_mtime_v1 (new_item) > st_mtime_v1 (get_item (path))) {
memcpy (get_item (path), new_item, SD_V1_SIZE);
mark_buffer_dirty (get_bh (path));
}
} else {
if (st_mtime_v2 (new_item) > st_mtime_v2 (get_item (path))) {
memcpy (get_item (path), new_item, SD_SIZE);
mark_buffer_dirty (get_bh (path));
}
}
return;
}
/* insert sd item if it does not exist, overwrite it otherwise */
static void put_sd_into_tree (struct item_head * new_ih, char * new_item)
{
struct path path;
if (!not_a_directory (new_item)) {
/* new item is a stat data of a directory. So we have to
relocate all items which have the same short key and are of
not a directory */
relocate_file (new_ih, 0/*do not change new_ih*/);
} else {
/* new item is a stat data of something else but directory. If
there are items of directory - we have to relocate the file */
if (should_relocate (new_ih))
relocate_file (new_ih, 1/*change new_ih*/);
}
/* if we will have to insert item into tree - it is ready */
zero_nlink (new_ih, new_item);
mark_item_unreachable (new_ih);
/* we are sure now that if we are inserting stat data of a
directory - there are no items with the same key which are not
items of a directory, and that if we are inserting stat data is
of not a directory - it either has new key already or there are
no items with this key which are items of a directory */
if (usearch_by_key (fs, &(new_ih->ih_key), &path) == ITEM_FOUND) {
/* this stat data is found */
if (ih_key_format (get_ih(&path)) != ih_key_format (new_ih)) {
/* in tree stat data and a new one are of different
formats */
fsck_log ("put_sd_into_tree: inserting stat data %K (%M)..",
&(new_ih->ih_key), st_mode (new_item));
if (stat_data_v1 (new_ih)) {
/* sd to be inserted is of V1, where as sd in the tree
is of V2 */
fsck_log ("found newer in the tree (%M), skip inserting\n",
st_mode (get_item (&path)));
} else {
/* the stat data in the tree is sd_v1 */
fsck_log ("older sd (%M) is replaced with it\n",
st_mode (get_item (&path)));
reiserfsck_delete_item (&path, 0/*not temporary*/);
usearch_by_key (fs, &new_ih->ih_key, &path);
reiserfsck_insert_item (&path, new_ih, new_item);
}
} else {
/* both stat data are of the same version */
overwrite_stat_data (new_ih, new_item, &path);
pathrelse (&path);
}
return;
}
/* item not found, insert a new one */
reiserfsck_insert_item (&path, new_ih, new_item);
}
/* this tries to put each item entry to the tree, if there is no items
of the directory, insert item containing 1 entry */
static void put_directory_item_into_tree (struct item_head * comingih, char * item)
{
struct reiserfs_de_head * deh;
int i;
char * buf;
char * name;
int namelen;
/* if there are anything ith this key but a directory - move it
somewhere else */
relocate_file (comingih, 0/* do not change ih */);
deh = (struct reiserfs_de_head *)item;
for (i = 0; i < ih_entry_count (comingih); i ++, deh ++) {
name = name_in_entry (deh, i);
namelen = name_length (comingih, deh, i);
if (!is_properly_hashed (fs, name, namelen, deh_offset (deh)))
reiserfs_panic ("put_directory_item_into_tree: should be hashed properly ()");
asprintf (&buf, "%.*s", namelen, name);
/* 1 for fsck is important: if there is no any items of this
directory in the tree yet - new item will be inserted
marked not reached */
reiserfs_add_entry (fs, &(comingih->ih_key), buf, (struct key *)&(deh->deh_dir_id), 1/*fsck_need*/);
free (buf);
}
/* make a directory */
}
/* relocated files get added into lost+found with slightly different names */
static void link_one (struct relocated * file)
{
char * name;
struct key obj_key;
asprintf (&name, "%lu,%lu", file->old_dir_id, file->new_objectid);
obj_key.k_dir_id = file->old_dir_id;
obj_key.k_objectid = file->new_objectid;
/* 0 for fsck_need does not mean too much - it would make effect
if there were no this directory yet. But /lost_found is there
already */
reiserfs_add_entry (fs, &lost_found_dir_key, name, &obj_key, 0/*fsck_need*/);
stats(fs)->relocated ++;
free (name);
}
void link_relocated_files (void)
{
struct relocated * tmp;
int count;
count = 0;
while (relocated_list) {
link_one (relocated_list);
tmp = relocated_list;
relocated_list = relocated_list->next;
freemem (tmp);
count ++;
}
}
void insert_item_separately (struct item_head * ih,
char * item, int was_in_tree)
{
if (ih->ih_key.k_dir_id == ih->ih_key.k_objectid)
reiserfs_panic ("insert_item_separately: can not insert bad item %H", ih);
if (is_stat_data_ih (ih)) {
put_sd_into_tree (ih, item);
} else if (is_direntry_ih (ih)) {
put_directory_item_into_tree (ih, item);
} else {
if (should_relocate (ih))
relocate_file (ih, 1/*change new_ih*/);
reiserfsck_file_write (ih, item, was_in_tree);
}
}
static void put_items (struct buffer_head * bh)
{
int i;
struct item_head * ih;
ih = B_N_PITEM_HEAD (bh, 0);
for (i = 0; i < B_NR_ITEMS (bh); i ++, ih ++) {
if (i && bad_pair (fs, bh, i)) {
/* skip item if it is in wrong order */
continue;
}
insert_item_separately (ih, B_I_PITEM (bh, ih), 0/*was in tree*/);
}
}
/* uninsertable blocks are marked by 0s in uninsertable_leaf_bitmap
during the pass 1. They must be not in the tree */
void pass_2_take_bad_blocks_put_into_tree (void)
{
struct buffer_head * bh;
unsigned long j;
unsigned long bb_counter = 0;
int what_node;
if (!stats(fs)->uninsertable_leaves)
return;
if (fsck_log_file (fs) != stderr)
fsck_log ("####### Pass 2 #######\n");
fsck_progress ("\nPass2:\n");
j = 0;
while (reiserfs_bitmap_find_zero_bit (uninsertable_leaf_bitmap, &j) == 0) {
bh = bread (fs->s_dev, j, fs->s_blocksize);
if (bh == 0) {
fsck_log ("pass_2_take_bad_blocks_put_into_tree: "
"unable to read %lu block on device 0x%x\n",
j, fs->s_dev);
goto next;
}
if (is_block_used (bh->b_blocknr)) {
fsck_log ("pass_2_take_bad_blocks_put_into_tree: "
"block %d can not be in tree\n", bh->b_blocknr);
goto next;
}
/* this must be leaf */
what_node = who_is_this (bh->b_data, fs->s_blocksize);
if (what_node != THE_LEAF) { // || B_IS_KEYS_LEVEL(bh)) {
fsck_log ("take_bad_blocks_put_into_tree: buffer (%b %z) must contain leaf\n", bh, bh);
goto next;
}
/*fsck_log ("block %lu is being inserted\n", bh->b_blocknr);*/
put_items (bh);
print_how_far (&bb_counter, stats(fs)->uninsertable_leaves, 1, fsck_quiet (fs));
next:
brelse (bh);
j ++;
}
fsck_progress ("\n");
if (bb_counter != stats(fs)->uninsertable_leaves)
die ("take_bad_blocks_put_into_tree: found bad block %d, must be %d",
bb_counter, stats(fs)->uninsertable_leaves);
}
+79
View File
@@ -0,0 +1,79 @@
/*
* Copyright 1996, 1997, 1998 Hans Reiser
*/
#include "fsck.h"
void get_next_key (struct path * path, int i, struct key * key)
{
struct buffer_head * bh = PATH_PLAST_BUFFER (path);
struct key * rkey;
if (i < B_NR_ITEMS (bh) - 1) {
/* next item is in this block */
copy_key (key, B_N_PKEY (bh, i + 1));
return;
}
rkey = uget_rkey (path);
if (rkey) {
/* got next item key from right delimiting key */
copy_key (key, rkey);
} else {
/* there is no next item */
memset (key, 0xff, KEY_SIZE);
}
}
int pass_4_check_unaccessed_items (void)
{
struct key key;
struct path path;
int i;
struct buffer_head * bh;
struct item_head * ih;
unsigned long items;
path.path_length = ILLEGAL_PATH_ELEMENT_OFFSET;
key = root_dir_key;
fsck_progress ("Pass 4 - ");
items = 0;
while (usearch_by_key (fs, &key, &path) == ITEM_FOUND) {
bh = PATH_PLAST_BUFFER (&path);
/* print ~ how many leaves were scanned and how fast it was */
if (!fsck_quiet (fs))
print_how_fast (0, items++, 50);
for (i = get_item_pos (&path), ih = get_ih (&path); i < B_NR_ITEMS (bh); i ++, ih ++) {
if (!is_item_reachable (ih)) {
get_next_key (&path, i, &key);
stats(fs)->deleted_items ++;
PATH_LAST_POSITION (&path) = i;
reiserfsck_delete_item (&path, 0);
goto cont;
}
}
get_next_key (&path, i - 1, &key);
pathrelse (&path);
cont:
}
pathrelse (&path);
fsck_progress ("done\n");
stage_report (4, fs);
return 0;
}
+91
View File
@@ -0,0 +1,91 @@
.\" -*- nroff -*-
.\" Copyright 1996-2001 Hans Reiser.
.\"
.TH REISERFSCK 8 "March 2001" "Reiserfsprogs-3.x.0j"
.SH NAME
reiserfsck \- check a Linux Reiserfs file system
.SH SYNOPSIS
.B reiserfsck
[
.B -arvixoV
] [
.B -l logfilename
] [
.B --rebuild-tree
] [
.B --check
] [
.B --rebuild-sb
] [
.B --interactive
] [
\fB --logfile \fI logfilename
] [
.B --fix-fixable
]
.I device
.SH DESCRIPTION
It looks for reiserfs filesystem on a device, replays transactions
which are to be replayed and either check or repair the filesystem
.TP
.I device
is the special file corresponding to the device (e.g /dev/hdXX for
IDE disk partition or /dev/sdXX for SCSI disk partition).
.SH OPTIONS
.TP
.B --check
This checks filesystem consistency. This is a default action. It may
be used on a filesystem mounted read-only
.TP
.B --rebuild-tree
This rebuilds filesystem tree using leaf nodes found on the
device. Normally, you do not need this, but if you have to rebuild
tree - please backup whole partition first or at least the most
important data if you can mount the partition.
.TP
.B --rebuild-sb
.TP
.B --interactive, -i
This makes \fBreiserfsck\fR to stop after each pass completed.
.TP
.B --quiet, -q
have \fBreiserfsck\fR to not reflect its progress
.TP
.B --nolog, -n
have \fBreiserfsck\fR to not log anything
.TP
\fB--logfile \fIfilename\fR, \fB-l \fI filename
have \fBreiserfsck\fR to put info about found corruptions in logfile
rather than on stderr
.TP
.B --fix-fixable, -x
have \fBreiserfsck\fR to recover corruptions which can be fixed w/o
--rebuild-tree when it is runnig in check mode. Corruptions which can
be fixed so far: bad pointers to data blocks, wrong directory's
st_size and st_blocks, directories entries pointing to nowhere can be
deleted
.TP
.B --fix-non-critical, -o
have \fBreiserfsck\fR to fix: file sizes when they are bigger than
real file size, set file mode to regular file when mode looks wrong
and to try to recover "objectid sharing" problem
.TP
.B -a
When it is set - \fBreiserfsck\fR assumes that it is called by fsck -A
and just returns even if filesystem seems not umounted cleanly
.TP
.B -r
ignored
.TP
.B -V
Prints version and exits
.SH AUTHOR
This version of \fBreiserfsck\fR has been written by Hans Reiser
<reiser@idiom.com>.
.SH BUGS
There are probably few of them. Please, report bugs to Hans Reiser <reiser@idiom.com>.
.SH TODO
Faster recovering, signal handling, i/o error handling, etc.
.SH SEE ALSO
.BR mkreiserfs (8),
.BR debugreiserfs (8)
+202
View File
@@ -0,0 +1,202 @@
/*
* Copyright 1998 Hans Reiser
*/
/*#include <stdio.h>
#include <string.h>*/
/*#include <asm/bitops.h>
#include "../include/reiserfs_fs.h"
#include "../include/reiserfs_fs_sb.h"
#include "../include/reiserfslib.h"*/
#include "fsck.h"
/* there is a situation, when we overwrite contents of unformatted
node with direct item. One unformatted node can be overwritten
several times by direct items */
/*
struct overwritten_unfm_segment {
int ous_begin;
int ous_end;
struct overwritten_unfm_segment * ous_next;
};
*/
struct overwritten_unfm {
unsigned long ou_unfm_ptr; /* block number of unfm node */
unsigned long ou_dir_id;
unsigned long ou_objectid; /* key corresponding to an unfm node */
unsigned long ou_offset;
struct overwritten_unfm_segment * ou_segments; /* list of segmens, than have been overwritten in ths unfm node */
};
struct overwritten_unfm ** g_overwritten_unfms;
int g_overwritten_unfms_amount; /* number of unformatted nodes, which contain direct items */
/* adds segment to the single linked list of segments sorted by begin
field. Retuns pointer to first element of list */
static struct overwritten_unfm_segment * add_segment (struct overwritten_unfm_segment * first, int begin, int end)
{
struct overwritten_unfm_segment * new, * next, * prev;
new = getmem (sizeof (struct overwritten_unfm_segment));
new->ous_begin = begin;
new->ous_end = end;
new->ous_next = 0;
next = first;
prev = 0;
while (next) {
if (next->ous_begin > begin)
break;
prev = next;
next = next->ous_next;
}
if (prev == 0) {
/* insert into head of list */
first = new;
} else {
prev->ous_next = new;
}
new->ous_next = next;
return first;
}
/* input parameter
`list_head` - first element of overlapping segments sorted by left edge
`unoverwritten_segment` - returned by previous call of get_unoverwritten_segment or (-2,-2) if called first time
*/
/* returns
1 and segment unoverwritten by elements of list `list_head`
0 if there isno such segment
*/
int get_unoverwritten_segment (struct overwritten_unfm_segment * list_head, struct overwritten_unfm_segment * unoverwritten_segment)
{
int end;
/* look for segment, which has begin field greater than end of previous interval */
while (list_head->ous_begin <= unoverwritten_segment->ous_end) {
list_head = list_head->ous_next;
}
/* look for the end of the continuous region covered by otrezkami */
end = list_head->ous_end;
while (list_head->ous_next) {
if (list_head->ous_next->ous_begin > end + 1)
/* intreval found */
break;
if (list_head->ous_next->ous_end > end)
end = list_head->ous_next->ous_end;
list_head = list_head->ous_next;
}
/* ok, between segment and segment->next we have an interval (segment->next != 0) */
if (list_head->ous_next != 0) {
unoverwritten_segment->ous_begin = end + 1;
unoverwritten_segment->ous_end = list_head->ous_next->ous_begin - 1;
return 1;
}
return 0;
}
void print_segments (struct overwritten_unfm_segment * list_head)
{
struct overwritten_unfm_segment * cur;
cur = list_head;
while (cur) {
printf ("%s%d %d%s", cur == list_head ? "(" : "", cur->ous_begin, cur->ous_end, cur->ous_next ? ", " : ")\n");
cur = cur->ous_next;
}
}
/* this prepare list of segments to extracting of unoverwritten segments */
struct overwritten_unfm_segment * find_overwritten_unfm (unsigned long unfm, int length, struct overwritten_unfm_segment * segment_to_init)
{
int i;
for (i = 0; i < g_overwritten_unfms_amount && g_overwritten_unfms[i] != 0; i ++)
if (g_overwritten_unfms[i]->ou_unfm_ptr == unfm) {
if (g_overwritten_unfms[i]->ou_segments == 0)
die ("find_overwritten_unfm: no segment found");
g_overwritten_unfms[i]->ou_segments = add_segment (g_overwritten_unfms[i]->ou_segments, -1, -1);
add_segment (g_overwritten_unfms[i]->ou_segments, length, length);
segment_to_init->ous_begin = -2;
segment_to_init->ous_end = -2;
return g_overwritten_unfms[i]->ou_segments;
}
return 0;
}
struct overwritten_unfm * look_for_overwritten_unfm (__u32 unfm)
{
int i;
for (i = 0; i < g_overwritten_unfms_amount && g_overwritten_unfms[i] != 0; i ++)
if (g_overwritten_unfms[i]->ou_unfm_ptr == unfm)
return g_overwritten_unfms[i];
return 0;
}
#define GROW_BY 10
struct overwritten_unfm * add_overwritten_unfm (unsigned long unfm, struct item_head * direct_ih)
{
int i;
for (i = 0; i < g_overwritten_unfms_amount && g_overwritten_unfms[i] != 0; i ++) {
if (g_overwritten_unfms[i]->ou_unfm_ptr == unfm)
return g_overwritten_unfms[i];
}
if (i == g_overwritten_unfms_amount) {
g_overwritten_unfms = expandmem (g_overwritten_unfms, sizeof (struct overwritten_unfm *) * i,
sizeof (struct overwritten_unfm *) * GROW_BY);
g_overwritten_unfms_amount += GROW_BY;
}
g_overwritten_unfms[i] = getmem (sizeof (struct overwritten_unfm));
g_overwritten_unfms[i]->ou_unfm_ptr = unfm;
g_overwritten_unfms[i]->ou_dir_id = direct_ih->ih_key.k_dir_id;
g_overwritten_unfms[i]->ou_objectid = direct_ih->ih_key.k_objectid;
g_overwritten_unfms[i]->ou_offset = get_offset(&direct_ih->ih_key) - (get_offset(&direct_ih->ih_key) - 1) % fs->s_blocksize;
return g_overwritten_unfms[i];
}
void save_unfm_overwriting (unsigned long unfm, struct item_head * direct_ih)
{
struct overwritten_unfm * ov_unfm;
/* add new overwritten unfm or return existing one */
ov_unfm = add_overwritten_unfm (unfm, direct_ih);
ov_unfm->ou_segments = add_segment (ov_unfm->ou_segments, (get_offset(&direct_ih->ih_key) - 1) % fs->s_blocksize,
(get_offset(&direct_ih->ih_key) - 1) % fs->s_blocksize + ih_item_len (direct_ih) - 1);
}
void free_overwritten_unfms (void)
{
int i;
for (i = 0; i < g_overwritten_unfms_amount && g_overwritten_unfms[i]; i ++) {
/* free all segments */
while (g_overwritten_unfms[i]->ou_segments) {
struct overwritten_unfm_segment * tmp;
tmp = g_overwritten_unfms[i]->ou_segments->ous_next;
freemem (g_overwritten_unfms[i]->ou_segments);
g_overwritten_unfms[i]->ou_segments = tmp;
}
/* free struct overwritten_unfm */
freemem (g_overwritten_unfms[i]);
}
/* free array of pointers to overwritten unfms */
if (g_overwritten_unfms)
freemem (g_overwritten_unfms);
}
+1346
View File
File diff suppressed because it is too large. Load diff
+189
View File
@@ -0,0 +1,189 @@
/*
* Copyright 1996-1999 Hans Reiser
*/
#include "fsck.h"
/* g_disk_bitmap initially contains copy of disk bitmaps
(cautious version of it);
g_new_bitmap initially has marked only super block, bitmap blocks
and bits after the end of bitmap
in pass 1 we go through g_disk_bitmap.
If block does not look like formatted node, we skip it.
If block contains internal node, put 0 in g_disk_bitmap if block is
not used in new tree yet.
If block contains leaf and is used already (by an indirect item
handled already to this time) save all items. They will be inserted
into tree after pass 1.
If block looking like leaf is not used in the new tree, try to
insert in into tree. If it is not possible, mark block in
g_uninsertable_leaf_bitmap. Blocks marked in this bitmap will be inserted into tree in pass 2. They can not be
This means, that in pass 1 when we have
found block containing the internal nodes we mark it in
g_disk_bitmap as free (reiserfs_free_internal_block). When block
gets into new tree it is marked in g_new_bitmap (mark_block_used)
When collecting resources for do_balance, we mark new blocks with
mark_block_used. After do_balance we unmark unused new blocks in
g_new_bitmap (bitmap.c:/reiserfs_free_block)
Allocating of new blocks: look for 0 bit in g_disk_bitmap
(find_zero_bit_in_bitmap), make sure, that g_new_bitmap contains 0
at the corresponding bit (is_block_used).
*/
int is_to_be_read (reiserfs_filsys_t fs, unsigned long block)
{
return reiserfs_bitmap_test_bit (fsck_disk_bitmap (fs), block);
}
/* is blocks used (marked by 1 in new bitmap) in the tree which is being built
(as leaf, internal, bitmap, or unformatted node) */
int is_block_used (unsigned long block)
{
return reiserfs_bitmap_test_bit (fsck_new_bitmap (fs), block);
}
void mark_block_used (unsigned long block)
{
if (!block)
return;
if (is_block_used (block))
die ("mark_block_used: (%lu) used already", block);
reiserfs_bitmap_set_bit (fsck_new_bitmap (fs), block);
}
void mark_block_free (unsigned long block)
{
if (!is_block_used (block))
die ("mark_block_used: (%lu) is free", block);
reiserfs_bitmap_clear_bit (fsck_new_bitmap (fs), block);
}
int is_block_uninsertable (unsigned long block)
{
return !reiserfs_bitmap_test_bit (uninsertable_leaf_bitmap, block);
}
/* uninsertable block is marked by bit clearing */
void mark_block_uninsertable (unsigned long block)
{
if (is_block_uninsertable (block))
die ("mark_block_uninsertable: (%lu) is uninsertable already", block);
reiserfs_bitmap_clear_bit (uninsertable_leaf_bitmap, block);
}
int reiserfsck_reiserfs_new_blocknrs (reiserfs_filsys_t fs,
unsigned long * free_blocknrs,
unsigned long start, int amount_needed)
{
int i;
if (!are_there_allocable_blocks (amount_needed))
die ("out of disk space");
for (i = 0; i < amount_needed; i ++) {
free_blocknrs[i] = alloc_block ();
if (!free_blocknrs[i])
die ("reiserfs_new_blocknrs: 0 is allocated");
mark_block_used (free_blocknrs[i]);
}
return CARRY_ON;
}
// FIXME: do you check readability of a block? If f_read fails - you
// free block in bitmap or if you mark bad blocks used to avoid their
// allocation in future you should have bad block counter in a super
// block. Another minor issue: users of _get_new_buffer expect buffer
// to be filled with 0s
struct buffer_head * reiserfsck_get_new_buffer (unsigned long start)
{
unsigned long blocknr = 0;
struct buffer_head * bh = NULL;
reiserfs_new_blocknrs (fs, &blocknr, start, 1);
bh = getblk (fs->s_dev, blocknr, fs->s_blocksize);
return bh;
}
/* free block in new bitmap */
int reiserfsck_reiserfs_free_block (reiserfs_filsys_t fs, unsigned long block)
{
mark_block_free (block);
/* put it back to pool of blocks for allocation */
make_allocable (block);
return 0;
}
+1069
View File
File diff suppressed because it is too large. Load diff
+391
View File
@@ -0,0 +1,391 @@
/*
* Copyright 1996-2001 Hans Reiser
*/
#include "fsck.h"
/* when --check fsck builds a map of objectids of files it finds in the tree
when --rebuild-tree - fsck builds map of objectids it inserts into tree
FIXME: objectid gets into map when stat data item
*/
/* is it marked used in super block's objectid map */
int is_objectid_used (reiserfs_filsys_t s, __u32 objectid)
{
__u32 * objectid_map;
int i = 0;
objectid_map = (__u32 *)((char *)(s->s_rs) + (sb_size(s)));
while (i < SB_OBJECTID_MAP_SIZE (s)) {
if (objectid == objectid_map[i]) {
return 1; /* objectid is used */
}
if (objectid > objectid_map[i] && objectid < objectid_map[i+1]) {
return 1; /* objectid is used */
}
if (objectid < objectid_map[i])
break;
i += 2;
}
/* objectid is free */
return 0;
}
/* true objectid map */
/* size of 1 piece of map */
#define MAP_SIZE 4096 /* must be n * 2 * sizeof(__u32) */
#define MAX_MAP_SIZE 1 /* % of available memory? */
/* increase area by MAP_SIZE bytes */
static void grow_id_map (struct id_map * map)
{
if (map->m_page_count && ((map->m_page_count % 5) == 0)) {
fsck_log ("grow_id_map: objectid map expanded: used %lu, %d blocks\n",
map->m_used_slots_count, map->m_page_count);
}
map->m_begin = expandmem (map->m_begin, map->m_page_count * MAP_SIZE, MAP_SIZE);
map->m_page_count ++;
}
static void try_to_shrink_id_map (struct id_map * map)
{
if (map->m_used_slots_count * sizeof(__u32) <= (map->m_page_count - 1) * MAP_SIZE) {
if (map->m_page_count && ((map->m_page_count % 5) == 0))
fsck_log ("shrink_id_map: objectid map shrinked: used %lu, %d blocks\n",
map->m_used_slots_count, map->m_page_count);
map->m_begin = expandmem (map->m_begin, map->m_page_count * MAP_SIZE,
-MAP_SIZE);
map->m_page_count--;
}
}
/* ubin_search_id is used to find id in the map (or proper place to
insert the new id). if smth goes wrong or ubin_search_id stops
working properly check_id_search_result should help to find raised
problems */
static void check_id_search_result(struct id_map * map, int res, __u32 pos,
__u32 id)
{
if (res != ITEM_FOUND && res != ITEM_NOT_FOUND)
die("check_id_search_result: get wrong result from ubin_search (%d)", res);
if (res == 1 && *(map->m_begin + pos) != id)
die("check_id_search_result: wrong id found %u %u", id, *(map->m_begin + pos));
if (res == 1)
{
if (pos > map->m_used_slots_count)
die("check_id_search_result: get bad position (%u), used %u",
pos, map->m_used_slots_count);
if (pos >= 0 && pos <= map->m_used_slots_count && *(map->m_begin + pos - 1) >= id)
die("check_id_search_result: previous id (%u) not less than (%u)",
*(map->m_begin + pos - 1), id);
if (pos >= 0 && pos < map->m_used_slots_count && *(map->m_begin + pos) < id)
die("check_id_search_result: found id (%u) not much than (%u)",
*(map->m_begin + pos), id);
}
}
static int comp_ids (void * p1, void * p2)
{
__u32 * id1, * id2;
id1 = p1;
id2 = p2;
if ( *id1 < *id2 )
return -1;
if ( *id1 > *id2 )
return 1;
return 0;
}
/* */
struct id_map * init_id_map (void)
{
struct id_map * map;
map = getmem (sizeof (struct id_map));
map->m_begin = NULL;
map->m_used_slots_count = 0;
map->m_page_count = 0;
mark_objectid_really_used (map, 1);
return map;
}
/* free whole map */
void free_id_map (struct id_map ** map)
{
freemem ((*map)->m_begin);
freemem (*map);
*map = 0;
}
/* return 1 if id is marked used, 0 otherwise */
int is_objectid_really_used (struct id_map * map, __u32 id, int * ppos)
{
int res;
*ppos = 0;
if (map->m_begin == NULL)
return 0;
/* smth exists in the map, find proper place to insert or this id */
res = ubin_search (&id, map->m_begin, map->m_used_slots_count, sizeof (__u32), ppos, comp_ids);
#if 1
check_id_search_result (map, res, *ppos, id);
#endif
/* *ppos is position in objectid map of the element which is equal id
or position of an element which is smallest and greater than id */
if (res == ITEM_NOT_FOUND)
/* id is not found in the map. if returned position is odd -
id is marked used */
return (*ppos % 2);
/* if returned position is odd - id is marked free */
return !(*ppos % 2);
}
static void check_objectid_map (struct id_map * map)
{
int i;
for (i = 1; i < map->m_used_slots_count; i ++)
if (map->m_begin [i - 1] >= map->m_begin [i])
die ("check_objectid_map: map corrupted");
}
/* returns 1 objectid is marked used already, 0 otherwise */
int mark_objectid_really_used (struct id_map * map, __u32 id)
{
int pos;
/* check whether id is used and get place if used or place to insert if not */
if (is_objectid_really_used (map, id, &pos) == 1)
return 1;
map->objectids_marked ++;
if (pos % 2 == 0){
/* id not found in the map. why? is_id_used() knows */
if (map->m_begin == NULL)
/* map is empty */
grow_id_map (map);
/* id + 1 is used, change id + 1 to id and exit */
if ( id + 1 == le32_to_cpu (map->m_begin[pos]) ) {
/* we can mark id as used w/o expanding of id map */
map->m_begin[pos] = cpu_to_le32 (id);
check_objectid_map (map);
return 0;
}
if (map->m_page_count * MAP_SIZE == map->m_used_slots_count * sizeof(__u32))
/* fixme: do not grow too much */
grow_id_map (map);
if (map->m_used_slots_count - pos > 0)
memmove (map->m_begin + pos + 2, map->m_begin + pos, (map->m_used_slots_count - pos) * sizeof (__u32));
map->m_used_slots_count += 2;
map->m_begin[pos] = cpu_to_le32 (id);
map->m_begin[pos+1] = cpu_to_le32 (id + 1);
check_objectid_map (map);
return 0;
}
/* id found in the map. pos is odd position () */
map->m_begin[pos] = cpu_to_le32 (id + 1);
/* if end id of current interval == start id of next interval we
eliminated a sequence of unused objectids */
if (pos + 1 < map->m_used_slots_count &&
map->m_begin[pos + 1] == map->m_begin[pos]) {
memmove (map->m_begin + pos, map->m_begin + pos + 2, (map->m_used_slots_count - pos - 2) * sizeof (__u32));
map->m_used_slots_count -= 2;
try_to_shrink_id_map (map);
}
check_objectid_map (map);
return 0;
}
static __u32 get_free_id (reiserfs_filsys_t fs)
{
struct id_map * map;
map = proper_id_map (fs);
/* If map is not NULL return the second element (first position in
the map). This allocates the first unused objectid. That is to
say, the first entry on the objectid map is the first unused
objectid. */
if (map->m_begin == NULL) {
fprintf (stderr, "get_free_id: hmm, 1 is allocated as objectid\n");
return 1;
}
return (le32_to_cpu (map->m_begin[1]));
}
__u32 get_unused_objectid (reiserfs_filsys_t fs)
{
__u32 objectid;
objectid = get_free_id (fs);
if (mark_objectid_really_used (proper_id_map (fs), objectid))
die ("get_unused_objectid: could not mark %lu used", objectid);
return objectid;
}
#define objectid_map(fs) ((char *)((char *)((fs)->s_rs) + sb_size (fs)))
#if 0
/* returns 0 if on-disk objectid map matches to the correct one, 1
otherwise */
int compare_id_maps (reiserfs_filsys_t fs)
{
struct id_map * map;
int disk_size;
map = proper_id_map (fs);
disk_size = rs_objectid_map_size (fs->s_rs);
if (disk_size != map->m_used_slots_count ||
memcmp ((char *)((char *)((fs)->s_rs) + sb_size (fs)), map->m_begin, sizeof(__u32) * disk_size)) {
fprintf (stderr, "Objectid maps mismatch\n");
return 1;
}
return 0;
}
/* copy objectid map into buffer containing super block */
void correct_objectid_map (reiserfs_filsys_t fs)
{
struct id_map * map;
int size, disk_max;
map = proper_id_map (fs);
size = map->m_used_slots_count;
disk_max = rs_objectid_map_max_size (fs->s_rs);
if (disk_max < size) {
size = disk_max;
} else {
memset (fu_objectid_map (fs) + size, 0, (disk_max - size) * sizeof (__u32));
}
memcpy (fu_objectid_map (fs), map->m_begin, size * sizeof (__u32));
set_objectid_map_size (fs->s_rs, size);
mark_buffer_dirty (SB_BUFFER_WITH_SB (fs));
/*
if (fs->fu_job->verbose)
fprintf (stderr, "Objectid map corrected\n");
*/
}
#endif
#if 0
/* print the map of objectids */
void print_objectid_list ()
{
int i;
printf ("\n control id map: all %d, used:%d", id_map.m_page_count * MAP_SIZE, id_map.m_used_slots_count);
for (i = 0; i < id_map.m_used_slots_count; i += 2)
printf ("\n[%u-%u]", id_map.m_begin[i], id_map.m_begin[i + 1] - 1);
}
/* print on-disk map of objectids */
void print_disk_objectid_list (void)
{
int i;
__u32 * objectid_map = (__u32 *)((char *)SB_DISK_SUPER_BLOCK (&g_sb) + (sb_size(&g_sb)));
printf ("\n on-disk id map. used:%lu", SB_OBJECTID_MAP_SIZE(&g_sb));
for (i = 0; i < SB_OBJECTID_MAP_SIZE(&g_sb); i += 2)
printf ("\n[%u-%u]", objectid_map[i], objectid_map[i + 1] - 1);
}
#endif
void flush_objectid_map (struct id_map * map, reiserfs_filsys_t fs)
{
int size, max;
int sb_size;
__u32 * sb_objectid_map;
sb_size = (is_reiser2fs_magic_string (fs->s_rs) ? SB_SIZE : SB_SIZE_V1);
sb_objectid_map = (__u32 *)((char *)(fs->s_rs) + sb_size);
check_objectid_map (map);
max = ((fs->s_blocksize - sb_size) >> 3 << 1);
set_objectid_map_max_size (fs->s_rs, max);
if (map->m_used_slots_count > max)
size = max;
else
size = map->m_used_slots_count;
memcpy (sb_objectid_map, map->m_begin, size * sizeof (__u32));
memset (sb_objectid_map + size, 0, (max - size) * sizeof (__u32));
set_objectid_map_size (fs->s_rs, size);
if (size == max)
/*((__u32 *)((char *)(fs->s_rs) + sb_size))*/
sb_objectid_map [max - 1] = map->m_begin [map->m_used_slots_count - 1];
check_objectid_map (map);
}
void fetch_objectid_map (struct id_map * map, reiserfs_filsys_t fs)
{
int sb_size;
__u32 * sb_objectid_map;
sb_size = (is_reiser2fs_magic_string (fs->s_rs) ? SB_SIZE : SB_SIZE_V1);
sb_objectid_map = (__u32 *)((char *)(fs->s_rs) + sb_size);
if (map->m_page_count != 1)
die ("fetch_objectid_map: can not fetch long map");
grow_id_map (map);
memcpy (map->m_begin, sb_objectid_map, rs_objectid_map_size (fs->s_rs) * sizeof (__u32));
map->m_used_slots_count = rs_objectid_map_size (fs->s_rs);
}
+704
View File
@@ -0,0 +1,704 @@
/*
* Copyright 1996-2001 Hans Reiser
*/
#include "fsck.h"
/* key1 and key2 are pointer to deh_offset of the struct reiserfs_de_head */
int comp_dir_entries (void * key1, void * key2)
{
__u32 off1, off2;
off1 = le32_to_cpu (*(__u32 *)key1);
off2 = le32_to_cpu (*(__u32 *)key2);
if (off1 < off2)
return -1;
if (off1 > off2)
return 1;
return 0;
}
void init_tb_struct (struct tree_balance * tb, struct super_block * s, struct path * path, int size)
{
memset (tb, '\0', sizeof(struct tree_balance));
tb->tb_sb = s;
tb->tb_path = path;
PATH_OFFSET_PBUFFER(path, ILLEGAL_PATH_ELEMENT_OFFSET) = NULL;
PATH_OFFSET_POSITION(path, ILLEGAL_PATH_ELEMENT_OFFSET) = 0;
tb->insert_size[0] = size;
}
struct tree_balance * cur_tb = 0;
void reiserfsck_paste_into_item (struct path * path, const char * body, int size)
{
struct tree_balance tb;
init_tb_struct (&tb, fs, path, size);
if (fix_nodes (/*tb.transaction_handle,*/ M_PASTE, &tb, 0/*ih*/) != CARRY_ON)
//fix_nodes(options, tree_balance, ih_to_option, body_to_option)
die ("reiserfsck_paste_into_item: fix_nodes failed");
do_balance (/*tb.transaction_handle,*/ &tb, 0, body, M_PASTE, 0/*zero num*/);
}
void reiserfsck_insert_item (struct path * path, struct item_head * ih, const char * body)
{
struct tree_balance tb;
init_tb_struct (&tb, fs, path, IH_SIZE + ih_item_len(ih));
if (fix_nodes (/*tb.transaction_handle,*/ M_INSERT, &tb, ih/*, body*/) != CARRY_ON)
die ("reiserfsck_insert_item: fix_nodes failed");
do_balance (/*tb.transaction_handle,*/ &tb, ih, body, M_INSERT, 0/*zero num*/);
}
static void free_unformatted_nodes (struct item_head * ih, struct buffer_head * bh)
{
__u32 * punfm = (__u32 *)B_I_PITEM (bh, ih);
int i;
for (i = 0; i < I_UNFM_NUM (ih); i ++, punfm ++)
if (*punfm) {
struct buffer_head * to_be_forgotten;
to_be_forgotten = find_buffer (fs->s_dev, *punfm, fs->s_blocksize);
if (to_be_forgotten) {
//atomic_inc(&to_be_forgotten->b_count);
to_be_forgotten->b_count ++;
bforget (to_be_forgotten);
}
reiserfs_free_block (fs, *punfm);
}
}
void reiserfsck_delete_item (struct path * path, int temporary)
{
struct tree_balance tb;
struct item_head * ih = PATH_PITEM_HEAD (path);
if (is_indirect_ih (ih) && !temporary)
free_unformatted_nodes (ih, PATH_PLAST_BUFFER (path));
init_tb_struct (&tb, fs, path, -(IH_SIZE + ih_item_len(ih)));
if (fix_nodes (/*tb.transaction_handle,*/ M_DELETE, &tb, 0/*ih*/) != CARRY_ON)
die ("reiserfsck_delete_item: fix_nodes failed");
do_balance (/*tb.transaction_handle,*/ &tb, 0, 0, M_DELETE, 0/*zero num*/);
}
void reiserfsck_cut_from_item (struct path * path, int cut_size)
{
struct tree_balance tb;
struct item_head * ih;
if (cut_size >= 0)
die ("reiserfsck_cut_from_item: cut size == %d", cut_size);
if (is_indirect_ih (ih = PATH_PITEM_HEAD (path))) {
__u32 unfm_ptr = B_I_POS_UNFM_POINTER (PATH_PLAST_BUFFER (path), ih, I_UNFM_NUM (ih) - 1);
if (unfm_ptr) {
struct buffer_head * to_be_forgotten;
to_be_forgotten = find_buffer (fs->s_dev, le32_to_cpu (unfm_ptr), fs->s_blocksize);
if (to_be_forgotten) {
//atomic_inc(&to_be_forgotten->b_count);
to_be_forgotten->b_count ++;
bforget (to_be_forgotten);
}
reiserfs_free_block (fs, le32_to_cpu (unfm_ptr));
}
}
init_tb_struct (&tb, fs, path, cut_size);
if (fix_nodes (/*tb.transaction_handle,*/ M_CUT, &tb, 0) != CARRY_ON)
die ("reiserfsck_cut_from_item: fix_nodes failed");
do_balance (/*tb.transaction_handle,*/ &tb, 0, 0, M_CUT, 0/*zero num*/);
}
/* uget_lkey is utils clone of stree.c/get_lkey */
struct key * uget_lkey (struct path * path)
{
int pos, offset = path->path_length;
struct buffer_head * bh;
if (offset < FIRST_PATH_ELEMENT_OFFSET)
die ("uget_lkey: illegal offset in the path (%d)", offset);
/* While not higher in path than first element. */
while (offset-- > FIRST_PATH_ELEMENT_OFFSET) {
if (! buffer_uptodate (PATH_OFFSET_PBUFFER (path, offset)) )
die ("uget_lkey: parent is not uptodate");
/* Parent at the path is not in the tree now. */
if (! B_IS_IN_TREE (bh = PATH_OFFSET_PBUFFER (path, offset)))
die ("uget_lkey: buffer on the path is not in tree");
/* Check whether position in the parent is correct. */
if ((pos = PATH_OFFSET_POSITION (path, offset)) > B_NR_ITEMS (bh))
die ("uget_lkey: invalid position (%d) in the path", pos);
/* Check whether parent at the path really points to the child. */
if (B_N_CHILD_NUM (bh, pos) != PATH_OFFSET_PBUFFER (path, offset + 1)->b_blocknr)
die ("uget_lkey: invalid block number (%d). Must be %d",
B_N_CHILD_NUM (bh, pos), PATH_OFFSET_PBUFFER (path, offset + 1)->b_blocknr);
/* Return delimiting key if position in the parent is not equal to zero. */
if (pos)
return B_N_PDELIM_KEY(bh, pos - 1);
}
/* there is no left delimiting key */
return 0;
}
/* uget_rkey is utils clone of stree.c/get_rkey */
struct key * uget_rkey (struct path * path)
{
int pos, offset = path->path_length;
struct buffer_head * bh;
if (offset < FIRST_PATH_ELEMENT_OFFSET)
die ("uget_rkey: illegal offset in the path (%d)", offset);
while (offset-- > FIRST_PATH_ELEMENT_OFFSET) {
if (! buffer_uptodate (PATH_OFFSET_PBUFFER (path, offset)))
die ("uget_rkey: parent is not uptodate");
/* Parent at the path is not in the tree now. */
if (! B_IS_IN_TREE (bh = PATH_OFFSET_PBUFFER (path, offset)))
die ("uget_rkey: buffer on the path is not in tree");
/* Check whether position in the parrent is correct. */
if ((pos = PATH_OFFSET_POSITION (path, offset)) > B_NR_ITEMS (bh))
die ("uget_rkey: invalid position (%d) in the path", pos);
/* Check whether parent at the path really points to the child. */
if (B_N_CHILD_NUM (bh, pos) != PATH_OFFSET_PBUFFER (path, offset + 1)->b_blocknr)
die ("uget_rkey: invalid block number (%d). Must be %d",
B_N_CHILD_NUM (bh, pos), PATH_OFFSET_PBUFFER (path, offset + 1)->b_blocknr);
/* Return delimiting key if position in the parent is not the last one. */
if (pos != B_NR_ITEMS (bh))
return B_N_PDELIM_KEY(bh, pos);
}
/* there is no right delimiting key */
return 0;
}
inline int ubin_search (void * key, void * base, int num, int width, __u32 *ppos, comp_function_t comp_func)
{
__u32 rbound, lbound, j;
lbound = 0;
if (num == 0){
*ppos = 0;
return ITEM_NOT_FOUND;
}
rbound = num - 1;
for (j = (rbound + lbound) / 2; lbound <= rbound; j = (rbound + lbound) / 2) {
switch (comp_func ((void *)((char *)base + j * width), key ) ) {
case -1:/* second is greater */
lbound = j + 1;
continue;
case 1: /* first is greater */
if (j == 0){
*ppos = lbound;
return ITEM_NOT_FOUND;
}
rbound = j - 1;
continue;
case 0:
*ppos = j;
return ITEM_FOUND;
}
}
*ppos = lbound;
return ITEM_NOT_FOUND;
}
/* this searches in tree through items */
int usearch_by_key (struct super_block * s, struct key * key, struct path * path)
{
struct buffer_head * bh;
unsigned long block = SB_ROOT_BLOCK (s);
struct path_element * curr;
int retval;
path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET;
while (1) {
curr = PATH_OFFSET_PELEMENT (path, ++ path->path_length);
bh = curr->pe_buffer = bread (s->s_dev, block, s->s_blocksize);
if (bh == 0)
reiserfs_panic ("usearch_by_key: unable to read %lu block on device 0x%x\n",block, s->s_dev);
retval = ubin_search (key, B_N_PKEY (bh, 0), B_NR_ITEMS (bh),
is_leaf_node (bh) ? IH_SIZE : KEY_SIZE, &(curr->pe_position), comp_keys);
if (retval == ITEM_FOUND) {
/* key found, return if this is leaf level */
if (is_leaf_node (bh)) {
path->pos_in_item = 0;
return ITEM_FOUND;
}
curr->pe_position ++;
} else {
/* key not found in the node */
if (is_leaf_node (bh))
return ITEM_NOT_FOUND;
}
block = B_N_CHILD_NUM (bh, curr->pe_position);
}
die ("search_by_key: you can not get here");
return 0;
}
/* key is key of directory entry. This searches in tree through items and in
the found directory item as well */
int usearch_by_entry_key (struct super_block * s, struct key * key, struct path * path)
{
struct buffer_head * bh;
struct item_head * ih;
struct key tmpkey;
if (usearch_by_key (s, key, path) == ITEM_FOUND) {
/* entry found */
path->pos_in_item = 0;
return POSITION_FOUND;
}
bh = PATH_PLAST_BUFFER (path);
if (PATH_LAST_POSITION (path) == 0) {
/* previous item does not exist, that means we are in leftmost leaf of
the tree */
if (uget_lkey (path) != 0)
die ("search_by_entry_key: invalid position after search_by_key");
if (not_of_one_file (B_N_PKEY (bh, 0), key)) {
path->pos_in_item = 0;
return DIRECTORY_NOT_FOUND;
}
if (!is_direntry_ih (get_ih (path))) {
fsck_progress ("search_by_entry_key: directory expected to have this key %K\n", key);
return REGULAR_FILE_FOUND;
}
/* position for name insertion is found */
path->pos_in_item = 0;
return POSITION_NOT_FOUND;
}
/* take previous item */
PATH_LAST_POSITION (path) --;
ih = PATH_PITEM_HEAD (path);
if (not_of_one_file (&(ih->ih_key), key) || !is_direntry_ih(ih)) {
/* previous item belongs to another object or is stat data, check next
item */
PATH_LAST_POSITION (path) ++;
if (PATH_LAST_POSITION (path) < B_NR_ITEMS (bh))
{
/* found item is not last item of the node */
struct item_head * next_ih = B_N_PITEM_HEAD (bh, PATH_LAST_POSITION (path));
if (not_of_one_file (&(next_ih->ih_key), key))
{
path->pos_in_item = 0;
return DIRECTORY_NOT_FOUND;
}
if (!is_direntry_ih(next_ih))
{
/* there is an item in the tree, but it is not a directory item */
reiserfs_warning (stderr, "search_by_entry_key: directory expected to have this key %k\n",
key);
return REGULAR_FILE_FOUND;
}
} else {
/* found item is last item of the node */
struct key * next_key = uget_rkey (path);
if (next_key == 0 || not_of_one_file (next_key, key))
{
/* there is not any part of such directory in the tree */
path->pos_in_item = 0;
return DIRECTORY_NOT_FOUND;
}
if (!is_direntry_key (next_key))
{
/* there is an item in the tree, but it is not a directory item */
fsck_progress ("search_by_entry_key: directory expected to have this key %k\n",
key);
return REGULAR_FILE_FOUND;
}
// we got right delimiting key - search for it - the entry will be
// pasted in position 0
copy_key (&tmpkey, next_key);
pathrelse (path);
if (usearch_by_key (s, &tmpkey, path) != ITEM_FOUND || PATH_LAST_POSITION (path) != 0)
die ("search_by_entry_key: item not found by corresponding delimiting key");
}
/* next item is the part of this directory */
path->pos_in_item = 0;
return POSITION_NOT_FOUND;
}
/* previous item is part of desired directory */
if (ubin_search (&(key->u.k_offset_v1.k_offset), B_I_DEH (bh, ih), ih_entry_count (ih),
DEH_SIZE, &(path->pos_in_item), comp_dir_entries) == ITEM_FOUND)
return POSITION_FOUND;
return POSITION_NOT_FOUND;
}
/* key is key of byte in the regular file. This searches in tree
through items and in the found item as well */
int usearch_by_position (struct super_block * s, struct key * key, int version, struct path * path)
{
struct buffer_head * bh;
struct item_head * ih;
if (usearch_by_key (s, key, path) == ITEM_FOUND)
{
ih = PATH_PITEM_HEAD (path);
if (!is_direct_ih(ih) && !is_indirect_ih(ih))
return DIRECTORY_FOUND;
path->pos_in_item = 0;
return POSITION_FOUND;
}
bh = PATH_PLAST_BUFFER (path);
ih = PATH_PITEM_HEAD (path);
if ( (PATH_LAST_POSITION(path) < B_NR_ITEMS (bh)) &&
!not_of_one_file (&ih->ih_key, key) &&
(get_offset(&ih->ih_key) == get_offset(key)) )
{
if (!is_direct_ih(ih) && !is_indirect_ih(ih))
return DIRECTORY_FOUND;
path->pos_in_item = 0;
return POSITION_FOUND;
}
if (PATH_LAST_POSITION (path) == 0) {
/* previous item does not exist, that means we are in leftmost leaf of the tree */
if (!not_of_one_file (B_N_PKEY (bh, 0), key)) {
if (!is_direct_ih(ih) && !is_indirect_ih (ih))
return DIRECTORY_FOUND;
return POSITION_NOT_FOUND;
}
return FILE_NOT_FOUND;
}
/* take previous item */
PATH_LAST_POSITION (path) --;
ih = PATH_PITEM_HEAD (path);
if (not_of_one_file (&ih->ih_key, key) || is_stat_data_ih(ih)) {
struct key * next_key;
/* previous item belongs to another object or is a stat data, check next item */
PATH_LAST_POSITION (path) ++;
if (PATH_LAST_POSITION (path) < B_NR_ITEMS (PATH_PLAST_BUFFER (path)))
/* next key is in the same node */
next_key = B_N_PKEY (PATH_PLAST_BUFFER (path), PATH_LAST_POSITION (path));
else
next_key = uget_rkey (path);
if (next_key == 0 || not_of_one_file (next_key, key)) {
/* there is no any part of such file in the tree */
path->pos_in_item = 0;
return FILE_NOT_FOUND;
}
if (is_direntry_key (next_key)) {
fsck_log ("\nusearch_by_position: looking for %k found a directory with the same key\n", next_key);
return DIRECTORY_FOUND;
}
/* next item is the part of this file */
path->pos_in_item = 0;
if ( get_offset(next_key) == get_offset(key) ) {
pathrelse(path);
if (usearch_by_key (s, next_key, path) != ITEM_FOUND) {
reiserfs_panic ("usearch_by_position: keys must be equals %k %k",
next_key, &PATH_PITEM_HEAD (path)->ih_key);
}
return POSITION_FOUND;
}
return POSITION_NOT_FOUND;
}
if (is_direntry_ih(ih)) {
return DIRECTORY_FOUND;
}
if (is_stat_data_ih(ih)) {
PATH_LAST_POSITION (path) ++;
return FILE_NOT_FOUND;
}
/* previous item is part of desired file */
//if (is_key_in_item (bh,ih,key,bh->b_size)) {
if (I_K_KEY_IN_ITEM (ih, key, bh->b_size)) {
path->pos_in_item = get_offset (key) - get_offset (&ih->ih_key);
if (is_indirect_ih (ih) )
path->pos_in_item /= bh->b_size;
return POSITION_FOUND;
}
path->pos_in_item = is_indirect_ih (ih) ? I_UNFM_NUM (ih) : ih_item_len (ih);
return POSITION_NOT_FOUND;
}
static unsigned long first_child (struct buffer_head * bh)
{
return child_block_number (bh, 0);
}
#if 0
static unsigned long last_child (struct buffer_head * bh)
{
return child_block_number (bh, node_item_number (bh));
}
#endif
static unsigned long get_child (int pos, struct buffer_head * parent)
{
if (pos == -1)
return -1;
if (pos > B_NR_ITEMS (parent))
die ("get_child: no child found, should not happen: %d of %d", pos, B_NR_ITEMS (parent));
return child_block_number (parent, pos);
/*
for (i = 0; i < B_NR_ITEMS (parent); i ++)
{
if (child_block_number (parent, i) == block)
return child_block_number (parent, i + 1);
}
die ("next_child: no child found: should not happen");
return 0;
*/
}
static void print (int cur, int total)
{
printf ("/%3d (of %3d)", cur, total);fflush (stdout);
}
/* erase /XXX(of XXX) */
static void erase (void)
{
printf ("\b\b\b\b\b\b\b\b\b\b\b\b\b");
printf (" ");
printf ("\b\b\b\b\b\b\b\b\b\b\b\b\b");
fflush (stdout);
}
#if 0
void pass_through_tree2 (struct super_block * s, do_after_read_t action1,
do_on_full_path_t action2)
{
struct buffer_head * path[MAX_HEIGHT] = {0,};
int total[MAX_HEIGHT] = {0,};
int cur[MAX_HEIGHT] = {0,};
int h = 0;
unsigned long block = SB_ROOT_BLOCK (s);
int del_p;
if (block >= SB_BLOCK_COUNT (s) || not_data_block (s, block))
return;
while ( 1 ) {
if (path[h])
die ("pass_through_tree: empty slot expected");
if (h)
print (cur[h - 1], total[h - 1]);
path[h] = bread (s->s_dev, block, s->s_blocksize);
get_child (-1, path[h]);
if (path[h] == 0)
reiserfs_warning ("pass_through_tree: unable to read %lu block on device 0x%x\n",
block, s->s_dev);
del_p = 0;
if (path[h] && action1) {
if (action1 (s, path, h)) {
;
#if 0
// something wrong with a buffer we just have read
if (opt_fsck_mode == FSCK_FAST_REBUILD){
//need to change the way we are going on
del_p = 1;
if (h == 0)
break;
} else {
;
//reiserfs_panic (s, "Run reiserfsck with --rebuild-tree\n");
}
#endif
}
}
if (!path[h] || is_leaf_node (path[h]))
{
if (path[h] && action2) {
if (action2 (s, path, h)) {
;
#if 0
if (opt_fsck_mode == FSCK_FAST_REBUILD) {
//need to change the way we are going on
del_p = 1;
if (h == 0)
break;
} else {
;
//reiserfs_panic (s, "Run reiserfsck with --rebuild-tree\n");
}
#endif
}
}
if (path[h])
brelse (path[h]);
if (h)
erase ();
while (h && (!path[h-1] || cur[h-1] == total[h-1] ))
{
path[h] = 0;
h --;
if (path[h])
brelse (path[h]);
if (h)
erase ();
}
if (h == 0) {
path[h] = 0;
break;
}
if (path[h])
cur[h - 1] ++;
if (del_p){
total[h-1]--;
del_p = 0;
}
block = get_child (cur[h - 1] - 1, path[h-1]);
path[h] = 0;
continue;
}
total[h] = B_NR_ITEMS (path[h]) + 1;
cur[h] = 1;
block = first_child (path[h]);
h ++;
}
}
#endif
void pass_through_tree (struct super_block * s, do_after_read_t action1,
do_on_full_path_t action2)
{
struct buffer_head * path[MAX_HEIGHT] = {0,};
int total[MAX_HEIGHT] = {0,};
int cur[MAX_HEIGHT] = {0,};
int h = 0;
unsigned long block = SB_ROOT_BLOCK (s);
if (block >= SB_BLOCK_COUNT (s) || not_data_block (s, block)) {
fsck_progress ("\nBad root block %lu. (--rebuild-tree did not complete)\n", block);
return;
}
while ( 1 ) {
if (path[h])
die ("pass_through_tree: empty slot expected");
if (h)
print (cur[h - 1], total[h - 1]);
path[h] = bread (s->s_dev, block, s->s_blocksize);
if (path[h] == 0)
/* FIXME: handle case when read failed */
die ("pass_through_tree: unable to read %lu block on device 0x%x\n",
block, s->s_dev);
if (action1)
action1 (s, path, h);
if (is_leaf_node (path[h])) {
if (action2)
action2 (s, path, h);
brelse (path[h]);
if (h)
erase ();
while (h && (cur[h-1] == total[h-1])) {
path[h] = 0;
h --;
brelse (path[h]);
if (h)
erase ();
}
if (h == 0) {
path[h] = 0;
break;
}
block = get_child (cur[h - 1], path[h-1]);
cur[h - 1] ++;
path[h] = 0;
continue;
}
total[h] = B_NR_ITEMS (path[h]) + 1;
cur[h] = 1;
block = first_child (path[h]);
h ++;
}
}