|
@@ -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,
|
|
static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb,
|
|
struct inode *local_alloc_inode);
|
|
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
|
|
* Tell us whether a given allocation should use the local alloc
|
|
* file. Otherwise, it has to go to the main bitmap.
|
|
* 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 ocfs2_alloc_should_use_local(struct ocfs2_super *osb, u64 bits)
|
|
{
|
|
{
|
|
- int la_bits = osb->local_alloc_bits;
|
|
|
|
int ret = 0;
|
|
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;
|
|
goto bail;
|
|
|
|
|
|
/* la_bits should be at least twice the size (in clusters) of
|
|
/* la_bits should be at least twice the size (in clusters) of
|
|
@@ -96,6 +131,7 @@ int ocfs2_alloc_should_use_local(struct ocfs2_super *osb, u64 bits)
|
|
bail:
|
|
bail:
|
|
mlog(0, "state=%d, bits=%llu, la_bits=%d, ret=%d\n",
|
|
mlog(0, "state=%d, bits=%llu, la_bits=%d, ret=%d\n",
|
|
osb->local_alloc_state, (unsigned long long)bits, la_bits, ret);
|
|
osb->local_alloc_state, (unsigned long long)bits, la_bits, ret);
|
|
|
|
+ spin_unlock(&osb->osb_lock);
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -208,6 +244,9 @@ void ocfs2_shutdown_local_alloc(struct ocfs2_super *osb)
|
|
|
|
|
|
mlog_entry_void();
|
|
mlog_entry_void();
|
|
|
|
|
|
|
|
+ cancel_delayed_work(&osb->la_enable_wq);
|
|
|
|
+ flush_workqueue(ocfs2_wq);
|
|
|
|
+
|
|
if (osb->local_alloc_state == OCFS2_LA_UNUSED)
|
|
if (osb->local_alloc_state == OCFS2_LA_UNUSED)
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
@@ -445,7 +484,7 @@ out:
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
- * 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.
|
|
* local alloc. You lose them when you drop i_mutex.
|
|
*
|
|
*
|
|
* We will add ourselves to the transaction passed in, but may start
|
|
* We will add ourselves to the transaction passed in, but may start
|
|
@@ -476,16 +515,18 @@ int ocfs2_reserve_local_alloc_bits(struct ocfs2_super *osb,
|
|
|
|
|
|
mutex_lock(&local_alloc_inode->i_mutex);
|
|
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;
|
|
status = -ENOSPC;
|
|
goto bail;
|
|
goto bail;
|
|
}
|
|
}
|
|
|
|
+ spin_unlock(&osb->osb_lock);
|
|
|
|
|
|
alloc = (struct ocfs2_dinode *) osb->local_alloc_bh->b_data;
|
|
alloc = (struct ocfs2_dinode *) osb->local_alloc_bh->b_data;
|
|
|
|
|
|
@@ -513,6 +554,21 @@ int ocfs2_reserve_local_alloc_bits(struct ocfs2_super *osb,
|
|
mlog_errno(status);
|
|
mlog_errno(status);
|
|
goto bail;
|
|
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;
|
|
ac->ac_inode = local_alloc_inode;
|
|
@@ -780,6 +836,85 @@ bail:
|
|
return status;
|
|
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,
|
|
static int ocfs2_local_alloc_reserve_for_window(struct ocfs2_super *osb,
|
|
struct ocfs2_alloc_context **ac,
|
|
struct ocfs2_alloc_context **ac,
|
|
struct inode **bitmap_inode,
|
|
struct inode **bitmap_inode,
|
|
@@ -794,12 +929,21 @@ static int ocfs2_local_alloc_reserve_for_window(struct ocfs2_super *osb,
|
|
goto bail;
|
|
goto bail;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+retry_enospc:
|
|
(*ac)->ac_bits_wanted = osb->local_alloc_bits;
|
|
(*ac)->ac_bits_wanted = osb->local_alloc_bits;
|
|
|
|
|
|
status = ocfs2_reserve_cluster_bitmap_bits(osb, *ac);
|
|
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 < 0) {
|
|
- if (status != -ENOSPC)
|
|
|
|
- mlog_errno(status);
|
|
|
|
|
|
+ mlog_errno(status);
|
|
goto bail;
|
|
goto bail;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -852,6 +996,34 @@ static int ocfs2_local_alloc_new_window(struct ocfs2_super *osb,
|
|
* the more specific cluster api to claim bits. */
|
|
* the more specific cluster api to claim bits. */
|
|
status = ocfs2_claim_clusters(osb, handle, ac, osb->local_alloc_bits,
|
|
status = ocfs2_claim_clusters(osb, handle, ac, osb->local_alloc_bits,
|
|
&cluster_off, &cluster_count);
|
|
&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 < 0) {
|
|
if (status != -ENOSPC)
|
|
if (status != -ENOSPC)
|
|
mlog_errno(status);
|
|
mlog_errno(status);
|
|
@@ -895,6 +1067,8 @@ static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb,
|
|
|
|
|
|
mlog_entry_void();
|
|
mlog_entry_void();
|
|
|
|
|
|
|
|
+ ocfs2_recalc_la_window(osb, OCFS2_LA_EVENT_SLIDE);
|
|
|
|
+
|
|
/* This will lock the main bitmap for us. */
|
|
/* This will lock the main bitmap for us. */
|
|
status = ocfs2_local_alloc_reserve_for_window(osb,
|
|
status = ocfs2_local_alloc_reserve_for_window(osb,
|
|
&ac,
|
|
&ac,
|