Whamcloud - gitweb
LU-456 Force commit to reuse the just-deleted blocks
authorNiu Yawei <niu@whamcloud.com>
Mon, 27 Jun 2011 10:55:10 +0000 (03:55 -0700)
committerOleg Drokin <green@whamcloud.com>
Sun, 24 Jul 2011 19:26:56 +0000 (15:26 -0400)
In ext4 non-writeback journal mode, the just-deleted blocks are not
useable until the transaction committed, this could cause filter
return -ENOSPC mistakenly when the just-deleted blocks are not committed.

Whenever block allocation fails for -ENOSPC on filter, we should wait
for the previous deleted blocks committed, then retry the allocation.

Signed-off-by: Niu Yawei <niu@whamcloud.com>
Change-Id: I678b05ae9aa1b9e9d0aa29f48279bc7daedebbb2
Reviewed-on: http://review.whamcloud.com/1022
Tested-by: Hudson
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Johann Lombardi <johann@whamcloud.com>
Tested-by: Maloo <whamcloud.maloo@gmail.com>
lustre/include/obd_support.h
lustre/obdfilter/filter_io_26.c
lustre/tests/sanity.sh

index 43e5ad4..7fa0686 100644 (file)
@@ -277,6 +277,7 @@ int obd_alloc_fail(const void *ptr, const char *name, const char *type,
 #define OBD_FAIL_OST_CONNECT_NET2        0x225
 #define OBD_FAIL_OST_NOMEM               0x226
 #define OBD_FAIL_OST_BRW_PAUSE_BULK2     0x227
+#define OBD_FAIL_OST_MAPBLK_ENOSPC       0x228
 
 #define OBD_FAIL_LDLM                    0x300
 #define OBD_FAIL_LDLM_NAMESPACE_NEW      0x301
index f2fac88..1c9ad6b 100644 (file)
@@ -503,9 +503,14 @@ int filter_direct_io(int rw, struct dentry *dchild, struct filter_iobuf *iobuf,
                                iobuf->dr_ignore_quota);
         }
 
-        rc = fsfilt_map_inode_pages(obd, inode, iobuf->dr_pages,
+        if (rw == OBD_BRW_WRITE &&
+            OBD_FAIL_CHECK(OBD_FAIL_OST_MAPBLK_ENOSPC)) {
+                rc = -ENOSPC;
+        } else {
+                rc = fsfilt_map_inode_pages(obd, inode, iobuf->dr_pages,
                                     iobuf->dr_npages, iobuf->dr_blocks,
                                     obdfilter_created_scratchpad, create, sem);
+        }
 
         if (rw == OBD_BRW_WRITE) {
                 if (rc == 0) {
@@ -520,6 +525,13 @@ int filter_direct_io(int rw, struct dentry *dchild, struct filter_iobuf *iobuf,
 
                 UNLOCK_INODE_MUTEX(inode);
 
+                /* Force commit to make the just-deleted blocks
+                 * reusable. LU-456 */
+                if (rc == -ENOSPC) {
+                        fsfilt_commit(obd, inode, oti->oti_handle, 1);
+                        RETURN(rc);
+                }
+
                 rc2 = filter_finish_transno(exp, inode, oti, 0, 0);
                 if (rc2 != 0) {
                         CERROR("can't close transaction: %d\n", rc2);
@@ -597,6 +609,7 @@ int filter_commitrw_write(struct obd_export *exp, struct obdo *oa,
         unsigned int qcids[MAXQUOTAS] = { oa->o_uid, oa->o_gid };
         int rec_pending[MAXQUOTAS] = { 0, 0 }, quota_pages = 0;
         int sync_journal_commit = obd->u.filter.fo_syncjournal;
+        int retries = 0;
         ENTRY;
 
         LASSERT(oti != NULL);
@@ -684,6 +697,7 @@ int filter_commitrw_write(struct obd_export *exp, struct obdo *oa,
         ll_vfs_dq_init(inode);
         fsfilt_check_slow(obd, now, "quota init");
 
+retry:
         LOCK_INODE_MUTEX(inode);
         fsfilt_check_slow(obd, now, "i_mutex");
         oti->oti_handle = fsfilt_brw_start(obd, objcount, &fso, niocount, res,
@@ -742,6 +756,13 @@ int filter_commitrw_write(struct obd_export *exp, struct obdo *oa,
         /* filter_direct_io drops i_mutex */
         rc = filter_direct_io(OBD_BRW_WRITE, res->dentry, iobuf, exp, &iattr,
                               oti, sync_journal_commit ? &wait_handle : NULL);
+        if (rc == -ENOSPC && retries++ < 3) {
+                CDEBUG(D_INODE, "retry after force commit, retries:%d\n",
+                       retries);
+                oti->oti_handle = NULL;
+                fsfilt_check_slow(obd, now, "direct_io");
+                goto retry;
+        }
 
         obdo_from_inode(oa, inode, NULL, rc == 0 ? FILTER_VALID_FLAGS : 0 |
                                                    OBD_MD_FLUID |OBD_MD_FLGID);
index a4e3581..f337115 100644 (file)
@@ -4422,10 +4422,42 @@ test_80() { # bug 10718
                 error "elapsed for 1M@1T = $DIFF"
         fi
         true
-       rm -f $DIR/$tfile
+        rm -f $DIR/$tfile
 }
 run_test 80 "Page eviction is equally fast at high offsets too  ===="
 
+test_81a() { # LU-456
+        # define OBD_FAIL_OST_MAPBLK_ENOSPC    0x228
+        # MUST OR with the OBD_FAIL_ONCE (0x80000000)
+        do_facet ost0 lctl set_param fail_loc=0x80000228
+
+        # write should trigger a retry and success
+        $SETSTRIPE -i 0 -c 1 $DIR/$tfile
+        multiop $DIR/$tfile oO_CREAT:O_RDWR:O_SYNC:w4096c
+        RC=$?
+        if [ $RC -ne 0 ] ; then
+                error "write should success, but failed for $RC"
+        fi
+}
+run_test 81a "OST should retry write when get -ENOSPC ==============="
+
+test_81b() { # LU-456
+        # define OBD_FAIL_OST_MAPBLK_ENOSPC    0x228
+        # Don't OR with the OBD_FAIL_ONCE (0x80000000)
+        do_facet ost0 lctl set_param fail_loc=0x228
+
+        # write should retry several times and return -ENOSPC finally
+        $SETSTRIPE -i 0 -c 1 $DIR/$tfile
+        multiop $DIR/$tfile oO_CREAT:O_RDWR:O_SYNC:w4096c
+        RC=$?
+        ENOSPC=28
+        if [ $RC -ne $ENOSPC ] ; then
+                error "dd should fail for -ENOSPC, but succeed."
+        fi
+}
+run_test 81b "OST should return -ENOSPC when retry still fails ======="
+
+
 test_99a() {
         [ -z "$(which cvs 2>/dev/null)" ] && skip_env "could not find cvs" && \
            return