__u16 lr_active;
__u16 lr_param;
__u16 lr_async_windows;
- __u32 lr_flags2;
+ union {
+ __u32 lr_flags2;
+ __u32 lr_layout_version;
+ };
struct lu_fid lr_fid;
struct lu_fid lr_fid2;
- struct lu_fid lr_fid3;
- __u64 lr_padding_2;
+ union {
+ struct lu_fid lr_fid3;
+ char lr_pool_name[LOV_MAXPOOLNAME];
+ };
+ __u32 lr_stripe_count;
+ __u32 lr_hash_type;
__u64 lr_padding_3;
};
}
}
+/* This hash is only for testing purpose */
+static inline unsigned int
+lmv_hash_all_chars(unsigned int count, const char *name, int namelen)
+{
+ unsigned int c = 0;
+ const unsigned char *p = (const unsigned char *)name;
+
+ while (--namelen >= 0)
+ c += p[namelen];
+
+ c = c % count;
+
+ return c;
+}
+
+static inline unsigned int
+lmv_hash_fnv1a(unsigned int count, const char *name, int namelen)
+{
+ __u64 hash;
+
+ hash = lustre_hash_fnv_1a_64(name, namelen);
+
+ hash = hash % count;
+
+ return hash;
+}
+
+static inline int lmv_name_to_stripe_index(__u32 lmv_hash_type,
+ unsigned int stripe_count,
+ const char *name, int namelen)
+{
+ int idx;
+ __u32 hash_type = lmv_hash_type & LMV_HASH_TYPE_MASK;
+
+ LASSERT(namelen > 0);
+ if (stripe_count <= 1)
+ return 0;
+
+ /* for migrating object, always start from 0 stripe */
+ if (lmv_hash_type & LMV_HASH_FLAG_MIGRATION)
+ return 0;
+
+ switch (hash_type) {
+ case LMV_HASH_TYPE_ALL_CHARS:
+ idx = lmv_hash_all_chars(stripe_count, name, namelen);
+ break;
+ case LMV_HASH_TYPE_FNV_1A_64:
+ idx = lmv_hash_fnv1a(stripe_count, name, namelen);
+ break;
+ default:
+ idx = -EBADFD;
+ break;
+ }
+
+ CDEBUG(D_INFO, "name %.*s hash_type %d idx %d\n", namelen, name,
+ hash_type, idx);
+
+ return idx;
+}
+
+static inline bool lmv_is_known_hash_type(__u32 type)
+{
+ return (type & LMV_HASH_TYPE_MASK) == LMV_HASH_TYPE_FNV_1A_64 ||
+ (type & LMV_HASH_TYPE_MASK) == LMV_HASH_TYPE_ALL_CHARS;
+}
+
#endif
MODULES := lfsck
lfsck-objs := lfsck_lib.o lfsck_engine.o lfsck_bookmark.o lfsck_namespace.o
-lfsck-objs += lfsck_layout.o
+lfsck-objs += lfsck_layout.o lfsck_striped_dir.o
@INCLUDE_RULES@
iops->put(env, di);
}
-static void lfsck_close_dir(const struct lu_env *env,
- struct lfsck_instance *lfsck)
-{
- struct dt_object *dir_obj = lfsck->li_obj_dir;
- const struct dt_it_ops *dir_iops = &dir_obj->do_index_ops->dio_it;
- struct dt_it *dir_di = lfsck->li_di_dir;
-
- lfsck_di_dir_put(env, lfsck);
- dir_iops->fini(env, dir_di);
- lfsck->li_obj_dir = NULL;
- lfsck_object_put(env, dir_obj);
-}
-
static int lfsck_update_lma(const struct lu_env *env,
struct lfsck_instance *lfsck, struct dt_object *obj)
{
return rc;
}
+static int lfsck_load_stripe_lmv(const struct lu_env *env,
+ struct lfsck_instance *lfsck,
+ struct dt_object *obj)
+{
+ struct lmv_mds_md_v1 *lmv = &lfsck_env_info(env)->lti_lmv;
+ struct lfsck_lmv *llmv;
+ int rc;
+ ENTRY;
+
+ LASSERT(lfsck->li_obj_dir == NULL);
+ LASSERT(lfsck->li_lmv == NULL);
+
+ rc = lfsck_read_stripe_lmv(env, obj, lmv);
+ if (rc == -ENODATA) {
+ lfsck->li_obj_dir = lfsck_object_get(obj);
+
+ RETURN(0);
+ }
+
+ if (rc < 0)
+ RETURN(rc);
+
+ OBD_ALLOC_PTR(llmv);
+ if (llmv == NULL)
+ RETURN(-ENOMEM);
+
+ if (lmv->lmv_magic == LMV_MAGIC) {
+ struct lfsck_slave_lmv_rec *lslr;
+ __u32 stripes;
+
+ llmv->ll_lmv_master = 1;
+ if (lmv->lmv_stripe_count < 1)
+ stripes = LFSCK_LMV_DEF_STRIPES;
+ else if (lmv->lmv_stripe_count > LFSCK_LMV_MAX_STRIPES)
+ stripes = LFSCK_LMV_MAX_STRIPES;
+ else
+ stripes = lmv->lmv_stripe_count;
+
+ OBD_ALLOC_LARGE(lslr, sizeof(*lslr) * stripes);
+ if (lslr == NULL) {
+ OBD_FREE_PTR(llmv);
+
+ RETURN(-ENOMEM);
+ }
+
+ /* Find the object against the bottom device. */
+ obj = lfsck_object_find_by_dev(env, lfsck->li_bottom,
+ lfsck_dto2fid(obj));
+ if (IS_ERR(obj)) {
+ OBD_FREE_LARGE(lslr, sizeof(*lslr) * stripes);
+ OBD_FREE_PTR(llmv);
+
+ RETURN(PTR_ERR(obj));
+ }
+
+ llmv->ll_stripes_allocated = stripes;
+ llmv->ll_hash_type = LMV_HASH_TYPE_UNKNOWN;
+ llmv->ll_lslr = lslr;
+ lfsck->li_obj_dir = obj;
+ } else {
+ llmv->ll_lmv_slave = 1;
+ lfsck->li_obj_dir = lfsck_object_get(obj);
+ }
+
+ llmv->ll_lmv = *lmv;
+ atomic_set(&llmv->ll_ref, 1);
+ lfsck->li_lmv = llmv;
+
+ RETURN(0);
+}
+
/* LFSCK wrap functions */
static void lfsck_fail(const struct lu_env *env, struct lfsck_instance *lfsck,
}
}
+static void lfsck_close_dir(const struct lu_env *env,
+ struct lfsck_instance *lfsck,
+ int result)
+{
+ struct lfsck_component *com;
+ ENTRY;
+
+ if (lfsck->li_lmv != NULL) {
+ lfsck->li_lmv->ll_exit_value = result;
+ if (lfsck->li_obj_dir != NULL) {
+ list_for_each_entry(com, &lfsck->li_list_dir,
+ lc_link_dir) {
+ com->lc_ops->lfsck_close_dir(env, com);
+ }
+ }
+
+ lfsck_lmv_put(env, lfsck->li_lmv);
+ lfsck->li_lmv = NULL;
+ }
+
+ if (lfsck->li_di_dir != NULL) {
+ const struct dt_it_ops *dir_iops =
+ &lfsck->li_obj_dir->do_index_ops->dio_it;
+ struct dt_it *dir_di = lfsck->li_di_dir;
+
+ lfsck_di_dir_put(env, lfsck);
+ dir_iops->fini(env, dir_di);
+ }
+
+ if (lfsck->li_obj_dir != NULL) {
+ struct dt_object *dir_obj = lfsck->li_obj_dir;
+
+ lfsck->li_obj_dir = NULL;
+ lfsck_object_put(env, dir_obj);
+ }
+
+ EXIT;
+}
+
+static int lfsck_open_dir(const struct lu_env *env,
+ struct lfsck_instance *lfsck, __u64 cookie)
+{
+ struct dt_object *obj = lfsck->li_obj_dir;
+ struct dt_it *di = lfsck->li_di_dir;
+ struct lfsck_component *com;
+ const struct dt_it_ops *iops;
+ int rc = 0;
+ ENTRY;
+
+ LASSERT(obj != NULL);
+ LASSERT(di == NULL);
+
+ if (unlikely(!dt_try_as_dir(env, obj)))
+ GOTO(out, rc = -ENOTDIR);
+
+ list_for_each_entry(com, &lfsck->li_list_dir, lc_link_dir) {
+ rc = com->lc_ops->lfsck_open_dir(env, com);
+ if (rc != 0)
+ GOTO(out, rc);
+ }
+
+ iops = &obj->do_index_ops->dio_it;
+ di = iops->init(env, obj, lfsck->li_args_dir, BYPASS_CAPA);
+ if (IS_ERR(di))
+ GOTO(out, rc = PTR_ERR(di));
+
+ rc = iops->load(env, di, cookie);
+ if (rc == 0 || (rc > 0 && cookie > 0))
+ rc = iops->next(env, di);
+ else if (rc > 0)
+ rc = 0;
+
+ if (rc != 0) {
+ iops->put(env, di);
+ iops->fini(env, di);
+ } else {
+ lfsck->li_cookie_dir = iops->store(env, di);
+ spin_lock(&lfsck->li_lock);
+ lfsck->li_di_dir = di;
+ spin_unlock(&lfsck->li_lock);
+ }
+
+ GOTO(out, rc);
+
+out:
+ if (rc != 0)
+ lfsck_close_dir(env, lfsck, rc);
+
+ return rc;
+}
+
static int lfsck_checkpoint(const struct lu_env *env,
struct lfsck_instance *lfsck)
{
struct lfsck_position *pos = NULL;
const struct dt_it_ops *iops =
&lfsck->li_obj_oit->do_index_ops->dio_it;
- struct dt_it *di;
int rc;
ENTRY;
unlikely(!S_ISDIR(lfsck_object_type(obj))))
GOTO(out, rc = 0);
- if (unlikely(!dt_try_as_dir(env, obj)))
- GOTO(out, rc = -ENOTDIR);
+ rc = lfsck_load_stripe_lmv(env, lfsck, obj);
+ if (rc == 0) {
+ /* For the master MDT-object of a striped directory,
+ * reset the iteration from the directory beginning. */
+ if (lfsck->li_lmv != NULL && lfsck->li_lmv->ll_lmv_master)
+ pos->lp_dir_cookie = 0;
- /* Init the namespace-based directory traverse. */
- iops = &obj->do_index_ops->dio_it;
- di = iops->init(env, obj, lfsck->li_args_dir, BYPASS_CAPA);
- if (IS_ERR(di))
- GOTO(out, rc = PTR_ERR(di));
-
- LASSERT(pos->lp_dir_cookie < MDS_DIR_END_OFF);
-
- rc = iops->load(env, di, pos->lp_dir_cookie);
- if ((rc == 0) || (rc > 0 && pos->lp_dir_cookie > 0))
- rc = iops->next(env, di);
- else if (rc > 0)
- rc = 0;
-
- if (rc != 0) {
- iops->put(env, di);
- iops->fini(env, di);
- GOTO(out, rc);
+ rc = lfsck_open_dir(env, lfsck, pos->lp_dir_cookie);
}
- lfsck->li_obj_dir = lfsck_object_get(obj);
- lfsck->li_cookie_dir = iops->store(env, di);
- spin_lock(&lfsck->li_lock);
- lfsck->li_di_dir = di;
- spin_unlock(&lfsck->li_lock);
-
- GOTO(out, rc = 0);
+ GOTO(out, rc);
out:
if (obj != NULL)
lfsck_object_put(env, obj);
- if (rc < 0) {
+ if (rc != 0) {
+ lfsck_close_dir(env, lfsck, rc);
list_for_each_entry_safe(com, next, &lfsck->li_list_scan,
- lc_link)
+ lc_link) {
com->lc_ops->lfsck_post(env, com, rc, true);
+ }
return rc;
}
struct lfsck_instance *lfsck, struct dt_object *obj)
{
struct lfsck_component *com;
- const struct dt_it_ops *iops;
- struct dt_it *di;
int rc;
ENTRY;
if (rc <= 0)
GOTO(out, rc);
- if (unlikely(!dt_try_as_dir(env, obj)))
- GOTO(out, rc = -ENOTDIR);
-
- iops = &obj->do_index_ops->dio_it;
- di = iops->init(env, obj, lfsck->li_args_dir, BYPASS_CAPA);
- if (IS_ERR(di))
- GOTO(out, rc = PTR_ERR(di));
-
- rc = iops->load(env, di, 0);
+ rc = lfsck_load_stripe_lmv(env, lfsck, obj);
if (rc == 0)
- rc = iops->next(env, di);
- else if (rc > 0)
- rc = 0;
+ rc = lfsck_open_dir(env, lfsck, 0);
- if (rc != 0) {
- iops->put(env, di);
- iops->fini(env, di);
- GOTO(out, rc);
- }
-
- lfsck->li_obj_dir = lfsck_object_get(obj);
- lfsck->li_cookie_dir = iops->store(env, di);
- spin_lock(&lfsck->li_lock);
- lfsck->li_di_dir = di;
- spin_unlock(&lfsck->li_lock);
-
- GOTO(out, rc = 0);
+ GOTO(out, rc);
out:
if (rc < 0)
lfsck_fail(env, lfsck, false);
- return (rc > 0 ? 0 : rc);
+
+ if (rc != 0)
+ lfsck_close_dir(env, lfsck, rc);
+
+ return rc > 0 ? 0 : rc;
}
static int lfsck_exec_dir(const struct lu_env *env,
int rc1 = 0;
lfsck_pos_fill(env, lfsck, &lfsck->li_pos_checkpoint, false);
+ lfsck_close_dir(env, lfsck, result);
list_for_each_entry_safe(com, next, &lfsck->li_list_scan, lc_link) {
rc = com->lc_ops->lfsck_post(env, com, result, false);
if (rc != 0)
} while (rc == 0);
if (rc > 0 && !lfsck->li_oit_over)
- lfsck_close_dir(env, lfsck);
+ lfsck_close_dir(env, lfsck, rc);
RETURN(rc);
}
if (!OBD_FAIL_CHECK(OBD_FAIL_LFSCK_CRASH))
rc = lfsck_post(env, lfsck, rc);
-
- if (lfsck->li_di_dir != NULL)
- lfsck_close_dir(env, lfsck);
+ else
+ lfsck_close_dir(env, lfsck, rc);
fini_oit:
lfsck_di_oit_put(env, lfsck);
/* How many objects under /lost+found failed to be processed. */
__u64 ln_local_lpf_failed;
+ /* How many striped directories (master) have been scanned. */
+ __u64 ln_striped_dirs_scanned;
+
+ /* How many striped directories (master) have been repaired. */
+ __u64 ln_striped_dirs_repaired;
+
+ /* How many striped directories (master) failed verification. */
+ __u64 ln_striped_dirs_failed;
+
+ /* How many striped directories (master) has been disabled. */
+ __u64 ln_striped_dirs_disabled;
+
+ /* How many striped directory's (master) have been skipped
+ * (for shards verification) because of lost master LMV EA. */
+ __u64 ln_striped_dirs_skipped;
+
+ /* How many striped directory's shards (slave) have been scanned. */
+ __u64 ln_striped_shards_scanned;
+
+ /* How many striped directory's shards (slave) have been repaired. */
+ __u64 ln_striped_shards_repaired;
+
+ /* How many striped directory's shards (slave) failed verification. */
+ __u64 ln_striped_shards_failed;
+
+ /* How many striped directory's shards (slave) have been skipped
+ * (for name hash verification) because do not know whether the slave
+ * LMV EA is valid or not. */
+ __u64 ln_striped_shards_skipped;
+
+ /* How many name entries under striped directory with bad name
+ * hash have been repaired. */
+ __u64 ln_name_hash_repaired;
+
/* The size of MDT targets bitmap with nbits. Such bitmap records
* the MDTs that contain non-verified MDT-objects. */
__u32 ln_bitmap_size;
__u32 ln_reserved_1;
/* For further using. 256-bytes aligned now. */
- __u64 ln_reserved[25];
+ __u64 ln_reserved[15];
};
enum lfsck_layout_inconsistency_type {
struct lfsck_component *com,
bool new_checked);
+ void (*lfsck_close_dir)(const struct lu_env *env,
+ struct lfsck_component *com);
+
+ int (*lfsck_open_dir)(const struct lu_env *env,
+ struct lfsck_component *com);
+
int (*lfsck_checkpoint)(const struct lu_env *env,
struct lfsck_component *com,
bool init);
__u16 lc_type;
};
+#define LFSCK_LMV_MAX_STRIPES LMV_MAX_STRIPE_COUNT
+#define LFSCK_LMV_DEF_STRIPES 4
+
+struct lfsck_slave_lmv_rec {
+ struct lu_fid lslr_fid;
+ __u32 lslr_stripe_count;
+ __u32 lslr_index; /* the index in name or in slave lmv */
+ __u32 lslr_hash_type;
+ __u32 lslr_flags;
+};
+
+struct lfsck_lmv {
+ struct lmv_mds_md_v1 ll_lmv;
+ atomic_t ll_ref;
+ int ll_stripes_allocated;
+ int ll_stripes_filled;
+ int ll_exit_value;
+ __u32 ll_max_stripe_count;
+ __u32 ll_max_filled_off;
+ __u32 ll_hash_type;
+ unsigned int ll_lmv_master:1,
+ ll_lmv_slave:1,
+ ll_lmv_verified:1,
+ ll_lmv_updated:1,
+ ll_inline:1,
+ ll_failed:1,
+ ll_ignore:1;
+ struct lfsck_slave_lmv_rec *ll_lslr;
+};
+
struct lfsck_instance {
struct mutex li_mutex;
spinlock_t li_lock;
struct lfsck_position li_pos_current;
struct lfsck_position li_pos_checkpoint;
+ struct lfsck_lmv *li_lmv;
+
/* Obj for otable-based iteration */
struct dt_object *li_obj_oit;
struct lfsck_namespace_req {
struct lfsck_assistant_req lnr_lar;
struct dt_object *lnr_obj;
+ struct lfsck_lmv *lnr_lmv;
struct lu_fid lnr_fid;
__u64 lnr_oit_cookie;
__u64 lnr_dir_cookie;
/* There will be '\0' at the end of the name. */
char lti_key[sizeof(struct lu_dirent) + NAME_MAX + 1];
char lti_tmpbuf[LFSCK_TMPBUF_LEN];
+ char lti_tmpbuf2[LFSCK_TMPBUF_LEN];
struct lfsck_request lti_lr;
struct lfsck_async_interpret_args lti_laia;
struct lfsck_async_interpret_args lti_laia2;
struct dt_insert_rec lti_dt_rec;
struct lu_object_conf lti_conf;
struct lu_seq_range lti_range;
+ struct lmv_mds_md_v1 lti_lmv;
+ struct lmv_mds_md_v1 lti_lmv2;
+ struct lmv_mds_md_v1 lti_lmv3;
+ struct lmv_mds_md_v1 lti_lmv4;
};
/* lfsck_lib.c */
int lfsck_namespace_setup(const struct lu_env *env,
struct lfsck_instance *lfsck);
+/* lfsck_striped_dir.c */
+void lfsck_lmv_put(const struct lu_env *env, struct lfsck_lmv *llmv);
+int lfsck_read_stripe_lmv(const struct lu_env *env, struct dt_object *obj,
+ struct lmv_mds_md_v1 *lmv);
+int lfsck_shard_name_to_index(const struct lu_env *env, const char *name,
+ int namelen, __u16 type,
+ const struct lu_fid *fid);
+bool lfsck_is_valid_slave_name_entry(const struct lu_env *env,
+ struct lfsck_lmv *llmv,
+ const char *name, int namelen);
+int lfsck_namespace_check_name(const struct lu_env *env,
+ struct dt_object *parent,
+ struct dt_object *child,
+ const struct lu_name *cname);
+int lfsck_namespace_verify_stripe_slave(const struct lu_env *env,
+ struct lfsck_component *com,
+ struct dt_object *obj,
+ struct lfsck_lmv *llmv);
+
/* lfsck_layout.c */
int lfsck_layout_setup(const struct lu_env *env, struct lfsck_instance *lfsck);
extern const char *lfsck_param_names[];
extern struct lu_context_key lfsck_thread_key;
+static inline bool name_is_dot_or_dotdot(const char *name, int namelen)
+{
+ return name[0] == '.' &&
+ (namelen == 1 || (namelen == 2 && name[1] == '.'));
+}
+
static inline struct dt_device *lfsck_obj2dt_dev(struct dt_object *obj)
{
return container_of0(obj->do_lu.lo_dev, struct dt_device, dd_lu_dev);
return __lfsck_links_read(env, obj, ldata);
}
+static inline struct lfsck_lmv *lfsck_lmv_get(struct lfsck_lmv *llmv)
+{
+ if (llmv != NULL)
+ atomic_inc(&llmv->ll_ref);
+
+ return llmv;
+}
+
+static inline void lfsck_lmv_header_le_to_cpu(struct lmv_mds_md_v1 *dst,
+ const struct lmv_mds_md_v1 *src)
+{
+ dst->lmv_magic = le32_to_cpu(src->lmv_magic);
+ dst->lmv_stripe_count = le32_to_cpu(src->lmv_stripe_count);
+ dst->lmv_master_mdt_index = le32_to_cpu(src->lmv_master_mdt_index);
+ dst->lmv_hash_type = le32_to_cpu(src->lmv_hash_type);
+ dst->lmv_layout_version = le32_to_cpu(src->lmv_layout_version);
+}
+
+static inline void lfsck_lmv_header_cpu_to_le(struct lmv_mds_md_v1 *dst,
+ const struct lmv_mds_md_v1 *src)
+{
+ dst->lmv_magic = cpu_to_le32(src->lmv_magic);
+ dst->lmv_stripe_count = cpu_to_le32(src->lmv_stripe_count);
+ dst->lmv_master_mdt_index = cpu_to_le32(src->lmv_master_mdt_index);
+ dst->lmv_hash_type = cpu_to_le32(src->lmv_hash_type);
+ dst->lmv_layout_version = cpu_to_le32(src->lmv_layout_version);
+}
#endif /* _LFSCK_INTERNAL_H */
break;
ent->lde_namelen = le16_to_cpu(ent->lde_namelen);
- if (ent->lde_name[0] == '.') {
- if (ent->lde_namelen == 1)
- goto next;
-
- if (ent->lde_namelen == 2 && ent->lde_name[1] == '.')
- goto next;
- }
+ if (name_is_dot_or_dotdot(ent->lde_name, ent->lde_namelen))
+ goto next;
/* name length must be strlen("MDTxxxx") */
if (ent->lde_namelen != 7)
return ERR_PTR(-ENOMEM);
INIT_LIST_HEAD(&lnr->lnr_lar.lar_list);
- lu_object_get(&lfsck->li_obj_dir->do_lu);
- lnr->lnr_obj = lfsck->li_obj_dir;
+ lnr->lnr_obj = lfsck_object_get(lfsck->li_obj_dir);
+ lnr->lnr_lmv = lfsck_lmv_get(lfsck->li_lmv);
lnr->lnr_fid = ent->lde_fid;
lnr->lnr_oit_cookie = lfsck->li_pos_current.lp_oit_cookie;
lnr->lnr_dir_cookie = ent->lde_hash;
struct lfsck_namespace_req *lnr =
container_of0(lar, struct lfsck_namespace_req, lnr_lar);
+ if (lnr->lnr_lmv != NULL)
+ lfsck_lmv_put(env, lnr->lnr_lmv);
+
lu_object_put(env, &lnr->lnr_obj->do_lu);
OBD_FREE(lnr, lnr->lnr_size);
}
dst->ln_bad_type_repaired = le64_to_cpu(src->ln_bad_type_repaired);
dst->ln_lost_dirent_repaired =
le64_to_cpu(src->ln_lost_dirent_repaired);
+ dst->ln_striped_dirs_scanned =
+ le64_to_cpu(src->ln_striped_dirs_scanned);
+ dst->ln_striped_dirs_repaired =
+ le64_to_cpu(src->ln_striped_dirs_repaired);
+ dst->ln_striped_dirs_failed =
+ le64_to_cpu(src->ln_striped_dirs_failed);
+ dst->ln_striped_dirs_disabled =
+ le64_to_cpu(src->ln_striped_dirs_disabled);
+ dst->ln_striped_dirs_skipped =
+ le64_to_cpu(src->ln_striped_dirs_skipped);
+ dst->ln_striped_shards_scanned =
+ le64_to_cpu(src->ln_striped_shards_scanned);
+ dst->ln_striped_shards_repaired =
+ le64_to_cpu(src->ln_striped_shards_repaired);
+ dst->ln_striped_shards_failed =
+ le64_to_cpu(src->ln_striped_shards_failed);
+ dst->ln_striped_shards_skipped =
+ le64_to_cpu(src->ln_striped_shards_skipped);
+ dst->ln_name_hash_repaired = le64_to_cpu(src->ln_name_hash_repaired);
dst->ln_local_lpf_scanned = le64_to_cpu(src->ln_local_lpf_scanned);
dst->ln_local_lpf_moved = le64_to_cpu(src->ln_local_lpf_moved);
dst->ln_local_lpf_skipped = le64_to_cpu(src->ln_local_lpf_skipped);
dst->ln_bad_type_repaired = cpu_to_le64(src->ln_bad_type_repaired);
dst->ln_lost_dirent_repaired =
cpu_to_le64(src->ln_lost_dirent_repaired);
+ dst->ln_striped_dirs_scanned =
+ cpu_to_le64(src->ln_striped_dirs_scanned);
+ dst->ln_striped_dirs_repaired =
+ cpu_to_le64(src->ln_striped_dirs_repaired);
+ dst->ln_striped_dirs_failed =
+ cpu_to_le64(src->ln_striped_dirs_failed);
+ dst->ln_striped_dirs_disabled =
+ cpu_to_le64(src->ln_striped_dirs_disabled);
+ dst->ln_striped_dirs_skipped =
+ cpu_to_le64(src->ln_striped_dirs_skipped);
+ dst->ln_striped_shards_scanned =
+ cpu_to_le64(src->ln_striped_shards_scanned);
+ dst->ln_striped_shards_repaired =
+ cpu_to_le64(src->ln_striped_shards_repaired);
+ dst->ln_striped_shards_failed =
+ cpu_to_le64(src->ln_striped_shards_failed);
+ dst->ln_striped_shards_skipped =
+ cpu_to_le64(src->ln_striped_shards_skipped);
+ dst->ln_name_hash_repaired = cpu_to_le64(src->ln_name_hash_repaired);
dst->ln_local_lpf_scanned = cpu_to_le64(src->ln_local_lpf_scanned);
dst->ln_local_lpf_moved = cpu_to_le64(src->ln_local_lpf_moved);
dst->ln_local_lpf_skipped = cpu_to_le64(src->ln_local_lpf_skipped);
* type "O": The MDT-object has no linkEA, and there is no name
* entry that references the MDT-object.
*
+ * type "S": The orphan MDT-object is a shard of a striped directory
+ *
* \see lfsck_layout_recreate_parent() for more types.
*
* The orphan name will be like:
*
* \see lfsck_layout_recreate_parent() for more types.
*
+ * \param[in] lmv pointer to master LMV EA that will be set to the orphan
+ *
* \retval positive number for repaired cases
* \retval 0 if needs to repair nothing
* \retval negative error number on failure
static int lfsck_namespace_create_orphan_remote(const struct lu_env *env,
struct lfsck_component *com,
struct dt_object *orphan,
- __u32 type)
+ __u32 type,
+ struct lmv_mds_md_v1 *lmv)
{
struct lfsck_thread_info *info = lfsck_env_info(env);
struct lfsck_request *lr = &info->lti_lr;
lr->lr_active = LFSCK_TYPE_NAMESPACE;
lr->lr_fid = *fid;
lr->lr_type = type;
+ if (lmv != NULL) {
+ lr->lr_hash_type = lmv->lmv_hash_type;
+ lr->lr_stripe_count = lmv->lmv_stripe_count;
+ lr->lr_layout_version = lmv->lmv_layout_version;
+ memcpy(lr->lr_pool_name, lmv->lmv_pool_name,
+ sizeof(lr->lr_pool_name));
+ }
ptlrpc_request_set_replen(req);
rc = ptlrpc_queue_wait(req);
*
* \see lfsck_layout_recreate_parent() for more types.
*
+ * \param[in] lmv pointer to master LMV EA that will be set to the orphan
+ *
* \retval positive number for repaired cases
* \retval negative error number on failure
*/
static int lfsck_namespace_create_orphan_local(const struct lu_env *env,
struct lfsck_component *com,
struct dt_object *orphan,
- __u32 type)
+ __u32 type,
+ struct lmv_mds_md_v1 *lmv)
{
struct lfsck_thread_info *info = lfsck_env_info(env);
struct lu_attr *la = &info->lti_la;
struct lu_name *cname = &info->lti_name2;
struct dt_insert_rec *rec = &info->lti_dt_rec;
struct lu_fid *tfid = &info->lti_fid;
+ struct lmv_mds_md_v1 *lmv2 = &info->lti_lmv2;
const struct lu_fid *cfid = lfsck_dto2fid(orphan);
const struct lu_fid *pfid;
struct lfsck_instance *lfsck = com->lc_lfsck;
struct lustre_handle lh = { 0 };
struct linkea_data ldata = { 0 };
struct lu_buf linkea_buf;
+ struct lu_buf lmv_buf;
char name[32];
int namelen;
int idx = 0;
if (rc != 0)
GOTO(stop, rc);
+ if (lmv != NULL) {
+ lmv->lmv_magic = LMV_MAGIC;
+ lmv->lmv_master_mdt_index = lfsck_dev_idx(dev);
+ lfsck_lmv_header_cpu_to_le(lmv2, lmv);
+ lfsck_buf_init(&lmv_buf, lmv2, sizeof(*lmv2));
+ rc = dt_declare_xattr_set(env, child, &lmv_buf,
+ XATTR_NAME_LMV, 0, th);
+ if (rc != 0)
+ GOTO(stop, rc);
+ }
+
lfsck_buf_init(&linkea_buf, ldata.ld_buf->lb_buf,
ldata.ld_leh->leh_len);
rc = dt_declare_xattr_set(env, child, &linkea_buf,
GOTO(unlock2, rc);
}
+ if (lmv != NULL) {
+ rc = dt_xattr_set(env, child, &lmv_buf, XATTR_NAME_LMV, 0,
+ th, BYPASS_CAPA);
+ if (rc != 0)
+ GOTO(unlock2, rc);
+ }
+
rc = dt_xattr_set(env, child, &linkea_buf,
XATTR_NAME_LINK, 0, th, BYPASS_CAPA);
dt_write_unlock(env, child);
*
* \see lfsck_layout_recreate_parent() for more types.
*
+ * \param[in] lmv pointer to master LMV EA that will be set to the orphan
+ *
* \retval positive number for repaired cases
* \retval 0 if needs to repair nothing
* \retval negative error number on failure
*/
static int lfsck_namespace_create_orphan(const struct lu_env *env,
struct lfsck_component *com,
- struct dt_object *orphan)
+ struct dt_object *orphan,
+ struct lmv_mds_md_v1 *lmv)
{
struct lfsck_namespace *ns = com->lc_file_ram;
int rc;
if (dt_object_remote(orphan))
rc = lfsck_namespace_create_orphan_remote(env, com, orphan,
- S_IFDIR);
+ S_IFDIR, lmv);
else
rc = lfsck_namespace_create_orphan_local(env, com, orphan,
- S_IFDIR);
+ S_IFDIR, lmv);
if (rc != 0)
ns->ln_flags |= LF_INCONSISTENT;
struct lfsck_namespace *ns = com->lc_file_ram;
struct lfsck_instance *lfsck = com->lc_lfsck;
struct dt_object *parent = NULL;
+ struct lmv_mds_md_v1 *lmv;
int rc = 0;
ENTRY;
lfsck_ibits_unlock(lh, LCK_EX);
lost_parent:
+ lmv = &info->lti_lmv;
+ rc = lfsck_read_stripe_lmv(env, child, lmv);
+ if (rc != 0 && rc != -ENODATA)
+ GOTO(out, rc);
+
+ if (rc == -ENODATA || lmv->lmv_magic != LMV_MAGIC_STRIPE) {
+ lmv = NULL;
+ } else if (lfsck_shard_name_to_index(env,
+ cname->ln_name, cname->ln_namelen,
+ S_IFDIR, cfid) < 0) {
+ /* It is an invalid name entry, we
+ * cannot trust the parent also. */
+ rc = lfsck_namespace_shrink_linkea(env, com, child,
+ ldata, cname, tfid, true);
+ if (rc < 0)
+ GOTO(out, rc);
+
+ snprintf(info->lti_tmpbuf, sizeof(info->lti_tmpbuf),
+ "-"DFID, PFID(pfid));
+ rc = lfsck_namespace_insert_orphan(env, com, child,
+ info->lti_tmpbuf, "S", NULL);
+
+ GOTO(out, rc);
+ }
+
/* Create the lost parent as an orphan. */
- rc = lfsck_namespace_create_orphan(env, com, parent);
+ rc = lfsck_namespace_create_orphan(env, com, parent, lmv);
if (rc >= 0) {
/* Add the missing name entry to the parent. */
rc = lfsck_namespace_insert_normal(env, com, parent,
}
lfsck_ibits_unlock(lh, LCK_EX);
+ rc = lfsck_namespace_check_name(env, parent, child, cname);
+ if (rc == -ENOENT)
+ goto lost_parent;
+
+ if (rc < 0)
+ GOTO(out, rc);
+
+ /* It is an invalid name entry, drop it. */
+ if (unlikely(rc > 0)) {
+ rc = lfsck_namespace_shrink_linkea(env, com, child,
+ ldata, cname, tfid, true);
+ if (rc >= 0) {
+ snprintf(info->lti_tmpbuf,
+ sizeof(info->lti_tmpbuf),
+ "-"DFID, PFID(pfid));
+ rc = lfsck_namespace_insert_orphan(env, com,
+ child, info->lti_tmpbuf, "D", NULL);
+ }
+
+ GOTO(out, rc);
+ }
+
/* Add the missing name entry back to the namespace. */
rc = lfsck_namespace_insert_normal(env, com, parent, child,
cname->ln_name);
/* Create the lost parent as an orphan. */
rc = lfsck_namespace_create_orphan(env, com,
- parent);
+ parent, NULL);
if (rc < 0) {
lfsck_object_put(env, parent);
GOTO(out, rc = 0);
}
+ rc = lfsck_namespace_check_name(env, parent, child, cname);
+ if (rc == -ENOENT)
+ goto lost_parent;
+
+ if (rc < 0) {
+ lfsck_object_put(env, parent);
+
+ GOTO(out, rc);
+ }
+
+ /* It is an invalid name entry, drop it. */
+ if (unlikely(rc > 0)) {
+ lfsck_object_put(env, parent);
+ rc = lfsck_namespace_shrink_linkea(env, com, child,
+ &ldata, cname, pfid, true);
+ if (rc < 0)
+ GOTO(out, rc);
+
+ if (rc > 0)
+ repaired = true;
+
+ continue;
+ }
+
/* Add the missing name entry back to the namespace. */
rc = lfsck_namespace_insert_normal(env, com, parent, child,
cname->ln_name);
"local_lost_found_moved: "LPU64"\n"
"local_lost_found_skipped: "LPU64"\n"
"local_lost_found_failed: "LPU64"\n"
+ "striped_dirs_scanned: "LPU64"\n"
+ "striped_dirs_repaired: "LPU64"\n"
+ "striped_dirs_failed: "LPU64"\n"
+ "striped_dirs_disabled: "LPU64"\n"
+ "striped_dirs_skipped: "LPU64"\n"
+ "striped_shards_scanned: "LPU64"\n"
+ "striped_shards_repaired: "LPU64"\n"
+ "striped_shards_failed: "LPU64"\n"
+ "striped_shards_skipped: "LPU64"\n"
+ "name_hash_repaired: "LPU64"\n"
"success_count: %u\n"
"run_time_phase1: %u seconds\n"
"run_time_phase2: %u seconds\n",
ns->ln_local_lpf_moved,
ns->ln_local_lpf_skipped,
ns->ln_local_lpf_failed,
+ ns->ln_striped_dirs_scanned,
+ ns->ln_striped_dirs_repaired,
+ ns->ln_striped_dirs_failed,
+ ns->ln_striped_dirs_disabled,
+ ns->ln_striped_dirs_skipped,
+ ns->ln_striped_shards_scanned,
+ ns->ln_striped_shards_repaired,
+ ns->ln_striped_shards_failed,
+ ns->ln_striped_shards_skipped,
+ ns->ln_name_hash_repaired,
ns->ln_success_count,
time_phase1,
time_phase2);
up_write(&com->lc_sem);
}
+static void lfsck_namespace_close_dir(const struct lu_env *env,
+ struct lfsck_component *com)
+{
+ struct lfsck_namespace *ns = com->lc_file_ram;
+ struct lfsck_assistant_data *lad = com->lc_data;
+ struct lfsck_instance *lfsck = com->lc_lfsck;
+ struct lfsck_lmv *llmv = lfsck->li_lmv;
+ struct lfsck_namespace_req *lnr;
+ __u32 size =
+ sizeof(*lnr) + LFSCK_TMPBUF_LEN;
+ bool wakeup = false;
+ ENTRY;
+
+ if (llmv == NULL)
+ RETURN_EXIT;
+
+ OBD_ALLOC(lnr, size);
+ if (lnr == NULL) {
+ ns->ln_striped_dirs_skipped++;
+
+ RETURN_EXIT;
+ }
+
+ /* Generate a dummy request to indicate that all shards' name entry
+ * in this striped directory has been scanned for the first time. */
+ INIT_LIST_HEAD(&lnr->lnr_lar.lar_list);
+ lnr->lnr_obj = lfsck_object_get(lfsck->li_obj_dir);
+ lnr->lnr_lmv = lfsck_lmv_get(llmv);
+ lnr->lnr_fid = *lfsck_dto2fid(lfsck->li_obj_dir);
+ lnr->lnr_oit_cookie = lfsck->li_pos_current.lp_oit_cookie;
+ lnr->lnr_dir_cookie = MDS_DIR_END_OFF;
+ lnr->lnr_size = size;
+
+ spin_lock(&lad->lad_lock);
+ if (lad->lad_assistant_status < 0) {
+ spin_unlock(&lad->lad_lock);
+ lfsck_namespace_assistant_req_fini(env, &lnr->lnr_lar);
+ ns->ln_striped_dirs_skipped++;
+
+ RETURN_EXIT;
+ }
+
+ list_add_tail(&lnr->lnr_lar.lar_list, &lad->lad_req_list);
+ if (lad->lad_prefetched == 0)
+ wakeup = true;
+
+ lad->lad_prefetched++;
+ spin_unlock(&lad->lad_lock);
+ if (wakeup)
+ wake_up_all(&lad->lad_thread.t_ctl_waitq);
+
+ EXIT;
+}
+
+static int lfsck_namespace_open_dir(const struct lu_env *env,
+ struct lfsck_component *com)
+{
+ struct lfsck_instance *lfsck = com->lc_lfsck;
+ struct lfsck_namespace *ns = com->lc_file_ram;
+ struct lfsck_lmv *llmv = lfsck->li_lmv;
+ int rc = 0;
+ ENTRY;
+
+ if (llmv == NULL)
+ RETURN(0);
+
+ if (llmv->ll_lmv_master) {
+ struct lmv_mds_md_v1 *lmv = &llmv->ll_lmv;
+
+ if (lmv->lmv_master_mdt_index !=
+ lfsck_dev_idx(lfsck->li_bottom)) {
+ lmv->lmv_master_mdt_index =
+ lfsck_dev_idx(lfsck->li_bottom);
+ ns->ln_flags |= LF_INCONSISTENT;
+ llmv->ll_lmv_updated = 1;
+ }
+ } else {
+ rc = lfsck_namespace_verify_stripe_slave(env, com,
+ lfsck->li_obj_dir, llmv);
+ }
+
+ RETURN(rc > 0 ? 0 : rc);
+}
+
static int lfsck_namespace_checkpoint(const struct lu_env *env,
struct lfsck_component *com, bool init)
{
ns->ln_mul_ref_repaired = 0;
ns->ln_bad_type_repaired = 0;
ns->ln_lost_dirent_repaired = 0;
+ ns->ln_striped_dirs_scanned = 0;
+ ns->ln_striped_dirs_repaired = 0;
+ ns->ln_striped_dirs_failed = 0;
+ ns->ln_striped_dirs_disabled = 0;
+ ns->ln_striped_dirs_skipped = 0;
+ ns->ln_striped_shards_scanned = 0;
+ ns->ln_striped_shards_repaired = 0;
+ ns->ln_striped_shards_failed = 0;
+ ns->ln_striped_shards_skipped = 0;
+ ns->ln_name_hash_repaired = 0;
fid_zero(&ns->ln_fid_latest_scanned_phase2);
if (list_empty(&com->lc_link_dir))
list_add_tail(&com->lc_link_dir,
switch (lr->lr_event) {
case LE_CREATE_ORPHAN: {
struct dt_object *orphan = NULL;
+ struct lmv_mds_md_v1 *lmv;
CDEBUG(D_LFSCK, "%s: namespace LFSCK handling notify from "
"MDT %x to create orphan"DFID" with type %o\n",
if (dt_object_exists(orphan))
GOTO(out_create, rc = -EEXIST);
+ if (lr->lr_stripe_count > 0) {
+ lmv = &lfsck_env_info(env)->lti_lmv;
+ memset(lmv, 0, sizeof(*lmv));
+ lmv->lmv_hash_type = lr->lr_hash_type;
+ lmv->lmv_stripe_count = lr->lr_stripe_count;
+ lmv->lmv_layout_version = lr->lr_layout_version;
+ memcpy(lmv->lmv_pool_name, lr->lr_pool_name,
+ sizeof(lmv->lmv_pool_name));
+ } else {
+ lmv = NULL;
+ }
+
rc = lfsck_namespace_create_orphan_local(env, com, orphan,
- lr->lr_type);
+ lr->lr_type, lmv);
GOTO(out_create, rc = (rc == 1) ? 0 : rc);
static struct lfsck_operations lfsck_namespace_ops = {
.lfsck_reset = lfsck_namespace_reset,
.lfsck_fail = lfsck_namespace_fail,
+ .lfsck_close_dir = lfsck_namespace_close_dir,
+ .lfsck_open_dir = lfsck_namespace_open_dir,
.lfsck_checkpoint = lfsck_namespace_checkpoint,
.lfsck_prep = lfsck_namespace_prep,
.lfsck_exec_oit = lfsck_namespace_exec_oit,
struct dt_allocation_hint *hint = &info->lti_hint;
struct dt_object_format *dof = &info->lti_dof;
struct dt_insert_rec *rec = &info->lti_dt_rec;
+ struct lmv_mds_md_v1 *lmv2 = &info->lti_lmv2;
struct dt_object *parent = lnr->lnr_obj;
const struct lu_name *cname;
struct linkea_data ldata = { 0 };
struct lustre_handle lh = { 0 };
struct lu_buf linkea_buf;
+ struct lu_buf lmv_buf;
struct lfsck_instance *lfsck = com->lc_lfsck;
struct lfsck_bookmark *bk = &lfsck->li_bookmark_ram;
struct dt_device *dev = lfsck_obj2dt_dev(child);
rc = dt_declare_ref_add(env, child, th);
if (rc != 0)
GOTO(stop, rc);
+
+ /* 5a. generate slave LMV EA. */
+ if (lnr->lnr_lmv != NULL && lnr->lnr_lmv->ll_lmv_master) {
+ int idx;
+
+ idx = lfsck_shard_name_to_index(env,
+ lnr->lnr_name, lnr->lnr_namelen,
+ type, lfsck_dto2fid(child));
+ if (unlikely(idx < 0))
+ GOTO(stop, rc = idx);
+
+ *lmv2 = lnr->lnr_lmv->ll_lmv;
+ lmv2->lmv_magic = LMV_MAGIC_STRIPE;
+ lmv2->lmv_master_mdt_index = idx;
+
+ lfsck_lmv_header_cpu_to_le(lmv2, lmv2);
+ lfsck_buf_init(&lmv_buf, lmv2, sizeof(*lmv2));
+ rc = dt_declare_xattr_set(env, child, &lmv_buf,
+ XATTR_NAME_LMV, 0, th);
+ if (rc != 0)
+ GOTO(stop, rc);
+ }
}
- /* 5a. insert linkEA for child */
+ /* 6a. insert linkEA for child */
lfsck_buf_init(&linkea_buf, ldata.ld_buf->lb_buf,
ldata.ld_leh->leh_len);
rc = dt_declare_xattr_set(env, child, &linkea_buf,
rc = dt_ref_add(env, child, th);
if (rc != 0)
GOTO(unlock, rc);
+
+ /* 5b. generate slave LMV EA. */
+ if (lnr->lnr_lmv != NULL && lnr->lnr_lmv->ll_lmv_master) {
+ rc = dt_xattr_set(env, child, &lmv_buf, XATTR_NAME_LMV,
+ 0, th, BYPASS_CAPA);
+ if (rc != 0)
+ GOTO(unlock, rc);
+ }
}
- /* 5b. insert linkEA for child. */
+ /* 6b. insert linkEA for child. */
rc = dt_xattr_set(env, child, &linkea_buf,
XATTR_NAME_LINK, 0, th, BYPASS_CAPA);
dangling:
rc = lfsck_namespace_check_exist(env, dir, obj, lnr->lnr_name);
if (rc == 0) {
+ if (!lfsck_is_valid_slave_name_entry(env, lnr->lnr_lmv,
+ lnr->lnr_name, lnr->lnr_namelen)) {
+ type = LNIT_BAD_DIRENT;
+
+ GOTO(out, rc);
+ }
+
type = LNIT_DANGLING;
rc = lfsck_namespace_repair_dangling(env, com,
obj, lnr);
ns->ln_flags |= LF_INCONSISTENT;
+ /* If the name entry hash does not match the slave striped
+ * directory, and the name entry does not match also, then
+ * it is quite possible that name entry is corrupted. */
+ if (!lfsck_is_valid_slave_name_entry(env, lnr->lnr_lmv,
+ lnr->lnr_name, lnr->lnr_namelen)) {
+ type = LNIT_BAD_DIRENT;
+
+ GOTO(stop, rc = 0);
+ }
+
/* If the file type stored in the name entry does not match
* the file type claimed by the object, and the object does
* not recognize the name entry, then it is quite possible
}
/* skip dot and dotdot entries */
- if (ent->lde_name[0] == '.' &&
- (ent->lde_namelen == 1 ||
- (ent->lde_namelen == 2 && ent->lde_name[1] == '.')))
+ if (name_is_dot_or_dotdot(ent->lde_name, ent->lde_namelen))
goto next;
if (!fid_seq_in_fldb(fid_seq(&ent->lde_fid)))
goto checkpoint;
}
- target = lfsck_object_find(env, lfsck, &fid);
+ target = lfsck_object_find_by_dev(env, lfsck->li_bottom, &fid);
if (IS_ERR(target)) {
rc = PTR_ERR(target);
goto checkpoint;
--- /dev/null
+/*
+ * GPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * as published by the Free Software Foundation.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License version 2 for more details. A copy is
+ * included in the COPYING file that accompanied this code.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * GPL HEADER END
+ */
+/*
+ * Copyright (c) 2014, Intel Corporation.
+ */
+/*
+ * lustre/lfsck/lfsck_striped_dir.c
+ *
+ * Author: Fan, Yong <fan.yong@intel.com>
+ */
+
+#define DEBUG_SUBSYSTEM S_LFSCK
+
+#include <lustre/lustre_idl.h>
+#include <lu_object.h>
+#include <dt_object.h>
+#include <md_object.h>
+#include <lustre_fid.h>
+#include <lustre_lib.h>
+#include <lustre_net.h>
+#include <lustre_lmv.h>
+#include <lustre/lustre_user.h>
+
+#include "lfsck_internal.h"
+
+void lfsck_lmv_put(const struct lu_env *env, struct lfsck_lmv *llmv)
+{
+ if (llmv != NULL && atomic_dec_and_test(&llmv->ll_ref)) {
+ if (llmv->ll_lslr != NULL)
+ OBD_FREE_LARGE(llmv->ll_lslr,
+ sizeof(struct lfsck_slave_lmv_rec) *
+ llmv->ll_stripes_allocated);
+
+ OBD_FREE_PTR(llmv);
+ }
+}
+
+static inline bool lfsck_is_valid_slave_lmv(struct lmv_mds_md_v1 *lmv)
+{
+ return lmv->lmv_stripe_count >= 1 &&
+ lmv->lmv_stripe_count <= LFSCK_LMV_MAX_STRIPES &&
+ lmv->lmv_stripe_count > lmv->lmv_master_mdt_index &&
+ lmv_is_known_hash_type(lmv->lmv_hash_type);
+}
+
+int lfsck_read_stripe_lmv(const struct lu_env *env, struct dt_object *obj,
+ struct lmv_mds_md_v1 *lmv)
+{
+ struct dt_object *bottom;
+ int rc;
+
+ /* Currently, we only store the LMV header on disk. It is the LOD's
+ * duty to iterate the master MDT-object's directory to compose the
+ * integrated LMV EA. But here, we only want to load the LMV header,
+ * so we need to bypass LOD to avoid unnecessary iteration in LOD. */
+ bottom = lu2dt(container_of0(obj->do_lu.lo_header->loh_layers.prev,
+ struct lu_object, lo_linkage));
+ if (unlikely(bottom == NULL))
+ return -ENOENT;
+
+ dt_read_lock(env, bottom, 0);
+ rc = dt_xattr_get(env, bottom, lfsck_buf_get(env, lmv, sizeof(*lmv)),
+ XATTR_NAME_LMV, BYPASS_CAPA);
+ dt_read_unlock(env, bottom);
+ if (rc != sizeof(*lmv))
+ return rc > 0 ? -EINVAL : rc;
+
+ lfsck_lmv_header_le_to_cpu(lmv, lmv);
+ if ((lmv->lmv_magic == LMV_MAGIC &&
+ !(lmv->lmv_hash_type & LMV_HASH_FLAG_MIGRATION)) ||
+ (lmv->lmv_magic == LMV_MAGIC_STRIPE &&
+ !(lmv->lmv_hash_type & LMV_HASH_FLAG_DEAD)))
+ return 0;
+
+ return -ENODATA;
+}
+
+/**
+ * Parse the shard's index from the given shard name.
+ *
+ * The valid shard name/type should be:
+ * 1) The type must be S_IFDIR
+ * 2) The name should be $FID:$index
+ * 3) the index should within valid range.
+ *
+ * \param[in] env pointer to the thread context
+ * \param[in] name the shard name
+ * \param[in] namelen the name length
+ * \param[in] type the entry's type
+ * \param[in] fid the entry's FID
+ *
+ * \retval zero or positive number for the index from the name
+ * \retval negative error number on failure
+ */
+int lfsck_shard_name_to_index(const struct lu_env *env, const char *name,
+ int namelen, __u16 type, const struct lu_fid *fid)
+{
+ char *name2 = lfsck_env_info(env)->lti_tmpbuf2;
+ int len;
+ int idx = 0;
+
+ if (!S_ISDIR(type))
+ return -ENOTDIR;
+
+ LASSERT(name != name2);
+
+ len = snprintf(name2, sizeof(lfsck_env_info(env)->lti_tmpbuf2),
+ DFID":", PFID(fid));
+ if (namelen < len + 1 || memcmp(name, name2, len) != 0)
+ return -EINVAL;
+
+ do {
+ if (!isdigit(name[len]))
+ return -EINVAL;
+
+ idx = idx * 10 + name[len++] - '0';
+ } while (len < namelen);
+
+ if (idx >= LFSCK_LMV_MAX_STRIPES)
+ return -EINVAL;
+
+ return idx;
+}
+
+bool lfsck_is_valid_slave_name_entry(const struct lu_env *env,
+ struct lfsck_lmv *llmv,
+ const char *name, int namelen)
+{
+ struct lmv_mds_md_v1 *lmv;
+ int idx;
+
+ if (llmv == NULL || !llmv->ll_lmv_slave || !llmv->ll_lmv_verified)
+ return true;
+
+ lmv = &llmv->ll_lmv;
+ idx = lmv_name_to_stripe_index(lmv->lmv_hash_type,
+ lmv->lmv_stripe_count,
+ name, namelen);
+ if (unlikely(idx != lmv->lmv_master_mdt_index))
+ return false;
+
+ return true;
+}
+
+/**
+ * Check whether the given name is a valid entry under the @parent.
+ *
+ * If the @parent is a striped directory then the @child should one
+ * shard of the striped directory, its name should be $FID:$index.
+ *
+ * If the @parent is a shard of a striped directory, then the name hash
+ * should match the MDT, otherwise it is invalid.
+ *
+ * \param[in] env pointer to the thread context
+ * \param[in] parent the parent directory
+ * \param[in] child the child object to be checked
+ * \param[in] cname the name for the @child in the parent directory
+ *
+ * \retval positive number for invalid name entry
+ * \retval 0 if the name is valid or uncertain
+ * \retval negative error number on failure
+ */
+int lfsck_namespace_check_name(const struct lu_env *env,
+ struct dt_object *parent,
+ struct dt_object *child,
+ const struct lu_name *cname)
+{
+ struct lmv_mds_md_v1 *lmv = &lfsck_env_info(env)->lti_lmv;
+ int idx;
+ int rc;
+
+ rc = lfsck_read_stripe_lmv(env, parent, lmv);
+ if (rc != 0)
+ RETURN(rc == -ENODATA ? 0 : rc);
+
+ if (lmv->lmv_magic == LMV_MAGIC_STRIPE) {
+ if (!lfsck_is_valid_slave_lmv(lmv))
+ return 0;
+
+ idx = lmv_name_to_stripe_index(lmv->lmv_hash_type,
+ lmv->lmv_stripe_count,
+ cname->ln_name,
+ cname->ln_namelen);
+ if (unlikely(idx != lmv->lmv_master_mdt_index))
+ return 1;
+ } else if (lfsck_shard_name_to_index(env, cname->ln_name,
+ cname->ln_namelen, lfsck_object_type(child),
+ lfsck_dto2fid(child)) < 0) {
+ return 1;
+ }
+
+ return 0;
+}
+
+int lfsck_namespace_verify_stripe_slave(const struct lu_env *env,
+ struct lfsck_component *com,
+ struct dt_object *obj,
+ struct lfsck_lmv *llmv)
+{
+ /* XXX: TBD */
+ return 0;
+}
/* Both migrating dir and unknown hash dir need to try
* all of sub-stripes */
- if (lsm != NULL && !lmv_is_known_hash_type(lsm)) {
+ if (lsm != NULL && !lmv_is_known_hash_type(lsm->lsm_md_hash_type)) {
struct lmv_oinfo *oinfo;
oinfo = &lsm->lsm_md_oinfo[0];
return sizeof(*lsm) + stripe_count * sizeof(lsm->lsm_md_oinfo[0]);
}
-int lmv_name_to_stripe_index(enum lmv_hash_type hashtype,
- unsigned int max_mdt_index,
- const char *name, int namelen);
-
static inline const struct lmv_oinfo *
lsm_name_to_stripe_info(const struct lmv_stripe_md *lsm, const char *name,
int namelen)
return &lsm->lsm_md_oinfo[stripe_index];
}
-static inline bool lmv_is_known_hash_type(const struct lmv_stripe_md *lsm)
-{
- return lsm->lsm_md_hash_type == LMV_HASH_TYPE_FNV_1A_64 ||
- lsm->lsm_md_hash_type == LMV_HASH_TYPE_ALL_CHARS;
-}
-
static inline bool lmv_need_try_all_stripes(const struct lmv_stripe_md *lsm)
{
- return !lmv_is_known_hash_type(lsm) ||
+ return !lmv_is_known_hash_type(lsm->lsm_md_hash_type) ||
lsm->lsm_md_hash_type & LMV_HASH_FLAG_MIGRATION;
}
#include <lustre_ioctl.h>
#include "lmv_internal.h"
-/* This hash is only for testing purpose */
-static inline unsigned int
-lmv_hash_all_chars(unsigned int count, const char *name, int namelen)
-{
- unsigned int c = 0;
- const unsigned char *p = (const unsigned char *)name;
-
- while (--namelen >= 0)
- c += p[namelen];
-
- c = c % count;
-
- return c;
-}
-
-static inline unsigned int
-lmv_hash_fnv1a(unsigned int count, const char *name, int namelen)
-{
- __u64 hash;
-
- hash = lustre_hash_fnv_1a_64(name, namelen);
-
- hash = hash % count;
-
- return hash;
-}
-
-int lmv_name_to_stripe_index(__u32 lmv_hash_type, unsigned int stripe_count,
- const char *name, int namelen)
-{
- int idx;
- __u32 hash_type = lmv_hash_type & LMV_HASH_TYPE_MASK;
-
- LASSERT(namelen > 0);
- if (stripe_count <= 1)
- return 0;
-
- /* for migrating object, always start from 0 stripe */
- if (lmv_hash_type & LMV_HASH_FLAG_MIGRATION)
- return 0;
-
- switch (hash_type) {
- case LMV_HASH_TYPE_ALL_CHARS:
- idx = lmv_hash_all_chars(stripe_count, name, namelen);
- break;
- case LMV_HASH_TYPE_FNV_1A_64:
- idx = lmv_hash_fnv1a(stripe_count, name, namelen);
- break;
- default:
- idx = -EBADFD;
- break;
- }
-
- CDEBUG(D_INFO, "name %.*s hash_type %d idx %d\n", namelen, name,
- hash_type, idx);
-
- return idx;
-}
-
static void lmv_activate_target(struct lmv_obd *lmv,
struct lmv_tgt_desc *tgt,
int activate)
* name from stripe 0, but migrating dir is already handled
* inside lmv_locate_target_for_name(), so we only check
* unknown hash type directory here */
- if (!lmv_is_known_hash_type(lsm)) {
+ if (!lmv_is_known_hash_type(lsm->lsm_md_hash_type)) {
struct lmv_oinfo *oinfo;
oinfo = &lsm->lsm_md_oinfo[stripe_index];
lustre_swab_lu_fid(&lr->lr_fid);
lustre_swab_lu_fid(&lr->lr_fid2);
lustre_swab_lu_fid(&lr->lr_fid3);
- CLASSERT(offsetof(typeof(*lr), lr_padding_2) != 0);
+ __swab32s(&lr->lr_stripe_count);
+ __swab32s(&lr->lr_hash_type);
CLASSERT(offsetof(typeof(*lr), lr_padding_3) != 0);
}
EXPORT_SYMBOL(lustre_swab_lfsck_request);
(long long)(int)offsetof(struct lfsck_request, lr_fid3));
LASSERTF((int)sizeof(((struct lfsck_request *)0)->lr_fid3) == 16, "found %lld\n",
(long long)(int)sizeof(((struct lfsck_request *)0)->lr_fid3));
- LASSERTF((int)offsetof(struct lfsck_request, lr_padding_2) == 80, "found %lld\n",
- (long long)(int)offsetof(struct lfsck_request, lr_padding_2));
- LASSERTF((int)sizeof(((struct lfsck_request *)0)->lr_padding_2) == 8, "found %lld\n",
- (long long)(int)sizeof(((struct lfsck_request *)0)->lr_padding_2));
+ LASSERTF((int)offsetof(struct lfsck_request, lr_stripe_count) == 80, "found %lld\n",
+ (long long)(int)offsetof(struct lfsck_request, lr_stripe_count));
+ LASSERTF((int)sizeof(((struct lfsck_request *)0)->lr_stripe_count) == 4, "found %lld\n",
+ (long long)(int)sizeof(((struct lfsck_request *)0)->lr_stripe_count));
+ LASSERTF((int)offsetof(struct lfsck_request, lr_hash_type) == 84, "found %lld\n",
+ (long long)(int)offsetof(struct lfsck_request, lr_hash_type));
+ LASSERTF((int)sizeof(((struct lfsck_request *)0)->lr_hash_type) == 4, "found %lld\n",
+ (long long)(int)sizeof(((struct lfsck_request *)0)->lr_hash_type));
LASSERTF((int)offsetof(struct lfsck_request, lr_padding_3) == 88, "found %lld\n",
(long long)(int)offsetof(struct lfsck_request, lr_padding_3));
LASSERTF((int)sizeof(((struct lfsck_request *)0)->lr_padding_3) == 8, "found %lld\n",
CHECK_MEMBER(lfsck_request, lr_fid);
CHECK_MEMBER(lfsck_request, lr_fid2);
CHECK_MEMBER(lfsck_request, lr_fid3);
- CHECK_MEMBER(lfsck_request, lr_padding_2);
+ CHECK_MEMBER(lfsck_request, lr_stripe_count);
+ CHECK_MEMBER(lfsck_request, lr_hash_type);
CHECK_MEMBER(lfsck_request, lr_padding_3);
CHECK_VALUE_X(LFSCK_TYPE_SCRUB);
(long long)(int)offsetof(struct lfsck_request, lr_fid3));
LASSERTF((int)sizeof(((struct lfsck_request *)0)->lr_fid3) == 16, "found %lld\n",
(long long)(int)sizeof(((struct lfsck_request *)0)->lr_fid3));
- LASSERTF((int)offsetof(struct lfsck_request, lr_padding_2) == 80, "found %lld\n",
- (long long)(int)offsetof(struct lfsck_request, lr_padding_2));
- LASSERTF((int)sizeof(((struct lfsck_request *)0)->lr_padding_2) == 8, "found %lld\n",
- (long long)(int)sizeof(((struct lfsck_request *)0)->lr_padding_2));
+ LASSERTF((int)offsetof(struct lfsck_request, lr_stripe_count) == 80, "found %lld\n",
+ (long long)(int)offsetof(struct lfsck_request, lr_stripe_count));
+ LASSERTF((int)sizeof(((struct lfsck_request *)0)->lr_stripe_count) == 4, "found %lld\n",
+ (long long)(int)sizeof(((struct lfsck_request *)0)->lr_stripe_count));
+ LASSERTF((int)offsetof(struct lfsck_request, lr_hash_type) == 84, "found %lld\n",
+ (long long)(int)offsetof(struct lfsck_request, lr_hash_type));
+ LASSERTF((int)sizeof(((struct lfsck_request *)0)->lr_hash_type) == 4, "found %lld\n",
+ (long long)(int)sizeof(((struct lfsck_request *)0)->lr_hash_type));
LASSERTF((int)offsetof(struct lfsck_request, lr_padding_3) == 88, "found %lld\n",
(long long)(int)offsetof(struct lfsck_request, lr_padding_3));
LASSERTF((int)sizeof(((struct lfsck_request *)0)->lr_padding_3) == 8, "found %lld\n",