From 4c43d93016245b55ff6b3e1c8a245e5f5fff0e90 Mon Sep 17 00:00:00 2001 From: Bobi Jam Date: Fri, 2 Feb 2024 15:15:30 +0800 Subject: [PATCH] EX-8927 csdc: server reject FIEMAP/SEEK_HOLE|DATA on compr obj Server return -EOPNOTSUPP if they get the FIEMAP and SEEK_HOLE/SEEK_DATA requests upon compressed file objects. Signed-off-by: Bobi Jam Change-Id: I9f04fbb13a22cc83402d9989daab63a59367ff33 Reviewed-on: https://review.whamcloud.com/c/ex/lustre-release/+/53886 Tested-by: jenkins Tested-by: Andreas Dilger Reviewed-by: Sebastien Buisson Reviewed-by: Andreas Dilger --- lustre/include/obd_support.h | 1 + lustre/include/uapi/linux/lustre/lustre_user.h | 7 +++++ lustre/lov/lov_io.c | 3 +- lustre/lov/lov_object.c | 3 +- lustre/ofd/ofd_dev.c | 16 +++++++++-- lustre/ofd/ofd_internal.h | 7 ----- lustre/osd-ldiskfs/osd_handler.c | 4 +-- lustre/osd-ldiskfs/osd_internal.h | 3 ++ lustre/osd-ldiskfs/osd_io.c | 27 +++++++++++++++++ lustre/osd-zfs/osd_io.c | 26 +++++++++++++++++ lustre/tests/sanity.sh | 40 ++++++++++++++++++++++++++ 11 files changed, 123 insertions(+), 14 deletions(-) diff --git a/lustre/include/obd_support.h b/lustre/include/obd_support.h index 86ee3b6..3fa8521 100644 --- a/lustre/include/obd_support.h +++ b/lustre/include/obd_support.h @@ -638,6 +638,7 @@ extern char obd_jobid_var[]; #define OBD_FAIL_LOV_COMP_MAGIC 0x1426 #define OBD_FAIL_LOV_COMP_PATTERN 0x1427 #define OBD_FAIL_LOV_INVALID_OSTIDX 0x1428 +#define OBD_FAIL_LOV_SKIP_CHECK_COMPR 0x1429 #define OBD_FAIL_LLITE_DELAY_TRUNCATE 0x1430 #define OBD_FAIL_LLITE_READ_PAUSE 0x1431 diff --git a/lustre/include/uapi/linux/lustre/lustre_user.h b/lustre/include/uapi/linux/lustre/lustre_user.h index 70e7edb..8f8f94e 100644 --- a/lustre/include/uapi/linux/lustre/lustre_user.h +++ b/lustre/include/uapi/linux/lustre/lustre_user.h @@ -419,6 +419,13 @@ struct filter_fid { struct ost_layout_compr ff_layout_compr; } __attribute__((packed)); +/** + * for compatibility, filter_fid could occupy more space in newer version and + * downgraded Lustre would fail reading it with -ERANGE, so it can read it + * again with more space to hold it. + */ +#define FILTER_FID_EXTRA_SIZE 32 + /* Userspace should treat lu_fid as opaque, and only use the following methods * to print or parse them. Other functions (e.g. compare, swab) could be moved * here from lustre_idl.h if needed. */ diff --git a/lustre/lov/lov_io.c b/lustre/lov/lov_io.c index 18dbb36..2a0d91f 100644 --- a/lustre/lov/lov_io.c +++ b/lustre/lov/lov_io.c @@ -605,7 +605,8 @@ static int lov_io_slice_init(struct lov_io *lio, } case CIT_LSEEK: { - if (io->ci_compressed_file) + if (!OBD_FAIL_CHECK(OBD_FAIL_LOV_SKIP_CHECK_COMPR) && + io->ci_compressed_file) GOTO(out, result = -EOPNOTSUPP); lio->lis_pos = io->u.ci_lseek.ls_start; lio->lis_endpos = OBD_OBJECT_EOF; diff --git a/lustre/lov/lov_object.c b/lustre/lov/lov_object.c index 3d6952e..9188b40 100644 --- a/lustre/lov/lov_object.c +++ b/lustre/lov/lov_object.c @@ -2077,7 +2077,8 @@ static int lov_object_fiemap(const struct lu_env *env, struct cl_object *obj, lsme = lsm->lsm_entries[0]; /* No support for compressed yet. */ - if (lsme->lsme_compr_type != LL_COMPR_TYPE_NONE) + if (!OBD_FAIL_CHECK(OBD_FAIL_LOV_SKIP_CHECK_COMPR) && + lsme->lsme_compr_type != LL_COMPR_TYPE_NONE) GOTO(out_lsm, rc = -EOPNOTSUPP); if (!(fiemap->fm_flags & FIEMAP_FLAG_DEVICE_ORDER)) { diff --git a/lustre/ofd/ofd_dev.c b/lustre/ofd/ofd_dev.c index 7081caa..801eac8 100644 --- a/lustre/ofd/ofd_dev.c +++ b/lustre/ofd/ofd_dev.c @@ -961,10 +961,20 @@ int ofd_fiemap_get(const struct lu_env *env, struct ofd_device *ofd, } ofd_read_lock(env, fo); - if (ofd_object_exists(fo)) - rc = dt_fiemap_get(env, ofd_object_child(fo), fiemap); - else + if (!ofd_object_exists(fo)) { rc = -ENOENT; + goto out; + } + + rc = ofd_object_ff_load(env, fo); + if (rc == 0 && + fo->ofo_ff.ff_layout_compr.ol_compr_type != LL_COMPR_TYPE_NONE) { + rc = -EOPNOTSUPP; + goto out; + } + + rc = dt_fiemap_get(env, ofd_object_child(fo), fiemap); +out: ofd_read_unlock(env, fo); ofd_object_put(env, fo); return rc; diff --git a/lustre/ofd/ofd_internal.h b/lustre/ofd/ofd_internal.h index 53a47fb..075a0ce 100644 --- a/lustre/ofd/ofd_internal.h +++ b/lustre/ofd/ofd_internal.h @@ -181,13 +181,6 @@ static inline char *ofd_name(struct ofd_device *ofd) return ofd->ofd_dt_dev.dd_lu_dev.ld_obd->obd_name; } -/** - * for compatibility, filter_fid could occupy more space in newer version and - * downgraded Lustre would fail reading it with -ERANGE, so it can read it - * again with more space to hold it. - */ -#define FILTER_FID_EXTRA_SIZE 32 - struct ofd_object { struct lu_object_header ofo_header; struct dt_object ofo_obj; diff --git a/lustre/osd-ldiskfs/osd_handler.c b/lustre/osd-ldiskfs/osd_handler.c index 0902890..197baf1 100644 --- a/lustre/osd-ldiskfs/osd_handler.c +++ b/lustre/osd-ldiskfs/osd_handler.c @@ -4681,8 +4681,8 @@ static int osd_ref_del(const struct lu_env *env, struct dt_object *dt, /* * Concurrency: @dt is read locked. */ -static int osd_xattr_get(const struct lu_env *env, struct dt_object *dt, - struct lu_buf *buf, const char *name) +int osd_xattr_get(const struct lu_env *env, struct dt_object *dt, + struct lu_buf *buf, const char *name) { struct osd_object *obj = osd_dt_obj(dt); struct inode *inode = obj->oo_inode; diff --git a/lustre/osd-ldiskfs/osd_internal.h b/lustre/osd-ldiskfs/osd_internal.h index ead0ecd..e7640a0 100644 --- a/lustre/osd-ldiskfs/osd_internal.h +++ b/lustre/osd-ldiskfs/osd_internal.h @@ -812,6 +812,9 @@ extern int ldiskfs_pdo; #define DECLARE_BVEC_ITER_ALL(iter) int iter #endif +int osd_xattr_get(const struct lu_env *env, struct dt_object *dt, + struct lu_buf *buf, const char *name); + static inline int __osd_xattr_get(struct inode *inode, struct dentry *dentry, const char *name, void *buf, int len) { diff --git a/lustre/osd-ldiskfs/osd_io.c b/lustre/osd-ldiskfs/osd_io.c index bbcc2e0..837ab29 100644 --- a/lustre/osd-ldiskfs/osd_io.c +++ b/lustre/osd-ldiskfs/osd_io.c @@ -2765,11 +2765,13 @@ static int osd_ladvise(const struct lu_env *env, struct dt_object *dt, static loff_t osd_lseek(const struct lu_env *env, struct dt_object *dt, loff_t offset, int whence) { + struct osd_thread_info *oti = osd_oti_get(env); struct osd_object *obj = osd_dt_obj(dt); struct osd_device *dev = osd_obj2dev(obj); struct inode *inode = obj->oo_inode; struct file *file; loff_t result; + int rc; ENTRY; LASSERT(dt_object_exists(dt)); @@ -2777,6 +2779,31 @@ static loff_t osd_lseek(const struct lu_env *env, struct dt_object *dt, LASSERT(inode); LASSERT(offset >= 0); + /* check whether it's a compressed object */ + oti->oti_buf.lb_buf = &oti->oti_ff; + oti->oti_buf.lb_len = sizeof(oti->oti_ff); + rc = osd_xattr_get(env, dt, &oti->oti_buf, XATTR_NAME_FID); + if (rc == -ERANGE) { + struct filter_fid *ff_new; + + OBD_ALLOC(ff_new, sizeof(*ff_new) + FILTER_FID_EXTRA_SIZE); + if (!ff_new) + RETURN(-ENOMEM); + + oti->oti_buf.lb_buf = ff_new; + oti->oti_buf.lb_len = sizeof(*ff_new) + FILTER_FID_EXTRA_SIZE; + rc = osd_xattr_get(env, dt, &oti->oti_buf, XATTR_NAME_FID); + if (rc > 0) + memcpy(&oti->oti_ff, ff_new, sizeof(oti->oti_ff)); + OBD_FREE(ff_new, sizeof(*ff_new) + FILTER_FID_EXTRA_SIZE); + } + if (rc > 0) { + filter_fid_le_to_cpu(&oti->oti_ff, &oti->oti_ff, rc); + if (oti->oti_ff.ff_layout_compr.ol_compr_type != + LL_COMPR_TYPE_NONE) + RETURN(-EOPNOTSUPP); + } + file = alloc_file_pseudo(inode, dev->od_mnt, "/", O_NOATIME, inode->i_fop); if (IS_ERR(file)) diff --git a/lustre/osd-zfs/osd_io.c b/lustre/osd-zfs/osd_io.c index be48b92..bdf6a60 100644 --- a/lustre/osd-zfs/osd_io.c +++ b/lustre/osd-zfs/osd_io.c @@ -1197,6 +1197,8 @@ static loff_t osd_lseek(const struct lu_env *env, struct dt_object *dt, struct osd_object *obj = osd_dt_obj(dt); uint64_t size = obj->oo_attr.la_size; uint64_t result = offset; + struct lu_buf buf; + struct filter_fid ff; int rc; boolean_t hole = whence == SEEK_HOLE; @@ -1206,6 +1208,30 @@ static loff_t osd_lseek(const struct lu_env *env, struct dt_object *dt, LASSERT(osd_invariant(obj)); LASSERT(offset >= 0); + /* check whether it's a compressed object */ + buf.lb_buf = &ff; + buf.lb_len = sizeof(ff); + rc = osd_xattr_get(env, dt, &buf, XATTR_NAME_FID); + if (rc == -ERANGE) { + struct filter_fid *ff_new; + + OBD_ALLOC(ff_new, sizeof(*ff_new) + FILTER_FID_EXTRA_SIZE); + if (!ff_new) + RETURN(-ENOMEM); + + buf.lb_buf = ff_new; + buf.lb_len = sizeof(*ff_new) + FILTER_FID_EXTRA_SIZE; + rc = osd_xattr_get(env, dt, &buf, XATTR_NAME_FID); + if (rc > 0) + memcpy(&ff, ff_new, sizeof(ff)); + OBD_FREE(ff_new, sizeof(*ff_new) + FILTER_FID_EXTRA_SIZE); + } + if (rc > 0) { + filter_fid_le_to_cpu(&ff, &ff, rc); + if (ff.ff_layout_compr.ol_compr_type != LL_COMPR_TYPE_NONE) + RETURN(-EOPNOTSUPP); + } + /* for SEEK_HOLE treat 'offset' beyond the end of file as in real * hole. LOV to decide after all if that real hole or not. */ diff --git a/lustre/tests/sanity.sh b/lustre/tests/sanity.sh index d0dc227..0879100 100644 --- a/lustre/tests/sanity.sh +++ b/lustre/tests/sanity.sh @@ -28741,6 +28741,46 @@ test_460f() { } run_test 460f "verify hole/data lseek is disabled for compressed files" +test_460g() { + (( MDS1_VERSION >= $(version_code 2.14.0.134) )) || + skip "Need MDS version at least 2.14.0.134" + + local tf=$DIR/$tfile + + stack_trap "rm -f $tf; disable_compression" + enable_compression + + $LFS setstripe -E -1 -Z gzip:3 --compress-chunk=64 $tf || + error "set a compress component in $tf failed" + + dd if=/dev/zero of=$tf bs=32k count=2 || error "first dd failed" + dd if=/dev/urandom of=$tf bs=32k count=1 seek=3 || + error "second dd failed" + sync; echo 3 > /proc/sys/vm/drop_caches + + $LFS getstripe $tf | grep lcme_flags.*compress || + error "no compressed component" + + # skip the compression check from LOV, and prevent fiemap/lseek + # upon compressed file in OFD + #define OBD_FAIL_LOV_SKIP_CHECK_COMPR 0x1429 + $LCTL set_param fail_loc=0x1429 + + printf "Seeking hole from 0 ... " + offset=$(lseek_test -l 0 $tf) || error "hole lseek failed" + echo $offset + [[ $offset == 131072 ]] || error "offset $offset != 131072" + printf "Seeking data from $offset ... " + lseek_test -d $offset $tf && error "data lseek should fail" + + checkfiemap --test || + skip "checkfiemap not runnable: $?" + checkfiemap $tf 131072 && error "fiemap should fail" + + return 0 +} +run_test 460g "verify hole/data lseek or fiemap is disabled for compressed files on server" + prep_801() { [[ $MDS1_VERSION -lt $(version_code 2.9.55) ]] || [[ $OST1_VERSION -lt $(version_code 2.9.55) ]] && -- 1.8.3.1