Whamcloud - gitweb
LU-16465 llite: fix LSOM blocks for ftruncate and close
authorEtienne AUJAMES <etienne.aujames@cea.fr>
Wed, 18 Jan 2023 09:42:54 +0000 (10:42 +0100)
committerAndreas Dilger <adilger@whamcloud.com>
Tue, 25 Apr 2023 03:36:10 +0000 (03:36 +0000)
LSOM is updated on close and setattr request.
For the setattr, clients do not know the numbers blocks yet (OSTs
setattr requests have to finish). So the blocks number is set to 1 by
the server.

The close request send after a ftruncate() will wrongly update LSOM
back to its old blocks number. This is because clients do not update
the inode.i_blocks after an OST setattr.

Then the MDS will denied a client close request to update LSOM to its
correct blocks number. Only truncates are allowed to decrease the
blocks number (server side).

This patch force the client inode update at the end of an OST setattr.
And it tries (if no contention on the inode_size) to update the inode
at the end of an OST fsync or a sync IO.

Update sanity test 806/807 for this use case.

Lustre-change: https://review.whamcloud.com/49675
Lustre-commit: dfb08bbf77a1362f79c3738cc3952f8db2e46511

Test-Parameters: testlist=sanity env=ONLY=806,807,ONLY_REPEAT=20
Test-Parameters: fstype=zfs testlist=sanity-flr env=ONLY=70,ONLY_REPEAT=10
Signed-off-by: Etienne AUJAMES <eaujames@ddn.com>
Signed-off-by: Xing Huang <hxing@ddn.com>
Change-Id: Ib1afde97071ebae56f0b413ec444403c3cdebd02
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Qian Yingjin <qian@ddn.com>
Reviewed-on: https://review.whamcloud.com/c/ex/lustre-release/+/50611
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
lustre/llite/file.c
lustre/llite/llite_internal.h
lustre/llite/llite_lib.c
lustre/llite/vvp_io.c
lustre/tests/sanity.sh

index 6022548..94d9919 100644 (file)
@@ -1434,7 +1434,7 @@ out:
        return rc;
 }
 
-int ll_merge_attr(const struct lu_env *env, struct inode *inode)
+static int ll_merge_attr_nolock(const struct lu_env *env, struct inode *inode)
 {
        struct ll_inode_info *lli = ll_i2info(inode);
        struct cl_object *obj = lli->lli_clob;
@@ -1446,8 +1446,6 @@ int ll_merge_attr(const struct lu_env *env, struct inode *inode)
 
        ENTRY;
 
-       ll_inode_size_lock(inode);
-
        /* Merge timestamps the most recently obtained from MDS with
         * timestamps obtained from OSTs.
         *
@@ -1479,7 +1477,7 @@ int ll_merge_attr(const struct lu_env *env, struct inode *inode)
        cl_object_attr_unlock(obj);
 
        if (rc != 0)
-               GOTO(out_size_unlock, rc = (rc == -ENODATA ? 0 : rc));
+               GOTO(out, rc = (rc == -ENODATA ? 0 : rc));
 
        if (atime < attr->cat_atime)
                atime = attr->cat_atime;
@@ -1490,8 +1488,8 @@ int ll_merge_attr(const struct lu_env *env, struct inode *inode)
        if (mtime < attr->cat_mtime)
                mtime = attr->cat_mtime;
 
-       CDEBUG(D_VFSTRACE, DFID" updating i_size %llu\n",
-              PFID(&lli->lli_fid), attr->cat_size);
+       CDEBUG(D_VFSTRACE, DFID" updating i_size %llu i_blocks %llu\n",
+              PFID(&lli->lli_fid), attr->cat_size, attr->cat_blocks);
 
        if (ll_require_key(inode) == -ENOKEY) {
                /* Without the key, round up encrypted file size to next
@@ -1510,10 +1508,33 @@ int ll_merge_attr(const struct lu_env *env, struct inode *inode)
        inode->i_atime.tv_sec = atime;
        inode->i_ctime.tv_sec = ctime;
 
-out_size_unlock:
+       EXIT;
+out:
+       return rc;
+}
+
+int ll_merge_attr(const struct lu_env *env, struct inode *inode)
+{
+       int rc;
+
+       ll_inode_size_lock(inode);
+       rc = ll_merge_attr_nolock(env, inode);
        ll_inode_size_unlock(inode);
 
-       RETURN(rc);
+       return rc;
+}
+
+/* Use to update size and blocks on inode for LSOM if there is no contention */
+int ll_merge_attr_try(const struct lu_env *env, struct inode *inode)
+{
+       int rc = 0;
+
+       if (ll_inode_size_trylock(inode)) {
+               rc = ll_merge_attr_nolock(env, inode);
+               ll_inode_size_unlock(inode);
+       }
+
+       return rc;
 }
 
 /**
index 0244858..402b592 100644 (file)
@@ -577,6 +577,7 @@ static inline void obd_connect_set_name_enc(struct obd_connect_data *data)
 
 void ll_inode_size_lock(struct inode *inode);
 void ll_inode_size_unlock(struct inode *inode);
+int ll_inode_size_trylock(struct inode *inode);
 
 static inline struct ll_inode_info *ll_i2info(struct inode *inode)
 {
@@ -1297,6 +1298,7 @@ int ll_dir_getstripe(struct inode *inode, void **plmm, int *plmm_size,
                     struct ptlrpc_request **request, u64 valid);
 int ll_fsync(struct file *file, loff_t start, loff_t end, int data);
 int ll_merge_attr(const struct lu_env *env, struct inode *inode);
+int ll_merge_attr_try(const struct lu_env *env, struct inode *inode);
 int ll_fid2path(struct inode *inode, void __user *arg);
 int ll_data_version(struct inode *inode, __u64 *data_version, int flags);
 int ll_hsm_release(struct inode *inode);
index b2538e4..0b7a77a 100644 (file)
@@ -2534,6 +2534,16 @@ void ll_inode_size_unlock(struct inode *inode)
        mutex_unlock(&lli->lli_size_mutex);
 }
 
+int ll_inode_size_trylock(struct inode *inode)
+{
+       struct ll_inode_info *lli;
+
+       LASSERT(!S_ISDIR(inode->i_mode));
+
+       lli = ll_i2info(inode);
+       return mutex_trylock(&lli->lli_size_mutex);
+}
+
 void ll_update_inode_flags(struct inode *inode, int ext_flags)
 {
        /* do not clear encryption flag */
index ac96aee..7f99675 100644 (file)
@@ -783,6 +783,10 @@ static void vvp_io_setattr_end(const struct lu_env *env,
                vvp_do_vmtruncate(inode, io->u.ci_setattr.sa_attr.lvb_size);
                mutex_unlock(&lli->lli_setattr_mutex);
                trunc_sem_up_write(&lli->lli_trunc_sem);
+
+               /* Update size and blocks for LSOM */
+               if (!io->ci_ignore_layout)
+                       ll_merge_attr(env, inode);
        } else if (cl_io_is_fallocate(io)) {
                mutex_unlock(&lli->lli_setattr_mutex);
                trunc_sem_up_write(&lli->lli_trunc_sem);
@@ -1393,6 +1397,20 @@ static void vvp_io_rw_end(const struct lu_env *env,
        trunc_sem_up_read(&lli->lli_trunc_sem);
 }
 
+static void vvp_io_write_end(const struct lu_env *env,
+                            const struct cl_io_slice *ios)
+{
+       struct inode *inode = vvp_object_inode(ios->cis_obj);
+       struct cl_io *io = ios->cis_io;
+
+       vvp_io_rw_end(env, ios);
+
+       /* Update size and blocks for LSOM (best effort) */
+       if (!io->ci_ignore_layout && cl_io_is_sync_write(io))
+               ll_merge_attr_try(env, inode);
+}
+
+
 static int vvp_io_kernel_fault(struct vvp_fault_io *cfio)
 {
        struct vm_fault *vmf = cfio->ft_vmf;
@@ -1653,6 +1671,17 @@ static int vvp_io_fsync_start(const struct lu_env *env,
        return 0;
 }
 
+static void vvp_io_fsync_end(const struct lu_env *env,
+                            const struct cl_io_slice *ios)
+{
+       struct inode *inode = vvp_object_inode(ios->cis_obj);
+       struct cl_io *io = ios->cis_io;
+
+       /* Update size and blocks for LSOM (best effort) */
+       if (!io->ci_ignore_layout)
+               ll_merge_attr_try(env, inode);
+}
+
 static int vvp_io_read_ahead(const struct lu_env *env,
                             const struct cl_io_slice *ios,
                             pgoff_t start, struct cl_read_ahead *ra)
@@ -1734,7 +1763,7 @@ static const struct cl_io_operations vvp_io_ops = {
                        .cio_iter_fini = vvp_io_write_iter_fini,
                        .cio_lock      = vvp_io_write_lock,
                        .cio_start     = vvp_io_write_start,
-                       .cio_end       = vvp_io_rw_end,
+                       .cio_end       = vvp_io_write_end,
                        .cio_advance   = vvp_io_advance,
                 },
                 [CIT_SETATTR] = {
@@ -1753,7 +1782,8 @@ static const struct cl_io_operations vvp_io_ops = {
                 },
                [CIT_FSYNC] = {
                        .cio_start      = vvp_io_fsync_start,
-                       .cio_fini       = vvp_io_fini
+                       .cio_fini       = vvp_io_fini,
+                       .cio_end        = vvp_io_fsync_end,
                },
                [CIT_GLIMPSE] = {
                        .cio_fini       = vvp_io_fini
index 8219b62..05a9a30 100755 (executable)
@@ -27708,16 +27708,17 @@ check_lsom_size()
 }
 
 test_806() {
-       [ $MDS1_VERSION -lt $(version_code 2.11.52) ] &&
+       (( MDS1_VERSION >= $(version_code 2.11.52) )) ||
                skip "Need MDS version at least 2.11.52"
 
        local bs=1048576
 
-       touch $DIR/$tfile || error "touch $tfile failed"
+       $LFS setstripe -c-1 $DIR/$tfile || error "setstripe $tfile failed"
 
+       # Disable opencache
        local save="$TMP/$TESTSUITE-$TESTNAME.parameters"
-       save_lustre_params client "llite.*.xattr_cache" > $save
-       lctl set_param llite.*.xattr_cache=0
+       save_lustre_params client "llite.*.opencache_threshold_count" > $save
+       lctl set_param llite.*.opencache_threshold_count=0
        stack_trap "restore_lustre_params < $save; rm -f $save" EXIT
 
        # single-threaded write
@@ -27786,18 +27787,34 @@ test_806() {
        done
        check_lsom_size $DIR/$tfile $size
 
+       # 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
+
+       $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
+
+       $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
+
        # verify truncate
        echo "Test SOM for truncate"
-       $TRUNCATE $DIR/$tfile 1048576
-       check_lsom_size $DIR/$tfile 1048576
+       # 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
+
        $TRUNCATE $DIR/$tfile 1234
        check_lsom_size $DIR/$tfile 1234
-
-       # verify SOM blocks count
-       echo "Verify SOM block count"
-       $TRUNCATE $DIR/$tfile 0
-       $MULTIOP $DIR/$tfile oO_TRUNC:O_RDWR:w1048576YSc ||
-               error "failed to write file $tfile"
+       # sync blocks on the MDT
+       $MULTIOP $DIR/$tfile oc
        check_lsom_data $DIR/$tfile
 }
 run_test 806 "Verify Lazy Size on MDS"
@@ -27832,8 +27849,10 @@ verify_som_sync_utility() {
                error "truncate $tdir/trunc failed"
 
        local bs=1048576
-       dd if=/dev/zero of=$DIR/$tdir/single_dd bs=$bs count=1 conv=fsync ||
+       echo "Test SOM for single-threaded write with fsync"
+       dd if=/dev/zero of=$DIR/$tdir/single_dd bs=$bs count=1 ||
                error "write $tfile failed"
+       sync;sync;sync
 
        # multi-client wirtes
        local num=$(get_node_count ${CLIENTS//,/ })