diff -urN v2.4.17/fs/reiserfs/inode.c linux/fs/reiserfs/inode.c --- v2.4.17/fs/reiserfs/inode.c Mon Dec 24 17:15:13 2001 +++ linux/fs/reiserfs/inode.c Mon Dec 24 17:24:17 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.17/fs/reiserfs/super.c linux/fs/reiserfs/super.c --- v2.4.17/fs/reiserfs/super.c Mon Dec 24 17:15:13 2001 +++ linux/fs/reiserfs/super.c Mon Dec 24 17:24:17 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.17/include/linux/reiserfs_fs.h linux/include/linux/reiserfs_fs.h --- v2.4.17/include/linux/reiserfs_fs.h Mon Dec 24 17:15:15 2001 +++ linux/include/linux/reiserfs_fs.h Mon Dec 24 17:24:17 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.17/include/linux/reiserfs_fs_i.h linux/include/linux/reiserfs_fs_i.h --- v2.4.17/include/linux/reiserfs_fs_i.h Mon Dec 24 17:15:15 2001 +++ linux/include/linux/reiserfs_fs_i.h Mon Dec 24 17:24:17 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.17/include/linux/reiserfs_fs_sb.h linux/include/linux/reiserfs_fs_sb.h --- v2.4.17/include/linux/reiserfs_fs_sb.h Mon Dec 24 17:15:15 2001 +++ linux/include/linux/reiserfs_fs_sb.h Mon Dec 24 17:24:17 2001 @@ -471,6 +471,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)) @@ -480,6 +487,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)) .