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
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
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
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));
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, ...)
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;
}
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,
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;
}
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:
rc = -ENOTSUP;
break;
}
+out:
+ free(value);
- return 0;
+ return rc;
}
static int ldiskfs_read_attr_size(struct ls3_instance *li,
*
* 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;
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);
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;
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;
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;
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;
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,
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;
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;