From: Chris Mason ReiserFS support for quotas. Originally from Jan Kara --- 25-akpm/fs/reiserfs/bitmap.c | 70 ++++++++++--- 25-akpm/fs/reiserfs/do_balan.c | 6 - 25-akpm/fs/reiserfs/file.c | 12 +- 25-akpm/fs/reiserfs/fix_node.c | 7 - 25-akpm/fs/reiserfs/inode.c | 152 ++++++++++++++++++++-------- 25-akpm/fs/reiserfs/namei.c | 14 +- 25-akpm/fs/reiserfs/stree.c | 179 +++++++++++++++++++++++++++------- 25-akpm/fs/reiserfs/super.c | 11 +- 25-akpm/fs/reiserfs/tail_conversion.c | 10 + 25-akpm/include/linux/reiserfs_fs.h | 24 +++- 10 files changed, 364 insertions(+), 121 deletions(-) diff -puN fs/reiserfs/bitmap.c~reiserfs-quota fs/reiserfs/bitmap.c --- 25/fs/reiserfs/bitmap.c~reiserfs-quota Fri Apr 23 14:36:54 2004 +++ 25-akpm/fs/reiserfs/bitmap.c Fri Apr 23 14:36:54 2004 @@ -12,6 +12,7 @@ #include #include #include +#include #define PREALLOCATION_SIZE 9 @@ -281,7 +282,8 @@ static int scan_bitmap (struct reiserfs_ } 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 reiserfs_super_block * rs; @@ -323,11 +325,13 @@ static void _reiserfs_free_block (struct set_sb_free_blocks( rs, sb_free_blocks(rs) + 1 ); 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, - b_blocknr_t block) + struct inode *inode, b_blocknr_t block, + int for_unformatted) { struct super_block * s = th->t_super; @@ -335,42 +339,46 @@ void reiserfs_free_block (struct reiserf RFALSE(is_reusable (s, block, 1) == 0, "vs-4071: can not free such block"); /* mark it before we clear it, just in case */ 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 */ 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(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, struct reiserfs_inode_info *ei) { unsigned long save = ei->i_prealloc_block ; + int dirty = 0; + struct inode *inode = &ei->vfs_inode; #ifdef CONFIG_REISERFS_CHECK if (ei->i_prealloc_count < 0) reiserfs_warning("zam-4001:%s: inode has negative prealloc blocks count.\n", __FUNCTION__ ); #endif 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_count --; + dirty = 1; } + if (dirty) + reiserfs_update_sd(th, inode); ei->i_prealloc_block = save; list_del_init(&(ei->i_prealloc_list)); } /* FIXME: It should be inline function */ void reiserfs_discard_prealloc (struct reiserfs_transaction_handle *th, - struct inode * inode) + struct inode *inode) { struct reiserfs_inode_info *ei = REISERFS_I(inode); - if (ei->i_prealloc_count) { + if (ei->i_prealloc_count) __discard_prealloc(th, ei); - } } void reiserfs_discard_all_prealloc (struct reiserfs_transaction_handle *th) @@ -772,6 +780,24 @@ static inline int blocknrs_and_prealloc_ int nr_allocated = 0; 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 += allocate_without_wrapping_disk(hint, new_blocknrs + nr_allocated, start, finish, amount_needed - nr_allocated, hint->prealloc_size)) @@ -779,8 +805,14 @@ static inline int blocknrs_and_prealloc_ /* not all blocks were successfully allocated yet*/ 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 --) - 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; } else { /* refine search parameters for next pass */ @@ -789,7 +821,19 @@ static inline int blocknrs_and_prealloc_ start = 0; 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; } @@ -858,7 +902,7 @@ int reiserfs_allocate_blocknrs(reiserfs_ if (ret != CARRY_ON) { 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; diff -puN fs/reiserfs/do_balan.c~reiserfs-quota fs/reiserfs/do_balan.c --- 25/fs/reiserfs/do_balan.c~reiserfs-quota Fri Apr 23 14:36:54 2004 +++ 25-akpm/fs/reiserfs/do_balan.c Fri Apr 23 14:36:54 2004 @@ -1234,7 +1234,7 @@ static void free_thrown(struct tree_bala if (buffer_dirty (tb->thrown[i])) printk ("free_thrown deals with dirty buffer %d\n", blocknr); 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 set_blkh_nr_item( blkh, 0 ); 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); } diff -puN fs/reiserfs/file.c~reiserfs-quota fs/reiserfs/file.c --- 25/fs/reiserfs/file.c~reiserfs-quota Fri Apr 23 14:36:54 2004 +++ 25-akpm/fs/reiserfs/file.c Fri Apr 23 14:36:54 2004 @@ -13,6 +13,7 @@ #include #include #include +#include /* ** 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( /* Ok, there is existing indirect item already. Need to append it */ /* 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); - 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 ) { kfree(zeros); goto error_exit_free_blocks; @@ -304,7 +305,7 @@ int reiserfs_allocate_blocks_for_region( kfree(zeros); 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 { reiserfs_panic(inode->i_sb, "green-9011: Unexpected key type %K\n", &key); } @@ -421,7 +422,7 @@ retry: // position. We do not need to recalculate path as it should // 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); - 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 ) { goto error_exit_free_blocks; } @@ -452,7 +453,7 @@ retry: goto error_exit_free_blocks; } /* 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 { reiserfs_panic(inode->i_sb, "green-9010: unexpected item type for key %K\n",&key); } @@ -462,7 +463,6 @@ retry: // unless we return an error, they are also responsible for logging // the inode. // - inode->i_blocks += blocks_to_allocate << (inode->i_blkbits - 9); pathrelse(&path); reiserfs_write_unlock(inode->i_sb); @@ -508,7 +508,7 @@ error_exit_free_blocks: pathrelse(&path); // free blocks 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: reiserfs_update_sd(th, inode); // update any changes we made to blk count diff -puN fs/reiserfs/fix_node.c~reiserfs-quota fs/reiserfs/fix_node.c --- 25/fs/reiserfs/fix_node.c~reiserfs-quota Fri Apr 23 14:36:54 2004 +++ 25-akpm/fs/reiserfs/fix_node.c Fri Apr 23 14:36:54 2004 @@ -795,8 +795,9 @@ static int get_empty_nodes( else /* If we have enough already then there is nothing to do. */ return CARRY_ON; - if ( reiserfs_new_form_blocknrs (p_s_tb, a_n_blocknrs, - n_amount_needed) == NO_DISK_SPACE ) + /* No need to check quota - is not allocated for blocks used for formatted nodes */ + if (reiserfs_new_form_blocknrs (p_s_tb, a_n_blocknrs, + n_amount_needed) == NO_DISK_SPACE) return NO_DISK_SPACE; /* for each blocknumber we just got, get a buffer and stick it on FEB */ @@ -2492,7 +2493,7 @@ void unfix_nodes (struct tree_balance * /* de-allocated block which was not used by balancing and bforget about buffer for it */ brelse (tb->FEB[i]); - reiserfs_free_block (tb->transaction_handle, blocknr); + reiserfs_free_block (tb->transaction_handle, NULL, blocknr, 0); } if (tb->used[i]) { /* release used as new nodes including a new root */ diff -puN fs/reiserfs/inode.c~reiserfs-quota fs/reiserfs/inode.c --- 25/fs/reiserfs/inode.c~reiserfs-quota Fri Apr 23 14:36:54 2004 +++ 25-akpm/fs/reiserfs/inode.c Fri Apr 23 14:36:54 2004 @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -39,6 +40,7 @@ void reiserfs_delete_inode (struct inode 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); @@ -647,7 +649,7 @@ start_trans: 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 ** some blocks. releases the path, so we have to go back to ** research if we succeed on the second try @@ -656,10 +658,13 @@ start_trans: restart_transaction(th, inode, &path) ; 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 ; } - retval = -ENOSPC; + if (repeat == QUOTA_EXCEEDED) + retval = -EDQUOT; + else + retval = -ENOSPC; goto failure; } @@ -687,7 +692,6 @@ start_trans: put_block_num(item, pos_in_item, allocated_block_nr) ; unfm_ptr = allocated_block_nr; journal_mark_dirty (th, inode->i_sb, bh); - inode->i_blocks += (inode->i_sb->s_blocksize / 512) ; reiserfs_update_sd(th, inode) ; } set_block_dev_mapped(bh_result, unfm_ptr, inode); @@ -734,13 +738,11 @@ start_trans: set_cpu_key_k_offset (&tmp_key, 1); 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) { - reiserfs_free_block (th, allocated_block_nr); - goto failure; // retval == -ENOSPC or -EIO or -EEXIST + reiserfs_free_block (th, inode, allocated_block_nr, 1); + goto failure; // retval == -ENOSPC, -EDQUOT or -EIO or -EEXIST } - if (unp) - inode->i_blocks += inode->i_sb->s_blocksize / 512; //mark_tail_converted (inode); } else if (is_direct_le_ih (ih)) { /* direct item has to be converted */ @@ -778,7 +780,7 @@ start_trans: if (!th) th = reiserfs_persistent_transaction(inode->i_sb,3); if (th) - reiserfs_free_block (th, allocated_block_nr); + reiserfs_free_block (th,inode,allocated_block_nr,1); } goto failure ; } @@ -787,7 +789,7 @@ start_trans: retval = direct2indirect (th, inode, &path, unbh, tail_offset); if (retval) { reiserfs_unmap_buffer(unbh); - reiserfs_free_block (th, allocated_block_nr); + reiserfs_free_block (th, inode, allocated_block_nr, 1); goto failure; } /* it is important the set_buffer_uptodate is done after @@ -820,9 +822,6 @@ start_trans: */ mark_buffer_dirty(unbh) ; } - - //inode->i_blocks += inode->i_sb->s_blocksize / 512; - //mark_tail_converted (inode); } else { /* append indirect item with holes if needed, when appending pointer to 'block'-th block use block, which is already @@ -870,24 +869,21 @@ start_trans: only have space for one block */ 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) kfree(un); if (retval) { - reiserfs_free_block (th, allocated_block_nr); + reiserfs_free_block (th, inode, allocated_block_nr, 1); goto failure; } - if (done) { - inode->i_blocks += inode->i_sb->s_blocksize / 512; - } else { + if (!done) { /* We need to mark new file size in case this function will be interrupted/aborted later on. And we may do this only for holes. */ inode->i_size += inode->i_sb->s_blocksize * blocks_needed; } - //mark_tail_converted (inode); } if (done == 1) @@ -919,7 +915,7 @@ start_trans: "%K should not be found\n", &key); retval = -EEXIST; if (allocated_block_nr) - reiserfs_free_block (th, allocated_block_nr); + reiserfs_free_block (th, inode, allocated_block_nr, 1); pathrelse(&path) ; goto failure; } @@ -949,6 +945,58 @@ reiserfs_readpages(struct file *file, st 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 // of old type. Version stored in the inode says about body items, so @@ -1014,6 +1062,14 @@ static void init_inode (struct inode * i rdev = sd_v1_rdev(sd); REISERFS_I(inode)->i_first_direct_byte = sd_v1_first_direct_byte(sd); + /* an early bug in the quota code can give us an odd number for the + ** block count. This is incorrect, fix it here. + */ + if (inode->i_blocks & 1) { + inode->i_blocks++ ; + } + inode_set_bytes(inode, to_real_used_space(inode, inode->i_blocks, + SD_V1_SIZE)); /* nopack is initially zero for v1 objects. For v2 objects, nopack is initialised from sd_attrs */ REISERFS_I(inode)->i_flags &= ~i_nopack_mask; @@ -1046,6 +1102,8 @@ static void init_inode (struct inode * i set_inode_item_key_version (inode, KEY_FORMAT_3_6); REISERFS_I(inode)->i_first_direct_byte = 0; set_inode_sd_version (inode, STAT_DATA_V2); + inode_set_bytes(inode, to_real_used_space(inode, inode->i_blocks, + SD_V2_SIZE)); /* read persistent inode attributes from sd and initalise generic inode flags from them */ REISERFS_I(inode)->i_attrs = sd_v2_attrs( sd ); @@ -1072,7 +1130,7 @@ static void init_inode (struct inode * i // 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; __u16 flags; @@ -1080,12 +1138,12 @@ static void inode2sd (void * sd, struct set_sd_v2_mode(sd_v2, inode->i_mode ); set_sd_v2_nlink(sd_v2, inode->i_nlink ); set_sd_v2_uid(sd_v2, inode->i_uid ); - set_sd_v2_size(sd_v2, inode->i_size ); + set_sd_v2_size(sd_v2, size ); set_sd_v2_gid(sd_v2, inode->i_gid ); set_sd_v2_mtime(sd_v2, inode->i_mtime.tv_sec ); set_sd_v2_atime(sd_v2, inode->i_atime.tv_sec ); set_sd_v2_ctime(sd_v2, inode->i_ctime.tv_sec ); - set_sd_v2_blocks(sd_v2, 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)) set_sd_v2_rdev(sd_v2, new_encode_dev(inode->i_rdev)); else @@ -1097,7 +1155,7 @@ static void inode2sd (void * sd, struct // 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; @@ -1105,7 +1163,7 @@ static void inode2sd_v1 (void * sd, stru set_sd_v1_uid(sd_v1, inode->i_uid ); set_sd_v1_gid(sd_v1, inode->i_gid ); set_sd_v1_nlink(sd_v1, inode->i_nlink ); - set_sd_v1_size(sd_v1, inode->i_size ); + set_sd_v1_size(sd_v1, size ); set_sd_v1_atime(sd_v1, inode->i_atime.tv_sec ); set_sd_v1_ctime(sd_v1, inode->i_ctime.tv_sec ); set_sd_v1_mtime(sd_v1, inode->i_mtime.tv_sec ); @@ -1113,7 +1171,7 @@ static void inode2sd_v1 (void * sd, stru if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) set_sd_v1_rdev(sd_v1, new_encode_dev(inode->i_rdev)); else - set_sd_v1_blocks(sd_v1, inode->i_blocks ); + set_sd_v1_blocks(sd_v1, to_fake_used_blocks(inode, SD_V1_SIZE)); // Sigh. i_first_direct_byte is back set_sd_v1_first_direct_byte(sd_v1, REISERFS_I(inode)->i_first_direct_byte); @@ -1123,7 +1181,8 @@ static void inode2sd_v1 (void * sd, stru /* NOTE, you must prepare the buffer head before sending it here, ** and then log it after the call */ -static void update_stat_data (struct path * path, struct inode * inode) +static void update_stat_data (struct path * path, struct inode * inode, + loff_t size) { struct buffer_head * bh; struct item_head * ih; @@ -1137,17 +1196,17 @@ static void update_stat_data (struct pat if (stat_data_v1 (ih)) { // path points to old stat data - inode2sd_v1 (B_I_PITEM (bh, ih), inode); + inode2sd_v1 (B_I_PITEM (bh, ih), inode, size); } else { - inode2sd (B_I_PITEM (bh, ih), inode); + inode2sd (B_I_PITEM (bh, ih), inode, size); } return; } -void reiserfs_update_sd (struct reiserfs_transaction_handle *th, - struct inode * inode) +void reiserfs_update_sd_size (struct reiserfs_transaction_handle *th, + struct inode * inode, loff_t size) { struct cpu_key key; INITIALIZE_PATH(path); @@ -1197,7 +1256,7 @@ void reiserfs_update_sd (struct reiserfs } break; } - update_stat_data (&path, inode); + update_stat_data (&path, inode, size); journal_mark_dirty(th, th->t_super, bh) ; pathrelse (&path); return; @@ -1480,6 +1539,7 @@ int reiserfs_sync_inode (struct reiserfs /* stat data of new object is inserted already, this inserts the item containing "." and ".." entries */ static int reiserfs_new_directory (struct reiserfs_transaction_handle *th, + struct inode *inode, struct item_head * ih, struct path * path, struct inode * dir) { @@ -1524,13 +1584,14 @@ static int reiserfs_new_directory (struc } /* 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 containing the body of symlink */ static int reiserfs_new_symlink (struct reiserfs_transaction_handle *th, + struct inode *inode, /* Inode of symlink */ struct item_head * ih, struct path * path, const char * symname, int item_len) { @@ -1560,7 +1621,7 @@ static int reiserfs_new_symlink (struct } /* 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_ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; 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 : U32_MAX/*NO_BYTES_IN_DIRECT_ITEM*/; @@ -1673,9 +1735,9 @@ int reiserfs_new_inode (struct reiserfs_ err = -EINVAL; goto out_bad_inode; } - inode2sd_v1 (&sd, inode); + inode2sd_v1 (&sd, inode, inode->i_size); } else { - inode2sd (&sd, inode); + inode2sd (&sd, inode, inode->i_size); } // these do not go to on-disk stat data inode->i_ino = le32_to_cpu (ih.ih_key.k_objectid); @@ -1699,7 +1761,7 @@ int reiserfs_new_inode (struct reiserfs_ if (REISERFS_I(dir)->new_packing_locality) th->displace_new_blocks = 1; #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) { err = retval; reiserfs_check_path(&path_to_key) ; @@ -1712,14 +1774,14 @@ int reiserfs_new_inode (struct reiserfs_ #endif if (S_ISDIR(mode)) { /* 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)) { /* insert body of symlink */ if (!old_format_only (sb)) 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) { err = retval; @@ -1757,6 +1819,9 @@ out_bad_inode: /* dquot_drop must be done outside a transaction */ 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); out_inserted_sd: @@ -2294,6 +2359,7 @@ static int reiserfs_commit_write(struct struct inode *inode = page->mapping->host ; loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; int ret = 0; + int update_sd = 0; struct reiserfs_transaction_handle *th = NULL; reiserfs_wait_on_write_block(inode->i_sb) ; @@ -2320,11 +2386,14 @@ static int reiserfs_commit_write(struct reiserfs_update_inode_transaction(inode) ; inode->i_size = pos ; reiserfs_update_sd(&myth, inode) ; + update_sd = 1; journal_end(&myth, inode->i_sb, 1) ; reiserfs_write_unlock(inode->i_sb); } if (th) { reiserfs_write_lock(inode->i_sb); + if (!update_sd) + reiserfs_update_sd(th, inode) ; reiserfs_end_persistent_transaction(th); reiserfs_write_unlock(inode->i_sb); } @@ -2533,7 +2602,6 @@ static ssize_t reiserfs_direct_IO(int rw offset, nr_segs, reiserfs_get_blocks_direct_io, NULL); } - int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) { struct inode *inode = dentry->d_inode ; int error ; diff -puN fs/reiserfs/namei.c~reiserfs-quota fs/reiserfs/namei.c --- 25/fs/reiserfs/namei.c~reiserfs-quota Fri Apr 23 14:36:54 2004 +++ 25-akpm/fs/reiserfs/namei.c Fri Apr 23 14:36:54 2004 @@ -18,6 +18,7 @@ #include #include #include +#include #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--; @@ -519,7 +520,7 @@ static int reiserfs_add_entry (struct re } /* 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) reiserfs_kfree (buffer, buflen, dir->i_sb); if (retval) { @@ -528,7 +529,6 @@ static int reiserfs_add_entry (struct re } dir->i_size += paste_size; - dir->i_blocks = ((dir->i_size + 511) >> 9); dir->i_mtime = dir->i_ctime = CURRENT_TIME; if (!S_ISDIR (inode->i_mode) && visible) // reiserfs_mkdir or reiserfs_rename will do that by itself @@ -544,7 +544,9 @@ static int reiserfs_add_entry (struct re ** inserted into the tree yet. */ static int drop_new_inode(struct inode *inode) { + DQUOT_DROP(inode); make_bad_inode(inode) ; + inode->i_flags |= S_NOQUOTA; iput(inode) ; return 0 ; } @@ -570,6 +572,11 @@ static int new_inode_init(struct inode * } else { inode->i_gid = current->fsgid; } + DQUOT_INIT(inode); + if (DQUOT_ALLOC_INODE(inode)) { + drop_new_inode(inode); + return -EDQUOT; + } return 0 ; } @@ -836,7 +843,6 @@ static int reiserfs_rmdir (struct inode DEC_DIR_INODE_NLINK(dir) dir->i_size -= (DEH_SIZE + de.de_entrylen); - dir->i_blocks = ((dir->i_size + 511) >> 9); reiserfs_update_sd (&th, dir); /* prevent empty directory from getting lost */ @@ -919,7 +925,6 @@ static int reiserfs_unlink (struct inode reiserfs_update_sd (&th, inode); dir->i_size -= (de.de_entrylen + DEH_SIZE); - dir->i_blocks = ((dir->i_size + 511) >> 9); dir->i_ctime = dir->i_mtime = CURRENT_TIME; reiserfs_update_sd (&th, dir); @@ -1335,7 +1340,6 @@ static int reiserfs_rename (struct inode 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_blocks = ((old_dir->i_size + 511) >> 9); reiserfs_update_sd (&th, old_dir); reiserfs_update_sd (&th, new_dir); diff -puN fs/reiserfs/stree.c~reiserfs-quota fs/reiserfs/stree.c --- 25/fs/reiserfs/stree.c~reiserfs-quota Fri Apr 23 14:36:54 2004 +++ 25-akpm/fs/reiserfs/stree.c Fri Apr 23 14:36:54 2004 @@ -60,6 +60,7 @@ #include #include #include +#include /* 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) @@ -71,9 +72,6 @@ inline int B_IS_IN_TREE (const struct bu return ( B_LEVEL (p_s_bh) != FREE_LEVEL ); } - - - inline void copy_short_key (void * to, const void * from) { memcpy (to, from, SHORT_KEY_SIZE); @@ -1125,8 +1123,7 @@ static char prepare_for_delete_or_cut( tmp = get_block_num(p_n_unfm_pointer,0); put_block_num(p_n_unfm_pointer, 0, 0); journal_mark_dirty (th, p_s_sb, p_s_bh); - inode->i_blocks -= p_s_sb->s_blocksize / 512; - reiserfs_free_block(th, tmp); + reiserfs_free_block(th, inode, tmp, 1); if ( item_moved (&s_ih, p_s_path) ) { need_research = 1; break ; @@ -1155,8 +1152,7 @@ static char prepare_for_delete_or_cut( } } - -/* Calculate bytes number which will be deleted or cutted in the balance. */ +/* Calculate number of bytes which will be deleted or cut during balance */ int calc_deleted_bytes_number( struct tree_balance * p_s_tb, char c_mode @@ -1167,14 +1163,14 @@ int calc_deleted_bytes_number( if ( is_statdata_le_ih (p_le_ih) ) 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) ) { // return EMPTY_DIR_SIZE; /* We delete emty directoris only. */ // we can't use EMPTY_DIR_SIZE, as old format dirs have a different // 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) ) n_del_size = (n_del_size/UNFM_P_SIZE)* @@ -1208,17 +1204,46 @@ void padd_item (char * item, int total_l 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. */ int reiserfs_delete_item (struct reiserfs_transaction_handle *th, 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. */ - 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 super_block * p_s_sb = p_s_inode->i_sb; struct tree_balance s_del_balance; struct item_head s_ih; + struct item_head *q_ih; + int quota_cut_bytes; int n_ret_value, n_del_size, n_removed; @@ -1268,6 +1293,22 @@ int reiserfs_delete_item (struct reiserf // reiserfs_delete_item returns item length when success 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 ) { int off; @@ -1299,10 +1340,14 @@ int reiserfs_delete_item (struct reiserf B_I_PITEM(PATH_PLAST_BUFFER(p_s_path), &s_ih), n_ret_value); kunmap_atomic(data, KM_USER0); } - /* Perform balancing after all resources have been collected at once. */ 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 n_ret_value; } @@ -1327,14 +1372,16 @@ int reiserfs_delete_item (struct reiserf /* this deletes item which never gets split */ void reiserfs_delete_solid_item (struct reiserfs_transaction_handle *th, + struct inode *inode, struct key * key) { struct tree_balance tb; INITIALIZE_PATH (path); - int item_len; + int item_len = 0; int tb_init = 0 ; struct cpu_key cpu_key; int retval; + int quota_cut_bytes = 0; le_key2cpu_key (&cpu_key, key); @@ -1358,6 +1405,7 @@ void reiserfs_delete_solid_item (struct item_len = ih_item_len( PATH_PITEM_HEAD(&path) ); 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); if (retval == REPEAT_SEARCH) { @@ -1367,6 +1415,12 @@ void reiserfs_delete_solid_item (struct if (retval == CARRY_ON) { 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; } @@ -1399,7 +1453,7 @@ void reiserfs_delete_object (struct reis } /* USE_INODE_GENERATION_COUNTER */ #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 reise structure by using the init_tb_struct and fix_nodes functions. After that we can make tree balancing. */ struct tree_balance s_cut_balance; + struct item_head *p_le_ih; int n_cut_size = 0, /* Amount to be cut. */ n_ret_value = CARRY_ON, n_removed = 0, /* Number of the removed unformatted nodes. */ n_is_inode_locked = 0; char c_mode; /* Mode of the balance. */ 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); @@ -1579,23 +1635,27 @@ int reiserfs_cut_from_item (struct reise RFALSE( c_mode == M_PASTE || c_mode == M_INSERT, "invalid mode"); /* 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) n_ret_value = calc_deleted_bytes_number(&s_cut_balance, c_mode); else 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 ) { - /* we delete first part of tail which was stored in direct - item(s) */ + + + /* For direct items, we only change the quota when deleting the last + ** item. + */ + 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 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 if (n_is_inode_locked) { struct item_head * le_ih = PATH_PITEM_HEAD (s_cut_balance.tb_path); @@ -1630,10 +1690,13 @@ int reiserfs_cut_from_item (struct reise */ 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; } - static void truncate_directory (struct reiserfs_transaction_handle *th, struct inode * inode) { if (inode->i_nlink) @@ -1641,8 +1704,8 @@ static void truncate_directory (struct r 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); - 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_type (KEY_FORMAT_3_5, INODE_PKEY (inode), TYPE_STAT_DATA); } @@ -1809,18 +1872,37 @@ static void check_research_for_paste (st int reiserfs_paste_into_item (struct reiserfs_transaction_handle *th, 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.*/ + struct inode * inode, /* Inode item belongs to */ const char * p_c_body, /* Pointer to the bytes to paste. */ int n_pasted_size) /* Size of pasted bytes. */ { struct tree_balance s_paste_balance; 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); #ifdef DISPLACE_NEW_PACKING_LOCALITIES s_paste_balance.key = p_s_key->on_disk_key; #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 */ 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); @@ -1849,6 +1931,10 @@ int reiserfs_paste_into_item (struct rei error_out: /* this also releases the path */ 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 ; } @@ -1858,23 +1944,45 @@ int reiserfs_insert_item(struct reiserfs struct path * p_s_path, /* Path to the inserteded item. */ const struct cpu_key * key, 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. */ { struct tree_balance s_ins_balance; 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)); #ifdef DISPLACE_NEW_PACKING_LOCALITIES s_ins_balance.key = key->on_disk_key; #endif - - /* - if (p_c_body == 0) - n_zeros_num = ih_item_len(p_s_ih); - */ - // le_key2cpu_key (&key, &(p_s_ih->ih_key)); + /* DQUOT_* can schedule, must check to be sure calling fix_nodes is safe */ + if (inode && fs_changed(fs_gen, inode->i_sb)) { + goto search_again; + } 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 */ PROC_INFO_INC( th -> t_super, insert_item_restarted ); retval = search_item (th->t_super, key, p_s_path); @@ -1900,6 +2008,11 @@ int reiserfs_insert_item(struct reiserfs error_out: /* also releases the path */ 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; } diff -puN fs/reiserfs/super.c~reiserfs-quota fs/reiserfs/super.c --- 25/fs/reiserfs/super.c~reiserfs-quota Fri Apr 23 14:36:54 2004 +++ 25-akpm/fs/reiserfs/super.c Fri Apr 23 14:36:54 2004 @@ -115,7 +115,7 @@ static void remove_save_link_only (struc /* we are going to do one balancing */ journal_begin (&th, s, JOURNAL_PER_BALANCE_CNT); - reiserfs_delete_solid_item (&th, key); + reiserfs_delete_solid_item (&th, NULL, key); if (oid_free) /* removals are protected by direct items */ reiserfs_release_objectid (&th, le32_to_cpu (key->k_objectid)); @@ -301,8 +301,8 @@ void add_save_link (struct reiserfs_tran /* body of "save" link */ link = INODE_PKEY (inode)->k_dir_id; - /* put "save" link inot tree */ - retval = reiserfs_insert_item (th, &path, &key, &ih, (char *)&link); + /* put "save" link inot tree, don't charge quota to anyone */ + retval = reiserfs_insert_item (th, &path, &key, &ih, NULL, (char *)&link); if (retval) { if (retval != -ENOSPC) reiserfs_warning ("vs-2120: add_save_link: insert_item returned %d\n", @@ -344,7 +344,8 @@ void remove_save_link (struct inode * in ( REISERFS_I(inode) -> i_flags & i_link_saved_truncate_mask ) ) || ( !truncate && ( 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) { reiserfs_release_objectid (&th, inode->i_ino); REISERFS_I(inode) -> i_flags &= ~i_link_saved_unlink_mask; @@ -714,6 +715,8 @@ static int reiserfs_parse_options (struc {"jdev", 'j', 0, 0, 0}, {"nolargeio", 'w', 0, 0, 0}, {"commit", 'c', 0, 0, 0}, + {"usrquota", 0, 0, 0, 0}, + {"grpquota", 0, 0, 0, 0}, {NULL, 0, 0, 0, 0} }; diff -puN fs/reiserfs/tail_conversion.c~reiserfs-quota fs/reiserfs/tail_conversion.c --- 25/fs/reiserfs/tail_conversion.c~reiserfs-quota Fri Apr 23 14:36:54 2004 +++ 25-akpm/fs/reiserfs/tail_conversion.c Fri Apr 23 14:36:54 2004 @@ -66,11 +66,11 @@ int direct2indirect (struct reiserfs_tra set_ih_free_space (&ind_ih, 0); /* delete at nearest future */ put_ih_item_len( &ind_ih, UNFM_P_SIZE ); 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); } else { /* 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); } if ( n_retval ) { @@ -274,7 +274,7 @@ int indirect2direct (struct reiserfs_tra set_cpu_key_k_type (&key, TYPE_DIRECT); key.key_length = 4; /* 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 ) { /* No disk memory. So we can not convert last unformatted node to the direct item. In this case we used to adjust @@ -292,13 +292,15 @@ int indirect2direct (struct reiserfs_tra */ 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 // conversion: there are two keys which have matching first three // key components. They only differ by the fouhth one. /* We have inserted new direct item and must remove last unformatted node. */ - p_s_inode->i_blocks += (p_s_sb->s_blocksize / 512); *p_c_mode = M_CUT; /* we store position of first direct item in the in-core inode */ diff -puN include/linux/reiserfs_fs.h~reiserfs-quota include/linux/reiserfs_fs.h --- 25/include/linux/reiserfs_fs.h~reiserfs-quota Fri Apr 23 14:36:54 2004 +++ 25-akpm/include/linux/reiserfs_fs.h Fri Apr 23 14:36:54 2004 @@ -268,6 +268,7 @@ int is_reiserfs_jr (struct reiserfs_supe #define NO_DISK_SPACE -3 #define NO_BALANCING_NEEDED (-4) #define NO_MORE_UNUSED_CONTIGUOUS_BLOCKS (-5) +#define QUOTA_EXCEEDED -6 typedef __u32 b_blocknr_t; typedef __u32 unp_t; @@ -1238,7 +1239,6 @@ excessive effort to avoid disturbing the gods only know how we are going to SMP the code that uses them. znodes are the way! */ - struct path { int path_length; /* Length of the array above. */ struct path_element path_elements[EXTENDED_MAX_HEIGHT]; /* Array of the path elements. */ @@ -1889,11 +1889,13 @@ void pathrelse_and_restore (struct super int reiserfs_insert_item (struct reiserfs_transaction_handle *th, struct path * path, 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, struct path * path, const struct cpu_key * key, + struct inode *inode, const char * body, int paste_size); int reiserfs_cut_from_item (struct reiserfs_transaction_handle *th, @@ -1910,7 +1912,7 @@ int reiserfs_delete_item (struct reiserf struct buffer_head * p_s_un_bh); 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_do_truncate (struct reiserfs_transaction_handle *th, struct inode * p_s_inode, struct page *, @@ -1955,8 +1957,18 @@ int reiserfs_new_inode (struct reiserfs_ struct inode * dir, int mode, const char * symname, loff_t i_size, 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 i_attrs_to_sd_attrs( struct inode *inode, __u16 *sd_attrs ); @@ -2139,7 +2151,7 @@ typedef struct __reiserfs_blocknr_hint r int reiserfs_parse_alloc_options (struct super_block *, char *); 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); extern inline int reiserfs_new_form_blocknrs (struct tree_balance * tb, b_blocknr_t *new_blocknrs, int amount_needed) _