ocfs2: lighten up allocate transaction
authorYounger Liu <younger.liu@huawei.com>
Wed, 11 Sep 2013 21:19:44 +0000 (14:19 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 11 Sep 2013 22:56:28 +0000 (15:56 -0700)
The issue scenario is as following:

When fallocating a very large disk space for a small file,
__ocfs2_extend_allocation attempts to get a very large transaction.  For
some journal sizes, there may be not enough room for this transaction,
and the fallocate will fail.

The patch below extends & restarts the transaction as necessary while
allocating space, and should work with even the smallest journal.  This
patch refers ext4 resize.

Test:
# mkfs.ocfs2 -b 4K -C 32K -T datafiles /dev/sdc
...(jounral size is 32M)
# mount.ocfs2 /dev/sdc /mnt/ocfs2/
# touch /mnt/ocfs2/1.log
# fallocate -o 0 -l 400G /mnt/ocfs2/1.log
fallocate: /mnt/ocfs2/1.log: fallocate failed: Cannot allocate memory
# tail -f /var/log/messages
[ 7372.278591] JBD: fallocate wants too many credits (2051 > 2048)
[ 7372.278597] (fallocate,6438,0):__ocfs2_extend_allocation:709 ERROR: status = -12
[ 7372.278603] (fallocate,6438,0):ocfs2_allocate_unwritten_extents:1504 ERROR: status = -12
[ 7372.278607] (fallocate,6438,0):__ocfs2_change_file_space:1955 ERROR: status = -12
^C
With this patch, the test works well.

Signed-off-by: Younger Liu <younger.liu@huawei.com>
Cc: Jie Liu <jeff.liu@oracle.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Mark Fasheh <mfasheh@suse.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
fs/ocfs2/file.c
fs/ocfs2/journal.c
fs/ocfs2/journal.h
fs/ocfs2/ocfs2_trace.h

index 3261d71319eeb27d3a569aeccf4f3f6e27a95496..409c549ae02aabe31cb3a81d0e8eeb9a364245b4 100644 (file)
@@ -671,11 +671,7 @@ restarted_transaction:
                } else {
                        BUG_ON(why != RESTART_TRANS);
 
-                       /* TODO: This can be more intelligent. */
-                       credits = ocfs2_calc_extend_credits(osb->sb,
-                                                           &fe->id2.i_list,
-                                                           clusters_to_add);
-                       status = ocfs2_extend_trans(handle, credits);
+                       status = ocfs2_allocate_extend_trans(handle, 1);
                        if (status < 0) {
                                /* handle still has to be committed at
                                 * this point. */
index 242170d83971a9bef488197111154db6c75cba0b..a126cb37ca4d690a8445bdcadc26bb6c8bda362e 100644 (file)
@@ -455,6 +455,41 @@ bail:
        return status;
 }
 
+/*
+ * If we have fewer than thresh credits, extend by OCFS2_MAX_TRANS_DATA.
+ * If that fails, restart the transaction & regain write access for the
+ * buffer head which is used for metadata modifications.
+ * Taken from Ext4: extend_or_restart_transaction()
+ */
+int ocfs2_allocate_extend_trans(handle_t *handle, int thresh)
+{
+       int status, old_nblks;
+
+       BUG_ON(!handle);
+
+       old_nblks = handle->h_buffer_credits;
+       trace_ocfs2_allocate_extend_trans(old_nblks, thresh);
+
+       if (old_nblks < thresh)
+               return 0;
+
+       status = jbd2_journal_extend(handle, OCFS2_MAX_TRANS_DATA);
+       if (status < 0) {
+               mlog_errno(status);
+               goto bail;
+       }
+
+       if (status > 0) {
+               status = jbd2_journal_restart(handle, OCFS2_MAX_TRANS_DATA);
+               if (status < 0)
+                       mlog_errno(status);
+       }
+
+bail:
+       return status;
+}
+
+
 struct ocfs2_triggers {
        struct jbd2_buffer_trigger_type ot_triggers;
        int                             ot_offset;
index 0a992737dcaf8e76d0b57b18dcb21b57d5ed6479..0b479bab36713ec3ef147c314fe2473b08ed1d9e 100644 (file)
@@ -258,6 +258,17 @@ handle_t               *ocfs2_start_trans(struct ocfs2_super *osb,
 int                         ocfs2_commit_trans(struct ocfs2_super *osb,
                                                handle_t *handle);
 int                         ocfs2_extend_trans(handle_t *handle, int nblocks);
+int                         ocfs2_allocate_extend_trans(handle_t *handle,
+                                               int thresh);
+
+/*
+ * Define an arbitrary limit for the amount of data we will anticipate
+ * writing to any given transaction.  For unbounded transactions such as
+ * fallocate(2) we can write more than this, but we always
+ * start off at the maximum transaction size and grow the transaction
+ * optimistically as we go.
+ */
+#define OCFS2_MAX_TRANS_DATA   64U
 
 /*
  * Create access is for when we get a newly created buffer and we're
index 3b481f490633af2f483afd1817fe8ad538908b6a..1b60c62aa9d6fa62940c0a9b8f9889943604170e 100644 (file)
@@ -2579,6 +2579,8 @@ DEFINE_OCFS2_INT_INT_EVENT(ocfs2_extend_trans);
 
 DEFINE_OCFS2_INT_EVENT(ocfs2_extend_trans_restart);
 
+DEFINE_OCFS2_INT_INT_EVENT(ocfs2_allocate_extend_trans);
+
 DEFINE_OCFS2_ULL_ULL_UINT_UINT_EVENT(ocfs2_journal_access);
 
 DEFINE_OCFS2_ULL_EVENT(ocfs2_journal_dirty);