diff options
Diffstat (limited to 'fs/ext3/balloc.c')
-rw-r--r-- | fs/ext3/balloc.c | 76 |
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)); |