Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 114365
b: refs/heads/master
c: 9c7af40
h: refs/heads/master
i:
  114363: 3d64a88
v: v3
  • Loading branch information
Mark Fasheh committed Oct 13, 2008
1 parent 1936d58 commit 37b057a
Show file tree
Hide file tree
Showing 7 changed files with 231 additions and 32 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: ebcee4b5c9136096f64ee6f691a013d7c0a4bc34
refs/heads/master: 9c7af40b210e87f8fddd97b0badc0a352862234a
198 changes: 186 additions & 12 deletions trunk/fs/ocfs2/localalloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,51 @@ static int ocfs2_local_alloc_new_window(struct ocfs2_super *osb,
static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb,
struct inode *local_alloc_inode);

static inline int ocfs2_la_state_enabled(struct ocfs2_super *osb)
{
return (osb->local_alloc_state == OCFS2_LA_THROTTLED ||
osb->local_alloc_state == OCFS2_LA_ENABLED);
}

void ocfs2_local_alloc_seen_free_bits(struct ocfs2_super *osb,
unsigned int num_clusters)
{
spin_lock(&osb->osb_lock);
if (osb->local_alloc_state == OCFS2_LA_DISABLED ||
osb->local_alloc_state == OCFS2_LA_THROTTLED)
if (num_clusters >= osb->local_alloc_default_bits) {
cancel_delayed_work(&osb->la_enable_wq);
osb->local_alloc_state = OCFS2_LA_ENABLED;
}
spin_unlock(&osb->osb_lock);
}

void ocfs2_la_enable_worker(struct work_struct *work)
{
struct ocfs2_super *osb =
container_of(work, struct ocfs2_super,
la_enable_wq.work);
spin_lock(&osb->osb_lock);
osb->local_alloc_state = OCFS2_LA_ENABLED;
spin_unlock(&osb->osb_lock);
}

/*
* Tell us whether a given allocation should use the local alloc
* file. Otherwise, it has to go to the main bitmap.
*
* This function does semi-dirty reads of local alloc size and state!
* This is ok however, as the values are re-checked once under mutex.
*/
int ocfs2_alloc_should_use_local(struct ocfs2_super *osb, u64 bits)
{
int la_bits = osb->local_alloc_bits;
int ret = 0;
int la_bits;

spin_lock(&osb->osb_lock);
la_bits = osb->local_alloc_bits;

if (osb->local_alloc_state != OCFS2_LA_ENABLED)
if (!ocfs2_la_state_enabled(osb))
goto bail;

/* la_bits should be at least twice the size (in clusters) of
Expand All @@ -96,6 +131,7 @@ int ocfs2_alloc_should_use_local(struct ocfs2_super *osb, u64 bits)
bail:
mlog(0, "state=%d, bits=%llu, la_bits=%d, ret=%d\n",
osb->local_alloc_state, (unsigned long long)bits, la_bits, ret);
spin_unlock(&osb->osb_lock);
return ret;
}

Expand Down Expand Up @@ -208,6 +244,9 @@ void ocfs2_shutdown_local_alloc(struct ocfs2_super *osb)

mlog_entry_void();

cancel_delayed_work(&osb->la_enable_wq);
flush_workqueue(ocfs2_wq);

if (osb->local_alloc_state == OCFS2_LA_UNUSED)
goto out;

Expand Down Expand Up @@ -445,7 +484,7 @@ int ocfs2_complete_local_alloc_recovery(struct ocfs2_super *osb,
}

/*
* make sure we've got at least bitswanted contiguous bits in the
* make sure we've got at least bits_wanted contiguous bits in the
* local alloc. You lose them when you drop i_mutex.
*
* We will add ourselves to the transaction passed in, but may start
Expand Down Expand Up @@ -476,16 +515,18 @@ int ocfs2_reserve_local_alloc_bits(struct ocfs2_super *osb,

mutex_lock(&local_alloc_inode->i_mutex);

if (osb->local_alloc_state != OCFS2_LA_ENABLED) {
status = -ENOSPC;
goto bail;
}

if (bits_wanted > osb->local_alloc_bits) {
mlog(0, "Asking for more than my max window size!\n");
/*
* We must double check state and allocator bits because
* another process may have changed them while holding i_mutex.
*/
spin_lock(&osb->osb_lock);
if (!ocfs2_la_state_enabled(osb) ||
(bits_wanted > osb->local_alloc_bits)) {
spin_unlock(&osb->osb_lock);
status = -ENOSPC;
goto bail;
}
spin_unlock(&osb->osb_lock);

alloc = (struct ocfs2_dinode *) osb->local_alloc_bh->b_data;

Expand Down Expand Up @@ -513,6 +554,21 @@ int ocfs2_reserve_local_alloc_bits(struct ocfs2_super *osb,
mlog_errno(status);
goto bail;
}

/*
* Under certain conditions, the window slide code
* might have reduced the number of bits available or
* disabled the the local alloc entirely. Re-check
* here and return -ENOSPC if necessary.
*/
status = -ENOSPC;
if (!ocfs2_la_state_enabled(osb))
goto bail;

free_bits = le32_to_cpu(alloc->id1.bitmap1.i_total) -
le32_to_cpu(alloc->id1.bitmap1.i_used);
if (bits_wanted > free_bits)
goto bail;
}

ac->ac_inode = local_alloc_inode;
Expand Down Expand Up @@ -780,6 +836,85 @@ static int ocfs2_sync_local_to_main(struct ocfs2_super *osb,
return status;
}

enum ocfs2_la_event {
OCFS2_LA_EVENT_SLIDE, /* Normal window slide. */
OCFS2_LA_EVENT_FRAGMENTED, /* The global bitmap has
* enough bits theoretically
* free, but a contiguous
* allocation could not be
* found. */
OCFS2_LA_EVENT_ENOSPC, /* Global bitmap doesn't have
* enough bits free to satisfy
* our request. */
};
#define OCFS2_LA_ENABLE_INTERVAL (30 * HZ)
/*
* Given an event, calculate the size of our next local alloc window.
*
* This should always be called under i_mutex of the local alloc inode
* so that local alloc disabling doesn't race with processes trying to
* use the allocator.
*
* Returns the state which the local alloc was left in. This value can
* be ignored by some paths.
*/
static int ocfs2_recalc_la_window(struct ocfs2_super *osb,
enum ocfs2_la_event event)
{
unsigned int bits;
int state;

spin_lock(&osb->osb_lock);
if (osb->local_alloc_state == OCFS2_LA_DISABLED) {
WARN_ON_ONCE(osb->local_alloc_state == OCFS2_LA_DISABLED);
goto out_unlock;
}

/*
* ENOSPC and fragmentation are treated similarly for now.
*/
if (event == OCFS2_LA_EVENT_ENOSPC ||
event == OCFS2_LA_EVENT_FRAGMENTED) {
/*
* We ran out of contiguous space in the primary
* bitmap. Drastically reduce the number of bits used
* by local alloc until we have to disable it.
*/
bits = osb->local_alloc_bits >> 1;
if (bits > ocfs2_megabytes_to_clusters(osb->sb, 1)) {
/*
* By setting state to THROTTLED, we'll keep
* the number of local alloc bits used down
* until an event occurs which would give us
* reason to assume the bitmap situation might
* have changed.
*/
osb->local_alloc_state = OCFS2_LA_THROTTLED;
osb->local_alloc_bits = bits;
} else {
osb->local_alloc_state = OCFS2_LA_DISABLED;
}
queue_delayed_work(ocfs2_wq, &osb->la_enable_wq,
OCFS2_LA_ENABLE_INTERVAL);
goto out_unlock;
}

/*
* Don't increase the size of the local alloc window until we
* know we might be able to fulfill the request. Otherwise, we
* risk bouncing around the global bitmap during periods of
* low space.
*/
if (osb->local_alloc_state != OCFS2_LA_THROTTLED)
osb->local_alloc_bits = osb->local_alloc_default_bits;

out_unlock:
state = osb->local_alloc_state;
spin_unlock(&osb->osb_lock);

return state;
}

static int ocfs2_local_alloc_reserve_for_window(struct ocfs2_super *osb,
struct ocfs2_alloc_context **ac,
struct inode **bitmap_inode,
Expand All @@ -794,12 +929,21 @@ static int ocfs2_local_alloc_reserve_for_window(struct ocfs2_super *osb,
goto bail;
}

retry_enospc:
(*ac)->ac_bits_wanted = osb->local_alloc_bits;

status = ocfs2_reserve_cluster_bitmap_bits(osb, *ac);
if (status == -ENOSPC) {
if (ocfs2_recalc_la_window(osb, OCFS2_LA_EVENT_ENOSPC) ==
OCFS2_LA_DISABLED)
goto bail;

ocfs2_free_ac_resource(*ac);
memset(*ac, 0, sizeof(struct ocfs2_alloc_context));
goto retry_enospc;
}
if (status < 0) {
if (status != -ENOSPC)
mlog_errno(status);
mlog_errno(status);
goto bail;
}

Expand Down Expand Up @@ -852,6 +996,34 @@ static int ocfs2_local_alloc_new_window(struct ocfs2_super *osb,
* the more specific cluster api to claim bits. */
status = ocfs2_claim_clusters(osb, handle, ac, osb->local_alloc_bits,
&cluster_off, &cluster_count);
if (status == -ENOSPC) {
retry_enospc:
/*
* Note: We could also try syncing the journal here to
* allow use of any free bits which the current
* transaction can't give us access to. --Mark
*/
if (ocfs2_recalc_la_window(osb, OCFS2_LA_EVENT_FRAGMENTED) ==
OCFS2_LA_DISABLED)
goto bail;

status = ocfs2_claim_clusters(osb, handle, ac,
osb->local_alloc_bits,
&cluster_off,
&cluster_count);
if (status == -ENOSPC)
goto retry_enospc;
/*
* We only shrunk the *minimum* number of in our
* request - it's entirely possible that the allocator
* might give us more than we asked for.
*/
if (status == 0) {
spin_lock(&osb->osb_lock);
osb->local_alloc_bits = cluster_count;
spin_unlock(&osb->osb_lock);
}
}
if (status < 0) {
if (status != -ENOSPC)
mlog_errno(status);
Expand Down Expand Up @@ -895,6 +1067,8 @@ static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb,

mlog_entry_void();

ocfs2_recalc_la_window(osb, OCFS2_LA_EVENT_SLIDE);

/* This will lock the main bitmap for us. */
status = ocfs2_local_alloc_reserve_for_window(osb,
&ac,
Expand Down
4 changes: 4 additions & 0 deletions trunk/fs/ocfs2/localalloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,8 @@ int ocfs2_claim_local_alloc_bits(struct ocfs2_super *osb,
u32 *bit_off,
u32 *num_bits);

void ocfs2_local_alloc_seen_free_bits(struct ocfs2_super *osb,
unsigned int num_clusters);
void ocfs2_la_enable_worker(struct work_struct *work);

#endif /* OCFS2_LOCALALLOC_H */
23 changes: 19 additions & 4 deletions trunk/fs/ocfs2/ocfs2.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,9 +171,13 @@ struct ocfs2_alloc_stats

enum ocfs2_local_alloc_state
{
OCFS2_LA_UNUSED = 0,
OCFS2_LA_ENABLED,
OCFS2_LA_DISABLED
OCFS2_LA_UNUSED = 0, /* Local alloc will never be used for
* this mountpoint. */
OCFS2_LA_ENABLED, /* Local alloc is in use. */
OCFS2_LA_THROTTLED, /* Local alloc is in use, but number
* of bits has been reduced. */
OCFS2_LA_DISABLED /* Local alloc has temporarily been
* disabled. */
};

enum ocfs2_mount_options
Expand Down Expand Up @@ -252,9 +256,20 @@ struct ocfs2_super
struct ocfs2_journal *journal;
unsigned long osb_commit_interval;

struct delayed_work la_enable_wq;

/*
* Must hold local alloc i_mutex and osb->osb_lock to change
* local_alloc_bits. Reads can be done under either lock.
*/
unsigned int local_alloc_bits;
enum ocfs2_local_alloc_state local_alloc_state;
unsigned int local_alloc_default_bits;

enum ocfs2_local_alloc_state local_alloc_state; /* protected
* by osb_lock */

struct buffer_head *local_alloc_bh;

u64 la_last_gd;

/* Next two fields are for local node slot recovery during
Expand Down
Loading

0 comments on commit 37b057a

Please sign in to comment.