Commit 446a7461 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] reiserfs: quota support

From: Chris Mason <mason@suse.com>

ReiserFS support for quotas.  Originally from Jan Kara
parent 30304fc9
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/reiserfs_fs_sb.h> #include <linux/reiserfs_fs_sb.h>
#include <linux/reiserfs_fs_i.h> #include <linux/reiserfs_fs_i.h>
#include <linux/quotaops.h>
#define PREALLOCATION_SIZE 9 #define PREALLOCATION_SIZE 9
...@@ -281,7 +282,8 @@ static int scan_bitmap (struct reiserfs_transaction_handle *th, ...@@ -281,7 +282,8 @@ static int scan_bitmap (struct reiserfs_transaction_handle *th,
} }
static void _reiserfs_free_block (struct reiserfs_transaction_handle *th, static void _reiserfs_free_block (struct reiserfs_transaction_handle *th,
b_blocknr_t block) struct inode *inode, b_blocknr_t block,
int for_unformatted)
{ {
struct super_block * s = th->t_super; struct super_block * s = th->t_super;
struct reiserfs_super_block * rs; struct reiserfs_super_block * rs;
...@@ -323,11 +325,13 @@ static void _reiserfs_free_block (struct reiserfs_transaction_handle *th, ...@@ -323,11 +325,13 @@ static void _reiserfs_free_block (struct reiserfs_transaction_handle *th,
set_sb_free_blocks( rs, sb_free_blocks(rs) + 1 ); set_sb_free_blocks( rs, sb_free_blocks(rs) + 1 );
journal_mark_dirty (th, s, sbh); journal_mark_dirty (th, s, sbh);
s->s_dirt = 1; if (for_unformatted)
DQUOT_FREE_BLOCK_NODIRTY(inode, 1);
} }
void reiserfs_free_block (struct reiserfs_transaction_handle *th, void reiserfs_free_block (struct reiserfs_transaction_handle *th,
b_blocknr_t block) struct inode *inode, b_blocknr_t block,
int for_unformatted)
{ {
struct super_block * s = th->t_super; struct super_block * s = th->t_super;
...@@ -335,42 +339,46 @@ void reiserfs_free_block (struct reiserfs_transaction_handle *th, ...@@ -335,42 +339,46 @@ void reiserfs_free_block (struct reiserfs_transaction_handle *th,
RFALSE(is_reusable (s, block, 1) == 0, "vs-4071: can not free such block"); RFALSE(is_reusable (s, block, 1) == 0, "vs-4071: can not free such block");
/* mark it before we clear it, just in case */ /* mark it before we clear it, just in case */
journal_mark_freed(th, s, block) ; journal_mark_freed(th, s, block) ;
_reiserfs_free_block(th, block) ; _reiserfs_free_block(th, inode, block, for_unformatted) ;
} }
/* preallocated blocks don't need to be run through journal_mark_freed */ /* preallocated blocks don't need to be run through journal_mark_freed */
void reiserfs_free_prealloc_block (struct reiserfs_transaction_handle *th, void reiserfs_free_prealloc_block (struct reiserfs_transaction_handle *th,
b_blocknr_t block) { struct inode *inode, b_blocknr_t block) {
RFALSE(!th->t_super, "vs-4060: trying to free block on nonexistent device"); RFALSE(!th->t_super, "vs-4060: trying to free block on nonexistent device");
RFALSE(is_reusable (th->t_super, block, 1) == 0, "vs-4070: can not free such block"); RFALSE(is_reusable (th->t_super, block, 1) == 0, "vs-4070: can not free such block");
_reiserfs_free_block(th, block) ; _reiserfs_free_block(th, inode, block, 1) ;
} }
static void __discard_prealloc (struct reiserfs_transaction_handle * th, static void __discard_prealloc (struct reiserfs_transaction_handle * th,
struct reiserfs_inode_info *ei) struct reiserfs_inode_info *ei)
{ {
unsigned long save = ei->i_prealloc_block ; unsigned long save = ei->i_prealloc_block ;
int dirty = 0;
struct inode *inode = &ei->vfs_inode;
#ifdef CONFIG_REISERFS_CHECK #ifdef CONFIG_REISERFS_CHECK
if (ei->i_prealloc_count < 0) if (ei->i_prealloc_count < 0)
reiserfs_warning("zam-4001:%s: inode has negative prealloc blocks count.\n", __FUNCTION__ ); reiserfs_warning("zam-4001:%s: inode has negative prealloc blocks count.\n", __FUNCTION__ );
#endif #endif
while (ei->i_prealloc_count > 0) { while (ei->i_prealloc_count > 0) {
reiserfs_free_prealloc_block(th,ei->i_prealloc_block); reiserfs_free_prealloc_block(th, inode, ei->i_prealloc_block);
ei->i_prealloc_block++; ei->i_prealloc_block++;
ei->i_prealloc_count --; ei->i_prealloc_count --;
dirty = 1;
} }
if (dirty)
reiserfs_update_sd(th, inode);
ei->i_prealloc_block = save; ei->i_prealloc_block = save;
list_del_init(&(ei->i_prealloc_list)); list_del_init(&(ei->i_prealloc_list));
} }
/* FIXME: It should be inline function */ /* FIXME: It should be inline function */
void reiserfs_discard_prealloc (struct reiserfs_transaction_handle *th, void reiserfs_discard_prealloc (struct reiserfs_transaction_handle *th,
struct inode * inode) struct inode *inode)
{ {
struct reiserfs_inode_info *ei = REISERFS_I(inode); struct reiserfs_inode_info *ei = REISERFS_I(inode);
if (ei->i_prealloc_count) { if (ei->i_prealloc_count)
__discard_prealloc(th, ei); __discard_prealloc(th, ei);
}
} }
void reiserfs_discard_all_prealloc (struct reiserfs_transaction_handle *th) void reiserfs_discard_all_prealloc (struct reiserfs_transaction_handle *th)
...@@ -772,6 +780,24 @@ static inline int blocknrs_and_prealloc_arrays_from_search_start ...@@ -772,6 +780,24 @@ static inline int blocknrs_and_prealloc_arrays_from_search_start
int nr_allocated = 0; int nr_allocated = 0;
determine_prealloc_size(hint); determine_prealloc_size(hint);
if (!hint->formatted_node) {
int quota_ret;
#ifdef REISERQUOTA_DEBUG
printk(KERN_DEBUG "reiserquota: allocating %d blocks id=%u\n", amount_needed, hint->inode->i_uid);
#endif
quota_ret = DQUOT_ALLOC_BLOCK_NODIRTY(hint->inode, amount_needed);
if (quota_ret) /* Quota exceeded? */
return QUOTA_EXCEEDED;
if (hint->preallocate && hint->prealloc_size ) {
#ifdef REISERQUOTA_DEBUG
printk(KERN_DEBUG "reiserquota: allocating (prealloc) %d blocks id=%u\n", hint->prealloc_size, hint->inode->i_uid);
#endif
quota_ret = DQUOT_PREALLOC_BLOCK_NODIRTY(hint->inode, hint->prealloc_size);
if (quota_ret)
hint->preallocate=hint->prealloc_size=0;
}
}
while((nr_allocated while((nr_allocated
+= allocate_without_wrapping_disk(hint, new_blocknrs + nr_allocated, start, finish, += allocate_without_wrapping_disk(hint, new_blocknrs + nr_allocated, start, finish,
amount_needed - nr_allocated, hint->prealloc_size)) amount_needed - nr_allocated, hint->prealloc_size))
...@@ -779,8 +805,14 @@ static inline int blocknrs_and_prealloc_arrays_from_search_start ...@@ -779,8 +805,14 @@ static inline int blocknrs_and_prealloc_arrays_from_search_start
/* not all blocks were successfully allocated yet*/ /* not all blocks were successfully allocated yet*/
if (second_pass) { /* it was a second pass; we must free all blocks */ if (second_pass) { /* it was a second pass; we must free all blocks */
if (!hint->formatted_node) {
#ifdef REISERQUOTA_DEBUG
printk(KERN_DEBUG "reiserquota: freeing (nospace) %d blocks id=%u\n", amount_needed + hint->prealloc_size - nr_allocated, hint->inode->i_uid);
#endif
DQUOT_FREE_BLOCK_NODIRTY(hint->inode, amount_needed + hint->prealloc_size - nr_allocated); /* Free not allocated blocks */
}
while (nr_allocated --) while (nr_allocated --)
reiserfs_free_block(hint->th, new_blocknrs[nr_allocated]); reiserfs_free_block(hint->th, hint->inode, new_blocknrs[nr_allocated], !hint->formatted_node);
return NO_DISK_SPACE; return NO_DISK_SPACE;
} else { /* refine search parameters for next pass */ } else { /* refine search parameters for next pass */
...@@ -790,6 +822,18 @@ static inline int blocknrs_and_prealloc_arrays_from_search_start ...@@ -790,6 +822,18 @@ static inline int blocknrs_and_prealloc_arrays_from_search_start
continue; continue;
} }
} }
if ( !hint->formatted_node &&
amount_needed + hint->prealloc_size >
nr_allocated + REISERFS_I(hint->inode)->i_prealloc_count) {
/* Some of preallocation blocks were not allocated */
#ifdef REISERQUOTA_DEBUG
printk(KERN_DEBUG "reiserquota: freeing (failed prealloc) %d blocks id=%u\n", amount_needed + hint->prealloc_size - nr_allocated - INODE_INFO(hint->inode)->i_prealloc_count, hint->inode->i_uid);
#endif
DQUOT_FREE_BLOCK_NODIRTY(hint->inode, amount_needed +
hint->prealloc_size - nr_allocated -
REISERFS_I(hint->inode)->i_prealloc_count);
}
return CARRY_ON; return CARRY_ON;
} }
...@@ -858,7 +902,7 @@ int reiserfs_allocate_blocknrs(reiserfs_blocknr_hint_t *hint, ...@@ -858,7 +902,7 @@ int reiserfs_allocate_blocknrs(reiserfs_blocknr_hint_t *hint,
if (ret != CARRY_ON) { if (ret != CARRY_ON) {
while (amount_needed ++ < initial_amount_needed) { while (amount_needed ++ < initial_amount_needed) {
reiserfs_free_block(hint->th, *(--new_blocknrs)); reiserfs_free_block(hint->th, hint->inode, *(--new_blocknrs), 1);
} }
} }
return ret; return ret;
......
...@@ -1234,7 +1234,7 @@ static void free_thrown(struct tree_balance *tb) { ...@@ -1234,7 +1234,7 @@ static void free_thrown(struct tree_balance *tb) {
if (buffer_dirty (tb->thrown[i])) if (buffer_dirty (tb->thrown[i]))
printk ("free_thrown deals with dirty buffer %d\n", blocknr); printk ("free_thrown deals with dirty buffer %d\n", blocknr);
brelse(tb->thrown[i]) ; /* incremented in store_thrown */ brelse(tb->thrown[i]) ; /* incremented in store_thrown */
reiserfs_free_block (tb->transaction_handle, blocknr); reiserfs_free_block (tb->transaction_handle, NULL, blocknr, 0);
} }
} }
} }
...@@ -1247,10 +1247,6 @@ void reiserfs_invalidate_buffer (struct tree_balance * tb, struct buffer_head * ...@@ -1247,10 +1247,6 @@ void reiserfs_invalidate_buffer (struct tree_balance * tb, struct buffer_head *
set_blkh_nr_item( blkh, 0 ); set_blkh_nr_item( blkh, 0 );
clear_buffer_dirty(bh); clear_buffer_dirty(bh);
/* reiserfs_free_block is no longer schedule safe
reiserfs_free_block (tb->transaction_handle, tb->tb_sb, bh->b_blocknr);
*/
store_thrown (tb, bh); store_thrown (tb, bh);
} }
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/writeback.h> #include <linux/writeback.h>
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/quotaops.h>
/* /*
** We pack the tails of files on file close, not at the time they are written. ** We pack the tails of files on file close, not at the time they are written.
...@@ -274,7 +275,7 @@ int reiserfs_allocate_blocks_for_region( ...@@ -274,7 +275,7 @@ int reiserfs_allocate_blocks_for_region(
/* Ok, there is existing indirect item already. Need to append it */ /* Ok, there is existing indirect item already. Need to append it */
/* Calculate position past inserted item */ /* Calculate position past inserted item */
make_cpu_key( &key, inode, le_key_k_offset( get_inode_item_key_version(inode), &(ih->ih_key)) + op_bytes_number(ih, inode->i_sb->s_blocksize), TYPE_INDIRECT, 3); make_cpu_key( &key, inode, le_key_k_offset( get_inode_item_key_version(inode), &(ih->ih_key)) + op_bytes_number(ih, inode->i_sb->s_blocksize), TYPE_INDIRECT, 3);
res = reiserfs_paste_into_item( th, &path, &key, (char *)zeros, UNFM_P_SIZE*to_paste); res = reiserfs_paste_into_item( th, &path, &key, inode, (char *)zeros, UNFM_P_SIZE*to_paste);
if ( res ) { if ( res ) {
kfree(zeros); kfree(zeros);
goto error_exit_free_blocks; goto error_exit_free_blocks;
...@@ -304,7 +305,7 @@ int reiserfs_allocate_blocks_for_region( ...@@ -304,7 +305,7 @@ int reiserfs_allocate_blocks_for_region(
kfree(zeros); kfree(zeros);
goto error_exit_free_blocks; goto error_exit_free_blocks;
} }
res = reiserfs_insert_item( th, &path, &key, &ins_ih, (char *)zeros); res = reiserfs_insert_item( th, &path, &key, &ins_ih, inode, (char *)zeros);
} else { } else {
reiserfs_panic(inode->i_sb, "green-9011: Unexpected key type %K\n", &key); reiserfs_panic(inode->i_sb, "green-9011: Unexpected key type %K\n", &key);
} }
...@@ -421,7 +422,7 @@ int reiserfs_allocate_blocks_for_region( ...@@ -421,7 +422,7 @@ int reiserfs_allocate_blocks_for_region(
// position. We do not need to recalculate path as it should // position. We do not need to recalculate path as it should
// already point to correct place. // already point to correct place.
make_cpu_key( &key, inode, le_key_k_offset( get_inode_item_key_version(inode), &(ih->ih_key)) + op_bytes_number(ih, inode->i_sb->s_blocksize), TYPE_INDIRECT, 3); make_cpu_key( &key, inode, le_key_k_offset( get_inode_item_key_version(inode), &(ih->ih_key)) + op_bytes_number(ih, inode->i_sb->s_blocksize), TYPE_INDIRECT, 3);
res = reiserfs_paste_into_item( th, &path, &key, (char *)(allocated_blocks+curr_block), UNFM_P_SIZE*(blocks_to_allocate-curr_block)); res = reiserfs_paste_into_item( th, &path, &key, inode, (char *)(allocated_blocks+curr_block), UNFM_P_SIZE*(blocks_to_allocate-curr_block));
if ( res ) { if ( res ) {
goto error_exit_free_blocks; goto error_exit_free_blocks;
} }
...@@ -452,7 +453,7 @@ int reiserfs_allocate_blocks_for_region( ...@@ -452,7 +453,7 @@ int reiserfs_allocate_blocks_for_region(
goto error_exit_free_blocks; goto error_exit_free_blocks;
} }
/* Insert item into the tree with the data as its body */ /* Insert item into the tree with the data as its body */
res = reiserfs_insert_item( th, &path, &key, &ins_ih, (char *)(allocated_blocks+curr_block)); res = reiserfs_insert_item( th, &path, &key, &ins_ih, inode, (char *)(allocated_blocks+curr_block));
} else { } else {
reiserfs_panic(inode->i_sb, "green-9010: unexpected item type for key %K\n",&key); reiserfs_panic(inode->i_sb, "green-9010: unexpected item type for key %K\n",&key);
} }
...@@ -462,7 +463,6 @@ int reiserfs_allocate_blocks_for_region( ...@@ -462,7 +463,6 @@ int reiserfs_allocate_blocks_for_region(
// unless we return an error, they are also responsible for logging // unless we return an error, they are also responsible for logging
// the inode. // the inode.
// //
inode->i_blocks += blocks_to_allocate << (inode->i_blkbits - 9);
pathrelse(&path); pathrelse(&path);
reiserfs_write_unlock(inode->i_sb); reiserfs_write_unlock(inode->i_sb);
...@@ -508,7 +508,7 @@ int reiserfs_allocate_blocks_for_region( ...@@ -508,7 +508,7 @@ int reiserfs_allocate_blocks_for_region(
pathrelse(&path); pathrelse(&path);
// free blocks // free blocks
for( i = 0; i < blocks_to_allocate; i++ ) for( i = 0; i < blocks_to_allocate; i++ )
reiserfs_free_block(th, le32_to_cpu(allocated_blocks[i])); reiserfs_free_block(th, inode, le32_to_cpu(allocated_blocks[i]), 1);
error_exit: error_exit:
reiserfs_update_sd(th, inode); // update any changes we made to blk count reiserfs_update_sd(th, inode); // update any changes we made to blk count
......
...@@ -795,8 +795,9 @@ static int get_empty_nodes( ...@@ -795,8 +795,9 @@ static int get_empty_nodes(
else /* If we have enough already then there is nothing to do. */ else /* If we have enough already then there is nothing to do. */
return CARRY_ON; return CARRY_ON;
if ( reiserfs_new_form_blocknrs (p_s_tb, a_n_blocknrs, /* No need to check quota - is not allocated for blocks used for formatted nodes */
n_amount_needed) == NO_DISK_SPACE ) if (reiserfs_new_form_blocknrs (p_s_tb, a_n_blocknrs,
n_amount_needed) == NO_DISK_SPACE)
return NO_DISK_SPACE; return NO_DISK_SPACE;
/* for each blocknumber we just got, get a buffer and stick it on FEB */ /* for each blocknumber we just got, get a buffer and stick it on FEB */
...@@ -2492,7 +2493,7 @@ void unfix_nodes (struct tree_balance * tb) ...@@ -2492,7 +2493,7 @@ void unfix_nodes (struct tree_balance * tb)
/* de-allocated block which was not used by balancing and /* de-allocated block which was not used by balancing and
bforget about buffer for it */ bforget about buffer for it */
brelse (tb->FEB[i]); brelse (tb->FEB[i]);
reiserfs_free_block (tb->transaction_handle, blocknr); reiserfs_free_block (tb->transaction_handle, NULL, blocknr, 0);
} }
if (tb->used[i]) { if (tb->used[i]) {
/* release used as new nodes including a new root */ /* release used as new nodes including a new root */
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include <linux/config.h> #include <linux/config.h>
#include <linux/time.h> #include <linux/time.h>
#include <linux/fs.h>
#include <linux/reiserfs_fs.h> #include <linux/reiserfs_fs.h>
#include <linux/reiserfs_acl.h> #include <linux/reiserfs_acl.h>
#include <linux/reiserfs_xattr.h> #include <linux/reiserfs_xattr.h>
...@@ -39,6 +40,7 @@ void reiserfs_delete_inode (struct inode * inode) ...@@ -39,6 +40,7 @@ void reiserfs_delete_inode (struct inode * inode)
reiserfs_write_lock(inode->i_sb); 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.. */ /* 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 */ if (!(inode->i_state & I_NEW) && INODE_PKEY(inode)->k_objectid != 0) { /* also handles bad_inode case */
down (&inode->i_sem); down (&inode->i_sem);
...@@ -647,7 +649,7 @@ int reiserfs_get_block (struct inode * inode, sector_t block, ...@@ -647,7 +649,7 @@ int reiserfs_get_block (struct inode * inode, sector_t block,
repeat = _allocate_block(th, block, inode, &allocated_block_nr, &path, create); repeat = _allocate_block(th, block, inode, &allocated_block_nr, &path, create);
if (repeat == NO_DISK_SPACE) { if (repeat == NO_DISK_SPACE || repeat == QUOTA_EXCEEDED) {
/* restart the transaction to give the journal a chance to free /* restart the transaction to give the journal a chance to free
** some blocks. releases the path, so we have to go back to ** some blocks. releases the path, so we have to go back to
** research if we succeed on the second try ** research if we succeed on the second try
...@@ -656,9 +658,12 @@ int reiserfs_get_block (struct inode * inode, sector_t block, ...@@ -656,9 +658,12 @@ int reiserfs_get_block (struct inode * inode, sector_t block,
restart_transaction(th, inode, &path) ; restart_transaction(th, inode, &path) ;
repeat = _allocate_block(th, block, inode, &allocated_block_nr, NULL, create); repeat = _allocate_block(th, block, inode, &allocated_block_nr, NULL, create);
if (repeat != NO_DISK_SPACE) { if (repeat != NO_DISK_SPACE && repeat != QUOTA_EXCEEDED) {
goto research ; goto research ;
} }
if (repeat == QUOTA_EXCEEDED)
retval = -EDQUOT;
else
retval = -ENOSPC; retval = -ENOSPC;
goto failure; goto failure;
} }
...@@ -687,7 +692,6 @@ int reiserfs_get_block (struct inode * inode, sector_t block, ...@@ -687,7 +692,6 @@ int reiserfs_get_block (struct inode * inode, sector_t block,
put_block_num(item, pos_in_item, allocated_block_nr) ; put_block_num(item, pos_in_item, allocated_block_nr) ;
unfm_ptr = allocated_block_nr; unfm_ptr = allocated_block_nr;
journal_mark_dirty (th, inode->i_sb, bh); journal_mark_dirty (th, inode->i_sb, bh);
inode->i_blocks += (inode->i_sb->s_blocksize / 512) ;
reiserfs_update_sd(th, inode) ; reiserfs_update_sd(th, inode) ;
} }
set_block_dev_mapped(bh_result, unfm_ptr, inode); set_block_dev_mapped(bh_result, unfm_ptr, inode);
...@@ -734,13 +738,11 @@ int reiserfs_get_block (struct inode * inode, sector_t block, ...@@ -734,13 +738,11 @@ int reiserfs_get_block (struct inode * inode, sector_t block,
set_cpu_key_k_offset (&tmp_key, 1); set_cpu_key_k_offset (&tmp_key, 1);
PATH_LAST_POSITION(&path) ++; PATH_LAST_POSITION(&path) ++;
retval = reiserfs_insert_item (th, &path, &tmp_key, &tmp_ih, (char *)&unp); retval = reiserfs_insert_item (th, &path, &tmp_key, &tmp_ih, inode, (char *)&unp);
if (retval) { if (retval) {
reiserfs_free_block (th, allocated_block_nr); reiserfs_free_block (th, inode, allocated_block_nr, 1);
goto failure; // retval == -ENOSPC or -EIO or -EEXIST goto failure; // retval == -ENOSPC, -EDQUOT or -EIO or -EEXIST
} }
if (unp)
inode->i_blocks += inode->i_sb->s_blocksize / 512;
//mark_tail_converted (inode); //mark_tail_converted (inode);
} else if (is_direct_le_ih (ih)) { } else if (is_direct_le_ih (ih)) {
/* direct item has to be converted */ /* direct item has to be converted */
...@@ -778,7 +780,7 @@ int reiserfs_get_block (struct inode * inode, sector_t block, ...@@ -778,7 +780,7 @@ int reiserfs_get_block (struct inode * inode, sector_t block,
if (!th) if (!th)
th = reiserfs_persistent_transaction(inode->i_sb,3); th = reiserfs_persistent_transaction(inode->i_sb,3);
if (th) if (th)
reiserfs_free_block (th, allocated_block_nr); reiserfs_free_block (th,inode,allocated_block_nr,1);
} }
goto failure ; goto failure ;
} }
...@@ -787,7 +789,7 @@ int reiserfs_get_block (struct inode * inode, sector_t block, ...@@ -787,7 +789,7 @@ int reiserfs_get_block (struct inode * inode, sector_t block,
retval = direct2indirect (th, inode, &path, unbh, tail_offset); retval = direct2indirect (th, inode, &path, unbh, tail_offset);
if (retval) { if (retval) {
reiserfs_unmap_buffer(unbh); reiserfs_unmap_buffer(unbh);
reiserfs_free_block (th, allocated_block_nr); reiserfs_free_block (th, inode, allocated_block_nr, 1);
goto failure; goto failure;
} }
/* it is important the set_buffer_uptodate is done after /* it is important the set_buffer_uptodate is done after
...@@ -820,9 +822,6 @@ int reiserfs_get_block (struct inode * inode, sector_t block, ...@@ -820,9 +822,6 @@ int reiserfs_get_block (struct inode * inode, sector_t block,
*/ */
mark_buffer_dirty(unbh) ; mark_buffer_dirty(unbh) ;
} }
//inode->i_blocks += inode->i_sb->s_blocksize / 512;
//mark_tail_converted (inode);
} else { } else {
/* append indirect item with holes if needed, when appending /* append indirect item with holes if needed, when appending
pointer to 'block'-th block use block, which is already pointer to 'block'-th block use block, which is already
...@@ -870,24 +869,21 @@ int reiserfs_get_block (struct inode * inode, sector_t block, ...@@ -870,24 +869,21 @@ int reiserfs_get_block (struct inode * inode, sector_t block,
only have space for one block */ only have space for one block */
blocks_needed=max_to_insert?max_to_insert:1; blocks_needed=max_to_insert?max_to_insert:1;
} }
retval = reiserfs_paste_into_item (th, &path, &tmp_key, (char *)un, UNFM_P_SIZE * blocks_needed); retval = reiserfs_paste_into_item (th, &path, &tmp_key, inode, (char *)un, UNFM_P_SIZE * blocks_needed);
if (blocks_needed != 1) if (blocks_needed != 1)
kfree(un); kfree(un);
if (retval) { if (retval) {
reiserfs_free_block (th, allocated_block_nr); reiserfs_free_block (th, inode, allocated_block_nr, 1);
goto failure; goto failure;
} }
if (done) { if (!done) {
inode->i_blocks += inode->i_sb->s_blocksize / 512;
} else {
/* We need to mark new file size in case this function will be /* We need to mark new file size in case this function will be
interrupted/aborted later on. And we may do this only for interrupted/aborted later on. And we may do this only for
holes. */ holes. */
inode->i_size += inode->i_sb->s_blocksize * blocks_needed; inode->i_size += inode->i_sb->s_blocksize * blocks_needed;
} }
//mark_tail_converted (inode);
} }
if (done == 1) if (done == 1)
...@@ -919,7 +915,7 @@ int reiserfs_get_block (struct inode * inode, sector_t block, ...@@ -919,7 +915,7 @@ int reiserfs_get_block (struct inode * inode, sector_t block,
"%K should not be found\n", &key); "%K should not be found\n", &key);
retval = -EEXIST; retval = -EEXIST;
if (allocated_block_nr) if (allocated_block_nr)
reiserfs_free_block (th, allocated_block_nr); reiserfs_free_block (th, inode, allocated_block_nr, 1);
pathrelse(&path) ; pathrelse(&path) ;
goto failure; goto failure;
} }
...@@ -949,6 +945,58 @@ reiserfs_readpages(struct file *file, struct address_space *mapping, ...@@ -949,6 +945,58 @@ reiserfs_readpages(struct file *file, struct address_space *mapping,
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
* Following three functions can go away when we'll have enough space in stat item
*/
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 ;
}
static inline loff_t to_real_used_space(struct inode *inode, ulong blocks,
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);
}
/* 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;
}
// //
// BAD: new directories have stat data of new type and all other items // BAD: new directories have stat data of new type and all other items
// of old type. Version stored in the inode says about body items, so // of old type. Version stored in the inode says about body items, so
...@@ -1014,6 +1062,14 @@ static void init_inode (struct inode * inode, struct path * path) ...@@ -1014,6 +1062,14 @@ static void init_inode (struct inode * inode, struct path * path)
rdev = sd_v1_rdev(sd); rdev = sd_v1_rdev(sd);
REISERFS_I(inode)->i_first_direct_byte = sd_v1_first_direct_byte(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 initially zero for v1 objects. For v2 objects,
nopack is initialised from sd_attrs */ nopack is initialised from sd_attrs */
REISERFS_I(inode)->i_flags &= ~i_nopack_mask; REISERFS_I(inode)->i_flags &= ~i_nopack_mask;
...@@ -1046,6 +1102,8 @@ static void init_inode (struct inode * inode, struct path * path) ...@@ -1046,6 +1102,8 @@ static void init_inode (struct inode * inode, struct path * path)
set_inode_item_key_version (inode, KEY_FORMAT_3_6); set_inode_item_key_version (inode, KEY_FORMAT_3_6);
REISERFS_I(inode)->i_first_direct_byte = 0; REISERFS_I(inode)->i_first_direct_byte = 0;
set_inode_sd_version (inode, STAT_DATA_V2); 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 /* read persistent inode attributes from sd and initalise
generic inode flags from them */ generic inode flags from them */
REISERFS_I(inode)->i_attrs = sd_v2_attrs( sd ); REISERFS_I(inode)->i_attrs = sd_v2_attrs( sd );
...@@ -1072,7 +1130,7 @@ static void init_inode (struct inode * inode, struct path * path) ...@@ -1072,7 +1130,7 @@ static void init_inode (struct inode * inode, struct path * path)
// update new stat data with inode fields // update new stat data with inode fields
static void inode2sd (void * sd, struct inode * inode) static void inode2sd (void * sd, struct inode * inode, loff_t size)
{ {
struct stat_data * sd_v2 = (struct stat_data *)sd; struct stat_data * sd_v2 = (struct stat_data *)sd;
__u16 flags; __u16 flags;
...@@ -1080,12 +1138,12 @@ static void inode2sd (void * sd, struct inode * inode) ...@@ -1080,12 +1138,12 @@ static void inode2sd (void * sd, struct inode * inode)
set_sd_v2_mode(sd_v2, inode->i_mode ); set_sd_v2_mode(sd_v2, inode->i_mode );
set_sd_v2_nlink(sd_v2, inode->i_nlink ); set_sd_v2_nlink(sd_v2, inode->i_nlink );
set_sd_v2_uid(sd_v2, inode->i_uid ); set_sd_v2_uid(sd_v2, inode->i_uid );
set_sd_v2_size(sd_v2, inode->i_size ); set_sd_v2_size(sd_v2, size );
set_sd_v2_gid(sd_v2, inode->i_gid ); set_sd_v2_gid(sd_v2, inode->i_gid );
set_sd_v2_mtime(sd_v2, inode->i_mtime.tv_sec ); 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_atime(sd_v2, inode->i_atime.tv_sec );
set_sd_v2_ctime(sd_v2, inode->i_ctime.tv_sec ); set_sd_v2_ctime(sd_v2, inode->i_ctime.tv_sec );
set_sd_v2_blocks(sd_v2, inode->i_blocks ); 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)) if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
set_sd_v2_rdev(sd_v2, new_encode_dev(inode->i_rdev)); set_sd_v2_rdev(sd_v2, new_encode_dev(inode->i_rdev));
else else
...@@ -1097,7 +1155,7 @@ static void inode2sd (void * sd, struct inode * inode) ...@@ -1097,7 +1155,7 @@ static void inode2sd (void * sd, struct inode * inode)
// used to copy inode's fields to old stat data // used to copy inode's fields to old stat data
static void inode2sd_v1 (void * sd, struct inode * inode) static void inode2sd_v1 (void * sd, struct inode * inode, loff_t size)
{ {
struct stat_data_v1 * sd_v1 = (struct stat_data_v1 *)sd; struct stat_data_v1 * sd_v1 = (struct stat_data_v1 *)sd;
...@@ -1105,7 +1163,7 @@ static void inode2sd_v1 (void * sd, struct inode * inode) ...@@ -1105,7 +1163,7 @@ static void inode2sd_v1 (void * sd, struct inode * inode)
set_sd_v1_uid(sd_v1, inode->i_uid ); set_sd_v1_uid(sd_v1, inode->i_uid );
set_sd_v1_gid(sd_v1, inode->i_gid ); set_sd_v1_gid(sd_v1, inode->i_gid );
set_sd_v1_nlink(sd_v1, inode->i_nlink ); set_sd_v1_nlink(sd_v1, inode->i_nlink );
set_sd_v1_size(sd_v1, inode->i_size ); set_sd_v1_size(sd_v1, size );
set_sd_v1_atime(sd_v1, inode->i_atime.tv_sec ); 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_ctime(sd_v1, inode->i_ctime.tv_sec );
set_sd_v1_mtime(sd_v1, inode->i_mtime.tv_sec ); set_sd_v1_mtime(sd_v1, inode->i_mtime.tv_sec );
...@@ -1113,7 +1171,7 @@ static void inode2sd_v1 (void * sd, struct inode * inode) ...@@ -1113,7 +1171,7 @@ static void inode2sd_v1 (void * sd, struct inode * inode)
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
set_sd_v1_rdev(sd_v1, new_encode_dev(inode->i_rdev)); set_sd_v1_rdev(sd_v1, new_encode_dev(inode->i_rdev));
else else
set_sd_v1_blocks(sd_v1, inode->i_blocks ); set_sd_v1_blocks(sd_v1, to_fake_used_blocks(inode, SD_V1_SIZE));
// Sigh. i_first_direct_byte is back // Sigh. i_first_direct_byte is back
set_sd_v1_first_direct_byte(sd_v1, REISERFS_I(inode)->i_first_direct_byte); set_sd_v1_first_direct_byte(sd_v1, REISERFS_I(inode)->i_first_direct_byte);
...@@ -1123,7 +1181,8 @@ static void inode2sd_v1 (void * sd, struct inode * inode) ...@@ -1123,7 +1181,8 @@ static void inode2sd_v1 (void * sd, struct inode * inode)
/* NOTE, you must prepare the buffer head before sending it here, /* NOTE, you must prepare the buffer head before sending it here,
** and then log it after the call ** and then log it after the call
*/ */
static void update_stat_data (struct path * path, struct inode * inode) static void update_stat_data (struct path * path, struct inode * inode,
loff_t size)
{ {
struct buffer_head * bh; struct buffer_head * bh;
struct item_head * ih; struct item_head * ih;
...@@ -1137,17 +1196,17 @@ static void update_stat_data (struct path * path, struct inode * inode) ...@@ -1137,17 +1196,17 @@ static void update_stat_data (struct path * path, struct inode * inode)
if (stat_data_v1 (ih)) { if (stat_data_v1 (ih)) {
// path points to old stat data // path points to old stat data
inode2sd_v1 (B_I_PITEM (bh, ih), inode); inode2sd_v1 (B_I_PITEM (bh, ih), inode, size);
} else { } else {
inode2sd (B_I_PITEM (bh, ih), inode); inode2sd (B_I_PITEM (bh, ih), inode, size);
} }
return; return;
} }
void reiserfs_update_sd (struct reiserfs_transaction_handle *th, void reiserfs_update_sd_size (struct reiserfs_transaction_handle *th,
struct inode * inode) struct inode * inode, loff_t size)
{ {
struct cpu_key key; struct cpu_key key;
INITIALIZE_PATH(path); INITIALIZE_PATH(path);
...@@ -1197,7 +1256,7 @@ void reiserfs_update_sd (struct reiserfs_transaction_handle *th, ...@@ -1197,7 +1256,7 @@ void reiserfs_update_sd (struct reiserfs_transaction_handle *th,
} }
break; break;
} }
update_stat_data (&path, inode); update_stat_data (&path, inode, size);
journal_mark_dirty(th, th->t_super, bh) ; journal_mark_dirty(th, th->t_super, bh) ;
pathrelse (&path); pathrelse (&path);
return; return;
...@@ -1480,6 +1539,7 @@ int reiserfs_sync_inode (struct reiserfs_transaction_handle *th, struct inode * ...@@ -1480,6 +1539,7 @@ int reiserfs_sync_inode (struct reiserfs_transaction_handle *th, struct inode *
/* stat data of new object is inserted already, this inserts the item /* stat data of new object is inserted already, this inserts the item
containing "." and ".." entries */ containing "." and ".." entries */
static int reiserfs_new_directory (struct reiserfs_transaction_handle *th, static int reiserfs_new_directory (struct reiserfs_transaction_handle *th,
struct inode *inode,
struct item_head * ih, struct path * path, struct item_head * ih, struct path * path,
struct inode * dir) struct inode * dir)
{ {
...@@ -1524,13 +1584,14 @@ static int reiserfs_new_directory (struct reiserfs_transaction_handle *th, ...@@ -1524,13 +1584,14 @@ static int reiserfs_new_directory (struct reiserfs_transaction_handle *th,
} }
/* insert item, that is empty directory item */ /* insert item, that is empty directory item */
return reiserfs_insert_item (th, path, &key, ih, body); return reiserfs_insert_item (th, path, &key, ih, inode, body);
} }
/* stat data of object has been inserted, this inserts the item /* stat data of object has been inserted, this inserts the item
containing the body of symlink */ containing the body of symlink */
static int reiserfs_new_symlink (struct reiserfs_transaction_handle *th, static int reiserfs_new_symlink (struct reiserfs_transaction_handle *th,
struct inode *inode, /* Inode of symlink */
struct item_head * ih, struct item_head * ih,
struct path * path, const char * symname, int item_len) struct path * path, const char * symname, int item_len)
{ {
...@@ -1560,7 +1621,7 @@ static int reiserfs_new_symlink (struct reiserfs_transaction_handle *th, ...@@ -1560,7 +1621,7 @@ static int reiserfs_new_symlink (struct reiserfs_transaction_handle *th,
} }
/* insert item, that is body of symlink */ /* insert item, that is body of symlink */
return reiserfs_insert_item (th, path, &key, ih, symname); return reiserfs_insert_item (th, path, &key, ih, inode, symname);
} }
...@@ -1628,7 +1689,8 @@ int reiserfs_new_inode (struct reiserfs_transaction_handle *th, ...@@ -1628,7 +1689,8 @@ int reiserfs_new_inode (struct reiserfs_transaction_handle *th,
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_size = i_size; inode->i_size = i_size;
inode->i_blocks = (inode->i_size + 511) >> 9; inode->i_blocks = 0;
inode->i_bytes = 0;
REISERFS_I(inode)->i_first_direct_byte = S_ISLNK(mode) ? 1 : REISERFS_I(inode)->i_first_direct_byte = S_ISLNK(mode) ? 1 :
U32_MAX/*NO_BYTES_IN_DIRECT_ITEM*/; U32_MAX/*NO_BYTES_IN_DIRECT_ITEM*/;
...@@ -1673,9 +1735,9 @@ int reiserfs_new_inode (struct reiserfs_transaction_handle *th, ...@@ -1673,9 +1735,9 @@ int reiserfs_new_inode (struct reiserfs_transaction_handle *th,
err = -EINVAL; err = -EINVAL;
goto out_bad_inode; goto out_bad_inode;
} }
inode2sd_v1 (&sd, inode); inode2sd_v1 (&sd, inode, inode->i_size);
} else { } else {
inode2sd (&sd, inode); inode2sd (&sd, inode, inode->i_size);
} }
// these do not go to on-disk stat data // these do not go to on-disk stat data
inode->i_ino = le32_to_cpu (ih.ih_key.k_objectid); inode->i_ino = le32_to_cpu (ih.ih_key.k_objectid);
...@@ -1699,7 +1761,7 @@ int reiserfs_new_inode (struct reiserfs_transaction_handle *th, ...@@ -1699,7 +1761,7 @@ int reiserfs_new_inode (struct reiserfs_transaction_handle *th,
if (REISERFS_I(dir)->new_packing_locality) if (REISERFS_I(dir)->new_packing_locality)
th->displace_new_blocks = 1; th->displace_new_blocks = 1;
#endif #endif
retval = reiserfs_insert_item (th, &path_to_key, &key, &ih, (char *)(&sd)); retval = reiserfs_insert_item (th, &path_to_key, &key, &ih, inode, (char *)(&sd));
if (retval) { if (retval) {
err = retval; err = retval;
reiserfs_check_path(&path_to_key) ; reiserfs_check_path(&path_to_key) ;
...@@ -1712,14 +1774,14 @@ int reiserfs_new_inode (struct reiserfs_transaction_handle *th, ...@@ -1712,14 +1774,14 @@ int reiserfs_new_inode (struct reiserfs_transaction_handle *th,
#endif #endif
if (S_ISDIR(mode)) { if (S_ISDIR(mode)) {
/* insert item with "." and ".." */ /* insert item with "." and ".." */
retval = reiserfs_new_directory (th, &ih, &path_to_key, dir); retval = reiserfs_new_directory (th, inode, &ih, &path_to_key, dir);
} }
if (S_ISLNK(mode)) { if (S_ISLNK(mode)) {
/* insert body of symlink */ /* insert body of symlink */
if (!old_format_only (sb)) if (!old_format_only (sb))
i_size = ROUND_UP(i_size); i_size = ROUND_UP(i_size);
retval = reiserfs_new_symlink (th, &ih, &path_to_key, symname, i_size); retval = reiserfs_new_symlink (th, inode, &ih, &path_to_key, symname, i_size);
} }
if (retval) { if (retval) {
err = retval; err = retval;
...@@ -1757,6 +1819,9 @@ int reiserfs_new_inode (struct reiserfs_transaction_handle *th, ...@@ -1757,6 +1819,9 @@ int reiserfs_new_inode (struct reiserfs_transaction_handle *th,
/* dquot_drop must be done outside a transaction */ /* dquot_drop must be done outside a transaction */
journal_end(th, th->t_super, th->t_blocks_allocated) ; journal_end(th, th->t_super, th->t_blocks_allocated) ;
DQUOT_FREE_INODE(inode);
DQUOT_DROP(inode);
inode->i_flags |= S_NOQUOTA;
make_bad_inode(inode); make_bad_inode(inode);
out_inserted_sd: out_inserted_sd:
...@@ -2294,6 +2359,7 @@ static int reiserfs_commit_write(struct file *f, struct page *page, ...@@ -2294,6 +2359,7 @@ static int reiserfs_commit_write(struct file *f, struct page *page,
struct inode *inode = page->mapping->host ; struct inode *inode = page->mapping->host ;
loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
int ret = 0; int ret = 0;
int update_sd = 0;
struct reiserfs_transaction_handle *th = NULL; struct reiserfs_transaction_handle *th = NULL;
reiserfs_wait_on_write_block(inode->i_sb) ; reiserfs_wait_on_write_block(inode->i_sb) ;
...@@ -2320,11 +2386,14 @@ static int reiserfs_commit_write(struct file *f, struct page *page, ...@@ -2320,11 +2386,14 @@ static int reiserfs_commit_write(struct file *f, struct page *page,
reiserfs_update_inode_transaction(inode) ; reiserfs_update_inode_transaction(inode) ;
inode->i_size = pos ; inode->i_size = pos ;
reiserfs_update_sd(&myth, inode) ; reiserfs_update_sd(&myth, inode) ;
update_sd = 1;
journal_end(&myth, inode->i_sb, 1) ; journal_end(&myth, inode->i_sb, 1) ;
reiserfs_write_unlock(inode->i_sb); reiserfs_write_unlock(inode->i_sb);
} }
if (th) { if (th) {
reiserfs_write_lock(inode->i_sb); reiserfs_write_lock(inode->i_sb);
if (!update_sd)
reiserfs_update_sd(th, inode) ;
reiserfs_end_persistent_transaction(th); reiserfs_end_persistent_transaction(th);
reiserfs_write_unlock(inode->i_sb); reiserfs_write_unlock(inode->i_sb);
} }
...@@ -2533,7 +2602,6 @@ static ssize_t reiserfs_direct_IO(int rw, struct kiocb *iocb, ...@@ -2533,7 +2602,6 @@ static ssize_t reiserfs_direct_IO(int rw, struct kiocb *iocb,
offset, nr_segs, reiserfs_get_blocks_direct_io, NULL); offset, nr_segs, reiserfs_get_blocks_direct_io, NULL);
} }
int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) { int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) {
struct inode *inode = dentry->d_inode ; struct inode *inode = dentry->d_inode ;
int error ; int error ;
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/reiserfs_acl.h> #include <linux/reiserfs_acl.h>
#include <linux/reiserfs_xattr.h> #include <linux/reiserfs_xattr.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/quotaops.h>
#define INC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) { i->i_nlink++; if (i->i_nlink >= REISERFS_LINK_MAX) i->i_nlink=1; } #define INC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) { i->i_nlink++; if (i->i_nlink >= REISERFS_LINK_MAX) i->i_nlink=1; }
#define DEC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) i->i_nlink--; #define DEC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) i->i_nlink--;
...@@ -519,7 +520,7 @@ static int reiserfs_add_entry (struct reiserfs_transaction_handle *th, struct in ...@@ -519,7 +520,7 @@ static int reiserfs_add_entry (struct reiserfs_transaction_handle *th, struct in
} }
/* perform the insertion of the entry that we have prepared */ /* perform the insertion of the entry that we have prepared */
retval = reiserfs_paste_into_item (th, &path, &entry_key, buffer, paste_size); retval = reiserfs_paste_into_item (th, &path, &entry_key, dir, buffer, paste_size);
if (buffer != small_buf) if (buffer != small_buf)
reiserfs_kfree (buffer, buflen, dir->i_sb); reiserfs_kfree (buffer, buflen, dir->i_sb);
if (retval) { if (retval) {
...@@ -528,7 +529,6 @@ static int reiserfs_add_entry (struct reiserfs_transaction_handle *th, struct in ...@@ -528,7 +529,6 @@ static int reiserfs_add_entry (struct reiserfs_transaction_handle *th, struct in
} }
dir->i_size += paste_size; dir->i_size += paste_size;
dir->i_blocks = ((dir->i_size + 511) >> 9);
dir->i_mtime = dir->i_ctime = CURRENT_TIME; dir->i_mtime = dir->i_ctime = CURRENT_TIME;
if (!S_ISDIR (inode->i_mode) && visible) if (!S_ISDIR (inode->i_mode) && visible)
// reiserfs_mkdir or reiserfs_rename will do that by itself // reiserfs_mkdir or reiserfs_rename will do that by itself
...@@ -544,7 +544,9 @@ static int reiserfs_add_entry (struct reiserfs_transaction_handle *th, struct in ...@@ -544,7 +544,9 @@ static int reiserfs_add_entry (struct reiserfs_transaction_handle *th, struct in
** inserted into the tree yet. ** inserted into the tree yet.
*/ */
static int drop_new_inode(struct inode *inode) { static int drop_new_inode(struct inode *inode) {
DQUOT_DROP(inode);
make_bad_inode(inode) ; make_bad_inode(inode) ;
inode->i_flags |= S_NOQUOTA;
iput(inode) ; iput(inode) ;
return 0 ; return 0 ;
} }
...@@ -570,6 +572,11 @@ static int new_inode_init(struct inode *inode, struct inode *dir, int mode) { ...@@ -570,6 +572,11 @@ static int new_inode_init(struct inode *inode, struct inode *dir, int mode) {
} else { } else {
inode->i_gid = current->fsgid; inode->i_gid = current->fsgid;
} }
DQUOT_INIT(inode);
if (DQUOT_ALLOC_INODE(inode)) {
drop_new_inode(inode);
return -EDQUOT;
}
return 0 ; return 0 ;
} }
...@@ -836,7 +843,6 @@ static int reiserfs_rmdir (struct inode * dir, struct dentry *dentry) ...@@ -836,7 +843,6 @@ static int reiserfs_rmdir (struct inode * dir, struct dentry *dentry)
DEC_DIR_INODE_NLINK(dir) DEC_DIR_INODE_NLINK(dir)
dir->i_size -= (DEH_SIZE + de.de_entrylen); dir->i_size -= (DEH_SIZE + de.de_entrylen);
dir->i_blocks = ((dir->i_size + 511) >> 9);
reiserfs_update_sd (&th, dir); reiserfs_update_sd (&th, dir);
/* prevent empty directory from getting lost */ /* prevent empty directory from getting lost */
...@@ -919,7 +925,6 @@ static int reiserfs_unlink (struct inode * dir, struct dentry *dentry) ...@@ -919,7 +925,6 @@ static int reiserfs_unlink (struct inode * dir, struct dentry *dentry)
reiserfs_update_sd (&th, inode); reiserfs_update_sd (&th, inode);
dir->i_size -= (de.de_entrylen + DEH_SIZE); dir->i_size -= (de.de_entrylen + DEH_SIZE);
dir->i_blocks = ((dir->i_size + 511) >> 9);
dir->i_ctime = dir->i_mtime = CURRENT_TIME; dir->i_ctime = dir->i_mtime = CURRENT_TIME;
reiserfs_update_sd (&th, dir); reiserfs_update_sd (&th, dir);
...@@ -1335,7 +1340,6 @@ static int reiserfs_rename (struct inode * old_dir, struct dentry *old_dentry, ...@@ -1335,7 +1340,6 @@ static int reiserfs_rename (struct inode * old_dir, struct dentry *old_dentry,
reiserfs_warning ("vs-7060: reiserfs_rename: couldn't not cut old name. Fsck later?\n"); reiserfs_warning ("vs-7060: reiserfs_rename: couldn't not cut old name. Fsck later?\n");
old_dir->i_size -= DEH_SIZE + old_de.de_entrylen; old_dir->i_size -= DEH_SIZE + old_de.de_entrylen;
old_dir->i_blocks = ((old_dir->i_size + 511) >> 9);
reiserfs_update_sd (&th, old_dir); reiserfs_update_sd (&th, old_dir);
reiserfs_update_sd (&th, new_dir); reiserfs_update_sd (&th, new_dir);
......
...@@ -60,6 +60,7 @@ ...@@ -60,6 +60,7 @@
#include <linux/reiserfs_fs.h> #include <linux/reiserfs_fs.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/quotaops.h>
/* Does the buffer contain a disk block which is in the tree. */ /* Does the buffer contain a disk block which is in the tree. */
inline int B_IS_IN_TREE (const struct buffer_head * p_s_bh) inline int B_IS_IN_TREE (const struct buffer_head * p_s_bh)
...@@ -71,9 +72,6 @@ inline int B_IS_IN_TREE (const struct buffer_head * p_s_bh) ...@@ -71,9 +72,6 @@ inline int B_IS_IN_TREE (const struct buffer_head * p_s_bh)
return ( B_LEVEL (p_s_bh) != FREE_LEVEL ); return ( B_LEVEL (p_s_bh) != FREE_LEVEL );
} }
inline void copy_short_key (void * to, const void * from) inline void copy_short_key (void * to, const void * from)
{ {
memcpy (to, from, SHORT_KEY_SIZE); memcpy (to, from, SHORT_KEY_SIZE);
...@@ -1125,8 +1123,7 @@ static char prepare_for_delete_or_cut( ...@@ -1125,8 +1123,7 @@ static char prepare_for_delete_or_cut(
tmp = get_block_num(p_n_unfm_pointer,0); tmp = get_block_num(p_n_unfm_pointer,0);
put_block_num(p_n_unfm_pointer, 0, 0); put_block_num(p_n_unfm_pointer, 0, 0);
journal_mark_dirty (th, p_s_sb, p_s_bh); journal_mark_dirty (th, p_s_sb, p_s_bh);
inode->i_blocks -= p_s_sb->s_blocksize / 512; reiserfs_free_block(th, inode, tmp, 1);
reiserfs_free_block(th, tmp);
if ( item_moved (&s_ih, p_s_path) ) { if ( item_moved (&s_ih, p_s_path) ) {
need_research = 1; need_research = 1;
break ; break ;
...@@ -1155,8 +1152,7 @@ static char prepare_for_delete_or_cut( ...@@ -1155,8 +1152,7 @@ static char prepare_for_delete_or_cut(
} }
} }
/* Calculate number of bytes which will be deleted or cut during balance */
/* Calculate bytes number which will be deleted or cutted in the balance. */
int calc_deleted_bytes_number( int calc_deleted_bytes_number(
struct tree_balance * p_s_tb, struct tree_balance * p_s_tb,
char c_mode char c_mode
...@@ -1167,14 +1163,14 @@ int calc_deleted_bytes_number( ...@@ -1167,14 +1163,14 @@ int calc_deleted_bytes_number(
if ( is_statdata_le_ih (p_le_ih) ) if ( is_statdata_le_ih (p_le_ih) )
return 0; return 0;
n_del_size = ( c_mode == M_DELETE ) ? ih_item_len(p_le_ih) : -p_s_tb->insert_size[0];
if ( is_direntry_le_ih (p_le_ih) ) { if ( is_direntry_le_ih (p_le_ih) ) {
// return EMPTY_DIR_SIZE; /* We delete emty directoris only. */ // return EMPTY_DIR_SIZE; /* We delete emty directoris only. */
// we can't use EMPTY_DIR_SIZE, as old format dirs have a different // we can't use EMPTY_DIR_SIZE, as old format dirs have a different
// empty size. ick. FIXME, is this right? // empty size. ick. FIXME, is this right?
// //
return ih_item_len(p_le_ih); return n_del_size ;
} }
n_del_size = ( c_mode == M_DELETE ) ? ih_item_len(p_le_ih) : -p_s_tb->insert_size[0];
if ( is_indirect_le_ih (p_le_ih) ) if ( is_indirect_le_ih (p_le_ih) )
n_del_size = (n_del_size/UNFM_P_SIZE)* n_del_size = (n_del_size/UNFM_P_SIZE)*
...@@ -1208,17 +1204,46 @@ void padd_item (char * item, int total_length, int length) ...@@ -1208,17 +1204,46 @@ void padd_item (char * item, int total_length, int length)
item [--i] = 0; item [--i] = 0;
} }
#ifdef REISERQUOTA_DEBUG
char key2type(struct key *ih)
{
if (is_direntry_le_key(2, ih))
return 'd';
if (is_direct_le_key(2, ih))
return 'D';
if (is_indirect_le_key(2, ih))
return 'i';
if (is_statdata_le_key(2, ih))
return 's';
return 'u';
}
char head2type(struct item_head *ih)
{
if (is_direntry_le_ih(ih))
return 'd';
if (is_direct_le_ih(ih))
return 'D';
if (is_indirect_le_ih(ih))
return 'i';
if (is_statdata_le_ih(ih))
return 's';
return 'u';
}
#endif
/* Delete object item. */ /* Delete object item. */
int reiserfs_delete_item (struct reiserfs_transaction_handle *th, int reiserfs_delete_item (struct reiserfs_transaction_handle *th,
struct path * p_s_path, /* Path to the deleted item. */ struct path * p_s_path, /* Path to the deleted item. */
const struct cpu_key * p_s_item_key, /* Key to search for the deleted item. */ const struct cpu_key * p_s_item_key, /* Key to search for the deleted item. */
struct inode * p_s_inode,/* inode is here just to update i_blocks */ struct inode * p_s_inode,/* inode is here just to update i_blocks and quotas */
struct buffer_head * p_s_un_bh) /* NULL or unformatted node pointer. */ struct buffer_head * p_s_un_bh) /* NULL or unformatted node pointer. */
{ {
struct super_block * p_s_sb = p_s_inode->i_sb; struct super_block * p_s_sb = p_s_inode->i_sb;
struct tree_balance s_del_balance; struct tree_balance s_del_balance;
struct item_head s_ih; struct item_head s_ih;
struct item_head *q_ih;
int quota_cut_bytes;
int n_ret_value, int n_ret_value,
n_del_size, n_del_size,
n_removed; n_removed;
...@@ -1268,6 +1293,22 @@ int reiserfs_delete_item (struct reiserfs_transaction_handle *th, ...@@ -1268,6 +1293,22 @@ int reiserfs_delete_item (struct reiserfs_transaction_handle *th,
// reiserfs_delete_item returns item length when success // reiserfs_delete_item returns item length when success
n_ret_value = calc_deleted_bytes_number(&s_del_balance, M_DELETE); n_ret_value = calc_deleted_bytes_number(&s_del_balance, M_DELETE);
q_ih = get_ih(p_s_path) ;
quota_cut_bytes = ih_item_len(q_ih) ;
/* hack so the quota code doesn't have to guess if the file
** has a tail. On tail insert, we allocate quota for 1 unformatted node.
** We test the offset because the tail might have been
** split into multiple items, and we only want to decrement for
** the unfm node once
*/
if (!S_ISLNK (p_s_inode->i_mode) && is_direct_le_ih(q_ih)) {
if ((le_ih_k_offset(q_ih) & (p_s_sb->s_blocksize - 1)) == 1) {
quota_cut_bytes = p_s_sb->s_blocksize + UNFM_P_SIZE;
} else {
quota_cut_bytes = 0 ;
}
}
if ( p_s_un_bh ) { if ( p_s_un_bh ) {
int off; int off;
...@@ -1299,10 +1340,14 @@ int reiserfs_delete_item (struct reiserfs_transaction_handle *th, ...@@ -1299,10 +1340,14 @@ int reiserfs_delete_item (struct reiserfs_transaction_handle *th,
B_I_PITEM(PATH_PLAST_BUFFER(p_s_path), &s_ih), n_ret_value); B_I_PITEM(PATH_PLAST_BUFFER(p_s_path), &s_ih), n_ret_value);
kunmap_atomic(data, KM_USER0); kunmap_atomic(data, KM_USER0);
} }
/* Perform balancing after all resources have been collected at once. */ /* Perform balancing after all resources have been collected at once. */
do_balance(&s_del_balance, NULL, NULL, M_DELETE); do_balance(&s_del_balance, NULL, NULL, M_DELETE);
#ifdef REISERQUOTA_DEBUG
printk(KERN_DEBUG "reiserquota delete_item(): freeing %u, id=%u type=%c\n", quota_cut_bytes, p_s_inode->i_uid, head2type(&s_ih));
#endif
DQUOT_FREE_SPACE_NODIRTY(p_s_inode, quota_cut_bytes);
/* Return deleted body length */ /* Return deleted body length */
return n_ret_value; return n_ret_value;
} }
...@@ -1327,14 +1372,16 @@ int reiserfs_delete_item (struct reiserfs_transaction_handle *th, ...@@ -1327,14 +1372,16 @@ int reiserfs_delete_item (struct reiserfs_transaction_handle *th,
/* this deletes item which never gets split */ /* this deletes item which never gets split */
void reiserfs_delete_solid_item (struct reiserfs_transaction_handle *th, void reiserfs_delete_solid_item (struct reiserfs_transaction_handle *th,
struct inode *inode,
struct key * key) struct key * key)
{ {
struct tree_balance tb; struct tree_balance tb;
INITIALIZE_PATH (path); INITIALIZE_PATH (path);
int item_len; int item_len = 0;
int tb_init = 0 ; int tb_init = 0 ;
struct cpu_key cpu_key; struct cpu_key cpu_key;
int retval; int retval;
int quota_cut_bytes = 0;
le_key2cpu_key (&cpu_key, key); le_key2cpu_key (&cpu_key, key);
...@@ -1358,6 +1405,7 @@ void reiserfs_delete_solid_item (struct reiserfs_transaction_handle *th, ...@@ -1358,6 +1405,7 @@ void reiserfs_delete_solid_item (struct reiserfs_transaction_handle *th,
item_len = ih_item_len( PATH_PITEM_HEAD(&path) ); item_len = ih_item_len( PATH_PITEM_HEAD(&path) );
init_tb_struct (th, &tb, th->t_super, &path, - (IH_SIZE + item_len)); init_tb_struct (th, &tb, th->t_super, &path, - (IH_SIZE + item_len));
} }
quota_cut_bytes = ih_item_len(PATH_PITEM_HEAD(&path)) ;
retval = fix_nodes (M_DELETE, &tb, NULL, 0); retval = fix_nodes (M_DELETE, &tb, NULL, 0);
if (retval == REPEAT_SEARCH) { if (retval == REPEAT_SEARCH) {
...@@ -1367,6 +1415,12 @@ void reiserfs_delete_solid_item (struct reiserfs_transaction_handle *th, ...@@ -1367,6 +1415,12 @@ void reiserfs_delete_solid_item (struct reiserfs_transaction_handle *th,
if (retval == CARRY_ON) { if (retval == CARRY_ON) {
do_balance (&tb, 0, 0, M_DELETE); do_balance (&tb, 0, 0, M_DELETE);
if (inode) { /* Should we count quota for item? (we don't count quotas for save-links) */
#ifdef REISERQUOTA_DEBUG
printk(KERN_DEBUG "reiserquota delete_solid_item(): freeing %u id=%u type=%c\n", quota_cut_bytes, inode->i_uid, key2type(key));
#endif
DQUOT_FREE_SPACE_NODIRTY(inode, quota_cut_bytes);
}
break; break;
} }
...@@ -1399,7 +1453,7 @@ void reiserfs_delete_object (struct reiserfs_transaction_handle *th, struct inod ...@@ -1399,7 +1453,7 @@ void reiserfs_delete_object (struct reiserfs_transaction_handle *th, struct inod
} }
/* USE_INODE_GENERATION_COUNTER */ /* USE_INODE_GENERATION_COUNTER */
#endif #endif
reiserfs_delete_solid_item (th, INODE_PKEY (inode)); reiserfs_delete_solid_item (th, inode, INODE_PKEY (inode));
} }
...@@ -1486,12 +1540,14 @@ int reiserfs_cut_from_item (struct reiserfs_transaction_handle *th, ...@@ -1486,12 +1540,14 @@ int reiserfs_cut_from_item (struct reiserfs_transaction_handle *th,
structure by using the init_tb_struct and fix_nodes functions. structure by using the init_tb_struct and fix_nodes functions.
After that we can make tree balancing. */ After that we can make tree balancing. */
struct tree_balance s_cut_balance; struct tree_balance s_cut_balance;
struct item_head *p_le_ih;
int n_cut_size = 0, /* Amount to be cut. */ int n_cut_size = 0, /* Amount to be cut. */
n_ret_value = CARRY_ON, n_ret_value = CARRY_ON,
n_removed = 0, /* Number of the removed unformatted nodes. */ n_removed = 0, /* Number of the removed unformatted nodes. */
n_is_inode_locked = 0; n_is_inode_locked = 0;
char c_mode; /* Mode of the balance. */ char c_mode; /* Mode of the balance. */
int retval2 = -1; int retval2 = -1;
int quota_cut_bytes;
init_tb_struct(th, &s_cut_balance, p_s_inode->i_sb, p_s_path, n_cut_size); init_tb_struct(th, &s_cut_balance, p_s_inode->i_sb, p_s_path, n_cut_size);
...@@ -1579,23 +1635,27 @@ int reiserfs_cut_from_item (struct reiserfs_transaction_handle *th, ...@@ -1579,23 +1635,27 @@ int reiserfs_cut_from_item (struct reiserfs_transaction_handle *th,
RFALSE( c_mode == M_PASTE || c_mode == M_INSERT, "invalid mode"); RFALSE( c_mode == M_PASTE || c_mode == M_INSERT, "invalid mode");
/* Calculate number of bytes that need to be cut from the item. */ /* Calculate number of bytes that need to be cut from the item. */
quota_cut_bytes = ( c_mode == M_DELETE ) ? ih_item_len(get_ih(p_s_path)) : -s_cut_balance.insert_size[0];
if (retval2 == -1) if (retval2 == -1)
n_ret_value = calc_deleted_bytes_number(&s_cut_balance, c_mode); n_ret_value = calc_deleted_bytes_number(&s_cut_balance, c_mode);
else else
n_ret_value = retval2; n_ret_value = retval2;
if ( c_mode == M_DELETE ) {
struct item_head * p_le_ih = PATH_PITEM_HEAD (s_cut_balance.tb_path);
if ( is_direct_le_ih (p_le_ih) && (le_ih_k_offset (p_le_ih) & (p_s_sb->s_blocksize - 1)) == 1 ) { /* For direct items, we only change the quota when deleting the last
/* we delete first part of tail which was stored in direct ** item.
item(s) */ */
p_le_ih = PATH_PITEM_HEAD (s_cut_balance.tb_path);
if (!S_ISLNK (p_s_inode->i_mode) && is_direct_le_ih(p_le_ih)) {
if (c_mode == M_DELETE &&
(le_ih_k_offset (p_le_ih) & (p_s_sb->s_blocksize - 1)) == 1 ) {
// FIXME: this is to keep 3.5 happy // FIXME: this is to keep 3.5 happy
REISERFS_I(p_s_inode)->i_first_direct_byte = U32_MAX; REISERFS_I(p_s_inode)->i_first_direct_byte = U32_MAX;
p_s_inode->i_blocks -= p_s_sb->s_blocksize / 512; quota_cut_bytes = p_s_sb->s_blocksize + UNFM_P_SIZE ;
} else {
quota_cut_bytes = 0 ;
} }
} }
#ifdef CONFIG_REISERFS_CHECK #ifdef CONFIG_REISERFS_CHECK
if (n_is_inode_locked) { if (n_is_inode_locked) {
struct item_head * le_ih = PATH_PITEM_HEAD (s_cut_balance.tb_path); struct item_head * le_ih = PATH_PITEM_HEAD (s_cut_balance.tb_path);
...@@ -1630,10 +1690,13 @@ int reiserfs_cut_from_item (struct reiserfs_transaction_handle *th, ...@@ -1630,10 +1690,13 @@ int reiserfs_cut_from_item (struct reiserfs_transaction_handle *th,
*/ */
REISERFS_I(p_s_inode)->i_flags &= ~i_pack_on_close_mask ; REISERFS_I(p_s_inode)->i_flags &= ~i_pack_on_close_mask ;
} }
#ifdef REISERQUOTA_DEBUG
printk(KERN_DEBUG "reiserquota cut_from_item(): freeing %u id=%u type=%c\n", quota_cut_bytes, p_s_inode->i_uid, '?');
#endif
DQUOT_FREE_SPACE_NODIRTY(p_s_inode, quota_cut_bytes);
return n_ret_value; return n_ret_value;
} }
static void truncate_directory (struct reiserfs_transaction_handle *th, struct inode * inode) static void truncate_directory (struct reiserfs_transaction_handle *th, struct inode * inode)
{ {
if (inode->i_nlink) if (inode->i_nlink)
...@@ -1641,8 +1704,8 @@ static void truncate_directory (struct reiserfs_transaction_handle *th, struct i ...@@ -1641,8 +1704,8 @@ static void truncate_directory (struct reiserfs_transaction_handle *th, struct i
set_le_key_k_offset (KEY_FORMAT_3_5, INODE_PKEY (inode), DOT_OFFSET); set_le_key_k_offset (KEY_FORMAT_3_5, INODE_PKEY (inode), DOT_OFFSET);
set_le_key_k_type (KEY_FORMAT_3_5, INODE_PKEY (inode), TYPE_DIRENTRY); set_le_key_k_type (KEY_FORMAT_3_5, INODE_PKEY (inode), TYPE_DIRENTRY);
reiserfs_delete_solid_item (th, INODE_PKEY (inode)); reiserfs_delete_solid_item (th, inode, INODE_PKEY (inode));
reiserfs_update_sd(th, inode) ;
set_le_key_k_offset (KEY_FORMAT_3_5, INODE_PKEY (inode), SD_OFFSET); set_le_key_k_offset (KEY_FORMAT_3_5, INODE_PKEY (inode), SD_OFFSET);
set_le_key_k_type (KEY_FORMAT_3_5, INODE_PKEY (inode), TYPE_STAT_DATA); set_le_key_k_type (KEY_FORMAT_3_5, INODE_PKEY (inode), TYPE_STAT_DATA);
} }
...@@ -1809,18 +1872,37 @@ static void check_research_for_paste (struct path * path, ...@@ -1809,18 +1872,37 @@ static void check_research_for_paste (struct path * path,
int reiserfs_paste_into_item (struct reiserfs_transaction_handle *th, int reiserfs_paste_into_item (struct reiserfs_transaction_handle *th,
struct path * p_s_search_path, /* Path to the pasted item. */ struct path * p_s_search_path, /* Path to the pasted item. */
const struct cpu_key * p_s_key, /* Key to search for the needed item.*/ const struct cpu_key * p_s_key, /* Key to search for the needed item.*/
struct inode * inode, /* Inode item belongs to */
const char * p_c_body, /* Pointer to the bytes to paste. */ const char * p_c_body, /* Pointer to the bytes to paste. */
int n_pasted_size) /* Size of pasted bytes. */ int n_pasted_size) /* Size of pasted bytes. */
{ {
struct tree_balance s_paste_balance; struct tree_balance s_paste_balance;
int retval; int retval;
int fs_gen;
fs_gen = get_generation(inode->i_sb) ;
#ifdef REISERQUOTA_DEBUG
printk(KERN_DEBUG "reiserquota paste_into_item(): allocating %u id=%u type=%c\n", n_pasted_size, inode->i_uid, key2type(&(p_s_key->on_disk_key)));
#endif
if (DQUOT_ALLOC_SPACE_NODIRTY(inode, n_pasted_size)) {
pathrelse(p_s_search_path);
return -EDQUOT;
}
init_tb_struct(th, &s_paste_balance, th->t_super, p_s_search_path, n_pasted_size); init_tb_struct(th, &s_paste_balance, th->t_super, p_s_search_path, n_pasted_size);
#ifdef DISPLACE_NEW_PACKING_LOCALITIES #ifdef DISPLACE_NEW_PACKING_LOCALITIES
s_paste_balance.key = p_s_key->on_disk_key; s_paste_balance.key = p_s_key->on_disk_key;
#endif #endif
while ( (retval = fix_nodes(M_PASTE, &s_paste_balance, NULL, p_c_body)) == REPEAT_SEARCH ) { /* DQUOT_* can schedule, must check before the fix_nodes */
if (fs_changed(fs_gen, inode->i_sb)) {
goto search_again;
}
while ((retval = fix_nodes(M_PASTE, &s_paste_balance, NULL, p_c_body)) ==
REPEAT_SEARCH ) {
search_again:
/* file system changed while we were in the fix_nodes */ /* file system changed while we were in the fix_nodes */
PROC_INFO_INC( th -> t_super, paste_into_item_restarted ); PROC_INFO_INC( th -> t_super, paste_into_item_restarted );
retval = search_for_position_by_key (th->t_super, p_s_key, p_s_search_path); retval = search_for_position_by_key (th->t_super, p_s_key, p_s_search_path);
...@@ -1849,6 +1931,10 @@ int reiserfs_paste_into_item (struct reiserfs_transaction_handle *th, ...@@ -1849,6 +1931,10 @@ int reiserfs_paste_into_item (struct reiserfs_transaction_handle *th,
error_out: error_out:
/* this also releases the path */ /* this also releases the path */
unfix_nodes(&s_paste_balance); unfix_nodes(&s_paste_balance);
#ifdef REISERQUOTA_DEBUG
printk(KERN_DEBUG "reiserquota paste_into_item(): freeing %u id=%u type=%c\n", n_pasted_size, inode->i_uid, key2type(&(p_s_key->on_disk_key)));
#endif
DQUOT_FREE_SPACE_NODIRTY(inode, n_pasted_size);
return retval ; return retval ;
} }
...@@ -1858,23 +1944,45 @@ int reiserfs_insert_item(struct reiserfs_transaction_handle *th, ...@@ -1858,23 +1944,45 @@ int reiserfs_insert_item(struct reiserfs_transaction_handle *th,
struct path * p_s_path, /* Path to the inserteded item. */ struct path * p_s_path, /* Path to the inserteded item. */
const struct cpu_key * key, const struct cpu_key * key,
struct item_head * p_s_ih, /* Pointer to the item header to insert.*/ struct item_head * p_s_ih, /* Pointer to the item header to insert.*/
struct inode * inode,
const char * p_c_body) /* Pointer to the bytes to insert. */ const char * p_c_body) /* Pointer to the bytes to insert. */
{ {
struct tree_balance s_ins_balance; struct tree_balance s_ins_balance;
int retval; int retval;
int fs_gen = 0 ;
int quota_bytes = 0 ;
if (inode) { /* Do we count quotas for item? */
fs_gen = get_generation(inode->i_sb);
quota_bytes = ih_item_len(p_s_ih);
/* hack so the quota code doesn't have to guess if the file has
** a tail, links are always tails, so there's no guessing needed
*/
if (!S_ISLNK (inode->i_mode) && is_direct_le_ih(p_s_ih)) {
quota_bytes = inode->i_sb->s_blocksize + UNFM_P_SIZE ;
}
#ifdef REISERQUOTA_DEBUG
printk(KERN_DEBUG "reiserquota insert_item(): allocating %u id=%u type=%c\n", quota_bytes, inode->i_uid, head2type(p_s_ih));
#endif
/* We can't dirty inode here. It would be immediately written but
* appropriate stat item isn't inserted yet... */
if (DQUOT_ALLOC_SPACE_NODIRTY(inode, quota_bytes)) {
pathrelse(p_s_path);
return -EDQUOT;
}
}
init_tb_struct(th, &s_ins_balance, th->t_super, p_s_path, IH_SIZE + ih_item_len(p_s_ih)); init_tb_struct(th, &s_ins_balance, th->t_super, p_s_path, IH_SIZE + ih_item_len(p_s_ih));
#ifdef DISPLACE_NEW_PACKING_LOCALITIES #ifdef DISPLACE_NEW_PACKING_LOCALITIES
s_ins_balance.key = key->on_disk_key; s_ins_balance.key = key->on_disk_key;
#endif #endif
/* DQUOT_* can schedule, must check to be sure calling fix_nodes is safe */
/* if (inode && fs_changed(fs_gen, inode->i_sb)) {
if (p_c_body == 0) goto search_again;
n_zeros_num = ih_item_len(p_s_ih); }
*/
// le_key2cpu_key (&key, &(p_s_ih->ih_key));
while ( (retval = fix_nodes(M_INSERT, &s_ins_balance, p_s_ih, p_c_body)) == REPEAT_SEARCH) { while ( (retval = fix_nodes(M_INSERT, &s_ins_balance, p_s_ih, p_c_body)) == REPEAT_SEARCH) {
search_again:
/* file system changed while we were in the fix_nodes */ /* file system changed while we were in the fix_nodes */
PROC_INFO_INC( th -> t_super, insert_item_restarted ); PROC_INFO_INC( th -> t_super, insert_item_restarted );
retval = search_item (th->t_super, key, p_s_path); retval = search_item (th->t_super, key, p_s_path);
...@@ -1900,6 +2008,11 @@ int reiserfs_insert_item(struct reiserfs_transaction_handle *th, ...@@ -1900,6 +2008,11 @@ int reiserfs_insert_item(struct reiserfs_transaction_handle *th,
error_out: error_out:
/* also releases the path */ /* also releases the path */
unfix_nodes(&s_ins_balance); unfix_nodes(&s_ins_balance);
#ifdef REISERQUOTA_DEBUG
printk(KERN_DEBUG "reiserquota insert_item(): freeing %u id=%u type=%c\n", quota_bytes, inode->i_uid, head2type(p_s_ih));
#endif
if (inode)
DQUOT_FREE_SPACE_NODIRTY(inode, quota_bytes) ;
return retval; return retval;
} }
......
...@@ -115,7 +115,7 @@ static void remove_save_link_only (struct super_block * s, struct key * key, int ...@@ -115,7 +115,7 @@ static void remove_save_link_only (struct super_block * s, struct key * key, int
/* we are going to do one balancing */ /* we are going to do one balancing */
journal_begin (&th, s, JOURNAL_PER_BALANCE_CNT); journal_begin (&th, s, JOURNAL_PER_BALANCE_CNT);
reiserfs_delete_solid_item (&th, key); reiserfs_delete_solid_item (&th, NULL, key);
if (oid_free) if (oid_free)
/* removals are protected by direct items */ /* removals are protected by direct items */
reiserfs_release_objectid (&th, le32_to_cpu (key->k_objectid)); reiserfs_release_objectid (&th, le32_to_cpu (key->k_objectid));
...@@ -301,8 +301,8 @@ void add_save_link (struct reiserfs_transaction_handle * th, ...@@ -301,8 +301,8 @@ void add_save_link (struct reiserfs_transaction_handle * th,
/* body of "save" link */ /* body of "save" link */
link = INODE_PKEY (inode)->k_dir_id; link = INODE_PKEY (inode)->k_dir_id;
/* put "save" link inot tree */ /* put "save" link inot tree, don't charge quota to anyone */
retval = reiserfs_insert_item (th, &path, &key, &ih, (char *)&link); retval = reiserfs_insert_item (th, &path, &key, &ih, NULL, (char *)&link);
if (retval) { if (retval) {
if (retval != -ENOSPC) if (retval != -ENOSPC)
reiserfs_warning ("vs-2120: add_save_link: insert_item returned %d\n", reiserfs_warning ("vs-2120: add_save_link: insert_item returned %d\n",
...@@ -344,7 +344,8 @@ void remove_save_link (struct inode * inode, int truncate) ...@@ -344,7 +344,8 @@ void remove_save_link (struct inode * inode, int truncate)
( REISERFS_I(inode) -> i_flags & i_link_saved_truncate_mask ) ) || ( REISERFS_I(inode) -> i_flags & i_link_saved_truncate_mask ) ) ||
( !truncate && ( !truncate &&
( REISERFS_I(inode) -> i_flags & i_link_saved_unlink_mask ) ) ) ( REISERFS_I(inode) -> i_flags & i_link_saved_unlink_mask ) ) )
reiserfs_delete_solid_item (&th, &key); /* don't take quota bytes from anywhere */
reiserfs_delete_solid_item (&th, NULL, &key);
if (!truncate) { if (!truncate) {
reiserfs_release_objectid (&th, inode->i_ino); reiserfs_release_objectid (&th, inode->i_ino);
REISERFS_I(inode) -> i_flags &= ~i_link_saved_unlink_mask; REISERFS_I(inode) -> i_flags &= ~i_link_saved_unlink_mask;
...@@ -714,6 +715,8 @@ static int reiserfs_parse_options (struct super_block * s, char * options, /* st ...@@ -714,6 +715,8 @@ static int reiserfs_parse_options (struct super_block * s, char * options, /* st
{"jdev", 'j', 0, 0, 0}, {"jdev", 'j', 0, 0, 0},
{"nolargeio", 'w', 0, 0, 0}, {"nolargeio", 'w', 0, 0, 0},
{"commit", 'c', 0, 0, 0}, {"commit", 'c', 0, 0, 0},
{"usrquota", 0, 0, 0, 0},
{"grpquota", 0, 0, 0, 0},
{NULL, 0, 0, 0, 0} {NULL, 0, 0, 0, 0}
}; };
......
...@@ -66,11 +66,11 @@ int direct2indirect (struct reiserfs_transaction_handle *th, struct inode * inod ...@@ -66,11 +66,11 @@ int direct2indirect (struct reiserfs_transaction_handle *th, struct inode * inod
set_ih_free_space (&ind_ih, 0); /* delete at nearest future */ set_ih_free_space (&ind_ih, 0); /* delete at nearest future */
put_ih_item_len( &ind_ih, UNFM_P_SIZE ); put_ih_item_len( &ind_ih, UNFM_P_SIZE );
PATH_LAST_POSITION (path)++; PATH_LAST_POSITION (path)++;
n_retval = reiserfs_insert_item (th, path, &end_key, &ind_ih, n_retval = reiserfs_insert_item (th, path, &end_key, &ind_ih, inode,
(char *)&unfm_ptr); (char *)&unfm_ptr);
} else { } else {
/* Paste into last indirect item of an object. */ /* Paste into last indirect item of an object. */
n_retval = reiserfs_paste_into_item(th, path, &end_key, n_retval = reiserfs_paste_into_item(th, path, &end_key, inode,
(char *)&unfm_ptr, UNFM_P_SIZE); (char *)&unfm_ptr, UNFM_P_SIZE);
} }
if ( n_retval ) { if ( n_retval ) {
...@@ -274,7 +274,7 @@ int indirect2direct (struct reiserfs_transaction_handle *th, ...@@ -274,7 +274,7 @@ int indirect2direct (struct reiserfs_transaction_handle *th,
set_cpu_key_k_type (&key, TYPE_DIRECT); set_cpu_key_k_type (&key, TYPE_DIRECT);
key.key_length = 4; key.key_length = 4;
/* Insert tail as new direct item in the tree */ /* Insert tail as new direct item in the tree */
if ( reiserfs_insert_item(th, p_s_path, &key, &s_ih, if ( reiserfs_insert_item(th, p_s_path, &key, &s_ih, p_s_inode,
tail ? tail : NULL) < 0 ) { tail ? tail : NULL) < 0 ) {
/* No disk memory. So we can not convert last unformatted node /* No disk memory. So we can not convert last unformatted node
to the direct item. In this case we used to adjust to the direct item. In this case we used to adjust
...@@ -292,13 +292,15 @@ int indirect2direct (struct reiserfs_transaction_handle *th, ...@@ -292,13 +292,15 @@ int indirect2direct (struct reiserfs_transaction_handle *th,
*/ */
unmap_buffers(page, pos1) ; unmap_buffers(page, pos1) ;
/* make sure to get the i_blocks changes from reiserfs_insert_item */
reiserfs_update_sd(th, p_s_inode);
// note: we have now the same as in above direct2indirect // note: we have now the same as in above direct2indirect
// conversion: there are two keys which have matching first three // conversion: there are two keys which have matching first three
// key components. They only differ by the fouhth one. // key components. They only differ by the fouhth one.
/* We have inserted new direct item and must remove last /* We have inserted new direct item and must remove last
unformatted node. */ unformatted node. */
p_s_inode->i_blocks += (p_s_sb->s_blocksize / 512);
*p_c_mode = M_CUT; *p_c_mode = M_CUT;
/* we store position of first direct item in the in-core inode */ /* we store position of first direct item in the in-core inode */
......
...@@ -268,6 +268,7 @@ int is_reiserfs_jr (struct reiserfs_super_block * rs); ...@@ -268,6 +268,7 @@ int is_reiserfs_jr (struct reiserfs_super_block * rs);
#define NO_DISK_SPACE -3 #define NO_DISK_SPACE -3
#define NO_BALANCING_NEEDED (-4) #define NO_BALANCING_NEEDED (-4)
#define NO_MORE_UNUSED_CONTIGUOUS_BLOCKS (-5) #define NO_MORE_UNUSED_CONTIGUOUS_BLOCKS (-5)
#define QUOTA_EXCEEDED -6
typedef __u32 b_blocknr_t; typedef __u32 b_blocknr_t;
typedef __u32 unp_t; typedef __u32 unp_t;
...@@ -1238,7 +1239,6 @@ excessive effort to avoid disturbing the precious VFS code.:-( The ...@@ -1238,7 +1239,6 @@ excessive effort to avoid disturbing the precious VFS code.:-( The
gods only know how we are going to SMP the code that uses them. gods only know how we are going to SMP the code that uses them.
znodes are the way! */ znodes are the way! */
struct path { struct path {
int path_length; /* Length of the array above. */ int path_length; /* Length of the array above. */
struct path_element path_elements[EXTENDED_MAX_HEIGHT]; /* Array of the path elements. */ struct path_element path_elements[EXTENDED_MAX_HEIGHT]; /* Array of the path elements. */
...@@ -1889,11 +1889,13 @@ void pathrelse_and_restore (struct super_block *s, struct path * p_s_search_path ...@@ -1889,11 +1889,13 @@ void pathrelse_and_restore (struct super_block *s, struct path * p_s_search_path
int reiserfs_insert_item (struct reiserfs_transaction_handle *th, int reiserfs_insert_item (struct reiserfs_transaction_handle *th,
struct path * path, struct path * path,
const struct cpu_key * key, const struct cpu_key * key,
struct item_head * ih, const char * body); struct item_head * ih,
struct inode *inode, const char * body);
int reiserfs_paste_into_item (struct reiserfs_transaction_handle *th, int reiserfs_paste_into_item (struct reiserfs_transaction_handle *th,
struct path * path, struct path * path,
const struct cpu_key * key, const struct cpu_key * key,
struct inode *inode,
const char * body, int paste_size); const char * body, int paste_size);
int reiserfs_cut_from_item (struct reiserfs_transaction_handle *th, int reiserfs_cut_from_item (struct reiserfs_transaction_handle *th,
...@@ -1910,7 +1912,7 @@ int reiserfs_delete_item (struct reiserfs_transaction_handle *th, ...@@ -1910,7 +1912,7 @@ int reiserfs_delete_item (struct reiserfs_transaction_handle *th,
struct buffer_head * p_s_un_bh); struct buffer_head * p_s_un_bh);
void reiserfs_delete_solid_item (struct reiserfs_transaction_handle *th, void reiserfs_delete_solid_item (struct reiserfs_transaction_handle *th,
struct key * key); struct inode *inode, struct key * key);
void reiserfs_delete_object (struct reiserfs_transaction_handle *th, struct inode * p_s_inode); void reiserfs_delete_object (struct reiserfs_transaction_handle *th, struct inode * p_s_inode);
void reiserfs_do_truncate (struct reiserfs_transaction_handle *th, void reiserfs_do_truncate (struct reiserfs_transaction_handle *th,
struct inode * p_s_inode, struct page *, struct inode * p_s_inode, struct page *,
...@@ -1955,8 +1957,18 @@ int reiserfs_new_inode (struct reiserfs_transaction_handle *th, ...@@ -1955,8 +1957,18 @@ int reiserfs_new_inode (struct reiserfs_transaction_handle *th,
struct inode * dir, int mode, struct inode * dir, int mode,
const char * symname, loff_t i_size, const char * symname, loff_t i_size,
struct dentry *dentry, struct inode *inode); struct dentry *dentry, struct inode *inode);
int reiserfs_sync_inode (struct reiserfs_transaction_handle *th, struct inode * inode);
void reiserfs_update_sd (struct reiserfs_transaction_handle *th, struct inode * inode); int reiserfs_sync_inode (struct reiserfs_transaction_handle *th,
struct inode * inode);
void reiserfs_update_sd_size (struct reiserfs_transaction_handle *th,
struct inode * inode, loff_t size);
static inline void reiserfs_update_sd(struct reiserfs_transaction_handle *th,
struct inode *inode)
{
reiserfs_update_sd_size(th, inode, inode->i_size) ;
}
void sd_attrs_to_i_attrs( __u16 sd_attrs, struct inode *inode ); void sd_attrs_to_i_attrs( __u16 sd_attrs, struct inode *inode );
void i_attrs_to_sd_attrs( struct inode *inode, __u16 *sd_attrs ); void i_attrs_to_sd_attrs( struct inode *inode, __u16 *sd_attrs );
...@@ -2139,7 +2151,7 @@ typedef struct __reiserfs_blocknr_hint reiserfs_blocknr_hint_t; ...@@ -2139,7 +2151,7 @@ typedef struct __reiserfs_blocknr_hint reiserfs_blocknr_hint_t;
int reiserfs_parse_alloc_options (struct super_block *, char *); int reiserfs_parse_alloc_options (struct super_block *, char *);
int is_reusable (struct super_block * s, b_blocknr_t block, int bit_value); int is_reusable (struct super_block * s, b_blocknr_t block, int bit_value);
void reiserfs_free_block (struct reiserfs_transaction_handle *th, b_blocknr_t); void reiserfs_free_block (struct reiserfs_transaction_handle *th, struct inode *, b_blocknr_t, int for_unformatted);
int reiserfs_allocate_blocknrs(reiserfs_blocknr_hint_t *, b_blocknr_t * , int, int); int reiserfs_allocate_blocknrs(reiserfs_blocknr_hint_t *, b_blocknr_t * , int, int);
extern inline int reiserfs_new_form_blocknrs (struct tree_balance * tb, extern inline int reiserfs_new_form_blocknrs (struct tree_balance * tb,
b_blocknr_t *new_blocknrs, int amount_needed) b_blocknr_t *new_blocknrs, int amount_needed)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment