diff options
author | David Woodhouse <dwmw2@shinybook.infradead.org> | 2005-07-13 15:25:59 +0100 |
---|---|---|
committer | David Woodhouse <dwmw2@shinybook.infradead.org> | 2005-07-13 15:25:59 +0100 |
commit | 30beab1491f0b96b2f23d3fb68af01fd921a16d8 (patch) | |
tree | c580bdc0846269fbb10feeda901ecec1a48ee2ef /fs/reiserfs/inode.c | |
parent | 21af6c4f2aa5f63138871b4ddd77d7ebf2588c9d (diff) | |
parent | c32511e2718618f0b53479eb36e07439aa363a74 (diff) | |
download | linux-stable-30beab1491f0b96b2f23d3fb68af01fd921a16d8.tar.gz linux-stable-30beab1491f0b96b2f23d3fb68af01fd921a16d8.tar.bz2 linux-stable-30beab1491f0b96b2f23d3fb68af01fd921a16d8.zip |
Merge with /shiny/git/linux-2.6/.git
Diffstat (limited to 'fs/reiserfs/inode.c')
-rw-r--r-- | fs/reiserfs/inode.c | 4915 |
1 files changed, 2521 insertions, 2394 deletions
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 289d864fe731..1aaf2c7d44e6 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -18,107 +18,109 @@ #include <linux/writeback.h> #include <linux/quotaops.h> -extern int reiserfs_default_io_size; /* default io size devuned in super.c */ +extern int reiserfs_default_io_size; /* default io size devuned in super.c */ static int reiserfs_commit_write(struct file *f, struct page *page, - unsigned from, unsigned to); + unsigned from, unsigned to); static int reiserfs_prepare_write(struct file *f, struct page *page, unsigned from, unsigned to); -void reiserfs_delete_inode (struct inode * inode) +void reiserfs_delete_inode(struct inode *inode) { - /* We need blocks for transaction + (user+group) quota update (possibly delete) */ - int jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2 * REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb); - struct reiserfs_transaction_handle th ; - - reiserfs_write_lock(inode->i_sb); + /* We need blocks for transaction + (user+group) quota update (possibly delete) */ + int jbegin_count = + JOURNAL_PER_BALANCE_CNT * 2 + + 2 * REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb); + struct reiserfs_transaction_handle th; - /* The = 0 happens when we abort creating a new inode for some reason like lack of space.. */ - if (!(inode->i_state & I_NEW) && INODE_PKEY(inode)->k_objectid != 0) { /* also handles bad_inode case */ - down (&inode->i_sem); + reiserfs_write_lock(inode->i_sb); - reiserfs_delete_xattrs (inode); + /* The = 0 happens when we abort creating a new inode for some reason like lack of space.. */ + if (!(inode->i_state & I_NEW) && INODE_PKEY(inode)->k_objectid != 0) { /* also handles bad_inode case */ + down(&inode->i_sem); - if (journal_begin(&th, inode->i_sb, jbegin_count)) { - up (&inode->i_sem); - goto out; - } - reiserfs_update_inode_transaction(inode) ; + reiserfs_delete_xattrs(inode); - if (reiserfs_delete_object (&th, inode)) { - up (&inode->i_sem); - goto out; - } + if (journal_begin(&th, inode->i_sb, jbegin_count)) { + up(&inode->i_sem); + goto out; + } + reiserfs_update_inode_transaction(inode); - /* Do quota update inside a transaction for journaled quotas. We must do that - * after delete_object so that quota updates go into the same transaction as - * stat data deletion */ - DQUOT_FREE_INODE(inode); + if (reiserfs_delete_object(&th, inode)) { + up(&inode->i_sem); + goto out; + } - if (journal_end(&th, inode->i_sb, jbegin_count)) { - up (&inode->i_sem); - goto out; - } + /* Do quota update inside a transaction for journaled quotas. We must do that + * after delete_object so that quota updates go into the same transaction as + * stat data deletion */ + DQUOT_FREE_INODE(inode); + + if (journal_end(&th, inode->i_sb, jbegin_count)) { + up(&inode->i_sem); + goto out; + } - up (&inode->i_sem); + up(&inode->i_sem); - /* all items of file are deleted, so we can remove "save" link */ - remove_save_link (inode, 0/* not truncate */); /* we can't do anything - * about an error here */ - } else { - /* no object items are in the tree */ - ; - } -out: - clear_inode (inode); /* note this must go after the journal_end to prevent deadlock */ - inode->i_blocks = 0; - reiserfs_write_unlock(inode->i_sb); + /* all items of file are deleted, so we can remove "save" link */ + remove_save_link(inode, 0 /* not truncate */ ); /* we can't do anything + * about an error here */ + } else { + /* no object items are in the tree */ + ; + } + out: + clear_inode(inode); /* note this must go after the journal_end to prevent deadlock */ + inode->i_blocks = 0; + reiserfs_write_unlock(inode->i_sb); } -static void _make_cpu_key (struct cpu_key * key, int version, __u32 dirid, __u32 objectid, - loff_t offset, int type, int length ) +static void _make_cpu_key(struct cpu_key *key, int version, __u32 dirid, + __u32 objectid, loff_t offset, int type, int length) { - key->version = version; + key->version = version; - key->on_disk_key.k_dir_id = dirid; - key->on_disk_key.k_objectid = objectid; - set_cpu_key_k_offset (key, offset); - set_cpu_key_k_type (key, type); - key->key_length = length; + key->on_disk_key.k_dir_id = dirid; + key->on_disk_key.k_objectid = objectid; + set_cpu_key_k_offset(key, offset); + set_cpu_key_k_type(key, type); + key->key_length = length; } - /* take base of inode_key (it comes from inode always) (dirid, objectid) and version from an inode, set offset and type of key */ -void make_cpu_key (struct cpu_key * key, struct inode * inode, loff_t offset, - int type, int length ) +void make_cpu_key(struct cpu_key *key, struct inode *inode, loff_t offset, + int type, int length) { - _make_cpu_key (key, get_inode_item_key_version (inode), le32_to_cpu (INODE_PKEY (inode)->k_dir_id), - le32_to_cpu (INODE_PKEY (inode)->k_objectid), - offset, type, length); + _make_cpu_key(key, get_inode_item_key_version(inode), + le32_to_cpu(INODE_PKEY(inode)->k_dir_id), + le32_to_cpu(INODE_PKEY(inode)->k_objectid), offset, type, + length); } - // // when key is 0, do not set version and short key // -inline void make_le_item_head (struct item_head * ih, const struct cpu_key * key, - int version, - loff_t offset, int type, int length, - int entry_count/*or ih_free_space*/) +inline void make_le_item_head(struct item_head *ih, const struct cpu_key *key, + int version, + loff_t offset, int type, int length, + int entry_count /*or ih_free_space */ ) { - if (key) { - ih->ih_key.k_dir_id = cpu_to_le32 (key->on_disk_key.k_dir_id); - ih->ih_key.k_objectid = cpu_to_le32 (key->on_disk_key.k_objectid); - } - put_ih_version( ih, version ); - set_le_ih_k_offset (ih, offset); - set_le_ih_k_type (ih, type); - put_ih_item_len( ih, length ); - /* set_ih_free_space (ih, 0);*/ - // for directory items it is entry count, for directs and stat - // datas - 0xffff, for indirects - 0 - put_ih_entry_count( ih, entry_count ); + if (key) { + ih->ih_key.k_dir_id = cpu_to_le32(key->on_disk_key.k_dir_id); + ih->ih_key.k_objectid = + cpu_to_le32(key->on_disk_key.k_objectid); + } + put_ih_version(ih, version); + set_le_ih_k_offset(ih, offset); + set_le_ih_k_type(ih, type); + put_ih_item_len(ih, length); + /* set_ih_free_space (ih, 0); */ + // for directory items it is entry count, for directs and stat + // datas - 0xffff, for indirects - 0 + put_ih_entry_count(ih, entry_count); } // @@ -153,84 +155,84 @@ inline void make_le_item_head (struct item_head * ih, const struct cpu_key * key ** to be unmapped, so that block_prepare_write will correctly call ** reiserfs_get_block to convert the tail into an unformatted node */ -static inline void fix_tail_page_for_writing(struct page *page) { - struct buffer_head *head, *next, *bh ; - - if (page && page_has_buffers(page)) { - head = page_buffers(page) ; - bh = head ; - do { - next = bh->b_this_page ; - if (buffer_mapped(bh) && bh->b_blocknr == 0) { - reiserfs_unmap_buffer(bh) ; - } - bh = next ; - } while (bh != head) ; - } +static inline void fix_tail_page_for_writing(struct page *page) +{ + struct buffer_head *head, *next, *bh; + + if (page && page_has_buffers(page)) { + head = page_buffers(page); + bh = head; + do { + next = bh->b_this_page; + if (buffer_mapped(bh) && bh->b_blocknr == 0) { + reiserfs_unmap_buffer(bh); + } + bh = next; + } while (bh != head); + } } /* reiserfs_get_block does not need to allocate a block only if it has been done already or non-hole position has been found in the indirect item */ -static inline int allocation_needed (int retval, b_blocknr_t allocated, - struct item_head * ih, - __le32 * item, int pos_in_item) +static inline int allocation_needed(int retval, b_blocknr_t allocated, + struct item_head *ih, + __le32 * item, int pos_in_item) { - if (allocated) - return 0; - if (retval == POSITION_FOUND && is_indirect_le_ih (ih) && - get_block_num(item, pos_in_item)) - return 0; - return 1; + if (allocated) + return 0; + if (retval == POSITION_FOUND && is_indirect_le_ih(ih) && + get_block_num(item, pos_in_item)) + return 0; + return 1; } -static inline int indirect_item_found (int retval, struct item_head * ih) +static inline int indirect_item_found(int retval, struct item_head *ih) { - return (retval == POSITION_FOUND) && is_indirect_le_ih (ih); + return (retval == POSITION_FOUND) && is_indirect_le_ih(ih); } - -static inline void set_block_dev_mapped (struct buffer_head * bh, - b_blocknr_t block, struct inode * inode) +static inline void set_block_dev_mapped(struct buffer_head *bh, + b_blocknr_t block, struct inode *inode) { map_bh(bh, inode->i_sb, block); } - // // files which were created in the earlier version can not be longer, // than 2 gb // -static int file_capable (struct inode * inode, long block) +static int file_capable(struct inode *inode, long block) { - if (get_inode_item_key_version (inode) != KEY_FORMAT_3_5 || // it is new file. - block < (1 << (31 - inode->i_sb->s_blocksize_bits))) // old file, but 'block' is inside of 2gb - return 1; + if (get_inode_item_key_version(inode) != KEY_FORMAT_3_5 || // it is new file. + block < (1 << (31 - inode->i_sb->s_blocksize_bits))) // old file, but 'block' is inside of 2gb + return 1; - return 0; + return 0; } /*static*/ int restart_transaction(struct reiserfs_transaction_handle *th, - struct inode *inode, struct path *path) { - struct super_block *s = th->t_super ; - int len = th->t_blocks_allocated ; - int err; - - BUG_ON (!th->t_trans_id); - BUG_ON (!th->t_refcount); - - /* we cannot restart while nested */ - if (th->t_refcount > 1) { - return 0 ; - } - pathrelse(path) ; - reiserfs_update_sd(th, inode) ; - err = journal_end(th, s, len) ; - if (!err) { - err = journal_begin(th, s, JOURNAL_PER_BALANCE_CNT * 6) ; - if (!err) - reiserfs_update_inode_transaction(inode) ; - } - return err; + struct inode *inode, struct path *path) +{ + struct super_block *s = th->t_super; + int len = th->t_blocks_allocated; + int err; + + BUG_ON(!th->t_trans_id); + BUG_ON(!th->t_refcount); + + /* we cannot restart while nested */ + if (th->t_refcount > 1) { + return 0; + } + pathrelse(path); + reiserfs_update_sd(th, inode); + err = journal_end(th, s, len); + if (!err) { + err = journal_begin(th, s, JOURNAL_PER_BALANCE_CNT * 6); + if (!err) + reiserfs_update_inode_transaction(inode); + } + return err; } // it is called by get_block when create == 0. Returns block number @@ -241,190 +243,192 @@ static int file_capable (struct inode * inode, long block) // Please improve the english/clarity in the comment above, as it is // hard to understand. -static int _get_block_create_0 (struct inode * inode, long block, - struct buffer_head * bh_result, - int args) +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 buffer_head * bh; - struct item_head * ih, tmp_ih; - int fs_gen ; - int blocknr; - char * p = NULL; - int chars; - int ret ; - int result ; - 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); - -research: - result = search_for_position_by_key (inode->i_sb, &key, &path) ; - if (result != POSITION_FOUND) { - pathrelse (&path); - if (p) - kunmap(bh_result->b_page) ; - if (result == IO_ERROR) - return -EIO; - // We do not return -ENOENT if there is a hole but page is uptodate, because it means - // That there is some MMAPED data associated with it that is yet to be written to disk. - if ((args & GET_BLOCK_NO_HOLE) && !PageUptodate(bh_result->b_page) ) { - return -ENOENT ; - } - return 0 ; - } - - // - bh = get_last_bh (&path); - ih = get_ih (&path); - if (is_indirect_le_ih (ih)) { - __le32 * ind_item = (__le32 *)B_I_PITEM (bh, ih); - - /* 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) { - map_bh(bh_result, inode->i_sb, blocknr); - if (path.pos_in_item == ((ih_item_len(ih) / UNFM_P_SIZE) - 1)) { - set_buffer_boundary(bh_result); - } - } else - // We do not return -ENOENT if there is a hole but page is uptodate, because it means - // That there is some MMAPED data associated with it that is yet to be written to disk. - if ((args & GET_BLOCK_NO_HOLE) && !PageUptodate(bh_result->b_page) ) { - ret = -ENOENT ; - } - - pathrelse (&path); - if (p) - kunmap(bh_result->b_page) ; - return ret ; - } - - // 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; - } - - /* if we've got a direct item, and the buffer or page was uptodate, - ** we don't want to pull data off disk again. skip to the - ** end, where we map the buffer and return - */ - if (buffer_uptodate(bh_result)) { - goto finished ; - } else - /* - ** grab_tail_page can trigger calls to reiserfs_get_block on up to date - ** pages without any buffers. If the page is up to date, we don't want - ** read old data off disk. Set the up to date bit on the buffer instead - ** and jump to the end - */ - if (!bh_result->b_page || PageUptodate(bh_result->b_page)) { + 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 result; + 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); + + research: + result = search_for_position_by_key(inode->i_sb, &key, &path); + if (result != POSITION_FOUND) { + pathrelse(&path); + if (p) + kunmap(bh_result->b_page); + if (result == IO_ERROR) + return -EIO; + // We do not return -ENOENT if there is a hole but page is uptodate, because it means + // That there is some MMAPED data associated with it that is yet to be written to disk. + if ((args & GET_BLOCK_NO_HOLE) + && !PageUptodate(bh_result->b_page)) { + return -ENOENT; + } + return 0; + } + // + bh = get_last_bh(&path); + ih = get_ih(&path); + if (is_indirect_le_ih(ih)) { + __le32 *ind_item = (__le32 *) B_I_PITEM(bh, ih); + + /* 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) { + map_bh(bh_result, inode->i_sb, blocknr); + if (path.pos_in_item == + ((ih_item_len(ih) / UNFM_P_SIZE) - 1)) { + set_buffer_boundary(bh_result); + } + } else + // We do not return -ENOENT if there is a hole but page is uptodate, because it means + // That there is some MMAPED data associated with it that is yet to be written to disk. + if ((args & GET_BLOCK_NO_HOLE) + && !PageUptodate(bh_result->b_page)) { + ret = -ENOENT; + } + + pathrelse(&path); + if (p) + kunmap(bh_result->b_page); + return ret; + } + // 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; + } + + /* if we've got a direct item, and the buffer or page was uptodate, + ** we don't want to pull data off disk again. skip to the + ** end, where we map the buffer and return + */ + if (buffer_uptodate(bh_result)) { + goto finished; + } else + /* + ** grab_tail_page can trigger calls to reiserfs_get_block on up to date + ** pages without any buffers. If the page is up to date, we don't want + ** read old data off disk. Set the up to date bit on the buffer instead + ** and jump to the end + */ + if (!bh_result->b_page || PageUptodate(bh_result->b_page)) { set_buffer_uptodate(bh_result); - goto finished ; - } - - // 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); - - /* 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 - */ - if (!p) { - p = (char *)kmap(bh_result->b_page) ; - if (fs_changed (fs_gen, inode->i_sb) && item_moved (&tmp_ih, &path)) { - goto research; - } - } - 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 ; - - p += 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; - - // update key to look for the next piece - set_cpu_key_k_offset (&key, cpu_key_k_offset (&key) + chars); - result = search_for_position_by_key (inode->i_sb, &key, &path); - if (result != POSITION_FOUND) - // i/o error most likely - break; - bh = get_last_bh (&path); - ih = get_ih (&path); - } while (1); - - flush_dcache_page(bh_result->b_page) ; - kunmap(bh_result->b_page) ; - -finished: - pathrelse (&path); - - if (result == IO_ERROR) - return -EIO; - - /* this buffer has valid data, but isn't valid for io. mapping it to - * block #0 tells the rest of reiserfs it just has a tail in it - */ - map_bh(bh_result, inode->i_sb, 0); - set_buffer_uptodate (bh_result); - return 0; -} + goto finished; + } + // 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); + + /* 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 + */ + if (!p) { + p = (char *)kmap(bh_result->b_page); + if (fs_changed(fs_gen, inode->i_sb) + && item_moved(&tmp_ih, &path)) { + goto research; + } + } + 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; + + p += 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; + + // update key to look for the next piece + set_cpu_key_k_offset(&key, cpu_key_k_offset(&key) + chars); + result = search_for_position_by_key(inode->i_sb, &key, &path); + if (result != POSITION_FOUND) + // i/o error most likely + break; + bh = get_last_bh(&path); + ih = get_ih(&path); + } while (1); + + flush_dcache_page(bh_result->b_page); + kunmap(bh_result->b_page); + + finished: + pathrelse(&path); + + if (result == IO_ERROR) + return -EIO; + /* this buffer has valid data, but isn't valid for io. mapping it to + * block #0 tells the rest of reiserfs it just has a tail in it + */ + map_bh(bh_result, inode->i_sb, 0); + set_buffer_uptodate(bh_result); + return 0; +} // this is called to create file map. So, _get_block_create_0 will not // read direct item -static int reiserfs_bmap (struct inode * inode, sector_t block, - struct buffer_head * bh_result, int create) +static int reiserfs_bmap(struct inode *inode, sector_t block, + struct buffer_head *bh_result, int create) { - if (!file_capable (inode, block)) - return -EFBIG; - - reiserfs_write_lock(inode->i_sb); - /* do not read the direct item */ - _get_block_create_0 (inode, block, bh_result, 0) ; - reiserfs_write_unlock(inode->i_sb); - return 0; + if (!file_capable(inode, block)) + return -EFBIG; + + reiserfs_write_lock(inode->i_sb); + /* do not read the direct item */ + _get_block_create_0(inode, block, bh_result, 0); + reiserfs_write_unlock(inode->i_sb); + return 0; } /* special version of get_block that is only used by grab_tail_page right @@ -444,9 +448,11 @@ static int reiserfs_bmap (struct inode * inode, sector_t block, ** don't want to send create == GET_BLOCK_NO_HOLE to reiserfs_get_block, ** don't use this function. */ -static int reiserfs_get_block_create_0 (struct inode * inode, sector_t block, - struct buffer_head * bh_result, int create) { - return reiserfs_get_block(inode, block, bh_result, GET_BLOCK_NO_HOLE) ; +static int reiserfs_get_block_create_0(struct inode *inode, sector_t block, + struct buffer_head *bh_result, + int create) +{ + return reiserfs_get_block(inode, block, bh_result, GET_BLOCK_NO_HOLE); } /* This is special helper for reiserfs_get_block in case we are executing @@ -457,43 +463,42 @@ static int reiserfs_get_blocks_direct_io(struct inode *inode, struct buffer_head *bh_result, int create) { - int ret ; - - bh_result->b_page = NULL; - - /* We set the b_size before reiserfs_get_block call since it is - referenced in convert_tail_for_hole() that may be called from - reiserfs_get_block() */ - bh_result->b_size = (1 << inode->i_blkbits); - - ret = reiserfs_get_block(inode, iblock, bh_result, - create | GET_BLOCK_NO_DANGLE) ; - if (ret) - goto out; - - /* don't allow direct io onto tail pages */ - if (buffer_mapped(bh_result) && bh_result->b_blocknr == 0) { - /* make sure future calls to the direct io funcs for this offset - ** in the file fail by unmapping the buffer - */ - clear_buffer_mapped(bh_result); - ret = -EINVAL ; - } - /* Possible unpacked tail. Flush the data before pages have - disappeared */ - if (REISERFS_I(inode)->i_flags & i_pack_on_close_mask) { - int err; - lock_kernel(); - err = reiserfs_commit_for_inode(inode); - REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask; - unlock_kernel(); - if (err < 0) - ret = err; - } -out: - return ret ; -} + int ret; + + bh_result->b_page = NULL; + /* We set the b_size before reiserfs_get_block call since it is + referenced in convert_tail_for_hole() that may be called from + reiserfs_get_block() */ + bh_result->b_size = (1 << inode->i_blkbits); + + ret = reiserfs_get_block(inode, iblock, bh_result, + create | GET_BLOCK_NO_DANGLE); + if (ret) + goto out; + + /* don't allow direct io onto tail pages */ + if (buffer_mapped(bh_result) && bh_result->b_blocknr == 0) { + /* make sure future calls to the direct io funcs for this offset + ** in the file fail by unmapping the buffer + */ + clear_buffer_mapped(bh_result); + ret = -EINVAL; + } + /* Possible unpacked tail. Flush the data before pages have + disappeared */ + if (REISERFS_I(inode)->i_flags & i_pack_on_close_mask) { + int err; + lock_kernel(); + err = reiserfs_commit_for_inode(inode); + REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask; + unlock_kernel(); + if (err < 0) + ret = err; + } + out: + return ret; +} /* ** helper function for when reiserfs_get_block is called for a hole @@ -505,490 +510,547 @@ out: ** you should not be in a transaction, or have any paths held when you ** call this. */ -static int convert_tail_for_hole(struct inode *inode, - struct buffer_head *bh_result, - loff_t tail_offset) { - unsigned long index ; - unsigned long tail_end ; - unsigned long tail_start ; - struct page * tail_page ; - struct page * hole_page = bh_result->b_page ; - int retval = 0 ; - - if ((tail_offset & (bh_result->b_size - 1)) != 1) - return -EIO ; - - /* always try to read until the end of the block */ - tail_start = tail_offset & (PAGE_CACHE_SIZE - 1) ; - tail_end = (tail_start | (bh_result->b_size - 1)) + 1 ; - - index = tail_offset >> PAGE_CACHE_SHIFT ; - /* hole_page can be zero in case of direct_io, we are sure - that we cannot get here if we write with O_DIRECT into - tail page */ - if (!hole_page || index != hole_page->index) { - tail_page = grab_cache_page(inode->i_mapping, index) ; - retval = -ENOMEM; - if (!tail_page) { - goto out ; - } - } else { - tail_page = hole_page ; - } - - /* we don't have to make sure the conversion did not happen while - ** we were locking the page because anyone that could convert - ** must first take i_sem. - ** - ** We must fix the tail page for writing because it might have buffers - ** that are mapped, but have a block number of 0. This indicates tail - ** data that has been read directly into the page, and block_prepare_write - ** won't trigger a get_block in this case. - */ - fix_tail_page_for_writing(tail_page) ; - retval = reiserfs_prepare_write(NULL, tail_page, tail_start, tail_end); - if (retval) - goto unlock ; - - /* tail conversion might change the data in the page */ - flush_dcache_page(tail_page) ; - - retval = reiserfs_commit_write(NULL, tail_page, tail_start, tail_end) ; - -unlock: - if (tail_page != hole_page) { - unlock_page(tail_page) ; - page_cache_release(tail_page) ; - } -out: - return retval ; +static int convert_tail_for_hole(struct inode *inode, + struct buffer_head *bh_result, + loff_t tail_offset) +{ + unsigned long index; + unsigned long tail_end; + unsigned long tail_start; + struct page *tail_page; + struct page *hole_page = bh_result->b_page; + int retval = 0; + + if ((tail_offset & (bh_result->b_size - 1)) != 1) + return -EIO; + + /* always try to read until the end of the block */ + tail_start = tail_offset & (PAGE_CACHE_SIZE - 1); + tail_end = (tail_start | (bh_result->b_size - 1)) + 1; + + index = tail_offset >> PAGE_CACHE_SHIFT; + /* hole_page can be zero in case of direct_io, we are sure + that we cannot get here if we write with O_DIRECT into + tail page */ + if (!hole_page || index != hole_page->index) { + tail_page = grab_cache_page(inode->i_mapping, index); + retval = -ENOMEM; + if (!tail_page) { + goto out; + } + } else { + tail_page = hole_page; + } + + /* we don't have to make sure the conversion did not happen while + ** we were locking the page because anyone that could convert + ** must first take i_sem. + ** + ** We must fix the tail page for writing because it might have buffers + ** that are mapped, but have a block number of 0. This indicates tail + ** data that has been read directly into the page, and block_prepare_write + ** won't trigger a get_block in this case. + */ + fix_tail_page_for_writing(tail_page); + retval = reiserfs_prepare_write(NULL, tail_page, tail_start, tail_end); + if (retval) + goto unlock; + + /* tail conversion might change the data in the page */ + flush_dcache_page(tail_page); + + retval = reiserfs_commit_write(NULL, tail_page, tail_start, tail_end); + + unlock: + if (tail_page != hole_page) { + unlock_page(tail_page); + page_cache_release(tail_page); + } + out: + return retval; } static inline int _allocate_block(struct reiserfs_transaction_handle *th, - long block, - struct inode *inode, - b_blocknr_t *allocated_block_nr, - struct path * path, - int flags) { - BUG_ON (!th->t_trans_id); - + long block, + struct inode *inode, + b_blocknr_t * allocated_block_nr, + struct path *path, int flags) +{ + BUG_ON(!th->t_trans_id); + #ifdef REISERFS_PREALLOCATE - if (!(flags & GET_BLOCK_NO_ISEM)) { - return reiserfs_new_unf_blocknrs2(th, inode, allocated_block_nr, path, block); - } + if (!(flags & GET_BLOCK_NO_ISEM)) { + return reiserfs_new_unf_blocknrs2(th, inode, allocated_block_nr, + path, block); + } #endif - return reiserfs_new_unf_blocknrs (th, inode, allocated_block_nr, path, block); + return reiserfs_new_unf_blocknrs(th, inode, allocated_block_nr, path, + block); } -int reiserfs_get_block (struct inode * inode, sector_t block, - struct buffer_head * bh_result, int create) +int reiserfs_get_block(struct inode *inode, sector_t block, + struct buffer_head *bh_result, int create) { - int repeat, retval = 0; - b_blocknr_t allocated_block_nr = 0;// b_blocknr_t is (unsigned) 32 bit int - INITIALIZE_PATH(path); - int pos_in_item; - struct cpu_key key; - struct buffer_head * bh, * unbh = NULL; - struct item_head * ih, tmp_ih; - __le32 * item; - int done; - int fs_gen; - struct reiserfs_transaction_handle *th = NULL; - /* space reserved in transaction batch: - . 3 balancings in direct->indirect conversion - . 1 block involved into reiserfs_update_sd() - XXX in practically impossible worst case direct2indirect() - can incur (much) more than 3 balancings. - quota update for user, group */ - int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 1 + 2 * REISERFS_QUOTA_TRANS_BLOCKS(inode->i_sb); - int version; - int dangle = 1; - loff_t new_offset = (((loff_t)block) << inode->i_sb->s_blocksize_bits) + 1 ; - - /* bad.... */ - reiserfs_write_lock(inode->i_sb); - version = get_inode_item_key_version (inode); - - if (block < 0) { - reiserfs_write_unlock(inode->i_sb); - return -EIO; - } + int repeat, retval = 0; + b_blocknr_t allocated_block_nr = 0; // b_blocknr_t is (unsigned) 32 bit int + INITIALIZE_PATH(path); + int pos_in_item; + struct cpu_key key; + struct buffer_head *bh, *unbh = NULL; + struct item_head *ih, tmp_ih; + __le32 *item; + int done; + int fs_gen; + struct reiserfs_transaction_handle *th = NULL; + /* space reserved in transaction batch: + . 3 balancings in direct->indirect conversion + . 1 block involved into reiserfs_update_sd() + XXX in practically impossible worst case direct2indirect() + can incur (much) more than 3 balancings. + quota update for user, group */ + int jbegin_count = + JOURNAL_PER_BALANCE_CNT * 3 + 1 + + 2 * REISERFS_QUOTA_TRANS_BLOCKS(inode->i_sb); + int version; + int dangle = 1; + loff_t new_offset = + (((loff_t) block) << inode->i_sb->s_blocksize_bits) + 1; + + /* bad.... */ + reiserfs_write_lock(inode->i_sb); + version = get_inode_item_key_version(inode); - if (!file_capable (inode, block)) { - reiserfs_write_unlock(inode->i_sb); - return -EFBIG; - } - - /* if !create, we aren't changing the FS, so we don't need to - ** log anything, so we don't need to start a transaction - */ - if (!(create & GET_BLOCK_CREATE)) { - int ret ; - /* find number of block-th logical block of the file */ - ret = _get_block_create_0 (inode, block, bh_result, - create | GET_BLOCK_READ_DIRECT) ; - reiserfs_write_unlock(inode->i_sb); - return ret; - } - /* - * if we're already in a transaction, make sure to close - * any new transactions we start in this func - */ - if ((create & GET_BLOCK_NO_DANGLE) || - reiserfs_transaction_running(inode->i_sb)) - dangle = 0; - - /* If file is of such a size, that it might have a tail and tails are enabled - ** we should mark it as possibly needing tail packing on close - */ - if ( (have_large_tails (inode->i_sb) && inode->i_size < i_block_size (inode)*4) || - (have_small_tails (inode->i_sb) && inode->i_size < i_block_size(inode)) ) - REISERFS_I(inode)->i_flags |= i_pack_on_close_mask ; - - /* set the key of the first byte in the 'block'-th block of file */ - make_cpu_key (&key, inode, new_offset, - TYPE_ANY, 3/*key length*/); - if ((new_offset + inode->i_sb->s_blocksize - 1) > inode->i_size) { -start_trans: - th = reiserfs_persistent_transaction(inode->i_sb, jbegin_count); - if (!th) { - retval = -ENOMEM; - goto failure; - } - reiserfs_update_inode_transaction(inode) ; - } - research: - - retval = search_for_position_by_key (inode->i_sb, &key, &path); - if (retval == IO_ERROR) { - retval = -EIO; - goto failure; - } - - bh = get_last_bh (&path); - ih = get_ih (&path); - item = get_item (&path); - pos_in_item = path.pos_in_item; - - fs_gen = get_generation (inode->i_sb); - copy_item_head (&tmp_ih, ih); - - if (allocation_needed (retval, allocated_block_nr, ih, item, pos_in_item)) { - /* we have to allocate block for the unformatted node */ - if (!th) { - pathrelse(&path) ; - goto start_trans; - } - - repeat = _allocate_block(th, block, inode, &allocated_block_nr, &path, create); - - if (repeat == NO_DISK_SPACE || repeat == QUOTA_EXCEEDED) { - /* restart the transaction to give the journal a chance to free - ** some blocks. releases the path, so we have to go back to - ** research if we succeed on the second try - */ - SB_JOURNAL(inode->i_sb)->j_next_async_flush = 1; - retval = restart_transaction(th, inode, &path) ; - if (retval) - goto failure; - repeat = _allocate_block(th, block, inode, &allocated_block_nr, NULL, create); - - if (repeat != NO_DISK_SPACE && repeat != QUOTA_EXCEEDED) { - goto research ; - } - if (repeat == QUOTA_EXCEEDED) - retval = -EDQUOT; - else - retval = -ENOSPC; - goto failure; - } - - if (fs_changed (fs_gen, inode->i_sb) && item_moved (&tmp_ih, &path)) { - goto research; - } - } - - if (indirect_item_found (retval, ih)) { - b_blocknr_t unfm_ptr; - /* 'block'-th block is in the file already (there is - corresponding cell in some indirect item). But it may be - zero unformatted node pointer (hole) */ - unfm_ptr = get_block_num (item, pos_in_item); - if (unfm_ptr == 0) { - /* use allocated block to plug the hole */ - reiserfs_prepare_for_journal(inode->i_sb, bh, 1) ; - if (fs_changed (fs_gen, inode->i_sb) && item_moved (&tmp_ih, &path)) { - reiserfs_restore_prepared_buffer(inode->i_sb, bh) ; - goto research; - } - set_buffer_new(bh_result); - if (buffer_dirty(bh_result) && reiserfs_data_ordered(inode->i_sb)) - reiserfs_add_ordered_list(inode, bh_result); - put_block_num(item, pos_in_item, allocated_block_nr) ; - unfm_ptr = allocated_block_nr; - journal_mark_dirty (th, inode->i_sb, bh); - reiserfs_update_sd(th, inode) ; - } - set_block_dev_mapped(bh_result, unfm_ptr, inode); - pathrelse (&path); - retval = 0; - if (!dangle && th) - retval = reiserfs_end_persistent_transaction(th); + if (block < 0) { + reiserfs_write_unlock(inode->i_sb); + return -EIO; + } - reiserfs_write_unlock(inode->i_sb); - - /* the item was found, so new blocks were not added to the file - ** there is no need to make sure the inode is updated with this - ** transaction - */ - return retval; - } - - if (!th) { - pathrelse(&path) ; - goto start_trans; - } - - /* desired position is not found or is in the direct item. We have - to append file with holes up to 'block'-th block converting - direct items to indirect one if necessary */ - done = 0; - do { - if (is_statdata_le_ih (ih)) { - __le32 unp = 0; - struct cpu_key tmp_key; - - /* indirect item has to be inserted */ - make_le_item_head (&tmp_ih, &key, version, 1, TYPE_INDIRECT, - UNFM_P_SIZE, 0/* free_space */); - - if (cpu_key_k_offset (&key) == 1) { - /* we are going to add 'block'-th block to the file. Use - allocated block for that */ - unp = cpu_to_le32 (allocated_block_nr); - set_block_dev_mapped (bh_result, allocated_block_nr, inode); - set_buffer_new(bh_result); - done = 1; - } - tmp_key = key; // ;) - set_cpu_key_k_offset (&tmp_key, 1); - PATH_LAST_POSITION(&path) ++; - - retval = reiserfs_insert_item (th, &path, &tmp_key, &tmp_ih, inode, (char *)&unp); - if (retval) { - reiserfs_free_block (th, inode, allocated_block_nr, 1); - goto failure; // retval == -ENOSPC, -EDQUOT or -EIO or -EEXIST - } - //mark_tail_converted (inode); - } else if (is_direct_le_ih (ih)) { - /* direct item has to be converted */ - loff_t tail_offset; - - tail_offset = ((le_ih_k_offset (ih) - 1) & ~(inode->i_sb->s_blocksize - 1)) + 1; - if (tail_offset == cpu_key_k_offset (&key)) { - /* direct item we just found fits into block we have - to map. Convert it into unformatted node: use - bh_result for the conversion */ - set_block_dev_mapped (bh_result, allocated_block_nr, inode); - unbh = bh_result; - done = 1; - } else { - /* we have to padd file tail stored in direct item(s) - up to block size and convert it to unformatted - node. FIXME: this should also get into page cache */ - - pathrelse(&path) ; - /* - * ugly, but we can only end the transaction if - * we aren't nested - */ - BUG_ON (!th->t_refcount); - if (th->t_refcount == 1) { - retval = reiserfs_end_persistent_transaction(th); - th = NULL; - if (retval) + if (!file_capable(inode, block)) { + reiserfs_write_unlock(inode->i_sb); + return -EFBIG; + } + + /* if !create, we aren't changing the FS, so we don't need to + ** log anything, so we don't need to start a transaction + */ + if (!(create & GET_BLOCK_CREATE)) { + int ret; + /* find number of block-th logical block of the file */ + ret = _get_block_create_0(inode, block, bh_result, + create | GET_BLOCK_READ_DIRECT); + reiserfs_write_unlock(inode->i_sb); + return ret; + } + /* + * if we're already in a transaction, make sure to close + * any new transactions we start in this func + */ + if ((create & GET_BLOCK_NO_DANGLE) || + reiserfs_transaction_running(inode->i_sb)) + dangle = 0; + + /* If file is of such a size, that it might have a tail and tails are enabled + ** we should mark it as possibly needing tail packing on close + */ + if ((have_large_tails(inode->i_sb) + && inode->i_size < i_block_size(inode) * 4) + || (have_small_tails(inode->i_sb) + && inode->i_size < i_block_size(inode))) + REISERFS_I(inode)->i_flags |= i_pack_on_close_mask; + + /* set the key of the first byte in the 'block'-th block of file */ + make_cpu_key(&key, inode, new_offset, TYPE_ANY, 3 /*key length */ ); + if ((new_offset + inode->i_sb->s_blocksize - 1) > inode->i_size) { + start_trans: + th = reiserfs_persistent_transaction(inode->i_sb, jbegin_count); + if (!th) { + retval = -ENOMEM; goto failure; } + reiserfs_update_inode_transaction(inode); + } + research: - retval = convert_tail_for_hole(inode, bh_result, tail_offset) ; - if (retval) { - if ( retval != -ENOSPC ) - reiserfs_warning (inode->i_sb, "clm-6004: convert tail failed inode %lu, error %d", inode->i_ino, retval) ; - if (allocated_block_nr) { - /* the bitmap, the super, and the stat data == 3 */ - if (!th) - th = reiserfs_persistent_transaction(inode->i_sb,3); - if (th) - reiserfs_free_block (th,inode,allocated_block_nr,1); - } - goto failure ; - } - goto research ; - } - retval = direct2indirect (th, inode, &path, unbh, tail_offset); - if (retval) { - reiserfs_unmap_buffer(unbh); - reiserfs_free_block (th, inode, allocated_block_nr, 1); - goto failure; - } - /* it is important the set_buffer_uptodate is done after - ** the direct2indirect. The buffer might contain valid - ** data newer than the data on disk (read by readpage, changed, - ** and then sent here by writepage). direct2indirect needs - ** to know if unbh was already up to date, so it can decide - ** if the data in unbh needs to be replaced with data from - ** the disk - */ - set_buffer_uptodate (unbh); - - /* unbh->b_page == NULL in case of DIRECT_IO request, this means - buffer will disappear shortly, so it should not be added to - */ - if ( unbh->b_page ) { - /* we've converted the tail, so we must - ** flush unbh before the transaction commits - */ - reiserfs_add_tail_list(inode, unbh) ; - - /* mark it dirty now to prevent commit_write from adding - ** this buffer to the inode's dirty buffer list - */ - /* - * AKPM: changed __mark_buffer_dirty to mark_buffer_dirty(). - * It's still atomic, but it sets the page dirty too, - * which makes it eligible for writeback at any time by the - * VM (which was also the case with __mark_buffer_dirty()) - */ - mark_buffer_dirty(unbh) ; - } - } else { - /* append indirect item with holes if needed, when appending - pointer to 'block'-th block use block, which is already - allocated */ - struct cpu_key tmp_key; - unp_t unf_single=0; // We use this in case we need to allocate only - // one block which is a fastpath - unp_t *un; - __u64 max_to_insert=MAX_ITEM_LEN(inode->i_sb->s_blocksize)/UNFM_P_SIZE; - __u64 blocks_needed; - - RFALSE( pos_in_item != ih_item_len(ih) / UNFM_P_SIZE, - "vs-804: invalid position for append"); - /* indirect item has to be appended, set up key of that position */ - make_cpu_key (&tmp_key, inode, - le_key_k_offset (version, &(ih->ih_key)) + op_bytes_number (ih, inode->i_sb->s_blocksize), - //pos_in_item * inode->i_sb->s_blocksize, - TYPE_INDIRECT, 3);// key type is unimportant - - blocks_needed = 1 + ((cpu_key_k_offset (&key) - cpu_key_k_offset (&tmp_key)) >> inode->i_sb->s_blocksize_bits); - RFALSE( blocks_needed < 0, "green-805: invalid offset"); - - if ( blocks_needed == 1 ) { - un = &unf_single; - } else { - un=kmalloc( min(blocks_needed,max_to_insert)*UNFM_P_SIZE, - GFP_ATOMIC); // We need to avoid scheduling. - if ( !un) { - un = &unf_single; - blocks_needed = 1; - max_to_insert = 0; - } else - memset(un, 0, UNFM_P_SIZE * min(blocks_needed,max_to_insert)); - } - if ( blocks_needed <= max_to_insert) { - /* we are going to add target block to the file. Use allocated - block for that */ - un[blocks_needed-1] = cpu_to_le32 (allocated_block_nr); - set_block_dev_mapped (bh_result, allocated_block_nr, inode); - set_buffer_new(bh_result); - done = 1; - } else { - /* paste hole to the indirect item */ - /* If kmalloc failed, max_to_insert becomes zero and it means we - only have space for one block */ - blocks_needed=max_to_insert?max_to_insert:1; - } - retval = reiserfs_paste_into_item (th, &path, &tmp_key, inode, (char *)un, UNFM_P_SIZE * blocks_needed); - - if (blocks_needed != 1) - kfree(un); - - if (retval) { - reiserfs_free_block (th, inode, allocated_block_nr, 1); - goto failure; - } - if (!done) { - /* We need to mark new file size in case this function will be - interrupted/aborted later on. And we may do this only for - holes. */ - inode->i_size += inode->i_sb->s_blocksize * blocks_needed; - } - } - - if (done == 1) - break; - - /* this loop could log more blocks than we had originally asked - ** for. So, we have to allow the transaction to end if it is - ** too big or too full. Update the inode so things are - ** consistent if we crash before the function returns - ** - ** release the path so that anybody waiting on the path before - ** ending their transaction will be able to continue. - */ - if (journal_transaction_should_end(th, th->t_blocks_allocated)) { - retval = restart_transaction(th, inode, &path) ; - if (retval) - goto failure; - } - /* inserting indirect pointers for a hole can take a - ** long time. reschedule if needed - */ - cond_resched(); - - retval = search_for_position_by_key (inode->i_sb, &key, &path); + retval = search_for_position_by_key(inode->i_sb, &key, &path); if (retval == IO_ERROR) { - retval = -EIO; - goto failure; - } - if (retval == POSITION_FOUND) { - reiserfs_warning (inode->i_sb, "vs-825: reiserfs_get_block: " - "%K should not be found", &key); - retval = -EEXIST; - if (allocated_block_nr) - reiserfs_free_block (th, inode, allocated_block_nr, 1); - pathrelse(&path) ; - goto failure; - } - bh = get_last_bh (&path); - ih = get_ih (&path); - item = get_item (&path); + retval = -EIO; + goto failure; + } + + bh = get_last_bh(&path); + ih = get_ih(&path); + item = get_item(&path); pos_in_item = path.pos_in_item; - } while (1); + fs_gen = get_generation(inode->i_sb); + copy_item_head(&tmp_ih, ih); + + if (allocation_needed + (retval, allocated_block_nr, ih, item, pos_in_item)) { + /* we have to allocate block for the unformatted node */ + if (!th) { + pathrelse(&path); + goto start_trans; + } + + repeat = + _allocate_block(th, block, inode, &allocated_block_nr, + &path, create); + + if (repeat == NO_DISK_SPACE || repeat == QUOTA_EXCEEDED) { + /* restart the transaction to give the journal a chance to free + ** some blocks. releases the path, so we have to go back to + ** research if we succeed on the second try + */ + SB_JOURNAL(inode->i_sb)->j_next_async_flush = 1; + retval = restart_transaction(th, inode, &path); + if (retval) + goto failure; + repeat = + _allocate_block(th, block, inode, + &allocated_block_nr, NULL, create); + + if (repeat != NO_DISK_SPACE && repeat != QUOTA_EXCEEDED) { + goto research; + } + if (repeat == QUOTA_EXCEEDED) + retval = -EDQUOT; + else + retval = -ENOSPC; + goto failure; + } + + if (fs_changed(fs_gen, inode->i_sb) + && item_moved(&tmp_ih, &path)) { + goto research; + } + } + + if (indirect_item_found(retval, ih)) { + b_blocknr_t unfm_ptr; + /* 'block'-th block is in the file already (there is + corresponding cell in some indirect item). But it may be + zero unformatted node pointer (hole) */ + unfm_ptr = get_block_num(item, pos_in_item); + if (unfm_ptr == 0) { + /* use allocated block to plug the hole */ + reiserfs_prepare_for_journal(inode->i_sb, bh, 1); + if (fs_changed(fs_gen, inode->i_sb) + && item_moved(&tmp_ih, &path)) { + reiserfs_restore_prepared_buffer(inode->i_sb, + bh); + goto research; + } + set_buffer_new(bh_result); + if (buffer_dirty(bh_result) + && reiserfs_data_ordered(inode->i_sb)) + reiserfs_add_ordered_list(inode, bh_result); + put_block_num(item, pos_in_item, allocated_block_nr); + unfm_ptr = allocated_block_nr; + journal_mark_dirty(th, inode->i_sb, bh); + reiserfs_update_sd(th, inode); + } + set_block_dev_mapped(bh_result, unfm_ptr, inode); + pathrelse(&path); + retval = 0; + if (!dangle && th) + retval = reiserfs_end_persistent_transaction(th); + + reiserfs_write_unlock(inode->i_sb); + + /* the item was found, so new blocks were not added to the file + ** there is no need to make sure the inode is updated with this + ** transaction + */ + return retval; + } + + if (!th) { + pathrelse(&path); + goto start_trans; + } + + /* desired position is not found or is in the direct item. We have + to append file with holes up to 'block'-th block converting + direct items to indirect one if necessary */ + done = 0; + do { + if (is_statdata_le_ih(ih)) { + __le32 unp = 0; + struct cpu_key tmp_key; + + /* indirect item has to be inserted */ + make_le_item_head(&tmp_ih, &key, version, 1, + TYPE_INDIRECT, UNFM_P_SIZE, + 0 /* free_space */ ); + + if (cpu_key_k_offset(&key) == 1) { + /* we are going to add 'block'-th block to the file. Use + allocated block for that */ + unp = cpu_to_le32(allocated_block_nr); + set_block_dev_mapped(bh_result, + allocated_block_nr, inode); + set_buffer_new(bh_result); + done = 1; + } + tmp_key = key; // ;) + set_cpu_key_k_offset(&tmp_key, 1); + PATH_LAST_POSITION(&path)++; + + retval = + reiserfs_insert_item(th, &path, &tmp_key, &tmp_ih, + inode, (char *)&unp); + if (retval) { + reiserfs_free_block(th, inode, + allocated_block_nr, 1); + goto failure; // retval == -ENOSPC, -EDQUOT or -EIO or -EEXIST + } + //mark_tail_converted (inode); + } else if (is_direct_le_ih(ih)) { + /* direct item has to be converted */ + loff_t tail_offset; + + tail_offset = + ((le_ih_k_offset(ih) - + 1) & ~(inode->i_sb->s_blocksize - 1)) + 1; + if (tail_offset == cpu_key_k_offset(&key)) { + /* direct item we just found fits into block we have + to map. Convert it into unformatted node: use + bh_result for the conversion */ + set_block_dev_mapped(bh_result, + allocated_block_nr, inode); + unbh = bh_result; + done = 1; + } else { + /* we have to padd file tail stored in direct item(s) + up to block size and convert it to unformatted + node. FIXME: this should also get into page cache */ + + pathrelse(&path); + /* + * ugly, but we can only end the transaction if + * we aren't nested + */ + BUG_ON(!th->t_refcount); + if (th->t_refcount == 1) { + retval = + reiserfs_end_persistent_transaction + (th); + th = NULL; + if (retval) + goto failure; + } + + retval = + convert_tail_for_hole(inode, bh_result, + tail_offset); + if (retval) { + if (retval != -ENOSPC) + reiserfs_warning(inode->i_sb, + "clm-6004: convert tail failed inode %lu, error %d", + inode->i_ino, + retval); + if (allocated_block_nr) { + /* the bitmap, the super, and the stat data == 3 */ + if (!th) + th = reiserfs_persistent_transaction(inode->i_sb, 3); + if (th) + reiserfs_free_block(th, + inode, + allocated_block_nr, + 1); + } + goto failure; + } + goto research; + } + retval = + direct2indirect(th, inode, &path, unbh, + tail_offset); + if (retval) { + reiserfs_unmap_buffer(unbh); + reiserfs_free_block(th, inode, + allocated_block_nr, 1); + goto failure; + } + /* it is important the set_buffer_uptodate is done after + ** the direct2indirect. The buffer might contain valid + ** data newer than the data on disk (read by readpage, changed, + ** and then sent here by writepage). direct2indirect needs + ** to know if unbh was already up to date, so it can decide + ** if the data in unbh needs to be replaced with data from + ** the disk + */ + set_buffer_uptodate(unbh); + + /* unbh->b_page == NULL in case of DIRECT_IO request, this means + buffer will disappear shortly, so it should not be added to + */ + if (unbh->b_page) { + /* we've converted the tail, so we must + ** flush unbh before the transaction commits + */ + reiserfs_add_tail_list(inode, unbh); + + /* mark it dirty now to prevent commit_write from adding + ** this buffer to the inode's dirty buffer list + */ + /* + * AKPM: changed __mark_buffer_dirty to mark_buffer_dirty(). + * It's still atomic, but it sets the page dirty too, + * which makes it eligible for writeback at any time by the + * VM (which was also the case with __mark_buffer_dirty()) + */ + mark_buffer_dirty(unbh); + } + } else { + /* append indirect item with holes if needed, when appending + pointer to 'block'-th block use block, which is already + allocated */ + struct cpu_key tmp_key; + unp_t unf_single = 0; // We use this in case we need to allocate only + // one block which is a fastpath + unp_t *un; + __u64 max_to_insert = + MAX_ITEM_LEN(inode->i_sb->s_blocksize) / + UNFM_P_SIZE; + __u64 blocks_needed; + + RFALSE(pos_in_item != ih_item_len(ih) / UNFM_P_SIZE, + "vs-804: invalid position for append"); + /* indirect item has to be appended, set up key of that position */ + make_cpu_key(&tmp_key, inode, + le_key_k_offset(version, + &(ih->ih_key)) + + op_bytes_number(ih, + inode->i_sb->s_blocksize), + //pos_in_item * inode->i_sb->s_blocksize, + TYPE_INDIRECT, 3); // key type is unimportant + + blocks_needed = + 1 + + ((cpu_key_k_offset(&key) - + cpu_key_k_offset(&tmp_key)) >> inode->i_sb-> + s_blocksize_bits); + RFALSE(blocks_needed < 0, "green-805: invalid offset"); + + if (blocks_needed == 1) { + un = &unf_single; + } else { + un = kmalloc(min(blocks_needed, max_to_insert) * UNFM_P_SIZE, GFP_ATOMIC); // We need to avoid scheduling. + if (!un) { + un = &unf_single; + blocks_needed = 1; + max_to_insert = 0; + } else + memset(un, 0, + UNFM_P_SIZE * min(blocks_needed, + max_to_insert)); + } + if (blocks_needed <= max_to_insert) { + /* we are going to add target block to the file. Use allocated + block for that */ + un[blocks_needed - 1] = + cpu_to_le32(allocated_block_nr); + set_block_dev_mapped(bh_result, + allocated_block_nr, inode); + set_buffer_new(bh_result); + done = 1; + } else { + /* paste hole to the indirect item */ + /* If kmalloc failed, max_to_insert becomes zero and it means we + only have space for one block */ + blocks_needed = + max_to_insert ? max_to_insert : 1; + } + retval = + reiserfs_paste_into_item(th, &path, &tmp_key, inode, + (char *)un, + UNFM_P_SIZE * + blocks_needed); + + if (blocks_needed != 1) + kfree(un); + + if (retval) { + reiserfs_free_block(th, inode, + allocated_block_nr, 1); + goto failure; + } + if (!done) { + /* We need to mark new file size in case this function will be + interrupted/aborted later on. And we may do this only for + holes. */ + inode->i_size += + inode->i_sb->s_blocksize * blocks_needed; + } + } - retval = 0; + if (done == 1) + break; - failure: - if (th && (!dangle || (retval && !th->t_trans_id))) { - int err; - if (th->t_trans_id) - reiserfs_update_sd(th, inode); - err = reiserfs_end_persistent_transaction(th); - if (err) - retval = err; - } + /* this loop could log more blocks than we had originally asked + ** for. So, we have to allow the transaction to end if it is + ** too big or too full. Update the inode so things are + ** consistent if we crash before the function returns + ** + ** release the path so that anybody waiting on the path before + ** ending their transaction will be able to continue. + */ + if (journal_transaction_should_end(th, th->t_blocks_allocated)) { + retval = restart_transaction(th, inode, &path); + if (retval) + goto failure; + } + /* inserting indirect pointers for a hole can take a + ** long time. reschedule if needed + */ + cond_resched(); - reiserfs_write_unlock(inode->i_sb); - reiserfs_check_path(&path) ; - return retval; + retval = search_for_position_by_key(inode->i_sb, &key, &path); + if (retval == IO_ERROR) { + retval = -EIO; + goto failure; + } + if (retval == POSITION_FOUND) { + reiserfs_warning(inode->i_sb, + "vs-825: reiserfs_get_block: " + "%K should not be found", &key); + retval = -EEXIST; + if (allocated_block_nr) + reiserfs_free_block(th, inode, + allocated_block_nr, 1); + pathrelse(&path); + goto failure; + } + bh = get_last_bh(&path); + ih = get_ih(&path); + item = get_item(&path); + pos_in_item = path.pos_in_item; + } while (1); + + retval = 0; + + failure: + if (th && (!dangle || (retval && !th->t_trans_id))) { + int err; + if (th->t_trans_id) + reiserfs_update_sd(th, inode); + err = reiserfs_end_persistent_transaction(th); + if (err) + retval = err; + } + + reiserfs_write_unlock(inode->i_sb); + reiserfs_check_path(&path); + return retval; } static int reiserfs_readpages(struct file *file, struct address_space *mapping, - struct list_head *pages, unsigned nr_pages) + struct list_head *pages, unsigned nr_pages) { - return mpage_readpages(mapping, pages, nr_pages, reiserfs_get_block); + return mpage_readpages(mapping, pages, nr_pages, reiserfs_get_block); } /* Compute real number of used bytes by file @@ -996,51 +1058,56 @@ reiserfs_readpages(struct file *file, struct address_space *mapping, */ static int real_space_diff(struct inode *inode, int sd_size) { - int bytes; - loff_t blocksize = inode->i_sb->s_blocksize ; - - if (S_ISLNK(inode->i_mode) || S_ISDIR(inode->i_mode)) - return sd_size ; - - /* End of file is also in full block with indirect reference, so round - ** up to the next block. - ** - ** there is just no way to know if the tail is actually packed - ** on the file, so we have to assume it isn't. When we pack the - ** tail, we add 4 bytes to pretend there really is an unformatted - ** node pointer - */ - bytes = ((inode->i_size + (blocksize-1)) >> inode->i_sb->s_blocksize_bits) * UNFM_P_SIZE + sd_size; - return bytes ; + int bytes; + loff_t blocksize = inode->i_sb->s_blocksize; + + if (S_ISLNK(inode->i_mode) || S_ISDIR(inode->i_mode)) + return sd_size; + + /* End of file is also in full block with indirect reference, so round + ** up to the next block. + ** + ** there is just no way to know if the tail is actually packed + ** on the file, so we have to assume it isn't. When we pack the + ** tail, we add 4 bytes to pretend there really is an unformatted + ** node pointer + */ + bytes = + ((inode->i_size + + (blocksize - 1)) >> inode->i_sb->s_blocksize_bits) * UNFM_P_SIZE + + sd_size; + return bytes; } static inline loff_t to_real_used_space(struct inode *inode, ulong blocks, - int sd_size) + int sd_size) { - if (S_ISLNK(inode->i_mode) || S_ISDIR(inode->i_mode)) { - return inode->i_size + (loff_t)(real_space_diff(inode, sd_size)) ; - } - return ((loff_t)real_space_diff(inode, sd_size)) + (((loff_t)blocks) << 9); + if (S_ISLNK(inode->i_mode) || S_ISDIR(inode->i_mode)) { + return inode->i_size + + (loff_t) (real_space_diff(inode, sd_size)); + } + return ((loff_t) real_space_diff(inode, sd_size)) + + (((loff_t) blocks) << 9); } /* Compute number of blocks used by file in ReiserFS counting */ static inline ulong to_fake_used_blocks(struct inode *inode, int sd_size) { - loff_t bytes = inode_get_bytes(inode) ; - loff_t real_space = real_space_diff(inode, sd_size) ; - - /* keeps fsck and non-quota versions of reiserfs happy */ - if (S_ISLNK(inode->i_mode) || S_ISDIR(inode->i_mode)) { - bytes += (loff_t)511 ; - } - - /* files from before the quota patch might i_blocks such that - ** bytes < real_space. Deal with that here to prevent it from - ** going negative. - */ - if (bytes < real_space) - return 0 ; - return (bytes - real_space) >> 9; + loff_t bytes = inode_get_bytes(inode); + loff_t real_space = real_space_diff(inode, sd_size); + + /* keeps fsck and non-quota versions of reiserfs happy */ + if (S_ISLNK(inode->i_mode) || S_ISDIR(inode->i_mode)) { + bytes += (loff_t) 511; + } + + /* files from before the quota patch might i_blocks such that + ** bytes < real_space. Deal with that here to prevent it from + ** going negative. + */ + if (bytes < real_space) + return 0; + return (bytes - real_space) >> 9; } // @@ -1051,263 +1118,269 @@ static inline ulong to_fake_used_blocks(struct inode *inode, int sd_size) // // called by read_locked_inode -static void init_inode (struct inode * inode, struct path * path) +static void init_inode(struct inode *inode, struct path *path) { - struct buffer_head * bh; - struct item_head * ih; - __u32 rdev; - //int version = ITEM_VERSION_1; - - bh = PATH_PLAST_BUFFER (path); - ih = PATH_PITEM_HEAD (path); - - - copy_key (INODE_PKEY (inode), &(ih->ih_key)); - inode->i_blksize = reiserfs_default_io_size; - - INIT_LIST_HEAD(&(REISERFS_I(inode)->i_prealloc_list )); - REISERFS_I(inode)->i_flags = 0; - REISERFS_I(inode)->i_prealloc_block = 0; - REISERFS_I(inode)->i_prealloc_count = 0; - REISERFS_I(inode)->i_trans_id = 0; - REISERFS_I(inode)->i_jl = NULL; - REISERFS_I(inode)->i_acl_access = NULL; - REISERFS_I(inode)->i_acl_default = NULL; - init_rwsem (&REISERFS_I(inode)->xattr_sem); - - if (stat_data_v1 (ih)) { - struct stat_data_v1 * sd = (struct stat_data_v1 *)B_I_PITEM (bh, ih); - unsigned long blocks; - - set_inode_item_key_version (inode, KEY_FORMAT_3_5); - set_inode_sd_version (inode, STAT_DATA_V1); - inode->i_mode = sd_v1_mode(sd); - inode->i_nlink = sd_v1_nlink(sd); - inode->i_uid = sd_v1_uid(sd); - inode->i_gid = sd_v1_gid(sd); - inode->i_size = sd_v1_size(sd); - inode->i_atime.tv_sec = sd_v1_atime(sd); - inode->i_mtime.tv_sec = sd_v1_mtime(sd); - inode->i_ctime.tv_sec = sd_v1_ctime(sd); - inode->i_atime.tv_nsec = 0; - inode->i_ctime.tv_nsec = 0; - inode->i_mtime.tv_nsec = 0; - - inode->i_blocks = sd_v1_blocks(sd); - inode->i_generation = le32_to_cpu (INODE_PKEY (inode)->k_dir_id); - blocks = (inode->i_size + 511) >> 9; - blocks = _ROUND_UP (blocks, inode->i_sb->s_blocksize >> 9); - if (inode->i_blocks > blocks) { - // there was a bug in <=3.5.23 when i_blocks could take negative - // values. Starting from 3.5.17 this value could even be stored in - // stat data. For such files we set i_blocks based on file - // size. Just 2 notes: this can be wrong for sparce files. On-disk value will be - // only updated if file's inode will ever change - inode->i_blocks = blocks; - } - - rdev = sd_v1_rdev(sd); - REISERFS_I(inode)->i_first_direct_byte = sd_v1_first_direct_byte(sd); - /* an early bug in the quota code can give us an odd number for the - ** block count. This is incorrect, fix it here. - */ - if (inode->i_blocks & 1) { - inode->i_blocks++ ; - } - inode_set_bytes(inode, to_real_used_space(inode, inode->i_blocks, - SD_V1_SIZE)); - /* nopack is initially zero for v1 objects. For v2 objects, - nopack is initialised from sd_attrs */ - REISERFS_I(inode)->i_flags &= ~i_nopack_mask; - } else { - // new stat data found, but object may have old items - // (directories and symlinks) - struct stat_data * sd = (struct stat_data *)B_I_PITEM (bh, ih); - - inode->i_mode = sd_v2_mode(sd); - inode->i_nlink = sd_v2_nlink(sd); - inode->i_uid = sd_v2_uid(sd); - inode->i_size = sd_v2_size(sd); - inode->i_gid = sd_v2_gid(sd); - inode->i_mtime.tv_sec = sd_v2_mtime(sd); - inode->i_atime.tv_sec = sd_v2_atime(sd); - inode->i_ctime.tv_sec = sd_v2_ctime(sd); - inode->i_ctime.tv_nsec = 0; - inode->i_mtime.tv_nsec = 0; - inode->i_atime.tv_nsec = 0; - inode->i_blocks = sd_v2_blocks(sd); - rdev = sd_v2_rdev(sd); - if( S_ISCHR( inode -> i_mode ) || S_ISBLK( inode -> i_mode ) ) - inode->i_generation = le32_to_cpu (INODE_PKEY (inode)->k_dir_id); - else - inode->i_generation = sd_v2_generation(sd); + struct buffer_head *bh; + struct item_head *ih; + __u32 rdev; + //int version = ITEM_VERSION_1; + + bh = PATH_PLAST_BUFFER(path); + ih = PATH_PITEM_HEAD(path); + + copy_key(INODE_PKEY(inode), &(ih->ih_key)); + inode->i_blksize = reiserfs_default_io_size; + + INIT_LIST_HEAD(&(REISERFS_I(inode)->i_prealloc_list)); + REISERFS_I(inode)->i_flags = 0; + REISERFS_I(inode)->i_prealloc_block = 0; + REISERFS_I(inode)->i_prealloc_count = 0; + REISERFS_I(inode)->i_trans_id = 0; + REISERFS_I(inode)->i_jl = NULL; + REISERFS_I(inode)->i_acl_access = NULL; + REISERFS_I(inode)->i_acl_default = NULL; + init_rwsem(&REISERFS_I(inode)->xattr_sem); + + if (stat_data_v1(ih)) { + struct stat_data_v1 *sd = + (struct stat_data_v1 *)B_I_PITEM(bh, ih); + unsigned long blocks; + + set_inode_item_key_version(inode, KEY_FORMAT_3_5); + set_inode_sd_version(inode, STAT_DATA_V1); + inode->i_mode = sd_v1_mode(sd); + inode->i_nlink = sd_v1_nlink(sd); + inode->i_uid = sd_v1_uid(sd); + inode->i_gid = sd_v1_gid(sd); + inode->i_size = sd_v1_size(sd); + inode->i_atime.tv_sec = sd_v1_atime(sd); + inode->i_mtime.tv_sec = sd_v1_mtime(sd); + inode->i_ctime.tv_sec = sd_v1_ctime(sd); + inode->i_atime.tv_nsec = 0; + inode->i_ctime.tv_nsec = 0; + inode->i_mtime.tv_nsec = 0; + + inode->i_blocks = sd_v1_blocks(sd); + inode->i_generation = le32_to_cpu(INODE_PKEY(inode)->k_dir_id); + blocks = (inode->i_size + 511) >> 9; + blocks = _ROUND_UP(blocks, inode->i_sb->s_blocksize >> 9); + if (inode->i_blocks > blocks) { + // there was a bug in <=3.5.23 when i_blocks could take negative + // values. Starting from 3.5.17 this value could even be stored in + // stat data. For such files we set i_blocks based on file + // size. Just 2 notes: this can be wrong for sparce files. On-disk value will be + // only updated if file's inode will ever change + inode->i_blocks = blocks; + } - if (S_ISDIR (inode->i_mode) || S_ISLNK (inode->i_mode)) - set_inode_item_key_version (inode, KEY_FORMAT_3_5); - else - set_inode_item_key_version (inode, KEY_FORMAT_3_6); - REISERFS_I(inode)->i_first_direct_byte = 0; - set_inode_sd_version (inode, STAT_DATA_V2); - inode_set_bytes(inode, to_real_used_space(inode, inode->i_blocks, - SD_V2_SIZE)); - /* read persistent inode attributes from sd and initalise - generic inode flags from them */ - REISERFS_I(inode)->i_attrs = sd_v2_attrs( sd ); - sd_attrs_to_i_attrs( sd_v2_attrs( sd ), inode ); - } - - pathrelse (path); - if (S_ISREG (inode->i_mode)) { - inode->i_op = &reiserfs_file_inode_operations; - inode->i_fop = &reiserfs_file_operations; - inode->i_mapping->a_ops = &reiserfs_address_space_operations ; - } else if (S_ISDIR (inode->i_mode)) { - inode->i_op = &reiserfs_dir_inode_operations; - inode->i_fop = &reiserfs_dir_operations; - } else if (S_ISLNK (inode->i_mode)) { - inode->i_op = &reiserfs_symlink_inode_operations; - inode->i_mapping->a_ops = &reiserfs_address_space_operations; - } else { - inode->i_blocks = 0; - inode->i_op = &reiserfs_special_inode_operations; - init_special_inode(inode, inode->i_mode, new_decode_dev(rdev)); - } -} + rdev = sd_v1_rdev(sd); + REISERFS_I(inode)->i_first_direct_byte = + sd_v1_first_direct_byte(sd); + /* an early bug in the quota code can give us an odd number for the + ** block count. This is incorrect, fix it here. + */ + if (inode->i_blocks & 1) { + inode->i_blocks++; + } + inode_set_bytes(inode, + to_real_used_space(inode, inode->i_blocks, + SD_V1_SIZE)); + /* nopack is initially zero for v1 objects. For v2 objects, + nopack is initialised from sd_attrs */ + REISERFS_I(inode)->i_flags &= ~i_nopack_mask; + } else { + // new stat data found, but object may have old items + // (directories and symlinks) + struct stat_data *sd = (struct stat_data *)B_I_PITEM(bh, ih); + + inode->i_mode = sd_v2_mode(sd); + inode->i_nlink = sd_v2_nlink(sd); + inode->i_uid = sd_v2_uid(sd); + inode->i_size = sd_v2_size(sd); + inode->i_gid = sd_v2_gid(sd); + inode->i_mtime.tv_sec = sd_v2_mtime(sd); + inode->i_atime.tv_sec = sd_v2_atime(sd); + inode->i_ctime.tv_sec = sd_v2_ctime(sd); + inode->i_ctime.tv_nsec = 0; + inode->i_mtime.tv_nsec = 0; + inode->i_atime.tv_nsec = 0; + inode->i_blocks = sd_v2_blocks(sd); + rdev = sd_v2_rdev(sd); + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) + inode->i_generation = + le32_to_cpu(INODE_PKEY(inode)->k_dir_id); + else + inode->i_generation = sd_v2_generation(sd); + if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) + set_inode_item_key_version(inode, KEY_FORMAT_3_5); + else + set_inode_item_key_version(inode, KEY_FORMAT_3_6); + REISERFS_I(inode)->i_first_direct_byte = 0; + set_inode_sd_version(inode, STAT_DATA_V2); + inode_set_bytes(inode, + to_real_used_space(inode, inode->i_blocks, + SD_V2_SIZE)); + /* read persistent inode attributes from sd and initalise + generic inode flags from them */ + REISERFS_I(inode)->i_attrs = sd_v2_attrs(sd); + sd_attrs_to_i_attrs(sd_v2_attrs(sd), inode); + } + + pathrelse(path); + if (S_ISREG(inode->i_mode)) { + inode->i_op = &reiserfs_file_inode_operations; + inode->i_fop = &reiserfs_file_operations; + inode->i_mapping->a_ops = &reiserfs_address_space_operations; + } else if (S_ISDIR(inode->i_mode)) { + inode->i_op = &reiserfs_dir_inode_operations; + inode->i_fop = &reiserfs_dir_operations; + } else if (S_ISLNK(inode->i_mode)) { + inode->i_op = &reiserfs_symlink_inode_operations; + inode->i_mapping->a_ops = &reiserfs_address_space_operations; + } else { + inode->i_blocks = 0; + inode->i_op = &reiserfs_special_inode_operations; + init_special_inode(inode, inode->i_mode, new_decode_dev(rdev)); + } +} // update new stat data with inode fields -static void inode2sd (void * sd, struct inode * inode, loff_t size) +static void inode2sd(void *sd, struct inode *inode, loff_t size) { - struct stat_data * sd_v2 = (struct stat_data *)sd; - __u16 flags; - - set_sd_v2_mode(sd_v2, inode->i_mode ); - set_sd_v2_nlink(sd_v2, inode->i_nlink ); - set_sd_v2_uid(sd_v2, inode->i_uid ); - set_sd_v2_size(sd_v2, size ); - set_sd_v2_gid(sd_v2, inode->i_gid ); - set_sd_v2_mtime(sd_v2, inode->i_mtime.tv_sec ); - set_sd_v2_atime(sd_v2, inode->i_atime.tv_sec ); - set_sd_v2_ctime(sd_v2, inode->i_ctime.tv_sec ); - set_sd_v2_blocks(sd_v2, to_fake_used_blocks(inode, SD_V2_SIZE)); - if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) - set_sd_v2_rdev(sd_v2, new_encode_dev(inode->i_rdev)); - else - set_sd_v2_generation(sd_v2, inode->i_generation); - flags = REISERFS_I(inode)->i_attrs; - i_attrs_to_sd_attrs( inode, &flags ); - set_sd_v2_attrs( sd_v2, flags ); + struct stat_data *sd_v2 = (struct stat_data *)sd; + __u16 flags; + + set_sd_v2_mode(sd_v2, inode->i_mode); + set_sd_v2_nlink(sd_v2, inode->i_nlink); + set_sd_v2_uid(sd_v2, inode->i_uid); + set_sd_v2_size(sd_v2, size); + set_sd_v2_gid(sd_v2, inode->i_gid); + set_sd_v2_mtime(sd_v2, inode->i_mtime.tv_sec); + set_sd_v2_atime(sd_v2, inode->i_atime.tv_sec); + set_sd_v2_ctime(sd_v2, inode->i_ctime.tv_sec); + set_sd_v2_blocks(sd_v2, to_fake_used_blocks(inode, SD_V2_SIZE)); + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) + set_sd_v2_rdev(sd_v2, new_encode_dev(inode->i_rdev)); + else + set_sd_v2_generation(sd_v2, inode->i_generation); + flags = REISERFS_I(inode)->i_attrs; + i_attrs_to_sd_attrs(inode, &flags); + set_sd_v2_attrs(sd_v2, flags); } - // used to copy inode's fields to old stat data -static void inode2sd_v1 (void * sd, struct inode * inode, loff_t size) +static void inode2sd_v1(void *sd, struct inode *inode, loff_t size) { - struct stat_data_v1 * sd_v1 = (struct stat_data_v1 *)sd; - - set_sd_v1_mode(sd_v1, inode->i_mode ); - set_sd_v1_uid(sd_v1, inode->i_uid ); - set_sd_v1_gid(sd_v1, inode->i_gid ); - set_sd_v1_nlink(sd_v1, inode->i_nlink ); - set_sd_v1_size(sd_v1, size ); - set_sd_v1_atime(sd_v1, inode->i_atime.tv_sec ); - set_sd_v1_ctime(sd_v1, inode->i_ctime.tv_sec ); - set_sd_v1_mtime(sd_v1, inode->i_mtime.tv_sec ); - - if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) - set_sd_v1_rdev(sd_v1, new_encode_dev(inode->i_rdev)); - else - set_sd_v1_blocks(sd_v1, to_fake_used_blocks(inode, SD_V1_SIZE)); - - // Sigh. i_first_direct_byte is back - set_sd_v1_first_direct_byte(sd_v1, REISERFS_I(inode)->i_first_direct_byte); -} + struct stat_data_v1 *sd_v1 = (struct stat_data_v1 *)sd; + + set_sd_v1_mode(sd_v1, inode->i_mode); + set_sd_v1_uid(sd_v1, inode->i_uid); + set_sd_v1_gid(sd_v1, inode->i_gid); + set_sd_v1_nlink(sd_v1, inode->i_nlink); + set_sd_v1_size(sd_v1, size); + set_sd_v1_atime(sd_v1, inode->i_atime.tv_sec); + set_sd_v1_ctime(sd_v1, inode->i_ctime.tv_sec); + set_sd_v1_mtime(sd_v1, inode->i_mtime.tv_sec); + + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) + set_sd_v1_rdev(sd_v1, new_encode_dev(inode->i_rdev)); + else + set_sd_v1_blocks(sd_v1, to_fake_used_blocks(inode, SD_V1_SIZE)); + // Sigh. i_first_direct_byte is back + set_sd_v1_first_direct_byte(sd_v1, + REISERFS_I(inode)->i_first_direct_byte); +} /* NOTE, you must prepare the buffer head before sending it here, ** and then log it after the call */ -static void update_stat_data (struct path * path, struct inode * inode, - loff_t size) +static void update_stat_data(struct path *path, struct inode *inode, + loff_t size) { - struct buffer_head * bh; - struct item_head * ih; - - bh = PATH_PLAST_BUFFER (path); - ih = PATH_PITEM_HEAD (path); - - if (!is_statdata_le_ih (ih)) - reiserfs_panic (inode->i_sb, "vs-13065: update_stat_data: key %k, found item %h", - INODE_PKEY (inode), ih); - - if (stat_data_v1 (ih)) { - // path points to old stat data - inode2sd_v1 (B_I_PITEM (bh, ih), inode, size); - } else { - inode2sd (B_I_PITEM (bh, ih), inode, size); - } - - return; -} + struct buffer_head *bh; + struct item_head *ih; + + bh = PATH_PLAST_BUFFER(path); + ih = PATH_PITEM_HEAD(path); + + if (!is_statdata_le_ih(ih)) + reiserfs_panic(inode->i_sb, + "vs-13065: update_stat_data: key %k, found item %h", + INODE_PKEY(inode), ih); + + if (stat_data_v1(ih)) { + // path points to old stat data + inode2sd_v1(B_I_PITEM(bh, ih), inode, size); + } else { + inode2sd(B_I_PITEM(bh, ih), inode, size); + } + return; +} -void reiserfs_update_sd_size (struct reiserfs_transaction_handle *th, - struct inode * inode, loff_t size) +void reiserfs_update_sd_size(struct reiserfs_transaction_handle *th, + struct inode *inode, loff_t size) { - struct cpu_key key; - INITIALIZE_PATH(path); - struct buffer_head *bh ; - int fs_gen ; - struct item_head *ih, tmp_ih ; - int retval; - - BUG_ON (!th->t_trans_id); - - make_cpu_key (&key, inode, SD_OFFSET, TYPE_STAT_DATA, 3);//key type is unimportant - - for(;;) { - int pos; - /* look for the object's stat data */ - retval = search_item (inode->i_sb, &key, &path); - if (retval == IO_ERROR) { - reiserfs_warning (inode->i_sb, "vs-13050: reiserfs_update_sd: " - "i/o failure occurred trying to update %K stat data", - &key); - return; - } - if (retval == ITEM_NOT_FOUND) { - pos = PATH_LAST_POSITION (&path); - pathrelse(&path) ; - if (inode->i_nlink == 0) { - /*reiserfs_warning (inode->i_sb, "vs-13050: reiserfs_update_sd: i_nlink == 0, stat data not found");*/ - return; - } - reiserfs_warning (inode->i_sb, "vs-13060: reiserfs_update_sd: " - "stat data of object %k (nlink == %d) not found (pos %d)", - INODE_PKEY (inode), inode->i_nlink, pos); - reiserfs_check_path(&path) ; - return; - } - - /* sigh, prepare_for_journal might schedule. When it schedules the - ** FS might change. We have to detect that, and loop back to the - ** search if the stat data item has moved - */ - bh = get_last_bh(&path) ; - ih = get_ih(&path) ; - copy_item_head (&tmp_ih, ih); - fs_gen = get_generation (inode->i_sb); - reiserfs_prepare_for_journal(inode->i_sb, bh, 1) ; - if (fs_changed (fs_gen, inode->i_sb) && item_moved(&tmp_ih, &path)) { - reiserfs_restore_prepared_buffer(inode->i_sb, bh) ; - continue ; /* Stat_data item has been moved after scheduling. */ - } - break; - } - update_stat_data (&path, inode, size); - journal_mark_dirty(th, th->t_super, bh) ; - pathrelse (&path); - return; + struct cpu_key key; + INITIALIZE_PATH(path); + struct buffer_head *bh; + int fs_gen; + struct item_head *ih, tmp_ih; + int retval; + + BUG_ON(!th->t_trans_id); + + make_cpu_key(&key, inode, SD_OFFSET, TYPE_STAT_DATA, 3); //key type is unimportant + + for (;;) { + int pos; + /* look for the object's stat data */ + retval = search_item(inode->i_sb, &key, &path); + if (retval == IO_ERROR) { + reiserfs_warning(inode->i_sb, + "vs-13050: reiserfs_update_sd: " + "i/o failure occurred trying to update %K stat data", + &key); + return; + } + if (retval == ITEM_NOT_FOUND) { + pos = PATH_LAST_POSITION(&path); + pathrelse(&path); + if (inode->i_nlink == 0) { + /*reiserfs_warning (inode->i_sb, "vs-13050: reiserfs_update_sd: i_nlink == 0, stat data not found"); */ + return; + } + reiserfs_warning(inode->i_sb, + "vs-13060: reiserfs_update_sd: " + "stat data of object %k (nlink == %d) not found (pos %d)", + INODE_PKEY(inode), inode->i_nlink, + pos); + reiserfs_check_path(&path); + return; + } + + /* sigh, prepare_for_journal might schedule. When it schedules the + ** FS might change. We have to detect that, and loop back to the + ** search if the stat data item has moved + */ + bh = get_last_bh(&path); + ih = get_ih(&path); + copy_item_head(&tmp_ih, ih); + fs_gen = get_generation(inode->i_sb); + reiserfs_prepare_for_journal(inode->i_sb, bh, 1); + if (fs_changed(fs_gen, inode->i_sb) + && item_moved(&tmp_ih, &path)) { + reiserfs_restore_prepared_buffer(inode->i_sb, bh); + continue; /* Stat_data item has been moved after scheduling. */ + } + break; + } + update_stat_data(&path, inode, size); + journal_mark_dirty(th, th->t_super, bh); + pathrelse(&path); + return; } /* reiserfs_read_locked_inode is called to read the inode off disk, and it @@ -1316,9 +1389,10 @@ void reiserfs_update_sd_size (struct reiserfs_transaction_handle *th, ** corresponding iput might try to delete whatever object the inode last ** represented. */ -static void reiserfs_make_bad_inode(struct inode *inode) { - memset(INODE_PKEY(inode), 0, KEY_SIZE); - make_bad_inode(inode); +static void reiserfs_make_bad_inode(struct inode *inode) +{ + memset(INODE_PKEY(inode), 0, KEY_SIZE); + make_bad_inode(inode); } // @@ -1326,77 +1400,79 @@ static void reiserfs_make_bad_inode(struct inode *inode) { // evolved as the prototype did // -int reiserfs_init_locked_inode (struct inode * inode, void *p) +int reiserfs_init_locked_inode(struct inode *inode, void *p) { - struct reiserfs_iget_args *args = (struct reiserfs_iget_args *)p ; - inode->i_ino = args->objectid; - INODE_PKEY(inode)->k_dir_id = cpu_to_le32(args->dirid); - return 0; + struct reiserfs_iget_args *args = (struct reiserfs_iget_args *)p; + inode->i_ino = args->objectid; + INODE_PKEY(inode)->k_dir_id = cpu_to_le32(args->dirid); + return 0; } /* looks for stat data in the tree, and fills up the fields of in-core inode stat data fields */ -void reiserfs_read_locked_inode (struct inode * inode, struct reiserfs_iget_args *args) +void reiserfs_read_locked_inode(struct inode *inode, + struct reiserfs_iget_args *args) { - INITIALIZE_PATH (path_to_sd); - struct cpu_key key; - unsigned long dirino; - int retval; - - dirino = args->dirid ; - - /* set version 1, version 2 could be used too, because stat data - key is the same in both versions */ - key.version = KEY_FORMAT_3_5; - key.on_disk_key.k_dir_id = dirino; - key.on_disk_key.k_objectid = inode->i_ino; - key.on_disk_key.k_offset = 0; - key.on_disk_key.k_type = 0; - - /* look for the object's stat data */ - retval = search_item (inode->i_sb, &key, &path_to_sd); - if (retval == IO_ERROR) { - reiserfs_warning (inode->i_sb, "vs-13070: reiserfs_read_locked_inode: " - "i/o failure occurred trying to find stat data of %K", - &key); - reiserfs_make_bad_inode(inode) ; - return; - } - if (retval != ITEM_FOUND) { - /* a stale NFS handle can trigger this without it being an error */ - pathrelse (&path_to_sd); - reiserfs_make_bad_inode(inode) ; - inode->i_nlink = 0; - return; - } - - init_inode (inode, &path_to_sd); - - /* It is possible that knfsd is trying to access inode of a file - that is being removed from the disk by some other thread. As we - update sd on unlink all that is required is to check for nlink - here. This bug was first found by Sizif when debugging - SquidNG/Butterfly, forgotten, and found again after Philippe - Gramoulle <philippe.gramoulle@mmania.com> reproduced it. - - More logical fix would require changes in fs/inode.c:iput() to - remove inode from hash-table _after_ fs cleaned disk stuff up and - in iget() to return NULL if I_FREEING inode is found in - hash-table. */ - /* Currently there is one place where it's ok to meet inode with - nlink==0: processing of open-unlinked and half-truncated files - during mount (fs/reiserfs/super.c:finish_unfinished()). */ - if( ( inode -> i_nlink == 0 ) && - ! REISERFS_SB(inode -> i_sb) -> s_is_unlinked_ok ) { - reiserfs_warning (inode->i_sb, - "vs-13075: reiserfs_read_locked_inode: " - "dead inode read from disk %K. " - "This is likely to be race with knfsd. Ignore", - &key ); - reiserfs_make_bad_inode( inode ); - } - - reiserfs_check_path(&path_to_sd) ; /* init inode should be relsing */ + INITIALIZE_PATH(path_to_sd); + struct cpu_key key; + unsigned long dirino; + int retval; + + dirino = args->dirid; + + /* set version 1, version 2 could be used too, because stat data + key is the same in both versions */ + key.version = KEY_FORMAT_3_5; + key.on_disk_key.k_dir_id = dirino; + key.on_disk_key.k_objectid = inode->i_ino; + key.on_disk_key.k_offset = 0; + key.on_disk_key.k_type = 0; + + /* look for the object's stat data */ + retval = search_item(inode->i_sb, &key, &path_to_sd); + if (retval == IO_ERROR) { + reiserfs_warning(inode->i_sb, + "vs-13070: reiserfs_read_locked_inode: " + "i/o failure occurred trying to find stat data of %K", + &key); + reiserfs_make_bad_inode(inode); + return; + } + if (retval != ITEM_FOUND) { + /* a stale NFS handle can trigger this without it being an error */ + pathrelse(&path_to_sd); + reiserfs_make_bad_inode(inode); + inode->i_nlink = 0; + return; + } + + init_inode(inode, &path_to_sd); + + /* It is possible that knfsd is trying to access inode of a file + that is being removed from the disk by some other thread. As we + update sd on unlink all that is required is to check for nlink + here. This bug was first found by Sizif when debugging + SquidNG/Butterfly, forgotten, and found again after Philippe + Gramoulle <philippe.gramoulle@mmania.com> reproduced it. + + More logical fix would require changes in fs/inode.c:iput() to + remove inode from hash-table _after_ fs cleaned disk stuff up and + in iget() to return NULL if I_FREEING inode is found in + hash-table. */ + /* Currently there is one place where it's ok to meet inode with + nlink==0: processing of open-unlinked and half-truncated files + during mount (fs/reiserfs/super.c:finish_unfinished()). */ + if ((inode->i_nlink == 0) && + !REISERFS_SB(inode->i_sb)->s_is_unlinked_ok) { + reiserfs_warning(inode->i_sb, + "vs-13075: reiserfs_read_locked_inode: " + "dead inode read from disk %K. " + "This is likely to be race with knfsd. Ignore", + &key); + reiserfs_make_bad_inode(inode); + } + + reiserfs_check_path(&path_to_sd); /* init inode should be relsing */ } @@ -1412,140 +1488,148 @@ void reiserfs_read_locked_inode (struct inode * inode, struct reiserfs_iget_args * inode numbers (objectids) are distinguished by parent directory ids. * */ -int reiserfs_find_actor( struct inode *inode, void *opaque ) +int reiserfs_find_actor(struct inode *inode, void *opaque) { - struct reiserfs_iget_args *args; + struct reiserfs_iget_args *args; - args = opaque; - /* args is already in CPU order */ - return (inode->i_ino == args->objectid) && - (le32_to_cpu(INODE_PKEY(inode)->k_dir_id) == args->dirid); + args = opaque; + /* args is already in CPU order */ + return (inode->i_ino == args->objectid) && + (le32_to_cpu(INODE_PKEY(inode)->k_dir_id) == args->dirid); } -struct inode * reiserfs_iget (struct super_block * s, const struct cpu_key * key) +struct inode *reiserfs_iget(struct super_block *s, const struct cpu_key *key) { - struct inode * inode; - struct reiserfs_iget_args args ; - - args.objectid = key->on_disk_key.k_objectid ; - args.dirid = key->on_disk_key.k_dir_id ; - inode = iget5_locked (s, key->on_disk_key.k_objectid, - reiserfs_find_actor, reiserfs_init_locked_inode, (void *)(&args)); - if (!inode) - return ERR_PTR(-ENOMEM) ; - - if (inode->i_state & I_NEW) { - reiserfs_read_locked_inode(inode, &args); - unlock_new_inode(inode); - } - - if (comp_short_keys (INODE_PKEY (inode), key) || is_bad_inode (inode)) { - /* either due to i/o error or a stale NFS handle */ - iput (inode); - inode = NULL; - } - return inode; + struct inode *inode; + struct reiserfs_iget_args args; + + args.objectid = key->on_disk_key.k_objectid; + args.dirid = key->on_disk_key.k_dir_id; + inode = iget5_locked(s, key->on_disk_key.k_objectid, + reiserfs_find_actor, reiserfs_init_locked_inode, + (void *)(&args)); + if (!inode) + return ERR_PTR(-ENOMEM); + + if (inode->i_state & I_NEW) { + reiserfs_read_locked_inode(inode, &args); + unlock_new_inode(inode); + } + + if (comp_short_keys(INODE_PKEY(inode), key) || is_bad_inode(inode)) { + /* either due to i/o error or a stale NFS handle */ + iput(inode); + inode = NULL; + } + return inode; } struct dentry *reiserfs_get_dentry(struct super_block *sb, void *vobjp) { - __u32 *data = vobjp; - struct cpu_key key ; - struct dentry *result; - struct inode *inode; - - key.on_disk_key.k_objectid = data[0] ; - key.on_disk_key.k_dir_id = data[1] ; - reiserfs_write_lock(sb); - inode = reiserfs_iget(sb, &key) ; - if (inode && !IS_ERR(inode) && data[2] != 0 && - data[2] != inode->i_generation) { - iput(inode) ; - inode = NULL ; - } - reiserfs_write_unlock(sb); - if (!inode) - inode = ERR_PTR(-ESTALE); - if (IS_ERR(inode)) - return ERR_PTR(PTR_ERR(inode)); - result = d_alloc_anon(inode); - if (!result) { - iput(inode); - return ERR_PTR(-ENOMEM); - } - return result; + __u32 *data = vobjp; + struct cpu_key key; + struct dentry *result; + struct inode *inode; + + key.on_disk_key.k_objectid = data[0]; + key.on_disk_key.k_dir_id = data[1]; + reiserfs_write_lock(sb); + inode = reiserfs_iget(sb, &key); + if (inode && !IS_ERR(inode) && data[2] != 0 && + data[2] != inode->i_generation) { + iput(inode); + inode = NULL; + } + reiserfs_write_unlock(sb); + if (!inode) + inode = ERR_PTR(-ESTALE); + if (IS_ERR(inode)) + return ERR_PTR(PTR_ERR(inode)); + result = d_alloc_anon(inode); + if (!result) { + iput(inode); + return ERR_PTR(-ENOMEM); + } + return result; } -struct dentry *reiserfs_decode_fh(struct super_block *sb, __u32 *data, - int len, int fhtype, - int (*acceptable)(void *contect, struct dentry *de), - void *context) { - __u32 obj[3], parent[3]; - - /* fhtype happens to reflect the number of u32s encoded. - * due to a bug in earlier code, fhtype might indicate there - * are more u32s then actually fitted. - * so if fhtype seems to be more than len, reduce fhtype. - * Valid types are: - * 2 - objectid + dir_id - legacy support - * 3 - objectid + dir_id + generation - * 4 - objectid + dir_id + objectid and dirid of parent - legacy - * 5 - objectid + dir_id + generation + objectid and dirid of parent - * 6 - as above plus generation of directory - * 6 does not fit in NFSv2 handles - */ - if (fhtype > len) { - if (fhtype != 6 || len != 5) - reiserfs_warning (sb, "nfsd/reiserfs, fhtype=%d, len=%d - odd", - fhtype, len); - fhtype = 5; - } - - obj[0] = data[0]; - obj[1] = data[1]; - if (fhtype == 3 || fhtype >= 5) - obj[2] = data[2]; - else obj[2] = 0; /* generation number */ - - if (fhtype >= 4) { - parent[0] = data[fhtype>=5?3:2] ; - parent[1] = data[fhtype>=5?4:3] ; - if (fhtype == 6) - parent[2] = data[5]; - else parent[2] = 0; - } - return sb->s_export_op->find_exported_dentry(sb, obj, fhtype < 4 ? NULL : parent, - acceptable, context); -} +struct dentry *reiserfs_decode_fh(struct super_block *sb, __u32 * data, + int len, int fhtype, + int (*acceptable) (void *contect, + struct dentry * de), + void *context) +{ + __u32 obj[3], parent[3]; + + /* fhtype happens to reflect the number of u32s encoded. + * due to a bug in earlier code, fhtype might indicate there + * are more u32s then actually fitted. + * so if fhtype seems to be more than len, reduce fhtype. + * Valid types are: + * 2 - objectid + dir_id - legacy support + * 3 - objectid + dir_id + generation + * 4 - objectid + dir_id + objectid and dirid of parent - legacy + * 5 - objectid + dir_id + generation + objectid and dirid of parent + * 6 - as above plus generation of directory + * 6 does not fit in NFSv2 handles + */ + if (fhtype > len) { + if (fhtype != 6 || len != 5) + reiserfs_warning(sb, + "nfsd/reiserfs, fhtype=%d, len=%d - odd", + fhtype, len); + fhtype = 5; + } + + obj[0] = data[0]; + obj[1] = data[1]; + if (fhtype == 3 || fhtype >= 5) + obj[2] = data[2]; + else + obj[2] = 0; /* generation number */ -int reiserfs_encode_fh(struct dentry *dentry, __u32 *data, int *lenp, int need_parent) { - struct inode *inode = dentry->d_inode ; - int maxlen = *lenp; - - if (maxlen < 3) - return 255 ; - - data[0] = inode->i_ino ; - data[1] = le32_to_cpu(INODE_PKEY (inode)->k_dir_id) ; - data[2] = inode->i_generation ; - *lenp = 3 ; - /* no room for directory info? return what we've stored so far */ - if (maxlen < 5 || ! need_parent) - return 3 ; - - spin_lock(&dentry->d_lock); - inode = dentry->d_parent->d_inode ; - data[3] = inode->i_ino ; - data[4] = le32_to_cpu(INODE_PKEY (inode)->k_dir_id) ; - *lenp = 5 ; - if (maxlen >= 6) { - data[5] = inode->i_generation ; - *lenp = 6 ; - } - spin_unlock(&dentry->d_lock); - return *lenp ; + if (fhtype >= 4) { + parent[0] = data[fhtype >= 5 ? 3 : 2]; + parent[1] = data[fhtype >= 5 ? 4 : 3]; + if (fhtype == 6) + parent[2] = data[5]; + else + parent[2] = 0; + } + return sb->s_export_op->find_exported_dentry(sb, obj, + fhtype < 4 ? NULL : parent, + acceptable, context); } +int reiserfs_encode_fh(struct dentry *dentry, __u32 * data, int *lenp, + int need_parent) +{ + struct inode *inode = dentry->d_inode; + int maxlen = *lenp; + + if (maxlen < 3) + return 255; + + data[0] = inode->i_ino; + data[1] = le32_to_cpu(INODE_PKEY(inode)->k_dir_id); + data[2] = inode->i_generation; + *lenp = 3; + /* no room for directory info? return what we've stored so far */ + if (maxlen < 5 || !need_parent) + return 3; + + spin_lock(&dentry->d_lock); + inode = dentry->d_parent->d_inode; + data[3] = inode->i_ino; + data[4] = le32_to_cpu(INODE_PKEY(inode)->k_dir_id); + *lenp = 5; + if (maxlen >= 6) { + data[5] = inode->i_generation; + *lenp = 6; + } + spin_unlock(&dentry->d_lock); + return *lenp; +} /* looks for stat data, then copies fields to it, marks the buffer containing stat data as dirty */ @@ -1554,120 +1638,127 @@ int reiserfs_encode_fh(struct dentry *dentry, __u32 *data, int *lenp, int need_p ** to properly mark inodes for datasync and such, but only actually ** does something when called for a synchronous update. */ -int reiserfs_write_inode (struct inode * inode, int do_sync) { - struct reiserfs_transaction_handle th ; - int jbegin_count = 1 ; - - if (inode->i_sb->s_flags & MS_RDONLY) - return -EROFS; - /* memory pressure can sometimes initiate write_inode calls with sync == 1, - ** these cases are just when the system needs ram, not when the - ** inode needs to reach disk for safety, and they can safely be - ** ignored because the altered inode has already been logged. - */ - if (do_sync && !(current->flags & PF_MEMALLOC)) { - reiserfs_write_lock(inode->i_sb); - if (!journal_begin(&th, inode->i_sb, jbegin_count)) { - reiserfs_update_sd (&th, inode); - journal_end_sync(&th, inode->i_sb, jbegin_count) ; - } - reiserfs_write_unlock(inode->i_sb); - } - return 0; +int reiserfs_write_inode(struct inode *inode, int do_sync) +{ + struct reiserfs_transaction_handle th; + int jbegin_count = 1; + + if (inode->i_sb->s_flags & MS_RDONLY) + return -EROFS; + /* memory pressure can sometimes initiate write_inode calls with sync == 1, + ** these cases are just when the system needs ram, not when the + ** inode needs to reach disk for safety, and they can safely be + ** ignored because the altered inode has already been logged. + */ + if (do_sync && !(current->flags & PF_MEMALLOC)) { + reiserfs_write_lock(inode->i_sb); + if (!journal_begin(&th, inode->i_sb, jbegin_count)) { + reiserfs_update_sd(&th, inode); + journal_end_sync(&th, inode->i_sb, jbegin_count); + } + reiserfs_write_unlock(inode->i_sb); + } + return 0; } /* stat data of new object is inserted already, this inserts the item containing "." and ".." entries */ -static int reiserfs_new_directory (struct reiserfs_transaction_handle *th, - struct inode *inode, - struct item_head * ih, struct path * path, - struct inode * dir) +static int reiserfs_new_directory(struct reiserfs_transaction_handle *th, + struct inode *inode, + struct item_head *ih, struct path *path, + struct inode *dir) { - struct super_block * sb = th->t_super; - char empty_dir [EMPTY_DIR_SIZE]; - char * body = empty_dir; - struct cpu_key key; - int retval; - - BUG_ON (!th->t_trans_id); - - _make_cpu_key (&key, KEY_FORMAT_3_5, le32_to_cpu (ih->ih_key.k_dir_id), - le32_to_cpu (ih->ih_key.k_objectid), DOT_OFFSET, TYPE_DIRENTRY, 3/*key length*/); - - /* compose item head for new item. Directories consist of items of - old type (ITEM_VERSION_1). Do not set key (second arg is 0), it - is done by reiserfs_new_inode */ - if (old_format_only (sb)) { - make_le_item_head (ih, NULL, KEY_FORMAT_3_5, DOT_OFFSET, TYPE_DIRENTRY, EMPTY_DIR_SIZE_V1, 2); - - make_empty_dir_item_v1 (body, ih->ih_key.k_dir_id, ih->ih_key.k_objectid, - INODE_PKEY (dir)->k_dir_id, - INODE_PKEY (dir)->k_objectid ); - } else { - make_le_item_head (ih, NULL, KEY_FORMAT_3_5, DOT_OFFSET, TYPE_DIRENTRY, EMPTY_DIR_SIZE, 2); - - make_empty_dir_item (body, ih->ih_key.k_dir_id, ih->ih_key.k_objectid, - INODE_PKEY (dir)->k_dir_id, - INODE_PKEY (dir)->k_objectid ); - } - - /* look for place in the tree for new item */ - retval = search_item (sb, &key, path); - if (retval == IO_ERROR) { - reiserfs_warning (sb, "vs-13080: reiserfs_new_directory: " - "i/o failure occurred creating new directory"); - return -EIO; - } - if (retval == ITEM_FOUND) { - pathrelse (path); - reiserfs_warning (sb, "vs-13070: reiserfs_new_directory: " - "object with this key exists (%k)", &(ih->ih_key)); - return -EEXIST; - } - - /* insert item, that is empty directory item */ - return reiserfs_insert_item (th, path, &key, ih, inode, body); -} + struct super_block *sb = th->t_super; + char empty_dir[EMPTY_DIR_SIZE]; + char *body = empty_dir; + struct cpu_key key; + int retval; + + BUG_ON(!th->t_trans_id); + + _make_cpu_key(&key, KEY_FORMAT_3_5, le32_to_cpu(ih->ih_key.k_dir_id), + le32_to_cpu(ih->ih_key.k_objectid), DOT_OFFSET, + TYPE_DIRENTRY, 3 /*key length */ ); + + /* compose item head for new item. Directories consist of items of + old type (ITEM_VERSION_1). Do not set key (second arg is 0), it + is done by reiserfs_new_inode */ + if (old_format_only(sb)) { + make_le_item_head(ih, NULL, KEY_FORMAT_3_5, DOT_OFFSET, + TYPE_DIRENTRY, EMPTY_DIR_SIZE_V1, 2); + + make_empty_dir_item_v1(body, ih->ih_key.k_dir_id, + ih->ih_key.k_objectid, + INODE_PKEY(dir)->k_dir_id, + INODE_PKEY(dir)->k_objectid); + } else { + make_le_item_head(ih, NULL, KEY_FORMAT_3_5, DOT_OFFSET, + TYPE_DIRENTRY, EMPTY_DIR_SIZE, 2); + + make_empty_dir_item(body, ih->ih_key.k_dir_id, + ih->ih_key.k_objectid, + INODE_PKEY(dir)->k_dir_id, + INODE_PKEY(dir)->k_objectid); + } + + /* look for place in the tree for new item */ + retval = search_item(sb, &key, path); + if (retval == IO_ERROR) { + reiserfs_warning(sb, "vs-13080: reiserfs_new_directory: " + "i/o failure occurred creating new directory"); + return -EIO; + } + if (retval == ITEM_FOUND) { + pathrelse(path); + reiserfs_warning(sb, "vs-13070: reiserfs_new_directory: " + "object with this key exists (%k)", + &(ih->ih_key)); + return -EEXIST; + } + /* insert item, that is empty directory item */ + return reiserfs_insert_item(th, path, &key, ih, inode, body); +} /* stat data of object has been inserted, this inserts the item containing the body of symlink */ -static int reiserfs_new_symlink (struct reiserfs_transaction_handle *th, - struct inode *inode, /* Inode of symlink */ - struct item_head * ih, - struct path * path, const char * symname, int item_len) +static int reiserfs_new_symlink(struct reiserfs_transaction_handle *th, struct inode *inode, /* Inode of symlink */ + struct item_head *ih, + struct path *path, const char *symname, + int item_len) { - struct super_block * sb = th->t_super; - struct cpu_key key; - int retval; - - BUG_ON (!th->t_trans_id); - - _make_cpu_key (&key, KEY_FORMAT_3_5, - le32_to_cpu (ih->ih_key.k_dir_id), - le32_to_cpu (ih->ih_key.k_objectid), - 1, TYPE_DIRECT, 3/*key length*/); - - make_le_item_head (ih, NULL, KEY_FORMAT_3_5, 1, TYPE_DIRECT, item_len, 0/*free_space*/); - - /* look for place in the tree for new item */ - retval = search_item (sb, &key, path); - if (retval == IO_ERROR) { - reiserfs_warning (sb, "vs-13080: reiserfs_new_symlinik: " - "i/o failure occurred creating new symlink"); - return -EIO; - } - if (retval == ITEM_FOUND) { - pathrelse (path); - reiserfs_warning (sb, "vs-13080: reiserfs_new_symlink: " - "object with this key exists (%k)", &(ih->ih_key)); - return -EEXIST; - } - - /* insert item, that is body of symlink */ - return reiserfs_insert_item (th, path, &key, ih, inode, symname); -} + struct super_block *sb = th->t_super; + struct cpu_key key; + int retval; + + BUG_ON(!th->t_trans_id); + + _make_cpu_key(&key, KEY_FORMAT_3_5, + le32_to_cpu(ih->ih_key.k_dir_id), + le32_to_cpu(ih->ih_key.k_objectid), + 1, TYPE_DIRECT, 3 /*key length */ ); + + make_le_item_head(ih, NULL, KEY_FORMAT_3_5, 1, TYPE_DIRECT, item_len, + 0 /*free_space */ ); + + /* look for place in the tree for new item */ + retval = search_item(sb, &key, path); + if (retval == IO_ERROR) { + reiserfs_warning(sb, "vs-13080: reiserfs_new_symlinik: " + "i/o failure occurred creating new symlink"); + return -EIO; + } + if (retval == ITEM_FOUND) { + pathrelse(path); + reiserfs_warning(sb, "vs-13080: reiserfs_new_symlink: " + "object with this key exists (%k)", + &(ih->ih_key)); + return -EEXIST; + } + /* insert item, that is body of symlink */ + return reiserfs_insert_item(th, path, &key, ih, inode, symname); +} /* inserts the stat data into the tree, and then calls reiserfs_new_directory (to insert ".", ".." item if new object is @@ -1678,213 +1769,219 @@ static int reiserfs_new_symlink (struct reiserfs_transaction_handle *th, non-zero due to an error, we have to drop the quota previously allocated for the fresh inode. This can only be done outside a transaction, so if we return non-zero, we also end the transaction. */ -int reiserfs_new_inode (struct reiserfs_transaction_handle *th, - struct inode * dir, int mode, - const char * symname, - /* 0 for regular, EMTRY_DIR_SIZE for dirs, - strlen (symname) for symlinks)*/ - loff_t i_size, struct dentry *dentry, - struct inode *inode) +int reiserfs_new_inode(struct reiserfs_transaction_handle *th, + struct inode *dir, int mode, const char *symname, + /* 0 for regular, EMTRY_DIR_SIZE for dirs, + strlen (symname) for symlinks) */ + loff_t i_size, struct dentry *dentry, + struct inode *inode) { - struct super_block * sb; - INITIALIZE_PATH (path_to_key); - struct cpu_key key; - struct item_head ih; - struct stat_data sd; - int retval; - int err; - - BUG_ON (!th->t_trans_id); - - if (DQUOT_ALLOC_INODE(inode)) { - err = -EDQUOT; - goto out_end_trans; - } - if (!dir || !dir->i_nlink) { - err = -EPERM; - goto out_bad_inode; - } - - sb = dir->i_sb; - - /* item head of new item */ - ih.ih_key.k_dir_id = reiserfs_choose_packing(dir); - ih.ih_key.k_objectid = cpu_to_le32 (reiserfs_get_unused_objectid (th)); - if (!ih.ih_key.k_objectid) { - err = -ENOMEM; - goto out_bad_inode ; - } - if (old_format_only (sb)) - /* not a perfect generation count, as object ids can be reused, but - ** this is as good as reiserfs can do right now. - ** note that the private part of inode isn't filled in yet, we have - ** to use the directory. - */ - inode->i_generation = le32_to_cpu (INODE_PKEY (dir)->k_objectid); - else + struct super_block *sb; + INITIALIZE_PATH(path_to_key); + struct cpu_key key; + struct item_head ih; + struct stat_data sd; + int retval; + int err; + + BUG_ON(!th->t_trans_id); + + if (DQUOT_ALLOC_INODE(inode)) { + err = -EDQUOT; + goto out_end_trans; + } + if (!dir || !dir->i_nlink) { + err = -EPERM; + goto out_bad_inode; + } + + sb = dir->i_sb; + + /* item head of new item */ + ih.ih_key.k_dir_id = reiserfs_choose_packing(dir); + ih.ih_key.k_objectid = cpu_to_le32(reiserfs_get_unused_objectid(th)); + if (!ih.ih_key.k_objectid) { + err = -ENOMEM; + goto out_bad_inode; + } + if (old_format_only(sb)) + /* not a perfect generation count, as object ids can be reused, but + ** this is as good as reiserfs can do right now. + ** note that the private part of inode isn't filled in yet, we have + ** to use the directory. + */ + inode->i_generation = le32_to_cpu(INODE_PKEY(dir)->k_objectid); + else #if defined( USE_INODE_GENERATION_COUNTER ) - inode->i_generation = le32_to_cpu(REISERFS_SB(sb)->s_rs->s_inode_generation); + inode->i_generation = + le32_to_cpu(REISERFS_SB(sb)->s_rs->s_inode_generation); #else - inode->i_generation = ++event; + inode->i_generation = ++event; #endif - /* fill stat data */ - inode->i_nlink = (S_ISDIR (mode) ? 2 : 1); - - /* uid and gid must already be set by the caller for quota init */ - - /* symlink cannot be immutable or append only, right? */ - if( S_ISLNK( inode -> i_mode ) ) - inode -> i_flags &= ~ ( S_IMMUTABLE | S_APPEND ); - - inode->i_mtime = inode->i_atime = inode->i_ctime = - CURRENT_TIME_SEC; - inode->i_size = i_size; - inode->i_blocks = 0; - inode->i_bytes = 0; - REISERFS_I(inode)->i_first_direct_byte = S_ISLNK(mode) ? 1 : - U32_MAX/*NO_BYTES_IN_DIRECT_ITEM*/; - - INIT_LIST_HEAD(&(REISERFS_I(inode)->i_prealloc_list )); - REISERFS_I(inode)->i_flags = 0; - REISERFS_I(inode)->i_prealloc_block = 0; - REISERFS_I(inode)->i_prealloc_count = 0; - REISERFS_I(inode)->i_trans_id = 0; - REISERFS_I(inode)->i_jl = NULL; - REISERFS_I(inode)->i_attrs = - REISERFS_I(dir)->i_attrs & REISERFS_INHERIT_MASK; - sd_attrs_to_i_attrs( REISERFS_I(inode) -> i_attrs, inode ); - REISERFS_I(inode)->i_acl_access = NULL; - REISERFS_I(inode)->i_acl_default = NULL; - init_rwsem (&REISERFS_I(inode)->xattr_sem); - - if (old_format_only (sb)) - make_le_item_head (&ih, NULL, KEY_FORMAT_3_5, SD_OFFSET, TYPE_STAT_DATA, SD_V1_SIZE, MAX_US_INT); - else - make_le_item_head (&ih, NULL, KEY_FORMAT_3_6, SD_OFFSET, TYPE_STAT_DATA, SD_SIZE, MAX_US_INT); - - /* key to search for correct place for new stat data */ - _make_cpu_key (&key, KEY_FORMAT_3_6, le32_to_cpu (ih.ih_key.k_dir_id), - le32_to_cpu (ih.ih_key.k_objectid), SD_OFFSET, TYPE_STAT_DATA, 3/*key length*/); - - /* find proper place for inserting of stat data */ - retval = search_item (sb, &key, &path_to_key); - if (retval == IO_ERROR) { - err = -EIO; - goto out_bad_inode; - } - if (retval == ITEM_FOUND) { - pathrelse (&path_to_key); - err = -EEXIST; - goto out_bad_inode; - } - if (old_format_only (sb)) { - if (inode->i_uid & ~0xffff || inode->i_gid & ~0xffff) { - pathrelse (&path_to_key); - /* i_uid or i_gid is too big to be stored in stat data v3.5 */ - err = -EINVAL; - goto out_bad_inode; - } - inode2sd_v1 (&sd, inode, inode->i_size); - } else { - inode2sd (&sd, inode, inode->i_size); - } - // these do not go to on-disk stat data - inode->i_ino = le32_to_cpu (ih.ih_key.k_objectid); - inode->i_blksize = reiserfs_default_io_size; - - // store in in-core inode the key of stat data and version all - // object items will have (directory items will have old offset - // format, other new objects will consist of new items) - memcpy (INODE_PKEY (inode), &(ih.ih_key), KEY_SIZE); - if (old_format_only (sb) || S_ISDIR(mode) || S_ISLNK(mode)) - set_inode_item_key_version (inode, KEY_FORMAT_3_5); - else - set_inode_item_key_version (inode, KEY_FORMAT_3_6); - if (old_format_only (sb)) - set_inode_sd_version (inode, STAT_DATA_V1); - else - set_inode_sd_version (inode, STAT_DATA_V2); - - /* insert the stat data into the tree */ + /* fill stat data */ + inode->i_nlink = (S_ISDIR(mode) ? 2 : 1); + + /* uid and gid must already be set by the caller for quota init */ + + /* symlink cannot be immutable or append only, right? */ + if (S_ISLNK(inode->i_mode)) + inode->i_flags &= ~(S_IMMUTABLE | S_APPEND); + + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC; + inode->i_size = i_size; + inode->i_blocks = 0; + inode->i_bytes = 0; + REISERFS_I(inode)->i_first_direct_byte = S_ISLNK(mode) ? 1 : + U32_MAX /*NO_BYTES_IN_DIRECT_ITEM */ ; + + INIT_LIST_HEAD(&(REISERFS_I(inode)->i_prealloc_list)); + REISERFS_I(inode)->i_flags = 0; + REISERFS_I(inode)->i_prealloc_block = 0; + REISERFS_I(inode)->i_prealloc_count = 0; + REISERFS_I(inode)->i_trans_id = 0; + REISERFS_I(inode)->i_jl = NULL; + REISERFS_I(inode)->i_attrs = + REISERFS_I(dir)->i_attrs & REISERFS_INHERIT_MASK; + sd_attrs_to_i_attrs(REISERFS_I(inode)->i_attrs, inode); + REISERFS_I(inode)->i_acl_access = NULL; + REISERFS_I(inode)->i_acl_default = NULL; + init_rwsem(&REISERFS_I(inode)->xattr_sem); + + if (old_format_only(sb)) + make_le_item_head(&ih, NULL, KEY_FORMAT_3_5, SD_OFFSET, + TYPE_STAT_DATA, SD_V1_SIZE, MAX_US_INT); + else + make_le_item_head(&ih, NULL, KEY_FORMAT_3_6, SD_OFFSET, + TYPE_STAT_DATA, SD_SIZE, MAX_US_INT); + + /* key to search for correct place for new stat data */ + _make_cpu_key(&key, KEY_FORMAT_3_6, le32_to_cpu(ih.ih_key.k_dir_id), + le32_to_cpu(ih.ih_key.k_objectid), SD_OFFSET, + TYPE_STAT_DATA, 3 /*key length */ ); + + /* find proper place for inserting of stat data */ + retval = search_item(sb, &key, &path_to_key); + if (retval == IO_ERROR) { + err = -EIO; + goto out_bad_inode; + } + if (retval == ITEM_FOUND) { + pathrelse(&path_to_key); + err = -EEXIST; + goto out_bad_inode; + } + if (old_format_only(sb)) { + if (inode->i_uid & ~0xffff || inode->i_gid & ~0xffff) { + pathrelse(&path_to_key); + /* i_uid or i_gid is too big to be stored in stat data v3.5 */ + err = -EINVAL; + goto out_bad_inode; + } + inode2sd_v1(&sd, inode, inode->i_size); + } else { + inode2sd(&sd, inode, inode->i_size); + } + // these do not go to on-disk stat data + inode->i_ino = le32_to_cpu(ih.ih_key.k_objectid); + inode->i_blksize = reiserfs_default_io_size; + + // store in in-core inode the key of stat data and version all + // object items will have (directory items will have old offset + // format, other new objects will consist of new items) + memcpy(INODE_PKEY(inode), &(ih.ih_key), KEY_SIZE); + if (old_format_only(sb) || S_ISDIR(mode) || S_ISLNK(mode)) + set_inode_item_key_version(inode, KEY_FORMAT_3_5); + else + set_inode_item_key_version(inode, KEY_FORMAT_3_6); + if (old_format_only(sb)) + set_inode_sd_version(inode, STAT_DATA_V1); + else + set_inode_sd_version(inode, STAT_DATA_V2); + + /* insert the stat data into the tree */ #ifdef DISPLACE_NEW_PACKING_LOCALITIES - if (REISERFS_I(dir)->new_packing_locality) - th->displace_new_blocks = 1; + if (REISERFS_I(dir)->new_packing_locality) + th->displace_new_blocks = 1; #endif - retval = reiserfs_insert_item (th, &path_to_key, &key, &ih, inode, (char *)(&sd)); - if (retval) { - err = retval; - reiserfs_check_path(&path_to_key) ; - goto out_bad_inode; - } - + retval = + reiserfs_insert_item(th, &path_to_key, &key, &ih, inode, + (char *)(&sd)); + if (retval) { + err = retval; + reiserfs_check_path(&path_to_key); + goto out_bad_inode; + } #ifdef DISPLACE_NEW_PACKING_LOCALITIES - if (!th->displace_new_blocks) - REISERFS_I(dir)->new_packing_locality = 0; + if (!th->displace_new_blocks) + REISERFS_I(dir)->new_packing_locality = 0; #endif - if (S_ISDIR(mode)) { - /* insert item with "." and ".." */ - retval = reiserfs_new_directory (th, inode, &ih, &path_to_key, dir); - } - - if (S_ISLNK(mode)) { - /* insert body of symlink */ - if (!old_format_only (sb)) - i_size = ROUND_UP(i_size); - retval = reiserfs_new_symlink (th, inode, &ih, &path_to_key, symname, i_size); - } - if (retval) { - err = retval; - reiserfs_check_path(&path_to_key) ; - journal_end(th, th->t_super, th->t_blocks_allocated); - goto out_inserted_sd; - } - - /* XXX CHECK THIS */ - if (reiserfs_posixacl (inode->i_sb)) { - retval = reiserfs_inherit_default_acl (dir, dentry, inode); - if (retval) { - err = retval; - reiserfs_check_path(&path_to_key) ; - journal_end(th, th->t_super, th->t_blocks_allocated); - goto out_inserted_sd; - } - } else if (inode->i_sb->s_flags & MS_POSIXACL) { - reiserfs_warning (inode->i_sb, "ACLs aren't enabled in the fs, " - "but vfs thinks they are!"); - } else if (is_reiserfs_priv_object (dir)) { - reiserfs_mark_inode_private (inode); - } - - insert_inode_hash (inode); - reiserfs_update_sd(th, inode); - reiserfs_check_path(&path_to_key) ; - - return 0; + if (S_ISDIR(mode)) { + /* insert item with "." and ".." */ + retval = + reiserfs_new_directory(th, inode, &ih, &path_to_key, dir); + } + + if (S_ISLNK(mode)) { + /* insert body of symlink */ + if (!old_format_only(sb)) + i_size = ROUND_UP(i_size); + retval = + reiserfs_new_symlink(th, inode, &ih, &path_to_key, symname, + i_size); + } + if (retval) { + err = retval; + reiserfs_check_path(&path_to_key); + journal_end(th, th->t_super, th->t_blocks_allocated); + goto out_inserted_sd; + } + + /* XXX CHECK THIS */ + if (reiserfs_posixacl(inode->i_sb)) { + retval = reiserfs_inherit_default_acl(dir, dentry, inode); + if (retval) { + err = retval; + reiserfs_check_path(&path_to_key); + journal_end(th, th->t_super, th->t_blocks_allocated); + goto out_inserted_sd; + } + } else if (inode->i_sb->s_flags & MS_POSIXACL) { + reiserfs_warning(inode->i_sb, "ACLs aren't enabled in the fs, " + "but vfs thinks they are!"); + } else if (is_reiserfs_priv_object(dir)) { + reiserfs_mark_inode_private(inode); + } + + insert_inode_hash(inode); + reiserfs_update_sd(th, inode); + reiserfs_check_path(&path_to_key); + + return 0; /* it looks like you can easily compress these two goto targets into * one. Keeping it like this doesn't actually hurt anything, and they * are place holders for what the quota code actually needs. */ -out_bad_inode: - /* Invalidate the object, nothing was inserted yet */ - INODE_PKEY(inode)->k_objectid = 0; - - /* Quota change must be inside a transaction for journaling */ - DQUOT_FREE_INODE(inode); - -out_end_trans: - journal_end(th, th->t_super, th->t_blocks_allocated) ; - /* Drop can be outside and it needs more credits so it's better to have it outside */ - DQUOT_DROP(inode); - inode->i_flags |= S_NOQUOTA; - make_bad_inode(inode); - -out_inserted_sd: - inode->i_nlink = 0; - th->t_trans_id = 0; /* so the caller can't use this handle later */ - iput(inode); - return err; + out_bad_inode: + /* Invalidate the object, nothing was inserted yet */ + INODE_PKEY(inode)->k_objectid = 0; + + /* Quota change must be inside a transaction for journaling */ + DQUOT_FREE_INODE(inode); + + out_end_trans: + journal_end(th, th->t_super, th->t_blocks_allocated); + /* Drop can be outside and it needs more credits so it's better to have it outside */ + DQUOT_DROP(inode); + inode->i_flags |= S_NOQUOTA; + make_bad_inode(inode); + + out_inserted_sd: + inode->i_nlink = 0; + th->t_trans_id = 0; /* so the caller can't use this handle later */ + iput(inode); + return err; } /* @@ -1900,77 +1997,78 @@ out_inserted_sd: ** ** on failure, nonzero is returned, page_result and bh_result are untouched. */ -static int grab_tail_page(struct inode *p_s_inode, - struct page **page_result, - struct buffer_head **bh_result) { - - /* we want the page with the last byte in the file, - ** not the page that will hold the next byte for appending - */ - unsigned long index = (p_s_inode->i_size-1) >> PAGE_CACHE_SHIFT ; - unsigned long pos = 0 ; - unsigned long start = 0 ; - unsigned long blocksize = p_s_inode->i_sb->s_blocksize ; - unsigned long offset = (p_s_inode->i_size) & (PAGE_CACHE_SIZE - 1) ; - struct buffer_head *bh ; - struct buffer_head *head ; - struct page * page ; - int error ; - - /* we know that we are only called with inode->i_size > 0. - ** we also know that a file tail can never be as big as a block - ** If i_size % blocksize == 0, our file is currently block aligned - ** and it won't need converting or zeroing after a truncate. - */ - if ((offset & (blocksize - 1)) == 0) { - return -ENOENT ; - } - page = grab_cache_page(p_s_inode->i_mapping, index) ; - error = -ENOMEM ; - if (!page) { - goto out ; - } - /* start within the page of the last block in the file */ - start = (offset / blocksize) * blocksize ; - - error = block_prepare_write(page, start, offset, - reiserfs_get_block_create_0) ; - if (error) - goto unlock ; - - head = page_buffers(page) ; - bh = head; - do { - if (pos >= start) { - break ; - } - bh = bh->b_this_page ; - pos += blocksize ; - } while(bh != head) ; - - if (!buffer_uptodate(bh)) { - /* note, this should never happen, prepare_write should - ** be taking care of this for us. If the buffer isn't up to date, - ** I've screwed up the code to find the buffer, or the code to - ** call prepare_write - */ - reiserfs_warning (p_s_inode->i_sb, - "clm-6000: error reading block %lu on dev %s", - bh->b_blocknr, - reiserfs_bdevname (p_s_inode->i_sb)) ; - error = -EIO ; - goto unlock ; - } - *bh_result = bh ; - *page_result = page ; - -out: - return error ; - -unlock: - unlock_page(page) ; - page_cache_release(page) ; - return error ; +static int grab_tail_page(struct inode *p_s_inode, + struct page **page_result, + struct buffer_head **bh_result) +{ + + /* we want the page with the last byte in the file, + ** not the page that will hold the next byte for appending + */ + unsigned long index = (p_s_inode->i_size - 1) >> PAGE_CACHE_SHIFT; + unsigned long pos = 0; + unsigned long start = 0; + unsigned long blocksize = p_s_inode->i_sb->s_blocksize; + unsigned long offset = (p_s_inode->i_size) & (PAGE_CACHE_SIZE - 1); + struct buffer_head *bh; + struct buffer_head *head; + struct page *page; + int error; + + /* we know that we are only called with inode->i_size > 0. + ** we also know that a file tail can never be as big as a block + ** If i_size % blocksize == 0, our file is currently block aligned + ** and it won't need converting or zeroing after a truncate. + */ + if ((offset & (blocksize - 1)) == 0) { + return -ENOENT; + } + page = grab_cache_page(p_s_inode->i_mapping, index); + error = -ENOMEM; + if (!page) { + goto out; + } + /* start within the page of the last block in the file */ + start = (offset / blocksize) * blocksize; + + error = block_prepare_write(page, start, offset, + reiserfs_get_block_create_0); + if (error) + goto unlock; + + head = page_buffers(page); + bh = head; + do { + if (pos >= start) { + break; + } + bh = bh->b_this_page; + pos += blocksize; + } while (bh != head); + + if (!buffer_uptodate(bh)) { + /* note, this should never happen, prepare_write should + ** be taking care of this for us. If the buffer isn't up to date, + ** I've screwed up the code to find the buffer, or the code to + ** call prepare_write + */ + reiserfs_warning(p_s_inode->i_sb, + "clm-6000: error reading block %lu on dev %s", + bh->b_blocknr, + reiserfs_bdevname(p_s_inode->i_sb)); + error = -EIO; + goto unlock; + } + *bh_result = bh; + *page_result = page; + + out: + return error; + + unlock: + unlock_page(page); + page_cache_release(page); + return error; } /* @@ -1979,235 +2077,247 @@ unlock: ** ** some code taken from block_truncate_page */ -int reiserfs_truncate_file(struct inode *p_s_inode, int update_timestamps) { - struct reiserfs_transaction_handle th ; - /* we want the offset for the first byte after the end of the file */ - unsigned long offset = p_s_inode->i_size & (PAGE_CACHE_SIZE - 1) ; - unsigned blocksize = p_s_inode->i_sb->s_blocksize ; - unsigned length ; - struct page *page = NULL ; - int error ; - struct buffer_head *bh = NULL ; - - reiserfs_write_lock(p_s_inode->i_sb); - - if (p_s_inode->i_size > 0) { - if ((error = grab_tail_page(p_s_inode, &page, &bh))) { - // -ENOENT means we truncated past the end of the file, - // and get_block_create_0 could not find a block to read in, - // which is ok. - if (error != -ENOENT) - reiserfs_warning (p_s_inode->i_sb, - "clm-6001: grab_tail_page failed %d", - error); - page = NULL ; - bh = NULL ; - } - } - - /* so, if page != NULL, we have a buffer head for the offset at - ** the end of the file. if the bh is mapped, and bh->b_blocknr != 0, - ** then we have an unformatted node. Otherwise, we have a direct item, - ** and no zeroing is required on disk. We zero after the truncate, - ** because the truncate might pack the item anyway - ** (it will unmap bh if it packs). - */ - /* it is enough to reserve space in transaction for 2 balancings: - one for "save" link adding and another for the first - cut_from_item. 1 is for update_sd */ - error = journal_begin (&th, p_s_inode->i_sb, - JOURNAL_PER_BALANCE_CNT * 2 + 1); - if (error) - goto out; - reiserfs_update_inode_transaction(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 - either appears truncated properly or not truncated at all */ - add_save_link (&th, p_s_inode, 1); - error = reiserfs_do_truncate (&th, p_s_inode, page, update_timestamps) ; - if (error) - goto out; - error = journal_end (&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 + 1); - if (error) - goto out; - - if (update_timestamps) { - error = remove_save_link (p_s_inode, 1/* truncate */); - if (error) - goto out; - } - - if (page) { - length = offset & (blocksize - 1) ; - /* if we are not on a block boundary */ - if (length) { - char *kaddr; - - length = blocksize - length ; - kaddr = kmap_atomic(page, KM_USER0) ; - memset(kaddr + offset, 0, length) ; - flush_dcache_page(page) ; - kunmap_atomic(kaddr, KM_USER0) ; - if (buffer_mapped(bh) && bh->b_blocknr != 0) { - mark_buffer_dirty(bh) ; - } - } - unlock_page(page) ; - page_cache_release(page) ; - } - - reiserfs_write_unlock(p_s_inode->i_sb); - return 0; -out: - if (page) { - unlock_page (page); - page_cache_release (page); - } - reiserfs_write_unlock(p_s_inode->i_sb); - return error; -} +int reiserfs_truncate_file(struct inode *p_s_inode, int update_timestamps) +{ + struct reiserfs_transaction_handle th; + /* we want the offset for the first byte after the end of the file */ + unsigned long offset = p_s_inode->i_size & (PAGE_CACHE_SIZE - 1); + unsigned blocksize = p_s_inode->i_sb->s_blocksize; + unsigned length; + struct page *page = NULL; + int error; + struct buffer_head *bh = NULL; + + reiserfs_write_lock(p_s_inode->i_sb); + + if (p_s_inode->i_size > 0) { + if ((error = grab_tail_page(p_s_inode, &page, &bh))) { + // -ENOENT means we truncated past the end of the file, + // and get_block_create_0 could not find a block to read in, + // which is ok. + if (error != -ENOENT) + reiserfs_warning(p_s_inode->i_sb, + "clm-6001: grab_tail_page failed %d", + error); + page = NULL; + bh = NULL; + } + } -static int map_block_for_writepage(struct inode *inode, - struct buffer_head *bh_result, - unsigned long block) { - struct reiserfs_transaction_handle th ; - int fs_gen ; - struct item_head tmp_ih ; - struct item_head *ih ; - struct buffer_head *bh ; - __le32 *item ; - struct cpu_key key ; - INITIALIZE_PATH(path) ; - int pos_in_item ; - int jbegin_count = JOURNAL_PER_BALANCE_CNT ; - loff_t byte_offset = (block << inode->i_sb->s_blocksize_bits) + 1 ; - int retval ; - int use_get_block = 0 ; - int bytes_copied = 0 ; - int copy_size ; - int trans_running = 0; - - /* catch places below that try to log something without starting a trans */ - th.t_trans_id = 0; - - if (!buffer_uptodate(bh_result)) { - return -EIO; - } - - kmap(bh_result->b_page) ; -start_over: - reiserfs_write_lock(inode->i_sb); - make_cpu_key(&key, inode, byte_offset, TYPE_ANY, 3) ; - -research: - retval = search_for_position_by_key(inode->i_sb, &key, &path) ; - if (retval != POSITION_FOUND) { - use_get_block = 1; - goto out ; - } - - bh = get_last_bh(&path) ; - ih = get_ih(&path) ; - item = get_item(&path) ; - pos_in_item = path.pos_in_item ; - - /* we've found an unformatted node */ - if (indirect_item_found(retval, ih)) { - if (bytes_copied > 0) { - reiserfs_warning (inode->i_sb, "clm-6002: bytes_copied %d", - bytes_copied) ; - } - if (!get_block_num(item, pos_in_item)) { - /* crap, we are writing to a hole */ - use_get_block = 1; - goto out ; - } - set_block_dev_mapped(bh_result, get_block_num(item,pos_in_item),inode); - } else if (is_direct_le_ih(ih)) { - char *p ; - p = page_address(bh_result->b_page) ; - p += (byte_offset -1) & (PAGE_CACHE_SIZE - 1) ; - copy_size = ih_item_len(ih) - pos_in_item; - - fs_gen = get_generation(inode->i_sb) ; - copy_item_head(&tmp_ih, ih) ; - - if (!trans_running) { - /* vs-3050 is gone, no need to drop the path */ - retval = journal_begin(&th, inode->i_sb, jbegin_count) ; - if (retval) - goto out; - reiserfs_update_inode_transaction(inode) ; - trans_running = 1; - if (fs_changed(fs_gen, inode->i_sb) && item_moved(&tmp_ih, &path)) { - reiserfs_restore_prepared_buffer(inode->i_sb, bh) ; - goto research; - } - } - - reiserfs_prepare_for_journal(inode->i_sb, bh, 1) ; - - if (fs_changed (fs_gen, inode->i_sb) && item_moved (&tmp_ih, &path)) { - reiserfs_restore_prepared_buffer(inode->i_sb, bh) ; - goto research; - } - - memcpy( B_I_PITEM(bh, ih) + pos_in_item, p + bytes_copied, copy_size) ; - - journal_mark_dirty(&th, inode->i_sb, bh) ; - bytes_copied += copy_size ; - set_block_dev_mapped(bh_result, 0, inode); - - /* are there still bytes left? */ - if (bytes_copied < bh_result->b_size && - (byte_offset + bytes_copied) < inode->i_size) { - set_cpu_key_k_offset(&key, cpu_key_k_offset(&key) + copy_size) ; - goto research ; - } - } else { - reiserfs_warning (inode->i_sb, - "clm-6003: bad item inode %lu, device %s", - inode->i_ino, reiserfs_bdevname (inode->i_sb)) ; - retval = -EIO ; - goto out ; - } - retval = 0 ; - -out: - pathrelse(&path) ; - if (trans_running) { - int err = journal_end(&th, inode->i_sb, jbegin_count) ; - if (err) - retval = err; - trans_running = 0; - } - reiserfs_write_unlock(inode->i_sb); - - /* this is where we fill in holes in the file. */ - if (use_get_block) { - retval = reiserfs_get_block(inode, block, bh_result, - GET_BLOCK_CREATE | GET_BLOCK_NO_ISEM | - GET_BLOCK_NO_DANGLE); - if (!retval) { - if (!buffer_mapped(bh_result) || bh_result->b_blocknr == 0) { - /* get_block failed to find a mapped unformatted node. */ - use_get_block = 0 ; - goto start_over ; - } - } - } - kunmap(bh_result->b_page) ; - - if (!retval && buffer_mapped(bh_result) && bh_result->b_blocknr == 0) { - /* we've copied data from the page into the direct item, so the - * buffer in the page is now clean, mark it to reflect that. + /* so, if page != NULL, we have a buffer head for the offset at + ** the end of the file. if the bh is mapped, and bh->b_blocknr != 0, + ** then we have an unformatted node. Otherwise, we have a direct item, + ** and no zeroing is required on disk. We zero after the truncate, + ** because the truncate might pack the item anyway + ** (it will unmap bh if it packs). */ - lock_buffer(bh_result); - clear_buffer_dirty(bh_result); - unlock_buffer(bh_result); - } - return retval ; + /* it is enough to reserve space in transaction for 2 balancings: + one for "save" link adding and another for the first + cut_from_item. 1 is for update_sd */ + error = journal_begin(&th, p_s_inode->i_sb, + JOURNAL_PER_BALANCE_CNT * 2 + 1); + if (error) + goto out; + reiserfs_update_inode_transaction(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 + either appears truncated properly or not truncated at all */ + add_save_link(&th, p_s_inode, 1); + error = reiserfs_do_truncate(&th, p_s_inode, page, update_timestamps); + if (error) + goto out; + error = + journal_end(&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 + 1); + if (error) + goto out; + + if (update_timestamps) { + error = remove_save_link(p_s_inode, 1 /* truncate */ ); + if (error) + goto out; + } + + if (page) { + length = offset & (blocksize - 1); + /* if we are not on a block boundary */ + if (length) { + char *kaddr; + + length = blocksize - length; + kaddr = kmap_atomic(page, KM_USER0); + memset(kaddr + offset, 0, length); + flush_dcache_page(page); + kunmap_atomic(kaddr, KM_USER0); + if (buffer_mapped(bh) && bh->b_blocknr != 0) { + mark_buffer_dirty(bh); + } + } + unlock_page(page); + page_cache_release(page); + } + + reiserfs_write_unlock(p_s_inode->i_sb); + return 0; + out: + if (page) { + unlock_page(page); + page_cache_release(page); + } + reiserfs_write_unlock(p_s_inode->i_sb); + return error; +} + +static int map_block_for_writepage(struct inode *inode, + struct buffer_head *bh_result, + unsigned long block) +{ + struct reiserfs_transaction_handle th; + int fs_gen; + struct item_head tmp_ih; + struct item_head *ih; + struct buffer_head *bh; + __le32 *item; + struct cpu_key key; + INITIALIZE_PATH(path); + int pos_in_item; + int jbegin_count = JOURNAL_PER_BALANCE_CNT; + loff_t byte_offset = (block << inode->i_sb->s_blocksize_bits) + 1; + int retval; + int use_get_block = 0; + int bytes_copied = 0; + int copy_size; + int trans_running = 0; + + /* catch places below that try to log something without starting a trans */ + th.t_trans_id = 0; + + if (!buffer_uptodate(bh_result)) { + return -EIO; + } + + kmap(bh_result->b_page); + start_over: + reiserfs_write_lock(inode->i_sb); + make_cpu_key(&key, inode, byte_offset, TYPE_ANY, 3); + + research: + retval = search_for_position_by_key(inode->i_sb, &key, &path); + if (retval != POSITION_FOUND) { + use_get_block = 1; + goto out; + } + + bh = get_last_bh(&path); + ih = get_ih(&path); + item = get_item(&path); + pos_in_item = path.pos_in_item; + + /* we've found an unformatted node */ + if (indirect_item_found(retval, ih)) { + if (bytes_copied > 0) { + reiserfs_warning(inode->i_sb, + "clm-6002: bytes_copied %d", + bytes_copied); + } + if (!get_block_num(item, pos_in_item)) { + /* crap, we are writing to a hole */ + use_get_block = 1; + goto out; + } + set_block_dev_mapped(bh_result, + get_block_num(item, pos_in_item), inode); + } else if (is_direct_le_ih(ih)) { + char *p; + p = page_address(bh_result->b_page); + p += (byte_offset - 1) & (PAGE_CACHE_SIZE - 1); + copy_size = ih_item_len(ih) - pos_in_item; + + fs_gen = get_generation(inode->i_sb); + copy_item_head(&tmp_ih, ih); + + if (!trans_running) { + /* vs-3050 is gone, no need to drop the path */ + retval = journal_begin(&th, inode->i_sb, jbegin_count); + if (retval) + goto out; + reiserfs_update_inode_transaction(inode); + trans_running = 1; + if (fs_changed(fs_gen, inode->i_sb) + && item_moved(&tmp_ih, &path)) { + reiserfs_restore_prepared_buffer(inode->i_sb, + bh); + goto research; + } + } + + reiserfs_prepare_for_journal(inode->i_sb, bh, 1); + + if (fs_changed(fs_gen, inode->i_sb) + && item_moved(&tmp_ih, &path)) { + reiserfs_restore_prepared_buffer(inode->i_sb, bh); + goto research; + } + + memcpy(B_I_PITEM(bh, ih) + pos_in_item, p + bytes_copied, + copy_size); + + journal_mark_dirty(&th, inode->i_sb, bh); + bytes_copied += copy_size; + set_block_dev_mapped(bh_result, 0, inode); + + /* are there still bytes left? */ + if (bytes_copied < bh_result->b_size && + (byte_offset + bytes_copied) < inode->i_size) { + set_cpu_key_k_offset(&key, + cpu_key_k_offset(&key) + + copy_size); + goto research; + } + } else { + reiserfs_warning(inode->i_sb, + "clm-6003: bad item inode %lu, device %s", + inode->i_ino, reiserfs_bdevname(inode->i_sb)); + retval = -EIO; + goto out; + } + retval = 0; + + out: + pathrelse(&path); + if (trans_running) { + int err = journal_end(&th, inode->i_sb, jbegin_count); + if (err) + retval = err; + trans_running = 0; + } + reiserfs_write_unlock(inode->i_sb); + + /* this is where we fill in holes in the file. */ + if (use_get_block) { + retval = reiserfs_get_block(inode, block, bh_result, + GET_BLOCK_CREATE | GET_BLOCK_NO_ISEM + | GET_BLOCK_NO_DANGLE); + if (!retval) { + if (!buffer_mapped(bh_result) + || bh_result->b_blocknr == 0) { + /* get_block failed to find a mapped unformatted node. */ + use_get_block = 0; + goto start_over; + } + } + } + kunmap(bh_result->b_page); + + if (!retval && buffer_mapped(bh_result) && bh_result->b_blocknr == 0) { + /* we've copied data from the page into the direct item, so the + * buffer in the page is now clean, mark it to reflect that. + */ + lock_buffer(bh_result); + clear_buffer_dirty(bh_result); + unlock_buffer(bh_result); + } + return retval; } /* @@ -2215,383 +2325,390 @@ out: * start/recovery path as __block_write_full_page, along with special * code to handle reiserfs tails. */ -static int reiserfs_write_full_page(struct page *page, struct writeback_control *wbc) { - struct inode *inode = page->mapping->host ; - unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT ; - int error = 0; - unsigned long block ; - struct buffer_head *head, *bh; - int partial = 0 ; - int nr = 0; - int checked = PageChecked(page); - struct reiserfs_transaction_handle th; - struct super_block *s = inode->i_sb; - int bh_per_page = PAGE_CACHE_SIZE / s->s_blocksize; - th.t_trans_id = 0; - - /* The page dirty bit is cleared before writepage is called, which - * means we have to tell create_empty_buffers to make dirty buffers - * The page really should be up to date at this point, so tossing - * in the BH_Uptodate is just a sanity check. - */ - if (!page_has_buffers(page)) { - create_empty_buffers(page, s->s_blocksize, - (1 << BH_Dirty) | (1 << BH_Uptodate)); - } - head = page_buffers(page) ; - - /* last page in the file, zero out any contents past the - ** last byte in the file - */ - if (page->index >= end_index) { - char *kaddr; - unsigned last_offset; - - last_offset = inode->i_size & (PAGE_CACHE_SIZE - 1) ; - /* no file contents in this page */ - if (page->index >= end_index + 1 || !last_offset) { - unlock_page(page); - return 0; - } - kaddr = kmap_atomic(page, KM_USER0); - memset(kaddr + last_offset, 0, PAGE_CACHE_SIZE-last_offset) ; - flush_dcache_page(page) ; - kunmap_atomic(kaddr, KM_USER0) ; - } - bh = head ; - block = page->index << (PAGE_CACHE_SHIFT - s->s_blocksize_bits) ; - /* first map all the buffers, logging any direct items we find */ - do { - if ((checked || buffer_dirty(bh)) && (!buffer_mapped(bh) || - (buffer_mapped(bh) && bh->b_blocknr == 0))) { - /* not mapped yet, or it points to a direct item, search - * the btree for the mapping info, and log any direct - * items found - */ - if ((error = map_block_for_writepage(inode, bh, block))) { - goto fail ; - } - } - bh = bh->b_this_page; - block++; - } while(bh != head) ; - - /* - * we start the transaction after map_block_for_writepage, - * because it can create holes in the file (an unbounded operation). - * starting it here, we can make a reliable estimate for how many - * blocks we're going to log - */ - if (checked) { - ClearPageChecked(page); - reiserfs_write_lock(s); - error = journal_begin(&th, s, bh_per_page + 1); - if (error) { - reiserfs_write_unlock(s); - goto fail; - } - reiserfs_update_inode_transaction(inode); - } - /* now go through and lock any dirty buffers on the page */ - do { - get_bh(bh); - if (!buffer_mapped(bh)) - continue; - if (buffer_mapped(bh) && bh->b_blocknr == 0) - continue; +static int reiserfs_write_full_page(struct page *page, + struct writeback_control *wbc) +{ + struct inode *inode = page->mapping->host; + unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT; + int error = 0; + unsigned long block; + struct buffer_head *head, *bh; + int partial = 0; + int nr = 0; + int checked = PageChecked(page); + struct reiserfs_transaction_handle th; + struct super_block *s = inode->i_sb; + int bh_per_page = PAGE_CACHE_SIZE / s->s_blocksize; + th.t_trans_id = 0; + + /* The page dirty bit is cleared before writepage is called, which + * means we have to tell create_empty_buffers to make dirty buffers + * The page really should be up to date at this point, so tossing + * in the BH_Uptodate is just a sanity check. + */ + if (!page_has_buffers(page)) { + create_empty_buffers(page, s->s_blocksize, + (1 << BH_Dirty) | (1 << BH_Uptodate)); + } + head = page_buffers(page); - if (checked) { - reiserfs_prepare_for_journal(s, bh, 1); - journal_mark_dirty(&th, s, bh); - continue; + /* last page in the file, zero out any contents past the + ** last byte in the file + */ + if (page->index >= end_index) { + char *kaddr; + unsigned last_offset; + + last_offset = inode->i_size & (PAGE_CACHE_SIZE - 1); + /* no file contents in this page */ + if (page->index >= end_index + 1 || !last_offset) { + unlock_page(page); + return 0; + } + kaddr = kmap_atomic(page, KM_USER0); + memset(kaddr + last_offset, 0, PAGE_CACHE_SIZE - last_offset); + flush_dcache_page(page); + kunmap_atomic(kaddr, KM_USER0); } - /* from this point on, we know the buffer is mapped to a - * real block and not a direct item + bh = head; + block = page->index << (PAGE_CACHE_SHIFT - s->s_blocksize_bits); + /* first map all the buffers, logging any direct items we find */ + do { + if ((checked || buffer_dirty(bh)) && (!buffer_mapped(bh) || + (buffer_mapped(bh) + && bh->b_blocknr == + 0))) { + /* not mapped yet, or it points to a direct item, search + * the btree for the mapping info, and log any direct + * items found + */ + if ((error = map_block_for_writepage(inode, bh, block))) { + goto fail; + } + } + bh = bh->b_this_page; + block++; + } while (bh != head); + + /* + * we start the transaction after map_block_for_writepage, + * because it can create holes in the file (an unbounded operation). + * starting it here, we can make a reliable estimate for how many + * blocks we're going to log */ - if (wbc->sync_mode != WB_SYNC_NONE || !wbc->nonblocking) { - lock_buffer(bh); - } else { - if (test_set_buffer_locked(bh)) { - redirty_page_for_writepage(wbc, page); - continue; - } + if (checked) { + ClearPageChecked(page); + reiserfs_write_lock(s); + error = journal_begin(&th, s, bh_per_page + 1); + if (error) { + reiserfs_write_unlock(s); + goto fail; + } + reiserfs_update_inode_transaction(inode); } - if (test_clear_buffer_dirty(bh)) { - mark_buffer_async_write(bh); - } else { - unlock_buffer(bh); + /* now go through and lock any dirty buffers on the page */ + do { + get_bh(bh); + if (!buffer_mapped(bh)) + continue; + if (buffer_mapped(bh) && bh->b_blocknr == 0) + continue; + + if (checked) { + reiserfs_prepare_for_journal(s, bh, 1); + journal_mark_dirty(&th, s, bh); + continue; + } + /* from this point on, we know the buffer is mapped to a + * real block and not a direct item + */ + if (wbc->sync_mode != WB_SYNC_NONE || !wbc->nonblocking) { + lock_buffer(bh); + } else { + if (test_set_buffer_locked(bh)) { + redirty_page_for_writepage(wbc, page); + continue; + } + } + if (test_clear_buffer_dirty(bh)) { + mark_buffer_async_write(bh); + } else { + unlock_buffer(bh); + } + } while ((bh = bh->b_this_page) != head); + + if (checked) { + error = journal_end(&th, s, bh_per_page + 1); + reiserfs_write_unlock(s); + if (error) + goto fail; } - } while((bh = bh->b_this_page) != head); + BUG_ON(PageWriteback(page)); + set_page_writeback(page); + unlock_page(page); - if (checked) { - error = journal_end(&th, s, bh_per_page + 1); - reiserfs_write_unlock(s); - if (error) - goto fail; - } - BUG_ON(PageWriteback(page)); - set_page_writeback(page); - unlock_page(page); - - /* - * since any buffer might be the only dirty buffer on the page, - * the first submit_bh can bring the page out of writeback. - * be careful with the buffers. - */ - do { - struct buffer_head *next = bh->b_this_page; - if (buffer_async_write(bh)) { - submit_bh(WRITE, bh); - nr++; - } - put_bh(bh); - bh = next; - } while(bh != head); - - error = 0; -done: - if (nr == 0) { - /* - * if this page only had a direct item, it is very possible for - * no io to be required without there being an error. Or, - * someone else could have locked them and sent them down the - * pipe without locking the page + /* + * since any buffer might be the only dirty buffer on the page, + * the first submit_bh can bring the page out of writeback. + * be careful with the buffers. */ - bh = head ; do { - if (!buffer_uptodate(bh)) { - partial = 1; - break; - } - bh = bh->b_this_page; - } while(bh != head); - if (!partial) - SetPageUptodate(page); - end_page_writeback(page); - } - return error; - -fail: - /* catches various errors, we need to make sure any valid dirty blocks - * get to the media. The page is currently locked and not marked for - * writeback - */ - ClearPageUptodate(page); - bh = head; - do { - get_bh(bh); - if (buffer_mapped(bh) && buffer_dirty(bh) && bh->b_blocknr) { - lock_buffer(bh); - mark_buffer_async_write(bh); - } else { - /* - * clear any dirty bits that might have come from getting - * attached to a dirty page - */ - clear_buffer_dirty(bh); - } - bh = bh->b_this_page; - } while(bh != head); - SetPageError(page); - BUG_ON(PageWriteback(page)); - set_page_writeback(page); - unlock_page(page); - do { - struct buffer_head *next = bh->b_this_page; - if (buffer_async_write(bh)) { - clear_buffer_dirty(bh); - submit_bh(WRITE, bh); - nr++; - } - put_bh(bh); - bh = next; - } while(bh != head); - goto done; -} + struct buffer_head *next = bh->b_this_page; + if (buffer_async_write(bh)) { + submit_bh(WRITE, bh); + nr++; + } + put_bh(bh); + bh = next; + } while (bh != head); + error = 0; + done: + if (nr == 0) { + /* + * if this page only had a direct item, it is very possible for + * no io to be required without there being an error. Or, + * someone else could have locked them and sent them down the + * pipe without locking the page + */ + bh = head; + do { + if (!buffer_uptodate(bh)) { + partial = 1; + break; + } + bh = bh->b_this_page; + } while (bh != head); + if (!partial) + SetPageUptodate(page); + end_page_writeback(page); + } + return error; -static int reiserfs_readpage (struct file *f, struct page * page) -{ - return block_read_full_page (page, reiserfs_get_block); + fail: + /* catches various errors, we need to make sure any valid dirty blocks + * get to the media. The page is currently locked and not marked for + * writeback + */ + ClearPageUptodate(page); + bh = head; + do { + get_bh(bh); + if (buffer_mapped(bh) && buffer_dirty(bh) && bh->b_blocknr) { + lock_buffer(bh); + mark_buffer_async_write(bh); + } else { + /* + * clear any dirty bits that might have come from getting + * attached to a dirty page + */ + clear_buffer_dirty(bh); + } + bh = bh->b_this_page; + } while (bh != head); + SetPageError(page); + BUG_ON(PageWriteback(page)); + set_page_writeback(page); + unlock_page(page); + do { + struct buffer_head *next = bh->b_this_page; + if (buffer_async_write(bh)) { + clear_buffer_dirty(bh); + submit_bh(WRITE, bh); + nr++; + } + put_bh(bh); + bh = next; + } while (bh != head); + goto done; } +static int reiserfs_readpage(struct file *f, struct page *page) +{ + return block_read_full_page(page, reiserfs_get_block); +} -static int reiserfs_writepage (struct page * page, struct writeback_control *wbc) +static int reiserfs_writepage(struct page *page, struct writeback_control *wbc) { - struct inode *inode = page->mapping->host ; - reiserfs_wait_on_write_block(inode->i_sb) ; - return reiserfs_write_full_page(page, wbc) ; + struct inode *inode = page->mapping->host; + reiserfs_wait_on_write_block(inode->i_sb); + return reiserfs_write_full_page(page, wbc); } static int reiserfs_prepare_write(struct file *f, struct page *page, - unsigned from, unsigned to) { - struct inode *inode = page->mapping->host ; - int ret; - int old_ref = 0; - - reiserfs_wait_on_write_block(inode->i_sb) ; - fix_tail_page_for_writing(page) ; - if (reiserfs_transaction_running(inode->i_sb)) { - struct reiserfs_transaction_handle *th; - th = (struct reiserfs_transaction_handle *)current->journal_info; - BUG_ON (!th->t_refcount); - BUG_ON (!th->t_trans_id); - old_ref = th->t_refcount; - th->t_refcount++; - } - - ret = block_prepare_write(page, from, to, reiserfs_get_block) ; - if (ret && reiserfs_transaction_running(inode->i_sb)) { - struct reiserfs_transaction_handle *th = current->journal_info; - /* this gets a little ugly. If reiserfs_get_block returned an - * error and left a transacstion running, we've got to close it, - * and we've got to free handle if it was a persistent transaction. - * - * But, if we had nested into an existing transaction, we need - * to just drop the ref count on the handle. - * - * If old_ref == 0, the transaction is from reiserfs_get_block, - * and it was a persistent trans. Otherwise, it was nested above. - */ - if (th->t_refcount > old_ref) { - if (old_ref) - th->t_refcount--; - else { - int err; - reiserfs_write_lock(inode->i_sb); - err = reiserfs_end_persistent_transaction(th); - reiserfs_write_unlock(inode->i_sb); - if (err) - ret = err; - } + unsigned from, unsigned to) +{ + struct inode *inode = page->mapping->host; + int ret; + int old_ref = 0; + + reiserfs_wait_on_write_block(inode->i_sb); + fix_tail_page_for_writing(page); + if (reiserfs_transaction_running(inode->i_sb)) { + struct reiserfs_transaction_handle *th; + th = (struct reiserfs_transaction_handle *)current-> + journal_info; + BUG_ON(!th->t_refcount); + BUG_ON(!th->t_trans_id); + old_ref = th->t_refcount; + th->t_refcount++; } - } - return ret; -} + ret = block_prepare_write(page, from, to, reiserfs_get_block); + if (ret && reiserfs_transaction_running(inode->i_sb)) { + struct reiserfs_transaction_handle *th = current->journal_info; + /* this gets a little ugly. If reiserfs_get_block returned an + * error and left a transacstion running, we've got to close it, + * and we've got to free handle if it was a persistent transaction. + * + * But, if we had nested into an existing transaction, we need + * to just drop the ref count on the handle. + * + * If old_ref == 0, the transaction is from reiserfs_get_block, + * and it was a persistent trans. Otherwise, it was nested above. + */ + if (th->t_refcount > old_ref) { + if (old_ref) + th->t_refcount--; + else { + int err; + reiserfs_write_lock(inode->i_sb); + err = reiserfs_end_persistent_transaction(th); + reiserfs_write_unlock(inode->i_sb); + if (err) + ret = err; + } + } + } + return ret; +} -static sector_t reiserfs_aop_bmap(struct address_space *as, sector_t block) { - return generic_block_bmap(as, block, reiserfs_bmap) ; +static sector_t reiserfs_aop_bmap(struct address_space *as, sector_t block) +{ + return generic_block_bmap(as, block, reiserfs_bmap); } -static int reiserfs_commit_write(struct file *f, struct page *page, - unsigned from, unsigned to) { - struct inode *inode = page->mapping->host ; - loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; - int ret = 0; - int update_sd = 0; - struct reiserfs_transaction_handle *th = NULL; - - reiserfs_wait_on_write_block(inode->i_sb) ; - if (reiserfs_transaction_running(inode->i_sb)) { - th = current->journal_info; - } - reiserfs_commit_page(inode, page, from, to); - - /* generic_commit_write does this for us, but does not update the - ** transaction tracking stuff when the size changes. So, we have - ** to do the i_size updates here. - */ - if (pos > inode->i_size) { - struct reiserfs_transaction_handle myth ; - reiserfs_write_lock(inode->i_sb); - /* If the file have grown beyond the border where it - can have a tail, unmark it as needing a tail - packing */ - if ( (have_large_tails (inode->i_sb) && inode->i_size > i_block_size (inode)*4) || - (have_small_tails (inode->i_sb) && inode->i_size > i_block_size(inode)) ) - REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask ; - - ret = journal_begin(&myth, inode->i_sb, 1) ; - if (ret) { - reiserfs_write_unlock(inode->i_sb); - goto journal_error; - } - reiserfs_update_inode_transaction(inode) ; - inode->i_size = pos ; - reiserfs_update_sd(&myth, inode) ; - update_sd = 1; - ret = journal_end(&myth, inode->i_sb, 1) ; - reiserfs_write_unlock(inode->i_sb); - if (ret) - goto journal_error; - } - if (th) { - reiserfs_write_lock(inode->i_sb); - if (!update_sd) - reiserfs_update_sd(th, inode) ; - ret = reiserfs_end_persistent_transaction(th); - reiserfs_write_unlock(inode->i_sb); - if (ret) - goto out; - } - - /* we test for O_SYNC here so we can commit the transaction - ** for any packed tails the file might have had - */ - if (f && (f->f_flags & O_SYNC)) { - reiserfs_write_lock(inode->i_sb); - ret = reiserfs_commit_for_inode(inode) ; - reiserfs_write_unlock(inode->i_sb); - } -out: - return ret ; +static int reiserfs_commit_write(struct file *f, struct page *page, + unsigned from, unsigned to) +{ + struct inode *inode = page->mapping->host; + loff_t pos = ((loff_t) page->index << PAGE_CACHE_SHIFT) + to; + int ret = 0; + int update_sd = 0; + struct reiserfs_transaction_handle *th = NULL; + + reiserfs_wait_on_write_block(inode->i_sb); + if (reiserfs_transaction_running(inode->i_sb)) { + th = current->journal_info; + } + reiserfs_commit_page(inode, page, from, to); -journal_error: - if (th) { - reiserfs_write_lock(inode->i_sb); - if (!update_sd) - reiserfs_update_sd(th, inode) ; - ret = reiserfs_end_persistent_transaction(th); - reiserfs_write_unlock(inode->i_sb); - } + /* generic_commit_write does this for us, but does not update the + ** transaction tracking stuff when the size changes. So, we have + ** to do the i_size updates here. + */ + if (pos > inode->i_size) { + struct reiserfs_transaction_handle myth; + reiserfs_write_lock(inode->i_sb); + /* If the file have grown beyond the border where it + can have a tail, unmark it as needing a tail + packing */ + if ((have_large_tails(inode->i_sb) + && inode->i_size > i_block_size(inode) * 4) + || (have_small_tails(inode->i_sb) + && inode->i_size > i_block_size(inode))) + REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask; + + ret = journal_begin(&myth, inode->i_sb, 1); + if (ret) { + reiserfs_write_unlock(inode->i_sb); + goto journal_error; + } + reiserfs_update_inode_transaction(inode); + inode->i_size = pos; + reiserfs_update_sd(&myth, inode); + update_sd = 1; + ret = journal_end(&myth, inode->i_sb, 1); + reiserfs_write_unlock(inode->i_sb); + if (ret) + goto journal_error; + } + if (th) { + reiserfs_write_lock(inode->i_sb); + if (!update_sd) + reiserfs_update_sd(th, inode); + ret = reiserfs_end_persistent_transaction(th); + reiserfs_write_unlock(inode->i_sb); + if (ret) + goto out; + } + + /* we test for O_SYNC here so we can commit the transaction + ** for any packed tails the file might have had + */ + if (f && (f->f_flags & O_SYNC)) { + reiserfs_write_lock(inode->i_sb); + ret = reiserfs_commit_for_inode(inode); + reiserfs_write_unlock(inode->i_sb); + } + out: + return ret; - return ret; + journal_error: + if (th) { + reiserfs_write_lock(inode->i_sb); + if (!update_sd) + reiserfs_update_sd(th, inode); + ret = reiserfs_end_persistent_transaction(th); + reiserfs_write_unlock(inode->i_sb); + } + + return ret; } -void sd_attrs_to_i_attrs( __u16 sd_attrs, struct inode *inode ) +void sd_attrs_to_i_attrs(__u16 sd_attrs, struct inode *inode) { - if( reiserfs_attrs( inode -> i_sb ) ) { - if( sd_attrs & REISERFS_SYNC_FL ) - inode -> i_flags |= S_SYNC; + if (reiserfs_attrs(inode->i_sb)) { + if (sd_attrs & REISERFS_SYNC_FL) + inode->i_flags |= S_SYNC; else - inode -> i_flags &= ~S_SYNC; - if( sd_attrs & REISERFS_IMMUTABLE_FL ) - inode -> i_flags |= S_IMMUTABLE; + inode->i_flags &= ~S_SYNC; + if (sd_attrs & REISERFS_IMMUTABLE_FL) + inode->i_flags |= S_IMMUTABLE; else - inode -> i_flags &= ~S_IMMUTABLE; - if( sd_attrs & REISERFS_APPEND_FL ) - inode -> i_flags |= S_APPEND; + inode->i_flags &= ~S_IMMUTABLE; + if (sd_attrs & REISERFS_APPEND_FL) + inode->i_flags |= S_APPEND; else - inode -> i_flags &= ~S_APPEND; - if( sd_attrs & REISERFS_NOATIME_FL ) - inode -> i_flags |= S_NOATIME; + inode->i_flags &= ~S_APPEND; + if (sd_attrs & REISERFS_NOATIME_FL) + inode->i_flags |= S_NOATIME; else - inode -> i_flags &= ~S_NOATIME; - if( sd_attrs & REISERFS_NOTAIL_FL ) + inode->i_flags &= ~S_NOATIME; + if (sd_attrs & REISERFS_NOTAIL_FL) REISERFS_I(inode)->i_flags |= i_nopack_mask; else REISERFS_I(inode)->i_flags &= ~i_nopack_mask; } } -void i_attrs_to_sd_attrs( struct inode *inode, __u16 *sd_attrs ) +void i_attrs_to_sd_attrs(struct inode *inode, __u16 * sd_attrs) { - if( reiserfs_attrs( inode -> i_sb ) ) { - if( inode -> i_flags & S_IMMUTABLE ) + if (reiserfs_attrs(inode->i_sb)) { + if (inode->i_flags & S_IMMUTABLE) *sd_attrs |= REISERFS_IMMUTABLE_FL; else *sd_attrs &= ~REISERFS_IMMUTABLE_FL; - if( inode -> i_flags & S_SYNC ) + if (inode->i_flags & S_SYNC) *sd_attrs |= REISERFS_SYNC_FL; else *sd_attrs &= ~REISERFS_SYNC_FL; - if( inode -> i_flags & S_NOATIME ) + if (inode->i_flags & S_NOATIME) *sd_attrs |= REISERFS_NOATIME_FL; else *sd_attrs &= ~REISERFS_NOATIME_FL; - if( REISERFS_I(inode)->i_flags & i_nopack_mask ) + if (REISERFS_I(inode)->i_flags & i_nopack_mask) *sd_attrs |= REISERFS_NOTAIL_FL; else *sd_attrs &= ~REISERFS_NOTAIL_FL; @@ -2603,106 +2720,107 @@ void i_attrs_to_sd_attrs( struct inode *inode, __u16 *sd_attrs ) */ static int invalidatepage_can_drop(struct inode *inode, struct buffer_head *bh) { - int ret = 1 ; - struct reiserfs_journal *j = SB_JOURNAL(inode->i_sb) ; - - spin_lock(&j->j_dirty_buffers_lock) ; - if (!buffer_mapped(bh)) { - goto free_jh; - } - /* the page is locked, and the only places that log a data buffer - * also lock the page. - */ - if (reiserfs_file_data_log(inode)) { - /* - * very conservative, leave the buffer pinned if - * anyone might need it. - */ - if (buffer_journaled(bh) || buffer_journal_dirty(bh)) { - ret = 0 ; - } - } else - if (buffer_dirty(bh) || buffer_locked(bh)) { - struct reiserfs_journal_list *jl; - struct reiserfs_jh *jh = bh->b_private; - - /* why is this safe? - * reiserfs_setattr updates i_size in the on disk - * stat data before allowing vmtruncate to be called. - * - * If buffer was put onto the ordered list for this - * transaction, we know for sure either this transaction - * or an older one already has updated i_size on disk, - * and this ordered data won't be referenced in the file - * if we crash. - * - * if the buffer was put onto the ordered list for an older - * transaction, we need to leave it around + int ret = 1; + struct reiserfs_journal *j = SB_JOURNAL(inode->i_sb); + + spin_lock(&j->j_dirty_buffers_lock); + if (!buffer_mapped(bh)) { + goto free_jh; + } + /* the page is locked, and the only places that log a data buffer + * also lock the page. */ - if (jh && (jl = jh->jl) && jl != SB_JOURNAL(inode->i_sb)->j_current_jl) - ret = 0; - } -free_jh: - if (ret && bh->b_private) { - reiserfs_free_jh(bh); - } - spin_unlock(&j->j_dirty_buffers_lock) ; - return ret ; + if (reiserfs_file_data_log(inode)) { + /* + * very conservative, leave the buffer pinned if + * anyone might need it. + */ + if (buffer_journaled(bh) || buffer_journal_dirty(bh)) { + ret = 0; + } + } else if (buffer_dirty(bh) || buffer_locked(bh)) { + struct reiserfs_journal_list *jl; + struct reiserfs_jh *jh = bh->b_private; + + /* why is this safe? + * reiserfs_setattr updates i_size in the on disk + * stat data before allowing vmtruncate to be called. + * + * If buffer was put onto the ordered list for this + * transaction, we know for sure either this transaction + * or an older one already has updated i_size on disk, + * and this ordered data won't be referenced in the file + * if we crash. + * + * if the buffer was put onto the ordered list for an older + * transaction, we need to leave it around + */ + if (jh && (jl = jh->jl) + && jl != SB_JOURNAL(inode->i_sb)->j_current_jl) + ret = 0; + } + free_jh: + if (ret && bh->b_private) { + reiserfs_free_jh(bh); + } + spin_unlock(&j->j_dirty_buffers_lock); + return ret; } /* clm -- taken from fs/buffer.c:block_invalidate_page */ static int reiserfs_invalidatepage(struct page *page, unsigned long offset) { - struct buffer_head *head, *bh, *next; - struct inode *inode = page->mapping->host; - unsigned int curr_off = 0; - int ret = 1; + struct buffer_head *head, *bh, *next; + struct inode *inode = page->mapping->host; + unsigned int curr_off = 0; + int ret = 1; - BUG_ON(!PageLocked(page)); + BUG_ON(!PageLocked(page)); - if (offset == 0) - ClearPageChecked(page); + if (offset == 0) + ClearPageChecked(page); - if (!page_has_buffers(page)) - goto out; + if (!page_has_buffers(page)) + goto out; + + head = page_buffers(page); + bh = head; + do { + unsigned int next_off = curr_off + bh->b_size; + next = bh->b_this_page; - head = page_buffers(page); - bh = head; - do { - unsigned int next_off = curr_off + bh->b_size; - next = bh->b_this_page; + /* + * is this block fully invalidated? + */ + if (offset <= curr_off) { + if (invalidatepage_can_drop(inode, bh)) + reiserfs_unmap_buffer(bh); + else + ret = 0; + } + curr_off = next_off; + bh = next; + } while (bh != head); /* - * is this block fully invalidated? + * We release buffers only if the entire page is being invalidated. + * The get_block cached value has been unconditionally invalidated, + * so real IO is not possible anymore. */ - if (offset <= curr_off) { - if (invalidatepage_can_drop(inode, bh)) - reiserfs_unmap_buffer(bh); - else - ret = 0; - } - curr_off = next_off; - bh = next; - } while (bh != head); - - /* - * We release buffers only if the entire page is being invalidated. - * The get_block cached value has been unconditionally invalidated, - * so real IO is not possible anymore. - */ - if (!offset && ret) - ret = try_to_release_page(page, 0); -out: - return ret; + if (!offset && ret) + ret = try_to_release_page(page, 0); + out: + return ret; } -static int reiserfs_set_page_dirty(struct page *page) { - struct inode *inode = page->mapping->host; - if (reiserfs_file_data_log(inode)) { - SetPageChecked(page); - return __set_page_dirty_nobuffers(page); - } - return __set_page_dirty_buffers(page); +static int reiserfs_set_page_dirty(struct page *page) +{ + struct inode *inode = page->mapping->host; + if (reiserfs_file_data_log(inode)) { + SetPageChecked(page); + return __set_page_dirty_nobuffers(page); + } + return __set_page_dirty_buffers(page); } /* @@ -2716,143 +2834,152 @@ static int reiserfs_set_page_dirty(struct page *page) { */ static int reiserfs_releasepage(struct page *page, int unused_gfp_flags) { - struct inode *inode = page->mapping->host ; - struct reiserfs_journal *j = SB_JOURNAL(inode->i_sb) ; - struct buffer_head *head ; - struct buffer_head *bh ; - int ret = 1 ; - - WARN_ON(PageChecked(page)); - spin_lock(&j->j_dirty_buffers_lock) ; - head = page_buffers(page) ; - bh = head ; - do { - if (bh->b_private) { - if (!buffer_dirty(bh) && !buffer_locked(bh)) { - reiserfs_free_jh(bh); - } else { - ret = 0 ; - break ; - } - } - bh = bh->b_this_page ; - } while (bh != head) ; - if (ret) - ret = try_to_free_buffers(page) ; - spin_unlock(&j->j_dirty_buffers_lock) ; - return ret ; + struct inode *inode = page->mapping->host; + struct reiserfs_journal *j = SB_JOURNAL(inode->i_sb); + struct buffer_head *head; + struct buffer_head *bh; + int ret = 1; + + WARN_ON(PageChecked(page)); + spin_lock(&j->j_dirty_buffers_lock); + head = page_buffers(page); + bh = head; + do { + if (bh->b_private) { + if (!buffer_dirty(bh) && !buffer_locked(bh)) { + reiserfs_free_jh(bh); + } else { + ret = 0; + break; + } + } + bh = bh->b_this_page; + } while (bh != head); + if (ret) + ret = try_to_free_buffers(page); + spin_unlock(&j->j_dirty_buffers_lock); + return ret; } /* We thank Mingming Cao for helping us understand in great detail what to do in this section of the code. */ static ssize_t reiserfs_direct_IO(int rw, struct kiocb *iocb, - const struct iovec *iov, loff_t offset, unsigned long nr_segs) + const struct iovec *iov, loff_t offset, + unsigned long nr_segs) { - struct file *file = iocb->ki_filp; - struct inode *inode = file->f_mapping->host; + struct file *file = iocb->ki_filp; + struct inode *inode = file->f_mapping->host; - return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, - offset, nr_segs, reiserfs_get_blocks_direct_io, NULL); + return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, + offset, nr_segs, + reiserfs_get_blocks_direct_io, NULL); } -int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) { - struct inode *inode = dentry->d_inode ; - int error ; - unsigned int ia_valid = attr->ia_valid; - reiserfs_write_lock(inode->i_sb); - if (attr->ia_valid & ATTR_SIZE) { - /* version 2 items will be caught by the s_maxbytes check - ** done for us in vmtruncate - */ - if (get_inode_item_key_version(inode) == KEY_FORMAT_3_5 && - attr->ia_size > MAX_NON_LFS) { - error = -EFBIG ; - goto out; - } - /* fill in hole pointers in the expanding truncate case. */ - if (attr->ia_size > inode->i_size) { - error = generic_cont_expand(inode, attr->ia_size) ; - if (REISERFS_I(inode)->i_prealloc_count > 0) { - int err; - struct reiserfs_transaction_handle th ; - /* we're changing at most 2 bitmaps, inode + super */ - err = journal_begin(&th, inode->i_sb, 4) ; - if (!err) { - reiserfs_discard_prealloc (&th, inode); - err = journal_end(&th, inode->i_sb, 4) ; +int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) +{ + struct inode *inode = dentry->d_inode; + int error; + unsigned int ia_valid = attr->ia_valid; + reiserfs_write_lock(inode->i_sb); + if (attr->ia_valid & ATTR_SIZE) { + /* version 2 items will be caught by the s_maxbytes check + ** done for us in vmtruncate + */ + if (get_inode_item_key_version(inode) == KEY_FORMAT_3_5 && + attr->ia_size > MAX_NON_LFS) { + error = -EFBIG; + goto out; + } + /* fill in hole pointers in the expanding truncate case. */ + if (attr->ia_size > inode->i_size) { + error = generic_cont_expand(inode, attr->ia_size); + if (REISERFS_I(inode)->i_prealloc_count > 0) { + int err; + struct reiserfs_transaction_handle th; + /* we're changing at most 2 bitmaps, inode + super */ + err = journal_begin(&th, inode->i_sb, 4); + if (!err) { + reiserfs_discard_prealloc(&th, inode); + err = journal_end(&th, inode->i_sb, 4); + } + if (err) + error = err; + } + if (error) + goto out; } - if (err) - error = err; - } - if (error) - goto out; } - } - if ((((attr->ia_valid & ATTR_UID) && (attr->ia_uid & ~0xffff)) || - ((attr->ia_valid & ATTR_GID) && (attr->ia_gid & ~0xffff))) && - (get_inode_sd_version (inode) == STAT_DATA_V1)) { + if ((((attr->ia_valid & ATTR_UID) && (attr->ia_uid & ~0xffff)) || + ((attr->ia_valid & ATTR_GID) && (attr->ia_gid & ~0xffff))) && + (get_inode_sd_version(inode) == STAT_DATA_V1)) { /* stat data of format v3.5 has 16 bit uid and gid */ - error = -EINVAL; - goto out; - } - - error = inode_change_ok(inode, attr) ; - if (!error) { - if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || - (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) { - error = reiserfs_chown_xattrs (inode, attr); - - if (!error) { - struct reiserfs_transaction_handle th; - int jbegin_count = 2*(REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb)+REISERFS_QUOTA_DEL_BLOCKS(inode->i_sb))+2; - - /* (user+group)*(old+new) structure - we count quota info and , inode write (sb, inode) */ - error = journal_begin(&th, inode->i_sb, jbegin_count); - if (error) - goto out; - error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0; - if (error) { - journal_end(&th, inode->i_sb, jbegin_count); - goto out; - } - /* Update corresponding info in inode so that everything is in - * one transaction */ - if (attr->ia_valid & ATTR_UID) - inode->i_uid = attr->ia_uid; - if (attr->ia_valid & ATTR_GID) - inode->i_gid = attr->ia_gid; - mark_inode_dirty(inode); - error = journal_end(&th, inode->i_sb, jbegin_count); - } - } - if (!error) - error = inode_setattr(inode, attr) ; - } + error = -EINVAL; + goto out; + } + error = inode_change_ok(inode, attr); + if (!error) { + if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || + (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) { + error = reiserfs_chown_xattrs(inode, attr); + + if (!error) { + struct reiserfs_transaction_handle th; + int jbegin_count = + 2 * + (REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb) + + REISERFS_QUOTA_DEL_BLOCKS(inode->i_sb)) + + 2; + + /* (user+group)*(old+new) structure - we count quota info and , inode write (sb, inode) */ + error = + journal_begin(&th, inode->i_sb, + jbegin_count); + if (error) + goto out; + error = + DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0; + if (error) { + journal_end(&th, inode->i_sb, + jbegin_count); + goto out; + } + /* Update corresponding info in inode so that everything is in + * one transaction */ + if (attr->ia_valid & ATTR_UID) + inode->i_uid = attr->ia_uid; + if (attr->ia_valid & ATTR_GID) + inode->i_gid = attr->ia_gid; + mark_inode_dirty(inode); + error = + journal_end(&th, inode->i_sb, jbegin_count); + } + } + if (!error) + error = inode_setattr(inode, attr); + } - if (!error && reiserfs_posixacl (inode->i_sb)) { - if (attr->ia_valid & ATTR_MODE) - error = reiserfs_acl_chmod (inode); - } + if (!error && reiserfs_posixacl(inode->i_sb)) { + if (attr->ia_valid & ATTR_MODE) + error = reiserfs_acl_chmod(inode); + } -out: - reiserfs_write_unlock(inode->i_sb); - return error ; + out: + reiserfs_write_unlock(inode->i_sb); + return error; } - - struct address_space_operations reiserfs_address_space_operations = { - .writepage = reiserfs_writepage, - .readpage = reiserfs_readpage, - .readpages = reiserfs_readpages, - .releasepage = reiserfs_releasepage, - .invalidatepage = reiserfs_invalidatepage, - .sync_page = block_sync_page, - .prepare_write = reiserfs_prepare_write, - .commit_write = reiserfs_commit_write, - .bmap = reiserfs_aop_bmap, - .direct_IO = reiserfs_direct_IO, - .set_page_dirty = reiserfs_set_page_dirty, -} ; + .writepage = reiserfs_writepage, + .readpage = reiserfs_readpage, + .readpages = reiserfs_readpages, + .releasepage = reiserfs_releasepage, + .invalidatepage = reiserfs_invalidatepage, + .sync_page = block_sync_page, + .prepare_write = reiserfs_prepare_write, + .commit_write = reiserfs_commit_write, + .bmap = reiserfs_aop_bmap, + .direct_IO = reiserfs_direct_IO, + .set_page_dirty = reiserfs_set_page_dirty, +}; |