+ if (my_rsv)
+ my_rsv->rsv_alloc_hit++;
+ return goal;
+fail_access:
+ return -1;
+}
+
+/**
+ * find_next_reservable_window():
+ * find a reservable space within the given range
+ * It does not allocate the reservation window for now
+ * alloc_new_reservation() will do the work later.
+ *
+ * @search_head: the head of the searching list;
+ * This is not necessary the list head of the whole filesystem
+ *
+ * we have both head and start_block to assist the search
+ * for the reservable space. The list start from head,
+ * but we will shift to the place where start_block is,
+ * then start from there, we looking for a resevable space.
+ *
+ * @fs_rsv_head: per-filesystem reervation list head.
+ *
+ * @size: the target new reservation window size
+ * @group_first_block: the first block we consider to start
+ * the real search from
+ *
+ * @last_block:
+ * the maxium block number that our goal reservable space
+ * could start from. This is normally the last block in this
+ * group. The search will end when we found the start of next
+ * possiblereservable space is out of this boundary.
+ * This could handle the cross bounday reservation window request.
+ *
+ * basically we search from the given range, rather than the whole
+ * reservation double linked list, (start_block, last_block)
+ * to find a free region that of of my size and has not
+ * been reserved.
+ *
+ * on succeed, it returns the reservation window to be append to.
+ * failed, return NULL.
+ */
+static inline
+struct reserve_window *find_next_reservable_window(
+ struct reserve_window *search_head,
+ struct reserve_window *fs_rsv_head,
+ unsigned long size, int *start_block,
+ int last_block)
+{
+ struct reserve_window *rsv;
+ int cur;
+
+ /* TODO:make the start of the reservation window byte alligned */
+ /*cur = *start_block & 8;*/
+ cur = *start_block;
+ rsv = list_entry(search_head->rsv_list.next,
+ struct reserve_window, rsv_list);
+ while (rsv != fs_rsv_head) {
+ if (cur + size <= rsv->rsv_start) {
+ /*
+ * Found a reserveable space big enough. We could
+ * have a reservation across the group boundary here
+ */
+ break;
+ }
+ if (cur <= rsv->rsv_end)
+ cur = rsv->rsv_end + 1;
+
+ /* TODO?
+ * in the case we could not find a reservable space
+ * that is what is expected, during the re-search, we could
+ * remember what's the largest reservable space we could have
+ * and return that one.
+ *
+ * For now it will fail if we could not find the reservable
+ * space with expected-size (or more)...
+ */
+ rsv = list_entry(rsv->rsv_list.next,
+ struct reserve_window, rsv_list);
+ if (cur > last_block)
+ return NULL; /* fail */
+ }
+ /*
+ * we come here either :
+ * when we rearch to the end of the whole list,
+ * and there is empty reservable space after last entry in the list.
+ * append it to the end of the list.
+ *
+ * or we found one reservable space in the middle of the list,
+ * return the reservation window that we could append to.
+ * succeed.
+ */
+ *start_block = cur;
+ return list_entry(rsv->rsv_list.prev, struct reserve_window, rsv_list);
+}
+
+/**
+ * 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 reservatio, then we
+ * start from a given goal, or the first block of the group, if
+ * the goal is not given.
+ *
+ * We first find a reservable space after the goal, then from
+ * there,we check the bitmap for the first free block after
+ * it. If there is no free block until the end of group, then the
+ * whole group is full, we failed. Otherwise, check if the free
+ * block is inside the expected reservable space, if so, we
+ * succeed.
+ * If the first free block is outside the reseravle space, then
+ * start from the first free block, we search for next avalibale
+ * space, and go on.
+ *
+ * on succeed, a new reservation will be found and inserted into the list
+ * It contains at least one free block, and it is not overlap with other
+ * reservation window.
+ *
+ * failed: we failed to found a reservation window in this group
+ *
+ * @rsv: the reservation
+ *
+ * @goal: The goal. 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.
+ *
+ * @sb: the super block
+ * @group: the group we are trying to do allocate in
+ * @bitmap_bh: the block group block bitmap
+ */
+static int alloc_new_reservation(struct reserve_window *my_rsv,
+ int goal, struct super_block *sb,
+ unsigned int group, struct buffer_head *bitmap_bh)
+{
+ struct reserve_window *search_head;
+ int group_first_block, group_end_block, start_block;
+ int first_free_block;
+ int reservable_space_start;
+ struct reserve_window *prev_rsv;
+ struct reserve_window *fs_rsv_head = &EXT3_SB(sb)->s_rsv_window_head;
+ unsigned long size;
+
+ group_first_block = le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) +
+ group * EXT3_BLOCKS_PER_GROUP(sb);
+ group_end_block = group_first_block + EXT3_BLOCKS_PER_GROUP(sb) - 1;
+
+ if (goal < 0)
+ start_block = group_first_block;
+ else
+ 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)) {
+ /*
+ * if the old reservation is cross group boundary
+ * 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
+ * point to discard our window and try to allocate a new one
+ * in this group(which will fail). we should
+ * keep the reservation window, just simply move on.
+ *
+ * Maybe we could shift the start block of the reservation
+ * window to the first block of next group.
+ */
+
+ if ((my_rsv->rsv_start <= group_end_block) &&
+ (my_rsv->rsv_end > group_end_block))
+ 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 ((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
+ * we double the size of reservation window next time
+ * otherwise keep the same
+ */
+ size = size * 2;
+ if (size > EXT3_MAX_RESERVE_BLOCKS)
+ size = EXT3_MAX_RESERVE_BLOCKS;
+ 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 = fs_rsv_head;
+ }
+
+ /*
+ * find_next_reservable_window() simply find a reservable window
+ * inside the given range(start_block, group_end_block).
+ *
+ * To make sure the reservation window has a free bit inside it, we
+ * need to check the bitmap after we found a reservable window.
+ */
+retry:
+ prev_rsv = find_next_reservable_window(search_head, fs_rsv_head, size,
+ &start_block, group_end_block);
+ if (prev_rsv == NULL)
+ goto failed;
+ reservable_space_start = start_block;
+ /*
+ * On success, find_next_reservable_window() returns the
+ * reservation window where there is a reservable space after it.
+ * Before we reserve this reservable space, we need
+ * to make sure there is at least a free block inside this region.
+ *
+ * searching the first free bit on the block bitmap and copy of
+ * last committed bitmap alternatively, until we found a allocatable
+ * block. Search start from the start block of the reservable space
+ * we just found.
+ */
+ first_free_block = bitmap_search_next_usable_block(
+ reservable_space_start - group_first_block,
+ bitmap_bh, group_end_block - group_first_block + 1);