From 0be8bae577100f3c10c204a1ed786fe6f993b740 Mon Sep 17 00:00:00 2001 From: "John L. Hammond" Date: Mon, 21 Mar 2022 10:40:43 -0500 Subject: [PATCH] EX-4965 lipe: use new e2fsprogs xattr API in lipe_scan3 In lipe_scan3, switch to the ext2fs_xattr_handle API since this handles xattrs stored in a separate file. Update sanity-lipe-scan3 test_108() to verify. Test-Parameters: trivial testlist=sanity-lipe-find3 Test-Parameters: trivial testlist=sanity-lipe-scan3 Signed-off-by: John L. Hammond Change-Id: I307d78ba03c6612e5787f71a4682c0af5b23f1c5 Reviewed-on: https://review.whamcloud.com/46875 Tested-by: jenkins --- lipe/src/lipe_scan3/ls3_object_attrs.c | 29 +-- lipe/src/lipe_scan3/ls3_object_attrs.h | 9 +- lipe/src/lipe_scan3/ls3_scan.c | 347 ++++++++++++++++++++------------- lipe/src/lipe_scan3/ls3_scan.h | 1 + lustre/tests/sanity-lipe-scan3.sh | 9 + 5 files changed, 224 insertions(+), 171 deletions(-) diff --git a/lipe/src/lipe_scan3/ls3_object_attrs.c b/lipe/src/lipe_scan3/ls3_object_attrs.c index b3b4994..6d21b8a 100644 --- a/lipe/src/lipe_scan3/ls3_object_attrs.c +++ b/lipe/src/lipe_scan3/ls3_object_attrs.c @@ -530,34 +530,9 @@ static void lipe_object_attrs_xattrs_fini(struct ls3_object_attrs *attrs) assert(lipe_list_empty(&attrs->loa_xattrs)); } -void lipe_object_attrs_reset(struct ls3_object_attrs *loa) -{ - loa->loa_valid = 0; - loa->loa_nodata = 0; - loa->loa_error = 0; - loa->loa_ino = 0; - memset(&loa->loa_file_fid, 0, sizeof(loa->loa_file_fid)); - memset(&loa->loa_lma, 0, sizeof(loa->loa_lma)); - lipe_object_attrs_links_fini(loa); - lipe_object_attrs_paths_fini(loa); - lipe_object_attrs_xattrs_fini(loa); - llapi_layout_free(loa->loa_layout); - loa->loa_layout = NULL; -} - int lipe_object_attrs_init(struct ls3_object_attrs *loa) { memset(loa, 0, sizeof(*loa)); - loa->loa_lum_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, - LOV_USER_MAGIC_V3); - loa->loa_lum = xmalloc(loa->loa_lum_size); - - loa->loa_link_buf_size = XATTR_SIZE_MAX; - loa->loa_link_buf = xmalloc(loa->loa_link_buf_size); - - loa->loa_lmv_buf_size = XATTR_SIZE_MAX; - loa->loa_lmv_buf = xmalloc(loa->loa_lmv_buf_size); - LIPE_INIT_LIST_HEAD(&loa->loa_links); LIPE_INIT_LIST_HEAD(&loa->loa_paths); LIPE_INIT_LIST_HEAD(&loa->loa_xattrs); @@ -570,9 +545,7 @@ void lipe_object_attrs_fini(struct ls3_object_attrs *loa) lipe_object_attrs_links_fini(loa); lipe_object_attrs_paths_fini(loa); lipe_object_attrs_xattrs_fini(loa); - free(loa->loa_lum); - free(loa->loa_link_buf); - free(loa->loa_lmv_buf); + free(loa->loa_lmv); llapi_layout_free(loa->loa_layout); } diff --git a/lipe/src/lipe_scan3/ls3_object_attrs.h b/lipe/src/lipe_scan3/ls3_object_attrs.h index 7c87014..8edd54c 100644 --- a/lipe/src/lipe_scan3/ls3_object_attrs.h +++ b/lipe/src/lipe_scan3/ls3_object_attrs.h @@ -172,12 +172,8 @@ struct ls3_object_attrs { int64_t loa_projid; struct lu_fid loa_file_fid; struct lustre_mdt_attrs loa_lma; - void *loa_link_buf; - size_t loa_link_buf_size; - void *loa_lmv_buf; - size_t loa_lmv_buf_size; - struct lov_user_md *loa_lum; - int loa_lum_size; + void *loa_lmv; + size_t loa_lmv_size; struct llapi_layout *loa_layout; /* LS3_OBJECT_ATTR_LOV */ struct hsm_user_state loa_hsm_state; struct lustre_som_attrs loa_som; @@ -231,7 +227,6 @@ ls3_object_attrs_to_json(struct ls3_instance *li, int lipe_object_attrs_init(struct ls3_object_attrs *attrs); void lipe_object_attrs_fini(struct ls3_object_attrs *attrs); -void lipe_object_attrs_reset(struct ls3_object_attrs *attrs); int lipe_object_attrs_set_links(struct ls3_object_attrs *attrs, const void *link_xattr, size_t link_xattr_size); diff --git a/lipe/src/lipe_scan3/ls3_scan.c b/lipe/src/lipe_scan3/ls3_scan.c index f20ed6d..8b9f13d 100644 --- a/lipe/src/lipe_scan3/ls3_scan.c +++ b/lipe/src/lipe_scan3/ls3_scan.c @@ -90,39 +90,50 @@ const char LS3_CSTR_NONE[] = "NONE"; static bool xattr_name_not_found(long errcode) { - return errcode == EXT2_ET_EA_NAME_NOT_FOUND || + return errcode == EXT2_ET_EA_KEY_NOT_FOUND || + errcode == EXT2_ET_EA_NAME_NOT_FOUND || errcode == EXT2_ET_EA_NAME_NOT_FOUND_1445WC1 || errcode == EXT2_ET_EA_NAME_NOT_FOUND_1456WC1 || errcode == EXT2_ET_EA_NAME_NOT_FOUND_1456WC3 || errcode == EXT2_ET_EA_NAME_NOT_FOUND_1462WC3; } -static int ldiskfs_trusted_xattr_get(struct lipe_object *lo, - const char *name, - void *buf, size_t buf_size, - int *value_size) +static int ls3_xattr_get(struct lipe_object *lo, const char *name, void **value, size_t *value_size) { ext2_filsys fs = lo->u.lo_ldiskfs.lol_fs; struct ext2_inode_large *inode = lo->u.lo_ldiskfs.lol_inode; + struct ext2_xattr_handle *handle = NULL; errcode_t rc; - rc = ext2fs_attr_get(fs, (struct ext2_inode *)inode, - EXT2_ATTR_INDEX_TRUSTED, - name + strlen("trusted."), - buf, buf_size, value_size); + if (lo->u.lo_ldiskfs.lol_xattr_handle == NULL) { + rc = ext2fs_xattrs_open(fs, lo_ino(lo), &handle); + if (rc != 0) + goto out; + + rc = ext2fs_xattrs_read_inode(handle, inode); + if (rc != 0) + goto out; + + lo->u.lo_ldiskfs.lol_xattr_handle = handle; + handle = NULL; /* lo owns it now. */ + } + + rc = ext2fs_xattr_get(lo->u.lo_ldiskfs.lol_xattr_handle, name, value, value_size); +out: if (xattr_name_not_found(rc)) { - return -ENODATA; - } else if (rc) { + rc = -ENODATA; + } else if (rc != 0) { /* EXT2_ET_EA_TOO_BIG, what else? */ LS3_ERROR_OBJ(lo, "cannot get '%s' xattr: rc = %ld (%s)\n", name, rc, error_message(rc)); - return -EINVAL; + rc = -EINVAL; } - assert(0 <= *value_size && *value_size <= buf_size); + if (handle != NULL) + ext2fs_xattrs_close(&handle); - return 0; + return rc; } static int @@ -130,21 +141,29 @@ ldiskfs_read_attr_self_fid(struct ls3_instance *li, struct lipe_object *lo, struct ls3_object_attrs *loa) { - const struct lustre_mdt_attrs *lma; - char buf[XATTR_SIZE_MAX]; - int size; + const char *name = XATTR_NAME_LMA; + struct lustre_mdt_attrs *lma; + void *value = NULL; + size_t value_size = 0; int rc; - rc = ldiskfs_trusted_xattr_get(lo, XATTR_NAME_LMA, buf, sizeof(buf), &size); - if (rc < 0) - return rc; + rc = ls3_xattr_get(lo, name, &value, &value_size); + if (rc != 0) + goto out; + + if (value_size < sizeof(*lma)) { + rc = -EINVAL; + goto out; + } - lma = (const struct lustre_mdt_attrs *)buf; + lma = value; fid_le_to_cpu(&loa->loa_lma.lma_self_fid, &lma->lma_self_fid); loa->loa_lma.lma_compat = ext2fs_le32_to_cpu(lma->lma_compat); loa->loa_lma.lma_incompat = ext2fs_le32_to_cpu(lma->lma_incompat); +out: + free(value); - return 0; + return rc; } static int @@ -152,20 +171,31 @@ ldiskfs_read_attr_filter_fid(struct ls3_instance *li, struct lipe_object *lo, struct ls3_object_attrs *loa) { - struct filter_fid *ff = &loa->loa_filter_fid; - struct lu_fid pfid; - int size; + const char *name = XATTR_NAME_FID; + void *value = NULL; + size_t value_size = 0; int rc; + struct filter_fid *ff = &loa->loa_filter_fid; - rc = ldiskfs_trusted_xattr_get(lo, XATTR_NAME_FID, ff, sizeof(*ff), &size); - if (rc < 0) - return rc; + rc = ls3_xattr_get(lo, name, &value, &value_size); + if (rc != 0) + goto out; - fid_le_to_cpu(&pfid, &ff->ff_parent); - ff->ff_parent = pfid; - loa->loa_filter_fid_size = size; + if (value_size < sizeof(ff->ff_parent)) { + rc = -EINVAL; + goto out; + } - return 0; + memset(ff, 0, sizeof(&ff)); + memcpy(ff, value, min(sizeof(*ff), value_size)); + fid_le_to_cpu(&ff->ff_parent, &ff->ff_parent); + /* ...? */ + + loa->loa_filter_fid_size = value_size; +out: + free(value); + + return rc; } static int @@ -202,7 +232,9 @@ ldiskfs_read_attr_links(struct ls3_instance *li, struct lipe_object *lo, struct ls3_object_attrs *loa) { - int size; + const char *name = XATTR_NAME_LINK; + void *value = NULL; + size_t value_size = 0; int rc; assert(lipe_list_empty(&loa->loa_links)); @@ -218,21 +250,23 @@ ldiskfs_read_attr_links(struct ls3_instance *li, if (loa->loa_lma.lma_incompat & LMAI_ORPHAN) { /* Then no links and loa_links is empty so good. */ - goto out_ok; + rc = 0; + goto out; } - rc = ldiskfs_trusted_xattr_get(lo, XATTR_NAME_LINK, - loa->loa_link_buf, loa->loa_link_buf_size, &size); - if (rc < 0) - return rc; + rc = ls3_xattr_get(lo, name, &value, &value_size); + if (rc != 0) + goto out; - rc = lipe_object_attrs_set_links(loa, loa->loa_link_buf, size); - if (rc) { - LS3_ERROR_OBJ(lo, "cannot decode link xattr: rc = %d\n", rc); - return rc; + rc = lipe_object_attrs_set_links(loa, value, value_size); + if (rc != 0) { + LS3_DEBUG_OBJ(lo, "cannot decode '%s' xattr, ignoring: rc = %d\n", name, rc); + goto out; } -out_ok: - return 0; +out: + free(value); + + return rc; } static char *xsprintf(const char *fmt, ...) @@ -353,22 +387,27 @@ static int ldiskfs_read_attr_lov(struct ls3_instance *li, struct lipe_object *lo, struct ls3_object_attrs *loa) { - struct lov_user_md *lum = loa->loa_lum; - int size; + const char *name = XATTR_NAME_LOV; + void *value = NULL; + size_t value_size = 0; int rc; - rc = ldiskfs_trusted_xattr_get(lo, XATTR_NAME_LOV, lum, loa->loa_lum_size, &size); - if (rc < 0) + rc = ls3_xattr_get(lo, name, &value, &value_size); + if (rc != 0) goto out; - loa->loa_layout = llapi_layout_get_by_xattr(lum, size, 0); + loa->loa_layout = llapi_layout_get_by_xattr(value, value_size, 0); if (loa->loa_layout == NULL) { LS3_ERROR_OBJ(lo, "cannot decode '%s' xattr: rc = %d\n", - XATTR_NAME_LOV, rc); + name, rc); rc = -errno; goto out; } + + rc = 0; out: + free(value); + return rc; } @@ -376,17 +415,25 @@ static int ldiskfs_read_attr_lmv(struct ls3_instance *li, struct lipe_object *lo, struct ls3_object_attrs *loa) { - int size; + const char *name = XATTR_NAME_LMV; + void *value = NULL; + size_t value_size = 0; int rc; - rc = ldiskfs_trusted_xattr_get(lo, XATTR_NAME_LMV, - loa->loa_lmv_buf, loa->loa_lmv_buf_size, &size); - if (rc < 0) - return rc; + rc = ls3_xattr_get(lo, name, &value, &value_size); + if (rc != 0) + goto out; + + loa->loa_lmv = value; + loa->loa_lmv_size = value_size; + value = NULL; + value_size = 0; /* TODO Store and check size. */ +out: + free(value); - return 0; + return rc; } static bool lo_is_dir_stripe(struct ls3_instance *li, @@ -400,7 +447,9 @@ static bool lo_is_dir_stripe(struct ls3_instance *li, if (rc != 0 && rc != -ENOTSUP) return false; - lmm = (union lmv_mds_md *)loa->loa_lmv_buf; + lmm = (union lmv_mds_md *)loa->loa_lmv; + if (loa->loa_lmv_size < sizeof(lmm->lmv_magic)) + return false; return lmm->lmv_magic == LMV_MAGIC_STRIPE; } @@ -409,46 +458,60 @@ static int ldiskfs_read_attr_hsm(struct ls3_instance *li, struct lipe_object *lo, struct ls3_object_attrs *loa) { - struct hsm_user_state *hus = &loa->loa_hsm_state; - char buf[XATTR_SIZE_MAX]; - struct hsm_attrs *hsm; - int size; + const char *name = XATTR_NAME_HSM; + void *value = NULL; + size_t value_size = 0; int rc; + struct hsm_user_state *hus = &loa->loa_hsm_state; + const struct hsm_attrs *hsm; - assert(sizeof(*hsm) < XATTR_SIZE_MAX); + memset(hus, 0, sizeof(*hus)); - rc = ldiskfs_trusted_xattr_get(lo, XATTR_NAME_HSM, buf, sizeof(buf), &size); - if (rc < 0) - return rc; + rc = ls3_xattr_get(lo, name, &value, &value_size); + if (rc != 0) + goto out; - hsm = (struct hsm_attrs *)buf; + if (value_size < sizeof(*hsm)) { + LS3_DEBUG_OBJ(lo, "xattr '%s': got size %zu, expected %zu\n", + name, value_size, sizeof(*hsm)); + rc = -ENODATA; + goto out; + } + + hsm = value; hus->hus_states = ext2fs_le32_to_cpu(hsm->hsm_flags); hus->hus_archive_id = ext2fs_le64_to_cpu(hsm->hsm_arch_id); +out: + free(value); - return 0; + return rc; } static int ldiskfs_read_attr_som(struct ls3_instance *li, struct lipe_object *lo, struct ls3_object_attrs *loa) { - struct lustre_som_attrs *som = &loa->loa_som; - int size; + const char *name = XATTR_NAME_SOM; + void *value = NULL; + size_t value_size = 0; int rc; + const struct lustre_som_attrs *som; - rc = ldiskfs_trusted_xattr_get(lo, XATTR_NAME_SOM, som, sizeof(*som), &size); - if (rc < 0) - return rc; + rc = ls3_xattr_get(lo, name, &value, &value_size); + if (rc != 0) + goto out; - if (size != sizeof(*som)) { - LS3_ERROR_OBJ(lo, "unexpected size of '%s' xattr, expected %zu, got %d\n", - XATTR_NAME_SOM, sizeof(*som), size); - return -ENODATA; + if (value_size < sizeof(*som)) { + LS3_ERROR_OBJ(lo, "xattr '%s': got size %zu, expected %zu\n", + name, value_size, sizeof(*som)); + rc = -ENODATA; + goto out; } - som->lsa_valid = ext2fs_le16_to_cpu(som->lsa_valid); - som->lsa_size = ext2fs_le64_to_cpu(som->lsa_size); - som->lsa_blocks = ext2fs_le64_to_cpu(som->lsa_blocks); + som = value; + loa->loa_som.lsa_valid = ext2fs_le16_to_cpu(som->lsa_valid); + loa->loa_som.lsa_size = ext2fs_le64_to_cpu(som->lsa_size); + loa->loa_som.lsa_blocks = ext2fs_le64_to_cpu(som->lsa_blocks); switch (loa->loa_som.lsa_valid) { case SOM_FL_STRICT: @@ -460,8 +523,10 @@ static int ldiskfs_read_attr_som(struct ls3_instance *li, rc = -ENOTSUP; break; } +out: + free(value); - return 0; + return rc; } static int ldiskfs_read_attr_size(struct ls3_instance *li, @@ -605,7 +670,7 @@ static bool ldiskfs_scan_get_next_group_batch(struct ls3_scan_control *sc, * * The similar function in E2fsprogs has a bug LU-13103 */ -static blkcnt_t blocks_from_inode(ext2_filsys fs, struct ext2_inode_large *inode) +static blkcnt_t blocks_from_inode(ext2_filsys fs, const struct ext2_inode_large *inode) { blkcnt_t b; @@ -629,10 +694,10 @@ __s64 inode_time(__u32 xtime, __u32 xtime_extra) return time; } -static void ldiskfs_copy_inode_attrs(ext2_filsys fs, - struct ls3_object_attrs *loa, - ext2_ino_t ino, - struct ext2_inode_large *inode) +static void ls3_copy_inode_attrs(struct ls3_object_attrs *loa, + ext2_filsys fs, + ext2_ino_t ino, + const struct ext2_inode_large *inode) { loa->loa_ino = ino; loa->loa_atime = inode_time(inode->i_atime, inode->i_atime_extra); @@ -651,14 +716,70 @@ static void ldiskfs_copy_inode_attrs(ext2_filsys fs, loa->loa_valid = LS3_OBJECT_ATTR_BASE | LS3_OBJECT_ATTR_PROJID; } +static void ls3_scan_inode(struct ls3_instance *li, + ext2_filsys fs, + ext2_ino_t ino, + struct ext2_inode_large *inode) +{ + struct lipe_object lo = { + .u.lo_ldiskfs.lol_fs = fs, + .u.lo_ldiskfs.lol_ino = ino, + .u.lo_ldiskfs.lol_inode = inode, + }; + struct ls3_object_attrs loa; + int rc; + + lipe_object_attrs_init(&loa); + ls3_copy_inode_attrs(&loa, fs, ino, inode); + + rc = ls3_read_attrs(li, &lo, &loa, li->li_required_attrs, + true /* quit on error. */); + if (rc != 0) { + LS3_DEBUG_OBJ(&lo, "missing required attrs %#"PRIxMAX", have " + "valid %#"PRIxMAX", " + "nodata %#"PRIxMAX", " + "error %#"PRIxMAX"\n", + (uintmax_t)(li->li_required_attrs & ~loa.loa_valid), + (uintmax_t)(loa.loa_valid), + (uintmax_t)(loa.loa_nodata), + (uintmax_t)(loa.loa_error)); + goto out; + } + + assert((loa.loa_valid & li->li_required_attrs) == li->li_required_attrs); + + /* Requiring fid_is_norm() prevents us from returning ROOT, + * .lustre, .lustre/fid, etc. It also prevents crashes when we + * try to access objects by or using fid2path. */ + + if ((li->li_required_attrs & LS3_OBJECT_ATTR_SELF_FID) && + !fid_is_norm(loa_self_fid(&loa)) && !fid_is_idif(loa_self_fid(&loa))) + goto out; + + if (lo_is_dir_stripe(li, &lo, &loa)) + goto out; + + LS3_CURRENT.lc_object = &lo; + LS3_CURRENT.lc_attrs = &loa; + + scm_catch(SCM_BOOL_T, li->li_scm_policy_thunk, ls3_scm_policy_exception_handler); + + LS3_CURRENT.lc_object = NULL; + LS3_CURRENT.lc_attrs = NULL; +out: + if (lo.u.lo_ldiskfs.lol_xattr_handle != NULL) + ext2fs_xattrs_close(&lo.u.lo_ldiskfs.lol_xattr_handle); + + lipe_object_attrs_fini(&loa); +} + static int ldiskfs_scan_groups(ext2_inode_scan scan, ext2_filsys fs, - struct ls3_object_attrs *loa, - struct lipe_object *lo, struct ext2_inode_large *inode, int inode_size, struct ls3_thread_info *ti) { struct ls3_instance *li; + ext2_ino_t ino; errcode_t rc; li = ti->ti_instance; @@ -672,13 +793,9 @@ static int ldiskfs_scan_groups(ext2_inode_scan scan, goto out; } - while (!ext2fs_get_next_inode_full(scan, &lo->u.lo_ldiskfs.lol_ino, + while (!ext2fs_get_next_inode_full(scan, &ino, (struct ext2_inode *)inode, inode_size)) { - ext2_ino_t ino; - int rc2; - - ino = lo->u.lo_ldiskfs.lol_ino; if (ino == 0) break; @@ -703,44 +820,7 @@ static int ldiskfs_scan_groups(ext2_inode_scan scan, continue; } - lipe_object_attrs_reset(loa); - ldiskfs_copy_inode_attrs(fs, loa, ino, inode); - - rc2 = ls3_read_attrs(li, lo, loa, li->li_required_attrs, - true /* quit on error. */); - if (rc2 != 0) { - LS3_DEBUG_OBJ(lo, "missing required attrs %#"PRIxMAX", have " - "valid %#"PRIxMAX", " - "nodata %#"PRIxMAX", " - "error %#"PRIxMAX"\n", - (uintmax_t)(li->li_required_attrs & ~loa->loa_valid), - (uintmax_t)(loa->loa_valid), - (uintmax_t)(loa->loa_nodata), - (uintmax_t)(loa->loa_error)); - continue; - } - - assert((loa->loa_valid & li->li_required_attrs) == - li->li_required_attrs); - - /* Requiring fid_is_norm() prevents us from returning - * ROOT, .lustre, .lustre/fid, etc. It also prevents - * crashes when we try to access objects by or using - * fid2path. */ - if ((li->li_required_attrs & LS3_OBJECT_ATTR_SELF_FID) && - !fid_is_norm(loa_self_fid(loa)) && !fid_is_idif(loa_self_fid(loa))) - continue; - - if (lo_is_dir_stripe(li, lo, loa)) - continue; - - LS3_CURRENT.lc_object = lo; - LS3_CURRENT.lc_attrs = loa; - - scm_catch(SCM_BOOL_T, li->li_scm_policy_thunk, ls3_scm_policy_exception_handler); - - LS3_CURRENT.lc_object = NULL; - LS3_CURRENT.lc_attrs = NULL; + ls3_scan_inode(li, fs, ino, inode); } rc = 0; @@ -767,8 +847,6 @@ static void *ls3_scan_thread_start_scm(void *arg) ext2_filsys fs = NULL; ext2_inode_scan scan = NULL; struct ext2_inode_large *inode = NULL; - struct lipe_object lo = { - }; struct ls3_object_attrs loa; int inode_size; intptr_t rc; @@ -799,8 +877,6 @@ static void *ls3_scan_thread_start_scm(void *arg) goto out_free_attrs; } - lo.u.lo_ldiskfs.lol_fs = fs; - rc = ext2fs_read_inode_bitmap(fs); if (rc) { LS3_ERROR("cannot read inode bitmap from '%s': %s\n", dev, @@ -820,7 +896,6 @@ static void *ls3_scan_thread_start_scm(void *arg) inode_size = sizeof(*inode); inode = xcalloc(1, inode_size); - lo.u.lo_ldiskfs.lol_inode = inode; while (!__atomic_load_n(&ti->ti_should_stop, __ATOMIC_RELAXED)) { bool found_batch; @@ -837,7 +912,7 @@ static void *ls3_scan_thread_start_scm(void *arg) ext2fs_set_inode_callback(scan, &ls3_done_group_callback, ti); - rc = ldiskfs_scan_groups(scan, fs, &loa, &lo, inode, inode_size, ti); + rc = ldiskfs_scan_groups(scan, fs, inode, inode_size, ti); if (rc != 0) goto out_free; diff --git a/lipe/src/lipe_scan3/ls3_scan.h b/lipe/src/lipe_scan3/ls3_scan.h index b32fe3a..ffaf611 100644 --- a/lipe/src/lipe_scan3/ls3_scan.h +++ b/lipe/src/lipe_scan3/ls3_scan.h @@ -21,6 +21,7 @@ struct lipe_object_ldiskfs { ext2_filsys lol_fs; ext2_ino_t lol_ino; struct ext2_inode_large *lol_inode; + struct ext2_xattr_handle *lol_xattr_handle; }; struct lipe_object { diff --git a/lustre/tests/sanity-lipe-scan3.sh b/lustre/tests/sanity-lipe-scan3.sh index 7b6d6ee..8ac5764 100644 --- a/lustre/tests/sanity-lipe-scan3.sh +++ b/lustre/tests/sanity-lipe-scan3.sh @@ -580,6 +580,8 @@ test_108() { local device="$(facet_device $facet)" local file=$MOUNT/$tfile local fd + local link_count=200 + local i init_lipe_scan3_env "$file" @@ -595,6 +597,13 @@ test_108() { ln $file $file-3 expect_expr "$device" '(length (links))' 3 + for ((i = 4; i < link_count; i++)); do + ln $file $file-$i + done + + expect_expr "$device" '(caar (links))' "$ROOT_FID" + expect_expr "$device" '(cdar (links))' "$tfile" + # FIXME link xattr is not updated when removing last link. # exec {fd}>$file # rm -- "$file" "$file-2" "$file-3" -- 1.8.3.1