Skip to content

Commit

Permalink
ocfs2: allocation reservations
Browse files Browse the repository at this point in the history
This patch improves Ocfs2 allocation policy by allowing an inode to
reserve a portion of the local alloc bitmap for itself. The reserved
portion (allocation window) is advisory in that other allocation
windows might steal it if the local alloc bitmap becomes
full. Otherwise, the reservations are honored and guaranteed to be
free. When the local alloc window is moved to a different portion of
the bitmap, existing reservations are discarded.

Reservation windows are represented internally by a red-black
tree. Within that tree, each node represents the reservation window of
one inode. An LRU of active reservations is also maintained. When new
data is written, we allocate it from the inodes window. When all bits
in a window are exhausted, we allocate a new one as close to the
previous one as possible. Should we not find free space, an existing
reservation is pulled off the LRU and cannibalized.

Signed-off-by: Mark Fasheh <mfasheh@suse.com>
  • Loading branch information
Mark Fasheh authored and Joel Becker committed May 6, 2010
1 parent ec20cec commit d02f00c
Show file tree
Hide file tree
Showing 10 changed files with 1,094 additions and 11 deletions.
3 changes: 3 additions & 0 deletions Documentation/filesystems/ocfs2.txt
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,6 @@ user_xattr (*) Enables Extended User Attributes.
nouser_xattr Disables Extended User Attributes.
acl Enables POSIX Access Control Lists support.
noacl (*) Disables POSIX Access Control Lists support.
resv_level=4 (*) Set how agressive allocation reservations will be.
Valid values are between 0 (reservations off) to 8
(maximum space for reservations).
1 change: 1 addition & 0 deletions fs/ocfs2/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ ocfs2-objs := \
mmap.o \
namei.o \
refcounttree.o \
reservations.o \
resize.o \
slot_map.o \
suballoc.o \
Expand Down
1 change: 1 addition & 0 deletions fs/ocfs2/cluster/masklog.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ static struct mlog_attribute mlog_attrs[MLOG_MAX_BITS] = {
define_mask(ERROR),
define_mask(NOTICE),
define_mask(KTHREAD),
define_mask(RESERVATIONS),
};

static struct attribute *mlog_attr_ptrs[MLOG_MAX_BITS] = {NULL, };
Expand Down
1 change: 1 addition & 0 deletions fs/ocfs2/cluster/masklog.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@
#define ML_ERROR 0x0000000100000000ULL /* sent to KERN_ERR */
#define ML_NOTICE 0x0000000200000000ULL /* setn to KERN_NOTICE */
#define ML_KTHREAD 0x0000000400000000ULL /* kernel thread activity */
#define ML_RESERVATIONS 0x0000000800000000ULL /* ocfs2 alloc reservations */

#define MLOG_INITIAL_AND_MASK (ML_ERROR|ML_NOTICE)
#define MLOG_INITIAL_NOT_MASK (ML_ENTRY|ML_EXIT)
Expand Down
64 changes: 53 additions & 11 deletions fs/ocfs2/localalloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ static u32 ocfs2_local_alloc_count_bits(struct ocfs2_dinode *alloc);

static int ocfs2_local_alloc_find_clear_bits(struct ocfs2_super *osb,
struct ocfs2_dinode *alloc,
u32 numbits);
u32 *numbits,
struct ocfs2_alloc_reservation *resv);

static void ocfs2_clear_local_alloc(struct ocfs2_dinode *alloc);

Expand Down Expand Up @@ -262,6 +263,8 @@ void ocfs2_shutdown_local_alloc(struct ocfs2_super *osb)

osb->local_alloc_state = OCFS2_LA_DISABLED;

ocfs2_resmap_uninit(&osb->osb_la_resmap);

main_bm_inode = ocfs2_get_system_file_inode(osb,
GLOBAL_BITMAP_SYSTEM_INODE,
OCFS2_INVALID_SLOT);
Expand Down Expand Up @@ -493,7 +496,7 @@ static int ocfs2_local_alloc_in_range(struct inode *inode,
alloc = (struct ocfs2_dinode *) osb->local_alloc_bh->b_data;
la = OCFS2_LOCAL_ALLOC(alloc);

start = ocfs2_local_alloc_find_clear_bits(osb, alloc, bits_wanted);
start = ocfs2_local_alloc_find_clear_bits(osb, alloc, &bits_wanted, NULL);
if (start == -1) {
mlog_errno(-ENOSPC);
return 0;
Expand Down Expand Up @@ -659,7 +662,8 @@ int ocfs2_claim_local_alloc_bits(struct ocfs2_super *osb,
alloc = (struct ocfs2_dinode *) osb->local_alloc_bh->b_data;
la = OCFS2_LOCAL_ALLOC(alloc);

start = ocfs2_local_alloc_find_clear_bits(osb, alloc, bits_wanted);
start = ocfs2_local_alloc_find_clear_bits(osb, alloc, &bits_wanted,
ac->ac_resv);
if (start == -1) {
/* TODO: Shouldn't we just BUG here? */
status = -ENOSPC;
Expand All @@ -669,8 +673,6 @@ int ocfs2_claim_local_alloc_bits(struct ocfs2_super *osb,

bitmap = la->la_bitmap;
*bit_off = le32_to_cpu(la->la_bm_off) + start;
/* local alloc is always contiguous by nature -- we never
* delete bits from it! */
*num_bits = bits_wanted;

status = ocfs2_journal_access_di(handle,
Expand All @@ -682,6 +684,9 @@ int ocfs2_claim_local_alloc_bits(struct ocfs2_super *osb,
goto bail;
}

ocfs2_resmap_claimed_bits(&osb->osb_la_resmap, ac->ac_resv, start,
bits_wanted);

while(bits_wanted--)
ocfs2_set_bit(start++, bitmap);

Expand Down Expand Up @@ -711,20 +716,48 @@ static u32 ocfs2_local_alloc_count_bits(struct ocfs2_dinode *alloc)
}

static int ocfs2_local_alloc_find_clear_bits(struct ocfs2_super *osb,
struct ocfs2_dinode *alloc,
u32 numbits)
struct ocfs2_dinode *alloc,
u32 *numbits,
struct ocfs2_alloc_reservation *resv)
{
int numfound, bitoff, left, startoff, lastzero;
int local_resv = 0;
struct ocfs2_alloc_reservation r;
void *bitmap = NULL;
struct ocfs2_reservation_map *resmap = &osb->osb_la_resmap;

mlog_entry("(numbits wanted = %u)\n", numbits);
mlog_entry("(numbits wanted = %u)\n", *numbits);

if (!alloc->id1.bitmap1.i_total) {
mlog(0, "No bits in my window!\n");
bitoff = -1;
goto bail;
}

if (!resv) {
local_resv = 1;
ocfs2_resv_init_once(&r);
ocfs2_resv_set_type(&r, OCFS2_RESV_FLAG_TMP);
resv = &r;
}

numfound = *numbits;
if (ocfs2_resmap_resv_bits(resmap, resv, &bitoff, &numfound) == 0) {
if (numfound < *numbits)
*numbits = numfound;
goto bail;
}

/*
* Code error. While reservations are enabled, local
* allocation should _always_ go through them.
*/
BUG_ON(osb->osb_resv_level != 0);

/*
* Reservations are disabled. Handle this the old way.
*/

bitmap = OCFS2_LOCAL_ALLOC(alloc)->la_bitmap;

numfound = bitoff = startoff = 0;
Expand All @@ -750,7 +783,7 @@ static int ocfs2_local_alloc_find_clear_bits(struct ocfs2_super *osb,
startoff = bitoff+1;
}
/* we got everything we needed */
if (numfound == numbits) {
if (numfound == *numbits) {
/* mlog(0, "Found it all!\n"); */
break;
}
Expand All @@ -759,12 +792,18 @@ static int ocfs2_local_alloc_find_clear_bits(struct ocfs2_super *osb,
mlog(0, "Exiting loop, bitoff = %d, numfound = %d\n", bitoff,
numfound);

if (numfound == numbits)
if (numfound == *numbits) {
bitoff = startoff - numfound;
else
*numbits = numfound;
} else {
numfound = 0;
bitoff = -1;
}

bail:
if (local_resv)
ocfs2_resv_discard(resmap, resv);

mlog_exit(bitoff);
return bitoff;
}
Expand Down Expand Up @@ -1087,6 +1126,9 @@ static int ocfs2_local_alloc_new_window(struct ocfs2_super *osb,
memset(OCFS2_LOCAL_ALLOC(alloc)->la_bitmap, 0,
le16_to_cpu(la->la_size));

ocfs2_resmap_restart(&osb->osb_la_resmap, cluster_count,
OCFS2_LOCAL_ALLOC(alloc)->la_bitmap);

mlog(0, "New window allocated:\n");
mlog(0, "window la_bm_off = %u\n",
OCFS2_LOCAL_ALLOC(alloc)->la_bm_off);
Expand Down
5 changes: 5 additions & 0 deletions fs/ocfs2/ocfs2.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
/* For struct ocfs2_blockcheck_stats */
#include "blockcheck.h"

#include "reservations.h"

/* Caching of metadata buffers */

Expand Down Expand Up @@ -349,6 +350,10 @@ struct ocfs2_super

u64 la_last_gd;

struct ocfs2_reservation_map osb_la_resmap;

unsigned int osb_resv_level;

/* Next three fields are for local node slot recovery during
* mount. */
int dirty;
Expand Down
Loading

0 comments on commit d02f00c

Please sign in to comment.