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 @@
#include <linux/pagemap.h>
#include <linux/reiserfs_fs_sb.h>
#include <linux/reiserfs_fs_i.h>
#include <linux/quotaops.h>
#define PREALLOCATION_SIZE 9
......@@ -281,7 +282,8 @@ static int scan_bitmap (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 reiserfs_super_block * rs;
......@@ -323,11 +325,13 @@ static void _reiserfs_free_block (struct reiserfs_transaction_handle *th,
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 reiserfs_transaction_handle *th,
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_arrays_from_search_start
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_arrays_from_search_start
/* 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_arrays_from_search_start
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_blocknr_hint_t *hint,
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;
......
......@@ -1234,7 +1234,7 @@ static void free_thrown(struct tree_balance *tb) {
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 tree_balance * tb, struct buffer_head *
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);
}
......
......@@ -13,6 +13,7 @@
#include <linux/writeback.h>
#include <linux/blkdev.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.
......@@ -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 @@ int reiserfs_allocate_blocks_for_region(
// 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 @@ int reiserfs_allocate_blocks_for_region(
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 @@ int reiserfs_allocate_blocks_for_region(
// 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 @@ int reiserfs_allocate_blocks_for_region(
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
......
......@@ -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 * tb)
/* 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 */
......
This diff is collapsed.
......@@ -18,6 +18,7 @@
#include <linux/reiserfs_acl.h>
#include <linux/reiserfs_xattr.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 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
}
/* 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 reiserfs_transaction_handle *th, struct in
}
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 reiserfs_transaction_handle *th, struct in
** 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 *inode, struct inode *dir, int mode) {
} 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 * dir, struct dentry *dentry)
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 * dir, struct dentry *dentry)
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 * old_dir, struct dentry *old_dentry,
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);
......
This diff is collapsed.
......@@ -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 */
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_transaction_handle * th,
/* 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 * inode, int truncate)
( 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 (struct super_block * s, char * options, /* st
{"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}
};
......
......@@ -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 */
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_transaction_handle *th,
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_transaction_handle *th,
*/
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 */
......
......@@ -268,6 +268,7 @@ int is_reiserfs_jr (struct reiserfs_super_block * rs);
#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 precious VFS code.:-( 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_block *s, struct path * p_s_search_path
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 reiserfs_transaction_handle *th,
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_transaction_handle *th,
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 reiserfs_blocknr_hint_t;
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)
......
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