|
@@ -276,7 +276,7 @@ static void ail2_empty(struct gfs2_sbd *sdp, unsigned int new_tail)
|
|
|
* @blks: The number of blocks to reserve
|
|
|
*
|
|
|
* Note that we never give out the last few blocks of the journal. Thats
|
|
|
- * due to the fact that there is are a small number of header blocks
|
|
|
+ * due to the fact that there is a small number of header blocks
|
|
|
* associated with each log flush. The exact number can't be known until
|
|
|
* flush time, so we ensure that we have just enough free blocks at all
|
|
|
* times to avoid running out during a log flush.
|
|
@@ -371,6 +371,58 @@ static inline unsigned int log_distance(struct gfs2_sbd *sdp, unsigned int newer
|
|
|
return dist;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * calc_reserved - Calculate the number of blocks to reserve when
|
|
|
+ * refunding a transaction's unused buffers.
|
|
|
+ * @sdp: The GFS2 superblock
|
|
|
+ *
|
|
|
+ * This is complex. We need to reserve room for all our currently used
|
|
|
+ * metadata buffers (e.g. normal file I/O rewriting file time stamps) and
|
|
|
+ * all our journaled data buffers for journaled files (e.g. files in the
|
|
|
+ * meta_fs like rindex, or files for which chattr +j was done.)
|
|
|
+ * If we don't reserve enough space, gfs2_log_refund and gfs2_log_flush
|
|
|
+ * will count it as free space (sd_log_blks_free) and corruption will follow.
|
|
|
+ *
|
|
|
+ * We can have metadata bufs and jdata bufs in the same journal. So each
|
|
|
+ * type gets its own log header, for which we need to reserve a block.
|
|
|
+ * In fact, each type has the potential for needing more than one header
|
|
|
+ * in cases where we have more buffers than will fit on a journal page.
|
|
|
+ * Metadata journal entries take up half the space of journaled buffer entries.
|
|
|
+ * Thus, metadata entries have buf_limit (502) and journaled buffers have
|
|
|
+ * databuf_limit (251) before they cause a wrap around.
|
|
|
+ *
|
|
|
+ * Also, we need to reserve blocks for revoke journal entries and one for an
|
|
|
+ * overall header for the lot.
|
|
|
+ *
|
|
|
+ * Returns: the number of blocks reserved
|
|
|
+ */
|
|
|
+static unsigned int calc_reserved(struct gfs2_sbd *sdp)
|
|
|
+{
|
|
|
+ unsigned int reserved = 0;
|
|
|
+ unsigned int mbuf_limit, metabufhdrs_needed;
|
|
|
+ unsigned int dbuf_limit, databufhdrs_needed;
|
|
|
+ unsigned int revokes = 0;
|
|
|
+
|
|
|
+ mbuf_limit = buf_limit(sdp);
|
|
|
+ metabufhdrs_needed = (sdp->sd_log_commited_buf +
|
|
|
+ (mbuf_limit - 1)) / mbuf_limit;
|
|
|
+ dbuf_limit = databuf_limit(sdp);
|
|
|
+ databufhdrs_needed = (sdp->sd_log_commited_databuf +
|
|
|
+ (dbuf_limit - 1)) / dbuf_limit;
|
|
|
+
|
|
|
+ if (sdp->sd_log_commited_revoke)
|
|
|
+ revokes = gfs2_struct2blk(sdp, sdp->sd_log_commited_revoke,
|
|
|
+ sizeof(u64));
|
|
|
+
|
|
|
+ reserved = sdp->sd_log_commited_buf + metabufhdrs_needed +
|
|
|
+ sdp->sd_log_commited_databuf + databufhdrs_needed +
|
|
|
+ revokes;
|
|
|
+ /* One for the overall header */
|
|
|
+ if (reserved)
|
|
|
+ reserved++;
|
|
|
+ return reserved;
|
|
|
+}
|
|
|
+
|
|
|
static unsigned int current_tail(struct gfs2_sbd *sdp)
|
|
|
{
|
|
|
struct gfs2_ail *ai;
|
|
@@ -461,14 +513,14 @@ struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp,
|
|
|
return bh;
|
|
|
}
|
|
|
|
|
|
-static void log_pull_tail(struct gfs2_sbd *sdp, unsigned int new_tail, int pull)
|
|
|
+static void log_pull_tail(struct gfs2_sbd *sdp, unsigned int new_tail)
|
|
|
{
|
|
|
unsigned int dist = log_distance(sdp, new_tail, sdp->sd_log_tail);
|
|
|
|
|
|
ail2_empty(sdp, new_tail);
|
|
|
|
|
|
gfs2_log_lock(sdp);
|
|
|
- sdp->sd_log_blks_free += dist - (pull ? 1 : 0);
|
|
|
+ sdp->sd_log_blks_free += dist;
|
|
|
gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks);
|
|
|
gfs2_log_unlock(sdp);
|
|
|
|
|
@@ -518,7 +570,7 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull)
|
|
|
brelse(bh);
|
|
|
|
|
|
if (sdp->sd_log_tail != tail)
|
|
|
- log_pull_tail(sdp, tail, pull);
|
|
|
+ log_pull_tail(sdp, tail);
|
|
|
else
|
|
|
gfs2_assert_withdraw(sdp, !pull);
|
|
|
|
|
@@ -579,7 +631,10 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
|
|
|
INIT_LIST_HEAD(&ai->ai_ail1_list);
|
|
|
INIT_LIST_HEAD(&ai->ai_ail2_list);
|
|
|
|
|
|
- gfs2_assert_withdraw(sdp, sdp->sd_log_num_buf + sdp->sd_log_num_jdata == sdp->sd_log_commited_buf);
|
|
|
+ gfs2_assert_withdraw(sdp,
|
|
|
+ sdp->sd_log_num_buf + sdp->sd_log_num_jdata ==
|
|
|
+ sdp->sd_log_commited_buf +
|
|
|
+ sdp->sd_log_commited_databuf);
|
|
|
gfs2_assert_withdraw(sdp,
|
|
|
sdp->sd_log_num_revoke == sdp->sd_log_commited_revoke);
|
|
|
|
|
@@ -590,16 +645,19 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
|
|
|
lops_before_commit(sdp);
|
|
|
if (!list_empty(&sdp->sd_log_flush_list))
|
|
|
log_flush_commit(sdp);
|
|
|
- else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle)
|
|
|
+ else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle){
|
|
|
+ gfs2_log_lock(sdp);
|
|
|
+ sdp->sd_log_blks_free--; /* Adjust for unreserved buffer */
|
|
|
+ gfs2_log_unlock(sdp);
|
|
|
log_write_header(sdp, 0, PULL);
|
|
|
+ }
|
|
|
lops_after_commit(sdp, ai);
|
|
|
|
|
|
gfs2_log_lock(sdp);
|
|
|
sdp->sd_log_head = sdp->sd_log_flush_head;
|
|
|
- sdp->sd_log_blks_free -= sdp->sd_log_num_hdrs;
|
|
|
sdp->sd_log_blks_reserved = 0;
|
|
|
sdp->sd_log_commited_buf = 0;
|
|
|
- sdp->sd_log_num_hdrs = 0;
|
|
|
+ sdp->sd_log_commited_databuf = 0;
|
|
|
sdp->sd_log_commited_revoke = 0;
|
|
|
|
|
|
if (!list_empty(&ai->ai_ail1_list)) {
|
|
@@ -616,32 +674,26 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
|
|
|
|
|
|
static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
|
|
|
{
|
|
|
- unsigned int reserved = 0;
|
|
|
+ unsigned int reserved;
|
|
|
unsigned int old;
|
|
|
|
|
|
gfs2_log_lock(sdp);
|
|
|
|
|
|
sdp->sd_log_commited_buf += tr->tr_num_buf_new - tr->tr_num_buf_rm;
|
|
|
- gfs2_assert_withdraw(sdp, ((int)sdp->sd_log_commited_buf) >= 0);
|
|
|
+ sdp->sd_log_commited_databuf += tr->tr_num_databuf_new -
|
|
|
+ tr->tr_num_databuf_rm;
|
|
|
+ gfs2_assert_withdraw(sdp, (((int)sdp->sd_log_commited_buf) >= 0) ||
|
|
|
+ (((int)sdp->sd_log_commited_databuf) >= 0));
|
|
|
sdp->sd_log_commited_revoke += tr->tr_num_revoke - tr->tr_num_revoke_rm;
|
|
|
gfs2_assert_withdraw(sdp, ((int)sdp->sd_log_commited_revoke) >= 0);
|
|
|
-
|
|
|
- if (sdp->sd_log_commited_buf)
|
|
|
- reserved += sdp->sd_log_commited_buf;
|
|
|
- if (sdp->sd_log_commited_revoke)
|
|
|
- reserved += gfs2_struct2blk(sdp, sdp->sd_log_commited_revoke,
|
|
|
- sizeof(u64));
|
|
|
- if (reserved)
|
|
|
- reserved++;
|
|
|
-
|
|
|
+ reserved = calc_reserved(sdp);
|
|
|
old = sdp->sd_log_blks_free;
|
|
|
sdp->sd_log_blks_free += tr->tr_reserved -
|
|
|
(reserved - sdp->sd_log_blks_reserved);
|
|
|
|
|
|
gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free >= old);
|
|
|
- gfs2_assert_withdraw(sdp,
|
|
|
- sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks +
|
|
|
- sdp->sd_log_num_hdrs);
|
|
|
+ gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free <=
|
|
|
+ sdp->sd_jdesc->jd_blocks);
|
|
|
|
|
|
sdp->sd_log_blks_reserved = reserved;
|
|
|
|
|
@@ -687,13 +739,13 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp)
|
|
|
gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke);
|
|
|
gfs2_assert_withdraw(sdp, !sdp->sd_log_num_rg);
|
|
|
gfs2_assert_withdraw(sdp, !sdp->sd_log_num_databuf);
|
|
|
- gfs2_assert_withdraw(sdp, !sdp->sd_log_num_hdrs);
|
|
|
gfs2_assert_withdraw(sdp, list_empty(&sdp->sd_ail1_list));
|
|
|
|
|
|
sdp->sd_log_flush_head = sdp->sd_log_head;
|
|
|
sdp->sd_log_flush_wrapped = 0;
|
|
|
|
|
|
- log_write_header(sdp, GFS2_LOG_HEAD_UNMOUNT, 0);
|
|
|
+ log_write_header(sdp, GFS2_LOG_HEAD_UNMOUNT,
|
|
|
+ (sdp->sd_log_tail == current_tail(sdp)) ? 0 : PULL);
|
|
|
|
|
|
gfs2_assert_warn(sdp, sdp->sd_log_blks_free == sdp->sd_jdesc->jd_blocks);
|
|
|
gfs2_assert_warn(sdp, sdp->sd_log_head == sdp->sd_log_tail);
|