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>
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;
ENTRY;
- ll_inode_size_lock(inode);
-
/* Merge timestamps the most recently obtained from MDS with
* timestamps obtained from OSTs.
*
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;
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
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;
}
/**
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)
{
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);
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 */
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;
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;
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)
.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] = {
},
[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
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
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"
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//,/ })