aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext3/balloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ext3/balloc.c')
-rw-r--r--fs/ext3/balloc.c76
1 files changed, 55 insertions, 21 deletions
diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c
index 6a18447e9dd7f..ccd632fcc6d87 100644
--- a/fs/ext3/balloc.c
+++ b/fs/ext3/balloc.c
@@ -250,7 +250,7 @@ static void rsv_window_remove(struct super_block *sb,
{
rsv->rsv_start = EXT3_RESERVE_WINDOW_NOT_ALLOCATED;
rsv->rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED;
- atomic_set(&rsv->rsv_alloc_hit, 0);
+ rsv->rsv_alloc_hit = 0;
rb_erase(&rsv->rsv_node, &EXT3_SB(sb)->s_rsv_window_root);
}
@@ -259,13 +259,46 @@ static inline int rsv_is_empty(struct ext3_reserve_window *rsv)
/* a valid reservation end block could not be 0 */
return (rsv->_rsv_end == EXT3_RESERVE_WINDOW_NOT_ALLOCATED);
}
+void ext3_init_block_alloc_info(struct inode *inode)
+{
+ struct ext3_inode_info *ei = EXT3_I(inode);
+ struct ext3_block_alloc_info *block_i = ei->i_block_alloc_info;
+ struct super_block *sb = inode->i_sb;
+
+ block_i = kmalloc(sizeof(*block_i), GFP_NOFS);
+ if (block_i) {
+ struct ext3_reserve_window_node *rsv = &block_i->rsv_window_node;
+
+ rsv->rsv_start = EXT3_RESERVE_WINDOW_NOT_ALLOCATED;
+ rsv->rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED;
+
+ /*
+ * if filesystem is mounted with NORESERVATION, the goal
+ * reservation window size is set to zero to indicate
+ * block reservation is off
+ */
+ if (!test_opt(sb, RESERVATION))
+ rsv->rsv_goal_size = 0;
+ else
+ rsv->rsv_goal_size = EXT3_DEFAULT_RESERVE_BLOCKS;
+ rsv->rsv_alloc_hit = 0;
+ block_i->last_alloc_logical_block = 0;
+ block_i->last_alloc_physical_block = 0;
+ }
+ ei->i_block_alloc_info = block_i;
+}
void ext3_discard_reservation(struct inode *inode)
{
struct ext3_inode_info *ei = EXT3_I(inode);
- struct ext3_reserve_window_node *rsv = &ei->i_rsv_window;
+ struct ext3_block_alloc_info *block_i = ei->i_block_alloc_info;
+ struct ext3_reserve_window_node *rsv;
spinlock_t *rsv_lock = &EXT3_SB(inode->i_sb)->s_rsv_window_lock;
+ if (!block_i)
+ return;
+
+ rsv = &block_i->rsv_window_node;
if (!rsv_is_empty(&rsv->rsv_window)) {
spin_lock(rsv_lock);
if (!rsv_is_empty(&rsv->rsv_window))
@@ -841,7 +874,7 @@ static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv,
else
start_block = goal + group_first_block;
- size = atomic_read(&my_rsv->rsv_goal_size);
+ size = my_rsv->rsv_goal_size;
if (!rsv_is_empty(&my_rsv->rsv_window)) {
/*
* if the old reservation is cross group boundary
@@ -862,7 +895,7 @@ static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv,
(start_block >= my_rsv->rsv_start))
return -1;
- if ((atomic_read(&my_rsv->rsv_alloc_hit) >
+ if ((my_rsv->rsv_alloc_hit >
(my_rsv->rsv_end - my_rsv->rsv_start + 1) / 2)) {
/*
* if we previously allocation hit ration is greater than half
@@ -872,7 +905,7 @@ static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv,
size = size * 2;
if (size > EXT3_MAX_RESERVE_BLOCKS)
size = EXT3_MAX_RESERVE_BLOCKS;
- atomic_set(&my_rsv->rsv_goal_size, size);
+ my_rsv->rsv_goal_size= size;
}
}
/*
@@ -947,7 +980,7 @@ found_rsv_window:
}
my_rsv->rsv_start = reservable_space_start;
my_rsv->rsv_end = my_rsv->rsv_start + size - 1;
- atomic_set(&my_rsv->rsv_alloc_hit, 0);
+ my_rsv->rsv_alloc_hit = 0;
if (my_rsv != prev_rsv) {
ext3_rsv_window_add(sb, my_rsv);
}
@@ -1046,23 +1079,17 @@ ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle,
*/
while (1) {
struct ext3_reserve_window rsv_copy;
- unsigned int seq;
- do {
- seq = read_seqbegin(&my_rsv->rsv_seqlock);
- rsv_copy._rsv_start = my_rsv->rsv_start;
- rsv_copy._rsv_end = my_rsv->rsv_end;
- } while (read_seqretry(&my_rsv->rsv_seqlock, seq));
+ rsv_copy._rsv_start = my_rsv->rsv_start;
+ rsv_copy._rsv_end = my_rsv->rsv_end;
if (rsv_is_empty(&rsv_copy) || (ret < 0) ||
!goal_in_my_reservation(&rsv_copy, goal, group, sb)) {
spin_lock(rsv_lock);
- write_seqlock(&my_rsv->rsv_seqlock);
ret = alloc_new_reservation(my_rsv, goal, sb,
group, bitmap_bh);
rsv_copy._rsv_start = my_rsv->rsv_start;
rsv_copy._rsv_end = my_rsv->rsv_end;
- write_sequnlock(&my_rsv->rsv_seqlock);
spin_unlock(rsv_lock);
if (ret < 0)
break; /* failed */
@@ -1076,8 +1103,7 @@ ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle,
ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, goal,
&rsv_copy);
if (ret >= 0) {
- if (!read_seqretry(&my_rsv->rsv_seqlock, seq))
- atomic_inc(&my_rsv->rsv_alloc_hit);
+ my_rsv->rsv_alloc_hit++;
break; /* succeed */
}
}
@@ -1154,7 +1180,7 @@ int ext3_new_block(handle_t *handle, struct inode *inode,
struct ext3_super_block *es;
struct ext3_sb_info *sbi;
struct ext3_reserve_window_node *my_rsv = NULL;
- struct ext3_reserve_window_node *rsv = &EXT3_I(inode)->i_rsv_window;
+ struct ext3_block_alloc_info *block_i;
unsigned short windowsz = 0;
#ifdef EXT3FS_DEBUG
static int goal_hits, goal_attempts;
@@ -1187,10 +1213,10 @@ int ext3_new_block(handle_t *handle, struct inode *inode,
* command EXT3_IOC_SETRSVSZ to set the window size to 0 to turn off
* reservation on that particular file)
*/
- windowsz = atomic_read(&rsv->rsv_goal_size);
- if (test_opt(sb, RESERVATION) &&
- S_ISREG(inode->i_mode) && (windowsz > 0))
- my_rsv = rsv;
+ block_i = EXT3_I(inode)->i_block_alloc_info;
+ if (block_i && ((windowsz = block_i->rsv_window_node.rsv_goal_size) > 0))
+ my_rsv = &block_i->rsv_window_node;
+
if (!ext3_has_free_blocks(sbi)) {
*errp = -ENOSPC;
goto out;
@@ -1211,6 +1237,14 @@ int ext3_new_block(handle_t *handle, struct inode *inode,
goal_group = group_no;
retry:
free_blocks = le16_to_cpu(gdp->bg_free_blocks_count);
+ /*
+ * if there is not enough free blocks to make a new resevation
+ * turn off reservation for this allocation
+ */
+ if (my_rsv && (free_blocks < windowsz)
+ && (rsv_is_empty(&my_rsv->rsv_window)))
+ my_rsv = NULL;
+
if (free_blocks > 0) {
ret_block = ((goal - le32_to_cpu(es->s_first_data_block)) %
EXT3_BLOCKS_PER_GROUP(sb));