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;
}
- /* 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 (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;
+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;
/* 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 */
};