* code.
*/
#if 0
-static void __rsv_window_dump(struct rb_root *root, int verbose,
+static void __rsv_window_dump(struct rb_root *root, int verbose,
const char *fn)
{
struct rb_node *n;
- struct reserve_window_node *rsv, *prev;
+ struct ext3_reserve_window_node *rsv, *prev;
int bad;
-
+
restart:
n = rb_first(root);
bad = 0;
prev = NULL;
-
+
printk("Block Allocation Reservation Windows Map (%s):\n", fn);
while (n) {
- rsv = list_entry(n, struct reserve_window_node, rsv_node);
+ rsv = list_entry(n, struct ext3_reserve_window_node, rsv_node);
if (verbose)
printk("reservation window 0x%p "
"start: %d, end: %d\n",
rsv, rsv->rsv_start, rsv->rsv_end);
if (rsv->rsv_start && rsv->rsv_start >= rsv->rsv_end) {
- printk("Bad reservation %p (start >= end)\n",
+ printk("Bad reservation %p (start >= end)\n",
rsv);
bad = 1;
}
#endif
static int
-goal_in_my_reservation(struct reserve_window *rsv, int goal,
+goal_in_my_reservation(struct ext3_reserve_window *rsv, int goal,
unsigned int group, struct super_block * sb)
{
unsigned long group_first_block, group_last_block;
return 1;
}
-/*
+/*
* Find the reserved window which includes the goal, or the previous one
* if the goal is not in any window.
* Returns NULL if there are no windows or if all windows start after the goal.
*/
-static struct reserve_window_node *search_reserve_window(struct rb_root *root,
- unsigned long goal)
+static struct ext3_reserve_window_node *
+search_reserve_window(struct rb_root *root, unsigned long goal)
{
struct rb_node *n = root->rb_node;
- struct reserve_window_node *rsv;
+ struct ext3_reserve_window_node *rsv;
if (!n)
return NULL;
-
- while (n)
- {
- rsv = rb_entry(n, struct reserve_window_node, rsv_node);
+
+ do {
+ rsv = rb_entry(n, struct ext3_reserve_window_node, rsv_node);
if (goal < rsv->rsv_start)
n = n->rb_left;
n = n->rb_right;
else
return rsv;
- }
- /*
+ } while (n);
+ /*
* We've fallen off the end of the tree: the goal wasn't inside
* any particular node. OK, the previous node must be to one
* side of the interval containing the goal. If it's the RHS,
- * we need to back up one.
+ * we need to back up one.
*/
if (rsv->rsv_start > goal) {
n = rb_prev(&rsv->rsv_node);
- rsv = rb_entry(n, struct reserve_window_node, rsv_node);
+ rsv = rb_entry(n, struct ext3_reserve_window_node, rsv_node);
}
- return rsv;
+ return rsv;
}
-void rsv_window_add(struct super_block *sb,
- struct reserve_window_node *rsv)
+void ext3_rsv_window_add(struct super_block *sb,
+ struct ext3_reserve_window_node *rsv)
{
struct rb_root *root = &EXT3_SB(sb)->s_rsv_window_root;
struct rb_node *node = &rsv->rsv_node;
struct rb_node ** p = &root->rb_node;
struct rb_node * parent = NULL;
- struct reserve_window_node *this;
-
+ struct ext3_reserve_window_node *this;
+
while (*p)
{
parent = *p;
- this = rb_entry(parent, struct reserve_window_node, rsv_node);
+ this = rb_entry(parent, struct ext3_reserve_window_node, rsv_node);
if (start < this->rsv_start)
p = &(*p)->rb_left;
}
static void rsv_window_remove(struct super_block *sb,
- struct reserve_window_node *rsv)
+ struct ext3_reserve_window_node *rsv)
{
rsv->rsv_start = EXT3_RESERVE_WINDOW_NOT_ALLOCATED;
rsv->rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED;
rb_erase(&rsv->rsv_node, &EXT3_SB(sb)->s_rsv_window_root);
}
-static inline int rsv_is_empty(struct reserve_window *rsv)
+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_discard_reservation(struct inode *inode)
{
struct ext3_inode_info *ei = EXT3_I(inode);
- struct reserve_window_node *rsv = &ei->i_rsv_window;
+ struct ext3_reserve_window_node *rsv = &ei->i_rsv_window;
spinlock_t *rsv_lock = &EXT3_SB(inode->i_sb)->s_rsv_window_lock;
if (!rsv_is_empty(&rsv->rsv_window)) {
*/
static int
ext3_try_to_allocate(struct super_block *sb, handle_t *handle, int group,
- struct buffer_head *bitmap_bh, int goal, struct reserve_window *my_rsv)
+ struct buffer_head *bitmap_bh, int goal, struct ext3_reserve_window *my_rsv)
{
int group_first_block, start, end;
* group. The search will end when we found the start of next
* possible reservable space is out of this boundary.
* This could handle the cross boundary reservation window
- * request.
+ * request.
*
* basically we search from the given range, rather than the whole
* reservation double linked list, (start_block, last_block)
* on succeed, it returns the reservation window to be appended to.
* failed, return NULL.
*/
-static struct reserve_window_node *find_next_reservable_window(
- struct reserve_window_node *search_head,
+static struct ext3_reserve_window_node *find_next_reservable_window(
+ struct ext3_reserve_window_node *search_head,
unsigned long size, int *start_block,
int last_block)
{
struct rb_node *next;
- struct reserve_window_node *rsv, *prev;
+ struct ext3_reserve_window_node *rsv, *prev;
int cur;
/* TODO: make the start of the reservation window byte-aligned */
/* cur = *start_block & ~7;*/
cur = *start_block;
rsv = search_head;
- if (!rsv)
+ if (!rsv)
return NULL;
-
+
while (1) {
if (cur <= rsv->rsv_end)
cur = rsv->rsv_end + 1;
prev = rsv;
next = rb_next(&rsv->rsv_node);
- rsv = list_entry(next, struct reserve_window_node, rsv_node);
+ rsv = list_entry(next, struct ext3_reserve_window_node, rsv_node);
- /*
- * Reached the last reservation, we can just append to the
- * previous one.
+ /*
+ * Reached the last reservation, we can just append to the
+ * previous one.
*/
if (!next)
break;
/**
* alloc_new_reservation()--allocate a new reservation window
- * if there is an existing reservation, discard it first
- * then allocate the new one from there
- * otherwise allocate the new reservation from the given
- * start block, or the beginning of the group, if a goal
- * is not given.
*
* To make a new reservation, we search part of the filesystem
- * reservation list (the list that inside the group).
- *
- * If we have a old reservation, the search goal is the end of
- * last reservation. If we do not have a old reservation, then we
- * start from a given goal, or the first block of the group, if
- * the goal is not given.
+ * reservation list (the list that inside the group). We try to
+ * allocate a new reservation window near the allocation goal,
+ * or the beginning of the group, if there is no goal.
*
* We first find a reservable space after the goal, then from
* there, we check the bitmap for the first free block after
*
* @goal: The goal (group-relative). It is where the search for a
* free reservable space should start from.
- * if we have a old reservation, start_block is the end of
- * old reservation. Otherwise,
* if we have a goal(goal >0 ), then start from there,
* no goal(goal = -1), we start from the first block
* of the group.
* @group: the group we are trying to allocate in
* @bitmap_bh: the block group block bitmap
*/
-static int alloc_new_reservation(struct reserve_window_node *my_rsv,
+static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv,
int goal, struct super_block *sb,
unsigned int group, struct buffer_head *bitmap_bh)
{
- struct reserve_window_node *search_head;
+ struct ext3_reserve_window_node *search_head;
int group_first_block, group_end_block, start_block;
int first_free_block;
int reservable_space_start;
- struct reserve_window_node *prev_rsv;
+ struct ext3_reserve_window_node *prev_rsv;
struct rb_root *fs_rsv_root = &EXT3_SB(sb)->s_rsv_window_root;
unsigned long size;
start_block = goal + group_first_block;
size = atomic_read(&my_rsv->rsv_goal_size);
- /* if we have a old reservation, start the search from the old rsv */
if (!rsv_is_empty(&my_rsv->rsv_window)) {
/*
* if the old reservation is cross group boundary
+ * and if the goal is inside the old reservation window,
* we will come here when we just failed to allocate from
* the first part of the window. We still have another part
* that belongs to the next group. In this case, there is no
*/
if ((my_rsv->rsv_start <= group_end_block) &&
- (my_rsv->rsv_end > group_end_block))
+ (my_rsv->rsv_end > group_end_block) &&
+ (start_block >= my_rsv->rsv_start))
return -1;
- /* remember where we are before we discard the old one */
- if (my_rsv->rsv_end + 1 > start_block)
- start_block = my_rsv->rsv_end + 1;
- search_head = my_rsv;
- if ((atomic_read(&my_rsv->rsv_alloc_hit) >
+ if ((atomic_read(&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
atomic_set(&my_rsv->rsv_goal_size, size);
}
}
- else {
- /*
- * we don't have a reservation,
- * we set our goal(start_block) and
- * the list head for the search
- */
- search_head = search_reserve_window(fs_rsv_root, start_block);
- }
+ /*
+ * shift the search start to the window near the goal block
+ */
+ search_head = search_reserve_window(fs_rsv_root, start_block);
/*
* find_next_reservable_window() simply finds a reservable window
my_rsv->rsv_end = my_rsv->rsv_start + size - 1;
atomic_set(&my_rsv->rsv_alloc_hit, 0);
if (my_rsv != prev_rsv) {
- rsv_window_add(sb, my_rsv);
+ ext3_rsv_window_add(sb, my_rsv);
}
return 0; /* succeed */
failed:
+ /*
+ * failed to find a new reservation window in the current
+ * group, remove the current(stale) reservation window
+ * if there is any
+ */
+ if (!rsv_is_empty(&my_rsv->rsv_window))
+ rsv_window_remove(sb, my_rsv);
return -1; /* failed */
}
static int
ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle,
unsigned int group, struct buffer_head *bitmap_bh,
- int goal, struct reserve_window_node * my_rsv,
+ int goal, struct ext3_reserve_window_node * my_rsv,
int *errp)
{
spinlock_t *rsv_lock;
* then we could go to allocate from the reservation window directly.
*/
while (1) {
- struct reserve_window rsv_copy;
+ 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;
struct ext3_group_desc *gdp;
struct ext3_super_block *es;
struct ext3_sb_info *sbi;
- struct reserve_window_node *my_rsv = NULL;
+ struct ext3_reserve_window_node *my_rsv = NULL;
+ struct ext3_reserve_window_node *rsv = &EXT3_I(inode)->i_rsv_window;
+ unsigned short windowsz = 0;
#ifdef EXT3FS_DEBUG
static int goal_hits, goal_attempts;
#endif
sbi = EXT3_SB(sb);
es = EXT3_SB(sb)->s_es;
ext3_debug("goal=%lu.\n", goal);
- if (test_opt(sb, RESERVATION) && S_ISREG(inode->i_mode))
- my_rsv = &EXT3_I(inode)->i_rsv_window;
-#warning MEF was if (!ext3_has_free_blocks(sbi)) in 1.11-FC2
+ /*
+ * Allocate a block from reservation only when
+ * filesystem is mounted with reservation(default,-o reservation), and
+ * it's a regular file, and
+ * the desired window size is greater than 0 (One could use ioctl
+ * 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;
if (!ext3_has_free_blocks(sb)) {
*errp = -ENOSPC;
goto out;
goto out;
}
free_blocks = le16_to_cpu(gdp->bg_free_blocks_count);
- if (free_blocks <= 0)
+ /*
+ * skip this group if the number of
+ * free blocks is less than half of the reservation
+ * window size.
+ */
+ if (free_blocks <= (windowsz/2))
continue;
brelse(bitmap_bh);