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);
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
// 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;
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
*/
/* 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 ;
}
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)) {
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;
. 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 ;
** 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) {
}
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);
** there is no need to make sure the inode is updated with this
** transaction
*/
- return 0;
+ return retval;
}
if (!th) {
* 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) ;
** 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
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;
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(;;) {
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))
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
*/
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,
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*/);
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),
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;
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;
/* 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);
**
** 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) ;
/* 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) ;
}
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,
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)) {
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);
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 */
} 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);
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;
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++;
}
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;
}
}
}
(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
*/
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 )
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;
(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) ;