From bd29c2d95562591b0c063defc31c3cf70ea5a33b Mon Sep 17 00:00:00 2001 From: Niu Yawei Date: Thu, 30 Jun 2011 21:49:04 -0700 Subject: [PATCH] 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: I50878d4459377d68a9c67575f137a3a44cb3625e Reviewed-on: http://review.whamcloud.com/1039 Tested-by: Hudson Reviewed-by: Andreas Dilger Reviewed-by: Johann Lombardi --- lustre/include/obd_support.h | 1 + lustre/obdfilter/filter_io_26.c | 24 +++++++++++++++++++++++- lustre/tests/sanity.sh | 31 +++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/lustre/include/obd_support.h b/lustre/include/obd_support.h index bce5acd..5070f6a 100644 --- a/lustre/include/obd_support.h +++ b/lustre/include/obd_support.h @@ -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 diff --git a/lustre/obdfilter/filter_io_26.c b/lustre/obdfilter/filter_io_26.c index 2f148da..abd93d9 100644 --- a/lustre/obdfilter/filter_io_26.c +++ b/lustre/obdfilter/filter_io_26.c @@ -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); diff --git a/lustre/tests/sanity.sh b/lustre/tests/sanity.sh index 88ab9aa..d977ed3 100644 --- a/lustre/tests/sanity.sh +++ b/lustre/tests/sanity.sh @@ -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" -- 1.8.3.1