X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Freiserfs%2Finode.c;h=d44d122480109bc490b917a4b28a287374b7c33a;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=72abbaa61451488626093dedf328884d0ec8c1ad;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 72abbaa61..d44d12248 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -21,48 +21,56 @@ extern int reiserfs_default_io_size; /* default io size devuned in super.c */ -/* args for the create parameter of reiserfs_get_block */ -#define GET_BLOCK_NO_CREATE 0 /* don't create new blocks or convert tails */ -#define GET_BLOCK_CREATE 1 /* add anything you need to find block */ -#define GET_BLOCK_NO_HOLE 2 /* return -ENOENT for file holes */ -#define GET_BLOCK_READ_DIRECT 4 /* read the tail if indirect item not found */ -#define GET_BLOCK_NO_ISEM 8 /* i_sem is not held, don't preallocate */ -#define GET_BLOCK_NO_DANGLE 16 /* don't leave any transactions running */ - -static int reiserfs_get_block (struct inode * inode, sector_t block, - struct buffer_head * bh_result, int create); static int reiserfs_commit_write(struct file *f, struct page *page, 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) { - int jbegin_count = JOURNAL_PER_BALANCE_CNT * 2; + /* We need blocks for transaction + (user+group) quota update (possibly delete) */ + int jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2 * REISERFS_QUOTA_INIT_BLOCKS; struct reiserfs_transaction_handle th ; reiserfs_write_lock(inode->i_sb); - DQUOT_FREE_INODE(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); reiserfs_delete_xattrs (inode); - journal_begin(&th, inode->i_sb, jbegin_count) ; + if (journal_begin(&th, inode->i_sb, jbegin_count)) { + up (&inode->i_sem); + goto out; + } reiserfs_update_inode_transaction(inode) ; - reiserfs_delete_object (&th, inode); + if (reiserfs_delete_object (&th, inode)) { + 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); - journal_end(&th, inode->i_sb, jbegin_count) ; + if (journal_end(&th, inode->i_sb, jbegin_count)) { + up (&inode->i_sem); + goto out; + } up (&inode->i_sem); /* all items of file are deleted, so we can remove "save" link */ - remove_save_link (inode, 0/* not truncate */); + 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); @@ -202,20 +210,28 @@ static int file_capable (struct inode * inode, long block) return 0; } -/*static*/ void restart_transaction(struct reiserfs_transaction_handle *th, +/*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 ; + return 0 ; } pathrelse(path) ; reiserfs_update_sd(th, inode) ; - journal_end(th, s, len) ; - journal_begin(th, s, JOURNAL_PER_BALANCE_CNT * 6) ; - reiserfs_update_inode_transaction(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 @@ -390,8 +406,8 @@ finished: // this is called to create file map. So, _get_block_create_0 will not // read direct item -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; @@ -444,9 +460,11 @@ static int reiserfs_get_blocks_direct_io(struct inode *inode, 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 (ret == 0 && buffer_mapped(bh_result) && bh_result->b_blocknr == 0) { + 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 */ @@ -456,11 +474,15 @@ static int reiserfs_get_blocks_direct_io(struct inode *inode, /* 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(); - reiserfs_commit_for_inode(inode); + 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 ; } @@ -540,6 +562,7 @@ static inline int _allocate_block(struct reiserfs_transaction_handle *th, 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)) { @@ -552,7 +575,7 @@ static inline int _allocate_block(struct reiserfs_transaction_handle *th, int reiserfs_get_block (struct inode * inode, sector_t block, struct buffer_head * bh_result, int create) { - int repeat, retval; + 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; @@ -567,8 +590,9 @@ int reiserfs_get_block (struct inode * inode, sector_t block, . 3 balancings in direct->indirect conversion . 1 block involved into reiserfs_update_sd() XXX in practically impossible worst case direct2indirect() - can incur (much) more that 3 balancings. */ - int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 1; + 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; int version; int dangle = 1; loff_t new_offset = (((loff_t)block) << inode->i_sb->s_blocksize_bits) + 1 ; @@ -656,7 +680,9 @@ start_trans: ** research if we succeed on the second try */ SB_JOURNAL(inode->i_sb)->j_next_async_flush = 1; - restart_transaction(th, inode, &path) ; + 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) { @@ -697,8 +723,9 @@ start_trans: } set_block_dev_mapped(bh_result, unfm_ptr, inode); pathrelse (&path); + retval = 0; if (!dangle && th) - reiserfs_end_persistent_transaction(th); + retval = reiserfs_end_persistent_transaction(th); reiserfs_write_unlock(inode->i_sb); @@ -706,7 +733,7 @@ start_trans: ** there is no need to make sure the inode is updated with this ** transaction */ - return 0; + return retval; } if (!th) { @@ -767,9 +794,12 @@ start_trans: * ugly, but we can only end the transaction if * we aren't nested */ + BUG_ON (!th->t_refcount); if (th->t_refcount == 1) { - reiserfs_end_persistent_transaction(th); + retval = reiserfs_end_persistent_transaction(th); th = NULL; + if (retval) + goto failure; } retval = convert_tail_for_hole(inode, bh_result, tail_offset) ; @@ -899,7 +929,9 @@ start_trans: ** ending their transaction will be able to continue. */ if (journal_transaction_should_end(th, th->t_blocks_allocated)) { - restart_transaction(th, inode, &path) ; + retval = restart_transaction(th, inode, &path) ; + if (retval) + goto failure; } /* inserting indirect pointers for a hole can take a ** long time. reschedule if needed @@ -930,10 +962,15 @@ start_trans: retval = 0; failure: - if (th && !dangle) { - reiserfs_update_sd(th, inode) ; - reiserfs_end_persistent_transaction(th); + 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; @@ -1225,6 +1262,8 @@ void reiserfs_update_sd_size (struct reiserfs_transaction_handle *th, 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(;;) { @@ -1418,12 +1457,14 @@ struct dentry *reiserfs_get_dentry(struct super_block *sb, void *vobjp) 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)) @@ -1518,12 +1559,8 @@ 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) { - reiserfs_warning (inode->i_sb, - "clm-6005: writing inode %lu on readonly FS", - inode->i_ino) ; + 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 @@ -1531,24 +1568,15 @@ int reiserfs_write_inode (struct inode * inode, int do_sync) { */ if (do_sync && !(current->flags & PF_MEMALLOC)) { reiserfs_write_lock(inode->i_sb); - journal_begin(&th, inode->i_sb, jbegin_count) ; - reiserfs_update_sd (&th, inode); - journal_end_sync(&th, inode->i_sb, jbegin_count) ; + 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; } -/* FIXME: no need any more. right? */ -int reiserfs_sync_inode (struct reiserfs_transaction_handle *th, struct inode * inode) -{ - int err = 0; - - reiserfs_update_sd (th, inode); - return err; -} - - /* 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, @@ -1561,6 +1589,8 @@ static int reiserfs_new_directory (struct reiserfs_transaction_handle *th, 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*/); @@ -1612,6 +1642,8 @@ static int reiserfs_new_symlink (struct reiserfs_transaction_handle *th, 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), @@ -1662,7 +1694,13 @@ int reiserfs_new_inode (struct reiserfs_transaction_handle *th, 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; @@ -1700,7 +1738,8 @@ int reiserfs_new_inode (struct reiserfs_transaction_handle *th, if( S_ISLNK( inode -> i_mode ) ) inode -> i_flags &= ~ ( S_IMMUTABLE | S_APPEND ); - inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + 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; @@ -1830,9 +1869,12 @@ out_bad_inode: /* Invalidate the object, nothing was inserted yet */ INODE_PKEY(inode)->k_objectid = 0; - /* dquot_drop must be done outside a transaction */ - journal_end(th, th->t_super, th->t_blocks_allocated) ; + /* 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); @@ -1936,7 +1978,7 @@ unlock: ** ** some code taken from block_truncate_page */ -void reiserfs_truncate_file(struct inode *p_s_inode, int update_timestamps) { +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) ; @@ -1972,18 +2014,28 @@ void reiserfs_truncate_file(struct inode *p_s_inode, int update_timestamps) { /* 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 */ - journal_begin(&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 + 1 ) ; + 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); - reiserfs_do_truncate (&th, p_s_inode, page, update_timestamps) ; - journal_end(&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 + 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) - remove_save_link (p_s_inode, 1/* truncate */); + if (update_timestamps) { + error = remove_save_link (p_s_inode, 1/* truncate */); + if (error) + goto out; + } if (page) { length = offset & (blocksize - 1) ; @@ -2005,6 +2057,14 @@ void reiserfs_truncate_file(struct inode *p_s_inode, int update_timestamps) { } 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, @@ -2074,7 +2134,9 @@ research: if (!trans_running) { /* vs-3050 is gone, no need to drop the path */ - journal_begin(&th, inode->i_sb, jbegin_count) ; + 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)) { @@ -2114,7 +2176,9 @@ research: out: pathrelse(&path) ; if (trans_running) { - journal_end(&th, inode->i_sb, jbegin_count) ; + int err = journal_end(&th, inode->i_sb, jbegin_count) ; + if (err) + retval = err; trans_running = 0; } reiserfs_write_unlock(inode->i_sb); @@ -2220,7 +2284,11 @@ static int reiserfs_write_full_page(struct page *page, struct writeback_control if (checked) { ClearPageChecked(page); reiserfs_write_lock(s); - journal_begin(&th, s, bh_per_page + 1); + 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 */ @@ -2255,8 +2323,10 @@ static int reiserfs_write_full_page(struct page *page, struct writeback_control } while((bh = bh->b_this_page) != head); if (checked) { - journal_end(&th, s, bh_per_page + 1); + 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); @@ -2352,7 +2422,7 @@ static int reiserfs_writepage (struct page * page, struct writeback_control *wbc return reiserfs_write_full_page(page, wbc) ; } -int reiserfs_prepare_write(struct file *f, struct page *page, +static int reiserfs_prepare_write(struct file *f, struct page *page, unsigned from, unsigned to) { struct inode *inode = page->mapping->host ; int ret; @@ -2362,7 +2432,9 @@ int reiserfs_prepare_write(struct file *f, struct page *page, 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; + 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++; } @@ -2384,9 +2456,12 @@ int reiserfs_prepare_write(struct file *f, struct page *page, if (old_ref) th->t_refcount--; else { + int err; reiserfs_write_lock(inode->i_sb); - reiserfs_end_persistent_transaction(th); + err = reiserfs_end_persistent_transaction(th); reiserfs_write_unlock(inode->i_sb); + if (err) + ret = err; } } } @@ -2427,20 +2502,28 @@ static int reiserfs_commit_write(struct file *f, struct page *page, (have_small_tails (inode->i_sb) && inode->i_size > i_block_size(inode)) ) REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask ; - journal_begin(&myth, inode->i_sb, 1) ; + 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; - journal_end(&myth, inode->i_sb, 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) ; - reiserfs_end_persistent_transaction(th); + 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 @@ -2448,10 +2531,22 @@ static int reiserfs_commit_write(struct file *f, struct page *page, */ if (f && (f->f_flags & O_SYNC)) { reiserfs_write_lock(inode->i_sb); - reiserfs_commit_for_inode(inode) ; + ret = reiserfs_commit_for_inode(inode) ; reiserfs_write_unlock(inode->i_sb); } +out: 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 ) @@ -2714,11 +2809,16 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) { 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 */ - journal_begin(&th, inode->i_sb, 4) ; - reiserfs_discard_prealloc (&th, inode); - journal_end(&th, inode->i_sb, 4) ; + 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; @@ -2743,8 +2843,25 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) { (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) { error = reiserfs_chown_xattrs (inode, attr); - if (!error) + if (!error) { + struct reiserfs_transaction_handle th; + + /* (user+group)*(old+new) structure - we count quota info and , inode write (sb, inode) */ + journal_begin(&th, inode->i_sb, 4*REISERFS_QUOTA_INIT_BLOCKS+2); error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0; + if (error) { + journal_end(&th, inode->i_sb, 4*REISERFS_QUOTA_INIT_BLOCKS+2); + 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); + journal_end(&th, inode->i_sb, 4*REISERFS_QUOTA_INIT_BLOCKS+2); + } } if (!error) error = inode_setattr(inode, attr) ;