diff -urN v2.4.17rc1/fs/reiserfs/inode.c linux/fs/reiserfs/inode.c
--- v2.4.17rc1/fs/reiserfs/inode.c	Fri Dec 14 13:58:15 2001
+++ linux/fs/reiserfs/inode.c	Mon Dec 17 18:28:05 2001
@@ -17,6 +17,8 @@
 #define GET_BLOCK_READ_DIRECT 4  /* read the tail if indirect item not found */
 #define GET_BLOCK_NO_ISEM     8 /* i_sem is not held, don't preallocate */
 
+#define MAX_BUF_PER_PAGE (PAGE_CACHE_SIZE / 512)
+
 static int reiserfs_get_block (struct inode * inode, long block,
 			       struct buffer_head * bh_result, int create);
 //
@@ -239,78 +241,490 @@
   journal_begin(th, s, len) ;
   reiserfs_update_inode_transaction(inode) ;
 }
+/*
+** Get block number from the indirect item cache.
+** It helps us to avoid a lot of the search_by_key() calls.
+** It is used in  _get_block_create_0.
+*/
+static inline int iicache_find_map_block (struct inode * inode, long block,
+					  struct buffer_head * bh_result)
+{
+  long block_nr=0;
+  int ret=0;
+  /*
+  ** if the iicache is not empty for this file and
+  ** the requested logical block of file is cached 
+  ** then we return corresponded block number. 
+  */
+  if ( iicache_size(inode) && block_is_iicached(inode, block)) {
+    block_nr = iicache_blocknr(inode, block);
+    set_block_dev_mapped (bh_result, block_nr, inode);
+    ret = 1;   
+  } 
+  return ret;
+}
 
-// it is called by get_block when create == 0. Returns block number
-// for 'block'-th logical block of file. When it hits direct item it
-// returns 0 (being called from bmap) or read direct item into piece
-// of page (bh_result)
+/* 
+** Get block number from the indirect item by position. 
+*/
+static inline long iitem_get_blocknr (struct path *path, int pos)
+{
+  struct buffer_head * bh = get_last_bh (path);
+  struct item_head   * ih = get_ih (path);
+  __u32 * ind_item        = (__u32 *)B_I_PITEM (bh, ih);
 
-// Please improve the english/clarity in the comment above, as it is
-// hard to understand.
+  return le32_to_cpu(ind_item [path->pos_in_item + pos]);
+}
 
-static int _get_block_create_0 (struct inode * inode, long block,
-				 struct buffer_head * bh_result,
-				 int args)
+/* 
+** Get the indirect item size. 
+*/
+static inline int iitem_size (struct path *path)
 {
-    INITIALIZE_PATH (path);
-    struct cpu_key key;
-    struct buffer_head * bh;
-    struct item_head * ih, tmp_ih;
-    int fs_gen ;
-    int blocknr;
-    char * p = NULL;
-    int chars;
-    int ret ;
-    int done = 0 ;
-    unsigned long offset ;
-
-    // prepare the key to look for the 'block'-th block of file
-    make_cpu_key (&key, inode,
-		  (loff_t)block * inode->i_sb->s_blocksize + 1, TYPE_ANY, 3);
+  struct item_head * ih = get_ih (path);
+  return (I_UNFM_NUM(ih) - (path->pos_in_item + 1));
+}
 
-research:
-    if (search_for_position_by_key (inode->i_sb, &key, &path) != POSITION_FOUND) {
-	pathrelse (&path);
-        if (p)
-            kunmap(bh_result->b_page) ;
-	if ((args & GET_BLOCK_NO_HOLE)) {
-	    return -ENOENT ;
-	}
-        return 0 ;
-    }
+/* 
+** Get the number of contiguous blocks in the indirect item
+** from given pos to the end of the item.  
+*/
+static inline int iitem_amount_contiguous (struct path *path, int pos)
+{
+  long curr = 0;
+  long next = 0;
+  int  item_size = iitem_size(path);
+  int  amount = 1;
+
+  if (pos >= item_size) { 
+    return 0;
+  }
+  curr = iitem_get_blocknr(path, pos++);
+  while (pos <= item_size) {
+    next = iitem_get_blocknr(path, pos++);
+    if ((next - curr) != 1) break;
+    curr = next;
+    amount++;
+  }
+
+  return amount;
+}
+
+
+/* Fill indirect item cache.
+** Put N block numbers from current indirect item.
+*/
+static inline void iicache_fill (struct inode * inode, long block, 
+				 struct path * path)
+{
+  long blocknr=0;
+  int  pos=0; 
+  int  amount=0;
+
+  iicache_spin_lock(inode);
+
+  /* get amount of contiguous block numbers */
+  amount=iitem_amount_contiguous (path, pos + 1);
     
-    //
-    bh = get_last_bh (&path);
-    ih = get_ih (&path);
-    if (is_indirect_le_ih (ih)) {
-	__u32 * ind_item = (__u32 *)B_I_PITEM (bh, ih);
+  /* set new iicache size */  
+  iicache_set (inode, amount, IICACHE_SIZE);
+
+  /* set the number of the first cached logical block */
+  iicache_set (inode, block + 1, IICACHE_BLOCK);
+ 
+  /* put part of indirect item to the iicache */
+  blocknr = iitem_get_blocknr (path, pos + 1);
+  iicache_set (inode, blocknr, IICACHE_BLOCKNR);
+
+  iicache_spin_unlock(inode);
+}
+
+/*
+** Truncate indirect item cache. 
+*/
+static inline void iicache_truncate (struct  inode * inode)
+{
+  long new_file_end = inode->i_size >> 12;  
+  long last_cached, truncate_size;
+
+  if (iicache_size(inode)) {
+    if (new_file_end <= iicache_first_cached(inode)) {
+      iicache_clear(inode);
+      return;
+    }
+    last_cached = iicache_last_cached(inode); 
+    if (new_file_end <= last_cached) {
+      truncate_size = last_cached - new_file_end + 1;
+      inode->u.reiserfs_i.i_cache_size -= truncate_size;	
+    }
+  }
+}		   
+
+/*
+** Do readahed of the iicached block from the given iicache pos.
+*/
+static inline void iicache_readahead (struct inode *inode, int pos)
+{
+  struct super_block * sb = inode->i_sb;
+  struct buffer_head * bh, * bhp[1];
+  long block_nr;
+
+  /* if we have full indirect_item_cache then
+  ** do read_ahead for the first cached block.
+  */
+  if (iicache_size(inode)) {
+    block_nr = iicache_get (inode, IICACHE_BLOCKNR) + pos;
+    if (block_nr) {
+      bh = getblk (sb->s_dev, block_nr, sb->s_blocksize);
+      if (!buffer_uptodate (bh)) {
+        bhp[0] = bh;
+	ll_rw_block (READ, 1, bhp);
+      }
+      brelse (bh);
+    }
+  }
+
+}
+
+/*
+** If all buffers of the page are uptodate - return 1,
+** otherwise return 0; 
+*/
+static inline int is_page_buffers_uptodate (struct page * page)
+{
+  struct buffer_head * bh, *head;
+  head = bh = page->buffers;
+
+  do {
+    if (!buffer_uptodate(bh)) { 
+      return 0;
+    }
+  } while ((bh = bh->b_this_page) != head);
+ 
+  return 1;
+}
+
+/*
+** Map all buffers of the page
+*/
+static inline int iicache_map_buffers (struct page *page,
+				       int iicache_pos,
+				       struct buffer_head ** arr)
+{
+  struct inode *inode = page->mapping->host ;
+  unsigned long blocksize = inode->i_sb->s_blocksize;
+  unsigned long block_nr, iblock, lblock;  
+  struct buffer_head * bh, *head;
+  int nr=0, i=0;
+
+  if (!page->buffers) {
+    create_empty_buffers(page, inode->i_dev, blocksize);
+  }
+
+  head = bh = page->buffers;
+  iblock = page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
+  lblock = (inode->i_size+blocksize-1) >> inode->i_blkbits;
+
+  do {
+    if (buffer_uptodate(bh))
+      continue;
+
+    if (!buffer_mapped(bh)) { 
+      if (iblock < lblock) {
+	block_nr = iicache_get (inode, IICACHE_BLOCKNR) + iicache_pos + i;
+	set_block_dev_mapped(bh, block_nr, inode);
+	continue;
+      }
+      if (!buffer_mapped(bh)) {
+	memset(kmap(page) + i*blocksize, 0, blocksize);
+	flush_dcache_page(page);
+	kunmap(page);
+	set_bit(BH_Uptodate, &bh->b_state);
+	continue;
+      }
+      if (buffer_uptodate(bh)) {
+	continue;
+      }
+    }
+
+    arr[nr] = bh;
+    nr++;
+  } while(i++, iblock++, (bh = bh->b_this_page) != head);
+
+  return nr;
+
+}
+
+/*
+** Subbmit page buffers for read
+*/
+static inline void iicache_submit_bh (struct buffer_head ** arr, int nr)
+{
+  int i;
+
+  // lock the buffers
+  for (i = 0; i < nr; i++) {
+    struct buffer_head * bh = arr[i];
+    lock_buffer(bh);
+    set_buffer_async_io(bh);
+  }
+
+  // submit the buffers for read
+  for (i = 0; i < nr; i++)
+    submit_bh(READ, arr[i]);
+}
+
+/* 
+** Do page cache readahead 
+*/
+static inline void iicache_pagereada (struct inode *inode, int pos)
+{
+  struct page * page;
+  struct buffer_head *arr[MAX_BUF_PER_PAGE];
+  unsigned long block, index;
+  int nr;
 	
-	/* FIXME: here we could cache indirect item or part of it in
-	   the inode to avoid search_by_key in case of subsequent
-	   access to file */
-	blocknr = get_block_num(ind_item, path.pos_in_item) ;
-	ret = 0 ;
-	if (blocknr) {
-	    bh_result->b_dev = inode->i_dev;
-	    bh_result->b_blocknr = blocknr;
-	    bh_result->b_state |= (1UL << BH_Mapped);
-	} else if ((args & GET_BLOCK_NO_HOLE)) {
-	    ret = -ENOENT ;
-	}
-	pathrelse (&path);
-        if (p)
-            kunmap(bh_result->b_page) ;
-	return ret ;
+  if (!iicache_size(inode)) {
+    return;
+  }
+
+  // get current logical block of file
+  block = iicache_get (inode, IICACHE_BLOCK) + pos;
+  if (!block) {
+    return;
+  }  
+   
+  index = block >> PAGE_CACHE_SHIFT;
+
+  // get locked page at given index in given cache,
+  // creating it if needed.
+  page = grab_cache_page(inode->i_mapping, index);
+  if (!page) {
+    return;
+  }
+
+  // map the buffers of the page
+  nr = iicache_map_buffers(page, pos, arr);
+  if (!nr) {
+    if (is_page_buffers_uptodate(page)) {
+      SetPageUptodate(page);
     }
+    UnlockPage(page);
+    page_cache_release(page);
+    return;
+  }
+
+  // submit page buffers for read
+  iicache_submit_bh(arr, nr);
+  
+  return;
+}
+
+/*
+** Do page mapping only 
+*/
+static inline void iicache_mapping (struct inode *inode, int pos)
+{
+  struct page * page;
+  struct buffer_head *arr[MAX_BUF_PER_PAGE];
+  unsigned long block, index;
+  int nr;
+	
+  if (!iicache_size(inode)) {
+    return;
+  }
+
+  // get current logical block of file,
+  // it is page cache index as well.
+  block = iicache_get (inode, IICACHE_BLOCK) + pos;
+  if (!block) {
+    return;
+  }
+     
+  index = block >> PAGE_CACHE_SHIFT;
+
+  // get locked page at given index in given cache,
+  // creating it if needed.
+  page = grab_cache_page(inode->i_mapping, index);
+  if (!page) {
+    return;
+  }
+
+  // map the buffers of the page and
+  nr = iicache_map_buffers(page, pos, arr);
+  if (!nr && is_page_buffers_uptodate(page)) {
+    SetPageUptodate(page);
+  }
+ 
+  UnlockPage(page);
+  page_cache_release(page);
+  return;
+
+}
+
+/*
+** Try to find block in iicache.
+** Return 1 if it was used and 0 otherwise.  
+*/
+static inline int iicache_find_map_reada (struct inode * inode, long block,
+					  struct buffer_head * bh_result)
+{
+  struct super_block * sb = inode->i_sb;
+  int pos=0, ret=0;
+
+  iicache_spin_lock(inode);
+
+  if (iicache_find_map_block(inode, block, bh_result)) {
+
+    // the block was found in iicache
+    ret = 1; 
+
+    // if "reada" mount option is used 
+    if (reiserfs_iicache_reada(sb)) {
+      pos = block - iicache_first_cached(inode);
+      if ( ((pos % 8)==0) && (pos >= 8) ) { 
+	iicache_readahead (inode, pos);
+      }
+    }
+    
+    // if "readap" mount option is used 
+    if (reiserfs_iicache_readap(sb)) {
+      pos = block - iicache_first_cached(inode);
+      if ( ((pos % 7)==0) && (pos >= 7) &&
+	   block_is_iicached(inode, block+1) ) {
+	iicache_pagereada (inode, pos+1);
+      }
+    }
+    
+    // if "mapping" mount option is used 
+    if (reiserfs_iicache_mapping(sb)) {
+      pos = block - iicache_first_cached(inode);
+      if ( ((pos % 7)==0) && (pos >= 7) &&
+	   block_is_iicached(inode, block+1) ) {
+	iicache_mapping (inode, pos+1);
+      }
+    }
+  }
+  
+  iicache_spin_unlock(inode);
+  return ret;
+}
+
+/*
+** Helper function for _get_block_create_0
+*/
+static inline int iitem_map_indirect_block (struct path * path, struct inode * inode, 
+					    long block, struct buffer_head * bh_result, 
+					    int args)
+{
+  struct super_block * sb = inode->i_sb;
+  struct buffer_head * bh = get_last_bh (path);
+  struct item_head   * ih = get_ih (path);
+  __u32 * ind_item = (__u32 *)B_I_PITEM (bh, ih);
+  int blocknr=0, ret=0 ;
+
+  /*
+  ** Here we fill indirect item cache or part of it 
+  ** in the inode to avoid search_by_key in case of 
+  ** subsequent access to file.   
+  */
+  // if "iicache" mount option is used 
+  if (reiserfs_iicache(sb)) {	
+    iicache_fill (inode, block, path);
+  }	
+
+  // get disk block number from indirect item
+  blocknr = get_block_num(ind_item, path->pos_in_item) ;
+  if (!blocknr && (args & GET_BLOCK_NO_HOLE)) {
+    ret = -ENOENT ;
+  }
+
+  // map the found block
+  if (blocknr) {
+    set_block_dev_mapped (bh_result, blocknr, inode);
+  } 
+
+  return ret;
+}
+
+/*
+** Helper function for _get_block_create_0
+*/
+static int check_iicache_and_prepare_key (struct cpu_key * key,
+					  struct inode * inode, long block,
+					  struct buffer_head * bh_result)
+{
+  struct super_block * sb = inode->i_sb;
+  unsigned long offset ;  
+
+  /* 
+  ** Here we use the cache of indirect item.
+  ** Getting the unfm_block number from the cache   
+  ** we are trying to avoid some of the search_by_key() calls.  
+  */
+  // if "iicache" mount option is used 
+  if (reiserfs_iicache(sb)) {
+    if (iicache_find_map_reada(inode, block, bh_result)) {
+      return 0;
+    }
+  }
+
+  // prepare the key to look for the 'block'-th block of file
+  offset = block * inode->i_sb->s_blocksize + 1;
+  make_cpu_key (key, inode, (loff_t)offset, TYPE_ANY, 3);
+
+  return 1;
+}
+
+/*
+** Helper function for _get_block_create_0
+*/
+static inline void path_relse_page_unmap (struct path * path, char * p, 
+					  struct page * page) {
+  pathrelse(path);
+  if (p) 
+    kunmap(page);
+}
+
+/*
+** Handle Indirect Item case and simple direct case.
+** "gbc0" stands for "get_block_create_0"  
+*/
+static inline int gbc0_indirect_case (char * p, struct path * path, 
+				      struct inode *inode, long block, 
+				      struct buffer_head * bh_result, 
+				      int args) 
+{
+  struct page * page = bh_result->b_page;
+  struct item_head * ih = get_ih (path);
+  int ret=0;
+
+  // requested data are in indirect item(s)
+  if (is_indirect_le_ih (ih)) {
+    ret = iitem_map_indirect_block (path, inode, block, bh_result, args);
+    path_relse_page_unmap (path, p, page);
+    return ret ; /* could be "0" or "-ENOENT" only*/
+  }
+  return 1;
+}
+
+/*
+** Direct Item case start.
+** "gbc0" stands for "get_block_create_0"  
+*/
+static inline int gbc0_direct_case_start (char * p, struct path * path, 
+					  struct inode *inode, 
+					  struct buffer_head * bh_result, 
+					  int args) 
+{
+  struct page * page = bh_result->b_page;
 
     // requested data are in direct item(s)
     if (!(args & GET_BLOCK_READ_DIRECT)) {
-	// we are called by bmap. FIXME: we can not map block of file
-	// when it is stored in direct item(s)
-	pathrelse (&path);	
-        if (p)
-            kunmap(bh_result->b_page) ;
-	return -ENOENT;
+      // we are called by bmap. FIXME: we can not map block of file
+      // when it is stored in direct item(s)
+      path_relse_page_unmap (path, p, page);
+      return -ENOENT;
     }
 
     /* if we've got a direct item, and the buffer was uptodate,
@@ -318,80 +732,148 @@
     ** end, where we map the buffer and return
     */
     if (buffer_uptodate(bh_result)) {
-        goto finished ;
+      set_block_dev_mapped (bh_result, 0, inode);
+      path_relse_page_unmap (path, p, page);
+      return 0;
     }
 
-    // read file tail into part of page
-    offset = (cpu_key_k_offset(&key) - 1) & (PAGE_CACHE_SIZE - 1) ;
-    fs_gen = get_generation(inode->i_sb) ;
-    copy_item_head (&tmp_ih, ih);
+    return 1;
+}
 
-    /* we only want to kmap if we are reading the tail into the page.
-    ** this is not the common case, so we don't kmap until we are
-    ** sure we need to.  But, this means the item might move if
-    ** kmap schedules
+/*
+** Handle Direct Item case.
+** "gbc0" stands for "get_block_create_0"  
+*/
+static inline void gbc0_direct_case (char * p, struct path * path, 
+				     struct inode *inode, 
+				     struct cpu_key * key)			
+{
+  struct buffer_head * bh;
+  struct super_block * sb = inode->i_sb;
+  struct item_head * ih = get_ih (path);
+  int chars=0, done=0;
+
+  do {
+    if (!is_direct_le_ih (ih)) {
+      BUG ();
+    }
+    /* make sure we don't read more bytes than actually exist in
+    ** the file.  This can happen in odd cases where i_size isn't
+    ** correct, and when direct item padding results in a few 
+    ** extra bytes at the end of the direct item
     */
-    if (!p) {
-    p = (char *)kmap(bh_result->b_page) ;
-    if (fs_changed (fs_gen, inode->i_sb) && item_moved (&tmp_ih, &path)) {
-        goto research;
-    }
+    if ((le_ih_k_offset(ih) + path->pos_in_item) > inode->i_size)
+      break ;
+
+    if ((le_ih_k_offset(ih) - 1 + ih_item_len(ih)) > inode->i_size) {
+      chars = inode->i_size - (le_ih_k_offset(ih) - 1) - path->pos_in_item;
+      done = 1 ;
+    } else {
+      chars = ih_item_len(ih) - path->pos_in_item;
     }
-    p += offset ;
-    memset (p, 0, inode->i_sb->s_blocksize);
-    do {
-	if (!is_direct_le_ih (ih)) {
-	    BUG ();
-        }
-	/* make sure we don't read more bytes than actually exist in
-	** the file.  This can happen in odd cases where i_size isn't
-	** correct, and when direct item padding results in a few 
-	** extra bytes at the end of the direct item
-	*/
-        if ((le_ih_k_offset(ih) + path.pos_in_item) > inode->i_size)
-	    break ;
-	if ((le_ih_k_offset(ih) - 1 + ih_item_len(ih)) > inode->i_size) {
-	    chars = inode->i_size - (le_ih_k_offset(ih) - 1) - path.pos_in_item;
-	    done = 1 ;
-	} else {
-	    chars = ih_item_len(ih) - path.pos_in_item;
-	}
-	memcpy (p, B_I_PITEM (bh, ih) + path.pos_in_item, chars);
 
-	if (done) 
-	    break ;
+    bh = get_last_bh (path);
+    memcpy (p, B_I_PITEM (bh, ih) + path->pos_in_item, chars);
 
-	p += chars;
+    if (done) 
+      break ;
 
-	if (PATH_LAST_POSITION (&path) != (B_NR_ITEMS (bh) - 1))
-	    // we done, if read direct item is not the last item of
-	    // node FIXME: we could try to check right delimiting key
-	    // to see whether direct item continues in the right
-	    // neighbor or rely on i_size
-	    break;
+    p += chars;
 
-	// update key to look for the next piece
-	set_cpu_key_k_offset (&key, cpu_key_k_offset (&key) + chars);
-	if (search_for_position_by_key (inode->i_sb, &key, &path) != POSITION_FOUND)
-	    // we read something from tail, even if now we got IO_ERROR
-	    break;
-	bh = get_last_bh (&path);
-	ih = get_ih (&path);
-    } while (1);
+    if (PATH_LAST_POSITION (path) != (B_NR_ITEMS (bh) - 1))
+      // we done, if read direct item is not the last item of
+      // node FIXME: we could try to check right delimiting key
+      // to see whether direct item continues in the right
+      // neighbor or rely on i_size
+      break;
 
-    flush_dcache_page(bh_result->b_page) ;
-    kunmap(bh_result->b_page) ;
+    // update key to look for the next piece
+    set_cpu_key_k_offset (key, cpu_key_k_offset(key) + chars);
 
-finished:
-    pathrelse (&path);
-    bh_result->b_blocknr = 0 ;
-    bh_result->b_dev = inode->i_dev;
+    if (search_for_position_by_key (sb, key, path) != POSITION_FOUND)
+      // we read something from tail, even if now we got IO_ERROR
+      break;
+
+    bh = get_last_bh (path);
+    ih = get_ih (path);
+
+  } while (1);
+
+}
+
+/*
+** Return "1" if fs changed and item moved. 
+*/
+static inline int need_research (int fs_gen, struct super_block * sb,  
+				 struct item_head * ih, struct path * path ) 
+{
+  return (fs_changed(fs_gen, sb) && item_moved(ih, path));
+}
+
+//
+// It is called by reiserfs_get_block when create == 0. 
+// Returns disk block number by logical block number of file.
+//
+// When it hits direct item it returns 0 (being called from bmap) 
+// or read direct item into piece of page (bh_result)
+//
+static int _get_block_create_0 (struct inode * inode, long block,
+				struct buffer_head * bh_result,
+				int args)
+{
+    INITIALIZE_PATH (path);
+    struct cpu_key key;
+    struct item_head   * ih, tmp_ih;
+    struct super_block * sb = inode->i_sb;
+    struct page * page = bh_result->b_page;
+    char * p = NULL;   
+    unsigned long offset ;  
+    int fs_gen=0, ret=0;
+
+    ret = check_iicache_and_prepare_key (&key, inode, block, bh_result);
+    if (!ret) 
+      return 0;
+
+    do {
+
+      if (search_for_position_by_key (sb, &key, &path) != POSITION_FOUND) {
+	path_relse_page_unmap (&path, p, page);
+	return ( (args & GET_BLOCK_NO_HOLE) ? (-ENOENT) : 0 ) ;
+      }
+
+      // check and handle indirect case 
+      ret = gbc0_indirect_case (p, &path, inode, block, bh_result, args);
+      if (ret <= 0) 
+	return ret;
+
+      // start the direct case 
+      ret = gbc0_direct_case_start (p, &path, inode, bh_result, args);
+      if (ret <= 0) 
+	return ret;
+
+      // we should read the file tail into part of page.
+      offset = (cpu_key_k_offset(&key) - 1) & (PAGE_CACHE_SIZE - 1) ;
+      fs_gen = get_generation(sb) ;
+      ih = get_ih (&path);
+      copy_item_head (&tmp_ih, ih);
+      if (!p) 
+	p=(char *)kmap(page);
+      
+    } while (need_research(fs_gen, sb, &tmp_ih, &path));
+
+    // ok, we have direct item and kmapped page,
+    // do copy from direct item to page now. 
+    p += offset;
+    memset (p, 0, sb->s_blocksize);
+    gbc0_direct_case (p, &path, inode, &key);
+
+    flush_dcache_page(page) ;
+    path_relse_page_unmap (&path, p, page);
+    set_block_dev_mapped (bh_result, 0, inode);
     mark_buffer_uptodate (bh_result, 1);
-    bh_result->b_state |= (1UL << BH_Mapped);
     return 0;
 }
 
-
 // this is called to create file map. So, _get_block_create_0 will not
 // read direct item
 int reiserfs_bmap (struct inode * inode, long block,
@@ -515,7 +997,7 @@
 // determine which parts are derivative, if any, understanding that
 // there are only so many ways to code to a given interface.
 //
-static int reiserfs_get_block (struct inode * inode, long block,
+static int __reiserfs_get_block (struct inode * inode, long block,
 			       struct buffer_head * bh_result, int create)
 {
     int repeat, retval;
@@ -526,6 +1008,7 @@
     struct cpu_key key;
     struct buffer_head * bh, * unbh = 0;
     struct item_head * ih, tmp_ih;
+    struct super_block * sb = inode->i_sb;
     __u32 * item;
     int done;
     int fs_gen;
@@ -568,6 +1051,15 @@
 	return ret;
     }
 
+    if (reiserfs_iicache(sb)) {
+      /* Clear ii-cache to prevent situation when
+      ** changed disk block could miss ii-cache. 
+      */
+      iicache_spin_lock(inode);
+      iicache_clear(inode);
+      iicache_spin_unlock(inode);
+    }
+
     inode->u.reiserfs_i.i_flags |= i_pack_on_close_mask;
 
     windex = push_journal_writer("reiserfs_get_block") ;
@@ -855,6 +1347,36 @@
     return retval;
 }
 
+int reiserfs_get_block (struct inode * inode, long block,
+			struct buffer_head * bh_result, 
+			int create)
+{
+  int res=0;
+
+  // if "iicache,NO_BKL" mount options are used
+  if (reiserfs_iicache(inode->i_sb) && 
+      reiserfs_iicache_no_bkl(inode->i_sb)) {
+
+    // and fs should not be changed 
+    if (!(create & GET_BLOCK_CREATE)) {
+
+      // try to get the block from iicache
+      // and if we've got it - return.
+      iicache_spin_lock(inode);
+      res=iicache_find_map_block(inode, block, bh_result);
+      iicache_spin_unlock(inode);
+
+      if(res) { 
+	return 0;
+      }
+
+    }
+  }
+  
+  // if we could not get block from iicache then
+  // start to search needed block in the reiserfs tree.
+  return __reiserfs_get_block (inode, block, bh_result, create);
+}
 
 //
 // BAD: new directories have stat data of new type and all other items
@@ -879,6 +1401,7 @@
     inode->i_blksize = PAGE_SIZE;
 
     INIT_LIST_HEAD(&inode->u.reiserfs_i.i_prealloc_list) ;
+    iicache_spin_lock_init (inode);
 
     if (stat_data_v1 (ih)) {
 	struct stat_data_v1 * sd = (struct stat_data_v1 *)B_I_PITEM (bh, ih);
@@ -1457,8 +1980,14 @@
     inode->i_flags = 0;//inode->i_sb->s_flags;
 
     /* item head of new item */
-    ih.ih_key.k_dir_id = INODE_PKEY (dir)->k_objectid;
-    ih.ih_key.k_objectid = cpu_to_le32 (reiserfs_get_unused_objectid (th));
+    if (reiserfs_dirid_eq_objid(sb)) {
+      ih.ih_key.k_dir_id = cpu_to_le32 (reiserfs_get_unused_objectid (th));
+      ih.ih_key.k_objectid = ih.ih_key.k_dir_id;
+    } else {
+      ih.ih_key.k_dir_id = INODE_PKEY (dir)->k_objectid;
+      ih.ih_key.k_objectid = cpu_to_le32 (reiserfs_get_unused_objectid (th));
+    }
+
     if (!ih.ih_key.k_objectid) {
 	iput(inode) ;
 	*err = -ENOMEM;
@@ -1520,6 +2049,7 @@
       U32_MAX/*NO_BYTES_IN_DIRECT_ITEM*/;
 
     INIT_LIST_HEAD(&inode->u.reiserfs_i.i_prealloc_list) ;
+    iicache_spin_lock_init (inode);
 
     if (old_format_only (sb)) {
 	if (inode->i_uid & ~0xffff || inode->i_gid & ~0xffff) {
@@ -1681,6 +2211,7 @@
 */
 void reiserfs_truncate_file(struct inode *p_s_inode, int update_timestamps) {
     struct reiserfs_transaction_handle th ;
+    struct super_block * sb = p_s_inode->i_sb;
     int windex ;
 
     /* we want the offset for the first byte after the end of the file */
@@ -1716,6 +2247,13 @@
     journal_begin(&th, p_s_inode->i_sb,  JOURNAL_PER_BALANCE_CNT * 2 + 1 ) ;
     reiserfs_update_inode_transaction(p_s_inode) ;
     windex = push_journal_writer("reiserfs_vfs_truncate_file") ;
+
+    if (reiserfs_iicache(sb)) {
+      iicache_spin_lock(p_s_inode);
+      iicache_truncate (p_s_inode); /* truncate ii_cache */
+      iicache_spin_unlock(p_s_inode);
+    }
+
     if (update_timestamps)
            /* we are doing real truncate: if the system crashes before the last
               transaction of truncating gets committed - on reboot the file
diff -urN v2.4.17rc1/fs/reiserfs/super.c linux/fs/reiserfs/super.c
--- v2.4.17rc1/fs/reiserfs/super.c	Fri Dec 14 13:58:16 2001
+++ linux/fs/reiserfs/super.c	Mon Dec 17 18:37:19 2001
@@ -439,6 +439,20 @@
 	    set_bit (REISERFS_HASHED_RELOCATION, mount_options);
 	} else if (!strcmp (this_char, "test4")) {
 	    set_bit (REISERFS_TEST4, mount_options);
+	} else if (!strcmp (this_char, "iicache")) {
+	    set_bit (REISERFS_IICACHE, mount_options);
+	} else if (!strcmp (this_char, "reada")) {
+	    set_bit (REISERFS_IICACHE_READA, mount_options);
+	} else if (!strcmp (this_char, "readap")) {
+	    set_bit (REISERFS_IICACHE_READAP, mount_options);
+	} else if (!strcmp (this_char, "mapping")) {
+	    set_bit (REISERFS_IICACHE_MAPPING, mount_options);
+	} else if (!strcmp (this_char, "NO_BKL")) {
+	    set_bit (REISERFS_IICACHE_NO_BKL, mount_options);
+	} else if (!strcmp (this_char, "small_tails")) {
+	    set_bit (REISERFS_SMALL_TAILS, mount_options);
+	} else if (!strcmp (this_char, "deqo")) {
+	    set_bit (REISERFS_DIRID_EQ_OBJID, mount_options);
 	} else if (!strcmp (this_char, "nolog")) {
 	    reiserfs_warning("reiserfs: nolog mount option not supported yet\n");
 	} else if (!strcmp (this_char, "replayonly")) {
diff -urN v2.4.17rc1/include/linux/reiserfs_fs.h linux/include/linux/reiserfs_fs.h
--- v2.4.17rc1/include/linux/reiserfs_fs.h	Fri Dec 14 13:58:18 2001
+++ linux/include/linux/reiserfs_fs.h	Mon Dec 17 18:42:08 2001
@@ -197,6 +197,12 @@
      ( (n_tail_size) >=   (MAX_DIRECT_ITEM_LEN(n_block_size) * 3)/4) ) ) \
 )
 
+#define STORE_TAIL_IN_UNFM_2(n_file_size,n_tail_size,n_block_size) \
+(\
+  (!(n_tail_size)) || \
+  (n_tail_size >= (MAX_DIRECT_ITEM_LEN(n_block_size))) || \
+  (n_file_size >= (MAX_DIRECT_ITEM_LEN(n_block_size))) \
+)
 
 /*
  * values for s_state field
@@ -1668,9 +1674,19 @@
 #define file_size(inode) ((inode)->i_size)
 #define tail_size(inode) (file_size (inode) & (block_size (inode) - 1))
 
-#define tail_has_to_be_packed(inode) (!dont_have_tails ((inode)->i_sb) &&\
+#define _tail_has_to_be_packed(inode) (!dont_have_tails ((inode)->i_sb) &&\
 !STORE_TAIL_IN_UNFM(file_size (inode), tail_size(inode), block_size (inode)))
 
+#define _tail_has_to_be_packed_2(inode) (!dont_have_tails ((inode)->i_sb) &&\
+!STORE_TAIL_IN_UNFM_2(file_size (inode), tail_size(inode), block_size (inode)))
+
+static inline int tail_has_to_be_packed(struct inode * inode) {
+  if (reiserfs_small_tails(inode->i_sb)) {
+    return _tail_has_to_be_packed_2(inode); 
+  }
+  return _tail_has_to_be_packed(inode);
+}
+
 void padd_item (char * item, int total_length, int length);
 
 /* inode.c */
@@ -1700,6 +1716,125 @@
 				   struct dentry *dentry, struct inode *inode, int * err);
 int reiserfs_sync_inode (struct reiserfs_transaction_handle *th, struct inode * inode);
 void reiserfs_update_sd (struct reiserfs_transaction_handle *th, struct inode * inode);
+
+/*
+** The indirect item cache - iicache.
+** 
+** We put the indirect item or part of it to iicache and  
+** can avoid now a lot of search_by_key calls.  
+*/
+
+#define IICACHE_BLOCKNR 1
+#define IICACHE_SIZE    2
+#define IICACHE_BLOCK   3
+
+/* 
+** Set parameter of given type to iicache  
+*/
+static inline void iicache_set (struct inode * inode, 
+				long param, int type)
+{
+  switch (type) {
+  case IICACHE_BLOCKNR : inode->u.reiserfs_i.i_cache_blocknr = param; 
+                         break;
+  case IICACHE_SIZE    : inode->u.reiserfs_i.i_cache_size = param; 
+                         break;
+  case IICACHE_BLOCK   : inode->u.reiserfs_i.i_cache_block = param; 
+                         break;
+  }
+}
+
+/* 
+** Get parameter of given type from iicache  
+*/
+static inline long iicache_get (struct inode * inode, int type)
+{
+  long val;
+  switch (type) {
+  case IICACHE_BLOCKNR : val=inode->u.reiserfs_i.i_cache_blocknr;
+                         break; 
+  case IICACHE_SIZE    : val=inode->u.reiserfs_i.i_cache_size;
+                         break;  
+  case IICACHE_BLOCK   : val=inode->u.reiserfs_i.i_cache_block;
+                         break;  
+  }
+  return val;
+}
+
+/* 
+** Clear the indirect item cache 
+*/
+static inline void iicache_clear(struct inode * inode)
+{
+  iicache_set (inode, 0, IICACHE_SIZE);
+  iicache_set (inode, 0, IICACHE_BLOCK);
+  iicache_set (inode, 0, IICACHE_BLOCKNR);
+}
+
+/* 
+** Get the first blocknr of the set of contiguous blocknrs
+*/
+static inline long iicache_get_blocknr(struct inode * inode) 
+{
+  return (iicache_get(inode, IICACHE_BLOCKNR));
+}
+
+/* 
+** Get the size of indirect item cache  
+*/
+static inline long iicache_size(struct inode * inode)
+{
+  return (iicache_get(inode, IICACHE_SIZE));
+}
+
+/* 
+** Get the first cached logical block of file 
+*/
+static inline long iicache_first_cached(struct inode * inode)
+{
+  return (iicache_get(inode, IICACHE_BLOCK));
+}
+
+/* 
+** Get the last cached logical block of file 
+*/
+static inline long iicache_last_cached(struct inode * inode)
+{
+  return (iicache_first_cached(inode) + iicache_size(inode) - 1);
+}
+
+/* 
+** Check the logical block of file: is it in iicache 
+*/
+static inline int block_is_iicached(struct inode * inode, long block)
+{
+  return ((block >= iicache_first_cached(inode)) && 
+	  (block <= iicache_last_cached(inode))); 
+}
+
+/* 
+** Get the disk block number by the logical block number of file 
+*/
+static inline long iicache_blocknr(struct inode * inode, long block)
+{    
+  long offset = block - iicache_first_cached(inode); 
+  return (iicache_get_blocknr(inode) + offset);
+}
+
+static inline void iicache_spin_lock_init(struct inode * inode) 
+{
+  inode->u.reiserfs_i.i_cache_lock = SPIN_LOCK_UNLOCKED; 
+}
+
+static inline void iicache_spin_lock(struct inode * inode) 
+{
+  spin_lock ( &(inode->u.reiserfs_i.i_cache_lock) );
+}
+
+static inline void iicache_spin_unlock(struct inode * inode) 
+{
+  spin_unlock ( &(inode->u.reiserfs_i.i_cache_lock) );
+}
 
 /* namei.c */
 inline void set_de_name_and_namelen (struct reiserfs_dir_entry * de);
diff -urN v2.4.17rc1/include/linux/reiserfs_fs_i.h linux/include/linux/reiserfs_fs_i.h
--- v2.4.17rc1/include/linux/reiserfs_fs_i.h	Fri Dec 14 13:58:18 2001
+++ linux/include/linux/reiserfs_fs_i.h	Mon Dec 17 18:43:30 2001
@@ -43,6 +43,12 @@
     ** flushed */
     unsigned long i_trans_id ;
     unsigned long i_trans_index ;
+
+  // The cache for indirect item  
+  long  i_cache_blocknr;        /* the first of set of contiguous blocknrs */
+  long  i_cache_size;           /* the amount of set of contiguous blocknrs */      
+  long  i_cache_block;          /* the first, cached logical block of file  */
+  spinlock_t i_cache_lock;      /* spimlock to protect iicache changing     */
 };
 
 #endif
diff -urN v2.4.17rc1/include/linux/reiserfs_fs_sb.h linux/include/linux/reiserfs_fs_sb.h
--- v2.4.17rc1/include/linux/reiserfs_fs_sb.h	Fri Dec 14 13:58:18 2001
+++ linux/include/linux/reiserfs_fs_sb.h	Mon Dec 17 18:46:54 2001
@@ -465,6 +465,13 @@
 #define REISERFS_TEST2 12
 #define REISERFS_TEST3 13
 #define REISERFS_TEST4 14 
+#define REISERFS_IICACHE 17 
+#define REISERFS_IICACHE_READA 18 
+#define REISERFS_IICACHE_READAP 19 
+#define REISERFS_IICACHE_MAPPING 20 
+#define REISERFS_IICACHE_NO_BKL 21 
+#define REISERFS_SMALL_TAILS 22 
+#define REISERFS_DIRID_EQ_OBJID 23 
 
 #define reiserfs_r5_hash(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << FORCE_R5_HASH))
 #define reiserfs_rupasov_hash(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << FORCE_RUPASOV_HASH))
@@ -474,6 +481,14 @@
 #define reiserfs_no_unhashed_relocation(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_NO_UNHASHED_RELOCATION))
 #define reiserfs_hashed_relocation(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_HASHED_RELOCATION))
 #define reiserfs_test4(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_TEST4))
+
+#define reiserfs_iicache(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_IICACHE))
+#define reiserfs_iicache_reada(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_IICACHE_READA))
+#define reiserfs_iicache_readap(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_IICACHE_READAP))
+#define reiserfs_iicache_mapping(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_IICACHE_MAPPING))
+#define reiserfs_iicache_no_bkl(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_IICACHE_NO_BKL))
+#define reiserfs_small_tails(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_SMALL_TAILS))
+#define reiserfs_dirid_eq_objid(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_DIRID_EQ_OBJID))
 
 #define dont_have_tails(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << NOTAIL))
 #define replay_only(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REPLAYONLY))
