From 43afdc0ca2574b77fea8bc94e0dcdeb5afc82e6f Mon Sep 17 00:00:00 2001 From: Patrick Farrell Date: Wed, 13 Mar 2024 10:45:44 -0400 Subject: [PATCH] LU-17533 llite: call merge attr on all writes Because DIO writes do not update the inode size during the write, when a file is closed and the LSOM update is sent, the file size provided by the client is incorrect. DIO writes don't cause consistency problems because ls and other things which check the file size will get the correct size and update the inode size then, but that just means this issue isn't fatal - DIO should still update the inode size. This is best done by calling ll_merge_attr on all writes at the end of the write, rather than just for async writes in vvp_io_write_commit. Signed-off-by: Patrick Farrell Change-Id: I856b319254ad7093e69e41613120e06b71f656cc Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/54016 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Shaun Tancheff Reviewed-by: Andreas Dilger Reviewed-by: Qian Yingjin Reviewed-by: Oleg Drokin --- lustre/llite/file.c | 4 ++++ lustre/llite/vvp_io.c | 3 --- lustre/mdt/mdt_som.c | 4 ++++ lustre/tests/sanity.sh | 42 ++++++++++++++++++++++++------------------ 4 files changed, 32 insertions(+), 21 deletions(-) diff --git a/lustre/llite/file.c b/lustre/llite/file.c index 660a966..bc8905b 100644 --- a/lustre/llite/file.c +++ b/lustre/llite/file.c @@ -1962,6 +1962,10 @@ out: goto restart; } + /* update inode size */ + if (io->ci_type == CIT_WRITE) + ll_merge_attr(env, inode); + if (io->ci_dio_aio) { /* set the number of bytes successfully moved in the aio */ if (result > 0) diff --git a/lustre/llite/vvp_io.c b/lustre/llite/vvp_io.c index 393167a..ba73f4e 100644 --- a/lustre/llite/vvp_io.c +++ b/lustre/llite/vvp_io.c @@ -1263,9 +1263,6 @@ int vvp_io_write_commit(const struct lu_env *env, struct cl_io *io) lli->lli_async_rc = 0; } - /* update inode size */ - ll_merge_attr(env, inode); - /* Now the pages in queue were failed to commit, discard them * unless they were dirtied before. */ diff --git a/lustre/mdt/mdt_som.c b/lustre/mdt/mdt_som.c index c60b220..a7a38e5 100644 --- a/lustre/mdt/mdt_som.c +++ b/lustre/mdt/mdt_som.c @@ -199,6 +199,10 @@ int mdt_lsom_update(struct mdt_thread_info *info, ma = &info->mti_attr; la = &ma->ma_attr; + CDEBUG(D_INODE, + "valid %llx, lsom init %d lsom size %llu size %llu lsom blocks %llu blocks %llu truncate %d\n", + la->la_valid, o->mot_lsom_inited, o->mot_lsom_size, la->la_size, + o->mot_lsom_blocks, la->la_blocks, truncate); if (!(la->la_valid & (LA_SIZE | LA_LSIZE) && o->mot_lsom_size < la->la_size) && !(la->la_valid & (LA_BLOCKS | LA_LBLOCKS) && diff --git a/lustre/tests/sanity.sh b/lustre/tests/sanity.sh index e5a43f5..3cc9051 100755 --- a/lustre/tests/sanity.sh +++ b/lustre/tests/sanity.sh @@ -31253,25 +31253,27 @@ check_lsom_data() { local file=$1 local expect=$(stat -c %s $file) + local msg=$2 - check_lsom_size $1 $expect + check_lsom_size $1 $expect $msg local blocks=$($LFS getsom -b $file) expect=$(stat -c %b $file) [[ $blocks == $expect ]] || - error "$file expected blocks: $expect, got: $blocks" + error "$msg $file expected blocks: $expect, got: $blocks" } check_lsom_size() { local size local expect=$2 + local msg=$3 cancel_lru_locks mdc size=$($LFS getsom -s $1) [[ $size == $expect ]] || - error "$file expected size: $expect, got: $size" + error "$msg $file expected size: $expect, got: $size" } test_806() { @@ -31289,7 +31291,11 @@ test_806() { echo "Test SOM for single-threaded write" dd if=/dev/zero of=$DIR/$tfile bs=$bs count=1 || error "write $tfile failed" - check_lsom_size $DIR/$tfile $bs + check_lsom_size $DIR/$tfile $bs "(0)" + # Test SOM with DIO write (dd truncates to 0) + dd if=/dev/zero of=$DIR/$tfile bs=$bs count=1 oflag=direct || + error "write $tfile failed" + check_lsom_size $DIR/$tfile $bs "(1)" local num=32 local size=$(($num * $bs)) @@ -31306,7 +31312,7 @@ test_806() { for (( i=0; i < $num; i++ )); do wait ${pids[$i]} done - check_lsom_size $DIR/$tfile $size + check_lsom_size $DIR/$tfile $size "(2)" $TRUNCATE $DIR/$tfile 0 for ((i = 0; i < $num; i++)); do @@ -31317,7 +31323,7 @@ test_806() { for (( i=0; i < $num; i++ )); do wait ${pids[$i]} done - check_lsom_size $DIR/$tfile $size + check_lsom_size $DIR/$tfile $size "(3)" # multi-client writes num=$(get_node_count ${CLIENTS//,/ }) @@ -31336,7 +31342,7 @@ test_806() { for (( i=0; i < $num; i++ )); do wait ${pids[$i]} done - check_lsom_size $DIR/$tfile $offset + check_lsom_size $DIR/$tfile $offset "(4)" i=0 $TRUNCATE $DIR/$tfile 0 @@ -31349,37 +31355,37 @@ test_806() { for (( i=0; i < $num; i++ )); do wait ${pids[$i]} done - check_lsom_size $DIR/$tfile $size + check_lsom_size $DIR/$tfile $size "(5)" # verify SOM blocks count echo "Verify SOM block count" $TRUNCATE $DIR/$tfile 0 $MULTIOP $DIR/$tfile oO_TRUNC:O_RDWR:w$((bs))YSc || error "failed to write file $tfile with fdatasync and fstat" - check_lsom_data $DIR/$tfile + check_lsom_data $DIR/$tfile "(6)" $TRUNCATE $DIR/$tfile 0 $MULTIOP $DIR/$tfile oO_TRUNC:O_RDWR:w$((bs * 2))Yc || error "failed to write file $tfile with fdatasync" - check_lsom_data $DIR/$tfile + check_lsom_data $DIR/$tfile "(7)" $TRUNCATE $DIR/$tfile 0 $MULTIOP $DIR/$tfile oO_TRUNC:O_RDWR:O_SYNC:w$((bs * 3))c || error "failed to write file $tfile with sync IO" - check_lsom_data $DIR/$tfile + check_lsom_data $DIR/$tfile "(8)" # verify truncate echo "Test SOM for truncate" # use ftruncate to sync blocks on close request $MULTIOP $DIR/$tfile oO_WRONLY:T16384c - check_lsom_size $DIR/$tfile 16384 - check_lsom_data $DIR/$tfile + check_lsom_size $DIR/$tfile 16384 "(9)" + check_lsom_data $DIR/$tfile "(10)" $TRUNCATE $DIR/$tfile 1234 - check_lsom_size $DIR/$tfile 1234 + check_lsom_size $DIR/$tfile 1234 "(11)" # sync blocks on the MDT $MULTIOP $DIR/$tfile oc - check_lsom_data $DIR/$tfile + check_lsom_data $DIR/$tfile "(12)" } run_test 806 "Verify Lazy Size on MDS" @@ -31428,9 +31434,9 @@ test_807() { do_rpc_nodes "$CLIENTS" cancel_lru_locks osc do_nodes "$CLIENTS" "sync ; sleep 5 ; sync" $LSOM_SYNC -u $cl_user -m $FSNAME-MDT0000 $MOUNT - check_lsom_data $DIR/$tdir/trunc - check_lsom_data $DIR/$tdir/single_dd - check_lsom_data $DIR/$tfile + check_lsom_data $DIR/$tdir/trunc "(0)" + check_lsom_data $DIR/$tdir/single_dd "(1)" + check_lsom_data $DIR/$tfile "(2)" rm -rf $DIR/$tdir # Deregistration step -- 1.8.3.1