Whamcloud - gitweb
LU-456 Force commit to reuse the just-deleted blocks
authorNiu Yawei <niu@whamcloud.com>
Fri, 1 Jul 2011 04:49:04 +0000 (21:49 -0700)
committerJohann Lombardi <johann@whamcloud.com>
Fri, 15 Jul 2011 06:14:31 +0000 (23:14 -0700)
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: I50878d4459377d68a9c67575f137a3a44cb3625e
Reviewed-on: http://review.whamcloud.com/1039
Tested-by: Hudson
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Johann Lombardi <johann@whamcloud.com>
lustre/include/obd_support.h
lustre/obdfilter/filter_io_26.c
lustre/tests/sanity.sh

index bce5acd..5070f6a 100644 (file)
@@ -234,6 +234,7 @@ extern unsigned int obd_alloc_fail_rate;
 #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 2f148da..abd93d9 100644 (file)
@@ -500,9 +500,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) {
@@ -517,6 +522,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);
@@ -594,6 +606,7 @@ int filter_commitrw_write(struct obd_export *exp, struct obdo *oa,
         int quota_pending[2] = {0, 0}, quota_pages = 0;
         unsigned int qcids[MAXQUOTAS] = {oa->o_uid, oa->o_gid};
         int sync_journal_commit = obd->u.filter.fo_syncjournal;
+        int retries = 0;
         ENTRY;
 
         LASSERT(oti != NULL);
@@ -681,6 +694,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,
@@ -739,6 +753,14 @@ 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;
+        }
+
         if (rc == 0)
                 obdo_from_inode(oa, inode,
                                 FILTER_VALID_FLAGS |OBD_MD_FLUID |OBD_MD_FLGID);
index 88ab9aa..d977ed3 100644 (file)
@@ -3905,6 +3905,37 @@ test_80() { # bug 10718
 }
 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 "write 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
        mkdir -p $DIR/d99cvsroot || error "mkdir $DIR/d99cvsroot failed"