Skip to contentSkip to conversation

reiserfs: tree block validation

PATCH New [email protected] 1 participant 5 messages May 9, 2017

lore
Share & tools
lore
#0 lore raw

cover reiserfs: tree block validation

From: Jeff Mahoney <[email protected]>

Hi all -

Over the years, I've received bug reports that mostly fall under the fuzzer heading and were relatively low priority since physical access to the hardware was required to actually get the corrupted file system mounted. Those days are long over and real validation is required.

Reiserfs has had the CONFIG_REISERFS_CHECK mode since the beginning to do some sanity checking, but it's usually so heavyweight that it becomes a performance impediment.

This patch set takes care of a few outstanding issues:
1) fixes the print formatting so that we don't end up with multiple threads accessing the error_buf at once. Only one thread can change it, but another thread can overwrite it while another is printing it.
2) Adds tree block validation during media read and immediately before the block lands in the journal. In this way, we can ensure we get an EIO instead of malformed records that can cause failures later.

The impetus, for me, is a real corruption bug that ended up crashing a system. This doesn't identify the corruption but it does limit the damage it can cause. I'm working on a followup patch to this series that cleans up the journal dirtying in the tree balance code so that we can invoke the validator in journal_mark_tree_block_dirty instead of waiting for commit. Then we will be able to more or less pinpoint corruption immediately. I have no target date for the completion of that work yet, so I wanted to post these now.

-Jeff

Jeff Mahoney (4):
reiserfs: constify read-only helpers
reiserfs: use snprintf for buffer formatting
reiserfs: protect message formatting and printing with mutex
reiserfs: perform tree block sanity checks at read/write

 fs/reiserfs/do_balan.c |   7 +-
 fs/reiserfs/fix_node.c |   4 +-
 fs/reiserfs/inode.c    |   6 +-
 fs/reiserfs/journal.c  |  42 +++++-
 fs/reiserfs/namei.c    |   6 +-
 fs/reiserfs/prints.c   | 253 ++++++++++++++++++++++-----------
 fs/reiserfs/reiserfs.h |  57 +++++---
 fs/reiserfs/stree.c    | 372 ++++++++++++++++++++++++++++++++++++++++++++++++-
 fs/reiserfs/super.c    |   8 +-
 9 files changed, 632 insertions(+), 123 deletions(-)
Signature · 1 line
2.11.0
#1 lore raw

PATCH 1/4 reiserfs: constify read-only helpers

From: Jeff Mahoney <[email protected]>

Basic cleanup - constifying some helper routines.

---
 fs/reiserfs/prints.c   |  2 +-
 fs/reiserfs/reiserfs.h | 43 +++++++++++++++++++++++--------------------
 fs/reiserfs/super.c    |  8 ++++----
 3 files changed, 28 insertions(+), 25 deletions(-)
fs/reiserfs/prints.c +1 -1
index 4f3f928076f3..2f6a7b42fa31 100644
@@ -261,7 +261,7 @@ static void prepare_error_buf(const char *fmt, va_list args)
     va_end( args );\
 }
 
-void __reiserfs_warning(struct super_block *sb, const char *id,
+void __reiserfs_warning(const struct super_block *sb, const char *id,
 			 const char *function, const char *fmt, ...)
 {
 	do_reiserfs_warning(fmt);
fs/reiserfs/reiserfs.h +23 -20

136 lines not on this page · raw message

fs/reiserfs/super.c +4 -4
index 685f1e056998..c1a252f175ad 100644
@@ -37,25 +37,25 @@ static const char reiserfs_3_5_magic_string[] = REISERFS_SUPER_MAGIC_STRING;
 static const char reiserfs_3_6_magic_string[] = REISER2FS_SUPER_MAGIC_STRING;
 static const char reiserfs_jr_magic_string[] = REISER2FS_JR_SUPER_MAGIC_STRING;
 
-int is_reiserfs_3_5(struct reiserfs_super_block *rs)
+int is_reiserfs_3_5(const struct reiserfs_super_block *rs)
 {
 	return !strncmp(rs->s_v1.s_magic, reiserfs_3_5_magic_string,
 			strlen(reiserfs_3_5_magic_string));
 }
 
-int is_reiserfs_3_6(struct reiserfs_super_block *rs)
+int is_reiserfs_3_6(const struct reiserfs_super_block *rs)
 {
 	return !strncmp(rs->s_v1.s_magic, reiserfs_3_6_magic_string,
 			strlen(reiserfs_3_6_magic_string));
 }
 
-int is_reiserfs_jr(struct reiserfs_super_block *rs)
+int is_reiserfs_jr(const struct reiserfs_super_block *rs)
 {
 	return !strncmp(rs->s_v1.s_magic, reiserfs_jr_magic_string,
 			strlen(reiserfs_jr_magic_string));
 }
 
-static int is_any_reiserfs_magic_string(struct reiserfs_super_block *rs)
+static int is_any_reiserfs_magic_string(const struct reiserfs_super_block *rs)
 {
 	return (is_reiserfs_3_5(rs) || is_reiserfs_3_6(rs) ||
 		is_reiserfs_jr(rs));
Signature · 1 line
2.11.0
#2 lore raw

PATCH 2/4 reiserfs: use snprintf for buffer formatting

In reply to [email protected]

From: Jeff Mahoney <[email protected]>

We use a fixed-length buffer for formatting messages but don't do any bounds checking on it. This patch makes proper use of snprintf and bounds tracking to ensure that we don't overflow.

---
 fs/reiserfs/prints.c | 213 +++++++++++++++++++++++++++++++++------------------
 1 file changed, 138 insertions(+), 75 deletions(-)
fs/reiserfs/prints.c +138 -75
index 2f6a7b42fa31..1af3febb0419 100644
@@ -6,6 +6,7 @@
 #include <linux/fs.h>
 #include "reiserfs.h"
 #include <linux/string.h>
+#include <linux/ctype.h>
 #include <linux/buffer_head.h>
 
 #include <stdarg.h>
@@ -76,83 +77,111 @@ static char *le_type(struct reiserfs_key *key)
 }
 
 /* %k */
-static void sprintf_le_key(char *buf, struct reiserfs_key *key)
+static int snprintf_le_key(char *buf, size_t size, struct reiserfs_key *key)
 {
-	if (key)
-		sprintf(buf, "[%d %d %s %s]", le32_to_cpu(key->k_dir_id),
+	if (!key)
+		return snprintf(buf, size, "[NULL]");
+
+	return snprintf(buf, size, "[%d %d %s %s]", le32_to_cpu(key->k_dir_id),
 			le32_to_cpu(key->k_objectid), le_offset(key),
 			le_type(key));
-	else
-		sprintf(buf, "[NULL]");
 }
 
 /* %K */
-static void sprintf_cpu_key(char *buf, struct cpu_key *key)
+static int snprintf_cpu_key(char *buf, size_t size, struct cpu_key *key)
 {
-	if (key)
-		sprintf(buf, "[%d %d %s %s]", key->on_disk_key.k_dir_id,
+	if (!key)
+		return snprintf(buf, size, "[NULL]");
+
+	return snprintf(buf, size, "[%d %d %s %s]", key->on_disk_key.k_dir_id,
 			key->on_disk_key.k_objectid, reiserfs_cpu_offset(key),
 			cpu_type(key));
-	else
-		sprintf(buf, "[NULL]");
 }
 
-static void sprintf_de_head(char *buf, struct reiserfs_de_head *deh)
+static int snprintf_de_head(char *buf, size_t size,
+			    struct reiserfs_de_head *deh)
 {
-	if (deh)
-		sprintf(buf,
-			"[offset=%d dir_id=%d objectid=%d location=%d state=%04x]",
+	if (!deh)
+		return snprintf(buf, size, "[NULL]");
+
+	return snprintf(buf, size,
+		        "[offset=%d dir_id=%d objectid=%d location=%d state=%04x]",
 			deh_offset(deh), deh_dir_id(deh), deh_objectid(deh),
 			deh_location(deh), deh_state(deh));
-	else
-		sprintf(buf, "[NULL]");
-
 }
 
-static void sprintf_item_head(char *buf, struct item_head *ih)
+static int snprintf_item_head(char *buf, size_t size, struct item_head *ih)
 {
-	if (ih) {
-		strcpy(buf,
-		       (ih_version(ih) == KEY_FORMAT_3_6) ? "*3.6* " : "*3.5*");
-		sprintf_le_key(buf + strlen(buf), &(ih->ih_key));
-		sprintf(buf + strlen(buf), ", item_len %d, item_location %d, "
-			"free_space(entry_count) %d",
-			ih_item_len(ih), ih_location(ih), ih_free_space(ih));
-	} else
-		sprintf(buf, "[NULL]");
+	const char *key_format;
+	int used = 0;
+	if (!ih)
+		return snprintf(buf, size, "[NULL]");
+
+	key_format = (ih_version(ih) == KEY_FORMAT_3_6) ? "*3.6*" : "*3.5*";
+	used += snprintf(buf, size, "%s", key_format);
+	if (used > size)
+		return used;
+
+	used += snprintf_le_key(buf + used, size - used, &(ih->ih_key));
+	if (used > size)
+		return used;
+
+	used += snprintf(buf + used, size - used,
+			 ", item_len %d, item_location %d, free_space(entry_count) %d",
+			 ih_item_len(ih), ih_location(ih), ih_free_space(ih));
+	return used;
 }
 
-static void sprintf_direntry(char *buf, struct reiserfs_dir_entry *de)
+static int snprintf_direntry(char *buf, size_t size,
+			     struct reiserfs_dir_entry *de)
 {
 	char name[20];
 
-	memcpy(name, de->de_name, de->de_namelen > 19 ? 19 : de->de_namelen);
-	name[de->de_namelen > 19 ? 19 : de->de_namelen] = 0;
-	sprintf(buf, "\"%s\"==>[%d %d]", name, de->de_dir_id, de->de_objectid);
+	if (!de)
+		return snprintf(buf, size, "[NULL]");
+
+	if (de->de_name) {
+		memcpy(name, de->de_name, de->de_namelen > 19 ? 19 : de->de_namelen);
+		name[de->de_namelen > 19 ? 19 : de->de_namelen] = 0;
+	} else
+		strcpy(name, "[NULL]");
+	return snprintf(buf, size, "\"%s\"==>[%d %d]",
+			name, de->de_dir_id, de->de_objectid);
 }
 
-static void sprintf_block_head(char *buf, struct buffer_head *bh)
+static int snprintf_block_head(char *buf, size_t size, struct buffer_head *bh)
 {
-	sprintf(buf, "level=%d, nr_items=%d, free_space=%d rdkey ",
-		B_LEVEL(bh), B_NR_ITEMS(bh), B_FREE_SPACE(bh));
+	if (!bh)
+		return snprintf(buf, size, "[NULL]");
+
+	return snprintf(buf, size,
+			"level=%d, nr_items=%d, free_space=%d rdkey ",
+			B_LEVEL(bh), B_NR_ITEMS(bh), B_FREE_SPACE(bh));
 }
 
-static void sprintf_buffer_head(char *buf, struct buffer_head *bh)
+static int snprintf_buffer_head(char *buf, size_t size, struct buffer_head *bh)
 {
-	sprintf(buf,
-		"dev %pg, size %zd, blocknr %llu, count %d, state 0x%lx, page %p, (%s, %s, %s)",
-		bh->b_bdev, bh->b_size,
-		(unsigned long long)bh->b_blocknr, atomic_read(&(bh->b_count)),
-		bh->b_state, bh->b_page,
-		buffer_uptodate(bh) ? "UPTODATE" : "!UPTODATE",
-		buffer_dirty(bh) ? "DIRTY" : "CLEAN",
-		buffer_locked(bh) ? "LOCKED" : "UNLOCKED");
+	if (!bh)
+		return snprintf(buf, size, "[NULL]");
+
+	return snprintf(buf, size,
+			"dev %pg, size %zd, blocknr %llu, count %d, state 0x%lx, page %p, (%s, %s, %s)",
+			bh->b_bdev, bh->b_size,
+			(unsigned long long)bh->b_blocknr,
+			atomic_read(&bh->b_count),
+			bh->b_state, bh->b_page,
+			buffer_uptodate(bh) ? "UPTODATE" : "!UPTODATE",
+			buffer_dirty(bh) ? "DIRTY" : "CLEAN",
+			buffer_locked(bh) ? "LOCKED" : "UNLOCKED");
 }
 
-static void sprintf_disk_child(char *buf, struct disk_child *dc)
+static int snprintf_disk_child(char *buf, size_t size, struct disk_child *dc)
 {
-	sprintf(buf, "[dc_number=%d, dc_size=%u]", dc_block_number(dc),
-		dc_size(dc));
+	if (!dc)
+		return snprintf(buf, size, "[NULL]");
+
+	return snprintf(buf, size, "[dc_number=%d, dc_size=%u]",
+			dc_block_number(dc), dc_size(dc));
 }
 
 static char *is_there_reiserfs_struct(char *fmt, int *what)
@@ -160,8 +189,14 @@ static char *is_there_reiserfs_struct(char *fmt, int *what)
 	char *k = fmt;
 
 	while ((k = strchr(k, '%')) != NULL) {
-		if (k[1] == 'k' || k[1] == 'K' || k[1] == 'h' || k[1] == 't' ||
-		    k[1] == 'z' || k[1] == 'b' || k[1] == 'y' || k[1] == 'a') {
+		if (k[1] == 'k' || k[1] == 'K' || k[1] == 't' ||
+		    k[1] == 'b' || k[1] == 'y' || k[1] == 'a') {
+			*what = k[1];
+			break;
+		}
+
+		/* We can't gobble up normal qualifiers */
+		if ((k[1] == 'z' || k[1] == 'h') && !isalpha(k[2])) {
 			*what = k[1];
 			break;
 		}
@@ -190,6 +225,8 @@ static void prepare_error_buf(const char *fmt, va_list args)
 	char *k;
 	char *p = error_buf;
 	int what;
+	int left = sizeof(error_buf);
+	int bytes = 0;
 
 	spin_lock(&error_lock);
 
@@ -198,46 +235,72 @@ static void prepare_error_buf(const char *fmt, va_list args)
 	while ((k = is_there_reiserfs_struct(fmt1, &what)) != NULL) {
 		*k = 0;
 
-		p += vsprintf(p, fmt1, args);
+		bytes = vsnprintf(p, left, fmt1, args);
+		if (bytes >= left)
+			goto out;
+
+		p += bytes;
+		left -= bytes;
 
 		switch (what) {
-		case 'k':
-			sprintf_le_key(p, va_arg(args, struct reiserfs_key *));
-			break;
-		case 'K':
-			sprintf_cpu_key(p, va_arg(args, struct cpu_key *));
+		case 'k': {
+			struct reiserfs_key *key;
+			key = va_arg(args, struct reiserfs_key *);
+			bytes = snprintf_le_key(p, left, key);
 			break;
-		case 'h':
-			sprintf_item_head(p, va_arg(args, struct item_head *));
+		}
+		case 'K': {
+			struct cpu_key *key;
+			key = va_arg(args, struct cpu_key *);
+			bytes = snprintf_cpu_key(p, left, key);
 			break;
-		case 't':
-			sprintf_direntry(p,
-					 va_arg(args,
-						struct reiserfs_dir_entry *));
+		}
+		case 'h': {
+			struct item_head *ih;
+			ih = va_arg(args, struct item_head *);
+			bytes = snprintf_item_head(p, left, ih);
 			break;
-		case 'y':
-			sprintf_disk_child(p,
-					   va_arg(args, struct disk_child *));
+		}
+		case 't': {
+			struct reiserfs_dir_entry *de;
+			de = va_arg(args, struct reiserfs_dir_entry *);
+			bytes = snprintf_direntry(p, left, de);
 			break;
-		case 'z':
-			sprintf_block_head(p,
-					   va_arg(args, struct buffer_head *));
+		}
+		case 'y': {
+			struct disk_child *dc;
+			dc = va_arg(args, struct disk_child *);
+			bytes = snprintf_disk_child(p, left, dc);
 			break;
-		case 'b':
-			sprintf_buffer_head(p,
-					    va_arg(args, struct buffer_head *));
+		}
+		case 'z': {
+			struct buffer_head *bh;
+			bh = va_arg(args, struct buffer_head *);
+			bytes = snprintf_block_head(p, left, bh);
 			break;
-		case 'a':
-			sprintf_de_head(p,
-					va_arg(args,
-					       struct reiserfs_de_head *));
+		}
+		case 'b': {
+			struct buffer_head *bh;
+			bh = va_arg(args, struct buffer_head *);
+			bytes = snprintf_buffer_head(p, left, bh);
 			break;
 		}
+		case 'a': {
+			struct reiserfs_de_head *deh;
+			deh = va_arg(args, struct reiserfs_de_head *);
+			bytes = snprintf_de_head(p, left, deh);
+			break;
+		}};
+
+		if (bytes >= left)
+			goto out;
 
-		p += strlen(p);
+		p += bytes;
+		left -= bytes;
 		fmt1 = k + 2;
 	}
-	vsprintf(p, fmt1, args);
+out:
+	vsnprintf(p, left, fmt1, args);
 	spin_unlock(&error_lock);
 
 }
Signature · 1 line
2.11.0
#3 lore raw

PATCH 3/4 reiserfs: protect message formatting and printing with mutex

In reply to [email protected]

From: Jeff Mahoney <[email protected]>

Reiserfs uses a static buffer for formatting and printing messages. It's possible for one thread to overwrite the buffer while another is printing it. Depending on timing, it's possible to get the printer to crash if a pointer argument lands at the right time. We use a spinlock to protect against concurrent formatting, but it doesn't cover printk. This patch converts the spinlock to a mutex and covers the printk as well. There are currently no callers of these routines that do so with a spinlock held.

---
 fs/reiserfs/prints.c | 26 +++++++++++++++++++-------
 1 file changed, 19 insertions(+), 7 deletions(-)
fs/reiserfs/prints.c +19 -7
index 1af3febb0419..db7b02b06fcc 100644
@@ -218,7 +218,7 @@ static char *is_there_reiserfs_struct(char *fmt, int *what)
  * printk ("bad key %lu %lu %lu %lu", key->k_dir_id, key->k_objectid,
  *         key->k_offset, key->k_uniqueness);
  */
-static DEFINE_SPINLOCK(error_lock);
+static DEFINE_MUTEX(error_lock);
 static void prepare_error_buf(const char *fmt, va_list args)
 {
 	char *fmt1 = fmt_buf;
@@ -228,7 +228,7 @@ static void prepare_error_buf(const char *fmt, va_list args)
 	int left = sizeof(error_buf);
 	int bytes = 0;
 
-	spin_lock(&error_lock);
+	WARN_ON(!mutex_is_locked(&error_lock));
 
 	strcpy(fmt1, fmt);
 
@@ -301,8 +301,6 @@ static void prepare_error_buf(const char *fmt, va_list args)
 	}
 out:
 	vsnprintf(p, left, fmt1, args);
-	spin_unlock(&error_lock);
-
 }
 
 /*
@@ -327,6 +325,7 @@ static void prepare_error_buf(const char *fmt, va_list args)
 void __reiserfs_warning(const struct super_block *sb, const char *id,
 			 const char *function, const char *fmt, ...)
 {
+	mutex_lock(&error_lock);
 	do_reiserfs_warning(fmt);
 	if (sb)
 		printk(KERN_WARNING "REISERFS warning (device %s): %s%s%s: "
@@ -335,35 +334,42 @@ void __reiserfs_warning(const struct super_block *sb, const char *id,
 	else
 		printk(KERN_WARNING "REISERFS warning: %s%s%s: %s\n",
 		       id ? id : "", id ? " " : "", function, error_buf);
+	mutex_unlock(&error_lock);
 }
 
 /* No newline.. reiserfs_info calls can be followed by printk's */
 void reiserfs_info(struct super_block *sb, const char *fmt, ...)
 {
+	mutex_lock(&error_lock);
 	do_reiserfs_warning(fmt);
 	if (sb)
 		printk(KERN_NOTICE "REISERFS (device %s): %s",
 		       sb->s_id, error_buf);
 	else
 		printk(KERN_NOTICE "REISERFS %s:", error_buf);
+	mutex_unlock(&error_lock);
 }
 
 /* No newline.. reiserfs_printk calls can be followed by printk's */
 static void reiserfs_printk(const char *fmt, ...)
 {
+	mutex_lock(&error_lock);
 	do_reiserfs_warning(fmt);
 	printk(error_buf);
+	mutex_unlock(&error_lock);
 }
 
 void reiserfs_debug(struct super_block *s, int level, const char *fmt, ...)
 {
 #ifdef CONFIG_REISERFS_CHECK
+	mutex_lock(&error_lock);
 	do_reiserfs_warning(fmt);
 	if (s)
 		printk(KERN_DEBUG "REISERFS debug (device %s): %s\n",
 		       s->s_id, error_buf);
 	else
 		printk(KERN_DEBUG "REISERFS debug: %s\n", error_buf);
+	mutex_unlock(&error_lock);
 #endif
 }
 
@@ -417,6 +423,7 @@ void reiserfs_debug(struct super_block *s, int level, const char *fmt, ...)
 void __reiserfs_panic(struct super_block *sb, const char *id,
 		      const char *function, const char *fmt, ...)
 {
+	mutex_lock(&error_lock);
 	do_reiserfs_warning(fmt);
 
 #ifdef CONFIG_REISERFS_CHECK
@@ -429,16 +436,16 @@ void __reiserfs_panic(struct super_block *sb, const char *id,
 	else
 		printk(KERN_WARNING "REISERFS panic: %s%s%s: %s\n",
 		      id ? id : "", id ? " " : "", function, error_buf);
+	mutex_unlock(&error_lock);
 	BUG();
 }
 
 void __reiserfs_error(struct super_block *sb, const char *id,
 		      const char *function, const char *fmt, ...)
 {
+	mutex_lock(&error_lock);
 	do_reiserfs_warning(fmt);
 
-	BUG_ON(sb == NULL);
-
 	if (reiserfs_error_panic(sb))
 		__reiserfs_panic(sb, id, function, error_buf);
 
@@ -448,6 +455,7 @@ void __reiserfs_error(struct super_block *sb, const char *id,
 	else
 		printk(KERN_CRIT "REISERFS error (device %s): %s: %s\n",
 		       sb->s_id, function, error_buf);
+	mutex_unlock(&error_lock);
 
 	if (sb->s_flags & MS_RDONLY)
 		return;
@@ -459,6 +467,7 @@ void __reiserfs_error(struct super_block *sb, const char *id,
 
 void reiserfs_abort(struct super_block *sb, int errno, const char *fmt, ...)
 {
+	mutex_lock(&error_lock);
 	do_reiserfs_warning(fmt);
 
 	if (reiserfs_error_panic(sb)) {
@@ -466,11 +475,14 @@ void reiserfs_abort(struct super_block *sb, int errno, const char *fmt, ...)
 		      error_buf);
 	}
 
-	if (reiserfs_is_journal_aborted(SB_JOURNAL(sb)))
+	if (reiserfs_is_journal_aborted(SB_JOURNAL(sb))) {
+		mutex_unlock(&error_lock);
 		return;
+	}
 
 	printk(KERN_CRIT "REISERFS abort (device %s): %s\n", sb->s_id,
 	       error_buf);
+	mutex_unlock(&error_lock);
 
 	sb->s_flags |= MS_RDONLY;
 	reiserfs_abort_journal(sb, errno);
Signature · 1 line
2.11.0
#4 lore raw

PATCH 4/4 reiserfs: perform tree block sanity checks at read/write

In reply to [email protected]

From: Jeff Mahoney <[email protected]>

This patch adds tree block sanity checks at read/write time. The read portion is performed as part of the endio for the readers, for which there are now several helpers. The write portion is performed immediately before writing to the journal. The tree blocks are annotated with a new journal_mark_tree_block_dirty helper that sets a bit in the cnode to track what journaled blocks are tree blocks. The checker does some basic checks regarding key ordering, item size, directory entry parameters, and block numbers in indirect items. The idea is that we'll get an EIO when the buffer is read so we don't hit most kinds of fuzzer issues. On the write path, we'll go read-only before the buffer is committed to disk.

---
 fs/reiserfs/do_balan.c |   7 +-
 fs/reiserfs/fix_node.c |   4 +-
 fs/reiserfs/inode.c    |   6 +-
 fs/reiserfs/journal.c  |  42 +++++-
 fs/reiserfs/namei.c    |   6 +-
 fs/reiserfs/prints.c   |  12 ++
 fs/reiserfs/reiserfs.h |  14 +-
 fs/reiserfs/stree.c    | 372 ++++++++++++++++++++++++++++++++++++++++++++++++-
 8 files changed, 447 insertions(+), 16 deletions(-)
fs/reiserfs/do_balan.c +6 -1
index 9c02d96d3a42..456f41b857f4 100644
@@ -56,11 +56,16 @@ static inline void buffer_info_init_bh(struct tree_balance *tb,
 inline void do_balance_mark_leaf_dirty(struct tree_balance *tb,
 				       struct buffer_head *bh, int flag)
 {
+	journal_mark_tree_block_dirty(tb->transaction_handle, bh);
+}
+
+inline void do_balance_mark_sb_dirty(struct tree_balance *tb,
+				       struct buffer_head *bh, int flag)
+{
 	journal_mark_dirty(tb->transaction_handle, bh);
 }
 
 #define do_balance_mark_internal_dirty do_balance_mark_leaf_dirty
-#define do_balance_mark_sb_dirty do_balance_mark_leaf_dirty
 
 /*
  * summary:
fs/reiserfs/fix_node.c +2 -2
index 6b0ddb2a9091..fc6a3b5eb22e 100644
@@ -2178,7 +2178,7 @@ static int get_neighbors(struct tree_balance *tb, int h)
 								       FL[h]);
 		son_number = B_N_CHILD_NUM(tb->FL[h], child_position);
 		depth = reiserfs_write_unlock_nested(tb->tb_sb);
-		bh = sb_bread(sb, son_number);
+		bh = reiserfs_bread_tree_block(sb, son_number);
 		reiserfs_write_lock_nested(tb->tb_sb, depth);
 		if (!bh)
 			return IO_ERROR;
@@ -2218,7 +2218,7 @@ static int get_neighbors(struct tree_balance *tb, int h)
 		    (bh == tb->FR[h]) ? tb->rkey[h] + 1 : 0;
 		son_number = B_N_CHILD_NUM(tb->FR[h], child_position);
 		depth = reiserfs_write_unlock_nested(tb->tb_sb);
-		bh = sb_bread(sb, son_number);
+		bh = reiserfs_bread_tree_block(sb, son_number);
 		reiserfs_write_lock_nested(tb->tb_sb, depth);
 		if (!bh)
 			return IO_ERROR;
fs/reiserfs/inode.c +3 -3
index 873fc04e9403..9e0369ee1ca0 100644
@@ -817,7 +817,7 @@ int reiserfs_get_block(struct inode *inode, sector_t block,
 				reiserfs_add_ordered_list(inode, bh_result);
 			put_block_num(item, pos_in_item, allocated_block_nr);
 			unfm_ptr = allocated_block_nr;
-			journal_mark_dirty(th, bh);
+			journal_mark_tree_block_dirty(th, bh);
 			reiserfs_update_sd(th, inode);
 		}
 		set_block_dev_mapped(bh_result, unfm_ptr, inode);
@@ -1504,7 +1504,7 @@ void reiserfs_update_sd_size(struct reiserfs_transaction_handle *th,
 		break;
 	}
 	update_stat_data(&path, inode, size);
-	journal_mark_dirty(th, bh);
+	journal_mark_tree_block_dirty(th, bh);
 	pathrelse(&path);
 	return;
 }
@@ -2452,7 +2452,7 @@ static int map_block_for_writepage(struct inode *inode,
 		memcpy(ih_item_body(bh, ih) + pos_in_item, p + bytes_copied,
 		       copy_size);
 
-		journal_mark_dirty(&th, bh);
+		journal_mark_tree_block_dirty(&th, bh);
 		bytes_copied += copy_size;
 		set_block_dev_mapped(bh_result, 0, inode);
 
fs/reiserfs/journal.c +40 -2

78 lines not on this page · raw message

fs/reiserfs/namei.c +3 -3
index bd39a998843d..a46221a38b46 100644
@@ -1567,10 +1567,10 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 
 	mark_de_visible(new_de.de_deh + new_de.de_entry_num);
 	set_ino_in_dir_entry(&new_de, INODE_PKEY(old_inode));
-	journal_mark_dirty(&th, new_de.de_bh);
+	journal_mark_tree_block_dirty(&th, new_de.de_bh);
 
 	mark_de_hidden(old_de.de_deh + old_de.de_entry_num);
-	journal_mark_dirty(&th, old_de.de_bh);
+	journal_mark_tree_block_dirty(&th, old_de.de_bh);
 	ctime = current_time(old_dir);
 	old_dir->i_ctime = old_dir->i_mtime = ctime;
 	new_dir->i_ctime = new_dir->i_mtime = ctime;
@@ -1594,7 +1594,7 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 	if (S_ISDIR(old_inode_mode)) {
 		/* adjust ".." of renamed directory */
 		set_ino_in_dir_entry(&dot_dot_de, INODE_PKEY(new_dir));
-		journal_mark_dirty(&th, dot_dot_de.de_bh);
+		journal_mark_tree_block_dirty(&th, dot_dot_de.de_bh);
 
 		/*
 		 * there (in new_dir) was no directory, so it got new link
fs/reiserfs/prints.c +12 -0
index db7b02b06fcc..86346e868ad4 100644
@@ -337,6 +337,18 @@ void __reiserfs_warning(const struct super_block *sb, const char *id,
 	mutex_unlock(&error_lock);
 }
 
+void reiserfs_corrupt(const struct super_block *sb,
+		      const struct buffer_head *bh,
+		      const char *id, const char *fmt, ...)
+{
+	mutex_lock(&error_lock);
+	do_reiserfs_warning(fmt);
+	pr_err("REISERFS corruption detected (device %s, block %llu): %s %s",
+	       sb->s_id, (unsigned long long)bh->b_blocknr, id,
+	       error_buf);
+	mutex_unlock(&error_lock);
+}
+
 /* No newline.. reiserfs_info calls can be followed by printk's */
 void reiserfs_info(struct super_block *sb, const char *fmt, ...)
 {
fs/reiserfs/reiserfs.h +13 -1
index 15078039367a..75e4284c7c8f 100644
@@ -902,6 +902,9 @@ void __reiserfs_warning(const struct super_block *s, const char *id,
 			 const char *func, const char *fmt, ...);
 #define reiserfs_warning(s, id, fmt, args...) \
 	 __reiserfs_warning(s, id, __func__, fmt, ##args)
+void reiserfs_corrupt(const struct super_block *sb,
+		      const struct buffer_head *bh,
+		      const char *id, const char *fmt, ...);
 /* assertions handling */
 
 /* always check a condition and panic if it's false. */
@@ -2885,6 +2888,8 @@ int reiserfs_add_tail_list(struct inode *inode, struct buffer_head *bh);
 int reiserfs_add_ordered_list(struct inode *inode, struct buffer_head *bh);
 int journal_mark_dirty(struct reiserfs_transaction_handle *,
 		       struct buffer_head *bh);
+int journal_mark_tree_block_dirty(struct reiserfs_transaction_handle *,
+				  struct buffer_head *bh);
 
 static inline int reiserfs_file_data_log(const struct inode *inode)
 {
@@ -2966,6 +2971,12 @@ int reiserfs_convert_objectid_map_v1(struct super_block *);
 int B_IS_IN_TREE(const struct buffer_head *);
 extern void copy_item_head(struct item_head *to,
 			   const struct item_head *from);
+int reiserfs_validate_tree_block(const struct super_block *sb,
+				 const struct buffer_head *bh);
+void reiserfs_read_tree_block(struct super_block *sb, struct buffer_head *bh);
+void reiserfs_reada_tree_block(struct super_block *sb, struct buffer_head *bh);
+struct buffer_head *reiserfs_bread_tree_block(struct super_block *sb,
+					      u32 blocknr);
 
 /* first key is in cpu form, second - le */
 extern int comp_short_keys(const struct reiserfs_key *le_key,
@@ -3242,8 +3253,9 @@ int balance_internal(struct tree_balance *, int, int, struct item_head *,
 /* do_balance.c */
 void do_balance_mark_leaf_dirty(struct tree_balance *tb,
 				struct buffer_head *bh, int flag);
+void do_balance_mark_sb_dirty(struct tree_balance *tb,
+			      struct buffer_head *bh, int flag);
 #define do_balance_mark_internal_dirty do_balance_mark_leaf_dirty
-#define do_balance_mark_sb_dirty do_balance_mark_leaf_dirty
 
 void do_balance(struct tree_balance *tb, struct item_head *ih,
 		const char *body, int flag);
fs/reiserfs/stree.c +368 -4

393 lines not on this page · raw message

Signature · 1 line
2.11.0