Whamcloud - gitweb
LU-16465 llite: fix LSOM blocks for ftruncate and close 75/49675/8
authorEtienne AUJAMES <etienne.aujames@cea.fr>
Wed, 18 Jan 2023 09:42:54 +0000 (10:42 +0100)
committerOleg Drokin <green@whamcloud.com>
Tue, 11 Apr 2023 20:08:27 +0000 (20:08 +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.

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>
Change-Id: Ib1afde97071ebae56f0b413ec444403c3cdebd02
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/49675
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Qian Yingjin <qian@ddn.com>
Reviewed-by: Oleg Drokin <green@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 9f83b2b..c672b2b 100644 (file)
@@ -1421,7 +1421,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;
@@ -1433,8 +1433,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.
         *
@@ -1466,7 +1464,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;
@@ -1477,8 +1475,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 (llcrypt_require_key(inode) == -ENOKEY) {
                /* Without the key, round up encrypted file size to next
@@ -1497,10 +1495,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 b0e7a31..bb36cee 100644 (file)
@@ -566,6 +566,7 @@ static inline void obd_connect_set_enc_fid2path(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)
 {
@@ -1257,6 +1258,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_fid2path(struct inode *inode, struct getinfo_fid2path *gfout,
                  size_t outsize, __u32 pathlen_orig);
index bf57742..f20efc4 100644 (file)
@@ -2664,6 +2664,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, unsigned int ext_flags)
 {
        /* do not clear encryption flag */
index 7fa452e..f3f803b 100644 (file)
@@ -778,6 +778,10 @@ static void vvp_io_setattr_end(const struct lu_env *env,
                vvp_do_vmtruncate(inode, 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)) {
                int mode = io->u.ci_setattr.sa_falloc_mode;
 
@@ -1398,6 +1402,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;
@@ -1644,6 +1662,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)
@@ -1725,7 +1754,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] = {
@@ -1744,7 +1773,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 9054cf8..96ec5be 100755 (executable)
@@ -28801,11 +28801,12 @@ test_806() {
 
        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
@@ -28874,18 +28875,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"
@@ -28909,8 +28926,10 @@ test_807() {
                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//,/ })