From 6115eb7fd55abca12c110535be4f777e3eba2b10 Mon Sep 17 00:00:00 2001 From: Arshad Hussain Date: Sat, 10 Feb 2018 00:41:51 +0530 Subject: [PATCH] LU-10370 ofd: truncate does not update blocks count on client 'truncate' call correctly updates the server side with correct size and blocks count. However, on the client side all the metadata are correctly updated except the blocks count, which still reflects the old count prior to truncate call. This patch fixes this issue by modifying ofd_punch_hdl() to update repbody with the updated block count. New test case under sanity is added to verify the that the blocks counts are correctly updated after truncate call Change-Id: I8f3f44e1668fab925339350074d1ad8ab681fc95 Co-authored-by: Abrarahmed Momin Signed-off-by: Abrarahmed Momin Signed-off-by: Arshad Hussain Reviewed-on: https://review.whamcloud.com/31073 Tested-by: Jenkins Tested-by: Maloo Reviewed-by: Jinshan Xiong Reviewed-by: Andreas Dilger Reviewed-by: Oleg Drokin --- lustre/ofd/ofd_dev.c | 5 ++++ lustre/osc/osc_io.c | 34 ++++++++++++++++--------- lustre/tests/sanity.sh | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 11 deletions(-) diff --git a/lustre/ofd/ofd_dev.c b/lustre/ofd/ofd_dev.c index 7e306ff..c2cda39 100644 --- a/lustre/ofd/ofd_dev.c +++ b/lustre/ofd/ofd_dev.c @@ -2081,7 +2081,12 @@ out: res = ldlm_resource_get(ns, NULL, &tsi->tsi_resid, LDLM_EXTENT, 0); if (!IS_ERR(res)) { + struct ost_lvb *res_lvb; + ldlm_res_lvbo_update(res, NULL, 0); + res_lvb = res->lr_lvb_data; + repbody->oa.o_valid |= OBD_MD_FLBLOCKS; + repbody->oa.o_blocks = res_lvb->lvb_blocks; ldlm_resource_putref(res); } } diff --git a/lustre/osc/osc_io.c b/lustre/osc/osc_io.c index 8755b4f..b97750f 100644 --- a/lustre/osc/osc_io.c +++ b/lustre/osc/osc_io.c @@ -593,25 +593,37 @@ void osc_io_setattr_end(const struct lu_env *env, struct osc_io *oio = cl2osc_io(env, slice); struct cl_object *obj = slice->cis_obj; struct osc_async_cbargs *cbargs = &oio->oi_cbarg; - int result = 0; + struct cl_attr *attr = &osc_env_info(env)->oti_attr; + struct obdo *oa = &oio->oi_oa; + unsigned int cl_valid = 0; + int result = 0; if (cbargs->opc_rpc_sent) { wait_for_completion(&cbargs->opc_sync); result = io->ci_result = cbargs->opc_rc; } - if (result == 0) { - if (oio->oi_lockless) { - /* lockless truncate */ - struct osc_device *osd = lu2osc_dev(obj->co_lu.lo_dev); - - LASSERT(cl_io_is_trunc(io)); - /* XXX: Need a lock. */ - osd->od_stats.os_lockless_truncates++; - } - } + + if (result == 0) { + if (oio->oi_lockless) { + /* lockless truncate */ + struct osc_device *osd = lu2osc_dev(obj->co_lu.lo_dev); + + LASSERT(cl_io_is_trunc(io)); + /* XXX: Need a lock. */ + osd->od_stats.os_lockless_truncates++; + } + } if (cl_io_is_trunc(io)) { __u64 size = io->u.ci_setattr.sa_attr.lvb_size; + cl_object_attr_lock(obj); + if (oa->o_valid & OBD_MD_FLBLOCKS) { + attr->cat_blocks = oa->o_blocks; + cl_valid |= CAT_BLOCKS; + } + + cl_object_attr_update(env, obj, attr, cl_valid); + cl_object_attr_unlock(obj); osc_trunc_check(env, io, oio, size); osc_cache_truncate_end(env, oio->oi_trunc); oio->oi_trunc = NULL; diff --git a/lustre/tests/sanity.sh b/lustre/tests/sanity.sh index 9e3a268..0ad1322 100755 --- a/lustre/tests/sanity.sh +++ b/lustre/tests/sanity.sh @@ -17920,6 +17920,73 @@ test_316() { } run_test 316 "lfs mv" +test_317() { + local trunc_sz + local grant_blk_size + + if [ "$(facet_fstype $facet)" == "zfs" ]; then + skip "LU-10370: no implementation for ZFS" && return + fi + + stack_trap "rm -f $DIR/$tfile" EXIT + grant_blk_size=$($LCTL get_param osc.$FSNAME*.import | + awk '/grant_block_size:/ { print $2; exit; }') + # + # Create File of size 5M. Truncate it to below size's and verify + # blocks count. + # + dd if=/dev/zero of=$DIR/$tfile bs=5M count=1 conv=fsync || + error "Create file : $DIR/$tfile" + + for trunc_sz in 2097152 4097 4000 509 0; do + $TRUNCATE $DIR/$tfile $trunc_sz || + error "truncate $tfile to $trunc_sz failed" + local sz=$(stat --format=%s $DIR/$tfile) + local blk=$(stat --format=%b $DIR/$tfile) + local trunc_blk=$((((trunc_sz + (grant_blk_size - 1) ) / + grant_blk_size) * 8)) + + if [[ $blk -ne $trunc_blk ]]; then + $(which stat) $DIR/$tfile + error "Expected Block $trunc_blk got $blk for $tfile" + fi + + $CHECKSTAT -s $trunc_sz $DIR/$tfile || + error "Expected Size $trunc_sz got $sz for $tfile" + done + + # + # sparse file test + # Create file with a hole and write actual two blocks. Block count + # must be 16. + # + dd if=/dev/zero of=$DIR/$tfile bs=$grant_blk_size count=2 seek=5 \ + conv=fsync || error "Create file : $DIR/$tfile" + + # Calculate the final truncate size. + trunc_sz=$(($(stat --format=%s $DIR/$tfile) - (grant_blk_size + 1))) + + # + # truncate to size $trunc_sz bytes. Strip the last block + # The block count must drop to 8 + # + $TRUNCATE $DIR/$tfile $trunc_sz || + error "truncate $tfile to $trunc_sz failed" + + local trunc_bsz=$((grant_blk_size / $(stat --format=%B $DIR/$tfile))) + sz=$(stat --format=%s $DIR/$tfile) + blk=$(stat --format=%b $DIR/$tfile) + + if [[ $blk -ne $trunc_bsz ]]; then + $(which stat) $DIR/$tfile + error "Expected Block $trunc_bsz got $blk for $tfile" + fi + + $CHECKSTAT -s $trunc_sz $DIR/$tfile || + error "Expected Size $trunc_sz got $sz for $tfile" +} +run_test 317 "Verify blocks get correctly update after truncate" + test_fake_rw() { local read_write=$1 if [ "$read_write" = "write" ]; then -- 1.8.3.1