From: Niu Yawei Date: Mon, 27 Jun 2011 10:55:10 +0000 (-0700) Subject: LU-456 Force commit to reuse the just-deleted blocks X-Git-Tag: 2.0.66.0~3 X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=commitdiff_plain;h=346a17e4d8b5c291d776387ace81a5b74bc24141;ds=sidebyside LU-456 Force commit to reuse the just-deleted blocks 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 Change-Id: I678b05ae9aa1b9e9d0aa29f48279bc7daedebbb2 Reviewed-on: http://review.whamcloud.com/1022 Tested-by: Hudson Reviewed-by: Andreas Dilger Reviewed-by: Johann Lombardi Tested-by: Maloo --- diff --git a/lustre/include/obd_support.h b/lustre/include/obd_support.h index 43e5ad4..7fa0686 100644 --- a/lustre/include/obd_support.h +++ b/lustre/include/obd_support.h @@ -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 diff --git a/lustre/obdfilter/filter_io_26.c b/lustre/obdfilter/filter_io_26.c index f2fac88..1c9ad6b 100644 --- a/lustre/obdfilter/filter_io_26.c +++ b/lustre/obdfilter/filter_io_26.c @@ -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); diff --git a/lustre/tests/sanity.sh b/lustre/tests/sanity.sh index a4e3581..f337115 100644 --- a/lustre/tests/sanity.sh +++ b/lustre/tests/sanity.sh @@ -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