diff -rupN linux-2.4.7-ac1/Documentation/Configure.help linux-2.4.7-ac1.patched/Documentation/Configure.help
--- linux-2.4.7-ac1/Documentation/Configure.help	Fri Jul 27 22:10:47 2001
+++ linux-2.4.7-ac1.patched/Documentation/Configure.help	Sat Jul 28 15:01:31 2001
@@ -12979,6 +12979,15 @@ CONFIG_REISERFS_CHECK
   report, say yes and you might get a useful error message.  Almost
   everyone should say no.
 
+Publish some reiserfs-specific info under /proc/fs/reiserfs
+CONFIG_REISERFS_PROC_INFO
+  Create under /proc/fs/reiserfs hierarchy of files, displaying
+  various ReiserFS statistics and internal data on the expense of
+  making your kernel or module slightly larger (+8K). This also increases 
+  amount of kernel memory required for each mount. Almost everyone
+  but ReiserFS developers and people fine-tuning reiserfs or tracing
+  problems should say NO.
+
 Second extended fs support
 CONFIG_EXT2_FS
   This is the de facto standard Linux file system (method to organize
diff -rupN linux-2.4.7-ac1/fs/Config.in linux-2.4.7-ac1.patched/fs/Config.in
--- linux-2.4.7-ac1/fs/Config.in	Fri Jul 27 22:11:09 2001
+++ linux-2.4.7-ac1.patched/fs/Config.in	Sat Jul 28 15:01:31 2001
@@ -10,6 +10,7 @@ tristate 'Kernel automounter version 4 s
 
 dep_tristate 'Reiserfs support' CONFIG_REISERFS_FS $CONFIG_EXPERIMENTAL
 dep_mbool '  Have reiserfs do extra internal checking' CONFIG_REISERFS_CHECK $CONFIG_REISERFS_FS $CONFIG_EXPERIMENTAL
+dep_mbool '  Stats in /proc/fs/reiserfs' CONFIG_REISERFS_PROC_INFO $CONFIG_REISERFS_FS $CONFIG_EXPERIMENTAL
 
 dep_tristate 'ADFS file system support' CONFIG_ADFS_FS $CONFIG_EXPERIMENTAL
 dep_mbool '  ADFS write support (DANGEROUS)' CONFIG_ADFS_FS_RW $CONFIG_ADFS_FS $CONFIG_EXPERIMENTAL
diff -rupN linux-2.4.7-ac1/fs/reiserfs/Makefile linux-2.4.7-ac1.patched/fs/reiserfs/Makefile
--- linux-2.4.7-ac1/fs/reiserfs/Makefile	Mon Jan 15 23:42:32 2001
+++ linux-2.4.7-ac1.patched/fs/reiserfs/Makefile	Sat Jul 28 15:01:31 2001
@@ -9,7 +9,7 @@
 
 O_TARGET := reiserfs.o
 obj-y   := bitmap.o do_balan.o namei.o inode.o file.o dir.o fix_node.o super.o prints.o objectid.o \
-lbalance.o ibalance.o stree.o hashes.o buffer2.o tail_conversion.o journal.o resize.o tail_conversion.o version.o item_ops.o ioctl.o
+lbalance.o ibalance.o stree.o hashes.o buffer2.o tail_conversion.o journal.o resize.o tail_conversion.o version.o item_ops.o ioctl.o procfs.o
 
 obj-m   := $(O_TARGET)
 
diff -rupN linux-2.4.7-ac1/fs/reiserfs/bitmap.c linux-2.4.7-ac1.patched/fs/reiserfs/bitmap.c
--- linux-2.4.7-ac1/fs/reiserfs/bitmap.c	Fri Jul 27 23:32:05 2001
+++ linux-2.4.7-ac1.patched/fs/reiserfs/bitmap.c	Sat Jul 28 15:01:31 2001
@@ -95,6 +95,8 @@ void reiserfs_free_block (struct reiserf
   RFALSE(!s, "vs-4060: trying to free block on nonexistent device");
   RFALSE(is_reusable (s, block, 1) == 0, "vs-4070: can not free such block");
 
+  PROC_INFO_INC( s, free_block );
+
   rs = SB_DISK_SUPER_BLOCK (s);
   sbh = SB_BUFFER_WITH_SB (s);
   apbh = SB_AP_BITMAP (s);
@@ -136,10 +138,14 @@ static int find_forward (struct super_bl
   unsigned long block_to_try = 0;
   unsigned long next_block_to_try = 0 ;
 
-  for (i = *bmap_nr; i < SB_BMAP_NR (s); i ++, *offset = 0) {
+  PROC_INFO_INC( s, find_forward.call );
+
+  for (i = *bmap_nr; i < SB_BMAP_NR (s); i ++, *offset = 0, 
+	       PROC_INFO_INC( s, find_forward.bmap )) {
     /* get corresponding bitmap block */
     bh = SB_AP_BITMAP (s)[i];
     if (buffer_locked (bh)) {
+	PROC_INFO_INC( s, find_forward.wait );
         __wait_on_buffer (bh);
     }
 retry:
@@ -174,17 +180,21 @@ retry:
 	  int new_i ;
 	  get_bit_address (s, next_block_to_try, &new_i, offset);
 
+	  PROC_INFO_INC( s, find_forward.in_journal_hint );
+
 	  /* block is not in this bitmap. reset i and continue
 	  ** we only reset i if new_i is in a later bitmap.
 	  */
 	  if (new_i > i) {
 	    i = (new_i - 1 ); /* i gets incremented by the for loop */
+	    PROC_INFO_INC( s, find_forward.in_journal_out );
 	    continue ;
 	  }
 	} else {
 	  /* no suggestion was made, just try the next block */
 	  *offset = j+1 ;
 	}
+	PROC_INFO_INC( s, find_forward.retry );
 	goto retry ;
       }
     }
diff -rupN linux-2.4.7-ac1/fs/reiserfs/buffer2.c linux-2.4.7-ac1.patched/fs/reiserfs/buffer2.c
--- linux-2.4.7-ac1/fs/reiserfs/buffer2.c	Fri Jul 27 22:47:05 2001
+++ linux-2.4.7-ac1.patched/fs/reiserfs/buffer2.c	Sat Jul 28 15:01:31 2001
@@ -16,6 +16,7 @@
 #include <linux/locks.h>
 #include <linux/reiserfs_fs.h>
 #include <linux/smp_lock.h>
+#include <linux/kernel_stat.h>
 
 /*
  *  wait_buffer_until_released
@@ -63,9 +64,16 @@ void wait_buffer_until_released (const s
    block. */
 /* The function is NOT SCHEDULE-SAFE! */
 
-struct buffer_head  * reiserfs_bread (kdev_t n_dev, int n_block, int n_size) 
+struct buffer_head  * reiserfs_bread (struct super_block *super, int n_block, int n_size) 
 {
-    return bread (n_dev, n_block, n_size);
+    struct buffer_head  *result;
+    PROC_EXP( unsigned int ctx_switches = kstat.context_swtch );
+
+    result = bread (super -> s_dev, n_block, n_size);
+    PROC_INFO_INC( super, breads );
+    PROC_EXP( if( kstat.context_swtch != ctx_switches ) 
+	      PROC_INFO_INC( super, bread_miss ) );
+    return result;
 }
 
 /* This function looks for a buffer which contains a given block.  If
diff -rupN linux-2.4.7-ac1/fs/reiserfs/do_balan.c linux-2.4.7-ac1.patched/fs/reiserfs/do_balan.c
--- linux-2.4.7-ac1/fs/reiserfs/do_balan.c	Sat Jul 28 15:00:55 2001
+++ linux-2.4.7-ac1.patched/fs/reiserfs/do_balan.c	Sat Jul 28 15:01:31 2001
@@ -280,6 +280,9 @@ static int balance_leaf (struct tree_bal
 			tb->insert_size [0]);
     }
 #endif
+
+    PROC_INFO_INC( tb -> tb_sb, balance_at[ 0 ] );
+
     /* Make balance in case insert_size[0] < 0 */
     if ( tb->insert_size[0] < 0 )
 	return balance_leaf_when_delete (tb, flag);
diff -rupN linux-2.4.7-ac1/fs/reiserfs/fix_node.c linux-2.4.7-ac1.patched/fs/reiserfs/fix_node.c
--- linux-2.4.7-ac1/fs/reiserfs/fix_node.c	Sat Jul 28 15:00:55 2001
+++ linux-2.4.7-ac1.patched/fs/reiserfs/fix_node.c	Sat Jul 28 15:01:31 2001
@@ -575,6 +575,11 @@ static void set_parameters (struct tree_
       tb->lbytes = lb;
       tb->rbytes = rb;
     }
+  PROC_INFO_ADD( tb -> tb_sb, lnum[ h ], lnum );
+  PROC_INFO_ADD( tb -> tb_sb, rnum[ h ], rnum );
+
+  PROC_INFO_ADD( tb -> tb_sb, lbytes[ h ], lb );
+  PROC_INFO_ADD( tb -> tb_sb, rbytes[ h ], rb );
 }
 
 
@@ -667,6 +672,7 @@ static int are_leaves_removable (struct 
 
   if (MAX_CHILD_SIZE (S0) + vn->vn_size <= rfree + lfree + ih_size) {
     set_parameters (tb, 0, -1, -1, -1, NULL, -1, -1);
+    PROC_INFO_INC( tb -> tb_sb, leaves_removable );
     return 1;  
   }
   return 0;
@@ -1170,6 +1176,7 @@ static inline int can_node_be_removed (i
 	    return NO_BALANCING_NEEDED;
 	}
     }
+    PROC_INFO_INC( tb -> tb_sb, can_node_be_removed[ h ] );
     return !NO_BALANCING_NEEDED;
 }
 
@@ -1907,8 +1914,11 @@ static int  get_neighbors(
     struct buffer_head  * p_s_bh;
 
 
+    PROC_INFO_INC( p_s_sb, get_neighbors[ n_h ] );
+
     if ( p_s_tb->lnum[n_h] ) {
 	/* We need left neighbor to balance S[n_h]. */
+	PROC_INFO_INC( p_s_sb, need_l_neighbor[ n_h ] );
 	p_s_bh = PATH_OFFSET_PBUFFER(p_s_tb->tb_path, n_path_offset);
 	
 	RFALSE( p_s_bh == p_s_tb->FL[n_h] && 
@@ -1917,11 +1927,12 @@ static int  get_neighbors(
 
 	n_child_position = ( p_s_bh == p_s_tb->FL[n_h] ) ? p_s_tb->lkey[n_h] : B_NR_ITEMS (p_s_tb->FL[n_h]);
 	n_son_number = B_N_CHILD_NUM(p_s_tb->FL[n_h], n_child_position);
-	p_s_bh = reiserfs_bread(p_s_sb->s_dev, n_son_number, p_s_sb->s_blocksize);
+	p_s_bh = reiserfs_bread(p_s_sb, n_son_number, p_s_sb->s_blocksize);
 	if (!p_s_bh)
 	    return IO_ERROR;
 	if ( FILESYSTEM_CHANGED_TB (p_s_tb) ) {
 	    decrement_bcount(p_s_bh);
+	    PROC_INFO_INC( p_s_sb, get_neighbors_restart[ n_h ] );
 	    return REPEAT_SEARCH;
 	}
 	
@@ -1940,6 +1951,7 @@ static int  get_neighbors(
 
 
     if ( p_s_tb->rnum[n_h] ) { /* We need right neighbor to balance S[n_path_offset]. */
+	PROC_INFO_INC( p_s_sb, need_r_neighbor[ n_h ] );
 	p_s_bh = PATH_OFFSET_PBUFFER(p_s_tb->tb_path, n_path_offset);
 	
 	RFALSE( p_s_bh == p_s_tb->FR[n_h] && 
@@ -1948,11 +1960,12 @@ static int  get_neighbors(
 
 	n_child_position = ( p_s_bh == p_s_tb->FR[n_h] ) ? p_s_tb->rkey[n_h] + 1 : 0;
 	n_son_number = B_N_CHILD_NUM(p_s_tb->FR[n_h], n_child_position);
-	p_s_bh = reiserfs_bread(p_s_sb->s_dev, n_son_number, p_s_sb->s_blocksize);
+	p_s_bh = reiserfs_bread(p_s_sb, n_son_number, p_s_sb->s_blocksize);
 	if (!p_s_bh)
 	    return IO_ERROR;
 	if ( FILESYSTEM_CHANGED_TB (p_s_tb) ) {
 	    decrement_bcount(p_s_bh);
+	    PROC_INFO_INC( p_s_sb, get_neighbors_restart[ n_h ] );
 	    return REPEAT_SEARCH;
 	}
 	decrement_bcount(p_s_tb->R[n_h]);
@@ -2293,6 +2306,8 @@ int fix_nodes (int n_op_mode,
     int wait_tb_buffers_run = 0 ; 
     int windex ;
     struct buffer_head  * p_s_tbS0 = PATH_PLAST_BUFFER(p_s_tb->tb_path);
+
+    ++ p_s_tb -> tb_sb -> u.reiserfs_sb.s_fix_nodes;
 
     n_pos_in_item = p_s_tb->tb_path->pos_in_item;
 
diff -rupN linux-2.4.7-ac1/fs/reiserfs/ibalance.c linux-2.4.7-ac1.patched/fs/reiserfs/ibalance.c
--- linux-2.4.7-ac1/fs/reiserfs/ibalance.c	Fri Jul 27 22:47:05 2001
+++ linux-2.4.7-ac1.patched/fs/reiserfs/ibalance.c	Sat Jul 28 15:01:31 2001
@@ -754,6 +754,8 @@ int balance_internal (struct tree_balanc
 
     RFALSE( h < 1, "h (%d) can not be < 1 on internal level", h);
 
+    PROC_INFO_INC( tb -> tb_sb, balance_at[ h ] );
+
     order = ( tbSh ) ? PATH_H_POSITION (tb->tb_path, h + 1)/*tb->S[h]->b_item_order*/ : 0;
 
   /* Using insert_size[h] calculate the number insert_num of items
diff -rupN linux-2.4.7-ac1/fs/reiserfs/journal.c linux-2.4.7-ac1.patched/fs/reiserfs/journal.c
--- linux-2.4.7-ac1/fs/reiserfs/journal.c	Fri Jul 27 22:47:05 2001
+++ linux-2.4.7-ac1.patched/fs/reiserfs/journal.c	Sat Jul 28 15:01:31 2001
@@ -526,12 +526,14 @@ int reiserfs_in_journal(struct super_blo
     return 0 ;
   }
 
+  PROC_INFO_INC( p_s_sb, journal.in_journal );
   /* If we aren't doing a search_all, this is a metablock, and it will be logged before use.
   ** if we crash before the transaction that freed it commits,  this transaction won't
   ** have committed either, and the block will never be written
   */
   if (search_all) {
     for (i = 0 ; i < JOURNAL_NUM_BITMAPS ; i++) {
+      PROC_INFO_INC( p_s_sb, journal.in_journal_bitmap );
       jb = SB_JOURNAL(p_s_sb)->j_list_bitmap + i ;
       if (jb->journal_list && jb->bitmaps[bmap_nr] &&
           test_bit(bit_nr, jb->bitmaps[bmap_nr]->data)) {
@@ -554,6 +556,7 @@ int reiserfs_in_journal(struct super_blo
     return 1; 
   }
 
+  PROC_INFO_INC( p_s_sb, journal.in_journal_reusable );
   /* safe for reuse */
   return 0 ;
 }
@@ -574,7 +577,9 @@ inline void insert_journal_hash(struct r
 
 /* lock the current transaction */
 inline static void lock_journal(struct super_block *p_s_sb) {
+  PROC_INFO_INC( p_s_sb, journal.lock_journal );
   while(atomic_read(&(SB_JOURNAL(p_s_sb)->j_wlock)) > 0) {
+    PROC_INFO_INC( p_s_sb, journal.lock_journal_wait );
     sleep_on(&(SB_JOURNAL(p_s_sb)->j_wait)) ;
   }
   atomic_set(&(SB_JOURNAL(p_s_sb)->j_wlock), 1) ;
@@ -2005,6 +2010,7 @@ static int do_journal_begin_r(struct rei
     th->t_super = p_s_sb ; /* others will check this for the don't log flag */
     return 0 ;
   }
+  PROC_INFO_INC( p_s_sb, journal.journal_being );
 
 relock:
   lock_journal(p_s_sb) ;
@@ -2012,6 +2018,7 @@ relock:
   if (test_bit(WRITERS_BLOCKED, &SB_JOURNAL(p_s_sb)->j_state)) {
     unlock_journal(p_s_sb) ;
     reiserfs_wait_on_write_block(p_s_sb) ;
+    PROC_INFO_INC( p_s_sb, journal.journal_relock_writers );
     goto relock ;
   }
 
@@ -2050,6 +2057,7 @@ relock:
 	sleep_on(&(SB_JOURNAL(p_s_sb)->j_join_wait)) ;
       }
     }
+    PROC_INFO_INC( p_s_sb, journal.journal_relock_wcount );
     goto relock ;
   }
 
@@ -2096,6 +2104,7 @@ int journal_mark_dirty(struct reiserfs_t
   int count_already_incd = 0 ;
   int prepared = 0 ;
 
+  PROC_INFO_INC( p_s_sb, journal.mark_dirty );
   if (reiserfs_dont_log(th->t_super)) {
     mark_buffer_dirty(bh) ;
     return 0 ;
@@ -2110,6 +2119,7 @@ int journal_mark_dirty(struct reiserfs_t
   prepared = test_and_clear_bit(BH_JPrepared, &bh->b_state) ;
   /* already in this transaction, we are done */
   if (buffer_journaled(bh)) {
+    PROC_INFO_INC( p_s_sb, journal.mark_dirty_already );
     return 0 ;
   }
 
@@ -2139,6 +2149,7 @@ int journal_mark_dirty(struct reiserfs_t
 
   if (buffer_journal_dirty(bh)) {
     count_already_incd = 1 ;
+    PROC_INFO_INC( p_s_sb, journal.mark_dirty_notjournal );
     mark_buffer_notjournal_dirty(bh) ;
   }
 
@@ -2605,6 +2616,7 @@ int journal_mark_freed(struct reiserfs_t
 
 void reiserfs_restore_prepared_buffer(struct super_block *p_s_sb, 
                                       struct buffer_head *bh) {
+  PROC_INFO_INC( p_s_sb, journal.restore_prepared );
   if (reiserfs_dont_log (p_s_sb))
     return;
 
@@ -2626,6 +2638,7 @@ void reiserfs_prepare_for_journal(struct
                                   struct buffer_head *bh, int wait) {
   int retry_count = 0 ;
 
+  PROC_INFO_INC( p_s_sb, journal.prepare );
   if (reiserfs_dont_log (p_s_sb))
     return;
 
@@ -2641,6 +2654,7 @@ void reiserfs_prepare_for_journal(struct
 	      "waiting while do_balance was running\n") ;
       wait_on_buffer(bh) ;
     }
+    PROC_INFO_INC( p_s_sb, journal.prepare_retry );
     retry_count++ ;
   }
 }
diff -rupN linux-2.4.7-ac1/fs/reiserfs/namei.c linux-2.4.7-ac1.patched/fs/reiserfs/namei.c
--- linux-2.4.7-ac1/fs/reiserfs/namei.c	Fri Jul 27 22:47:05 2001
+++ linux-2.4.7-ac1.patched/fs/reiserfs/namei.c	Sat Jul 28 15:01:31 2001
@@ -480,6 +480,9 @@ static int reiserfs_add_entry (struct re
     deh->deh_offset = cpu_to_le32 (SET_GENERATION_NUMBER (deh_offset (deh), gen_number));
     set_cpu_key_k_offset (&entry_key, le32_to_cpu (deh->deh_offset));
 
+    /* update max-hash-collisions counter in reiserfs_sb_info */
+    PROC_INFO_MAX( th -> t_super, max_hash_collisions, gen_number );
+ 		  
     if (gen_number != 0) {	/* we need to re-search for the insertion point */
 	if (search_by_entry_key (dir->i_sb, &entry_key, &path, &de) != NAME_NOT_FOUND) {
 	    reiserfs_warning ("vs-7032: reiserfs_add_entry: "
diff -rupN linux-2.4.7-ac1/fs/reiserfs/objectid.c linux-2.4.7-ac1.patched/fs/reiserfs/objectid.c
--- linux-2.4.7-ac1/fs/reiserfs/objectid.c	Fri Jul 27 22:47:05 2001
+++ linux-2.4.7-ac1.patched/fs/reiserfs/objectid.c	Sat Jul 28 15:01:31 2001
@@ -145,9 +145,11 @@ void reiserfs_release_objectid (struct r
 		return;
 	    }
 
-	    if (rs->s_oid_cursize == rs->s_oid_maxsize)
+	    if (rs->s_oid_cursize == rs->s_oid_maxsize) {
 		/* objectid map must be expanded, but there is no space */
+		PROC_INFO_INC( s, leaked_oid );
 		return;
+	    }
 
 	    /* expand the objectid map*/
 	    memmove (map + i + 3, map + i + 1, 
diff -rupN linux-2.4.7-ac1/fs/reiserfs/prints.c linux-2.4.7-ac1.patched/fs/reiserfs/prints.c
--- linux-2.4.7-ac1/fs/reiserfs/prints.c	Sat Jul 28 15:00:55 2001
+++ linux-2.4.7-ac1.patched/fs/reiserfs/prints.c	Sat Jul 28 15:01:31 2001
@@ -504,7 +504,7 @@ static int print_super_block (struct buf
     printk ("Filesystem state %s\n", 
 	    (le16_to_cpu (rs->s_state) == REISERFS_VALID_FS) ? "VALID" : "ERROR");
     printk ("Hash function \"%s\"\n", le16_to_cpu (rs->s_hash_function_code) == TEA_HASH ? "tea" :
-	    ((le16_to_cpu (rs->s_hash_function_code) == YURA_HASH) ? "rupasov" : "unknown"));
+	    ( le16_to_cpu (rs->s_hash_function_code) == YURA_HASH ? "rupasov" : (le16_to_cpu (rs->s_hash_function_code) == R5_HASH ? "r5" : "unknown")));
 
 #if 0
     __u32 s_journal_trans_max ;           /* max number of blocks in a transaction.  */
diff -rupN linux-2.4.7-ac1/fs/reiserfs/procfs.c linux-2.4.7-ac1.patched/fs/reiserfs/procfs.c
--- linux-2.4.7-ac1/fs/reiserfs/procfs.c	Thu Jan  1 03:00:00 1970
+++ linux-2.4.7-ac1.patched/fs/reiserfs/procfs.c	Sat Jul 28 15:01:31 2001
@@ -0,0 +1,727 @@
+/* -*- linux-c -*- */
+
+/* fs/reiserfs/procfs.c */
+
+/*
+ * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ */
+
+/* proc info support a la one created by Sizif@Botik.RU for PGC */
+
+/* $Id: procfs.c,v 1.1.8.2 2001/07/15 17:08:42 god Exp $ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <asm/uaccess.h>
+#include <linux/reiserfs_fs.h>
+#include <linux/smp_lock.h>
+#include <linux/locks.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+
+#if defined( REISERFS_PROC_INFO )
+
+/*
+ * LOCKING:
+ *
+ * reiserfs_proc_info_data_t part of reiserfs super-block is protected
+ * by spinlock_t field .lock. Each procinfo display function acting on
+ * super-block, first takes this lock, then searches though list of all
+ * super-blocks (super_blocks), until current super-block is found. If
+ * it is not, or current super-block .exiting field is set, spinlock is
+ * released and operation aborted. Otherwise, data are stuffed into page
+ * and spinlock released. .exiting field is set up in
+ * reiserfs_proc_info_done() called from reiserfs_put_super() under
+ * spinlock.
+ * 
+ * This all is against proc vs. umount races pointed out by Al Viro
+ * at fsdevel.
+ *
+ */
+
+/** implements locking logic described above. */
+static struct super_block *procinfo_prologue( kdev_t dev )
+{
+	struct super_block *result;
+
+	/* get super-block by device */
+	result = get_super( dev );
+	if( result != NULL ) {
+		if( !reiserfs_is_super( result ) )
+			result = NULL;
+		else {
+			spin_lock( & __PINFO( result ).lock );
+			if( __PINFO( result ).exiting ) {
+				result = NULL;
+				spin_unlock( & __PINFO( result ).lock );
+			}
+		}
+	}
+	if( result == NULL )
+		printk( KERN_DEBUG "reiserfs: procfs-74: "
+			"race between procinfo and umount\n" );
+	return result;
+}
+
+int procinfo_epilogue( struct super_block *super )
+{
+	spin_unlock( & __PINFO( super ).lock );
+	return 0;
+}
+
+int reiserfs_proc_tail( int len, char *buffer, char **start, 
+			off_t offset, int count, int *eof )
+{
+	/* this is black procfs magic */
+	if( offset >= len ) {
+		*start = buffer;
+		*eof = 1;
+		return 0;
+	}
+	*start = buffer + offset;
+	if( ( len -= offset ) > count ) {
+		return count;
+	}
+	*eof = 1;
+	return len;
+}
+
+int reiserfs_version_in_proc( char *buffer, char **start, off_t offset,
+			      int count, int *eof, void *data )
+{
+	int len = 0;
+	struct super_block *sb;
+    
+	sb = procinfo_prologue( ( kdev_t ) ( int ) data );
+	if( sb == NULL )
+		return -ENOENT;
+	len += sprintf( &buffer[ len ], "%s format\twith checks %s\n",
+			old_format_only( sb ) ? "old" : "new",
+#if defined( CONFIG_REISERFS_CHECK )
+			"on"
+#else
+			"off"
+#endif
+		);
+	procinfo_epilogue( sb );
+	return reiserfs_proc_tail( len, buffer, start, offset, count, eof );
+}
+
+int reiserfs_global_version_in_proc( char *buffer, char **start, off_t offset,
+				     int count, int *eof, void *data )
+{
+	int len = 0;
+    
+	len += sprintf( &buffer[ len ], "%s [%s]\n", 
+			reiserfs_get_version_string(),
+#if defined( CONFIG_REISERFS_FS_MODULE )
+			"as module"
+#else
+			"built into kernel"
+#endif
+			);
+	return reiserfs_proc_tail( len, buffer, start, offset, count, eof );
+}
+
+#define SF( x ) ( r -> x )
+#define SFP( x ) SF( s_proc_info_data.x )
+#define SFPL( x ) SFP( x[ level ] )
+#define SFPF( x ) SFP( find_forward.x )
+#define SFPJ( x ) SFP( journal.x )
+
+#define D2C( x ) le16_to_cpu( x )
+#define D4C( x ) le32_to_cpu( x )
+#define DF( x ) D2C( rs -> x )
+#define DFL( x ) D4C( rs -> x )
+
+#define objectid_map( s, rs ) (old_format_only (s) ?				\
+                         (__u32 *)((struct reiserfs_super_block_v1 *)rs + 1) :	\
+			 (__u32 *)(rs + 1))
+#define MAP( i ) D4C( objectid_map( sb, rs )[ i ] )
+
+#define DJF( x ) le32_to_cpu( rs -> x )
+#define JF( x ) ( r -> s_journal -> x )
+
+int reiserfs_super_in_proc( char *buffer, char **start, off_t offset,
+			    int count, int *eof, void *data )
+{
+	struct super_block *sb;
+	struct reiserfs_sb_info *r;
+	int len = 0;
+    
+	sb = procinfo_prologue( ( kdev_t ) ( int ) data );
+	if( sb == NULL )
+		return -ENOENT;
+	r = &sb->u.reiserfs_sb;
+	len += sprintf( &buffer[ len ], 
+			"state: \t%s\n"
+			"mount options: \t%s%s%s%s%s%s%s%s%s%s%s%s\n"
+			"gen. counter: \t%i\n"
+			"s_kmallocs: \t%i\n"
+			"s_disk_reads: \t%i\n"
+			"s_disk_writes: \t%i\n"
+			"s_fix_nodes: \t%i\n"
+			"s_do_balance: \t%i\n"
+			"s_unneeded_left_neighbor: \t%i\n"
+			"s_good_search_by_key_reada: \t%i\n"
+			"s_bmaps: \t%i\n"
+			"s_bmaps_without_search: \t%i\n"
+			"s_direct2indirect: \t%i\n"
+			"s_indirect2direct: \t%i\n"
+			"\n"
+			"max_hash_collisions: \t%i\n"
+
+			"breads: \t%lu\n"
+			"bread_misses: \t%lu\n"
+
+			"search_by_key: \t%lu\n"
+			"search_by_key_fs_changed: \t%lu\n"
+			"search_by_key_restarted: \t%lu\n"
+			
+			"leaked_oid: \t%lu\n"
+			"leaves_removable: \t%lu\n",
+
+			SF( s_mount_state ) == REISERFS_VALID_FS ?
+			"REISERFS_VALID_FS" : "REISERFS_ERROR_FS",
+			reiserfs_r5_hash( sb ) ? "FORCE_R5 " : "",
+			reiserfs_rupasov_hash( sb ) ? "FORCE_RUPASOV " : "",
+			reiserfs_tea_hash( sb ) ? "FORCE_TEA " : "",
+			reiserfs_hash_detect( sb ) ? "DETECT_HASH " : "",
+			reiserfs_no_border( sb ) ? "NO_BORDER " : "BORDER ",
+			reiserfs_no_unhashed_relocation( sb ) ? "NO_UNHASHED_RELOCATION " : "",
+			reiserfs_hashed_relocation( sb ) ? "UNHASHED_RELOCATION " : "",
+			reiserfs_test4( sb ) ? "TEST4 " : "",
+			dont_have_tails( sb ) ? "NO_TAILS " : "TAILS ",
+			replay_only( sb ) ? "REPLAY_ONLY " : "",
+			reiserfs_dont_log( sb ) ? "DONT_LOG " : "LOG ",
+			old_format_only( sb ) ? "CONV " : "",
+
+			atomic_read( &r -> s_generation_counter ),
+			SF( s_kmallocs ),
+			SF( s_disk_reads ),
+			SF( s_disk_writes ),
+			SF( s_fix_nodes ),
+			SF( s_do_balance ),
+			SF( s_unneeded_left_neighbor ),
+			SF( s_good_search_by_key_reada ),
+			SF( s_bmaps ),
+			SF( s_bmaps_without_search ),
+			SF( s_direct2indirect ),
+			SF( s_indirect2direct ),
+			SFP( max_hash_collisions ),
+			SFP( breads ),
+			SFP( bread_miss ),
+			SFP( search_by_key ),
+			SFP( search_by_key_fs_changed ),
+			SFP( search_by_key_restarted ),
+			SFP( leaked_oid ),
+			SFP( leaves_removable ) );
+
+	procinfo_epilogue( sb );
+	return reiserfs_proc_tail( len, buffer, start, offset, count, eof );
+}
+
+int reiserfs_per_level_in_proc( char *buffer, char **start, off_t offset,
+				int count, int *eof, void *data )
+{
+	struct super_block *sb;
+	struct reiserfs_sb_info *r;
+	int len = 0;
+	int level;
+	
+	sb = procinfo_prologue( ( kdev_t ) ( int ) data );
+	if( sb == NULL )
+		return -ENOENT;
+	r = &sb->u.reiserfs_sb;
+
+	len += sprintf( &buffer[ len ],
+			"level\t"
+			"     balances"
+			" [sbk:  reads"
+			"   fs_changed"
+			"   restarted]"
+			"   free space"
+			"        items"
+			"   can_remove"
+			"         lnum"
+			"         rnum"
+			"       lbytes"
+			"       rbytes"
+			"     get_neig"
+			" get_neig_res"
+			"  need_l_neig"
+			"  need_r_neig"
+			"\n"
+			
+		);
+
+	for( level = 0 ; level < MAX_HEIGHT ; ++ level ) {
+		if( len > PAGE_SIZE - 240 ) {
+			len += sprintf( &buffer[ len ], "... and more\n" );
+			break;
+		}
+		len += sprintf( &buffer[ len ], 
+				"%i\t"
+				" %12lu"
+				" %12lu"
+				" %12lu"
+				" %12lu"
+				" %12lu"
+				" %12lu"
+				" %12lu"
+				" %12li"
+				" %12li"
+				" %12li"
+				" %12li"
+				" %12lu"
+				" %12lu"
+				" %12lu"
+				" %12lu"
+				"\n",
+				level, 
+				SFPL( balance_at ),
+				SFPL( sbk_read_at ),
+				SFPL( sbk_fs_changed ),
+				SFPL( sbk_restarted ),
+				SFPL( free_at ),
+				SFPL( items_at ),
+				SFPL( can_node_be_removed ),
+				SFPL( lnum ),
+				SFPL( rnum ),
+				SFPL( lbytes ),
+				SFPL( rbytes ),
+				SFPL( get_neighbors ),
+				SFPL( get_neighbors_restart ),
+				SFPL( need_l_neighbor ),
+				SFPL( need_r_neighbor )
+			);
+	}
+
+	procinfo_epilogue( sb );
+	return reiserfs_proc_tail( len, buffer, start, offset, count, eof );
+}
+
+int reiserfs_bitmap_in_proc( char *buffer, char **start, off_t offset,
+			     int count, int *eof, void *data )
+{
+	struct super_block *sb;
+	struct reiserfs_sb_info *r = &sb->u.reiserfs_sb;
+	int len = 0;
+    
+	sb = procinfo_prologue( ( kdev_t ) ( int ) data );
+	if( sb == NULL )
+		return -ENOENT;
+	r = &sb->u.reiserfs_sb;
+
+	len += sprintf( &buffer[ len ], "free_block: %lu\n"
+			"find_forward:"
+			"         wait"
+			"         bmap"
+			"        retry"
+			" journal_hint"
+			"  journal_out"
+			"\n"
+			" %12lu"
+			" %12lu"
+			" %12lu"
+			" %12lu"
+			" %12lu"
+			" %12lu"
+			"\n",
+			SFP( free_block ),
+			SFPF( call ), 
+			SFPF( wait ), 
+			SFPF( bmap ),
+			SFPF( retry ),
+			SFPF( in_journal_hint ),
+			SFPF( in_journal_out ) );
+
+	procinfo_epilogue( sb );
+	return reiserfs_proc_tail( len, buffer, start, offset, count, eof );
+}
+
+int reiserfs_on_disk_super_in_proc( char *buffer, char **start, off_t offset,
+				    int count, int *eof, void *data )
+{
+	struct super_block *sb;
+	struct reiserfs_sb_info *sb_info;
+	struct reiserfs_super_block *rs;
+	int hash_code;
+	int len = 0;
+    
+	sb = procinfo_prologue( ( kdev_t ) ( int ) data );
+	if( sb == NULL )
+		return -ENOENT;
+	sb_info = &sb->u.reiserfs_sb;
+	rs = sb_info -> s_rs;
+	hash_code = DFL( s_hash_function_code );
+
+	len += sprintf( &buffer[ len ], 
+			"block_count: \t%i\n"
+			"free_blocks: \t%i\n"
+			"root_block: \t%i\n"
+			"blocksize: \t%i\n"
+			"oid_maxsize: \t%i\n"
+			"oid_cursize: \t%i\n"
+			"state: \t%i\n"
+			"magic: \t%12.12s\n"
+			"hash: \t%s\n"
+			"tree_height: \t%i\n"
+			"bmap_nr: \t%i\n"
+			"version: \t%i\n",
+
+			DFL( s_block_count ),
+			DFL( s_free_blocks ),
+			DFL( s_root_block ),
+			DF( s_blocksize ),
+			DF( s_oid_maxsize ),
+			DF( s_oid_cursize ),
+			DF( s_state ),
+			rs -> s_magic,
+			hash_code == TEA_HASH ? "tea" :
+			( hash_code == YURA_HASH ) ? "rupasov" :
+			( hash_code == R5_HASH ) ? "r5" :
+			( hash_code == UNSET_HASH ) ? "unset" : "unknown",
+			DF( s_tree_height ),
+			DF( s_bmap_nr ),
+			DF( s_version ) );
+
+	procinfo_epilogue( sb );
+	return reiserfs_proc_tail( len, buffer, start, offset, count, eof );
+}
+
+int reiserfs_oidmap_in_proc( char *buffer, char **start, off_t offset,
+			     int count, int *eof, void *data )
+{
+	struct super_block *sb;
+	struct reiserfs_sb_info *sb_info;
+	struct reiserfs_super_block *rs;
+	int i;
+	unsigned int mapsize;
+	unsigned long total_used;
+	int len = 0;
+	int exact;
+    
+	sb = procinfo_prologue( ( kdev_t ) ( int ) data );
+	if( sb == NULL )
+		return -ENOENT;
+	sb_info = &sb->u.reiserfs_sb;
+	rs = sb_info -> s_rs;
+	mapsize = le16_to_cpu( rs -> s_oid_cursize );
+	total_used = 0;
+
+	for( i = 0 ; i < mapsize ; ++i ) {
+		__u32 right;
+
+		right = ( i == mapsize - 1 ) ? MAX_KEY_OBJECTID : MAP( i + 1 );
+		len += sprintf( &buffer[ len ], "%s: [ %x .. %x )\n",
+				( i & 1 ) ? "free" : "used", MAP( i ), right );
+		if( ! ( i & 1 ) ) {
+			total_used += right - MAP( i );
+		}
+		if( len > PAGE_SIZE - 100 ) {
+			len += sprintf( &buffer[ len ], "... and more\n" );
+			break;
+		}
+	}
+#if defined( REISERFS_USE_OIDMAPF )
+	if( sb_info -> oidmap.use_file && ( sb_info -> oidmap.mapf != NULL ) ) {
+		loff_t size;
+
+		size = sb_info -> oidmap.mapf -> f_dentry -> d_inode -> i_size;
+		total_used += size / sizeof( reiserfs_oidinterval_d_t );
+		exact = 1;
+	} else
+#endif
+	{
+		exact = ( i == mapsize );
+	}
+	len += sprintf( &buffer[ len ], "total: \t%i [%i/%i] used: %lu [%s]\n", 
+			i, 
+			mapsize, le16_to_cpu( rs -> s_oid_maxsize ),
+			total_used, exact ? "exact" : "estimation" );
+
+	procinfo_epilogue( sb );
+	return reiserfs_proc_tail( len, buffer, start, offset, count, eof );
+}
+
+int reiserfs_journal_in_proc( char *buffer, char **start, off_t offset,
+			      int count, int *eof, void *data )
+{
+	struct super_block *sb;
+	struct reiserfs_sb_info *r;
+	struct reiserfs_super_block *rs;
+	int len = 0;
+    
+	sb = procinfo_prologue( ( kdev_t ) ( int ) data );
+	if( sb == NULL )
+		return -ENOENT;
+	r = &sb->u.reiserfs_sb;
+	rs = r -> s_rs;
+
+	len += sprintf( &buffer[ len ], 
+			/* on-disk fields */
+			"s_journal_block: \t%i\n"
+			"s_journal_dev: \t%s[%x]\n"
+			"s_orig_journal_size: \t%i\n"
+			"s_journal_trans_max: \t%i\n"
+			"s_journal_block_count: \t%i\n"
+			"s_journal_max_batch: \t%i\n"
+			"s_journal_max_commit_age: \t%i\n"
+			"s_journal_max_trans_age: \t%i\n"
+			/* incore fields */
+			"j_state: \t%i\n"			
+			"j_trans_id: \t%lu\n"
+			"j_mount_id: \t%lu\n"
+			"j_start: \t%lu\n"
+			"j_len: \t%lu\n"
+			"j_len_alloc: \t%lu\n"
+			"j_wcount: \t%i\n"
+			"j_bcount: \t%lu\n"
+			"j_first_unflushed_offset: \t%lu\n"
+			"j_last_flush_trans_id: \t%lu\n"
+			"j_trans_start_time: \t%li\n"
+			"j_journal_list_index: \t%i\n"
+			"j_list_bitmap_index: \t%i\n"
+			"j_must_wait: \t%i\n"
+			"j_next_full_flush: \t%i\n"
+			"j_next_async_flush: \t%i\n"
+			"j_cnode_used: \t%i\n"
+			"j_cnode_free: \t%i\n"
+			"\n"
+			/* reiserfs_proc_info_data_t.journal fields */
+			"in_journal: \t%12lu\n"
+			"in_journal_bitmap: \t%12lu\n"
+			"in_journal_reusable: \t%12lu\n"
+			"lock_journal: \t%12lu\n"
+			"lock_journal_wait: \t%12lu\n"
+			"journal_begin: \t%12lu\n"
+			"journal_relock_writers: \t%12lu\n"
+			"journal_relock_wcount: \t%12lu\n"
+			"mark_dirty: \t%12lu\n"
+			"mark_dirty_already: \t%12lu\n"
+			"mark_dirty_notjournal: \t%12lu\n"
+			"restore_prepared: \t%12lu\n"
+			"prepare: \t%12lu\n"
+			"prepare_retry: \t%12lu\n",
+
+			DJF( s_journal_block ),
+			DJF( s_journal_dev ) == 0 ? "none" : bdevname( DJF( s_journal_dev ) ), 
+			DJF( s_journal_dev ),
+			DJF( s_orig_journal_size ),
+			DJF( s_journal_trans_max ),
+			DJF( s_journal_block_count ),
+			DJF( s_journal_max_batch ),
+			DJF( s_journal_max_commit_age ),
+			DJF( s_journal_max_trans_age ),
+			
+			JF( j_state ),			
+			JF( j_trans_id ),
+			JF( j_mount_id ),
+			JF( j_start ),
+			JF( j_len ),
+			JF( j_len_alloc ),
+			atomic_read( & r -> s_journal -> j_wcount ),
+			JF( j_bcount ),
+			JF( j_first_unflushed_offset ),
+			JF( j_last_flush_trans_id ),
+			JF( j_trans_start_time ),
+			JF( j_journal_list_index ),
+			JF( j_list_bitmap_index ),
+			JF( j_must_wait ),
+			JF( j_next_full_flush ),
+			JF( j_next_async_flush ),
+			JF( j_cnode_used ),
+			JF( j_cnode_free ),
+
+			SFPJ( in_journal ),
+			SFPJ( in_journal_bitmap ),
+			SFPJ( in_journal_reusable ),
+			SFPJ( lock_journal ),
+			SFPJ( lock_journal_wait ),
+			SFPJ( journal_being ),
+			SFPJ( journal_relock_writers ),
+			SFPJ( journal_relock_wcount ),
+			SFPJ( mark_dirty ),
+			SFPJ( mark_dirty_already ),
+			SFPJ( mark_dirty_notjournal ),
+			SFPJ( restore_prepared ),
+			SFPJ( prepare ),
+			SFPJ( prepare_retry )
+		);
+
+	procinfo_epilogue( sb );
+	return reiserfs_proc_tail( len, buffer, start, offset, count, eof );
+}
+
+
+static struct proc_dir_entry *proc_info_root = NULL;
+static const char *proc_info_root_name = "fs/reiserfs";
+
+int reiserfs_proc_info_init( struct super_block *sb )
+{
+	spin_lock_init( & __PINFO( sb ).lock );
+	sb->u.reiserfs_sb.procdir = proc_mkdir( bdevname( sb -> s_dev ), 
+						proc_info_root );
+	if( sb->u.reiserfs_sb.procdir ) {
+		sb->u.reiserfs_sb.procdir -> owner = THIS_MODULE;
+		return 0;
+	}
+	reiserfs_warning( "reiserfs: cannot create /proc/%s/%s\n",
+			  proc_info_root_name, bdevname( sb -> s_dev ) );
+	return 1;
+}
+
+
+int reiserfs_proc_info_done( struct super_block *sb )
+{
+	spin_lock( & __PINFO( sb ).lock );
+	__PINFO( sb ).exiting = 1;
+	spin_unlock( & __PINFO( sb ).lock );
+	if ( proc_info_root ) {
+		remove_proc_entry( bdevname( sb -> s_dev ), proc_info_root );
+		sb->u.reiserfs_sb.procdir = NULL;
+	}
+	return 0;
+}
+
+/* Create /proc/fs/reiserfs/DEV/name and attach read procedure @func
+   to it.  Other parts of reiserfs use this function to make their
+   per-device statistics available via /proc */
+
+struct proc_dir_entry *reiserfs_proc_register( struct super_block *sb, 
+					       char *name, read_proc_t *func )
+{
+	return ( sb->u.reiserfs_sb.procdir ) ? create_proc_read_entry
+		( name, 0, sb->u.reiserfs_sb.procdir, func, 
+		  ( void * ) ( int ) sb -> s_dev ) : NULL;
+}
+
+void reiserfs_proc_unregister( struct super_block *sb, const char *name )
+{
+	remove_proc_entry( name, sb->u.reiserfs_sb.procdir );
+}
+
+struct proc_dir_entry *reiserfs_proc_register_global( char *name, 
+						      read_proc_t *func )
+{
+	return ( proc_info_root ) ? create_proc_read_entry( name, 0, 
+							    proc_info_root, 
+							    func, NULL ) : NULL;
+}
+
+void reiserfs_proc_unregister_global( const char *name )
+{
+	remove_proc_entry( name, proc_info_root );
+}
+
+int reiserfs_proc_info_global_init( void )
+{
+	if( proc_info_root == NULL ) {
+		proc_info_root = proc_mkdir( proc_info_root_name, 0 );
+		if( proc_info_root ) {
+			proc_info_root -> owner = THIS_MODULE;
+		} else {
+			reiserfs_warning( "reiserfs: cannot create /proc/%s\n",
+					  proc_info_root_name );
+			return 1;
+		}
+	}
+	return 0;
+}
+
+int reiserfs_proc_info_global_done( void )
+{
+	if ( proc_info_root != NULL ) {
+		proc_info_root = NULL;
+		remove_proc_entry( proc_info_root_name, 0 );
+	}
+	return 0;
+}
+
+/* REISERFS_PROC_INFO */
+#else
+
+int reiserfs_proc_info_init( struct super_block *sb ) { return 0; }
+int reiserfs_proc_info_done( struct super_block *sb ) { return 0; }
+
+struct proc_dir_entry *reiserfs_proc_register( struct super_block *sb, 
+					       char *name, 
+					       read_proc_t *func ) 
+{ return NULL; }
+
+void reiserfs_proc_unregister( struct super_block *sb, const char *name ) 
+{;}
+
+struct proc_dir_entry *reiserfs_proc_register_global( char *name, 
+						      read_proc_t *func )
+{ return NULL; }
+
+void reiserfs_proc_unregister_global( const char *name ) {;}
+
+int reiserfs_proc_info_global_init( void ) { return 0; }
+int reiserfs_proc_info_global_done( void ) { return 0; }
+
+int reiserfs_global_version_in_proc( char *buffer, char **start, 
+				     off_t offset,
+				     int count, int *eof, void *data )
+{ return 0; }
+
+int reiserfs_version_in_proc( char *buffer, char **start, off_t offset,
+			      int count, int *eof, void *data )
+{ return 0; }
+
+int reiserfs_super_in_proc( char *buffer, char **start, off_t offset,
+			    int count, int *eof, void *data )
+{ return 0; }
+
+int reiserfs_per_level_in_proc( char *buffer, char **start, off_t offset,
+				int count, int *eof, void *data )
+{ return 0; }
+
+int reiserfs_bitmap_in_proc( char *buffer, char **start, off_t offset,
+			     int count, int *eof, void *data )
+{ return 0; }
+
+int reiserfs_on_disk_super_in_proc( char *buffer, char **start, off_t offset,
+				    int count, int *eof, void *data )
+{ return 0; }
+
+int reiserfs_oidmap_in_proc( char *buffer, char **start, off_t offset,
+			     int count, int *eof, void *data )
+{ return 0; }
+
+int reiserfs_journal_in_proc( char *buffer, char **start, off_t offset,
+			      int count, int *eof, void *data )
+{ return 0; }
+
+/* REISERFS_PROC_INFO */
+#endif
+
+/*
+ * $Log: procfs.c,v $
+ * Revision 1.1.8.2  2001/07/15 17:08:42  god
+ *  . use get_super() in procfs.c
+ *  . remove remove_save_link() from reiserfs_do_truncate()
+ *
+ * I accept terms and conditions stated in the Legal Agreement
+ * (available at http://www.namesys.com/legalese.html)
+ *
+ * Revision 1.1.8.1  2001/07/11 16:48:50  god
+ * proc info support
+ *
+ * I accept terms and conditions stated in the Legal Agreement
+ * (available at http://www.namesys.com/legalese.html)
+ *
+ */
+
+/* 
+ * Make Linus happy.
+ * Local variables:
+ * c-indentation-style: "K&R"
+ * mode-name: "LC"
+ * c-basic-offset: 8
+ * tab-width: 8
+ * End:
+ */
diff -rupN linux-2.4.7-ac1/fs/reiserfs/stree.c linux-2.4.7-ac1.patched/fs/reiserfs/stree.c
--- linux-2.4.7-ac1/fs/reiserfs/stree.c	Fri Jul 27 22:47:05 2001
+++ linux-2.4.7-ac1.patched/fs/reiserfs/stree.c	Sat Jul 28 15:01:31 2001
@@ -648,7 +648,6 @@ int search_by_key (struct super_block * 
                                        stop at leaf level - set to
                                        DISK_LEAF_NODE_LEVEL */
     ) {
-    kdev_t n_dev = p_s_sb->s_dev;
     int  n_block_number = SB_ROOT_BLOCK (p_s_sb),
       expected_level = SB_TREE_HEIGHT (p_s_sb),
       n_block_size    = p_s_sb->s_blocksize;
@@ -661,7 +660,9 @@ int search_by_key (struct super_block * 
 #ifdef CONFIG_REISERFS_CHECK
     int n_repeat_counter = 0;
 #endif
-
+    
+    PROC_INFO_INC( p_s_sb, search_by_key );
+    
     /* As we add each node to a path we increase its count.  This means that
        we must be careful to release all nodes in a path before we either
        discard the path struct or re-use the path struct, as we do here. */
@@ -696,17 +697,24 @@ int search_by_key (struct super_block * 
 	/* Read the next tree node, and set the last element in the path to
            have a pointer to it. */
 	if ( ! (p_s_bh = p_s_last_element->pe_buffer =
-		reiserfs_bread(n_dev, n_block_number, n_block_size)) ) {
+		reiserfs_bread(p_s_sb, n_block_number, n_block_size)) ) {
 	    p_s_search_path->path_length --;
 	    pathrelse(p_s_search_path);
 	    return IO_ERROR;
 	}
 
+ 	if( fs_changed (fs_gen, p_s_sb) ) {
+ 		PROC_INFO_INC( p_s_sb, search_by_key_fs_changed );
+ 		PROC_INFO_INC( p_s_sb, sbk_fs_changed[ expected_level - 1 ] );
+ 	}
+
 	/* It is possible that schedule occurred. We must check whether the key
 	   to search is still in the tree rooted from the current buffer. If
 	   not then repeat search from the root. */
 	if ( fs_changed (fs_gen, p_s_sb) && 
 	     (!B_IS_IN_TREE (p_s_bh) || !key_in_buffer(p_s_search_path, p_s_key, p_s_sb)) ) {
+ 	    PROC_INFO_INC( p_s_sb, search_by_key_restarted );
+	    PROC_INFO_INC( p_s_sb, sbk_restarted[ expected_level - 1 ] );
 	    decrement_counters_in_path(p_s_search_path);
 	    
 	    /* Get the root block number so that we can repeat the search
@@ -740,6 +748,8 @@ int search_by_key (struct super_block * 
 	
 	/* ok, we have acquired next formatted node in the tree */
 	n_node_level = B_LEVEL (p_s_bh);
+
+	PROC_INFO_BH_STAT( p_s_sb, p_s_bh, n_node_level - 1 );
 
 	RFALSE( n_node_level < n_stop_level,
 		"vs-5152: tree level (%d) is less than stop level (%d)",
diff -rupN linux-2.4.7-ac1/fs/reiserfs/super.c linux-2.4.7-ac1.patched/fs/reiserfs/super.c
--- linux-2.4.7-ac1/fs/reiserfs/super.c	Fri Jul 27 23:32:05 2001
+++ linux-2.4.7-ac1.patched/fs/reiserfs/super.c	Sat Jul 28 15:01:31 2001
@@ -111,10 +111,18 @@ void reiserfs_put_super (struct super_bl
   print_statistics (s);
 
   if (s->u.reiserfs_sb.s_kmallocs != 0) {
-    reiserfs_warning ("vs-2004: reiserfs_put_super: aloocated memory left %d\n",
+    reiserfs_warning ("vs-2004: reiserfs_put_super: allocated memory left %d\n",
 		      s->u.reiserfs_sb.s_kmallocs);
   }
 
+  reiserfs_proc_unregister( s, "journal" );
+  reiserfs_proc_unregister( s, "oidmap" );
+  reiserfs_proc_unregister( s, "on-disk-super" );
+  reiserfs_proc_unregister( s, "bitmap" );
+  reiserfs_proc_unregister( s, "per-level" );
+  reiserfs_proc_unregister( s, "super" );
+  reiserfs_proc_unregister( s, "version" );
+  reiserfs_proc_info_done( s );
   return;
 }
 
@@ -297,11 +305,11 @@ static int read_bitmaps (struct super_bl
        labeling scheme currently used will have enough space. Then we
        need one block for the super.  -Hans */
     bmp = (REISERFS_DISK_OFFSET_IN_BYTES / s->s_blocksize) + 1;	/* first of bitmap blocks */
-    SB_AP_BITMAP (s)[0] = reiserfs_bread (s->s_dev, bmp, s->s_blocksize);
+    SB_AP_BITMAP (s)[0] = reiserfs_bread (s, bmp, s->s_blocksize);
     if(!SB_AP_BITMAP(s)[0])
 	return 1;
     for (i = 1, bmp = dl = rs->s_blocksize * 8; i < le16_to_cpu (rs->s_bmap_nr); i ++) {
-	SB_AP_BITMAP (s)[i] = reiserfs_bread (s->s_dev, bmp, s->s_blocksize);
+	SB_AP_BITMAP (s)[i] = reiserfs_bread (s, bmp, s->s_blocksize);
 	if (!SB_AP_BITMAP (s)[i])
 	    return 1;
 	bmp += dl;
@@ -324,7 +332,7 @@ static int read_old_bitmaps (struct supe
   memset (SB_AP_BITMAP (s), 0, sizeof (struct buffer_head *) * le16_to_cpu (rs->s_bmap_nr));
 
   for (i = 0; i < le16_to_cpu (rs->s_bmap_nr); i ++) {
-    SB_AP_BITMAP (s)[i] = reiserfs_bread (s->s_dev, bmp1 + i, s->s_blocksize);
+    SB_AP_BITMAP (s)[i] = reiserfs_bread (s, bmp1 + i, s->s_blocksize);
     if (!SB_AP_BITMAP (s)[i])
       return 1;
   }
@@ -451,7 +459,7 @@ static int read_super_block (struct supe
     
     if (s->s_blocksize != size)
 	set_blocksize (s->s_dev, s->s_blocksize);
-    bh = reiserfs_bread (s->s_dev, REISERFS_DISK_OFFSET_IN_BYTES / s->s_blocksize, s->s_blocksize);
+    bh = reiserfs_bread (s, REISERFS_DISK_OFFSET_IN_BYTES / s->s_blocksize, s->s_blocksize);
     if (!bh) {
 	printk("read_super_block: unable to read superblock on dev %s\n", kdevname(s->s_dev));
 	return 1;
@@ -653,7 +661,6 @@ int function2code (hashf_t func)
     return 0;
 }
 
-
 //
 // a portion of this function, particularly the VFS interface portion,
 // was derived from minix or ext2's analog and evolved as the
@@ -802,6 +809,14 @@ struct super_block * reiserfs_read_super
 	}
     }
 
+    reiserfs_proc_info_init( s );
+    reiserfs_proc_register( s, "version", reiserfs_version_in_proc );
+    reiserfs_proc_register( s, "super", reiserfs_super_in_proc );
+    reiserfs_proc_register( s, "per-level", reiserfs_per_level_in_proc );
+    reiserfs_proc_register( s, "bitmap", reiserfs_bitmap_in_proc );
+    reiserfs_proc_register( s, "on-disk-super", reiserfs_on_disk_super_in_proc );
+    reiserfs_proc_register( s, "oidmap", reiserfs_oidmap_in_proc );
+    reiserfs_proc_register( s, "journal", reiserfs_journal_in_proc );
     init_waitqueue_head (&(s->u.reiserfs_sb.s_wait));
 
     printk("%s\n", reiserfs_get_version_string()) ;
@@ -851,21 +866,20 @@ int reiserfs_statfs (struct super_block 
 
 static DECLARE_FSTYPE_DEV(reiserfs_fs_type,"reiserfs",reiserfs_read_super);
 
-//
-// this is exactly what 2.3.99-pre9's init_ext2_fs is
-//
 static int __init init_reiserfs_fs (void)
 {
+	reiserfs_proc_info_global_init();
+	reiserfs_proc_register_global( "version", 
+				       reiserfs_global_version_in_proc );
         return register_filesystem(&reiserfs_fs_type);
 }
 
 EXPORT_NO_SYMBOLS;
 
-//
-// this is exactly what 2.3.99-pre9's init_ext2_fs is
-//
 static void __exit exit_reiserfs_fs(void)
 {
+	reiserfs_proc_unregister_global( "version" );
+	reiserfs_proc_info_global_done();
         unregister_filesystem(&reiserfs_fs_type);
 }
 
diff -rupN linux-2.4.7-ac1/include/linux/reiserfs_fs.h linux-2.4.7-ac1.patched/include/linux/reiserfs_fs.h
--- linux-2.4.7-ac1/include/linux/reiserfs_fs.h	Sat Jul 28 15:00:55 2001
+++ linux-2.4.7-ac1.patched/include/linux/reiserfs_fs.h	Sat Jul 28 15:01:31 2001
@@ -18,6 +18,7 @@
 #include <linux/slab.h>
 #include <linux/tqueue.h>
 #include <asm/hardirq.h>
+#include <linux/proc_fs.h>
 #endif
 
 /*
@@ -1761,6 +1762,67 @@ int read_old_super_block (struct super_b
 struct super_block * reiserfs_read_super (struct super_block * s, void * data, int silent);
 int reiserfs_statfs (struct super_block * s, struct statfs * buf);
 
+/* procfs.c */
+
+#if defined( CONFIG_PROC_FS ) && defined( CONFIG_REISERFS_PROC_INFO )
+#define REISERFS_PROC_INFO
+#else
+#undef REISERFS_PROC_INFO
+#endif
+
+int reiserfs_proc_info_init( struct super_block *sb );
+int reiserfs_proc_info_done( struct super_block *sb );
+struct proc_dir_entry *reiserfs_proc_register( struct super_block *sb, 
+											   char *name, read_proc_t *func );
+void reiserfs_proc_unregister( struct super_block *sb, const char *name );
+struct proc_dir_entry *reiserfs_proc_register_global( char *name, 
+													  read_proc_t *func );
+void reiserfs_proc_unregister_global( const char *name );
+int reiserfs_proc_info_global_init( void );
+int reiserfs_proc_info_global_done( void );
+int reiserfs_proc_tail( int len, char *buffer, char **start, 
+						off_t offset, int count, int *eof );
+int reiserfs_global_version_in_proc( char *buffer, char **start, off_t offset,
+									 int count, int *eof, void *data );
+int reiserfs_version_in_proc( char *buffer, char **start, off_t offset,
+							  int count, int *eof, void *data );
+int reiserfs_super_in_proc( char *buffer, char **start, off_t offset,
+							int count, int *eof, void *data );
+int reiserfs_per_level_in_proc( char *buffer, char **start, off_t offset,
+								int count, int *eof, void *data );
+int reiserfs_bitmap_in_proc( char *buffer, char **start, off_t offset,
+								int count, int *eof, void *data );
+int reiserfs_on_disk_super_in_proc( char *buffer, char **start, off_t offset,
+									int count, int *eof, void *data );
+int reiserfs_oidmap_in_proc( char *buffer, char **start, off_t offset,
+							 int count, int *eof, void *data );
+int reiserfs_journal_in_proc( char *buffer, char **start, off_t offset,
+							  int count, int *eof, void *data );
+
+#if defined( REISERFS_PROC_INFO )
+
+#define PROC_EXP( e )   e
+
+#define MAX( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) )
+#define __PINFO( sb ) ( sb ) -> u.reiserfs_sb.s_proc_info_data
+#define PROC_INFO_MAX( sb, field, value )								\
+    __PINFO( sb ).field =												\
+        MAX( ( sb ) -> u.reiserfs_sb.s_proc_info_data.field, value )
+#define PROC_INFO_INC( sb, field ) ( ++ ( __PINFO( sb ).field ) )
+#define PROC_INFO_ADD( sb, field, val ) ( __PINFO( sb ).field += ( val ) )
+#define PROC_INFO_BH_STAT( sb, bh, level )							\
+    PROC_INFO_INC( sb, sbk_read_at[ ( level ) ] );						\
+    PROC_INFO_ADD( sb, free_at[ ( level ) ], B_FREE_SPACE( bh ) );	\
+    PROC_INFO_ADD( sb, items_at[ ( level ) ], B_NR_ITEMS( bh ) )
+#else
+#define PROC_EXP( e )
+#define VOID_V ( ( void ) 0 )
+#define PROC_INFO_MAX( sb, field, value ) VOID_V
+#define PROC_INFO_INC( sb, field ) VOID_V
+#define PROC_INFO_ADD( sb, field, val ) VOID_V
+#define PROC_INFO_BH_STAT( p_s_sb, p_s_bh, n_node_level ) VOID_V
+#endif
+
 /* dir.c */
 extern struct inode_operations reiserfs_dir_inode_operations;
 extern struct file_operations reiserfs_dir_operations;
@@ -1782,8 +1844,8 @@ int get_new_buffer (struct reiserfs_tran
 /* buffer2.c */
 struct buffer_head * reiserfs_getblk (kdev_t n_dev, int n_block, int n_size);
 void wait_buffer_until_released (const struct buffer_head * bh);
-struct buffer_head * reiserfs_bread (kdev_t n_dev, int n_block, int n_size);
-
+struct buffer_head * reiserfs_bread (struct super_block *super, int n_block, 
+				     int n_size);
 
 /* fix_nodes.c */
 void * reiserfs_kmalloc (size_t size, int flags, struct super_block * s);
diff -rupN linux-2.4.7-ac1/include/linux/reiserfs_fs_sb.h linux-2.4.7-ac1.patched/include/linux/reiserfs_fs_sb.h
--- linux-2.4.7-ac1/include/linux/reiserfs_fs_sb.h	Fri Jul 27 23:24:55 2001
+++ linux-2.4.7-ac1.patched/include/linux/reiserfs_fs_sb.h	Sat Jul 28 15:01:31 2001
@@ -264,6 +264,74 @@ struct reiserfs_journal {
 
 typedef __u32 (*hashf_t) (const signed char *, int);
 
+struct proc_dir_entry;
+
+#if defined( CONFIG_PROC_FS ) && defined( CONFIG_REISERFS_PROC_INFO )
+typedef unsigned long int stat_cnt_t;
+typedef struct reiserfs_proc_info_data
+{
+  spinlock_t lock;
+  int exiting;
+  int max_hash_collisions;
+
+  stat_cnt_t breads;
+  stat_cnt_t bread_miss;
+  stat_cnt_t search_by_key;
+  stat_cnt_t search_by_key_fs_changed;
+  stat_cnt_t search_by_key_restarted;
+
+  stat_cnt_t leaked_oid;
+  stat_cnt_t leaves_removable;
+
+  /* balances per level. Use explicit 5 as MAX_HEIGHT is not visible yet. */
+  stat_cnt_t balance_at[ 5 ]; /* XXX */
+  /* sbk == search_by_key */
+  stat_cnt_t sbk_read_at[ 5 ]; /* XXX */
+  stat_cnt_t sbk_fs_changed[ 5 ];
+  stat_cnt_t sbk_restarted[ 5 ];
+  stat_cnt_t items_at[ 5 ]; /* XXX */
+  stat_cnt_t free_at[ 5 ]; /* XXX */
+  stat_cnt_t can_node_be_removed[ 5 ]; /* XXX */
+  long int lnum[ 5 ]; /* XXX */
+  long int rnum[ 5 ]; /* XXX */
+  long int lbytes[ 5 ]; /* XXX */
+  long int rbytes[ 5 ]; /* XXX */
+  stat_cnt_t get_neighbors[ 5 ];
+  stat_cnt_t get_neighbors_restart[ 5 ];
+  stat_cnt_t need_l_neighbor[ 5 ];
+  stat_cnt_t need_r_neighbor[ 5 ];
+
+  stat_cnt_t free_block;
+  struct __find_forward_stats {
+	stat_cnt_t call;
+	stat_cnt_t wait;
+	stat_cnt_t bmap;
+	stat_cnt_t retry;
+	stat_cnt_t in_journal_hint;
+	stat_cnt_t in_journal_out;
+  } find_forward;
+  struct __journal_stats {
+	stat_cnt_t in_journal;
+	stat_cnt_t in_journal_bitmap;
+	stat_cnt_t in_journal_reusable;
+	stat_cnt_t lock_journal;
+	stat_cnt_t lock_journal_wait;
+	stat_cnt_t journal_being;
+	stat_cnt_t journal_relock_writers;
+	stat_cnt_t journal_relock_wcount;
+	stat_cnt_t mark_dirty;
+	stat_cnt_t mark_dirty_already;
+	stat_cnt_t mark_dirty_notjournal;
+	stat_cnt_t restore_prepared;
+	stat_cnt_t prepare;
+	stat_cnt_t prepare_retry;
+  } journal;
+} reiserfs_proc_info_data_t;
+#else
+typedef struct reiserfs_proc_info_data
+{} reiserfs_proc_info_data_t;
+#endif
+
 /* reiserfs union of in-core super block data */
 struct reiserfs_sb_info
 {
@@ -302,6 +370,8 @@ struct reiserfs_sb_info
     int s_bmaps_without_search;
     int s_direct2indirect;
     int s_indirect2direct;
+    reiserfs_proc_info_data_t s_proc_info_data;
+    struct proc_dir_entry *procdir;
 };
 
 
