Viewing: lfsck_layout.c
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2014, 2017, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
*
* Author: Fan, Yong <fan.yong@intel.com>
*/
#define DEBUG_SUBSYSTEM S_LFSCK
#include <linux/bitops.h>
#include <linux/rbtree.h>
#include <lu_object.h>
#include <dt_object.h>
#include <lustre_fid.h>
#include <lustre_lib.h>
#include <lustre_net.h>
#include <md_object.h>
#include <obd_class.h>
#include "lfsck_internal.h"
#define LFSCK_LAYOUT_MAGIC_V1 0xB173AE14
#define LFSCK_LAYOUT_MAGIC_V2 0xB1734D76
#define LFSCK_LAYOUT_MAGIC_V3 0xB17371B9
#define LFSCK_LAYOUT_MAGIC_V4 0xB1732FED
#define LFSCK_LAYOUT_MAGIC LFSCK_LAYOUT_MAGIC_V4
struct lfsck_layout_seq {
struct list_head lls_list;
__u64 lls_seq;
__u64 lls_lastid;
__u64 lls_lastid_known;
struct dt_object *lls_lastid_obj;
unsigned int lls_dirty:1;
};
struct lfsck_layout_slave_target {
/* link into lfsck_layout_slave_data::llsd_master_list. */
struct list_head llst_list;
/* The position for next record in the rbtree for iteration. */
struct lu_fid llst_fid;
/* Dummy hash for iteration against the rbtree. */
__u64 llst_hash;
__u64 llst_gen;
struct kref llst_ref;
__u32 llst_index;
/* How many times we have failed to get the master status. */
int llst_failures;
};
struct lfsck_layout_slave_data {
/* list for lfsck_layout_seq */
struct list_head llsd_seq_list;
/* list for the masters involve layout verification. */
struct list_head llsd_master_list;
spinlock_t llsd_lock;
__u64 llsd_touch_gen;
struct dt_object *llsd_rb_obj;
struct rb_root llsd_rb_root;
struct rw_semaphore llsd_rb_rwsem;
unsigned int llsd_rbtree_valid:1;
};
struct lfsck_layout_slave_async_args {
struct obd_export *llsaa_exp;
struct lfsck_component *llsaa_com;
struct lfsck_layout_slave_target *llsaa_llst;
};
static inline bool lfsck_comp_extent_aligned(__u64 border, __u32 size)
{
return (border & (size - 1)) == 0;
}
static inline void
lfsck_layout_llst_put(struct kref *kref)
{
struct lfsck_layout_slave_target *llst;
llst = container_of(kref, struct lfsck_layout_slave_target, llst_ref);
LASSERT(list_empty(&llst->llst_list));
OBD_FREE_PTR(llst);
}
static inline int
lfsck_layout_llst_add(struct lfsck_layout_slave_data *llsd, __u32 index)
{
struct lfsck_layout_slave_target *llst;
struct lfsck_layout_slave_target *tmp;
int rc = 0;
OBD_ALLOC_PTR(llst);
if (llst == NULL)
return -ENOMEM;
INIT_LIST_HEAD(&llst->llst_list);
llst->llst_gen = 0;
llst->llst_index = index;
kref_init(&llst->llst_ref);
spin_lock(&llsd->llsd_lock);
list_for_each_entry(tmp, &llsd->llsd_master_list, llst_list) {
if (tmp->llst_index == index) {
rc = -EALREADY;
break;
}
}
if (rc == 0)
list_add_tail(&llst->llst_list, &llsd->llsd_master_list);
spin_unlock(&llsd->llsd_lock);
if (rc != 0)
OBD_FREE_PTR(llst);
return rc;
}
static inline void
lfsck_layout_llst_del(struct lfsck_layout_slave_data *llsd,
struct lfsck_layout_slave_target *llst)
{
bool del = false;
spin_lock(&llsd->llsd_lock);
if (!list_empty(&llst->llst_list)) {
list_del_init(&llst->llst_list);
del = true;
}
spin_unlock(&llsd->llsd_lock);
if (del)
kref_put(&llst->llst_ref, lfsck_layout_llst_put);
}
static inline struct lfsck_layout_slave_target *
lfsck_layout_llst_find_and_del(struct lfsck_layout_slave_data *llsd,
__u32 index, bool unlink)
{
struct lfsck_layout_slave_target *llst;
spin_lock(&llsd->llsd_lock);
list_for_each_entry(llst, &llsd->llsd_master_list, llst_list) {
if (llst->llst_index == index) {
if (unlink)
list_del_init(&llst->llst_list);
else
kref_get(&llst->llst_ref);
spin_unlock(&llsd->llsd_lock);
return llst;
}
}
spin_unlock(&llsd->llsd_lock);
return NULL;
}
static struct lfsck_layout_req *
lfsck_layout_assistant_req_init(struct lfsck_assistant_object *lso,
struct dt_object *child, __u32 comp_id,
__u32 ost_idx, __u32 lov_idx)
{
struct lfsck_layout_req *llr;
OBD_ALLOC_PTR(llr);
if (llr == NULL)
return ERR_PTR(-ENOMEM);
INIT_LIST_HEAD(&llr->llr_lar.lar_list);
llr->llr_lar.lar_parent = lfsck_assistant_object_get(lso);
llr->llr_child = child;
llr->llr_comp_id = comp_id;
llr->llr_ost_idx = ost_idx;
llr->llr_lov_idx = lov_idx;
return llr;
}
static void lfsck_layout_assistant_req_fini(const struct lu_env *env,
struct lfsck_assistant_req *lar)
{
struct lfsck_layout_req *llr =
container_of(lar, struct lfsck_layout_req, llr_lar);
lfsck_object_put(env, llr->llr_child);
kref_put(&lar->lar_parent->lso_ref, lfsck_assistant_object_put);
OBD_FREE_PTR(llr);
}
static int
lfsck_layout_assistant_sync_failures_interpret(const struct lu_env *env,
struct ptlrpc_request *req,
void *args, int rc)
{
if (rc == 0) {
struct lfsck_async_interpret_args *laia = args;
struct lfsck_tgt_desc *ltd = laia->laia_ltd;
ltd->ltd_synced_failures = 1;
atomic_dec(laia->laia_count);
}
return 0;
}
/**
* lfsck_layout_assistant_sync_failures() - Notify remote LFSCK instances about
* former failures.
* @env: pointer to the thread context
* @com: pointer to the lfsck component
* @lr: pointer to the lfsck request
*
* The local LFSCK instance has recorded which OSTs have ever failed to respond
* some LFSCK verification requests (maybe because of network issues or the OST
* itself trouble). During the respond gap, the OST may missed some OST-objects
* verification, then the OST cannot know whether related OST-objects have been
* referenced by related MDT-objects or not, then in the second-stage scanning,
* these OST-objects will be regarded as orphan, if the OST-object contains bad
* parent FID for back reference, then it will misguide the LFSCK to make wrong
* fixing for the fake orphan.
*
* To avoid above trouble, when layout LFSCK finishes the first-stage scanning,
* it will scan the bitmap for the ever failed OSTs, and notify them that they
* have ever missed some OST-object verification and should skip the handling
* for orphan OST-objects on all MDTs that are in the layout LFSCK.
*/
static void lfsck_layout_assistant_sync_failures(const struct lu_env *env,
struct lfsck_component *com,
struct lfsck_request *lr)
{
struct lfsck_async_interpret_args *laia =
&lfsck_env_info(env)->lti_laia2;
struct lfsck_assistant_data *lad = com->lc_data;
struct lfsck_layout *lo = com->lc_file_ram;
struct lfsck_instance *lfsck = com->lc_lfsck;
struct lfsck_tgt_descs *ltds = &lfsck->li_ost_descs;
struct lfsck_tgt_desc *ltd;
struct ptlrpc_request_set *set;
atomic_t count;
__u32 idx;
int rc = 0;
ENTRY;
if (!test_bit(LAD_INCOMPLETE, &lad->lad_flags))
RETURN_EXIT;
/* If the MDT has ever failed to verfiy some OST-objects,
* then sync failures with them firstly.
*/
lr->lr_flags2 = lo->ll_flags | LF_INCOMPLETE;
atomic_set(&count, 0);
memset(laia, 0, sizeof(*laia));
laia->laia_count = &count;
set = ptlrpc_prep_set();
if (set == NULL)
GOTO(out, rc = -ENOMEM);
down_read(<ds->ltd_rw_sem);
for_each_set_bit(idx, lad->lad_bitmap, lad->lad_bitmap_count) {
ltd = lfsck_ltd2tgt(ltds, idx);
if (unlikely(!ltd))
continue;
laia->laia_ltd = ltd;
rc = lfsck_async_request(env, ltd->ltd_exp, lr, set,
lfsck_layout_assistant_sync_failures_interpret,
laia, LFSCK_NOTIFY);
if (rc != 0) {
CDEBUG(D_LFSCK,
"%s: LFSCK assistant fail to notify target %x for %s phase1 done: rc = %d\n",
lfsck_lfsck2name(com->lc_lfsck), ltd->ltd_index,
lad->lad_name, rc);
break;
}
atomic_inc(&count);
}
up_read(<ds->ltd_rw_sem);
if (rc == 0 && atomic_read(&count) > 0)
rc = ptlrpc_set_wait(env, set);
ptlrpc_set_destroy(set);
if (rc == 0 && atomic_read(&count) > 0)
rc = -EINVAL;
GOTO(out, rc);
out:
if (rc != 0)
/* If failed to sync failures with the OSTs, then have to
* mark the whole LFSCK as LF_INCOMPLETE to skip the whole
* subsequent orphan OST-object handling.
*/
lo->ll_flags |= LF_INCOMPLETE;
lr->lr_flags2 = lo->ll_flags;
}
static int lfsck_layout_verify_header_v1v3(struct dt_object *obj,
struct lov_mds_md_v1 *lmm,
__u64 start, __u64 end,
__u32 comp_id,
bool ext, bool *dom)
{
__u32 magic;
__u32 pattern;
__u32 size;
magic = le32_to_cpu(lmm->lmm_magic);
/* If magic crashed, keep it there. Sometime later, during OST-object
* orphan handling, if some OST-object(s) back-point to it, it can be
* verified and repaired.
*/
if (magic != LOV_MAGIC_V1 && magic != LOV_MAGIC_V3) {
int rc;
if ((magic & LOV_MAGIC_MASK) == LOV_MAGIC_MAGIC)
rc = -EOPNOTSUPP;
else
rc = -EINVAL;
CDEBUG(D_LFSCK, "%s LOV EA magic 0x%X for the file "DFID"\n",
rc == -EINVAL ? "Unknown" : "Unsupported",
magic, PFID(lfsck_dto2fid(obj)));
return rc;
}
pattern = le32_to_cpu(lmm->lmm_pattern);
*dom = !!(lov_pattern(pattern) & LOV_PATTERN_MDT);
/* XXX: DoM file verification will be supportted via LU-11081. */
if (lov_pattern(pattern) & LOV_PATTERN_MDT) {
#if 0
if (start != 0) {
CDEBUG(D_LFSCK,
"The DoM entry for "DFID" is not the first component in the mirror %x/%llu\n",
PFID(lfsck_dto2fid(obj)), comp_id, start);
return -EINVAL;
}
#endif
} else if (!lov_pattern_supported_normal_comp(lov_pattern(pattern))) {
CDEBUG(D_LFSCK,
"Unsupported LOV EA pattern %u for the file "DFID" in the component %x\n",
pattern, PFID(lfsck_dto2fid(obj)), comp_id);
return -EOPNOTSUPP;
}
size = le32_to_cpu(lmm->lmm_stripe_size);
if (!ext && end != LUSTRE_EOF && start != end &&
!lfsck_comp_extent_aligned(end, size)) {
CDEBUG(D_LFSCK,
"not aligned border in PFL extent range [%llu - %llu) stripesize %u for the file "DFID" at idx %d\n",
start, end, size, PFID(lfsck_dto2fid(obj)), comp_id);
return -EINVAL;
}
return 0;
}
static int lfsck_layout_verify_header_foreign(struct dt_object *obj,
struct lov_foreign_md *lfm,
size_t len)
{
/* magic has been verified already */
__u32 value_len = le32_to_cpu(lfm->lfm_length);
/* type and flags are not checked for instance */
CDEBUG(D_INFO,
"foreign LOV EA, magic %x, len %u, type %x, flags %x, for file "DFID"\n",
le32_to_cpu(lfm->lfm_magic), value_len,
le32_to_cpu(lfm->lfm_type), le32_to_cpu(lfm->lfm_flags),
PFID(lfsck_dto2fid(obj)));
if (len != value_len + offsetof(typeof(*lfm), lfm_value))
CDEBUG(D_LFSCK,
"foreign LOV EA internal size %u does not match EA full size %zu for file "DFID"\n",
value_len, len, PFID(lfsck_dto2fid(obj)));
/* nothing to repair */
return -ENODATA;
}
static int lfsck_layout_verify_header(struct dt_object *obj,
struct lov_mds_md_v1 *lmm, size_t len)
{
bool p_dom = false;
int rc = 0;
if (le32_to_cpu(lmm->lmm_magic) == LOV_MAGIC_COMP_V1 ||
le32_to_cpu(lmm->lmm_magic) == LOV_MAGIC_SEL) {
struct lov_comp_md_v1 *lcm = (struct lov_comp_md_v1 *)lmm;
bool p_zero = false;
int i;
__u16 count = le16_to_cpu(lcm->lcm_entry_count);
if (unlikely(count == 0)) {
CDEBUG(D_LFSCK,
"the PFL file "DFID" contains invalid components count 0\n",
PFID(lfsck_dto2fid(obj)));
return -EINVAL;
}
for (i = 0; i < count && !rc; i++) {
struct lov_comp_md_entry_v1 *lcme =
&lcm->lcm_entries[i];
__u64 start = le64_to_cpu(lcme->lcme_extent.e_start);
__u64 end = le64_to_cpu(lcme->lcme_extent.e_end);
__u32 comp_id = le32_to_cpu(lcme->lcme_id);
struct lov_mds_md_v1 *v1;
bool ext, inited, zero;
__u32 flags;
if (unlikely(comp_id == LCME_ID_INVAL ||
comp_id > LCME_ID_MAX)) {
CDEBUG(D_LFSCK,
"found invalid PFL ID %u for the file "DFID" at idx %d\n",
comp_id, PFID(lfsck_dto2fid(obj)), i);
return -EINVAL;
}
flags = le32_to_cpu(lcme->lcme_flags);
ext = flags & LCME_FL_EXTENSION;
inited = flags & LCME_FL_INIT;
zero = !!(start == end);
if ((i == 0) && zero) {
CDEBUG(D_LFSCK,
"invalid PFL comp %d: [%llu - %llu) for "DFID"\n",
i, start, end, PFID(lfsck_dto2fid(obj)));
return -EINVAL;
}
if ((zero && (inited || (i + 1 == count))) ||
(start > end)) {
CDEBUG(D_LFSCK,
"invalid PFL comp %d/%d: [%llu, %llu) for "DFID", %sinited\n",
i, count, start, end,
PFID(lfsck_dto2fid(obj)),
inited ? "" : "NOT ");
return -EINVAL;
}
if (!ext && p_zero) {
CDEBUG(D_LFSCK,
"invalid PFL comp %d: [%llu, %llu) for "DFID": NOT extension after 0-length component\n",
i, start, end, PFID(lfsck_dto2fid(obj)));
return -EINVAL;
}
if (ext && (inited || p_dom || zero)) {
CDEBUG(D_LFSCK,
"invalid PFL comp %d: [%llu, %llu) for "DFID": %s\n",
i, start, end, PFID(lfsck_dto2fid(obj)),
inited ? "inited extension" :
p_dom ? "extension follows DOM" :
zero ? "zero length extension" : "");
return -EINVAL;
}
v1 = (struct lov_mds_md_v1 *)((char *)lmm +
le32_to_cpu(lcme->lcme_offset));
if (le32_to_cpu(v1->lmm_magic) == LOV_MAGIC_FOREIGN)
rc = lfsck_layout_verify_header_foreign(
obj, (struct lov_foreign_md *)v1,
le32_to_cpu(lcme->lcme_size));
else
rc = lfsck_layout_verify_header_v1v3(obj, v1,
start, end, comp_id, ext, &p_dom);
p_zero = zero;
}
} else if (le32_to_cpu(lmm->lmm_magic) == LOV_MAGIC_FOREIGN) {
rc = lfsck_layout_verify_header_foreign(obj,
(struct lov_foreign_md *)lmm,
len);
} else {
rc = lfsck_layout_verify_header_v1v3(obj, lmm, 0, LUSTRE_EOF,
0, false, &p_dom);
}
return rc;
}
static int lfsck_layout_get_lovea(const struct lu_env *env,
struct dt_object *obj, struct lu_buf *buf)
{
int rc;
int rc1;
again:
rc = dt_xattr_get(env, obj, buf, XATTR_NAME_LOV);
if (rc == -ERANGE) {
rc = dt_xattr_get(env, obj, &LU_BUF_NULL, XATTR_NAME_LOV);
if (rc <= 0)
return !rc ? -ENODATA : rc;
lu_buf_realloc(buf, rc);
if (buf->lb_buf == NULL)
return -ENOMEM;
goto again;
}
if (rc <= 0)
return !rc ? -ENODATA : rc;
if (unlikely(buf->lb_buf == NULL)) {
lu_buf_alloc(buf, rc);
if (buf->lb_buf == NULL)
return -ENOMEM;
goto again;
}
rc1 = lfsck_layout_verify_header(obj, buf->lb_buf, rc);
return rc1 ? rc1 : rc;
}
#define LFSCK_RBTREE_BITMAP_SIZE PAGE_SIZE
#define LFSCK_RBTREE_BITMAP_WIDTH (LFSCK_RBTREE_BITMAP_SIZE << 3)
#define LFSCK_RBTREE_BITMAP_MASK (LFSCK_RBTREE_BITMAP_WIDTH - 1)
struct lfsck_rbtree_node {
struct rb_node lrn_node;
__u64 lrn_seq;
__u32 lrn_first_oid;
atomic_t lrn_known_count;
atomic_t lrn_accessed_count;
void *lrn_known_bitmap;
void *lrn_accessed_bitmap;
};
static inline int lfsck_rbtree_cmp(struct lfsck_rbtree_node *lrn,
__u64 seq, __u32 oid)
{
if (seq < lrn->lrn_seq)
return -1;
if (seq > lrn->lrn_seq)
return 1;
if (oid < lrn->lrn_first_oid)
return -1;
if (oid - lrn->lrn_first_oid >= LFSCK_RBTREE_BITMAP_WIDTH)
return 1;
return 0;
}
/* The caller should hold llsd->llsd_rb_lock. */
static struct lfsck_rbtree_node *
lfsck_rbtree_search(struct lfsck_layout_slave_data *llsd,
const struct lu_fid *fid, bool *exact)
{
struct rb_node *node = llsd->llsd_rb_root.rb_node;
struct rb_node *prev = NULL;
struct lfsck_rbtree_node *lrn = NULL;
int rc = 0;
if (exact != NULL)
*exact = true;
while (node != NULL) {
prev = node;
lrn = rb_entry(node, struct lfsck_rbtree_node, lrn_node);
rc = lfsck_rbtree_cmp(lrn, fid_seq(fid), fid_oid(fid));
if (rc < 0)
node = node->rb_left;
else if (rc > 0)
node = node->rb_right;
else
return lrn;
}
if (exact == NULL)
return NULL;
/* If there is no exactly matched one, then to the next valid one. */
*exact = false;
/* The rbtree is empty. */
if (rc == 0)
return NULL;
if (rc < 0)
return lrn;
node = rb_next(prev);
/* The end of the rbtree. */
if (node == NULL)
return NULL;
lrn = rb_entry(node, struct lfsck_rbtree_node, lrn_node);
return lrn;
}
static struct lfsck_rbtree_node *lfsck_rbtree_new(const struct lu_env *env,
const struct lu_fid *fid)
{
struct lfsck_rbtree_node *lrn;
OBD_ALLOC_PTR(lrn);
if (lrn == NULL)
return ERR_PTR(-ENOMEM);
OBD_ALLOC(lrn->lrn_known_bitmap, LFSCK_RBTREE_BITMAP_SIZE);
if (lrn->lrn_known_bitmap == NULL) {
OBD_FREE_PTR(lrn);
return ERR_PTR(-ENOMEM);
}
OBD_ALLOC(lrn->lrn_accessed_bitmap, LFSCK_RBTREE_BITMAP_SIZE);
if (lrn->lrn_accessed_bitmap == NULL) {
OBD_FREE(lrn->lrn_known_bitmap, LFSCK_RBTREE_BITMAP_SIZE);
OBD_FREE_PTR(lrn);
return ERR_PTR(-ENOMEM);
}
RB_CLEAR_NODE(&lrn->lrn_node);
lrn->lrn_seq = fid_seq(fid);
lrn->lrn_first_oid = fid_oid(fid) & ~LFSCK_RBTREE_BITMAP_MASK;
atomic_set(&lrn->lrn_known_count, 0);
atomic_set(&lrn->lrn_accessed_count, 0);
return lrn;
}
static void lfsck_rbtree_free(struct lfsck_rbtree_node *lrn)
{
OBD_FREE(lrn->lrn_accessed_bitmap, LFSCK_RBTREE_BITMAP_SIZE);
OBD_FREE(lrn->lrn_known_bitmap, LFSCK_RBTREE_BITMAP_SIZE);
OBD_FREE_PTR(lrn);
}
/* The caller should hold lock. */
static struct lfsck_rbtree_node *
lfsck_rbtree_insert(struct lfsck_layout_slave_data *llsd,
struct lfsck_rbtree_node *lrn)
{
struct rb_node **pos = &llsd->llsd_rb_root.rb_node;
struct rb_node *parent = NULL;
struct lfsck_rbtree_node *tmp;
int rc;
while (*pos != NULL) {
parent = *pos;
tmp = rb_entry(parent, struct lfsck_rbtree_node, lrn_node);
rc = lfsck_rbtree_cmp(tmp, lrn->lrn_seq, lrn->lrn_first_oid);
if (rc < 0)
pos = &(*pos)->rb_left;
else if (rc > 0)
pos = &(*pos)->rb_right;
else
return tmp;
}
rb_link_node(&lrn->lrn_node, parent, pos);
rb_insert_color(&lrn->lrn_node, &llsd->llsd_rb_root);
return lrn;
}
static const struct dt_index_operations lfsck_orphan_index_ops;
static int lfsck_rbtree_setup(const struct lu_env *env,
struct lfsck_component *com)
{
struct lu_fid *fid = &lfsck_env_info(env)->lti_fid;
struct lfsck_instance *lfsck = com->lc_lfsck;
struct dt_device *dev = lfsck->li_bottom;
struct lfsck_layout_slave_data *llsd = com->lc_data;
struct dt_object *obj;
fid->f_seq = FID_SEQ_LAYOUT_RBTREE;
fid->f_oid = lfsck_dev_idx(lfsck);
fid->f_ver = 0;
obj = dt_locate(env, dev, fid);
if (IS_ERR(obj))
RETURN(PTR_ERR(obj));
/* Generate an in-RAM object to stand for the layout rbtree.
* Scanning the layout rbtree will be via the iteration over
* the object. In the future, the rbtree may be written onto
* disk with the object.
*
* Mark the object to be as exist.
*/
obj->do_lu.lo_header->loh_attr |= LOHA_EXISTS;
obj->do_index_ops = &lfsck_orphan_index_ops;
llsd->llsd_rb_obj = obj;
llsd->llsd_rbtree_valid = 1;
dev->dd_record_fid_accessed = 1;
CDEBUG(D_LFSCK, "%s: layout LFSCK init OST-objects accessing bitmap\n",
lfsck_lfsck2name(lfsck));
return 0;
}
static void lfsck_rbtree_cleanup(const struct lu_env *env,
struct lfsck_component *com)
{
struct lfsck_instance *lfsck = com->lc_lfsck;
struct lfsck_layout_slave_data *llsd = com->lc_data;
struct rb_node *node = rb_first(&llsd->llsd_rb_root);
struct rb_node *next;
struct lfsck_rbtree_node *lrn;
lfsck->li_bottom->dd_record_fid_accessed = 0;
/* Invalid the rbtree, then no others will use it. */
down_write(&llsd->llsd_rb_rwsem);
llsd->llsd_rbtree_valid = 0;
up_write(&llsd->llsd_rb_rwsem);
while (node != NULL) {
next = rb_next(node);
lrn = rb_entry(node, struct lfsck_rbtree_node, lrn_node);
rb_erase(node, &llsd->llsd_rb_root);
lfsck_rbtree_free(lrn);
node = next;
}
if (llsd->llsd_rb_obj != NULL) {
lfsck_object_put(env, llsd->llsd_rb_obj);
llsd->llsd_rb_obj = NULL;
}
CDEBUG(D_LFSCK, "%s: layout LFSCK fini OST-objects accessing bitmap\n",
lfsck_lfsck2name(lfsck));
}
static void lfsck_rbtree_update_bitmap(const struct lu_env *env,
struct lfsck_component *com,
const struct lu_fid *fid,
bool accessed)
{
struct lfsck_layout_slave_data *llsd = com->lc_data;
struct lfsck_rbtree_node *lrn;
bool insert = false;
int idx;
int rc = 0;
ENTRY;
if (unlikely(!fid_is_sane(fid) || fid_is_last_id(fid)))
RETURN_EXIT;
if (!fid_is_idif(fid) && !fid_is_norm(fid))
RETURN_EXIT;
down_read(&llsd->llsd_rb_rwsem);
if (!llsd->llsd_rbtree_valid)
GOTO(unlock, rc = 0);
lrn = lfsck_rbtree_search(llsd, fid, NULL);
if (lrn == NULL) {
struct lfsck_rbtree_node *tmp;
LASSERT(!insert);
up_read(&llsd->llsd_rb_rwsem);
tmp = lfsck_rbtree_new(env, fid);
if (IS_ERR(tmp))
GOTO(out, rc = PTR_ERR(tmp));
insert = true;
down_write(&llsd->llsd_rb_rwsem);
if (!llsd->llsd_rbtree_valid) {
lfsck_rbtree_free(tmp);
GOTO(unlock, rc = 0);
}
lrn = lfsck_rbtree_insert(llsd, tmp);
if (lrn != tmp)
lfsck_rbtree_free(tmp);
}
idx = fid_oid(fid) & LFSCK_RBTREE_BITMAP_MASK;
/* Any accessed object must be a known object. */
if (!test_and_set_bit(idx, lrn->lrn_known_bitmap))
atomic_inc(&lrn->lrn_known_count);
if (accessed && !test_and_set_bit(idx, lrn->lrn_accessed_bitmap))
atomic_inc(&lrn->lrn_accessed_count);
GOTO(unlock, rc = 0);
unlock:
if (insert)
up_write(&llsd->llsd_rb_rwsem);
else
up_read(&llsd->llsd_rb_rwsem);
out:
if (rc != 0 && accessed) {
struct lfsck_layout *lo = com->lc_file_ram;
CDEBUG(D_LFSCK,
"%s: fail to update OST-objects accessing bitmap, and will cause incorrect LFSCK OST-object handling, so disable it to cancel orphan handling for related device. rc = %d\n",
lfsck_lfsck2name(com->lc_lfsck), rc);
lo->ll_flags |= LF_INCOMPLETE;
lfsck_rbtree_cleanup(env, com);
}
}
static inline void lldk_le_to_cpu(struct lfsck_layout_dangling_key *des,
const struct lfsck_layout_dangling_key *src)
{
fid_le_to_cpu(&des->lldk_fid, &src->lldk_fid);
des->lldk_comp_id = le32_to_cpu(src->lldk_comp_id);
des->lldk_ea_off = le32_to_cpu(src->lldk_ea_off);
}
static inline void lldk_cpu_to_le(struct lfsck_layout_dangling_key *des,
const struct lfsck_layout_dangling_key *src)
{
fid_cpu_to_le(&des->lldk_fid, &src->lldk_fid);
des->lldk_comp_id = cpu_to_le32(src->lldk_comp_id);
des->lldk_ea_off = cpu_to_le32(src->lldk_ea_off);
}
static inline void lldk_be_to_cpu(struct lfsck_layout_dangling_key *des,
const struct lfsck_layout_dangling_key *src)
{
fid_be_to_cpu(&des->lldk_fid, &src->lldk_fid);
des->lldk_comp_id = be32_to_cpu(src->lldk_comp_id);
des->lldk_ea_off = be32_to_cpu(src->lldk_ea_off);
}
static inline void lldk_cpu_to_be(struct lfsck_layout_dangling_key *des,
const struct lfsck_layout_dangling_key *src)
{
fid_cpu_to_be(&des->lldk_fid, &src->lldk_fid);
des->lldk_comp_id = cpu_to_be32(src->lldk_comp_id);
des->lldk_ea_off = cpu_to_be32(src->lldk_ea_off);
}
static void lfsck_layout_le_to_cpu(struct lfsck_layout *des,
const struct lfsck_layout *src)
{
int i;
des->ll_magic = le32_to_cpu(src->ll_magic);
des->ll_status = le32_to_cpu(src->ll_status);
des->ll_flags = le32_to_cpu(src->ll_flags);
des->ll_success_count = le32_to_cpu(src->ll_success_count);
des->ll_run_time_phase1 = le64_to_cpu(src->ll_run_time_phase1);
des->ll_run_time_phase2 = le64_to_cpu(src->ll_run_time_phase2);
des->ll_time_last_complete = le64_to_cpu(src->ll_time_last_complete);
des->ll_time_latest_start = le64_to_cpu(src->ll_time_latest_start);
des->ll_time_last_checkpoint =
le64_to_cpu(src->ll_time_last_checkpoint);
des->ll_pos_latest_start = le64_to_cpu(src->ll_pos_latest_start);
des->ll_pos_last_checkpoint = le64_to_cpu(src->ll_pos_last_checkpoint);
des->ll_pos_first_inconsistent =
le64_to_cpu(src->ll_pos_first_inconsistent);
des->ll_objs_checked_phase1 = le64_to_cpu(src->ll_objs_checked_phase1);
des->ll_objs_failed_phase1 = le64_to_cpu(src->ll_objs_failed_phase1);
des->ll_objs_checked_phase2 = le64_to_cpu(src->ll_objs_checked_phase2);
des->ll_objs_failed_phase2 = le64_to_cpu(src->ll_objs_failed_phase2);
for (i = 0; i < LLIT_MAX; i++)
des->ll_objs_repaired[i] =
le64_to_cpu(src->ll_objs_repaired[i]);
des->ll_objs_skipped = le64_to_cpu(src->ll_objs_skipped);
des->ll_bitmap_size = le32_to_cpu(src->ll_bitmap_size);
lldk_le_to_cpu(&des->ll_lldk_latest_scanned_phase2,
&src->ll_lldk_latest_scanned_phase2);
}
static void lfsck_layout_cpu_to_le(struct lfsck_layout *des,
const struct lfsck_layout *src)
{
int i;
des->ll_magic = cpu_to_le32(src->ll_magic);
des->ll_status = cpu_to_le32(src->ll_status);
des->ll_flags = cpu_to_le32(src->ll_flags);
des->ll_success_count = cpu_to_le32(src->ll_success_count);
des->ll_run_time_phase1 = cpu_to_le64(src->ll_run_time_phase1);
des->ll_run_time_phase2 = cpu_to_le64(src->ll_run_time_phase2);
des->ll_time_last_complete = cpu_to_le64(src->ll_time_last_complete);
des->ll_time_latest_start = cpu_to_le64(src->ll_time_latest_start);
des->ll_time_last_checkpoint =
cpu_to_le64(src->ll_time_last_checkpoint);
des->ll_pos_latest_start = cpu_to_le64(src->ll_pos_latest_start);
des->ll_pos_last_checkpoint = cpu_to_le64(src->ll_pos_last_checkpoint);
des->ll_pos_first_inconsistent =
cpu_to_le64(src->ll_pos_first_inconsistent);
des->ll_objs_checked_phase1 = cpu_to_le64(src->ll_objs_checked_phase1);
des->ll_objs_failed_phase1 = cpu_to_le64(src->ll_objs_failed_phase1);
des->ll_objs_checked_phase2 = cpu_to_le64(src->ll_objs_checked_phase2);
des->ll_objs_failed_phase2 = cpu_to_le64(src->ll_objs_failed_phase2);
for (i = 0; i < LLIT_MAX; i++)
des->ll_objs_repaired[i] =
cpu_to_le64(src->ll_objs_repaired[i]);
des->ll_objs_skipped = cpu_to_le64(src->ll_objs_skipped);
des->ll_bitmap_size = cpu_to_le32(src->ll_bitmap_size);
lldk_cpu_to_le(&des->ll_lldk_latest_scanned_phase2,
&src->ll_lldk_latest_scanned_phase2);
}
/**
* lfsck_layout_load_bitmap() - Load the OST bitmap from the lfsck_layout trace
* file.
* @env: pointer to the thread context
* @com: pointer to the lfsck component
*
* Return:
* * %0 for success
* * %negative error number on failure or data corruption
*/
static int lfsck_layout_load_bitmap(const struct lu_env *env,
struct lfsck_component *com)
{
struct dt_object *obj = com->lc_obj;
struct lfsck_assistant_data *lad = com->lc_data;
struct lfsck_layout *lo = com->lc_file_ram;
unsigned long *bitmap = lad->lad_bitmap;
loff_t pos = com->lc_file_size;
ssize_t size;
__u32 nbits;
int rc;
ENTRY;
if (com->lc_lfsck->li_ost_descs.ltd_tgts_mask_len > lo->ll_bitmap_size)
nbits = com->lc_lfsck->li_ost_descs.ltd_tgts_mask_len;
else
nbits = lo->ll_bitmap_size;
if (unlikely(nbits < BITS_PER_LONG))
nbits = BITS_PER_LONG;
if (nbits > lad->lad_bitmap_count) {
u32 new_bits = lad->lad_bitmap_count;
unsigned long *new_bitmap;
while (new_bits < nbits)
new_bits <<= 1;
new_bitmap = bitmap_zalloc(new_bits, GFP_KERNEL);
if (new_bitmap == NULL)
RETURN(-ENOMEM);
lad->lad_bitmap = new_bitmap;
lad->lad_bitmap_count = new_bits;
bitmap_free(bitmap);
bitmap = new_bitmap;
}
if (lo->ll_bitmap_size == 0) {
clear_bit(LAD_INCOMPLETE, &lad->lad_flags);
bitmap_zero(bitmap, lad->lad_bitmap_count);
RETURN(0);
}
size = (lo->ll_bitmap_size + 7) >> 3;
rc = dt_read(env, obj, lfsck_buf_get(env, bitmap, size), &pos);
if (rc != size)
RETURN(rc >= 0 ? -EINVAL : rc);
if (bitmap_empty(bitmap, lad->lad_bitmap_count))
clear_bit(LAD_INCOMPLETE, &lad->lad_flags);
else
set_bit(LAD_INCOMPLETE, &lad->lad_flags);
RETURN(0);
}
/**
* lfsck_layout_load() - Load the layout LFSCK trace file from disk.
* @env: pointer to the thread context
* @com: pointer to the lfsck component
*
* The layout LFSCK trace file records the layout LFSCK status information
* and other statistics, such as how many objects have been scanned, and how
* many objects have been repaired, and etc. It also contains the bitmap for
* failed OSTs during the layout LFSCK. All these information will be loaded
* from disk to RAM when the layout LFSCK component setup.
*
* Return:
* * %positive number for file data corruption, the caller should reset the
* layout LFSCK trace file
* * %0 for success
* * %negative error number on failure
*/
static int lfsck_layout_load(const struct lu_env *env,
struct lfsck_component *com)
{
struct lfsck_layout *lo = com->lc_file_ram;
ssize_t size = com->lc_file_size;
loff_t pos = 0;
int rc;
rc = dt_read(env, com->lc_obj,
lfsck_buf_get(env, com->lc_file_disk, size), &pos);
if (rc == 0) {
return -ENOENT;
} else if (rc < 0) {
CDEBUG(D_LFSCK, "%s: failed to load lfsck_layout: rc = %d\n",
lfsck_lfsck2name(com->lc_lfsck), rc);
return rc;
} else if (rc != size) {
CDEBUG(D_LFSCK, "%s: lfsck_layout size %u != %u; reset it\n",
lfsck_lfsck2name(com->lc_lfsck), rc, (unsigned int)size);
return 1;
}
lfsck_layout_le_to_cpu(lo, com->lc_file_disk);
if (lo->ll_magic != LFSCK_LAYOUT_MAGIC) {
CDEBUG(D_LFSCK,
"%s: invalid lfsck_layout magic %#x != %#x, to be reset\n",
lfsck_lfsck2name(com->lc_lfsck), lo->ll_magic,
LFSCK_LAYOUT_MAGIC);
return 1;
}
return 0;
}
/**
* lfsck_layout_store() - Store the layout LFSCK trace file on disk.
* @env: pointer to the thread context
* @com: pointer to the lfsck component
*
* The layout LFSCK trace file records the layout LFSCK status information
* and other statistics, such as how many objects have been scanned, and how
* many objects have been repaired, and etc. It also contains the bitmap for
* failed OSTs during the layout LFSCK. All these information will be synced
* from RAM to disk periodically.
*
* Return:
* * %0 for success
* * %negative error number on failure
*/
static int lfsck_layout_store(const struct lu_env *env,
struct lfsck_component *com)
{
struct dt_object *obj = com->lc_obj;
struct lfsck_instance *lfsck = com->lc_lfsck;
struct lfsck_layout *lo_ram = com->lc_file_ram;
struct lfsck_layout *lo = com->lc_file_disk;
struct thandle *th;
struct dt_device *dev = lfsck_obj2dev(obj);
unsigned long *bitmap = NULL;
loff_t pos;
ssize_t size = com->lc_file_size;
__u32 nbits = 0;
int rc;
ENTRY;
if (lfsck->li_master) {
struct lfsck_assistant_data *lad = com->lc_data;
bitmap = lad->lad_bitmap;
nbits = lad->lad_bitmap_count;
LASSERT(nbits > 0);
LASSERTF((nbits & 7) == 0, "Invalid nbits %u\n", nbits);
}
lo_ram->ll_bitmap_size = nbits;
lfsck_layout_cpu_to_le(lo, lo_ram);
th = dt_trans_create(env, dev);
if (IS_ERR(th))
GOTO(log, rc = PTR_ERR(th));
rc = dt_declare_record_write(env, obj, lfsck_buf_get(env, lo, size),
(loff_t)0, th);
if (rc != 0)
GOTO(out, rc);
if (bitmap != NULL) {
rc = dt_declare_record_write(env, obj,
lfsck_buf_get(env, bitmap, nbits >> 3),
(loff_t)size, th);
if (rc != 0)
GOTO(out, rc);
}
rc = dt_trans_start_local(env, dev, th);
if (rc != 0)
GOTO(out, rc);
pos = 0;
rc = dt_record_write(env, obj, lfsck_buf_get(env, lo, size), &pos, th);
if (rc != 0)
GOTO(out, rc);
if (bitmap != NULL) {
pos = size;
rc = dt_record_write(env, obj,
lfsck_buf_get(env, bitmap, nbits >> 3),
&pos, th);
}
GOTO(out, rc);
out:
dt_trans_stop(env, dev, th);
log:
if (rc != 0)
CDEBUG(D_LFSCK, "%s: fail to store lfsck_layout: rc = %d\n",
lfsck_lfsck2name(lfsck), rc);
return rc;
}
static int lfsck_layout_init(const struct lu_env *env,
struct lfsck_component *com)
{
struct lfsck_layout *lo = com->lc_file_ram;
int rc;
memset(lo, 0, com->lc_file_size);
lo->ll_magic = LFSCK_LAYOUT_MAGIC;
lo->ll_status = LS_INIT;
down_write(&com->lc_sem);
rc = lfsck_layout_store(env, com);
if (rc == 0 && com->lc_lfsck->li_master)
rc = lfsck_load_sub_trace_files(env, com,
&dt_lfsck_layout_dangling_features, LFSCK_LAYOUT, true);
up_write(&com->lc_sem);
return rc;
}
static int fid_is_for_ostobj(const struct lu_env *env,
struct lfsck_instance *lfsck,
struct dt_object *obj, const struct lu_fid *fid)
{
struct seq_server_site *ss = lfsck_dev_site(lfsck);
struct lu_seq_range *range = &lfsck_env_info(env)->lti_range;
struct lustre_ost_attrs *loa;
int rc;
fld_range_set_any(range);
rc = fld_server_lookup(env, ss->ss_server_fld, fid_seq(fid), range);
if (rc == 0) {
if (fld_range_is_ost(range))
return 1;
return 0;
}
loa = &lfsck_env_info(env)->lti_loa;
rc = dt_xattr_get(env, obj, lfsck_buf_get(env, loa, sizeof(*loa)),
XATTR_NAME_LMA);
if (rc >= (int)sizeof(struct lustre_mdt_attrs)) {
lustre_lma_swab(&loa->loa_lma);
return loa->loa_lma.lma_compat & LMAC_FID_ON_OST ? 1 : 0;
}
rc = dt_xattr_get(env, obj, &LU_BUF_NULL, XATTR_NAME_FID);
return rc > 0;
}
static struct lfsck_layout_seq *
lfsck_layout_seq_lookup(struct lfsck_layout_slave_data *llsd, __u64 seq)
{
struct lfsck_layout_seq *lls;
list_for_each_entry(lls, &llsd->llsd_seq_list, lls_list) {
if (lls->lls_seq == seq)
return lls;
if (lls->lls_seq > seq)
return NULL;
}
return NULL;
}
static void
lfsck_layout_seq_insert(struct lfsck_layout_slave_data *llsd,
struct lfsck_layout_seq *lls)
{
struct lfsck_layout_seq *tmp;
struct list_head *pos = &llsd->llsd_seq_list;
list_for_each_entry(tmp, &llsd->llsd_seq_list, lls_list) {
if (lls->lls_seq < tmp->lls_seq) {
pos = &tmp->lls_list;
break;
}
}
list_add_tail(&lls->lls_list, pos);
}
static int
lfsck_layout_lastid_create(const struct lu_env *env,
struct lfsck_instance *lfsck,
struct dt_object *obj)
{
struct lfsck_thread_info *info = lfsck_env_info(env);
struct lu_attr *la = &info->lti_la;
struct dt_object_format *dof = &info->lti_dof;
struct lfsck_bookmark *bk = &lfsck->li_bookmark_ram;
struct dt_device *dt = lfsck_obj2dev(obj);
struct thandle *th;
__u64 lastid = 0;
loff_t pos = 0;
int rc;
ENTRY;
if (bk->lb_param & LPF_DRYRUN)
return 0;
memset(la, 0, sizeof(*la));
la->la_mode = S_IFREG | 0644;
la->la_valid = LA_MODE | LA_UID | LA_GID;
memset(dof, 0, sizeof(*dof));
dof->dof_type = dt_mode_to_dft(S_IFREG);
th = lfsck_trans_create(env, dt, lfsck);
if (IS_ERR(th))
GOTO(log, rc = PTR_ERR(th));
rc = dt_declare_create(env, obj, la, NULL, dof, th);
if (rc != 0)
GOTO(stop, rc);
rc = dt_declare_record_write(env, obj,
lfsck_buf_get(env, &lastid,
sizeof(lastid)),
pos, th);
if (rc != 0)
GOTO(stop, rc);
rc = dt_trans_start_local(env, dt, th);
if (rc != 0)
GOTO(stop, rc);
dt_write_lock(env, obj, 0);
if (likely(dt_object_exists(obj) == 0)) {
rc = dt_create(env, obj, la, NULL, dof, th);
if (rc == 0)
rc = dt_record_write(env, obj,
lfsck_buf_get(env, &lastid, sizeof(lastid)),
&pos, th);
}
dt_write_unlock(env, obj);
GOTO(stop, rc);
stop:
dt_trans_stop(env, dt, th);
log:
CDEBUG(D_LFSCK,
"%s: layout LFSCK will create LAST_ID for <seq> %#llx: rc = %d\n",
lfsck_lfsck2name(lfsck), fid_seq(lfsck_dto2fid(obj)), rc);
return rc;
}
static int
lfsck_layout_lastid_reload(const struct lu_env *env,
struct lfsck_component *com,
struct lfsck_layout_seq *lls)
{
__u64 lastid;
loff_t pos = 0;
int rc;
dt_read_lock(env, lls->lls_lastid_obj, 0);
rc = dt_record_read(env, lls->lls_lastid_obj,
lfsck_buf_get(env, &lastid, sizeof(lastid)), &pos);
dt_read_unlock(env, lls->lls_lastid_obj);
if (unlikely(rc != 0))
return rc;
lastid = le64_to_cpu(lastid);
if (lastid < lls->lls_lastid_known) {
struct lfsck_instance *lfsck = com->lc_lfsck;
struct lfsck_layout *lo = com->lc_file_ram;
lls->lls_lastid = lls->lls_lastid_known;
lls->lls_dirty = 1;
if (!(lo->ll_flags & LF_CRASHED_LASTID)) {
LASSERT(lfsck->li_out_notify != NULL);
lfsck->li_out_notify(env, lfsck->li_out_notify_data,
LE_LASTID_REBUILDING);
lo->ll_flags |= LF_CRASHED_LASTID;
CDEBUG(D_LFSCK,
"%s: layout LFSCK finds crashed LAST_ID file (1) for the sequence %#llx, old value %llu, known value %llu\n",
lfsck_lfsck2name(lfsck), lls->lls_seq,
lastid, lls->lls_lastid);
}
} else if (lastid >= lls->lls_lastid) {
lls->lls_lastid = lastid;
lls->lls_dirty = 0;
}
return 0;
}
static int
lfsck_layout_lastid_store(const struct lu_env *env,
struct lfsck_component *com)
{
struct lfsck_instance *lfsck = com->lc_lfsck;
struct lfsck_bookmark *bk = &lfsck->li_bookmark_ram;
struct dt_device *dt = lfsck->li_bottom;
struct lfsck_layout_slave_data *llsd = com->lc_data;
struct lfsck_layout_seq *lls;
struct thandle *th;
__u64 lastid;
int rc = 0;
int rc1 = 0;
list_for_each_entry(lls, &llsd->llsd_seq_list, lls_list) {
loff_t pos = 0;
if (!lls->lls_dirty)
continue;
CDEBUG(D_LFSCK,
"%s: layout LFSCK will sync the LAST_ID for <seq> %#llx as <oid> %llu\n",
lfsck_lfsck2name(lfsck), lls->lls_seq, lls->lls_lastid);
if (bk->lb_param & LPF_DRYRUN) {
lls->lls_dirty = 0;
continue;
}
th = lfsck_trans_create(env, dt, lfsck);
if (IS_ERR(th)) {
rc1 = PTR_ERR(th);
CDEBUG(D_LFSCK,
"%s: layout LFSCK failed to store the LAST_ID for <seq> %#llx(1): rc = %d\n",
lfsck_lfsck2name(com->lc_lfsck),
lls->lls_seq, rc1);
continue;
}
lastid = cpu_to_le64(lls->lls_lastid);
rc = dt_declare_record_write(env, lls->lls_lastid_obj,
lfsck_buf_get(env, &lastid,
sizeof(lastid)),
pos, th);
if (rc != 0)
goto stop;
rc = dt_trans_start_local(env, dt, th);
if (rc != 0)
goto stop;
dt_write_lock(env, lls->lls_lastid_obj, 0);
rc = dt_record_write(env, lls->lls_lastid_obj,
lfsck_buf_get(env, &lastid,
sizeof(lastid)), &pos, th);
dt_write_unlock(env, lls->lls_lastid_obj);
if (rc == 0)
lls->lls_dirty = 0;
stop:
dt_trans_stop(env, dt, th);
if (rc != 0) {
rc1 = rc;
CDEBUG(D_LFSCK,
"%s: layout LFSCK failed to store the LAST_ID for <seq> %#llx(2): rc = %d\n",
lfsck_lfsck2name(com->lc_lfsck),
lls->lls_seq, rc1);
}
}
return rc1;
}
static int
lfsck_layout_lastid_load(const struct lu_env *env,
struct lfsck_component *com,
struct lfsck_layout_seq *lls)
{
struct lfsck_instance *lfsck = com->lc_lfsck;
struct lfsck_layout *lo = com->lc_file_ram;
struct lu_fid *fid = &lfsck_env_info(env)->lti_fid;
struct dt_object *obj;
loff_t pos = 0;
int rc;
ENTRY;
lu_last_id_fid(fid, lls->lls_seq, lfsck_dev_idx(lfsck));
obj = dt_locate(env, lfsck->li_bottom, fid);
if (IS_ERR(obj))
RETURN(PTR_ERR(obj));
/* LAST_ID crashed, to be rebuilt */
if (dt_object_exists(obj) == 0) {
if (!(lo->ll_flags & LF_CRASHED_LASTID)) {
LASSERT(lfsck->li_out_notify != NULL);
lfsck->li_out_notify(env, lfsck->li_out_notify_data,
LE_LASTID_REBUILDING);
lo->ll_flags |= LF_CRASHED_LASTID;
CDEBUG(D_LFSCK,
"%s: layout LFSCK cannot find the LAST_ID file for sequence %#llx\n",
lfsck_lfsck2name(lfsck), lls->lls_seq);
if (CFS_FAIL_CHECK(OBD_FAIL_LFSCK_DELAY4) &&
cfs_fail_val > 0) {
up_write(&com->lc_sem);
wait_var_event_timeout(lfsck,
lfsck_should_stop(lfsck),
cfs_time_seconds(cfs_fail_val));
down_write(&com->lc_sem);
}
}
rc = lfsck_layout_lastid_create(env, lfsck, obj);
} else {
dt_read_lock(env, obj, 0);
rc = dt_read(env, obj,
lfsck_buf_get(env, &lls->lls_lastid, sizeof(__u64)),
&pos);
dt_read_unlock(env, obj);
if (rc != 0 && rc != sizeof(__u64))
GOTO(out, rc = (rc > 0 ? -EFAULT : rc));
if (rc == 0 && !(lo->ll_flags & LF_CRASHED_LASTID)) {
LASSERT(lfsck->li_out_notify != NULL);
lfsck->li_out_notify(env, lfsck->li_out_notify_data,
LE_LASTID_REBUILDING);
lo->ll_flags |= LF_CRASHED_LASTID;
CDEBUG(D_LFSCK,
"%s: layout LFSCK finds invalid LAST_ID file for the sequence %#llx: rc = %d\n",
lfsck_lfsck2name(lfsck), lls->lls_seq, rc);
}
lls->lls_lastid = le64_to_cpu(lls->lls_lastid);
rc = 0;
}
GOTO(out, rc);
out:
if (rc != 0)
lfsck_object_put(env, obj);
else
lls->lls_lastid_obj = obj;
return rc;
}
static void lfsck_layout_record_failure(const struct lu_env *env,
struct lfsck_instance *lfsck,
struct lfsck_layout *lo)
{
__u64 cookie;
lo->ll_objs_failed_phase1++;
cookie = lfsck->li_obj_oit->do_index_ops->dio_it.store(env,
lfsck->li_di_oit);
if (lo->ll_pos_first_inconsistent == 0 ||
lo->ll_pos_first_inconsistent < cookie) {
lo->ll_pos_first_inconsistent = cookie;
CDEBUG(D_LFSCK,
"%s: layout LFSCK hit first non-repaired inconsistency at the pos [%llu]\n",
lfsck_lfsck2name(lfsck),
lo->ll_pos_first_inconsistent);
}
}
static int lfsck_layout_double_scan_result(const struct lu_env *env,
struct lfsck_component *com,
int rc)
{
struct lfsck_instance *lfsck = com->lc_lfsck;
struct lfsck_layout *lo = com->lc_file_ram;
CDEBUG(D_LFSCK, "%s: layout LFSCK double scan: rc = %d\n",
lfsck_lfsck2name(lfsck), rc);
down_write(&com->lc_sem);
lo->ll_run_time_phase2 += ktime_get_seconds() -
com->lc_time_last_checkpoint;
lo->ll_time_last_checkpoint = ktime_get_real_seconds();
lo->ll_objs_checked_phase2 += com->lc_new_checked;
if (rc > 0) {
if (lo->ll_flags & LF_INCOMPLETE) {
lo->ll_status = LS_PARTIAL;
} else {
if (lfsck->li_master) {
struct lfsck_assistant_data *lad = com->lc_data;
if (test_bit(LAD_INCOMPLETE, &lad->lad_flags))
lo->ll_status = LS_PARTIAL;
else
lo->ll_status = LS_COMPLETED;
} else {
lo->ll_status = LS_COMPLETED;
}
}
lo->ll_flags &= ~LF_SCANNED_ONCE;
if (!(lfsck->li_bookmark_ram.lb_param & LPF_DRYRUN))
lo->ll_flags &= ~LF_INCONSISTENT;
lo->ll_time_last_complete = lo->ll_time_last_checkpoint;
lo->ll_success_count++;
} else if (rc == 0) {
if (lfsck->li_status != 0)
lo->ll_status = lfsck->li_status;
else
lo->ll_status = LS_STOPPED;
} else {
lo->ll_status = LS_FAILED;
}
rc = lfsck_layout_store(env, com);
up_write(&com->lc_sem);
CDEBUG(D_LFSCK, "%s: layout LFSCK double scan result %u: rc = %d\n",
lfsck_lfsck2name(lfsck), lo->ll_status, rc);
return rc;
}
static int lfsck_layout_trans_stop(const struct lu_env *env,
struct dt_device *dev,
struct thandle *handle, int result)
{
int rc;
/* XXX: If there is something worng or it needs to repair nothing,
* then notify the lower to stop the modification. Currently,
* we use th_result for such purpose, that may be replaced by
* some rollback mechanism in the future.
*/
handle->th_result = result;
rc = dt_trans_stop(env, dev, handle);
if (result != 0)
return result > 0 ? 0 : result;
return rc == 0 ? 1 : rc;
}
static int lfsck_layout_ins_dangling_rec(const struct lu_env *env,
struct lfsck_component *com,
const struct lu_fid *pfid,
const struct lu_fid *cfid,
__u32 comp_id, __u32 ea_off,
__u32 ost_idx)
{
struct lfsck_layout_dangling_key *key = &lfsck_env_info(env)->lti_lldk;
struct lu_fid *rec = &lfsck_env_info(env)->lti_fid3;
struct dt_device *dev;
struct dt_object *obj;
struct thandle *th = NULL;
int idx;
int rc = 0;
ENTRY;
if (com->lc_lfsck->li_bookmark_ram.lb_param & LPF_DRYRUN)
GOTO(log, rc = 0);
idx = lfsck_sub_trace_file_fid2idx(pfid);
obj = com->lc_sub_trace_objs[idx].lsto_obj;
dev = lfsck_obj2dev(obj);
fid_cpu_to_be(&key->lldk_fid, pfid);
key->lldk_comp_id = cpu_to_be32(comp_id);
key->lldk_ea_off = cpu_to_be32(ea_off);
fid_cpu_to_be(rec, cfid);
rec->f_ver = cpu_to_be32(ost_idx);
mutex_lock(&com->lc_sub_trace_objs[idx].lsto_mutex);
th = lfsck_trans_create(env, dev, com->lc_lfsck);
if (IS_ERR(th))
GOTO(unlock, rc = PTR_ERR(th));
rc = dt_declare_insert(env, obj,
(const struct dt_rec *)rec,
(const struct dt_key *)key, th);
if (rc)
GOTO(unlock, rc);
rc = dt_trans_start_local(env, dev, th);
if (rc)
GOTO(unlock, rc);
rc = dt_insert(env, obj, (const struct dt_rec *)rec,
(const struct dt_key *)key, th);
GOTO(unlock, rc);
unlock:
if (th && !IS_ERR(th))
dt_trans_stop(env, dev, th);
mutex_unlock(&com->lc_sub_trace_objs[idx].lsto_mutex);
log:
CDEBUG(D_LFSCK,
"%s: insert the paris "DFID" => "DFID", comp_id = %u, ea_off = %u, ost_idx = %u, into the trace file for further dangling check: rc = %d\n",
lfsck_lfsck2name(com->lc_lfsck), PFID(pfid), PFID(cfid), comp_id,
ea_off, ost_idx, rc);
return rc;
}
static int lfsck_layout_del_dangling_rec(const struct lu_env *env,
struct lfsck_component *com,
const struct lu_fid *fid,
__u32 comp_id, __u32 ea_off)
{
struct lfsck_layout_dangling_key *key = &lfsck_env_info(env)->lti_lldk;
struct dt_device *dev;
struct dt_object *obj;
struct thandle *th = NULL;
int idx;
int rc = 0;
ENTRY;
if (com->lc_lfsck->li_bookmark_ram.lb_param & LPF_DRYRUN)
GOTO(log, rc = 0);
idx = lfsck_sub_trace_file_fid2idx(fid);
obj = com->lc_sub_trace_objs[idx].lsto_obj;
dev = lfsck_obj2dev(obj);
fid_cpu_to_be(&key->lldk_fid, fid);
key->lldk_comp_id = cpu_to_be32(comp_id);
key->lldk_ea_off = cpu_to_be32(ea_off);
mutex_lock(&com->lc_sub_trace_objs[idx].lsto_mutex);
th = lfsck_trans_create(env, dev, com->lc_lfsck);
if (IS_ERR(th))
GOTO(unlock, rc = PTR_ERR(th));
rc = dt_declare_delete(env, obj, (const struct dt_key *)key, th);
if (rc)
GOTO(unlock, rc);
rc = dt_trans_start_local(env, dev, th);
if (rc)
GOTO(unlock, rc);
rc = dt_delete(env, obj, (const struct dt_key *)key, th);
GOTO(unlock, rc);
unlock:
if (th && !IS_ERR(th))
dt_trans_stop(env, dev, th);
mutex_unlock(&com->lc_sub_trace_objs[idx].lsto_mutex);
log:
CDEBUG(D_LFSCK,
"%s: delete the dangling record for "DFID", comp_id = %u, ea_off = %u from the trace file: rc = %d\n",
lfsck_lfsck2name(com->lc_lfsck), PFID(fid), comp_id, ea_off, rc);
return rc;
}
/**
* lfsck_layout_get_def_stripesize() - Get the system default stripe size.
* @env: pointer to the thread context
* @lfsck: pointer to the lfsck instance
* @size: pointer to the default stripe size [out]
*
* Return:
* * %0 for success
* * %negative error number on failure
*/
static int lfsck_layout_get_def_stripesize(const struct lu_env *env,
struct lfsck_instance *lfsck,
__u32 *size)
{
struct lov_user_md *lum = &lfsck_env_info(env)->lti_lum;
struct dt_object *root;
int rc;
root = dt_locate(env, lfsck->li_next, &lfsck->li_local_root_fid);
if (IS_ERR(root))
return PTR_ERR(root);
/* Get the default stripe size via xattr_get on the backend root. */
rc = dt_xattr_get(env, root, lfsck_buf_get(env, lum, sizeof(*lum)),
XATTR_NAME_LOV);
if (rc > 0) {
/* The lum->lmm_stripe_size is LE mode. The *size also
* should be LE mode. So it is unnecessary to convert.
*/
*size = lum->lmm_stripe_size;
rc = 0;
} else if (unlikely(rc == 0)) {
rc = -EINVAL;
}
lfsck_object_put(env, root);
return rc;
}
/**
* lfsck_layout_refill_lovea() - Refill LOV EA
* @env: pointer to the thread context
* @lfsck: pointer to the lfsck instance
* @handle: transaction handle
* @parent: pointer to parent MDT object (dt_object) holding LOV EA
* @cfid: FID for the OST-object
* @buf: buffer to be written to LOV EA
* @lmm: LOV metadata
* @slot: LOV metadata pointing to OST
* @fl: flag for EA attribute
* @ost_idx: Index of OST object
* @size: size of @buf
*
* Return:
* * %+1 for repair successfully
* * %0 for did nothing
* * %negative error number on failure
*/
static int lfsck_layout_refill_lovea(const struct lu_env *env,
struct lfsck_instance *lfsck,
struct thandle *handle,
struct dt_object *parent,
const struct lu_fid *cfid,
struct lu_buf *buf,
struct lov_mds_md_v1 *lmm,
struct lov_ost_data_v1 *slot,
int fl, __u32 ost_idx, int size)
{
struct ost_id *oi = &lfsck_env_info(env)->lti_oi;
struct lu_buf ea_buf;
int rc;
__u32 magic;
__u32 pattern;
__u16 count;
ENTRY;
magic = le32_to_cpu(lmm->lmm_magic);
pattern = le32_to_cpu(lmm->lmm_pattern);
count = le16_to_cpu(lmm->lmm_stripe_count);
fid_to_ostid(cfid, oi);
ostid_cpu_to_le(oi, &slot->l_ost_oi);
slot->l_ost_gen = cpu_to_le32(0);
slot->l_ost_idx = cpu_to_le32(ost_idx);
if (pattern & LOV_PATTERN_F_HOLE) {
struct lov_ost_data_v1 *objs;
int i;
if (magic == LOV_MAGIC_V1)
objs = &lmm->lmm_objects[0];
else
objs = &((struct lov_mds_md_v3 *)lmm)->lmm_objects[0];
for (i = 0; i < count; i++, objs++) {
if (lovea_slot_is_dummy(objs))
break;
}
/* If the @slot is the last dummy slot to be refilled,
* then drop LOV_PATTERN_F_HOLE from lmm::lmm_pattern.
*/
if (i == count) {
lmm->lmm_pattern =
cpu_to_le32(pattern & ~LOV_PATTERN_F_HOLE);
CDEBUG(D_LFSCK,
"%s: remove layout HOLE for "DFID": parent "DFID"\n",
lfsck_lfsck2name(lfsck), PFID(cfid),
PFID(lfsck_dto2fid(parent)));
}
}
lfsck_buf_init(&ea_buf, buf->lb_buf, size);
rc = dt_xattr_set(env, parent, &ea_buf, XATTR_NAME_LOV, fl, handle);
if (rc == 0)
rc = 1;
RETURN(rc);
}
static struct lov_ost_data_v1 *
__lfsck_layout_new_v1_lovea(struct lov_mds_md_v1 *lmm,
const struct lu_fid *pfid,
__u32 stripe_size, __u32 ea_off,
__u32 pattern, __u16 count)
{
lmm->lmm_magic = cpu_to_le32(LOV_MAGIC_V1);
lmm->lmm_pattern = cpu_to_le32(pattern);
fid_to_lmm_oi(pfid, &lmm->lmm_oi);
lmm_oi_cpu_to_le(&lmm->lmm_oi, &lmm->lmm_oi);
lmm->lmm_stripe_size = cpu_to_le32(stripe_size);
lmm->lmm_stripe_count = cpu_to_le16(count);
lmm->lmm_layout_gen = cpu_to_le16(1);
memset(&lmm->lmm_objects[0], 0,
sizeof(struct lov_ost_data_v1) * count);
return &lmm->lmm_objects[ea_off];
}
static int lfsck_layout_new_v1_lovea(const struct lu_env *env,
struct lfsck_instance *lfsck,
struct ost_layout *ol,
struct dt_object *parent,
struct lu_buf *buf, __u32 ea_off,
struct lov_mds_md_v1 **lmm,
struct lov_ost_data_v1 **objs)
{
int size;
__u32 stripe_size = ol->ol_stripe_size;
__u32 pattern = LOV_PATTERN_RAID0;
__u16 count;
if (ol->ol_stripe_count != 0)
count = ol->ol_stripe_count;
else
count = ea_off + 1;
size = lov_mds_md_size(count, LOV_MAGIC_V1);
LASSERTF(buf->lb_len >= size,
"buffer len %d is less than real size %d\n",
(int)buf->lb_len, size);
if (stripe_size == 0) {
int rc;
rc = lfsck_layout_get_def_stripesize(env, lfsck, &stripe_size);
if (rc)
return rc;
}
*lmm = buf->lb_buf;
if (ol->ol_stripe_count > 1 ||
(ol->ol_stripe_count == 0 && ea_off != 0)) {
pattern |= LOV_PATTERN_F_HOLE;
memset(&(*lmm)->lmm_objects[0], 0,
count * sizeof(struct lov_ost_data_v1));
}
*objs = __lfsck_layout_new_v1_lovea(*lmm, lfsck_dto2fid(parent),
stripe_size, ea_off, pattern, count);
return size;
}
static int lfsck_layout_new_comp_lovea(const struct lu_env *env,
struct lu_orphan_rec_v3 *rec,
struct dt_object *parent,
struct lu_buf *buf, __u32 ea_off,
struct lov_mds_md_v1 **lmm,
struct lov_ost_data_v1 **objs)
{
struct ost_layout *ol = &rec->lor_layout;
struct lov_comp_md_v1 *lcm;
struct lov_comp_md_entry_v1 *lcme;
__u32 pattern = LOV_PATTERN_RAID0;
__u32 offset = sizeof(*lcm) + sizeof(*lcme);
int lcme_size = lov_mds_md_size(ol->ol_stripe_count, LOV_MAGIC_V1);
int size = offset + lcme_size;
LASSERTF(buf->lb_len >= size,
"buffer len %d is less than real size %d\n",
(int)buf->lb_len, size);
lcm = buf->lb_buf;
lcm->lcm_magic = cpu_to_le32(LOV_MAGIC_COMP_V1);
lcm->lcm_size = cpu_to_le32(size);
if (rec->lor_range) {
lcm->lcm_layout_gen = cpu_to_le32(rec->lor_layout_version +
rec->lor_range);
lcm->lcm_flags = cpu_to_le16(LCM_FL_WRITE_PENDING);
} else if (rec->lor_layout_version) {
lcm->lcm_layout_gen = cpu_to_le32(rec->lor_layout_version +
rec->lor_range);
lcm->lcm_flags = cpu_to_le16(LCM_FL_NONE);
} else {
/*
* if OST doesn't provide layout version, then try
* to inherit one from MDS's layout, but increment
* it so the client notices and applies modified
* layout
*/
le32_add_cpu(&lcm->lcm_layout_gen, 1);
lcm->lcm_flags = cpu_to_le16(LCM_FL_NONE);
}
lcm->lcm_entry_count = cpu_to_le16(1);
/* Currently, we do not know how many mirrors will be, set it as zero
* at the beginning. It will be updated when more mirrors are found.
*/
lcm->lcm_mirror_count = 0;
lcme = &lcm->lcm_entries[0];
lcme->lcme_id = cpu_to_le32(ol->ol_comp_id);
lcme->lcme_flags = cpu_to_le32(LCME_FL_INIT);
lcme->lcme_extent.e_start = cpu_to_le64(ol->ol_comp_start);
lcme->lcme_extent.e_end = cpu_to_le64(ol->ol_comp_end);
lcme->lcme_offset = cpu_to_le32(offset);
lcme->lcme_size = cpu_to_le32(lcme_size);
lcme->lcme_layout_gen = lcm->lcm_layout_gen;
if (ol->ol_stripe_count > 1)
pattern |= LOV_PATTERN_F_HOLE;
*lmm = buf->lb_buf + offset;
*objs = __lfsck_layout_new_v1_lovea(*lmm, lfsck_dto2fid(parent),
ol->ol_stripe_size, ea_off,
pattern, ol->ol_stripe_count);
return size;
}
static void lfsck_layout_update_lcm(struct lov_comp_md_v1 *lcm,
struct lov_comp_md_entry_v1 *lcme,
__u32 version, __u32 range)
{
struct lov_comp_md_entry_v1 *tmp;
__u64 start = le64_to_cpu(lcme->lcme_extent.e_start);
__u64 end = le64_to_cpu(lcme->lcme_extent.e_end);
__u32 gen = version + range;
__u32 tmp_gen;
__u16 count = le16_to_cpu(lcm->lcm_entry_count);
__u16 flags = le16_to_cpu(lcm->lcm_flags);
__u16 flr_state = flags & LCM_FL_FLR_MASK;
int i;
if (!gen)
gen = 1;
lcme->lcme_layout_gen = cpu_to_le32(gen);
if (le32_to_cpu(lcm->lcm_layout_gen) < gen)
lcm->lcm_layout_gen = cpu_to_le32(gen);
if (range)
lcm->lcm_flags = cpu_to_le16((flags & ~LCM_FL_FLR_MASK) |
LCM_FL_WRITE_PENDING);
else if (flr_state == LCM_FL_NONE &&
le16_to_cpu(lcm->lcm_mirror_count) > 0)
lcm->lcm_flags = cpu_to_le16((flags & ~LCM_FL_FLR_MASK) |
LCM_FL_RDONLY);
for (i = 0; i < count; i++) {
tmp = &lcm->lcm_entries[i];
if (le64_to_cpu(tmp->lcme_extent.e_end) <= start)
continue;
if (le64_to_cpu(tmp->lcme_extent.e_start) >= end)
continue;
if (le32_to_cpu(tmp->lcme_flags) & LCME_FL_STALE)
continue;
tmp_gen = le32_to_cpu(tmp->lcme_layout_gen);
/* "lcme_layout_gen == 0" but without LCME_FL_STALE flag,
* then it should be the latest version of all mirrors.
*/
if (tmp_gen == 0 || tmp_gen > gen) {
lcme->lcme_flags = cpu_to_le32(
le32_to_cpu(lcme->lcme_flags) | LCME_FL_STALE);
break;
}
if (tmp_gen < gen)
tmp->lcme_flags = cpu_to_le32(
le32_to_cpu(tmp->lcme_flags) | LCME_FL_STALE);
}
}
static int lfsck_layout_add_comp(const struct lu_env *env,
struct lfsck_instance *lfsck,
struct thandle *handle,
struct lu_orphan_rec_v3 *rec,
struct dt_object *parent,
const struct lu_fid *cfid,
struct lu_buf *buf, __u32 ost_idx,
__u32 ea_off, int pos, bool new_mirror)
{
struct ost_layout *ol = &rec->lor_layout;
struct lov_comp_md_v1 *lcm = buf->lb_buf;
struct lov_comp_md_entry_v1 *lcme;
struct lov_mds_md_v1 *lmm;
struct lov_ost_data_v1 *objs;
int added = sizeof(*lcme) +
lov_mds_md_size(ol->ol_stripe_count, LOV_MAGIC_V1);
int size = le32_to_cpu(lcm->lcm_size) + added;
int rc;
int i;
__u32 offset;
__u32 pattern = LOV_PATTERN_RAID0;
__u16 count = le16_to_cpu(lcm->lcm_entry_count);
ENTRY;
lu_buf_check_and_grow(buf, size);
/* set the lcm again because lu_buf_check_and_grow() may
* have reallocated the buf.
*/
lcm = buf->lb_buf;
lcm->lcm_size = cpu_to_le32(size);
lcm->lcm_entry_count = cpu_to_le16(count + 1);
if (new_mirror)
le16_add_cpu(&lcm->lcm_mirror_count, 1);
/* 1. Move the component bodies from [pos, count-1] to [pos+1, count]
* with distance of 'added'.
*/
if (pos < count) {
size = 0;
for (i = pos; i < count; i++) {
lcme = &lcm->lcm_entries[i];
size += le32_to_cpu(lcme->lcme_size);
}
offset = le32_to_cpu(lcm->lcm_entries[pos].lcme_offset);
memmove(buf->lb_buf + offset + added,
buf->lb_buf + offset, size);
}
size = 0;
/* 2. Move the component header [0, pos-1] to [0, pos-1] with distance
* of 'sizeof(struct lov_comp_md_entry_v1)'
*/
if (pos > 0) {
for (i = 0; i < pos; i++) {
lcme = &lcm->lcm_entries[i];
size += le32_to_cpu(lcme->lcme_size);
}
offset = le32_to_cpu(lcm->lcm_entries[0].lcme_offset);
memmove(buf->lb_buf + offset + sizeof(*lcme),
buf->lb_buf + offset, size);
}
/* 3. Recalculate the enter offset for the component [pos, count-1] */
for (i = count - 1; i >= pos; i--) {
lcm->lcm_entries[i + 1] = lcm->lcm_entries[i];
lcm->lcm_entries[i + 1].lcme_offset =
cpu_to_le32(le32_to_cpu(lcm->lcm_entries[i + 1].
lcme_offset) + added);
}
/* 4. Recalculate the enter offset for the component [0, pos) */
for (i = 0; i < pos; i++) {
lcm->lcm_entries[i].lcme_offset =
cpu_to_le32(le32_to_cpu(lcm->lcm_entries[i].
lcme_offset) + sizeof(*lcme));
}
offset = sizeof(*lcm) + sizeof(*lcme) * (count + 1) + size;
/* 4. Insert the new component header (entry) at the slot 'pos'. */
lcme = &lcm->lcm_entries[pos];
lcme->lcme_id = cpu_to_le32(ol->ol_comp_id);
lcme->lcme_flags = cpu_to_le32(LCME_FL_INIT);
lcme->lcme_extent.e_start = cpu_to_le64(ol->ol_comp_start);
lcme->lcme_extent.e_end = cpu_to_le64(ol->ol_comp_end);
lcme->lcme_offset = cpu_to_le32(offset);
lcme->lcme_size = cpu_to_le32(lov_mds_md_size(ol->ol_stripe_count,
LOV_MAGIC_V1));
if (ol->ol_stripe_count > 1)
pattern |= LOV_PATTERN_F_HOLE;
lmm = buf->lb_buf + offset;
/* 5. Insert teh new component body at the 'offset'. */
objs = __lfsck_layout_new_v1_lovea(lmm, lfsck_dto2fid(parent),
ol->ol_stripe_size, ea_off,
pattern, ol->ol_stripe_count);
/* 6. Update mirror related flags and version. */
lfsck_layout_update_lcm(lcm, lcme, rec->lor_layout_version,
rec->lor_range);
rc = lfsck_layout_refill_lovea(env, lfsck, handle, parent, cfid, buf,
lmm, objs, LU_XATTR_REPLACE, ost_idx,
le32_to_cpu(lcm->lcm_size));
CDEBUG(D_LFSCK,
"%s: layout LFSCK assistant add new COMP for "DFID": parent "DFID", OST-index %u, stripe-index %u, stripe_size %u, stripe_count %u, comp_id %u, comp_start %llu, comp_end %llu, layout version %u, range %u, %s LOV EA hole: rc = %d\n",
lfsck_lfsck2name(lfsck), PFID(cfid), PFID(lfsck_dto2fid(parent)),
ost_idx, ea_off, ol->ol_stripe_size, ol->ol_stripe_count,
ol->ol_comp_id, ol->ol_comp_start, ol->ol_comp_end,
rec->lor_layout_version, rec->lor_range,
le32_to_cpu(lmm->lmm_pattern) & LOV_PATTERN_F_HOLE ?
"with" : "without", rc);
RETURN(rc);
}
static int lfsck_layout_extend_v1v3_lovea(const struct lu_env *env,
struct lfsck_instance *lfsck,
struct thandle *handle,
struct ost_layout *ol,
struct dt_object *parent,
const struct lu_fid *cfid,
struct lu_buf *buf, __u32 ost_idx,
__u32 ea_off)
{
struct lov_mds_md_v1 *lmm = buf->lb_buf;
struct lov_ost_data_v1 *objs;
__u16 count = le16_to_cpu(lmm->lmm_stripe_count);
__u32 magic = le32_to_cpu(lmm->lmm_magic);
int size;
int gap;
int rc;
ENTRY;
/* The original LOVEA maybe re-generated via old filter_fid, at
* that time, we do not know the stripe count and stripe size.
*/
if (ol->ol_stripe_count > count)
count = ol->ol_stripe_count;
if (ol->ol_stripe_size != 0 &&
ol->ol_stripe_size != le32_to_cpu(lmm->lmm_stripe_size))
lmm->lmm_stripe_size = cpu_to_le32(ol->ol_stripe_size);
if (magic == LOV_MAGIC_V1)
objs = &lmm->lmm_objects[count];
else
objs = &((struct lov_mds_md_v3 *)lmm)->lmm_objects[count];
gap = ea_off - count;
if (gap >= 0)
count = ea_off + 1;
size = lov_mds_md_size(count, magic);
LASSERTF(buf->lb_len >= size,
"buffer len %d is less than real size %d\n",
(int)buf->lb_len, size);
if (gap > 0) {
memset(objs, 0, gap * sizeof(*objs));
lmm->lmm_pattern |= cpu_to_le32(LOV_PATTERN_F_HOLE);
}
lmm->lmm_layout_gen = cpu_to_le16(le16_to_cpu(lmm->lmm_layout_gen) + 1);
lmm->lmm_stripe_count = cpu_to_le16(count);
objs += gap;
rc = lfsck_layout_refill_lovea(env, lfsck, handle, parent, cfid, buf,
lmm, objs, LU_XATTR_REPLACE, ost_idx, size);
CDEBUG(D_LFSCK,
"%s: layout LFSCK assistant extend layout EA for "DFID": parent "DFID", OST-index %u, stripe-index %u, stripe_size %u, stripe_count %u, comp_id %u, comp_start %llu, comp_end %llu, %s LOV EA hole: rc = %d\n",
lfsck_lfsck2name(lfsck), PFID(cfid), PFID(lfsck_dto2fid(parent)),
ost_idx, ea_off, ol->ol_stripe_size, ol->ol_stripe_count,
ol->ol_comp_id, ol->ol_comp_start, ol->ol_comp_end,
le32_to_cpu(lmm->lmm_pattern) & LOV_PATTERN_F_HOLE ?
"with" : "without", rc);
RETURN(rc);
}
/**
* lfsck_layout_update_lovea() - Update LOV EA
* @env: pointer to the thread context
* @lfsck: pointer to the lfsck instance
* @handle: transaction handle
* @rec: pointer to the record for the orphan OST-object
* @parent: pointer to parent MDT object (dt_object) holding LOV EA
* @cfid: FID for the OST-object
* @buf: buffer to be written to LOV EA
* @fl: flag for EA attribute
* @ost_idx: index of OST on which OST object resides.
* @ea_off: the stripe offset in the LOV EA
*
* Return:
* * %+1 for repair successfully
* * %0 for did nothing
* * %negative error number on failure
*/
static int lfsck_layout_update_lovea(const struct lu_env *env,
struct lfsck_instance *lfsck,
struct thandle *handle,
struct lu_orphan_rec_v3 *rec,
struct dt_object *parent,
const struct lu_fid *cfid,
struct lu_buf *buf, int fl,
__u32 ost_idx, __u32 ea_off)
{
struct ost_layout *ol = &rec->lor_layout;
struct lov_mds_md_v1 *lmm = NULL;
struct lov_ost_data_v1 *objs = NULL;
int rc = 0;
ENTRY;
if (ol->ol_comp_id != 0)
rc = lfsck_layout_new_comp_lovea(env, rec, parent, buf, ea_off,
&lmm, &objs);
else
rc = lfsck_layout_new_v1_lovea(env, lfsck, &rec->lor_layout,
parent, buf, ea_off, &lmm,
&objs);
if (rc > 0)
rc = lfsck_layout_refill_lovea(env, lfsck, handle, parent, cfid,
buf, lmm, objs, fl, ost_idx, rc);
CDEBUG(D_LFSCK,
"%s: layout LFSCK assistant created layout EA for "DFID": parent "DFID", OST-index %u, stripe-index %u, stripe_size %u, stripe_count %u, comp_id %u, comp_start %llu, comp_end %llu, layout version %u, range %u, fl %d, %s LOV EA hole: rc = %d\n",
lfsck_lfsck2name(lfsck), PFID(cfid), PFID(lfsck_dto2fid(parent)),
ost_idx, ea_off, ol->ol_stripe_size, ol->ol_stripe_count,
ol->ol_comp_id, ol->ol_comp_start, ol->ol_comp_end,
rec->lor_layout_version, rec->lor_range, fl,
le32_to_cpu(lmm->lmm_pattern) & LOV_PATTERN_F_HOLE ?
"with" : "without", rc);
RETURN(rc);
}
static int __lfsck_layout_update_pfid(const struct lu_env *env,
struct lfsck_component *com,
struct dt_object *child,
const struct lu_fid *pfid,
const struct ost_layout *ol, __u32 offset,
__u32 version, __u32 range)
{
struct dt_device *dev = lfsck_obj2dev(child);
struct filter_fid *ff = &lfsck_env_info(env)->lti_ff;
struct thandle *handle;
struct lu_buf buf = { NULL };
int rc;
if (com->lc_lfsck->li_bookmark_ram.lb_param & LPF_DRYRUN)
RETURN(0);
ff->ff_parent.f_seq = cpu_to_le64(pfid->f_seq);
ff->ff_parent.f_oid = cpu_to_le32(pfid->f_oid);
/* Currently, the filter_fid::ff_parent::f_ver is not the real parent
* MDT-object's FID::f_ver, instead it is the OST-object index in its
* parent MDT-object's layout EA.
*/
ff->ff_parent.f_stripe_idx = cpu_to_le32(offset);
ost_layout_cpu_to_le(&ff->ff_layout, ol);
ff->ff_layout_version = cpu_to_le32(version);
ff->ff_range = cpu_to_le32(range);
lfsck_buf_init(&buf, ff, sizeof(*ff));
if (!dt_object_exists(child) || lfsck_is_dead_obj(child))
return 0;
handle = lfsck_trans_create(env, dev, com->lc_lfsck);
if (IS_ERR(handle))
RETURN(PTR_ERR(handle));
rc = dt_declare_xattr_set(env, child, NULL, &buf, XATTR_NAME_FID, 0,
handle);
if (rc != 0)
GOTO(stop, rc);
rc = dt_trans_start_local(env, dev, handle);
if (rc != 0)
GOTO(stop, rc);
dt_write_lock(env, child, 0);
if (dt_object_exists(child) && !lfsck_is_dead_obj(child))
rc = dt_xattr_set(env, child, &buf, XATTR_NAME_FID, 0, handle);
dt_write_unlock(env, child);
GOTO(stop, rc);
stop:
dt_trans_stop(env, dev, handle);
return rc;
}
/**
* lfsck_layout_update_pfid() - Update pFID
* @env: Lustre environment
* @com: pointer to layout lfsck component (holds metadata + state)
* @parent: pointer to parent MDT object (dt_object) holding LOV EA
* @cfid: pointer to file identifier (lu_fid) of the child (OST) object
* @cdev: pointer to dt_device (device state)
* @rec: pointer to orphan record (lu_orphan_rec_v3)
* @ea_off: the offset of the OST-object in the LOV EA
*
* Return:
* * %+1 for repair successfully
* * %0 for did nothing
* * %negative error number on failure
*/
static int lfsck_layout_update_pfid(const struct lu_env *env,
struct lfsck_component *com,
struct dt_object *parent,
struct lu_fid *cfid,
struct dt_device *cdev,
struct lu_orphan_rec_v3 *rec, __u32 ea_off)
{
struct dt_object *child;
int rc = 0;
ENTRY;
child = lfsck_object_find_by_dev(env, cdev, cfid);
if (IS_ERR(child))
RETURN(PTR_ERR(child));
rc = __lfsck_layout_update_pfid(env, com, child,
lu_object_fid(&parent->do_lu),
&rec->lor_layout, ea_off,
rec->lor_layout_version,
rec->lor_range);
lfsck_object_put(env, child);
RETURN(rc == 0 ? 1 : rc);
}
static int lfsck_lovea_size(struct ost_layout *ol, __u32 ea_off)
{
if (ol->ol_comp_id != 0)
return sizeof(struct lov_comp_md_v1) +
sizeof(struct lov_comp_md_entry_v1) +
lov_mds_md_size(ol->ol_stripe_count, LOV_MAGIC_V1);
if (ol->ol_stripe_count != 0)
return lov_mds_md_size(ol->ol_stripe_count, LOV_MAGIC_V1);
return lov_mds_md_size(ea_off + 1, LOV_MAGIC_V1);
}
/**
* lfsck_layout_recreate_parent() - create MDT-object with given (partial) LOV EA.
* @env: pointer to the thread context
* @com: pointer to the lfsck component
* @ltd: pointer to target device descriptor
* @rec: pointer to the record for the orphan OST-object
* @cfid: pointer to FID for the orphan OST-object
* @infix: additional information, such as the FID for original MDT-object and
* the stripe offset in the LOV EA
* @type: the type for describing why the orphan MDT-object is created. The
* rules are as following:
* @ea_off: the stripe offset in the LOV EA
*
* This function will create the MDT-object with the given (partial) LOV EA.
*
* Under some data corruption cases, the MDT-object of the file may be lost,
* but its OST-objects, or some of them are there. The layout LFSCK needs to
* re-create the MDT-object with the orphan OST-object(s) information.
*
* On the other hand, the LFSCK may has created some OST-object for repairing
* dangling LOV EA reference, but as the LFSCK processing, it may find that
* the old OST-object is there and should replace the former new created OST
* object. Unfortunately, some others have modified such newly created object.
* To keep the data (both new and old), the LFSCK will create MDT-object with
* new FID to reference the original OST-object.
*
* type "C": Multiple OST-objects claim the same MDT-object and the
* same slot in the layout EA. Then the LFSCK will create
* new MDT-object(s) to hold the conflict OST-object(s).
*
* type "N": The orphan OST-object does not know which one was the
* real parent MDT-object, so the LFSCK uses new FID for
* its parent MDT-object.
*
* type "R": The orphan OST-object knows its parent MDT-object FID,
* but does not know the position (the file name) in the
* layout.
*
* type "D": The MDT-object is a directory, it may knows its parent
* but because there is no valid linkEA, the LFSCK cannot
* know where to put it back to the namespace.
* type "O": The MDT-object has no linkEA, and there is no name
* entry that references the MDT-object.
*
* type "P": The orphan object to be created was a parent directory
* of some MDT-object which linkEA shows that the @orphan
* object is missing.
*
* The orphan name will be like:
* ${FID}-${infix}-${type}-${conflict_version}
*
* Return:
* * %positive on repaired something
* * %0 if needs to repair nothing
* * %negative error number on failure
*/
static int lfsck_layout_recreate_parent(const struct lu_env *env,
struct lfsck_component *com,
struct lfsck_tgt_desc *ltd,
struct lu_orphan_rec_v3 *rec,
struct lu_fid *cfid,
const char *infix,
const char *type,
__u32 ea_off)
{
struct lfsck_thread_info *info = lfsck_env_info(env);
struct dt_insert_rec *dtrec = &info->lti_dt_rec;
char *name = info->lti_key;
struct lu_attr *la = &info->lti_la2;
struct dt_object_format *dof = &info->lti_dof;
struct lfsck_instance *lfsck = com->lc_lfsck;
struct lu_fid *pfid = &rec->lor_rec.lor_fid;
struct lu_fid *tfid = &info->lti_fid3;
struct dt_device *dev = lfsck->li_bottom;
struct dt_object *lpf = lfsck->li_lpf_obj;
struct dt_object *pobj = NULL;
struct dt_object *cobj = NULL;
struct thandle *th = NULL;
struct lu_buf *ea_buf = &info->lti_big_buf;
struct lu_buf lov_buf;
struct lfsck_lock_handle *llh = &info->lti_llh;
struct linkea_data ldata = { NULL };
struct lu_buf linkea_buf;
const struct lu_name *pname;
int size = 0;
int idx = 0;
int rc = 0;
ENTRY;
if (lfsck_is_dryrun(lfsck))
GOTO(log, rc = 0);
if (unlikely(lpf == NULL))
GOTO(log, rc = -ENXIO);
/* We use two separated transactions to repair the inconsistency.
*
* 1) create the MDT-object locally.
* 2) update the OST-object's PFID EA if necessary.
*
* If 1) succeed, but 2) failed, then the OST-object's PFID EA will be
* updated when the layout LFSCK run next time.
*
* If 1) failed, but 2) succeed, then such MDT-object will be re-created
* when the layout LFSCK run next time.
*/
if (fid_is_zero(pfid)) {
rc = lfsck_fid_alloc(env, lfsck, pfid, false);
if (rc != 0)
GOTO(log, rc);
cobj = lfsck_object_find_by_dev(env, ltd->ltd_tgt, cfid);
if (IS_ERR(cobj))
GOTO(log, rc = PTR_ERR(cobj));
}
pobj = lfsck_object_find_by_dev(env, dev, pfid);
if (IS_ERR(pobj))
GOTO(log, rc = PTR_ERR(pobj));
LASSERT(infix != NULL);
LASSERT(type != NULL);
memset(la, 0, sizeof(*la));
la->la_uid = rec->lor_rec.lor_uid;
la->la_gid = rec->lor_rec.lor_gid;
la->la_mode = S_IFREG | 0400;
la->la_valid = LA_MODE | LA_UID | LA_GID;
memset(dof, 0, sizeof(*dof));
dof->dof_type = dt_mode_to_dft(S_IFREG);
/* Because the dof->dof_reg.striped = 0, the LOD will not create
* the stripe(s). The LFSCK will specify the LOV EA via
* lfsck_layout_update_lovea().
*/
size = lfsck_lovea_size(&rec->lor_layout, ea_off);
if (ea_buf->lb_len < size) {
lu_buf_realloc(ea_buf, size);
if (ea_buf->lb_buf == NULL)
GOTO(log, rc = -ENOMEM);
}
again:
do {
snprintf(name, NAME_MAX, DFID"%s-%s-%d", PFID(pfid), infix,
type, idx++);
rc = dt_lookup_dir(env, lfsck->li_lpf_obj, name, tfid);
if (rc != 0 && rc != -ENOENT)
GOTO(log, rc);
} while (rc == 0);
rc = lfsck_lock(env, lfsck, lfsck->li_lpf_obj, name, llh,
MDS_INODELOCK_UPDATE, LCK_PW);
if (rc != 0)
GOTO(log, rc);
/* Recheck whether the name conflict with othrs after taken ldlm lock */
rc = dt_lookup_dir(env, lfsck->li_lpf_obj, name, tfid);
if (unlikely(rc == 0)) {
lfsck_unlock(llh);
goto again;
}
if (rc != -ENOENT)
GOTO(unlock, rc);
pname = lfsck_name_get_const(env, name, strlen(name));
rc = linkea_links_new(&ldata, &lfsck_env_info(env)->lti_linkea_buf,
pname, lfsck_dto2fid(lfsck->li_lpf_obj));
if (rc != 0)
GOTO(unlock, rc);
/* The 1st transaction. */
th = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(th))
GOTO(unlock, rc = PTR_ERR(th));
rc = dt_declare_create(env, pobj, la, NULL, dof, th);
if (rc != 0)
GOTO(stop, rc);
lfsck_buf_init(&lov_buf, ea_buf->lb_buf, size);
rc = dt_declare_xattr_set(env, pobj, NULL, &lov_buf, XATTR_NAME_LOV,
LU_XATTR_CREATE, th);
if (rc != 0)
GOTO(stop, rc);
dtrec->rec_fid = pfid;
dtrec->rec_type = S_IFREG;
rc = dt_declare_insert(env, lpf,
(const struct dt_rec *)dtrec,
(const struct dt_key *)name, 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, pobj, NULL, &linkea_buf,
XATTR_NAME_LINK, 0, th);
if (rc != 0)
GOTO(stop, rc);
rc = dt_trans_start_local(env, dev, th);
if (rc != 0)
GOTO(stop, rc);
dt_write_lock(env, pobj, 0);
rc = dt_create(env, pobj, la, NULL, dof, th);
if (rc == 0)
rc = lfsck_layout_update_lovea(env, lfsck, th, rec, pobj, cfid,
&lov_buf, LU_XATTR_CREATE, ltd->ltd_index, ea_off);
dt_write_unlock(env, pobj);
if (rc < 0)
GOTO(stop, rc);
rc = dt_insert(env, lpf, (const struct dt_rec *)dtrec,
(const struct dt_key *)name, th);
if (rc != 0)
GOTO(stop, rc);
rc = dt_xattr_set(env, pobj, &linkea_buf, XATTR_NAME_LINK, 0, th);
if (rc == 0 && cobj != NULL) {
dt_trans_stop(env, dev, th);
th = NULL;
/* The 2nd transaction. */
rc = __lfsck_layout_update_pfid(env, com, cobj, pfid,
&rec->lor_layout, ea_off,
rec->lor_layout_version,
rec->lor_range);
}
GOTO(stop, rc);
stop:
if (th != NULL)
dt_trans_stop(env, dev, th);
unlock:
lfsck_unlock(llh);
log:
if (cobj != NULL && !IS_ERR(cobj))
lfsck_object_put(env, cobj);
if (pobj != NULL && !IS_ERR(pobj))
lfsck_object_put(env, pobj);
if (rc < 0)
CDEBUG(D_LFSCK,
"%s layout LFSCK assistant failed to recreate the lost MDT-object: parent "DFID", child "DFID", OST-index %u, stripe-index %u, infix %s, type %s: rc = %d\n",
lfsck_lfsck2name(lfsck), PFID(pfid), PFID(cfid),
ltd->ltd_index, ea_off, infix, type, rc);
return rc >= 0 ? 1 : rc;
}
static int lfsck_layout_master_conditional_destroy(const struct lu_env *env,
struct lfsck_component *com,
const struct lu_fid *fid,
__u32 index)
{
struct lfsck_thread_info *info = lfsck_env_info(env);
struct lfsck_request *lr = &info->lti_lr;
struct lfsck_instance *lfsck = com->lc_lfsck;
struct lfsck_tgt_desc *ltd;
struct ptlrpc_request *req;
struct lfsck_request *tmp;
struct obd_export *exp;
int rc = 0;
ENTRY;
ltd = lfsck_tgt_get(&lfsck->li_ost_descs, index);
if (unlikely(ltd == NULL))
RETURN(-ENXIO);
exp = ltd->ltd_exp;
if (!(exp_connect_flags(exp) & OBD_CONNECT_LFSCK))
GOTO(put, rc = -EOPNOTSUPP);
req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_LFSCK_NOTIFY);
if (req == NULL)
GOTO(put, rc = -ENOMEM);
rc = ptlrpc_request_pack(req, LUSTRE_OBD_VERSION, LFSCK_NOTIFY);
if (rc != 0) {
ptlrpc_request_free(req);
GOTO(put, rc);
}
memset(lr, 0, sizeof(*lr));
lr->lr_event = LE_CONDITIONAL_DESTROY;
lr->lr_active = LFSCK_TYPE_LAYOUT;
lr->lr_fid = *fid;
tmp = req_capsule_client_get(&req->rq_pill, &RMF_LFSCK_REQUEST);
*tmp = *lr;
ptlrpc_request_set_replen(req);
rc = ptlrpc_queue_wait(req);
ptlrpc_req_put(req);
GOTO(put, rc);
put:
kref_put(<d->ltd_ref, lfsck_tgt_free);
return rc;
}
static int lfsck_layout_slave_conditional_destroy(const struct lu_env *env,
struct lfsck_component *com,
struct lfsck_request *lr)
{
struct lfsck_thread_info *info = lfsck_env_info(env);
struct lu_attr *la = &info->lti_la;
union ldlm_policy_data *policy = &info->lti_policy;
struct ldlm_res_id *resid = &info->lti_resid;
struct lfsck_instance *lfsck = com->lc_lfsck;
struct dt_device *dev = lfsck->li_bottom;
struct lu_fid *fid = &lr->lr_fid;
struct dt_object *obj;
struct thandle *th = NULL;
struct lustre_handle lh = { 0 };
__u64 flags = 0;
int rc = 0;
ENTRY;
if (lfsck->li_bookmark_ram.lb_param & LPF_DRYRUN)
RETURN(0);
obj = lfsck_object_find_by_dev(env, dev, fid);
if (IS_ERR(obj))
RETURN(PTR_ERR(obj));
dt_read_lock(env, obj, 0);
if (dt_object_exists(obj) == 0 ||
lfsck_is_dead_obj(obj)) {
dt_read_unlock(env, obj);
GOTO(put, rc = -ENOENT);
}
/* Get obj's attr without lock firstly. */
rc = dt_attr_get(env, obj, la);
dt_read_unlock(env, obj);
if (rc != 0)
GOTO(put, rc);
if (likely(la->la_ctime != 0 || la->la_mode & S_ISUID))
GOTO(put, rc = -ETXTBSY);
/* Acquire extent lock on [0, EOF] to sync with all possible written. */
LASSERT(lfsck->li_namespace != NULL);
memset(policy, 0, sizeof(*policy));
policy->l_extent.end = OBD_OBJECT_EOF;
ost_fid_build_resid(fid, resid);
/* LU-17344: check the validity of the ldlm_res_id */
if (unlikely(resid->name[0] == 0)) {
CERROR("%s: the res_id "DLDLMRES" built by the FID "DFID" (the obj %p) is invalid\n",
lfsck_lfsck2name(lfsck), resid->name[0], resid->name[1],
resid->name[2], resid->name[3], PFID(fid), obj);
dump_stack();
return -EIO;
}
rc = ldlm_cli_enqueue_local(env, lfsck->li_namespace, resid,
LDLM_EXTENT, policy, LCK_EX, &flags,
ldlm_blocking_ast, ldlm_completion_ast,
NULL, NULL, 0, LVB_T_NONE, NULL, &lh);
if (rc != ELDLM_OK)
GOTO(put, rc = -EIO);
dt_write_lock(env, obj, 0);
/* Get obj's attr within lock again. */
rc = dt_attr_get(env, obj, la);
if (rc != 0)
GOTO(unlock, rc);
if (la->la_ctime != 0)
GOTO(unlock, rc = -ETXTBSY);
th = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(th))
GOTO(unlock, rc = PTR_ERR(th));
rc = dt_declare_ref_del(env, obj, th);
if (rc != 0)
GOTO(stop, rc);
rc = dt_declare_destroy(env, obj, th);
if (rc != 0)
GOTO(stop, rc);
rc = dt_trans_start_local(env, dev, th);
if (rc != 0)
GOTO(stop, rc);
rc = dt_ref_del(env, obj, th);
if (rc != 0)
GOTO(stop, rc);
rc = dt_destroy(env, obj, th);
if (rc == 0)
CDEBUG(D_LFSCK,
"%s: layout LFSCK destroyed the empty OST-object "DFID" that was created for reparing dangling referenced case. But the original missing OST-object is found now.\n",
lfsck_lfsck2name(lfsck), PFID(fid));
GOTO(stop, rc);
stop:
dt_trans_stop(env, dev, th);
unlock:
dt_write_unlock(env, obj);
ldlm_lock_decref(&lh, LCK_EX);
put:
lfsck_object_put(env, obj);
return rc;
}
/**
* lfsck_layout_conflict_create() - resolve inconsistencies in file layout
* @env: Lustre environment
* @com: pointer to layout lfsck component (holds metadata + state)
* @ltd: pointer to target descriptor (OST object)
* @rec: pointer to orphan record (lu_orphan_rec_v3)
* @parent: pointer to parent MDT object (dt_object) holding LOV EA
* @cfid: pointer to file identifier (lu_fid) of the child (OST) object
* @ea_buf: Pointer to buffer for read/write of EA
* @lmm: LOV metadata
* @slot: LOV metadata pointing to OST
* @ea_off: Offset within LOV EA which points to OST
* @lovea_size: LOV EA size
*
* Some OST-object has occupied the specified layout EA slot.
* Such OST-object may be generated by the LFSCK when repair
* dangling referenced MDT-object, which can be indicated by
* attr::la_ctime == 0 but without S_ISUID in la_mode. If it
* is true and such OST-object has not been modified yet, we
* will replace it with the orphan OST-object; otherwise the
* LFSCK will create new MDT-object to reference the orphan.
*
* Retrun:
* * %+1 repaired
* * %0 did nothing
* * %negative on error
*/
static int lfsck_layout_conflict_create(const struct lu_env *env,
struct lfsck_component *com,
struct lfsck_tgt_desc *ltd,
struct lu_orphan_rec_v3 *rec,
struct dt_object *parent,
struct lu_fid *cfid,
struct lu_buf *ea_buf,
struct lov_mds_md_v1 *lmm,
struct lov_ost_data_v1 *slot,
__u32 ea_off, int lovea_size)
{
struct lfsck_thread_info *info = lfsck_env_info(env);
struct lfsck_instance *lfsck = com->lc_lfsck;
struct lu_fid *cfid2 = &info->lti_fid2;
struct ost_id *oi = &info->lti_oi;
struct dt_device *dev = lfsck_obj2dev(parent);
struct thandle *th = NULL;
struct lustre_handle lh = { 0 };
__u32 ost_idx2 = le32_to_cpu(slot->l_ost_idx);
int rc = 0;
ENTRY;
while (CFS_FAIL_CHECK(OBD_FAIL_LFSCK_DELAY3)) {
wait_var_event_timeout(lfsck, lfsck_should_stop(lfsck),
cfs_time_seconds(cfs_fail_val));
if (lfsck_should_stop(lfsck))
RETURN(0);
}
ostid_le_to_cpu(&slot->l_ost_oi, oi);
rc = ostid_to_fid(cfid2, oi, ost_idx2);
if (rc != 0)
GOTO(out, rc);
rc = lfsck_ibits_lock(env, lfsck, parent, &lh,
MDS_INODELOCK_LAYOUT | MDS_INODELOCK_XATTR,
LCK_EX);
if (rc != 0)
GOTO(out, rc);
rc = lfsck_layout_master_conditional_destroy(env, com, cfid2, ost_idx2);
/* If the conflict OST-object is not created for fixing dangling
* referenced MDT-object in former LFSCK check/repair, or it has
* been modified by others, then we cannot destroy it. Re-create
* a new MDT-object for the orphan OST-object.
*/
if (rc == -ETXTBSY) {
/* No need the layout lock on the original parent. */
lfsck_ibits_unlock(&lh, LCK_EX);
fid_zero(&rec->lor_rec.lor_fid);
snprintf(info->lti_tmpbuf, sizeof(info->lti_tmpbuf),
"-"DFID"-%x", PFID(lu_object_fid(&parent->do_lu)),
ea_off);
rc = lfsck_layout_recreate_parent(env, com, ltd, rec, cfid,
info->lti_tmpbuf, "C", ea_off);
RETURN(rc);
}
if (rc != 0 && rc != -ENOENT)
GOTO(unlock, rc);
if (lfsck_is_dryrun(lfsck))
GOTO(unlock, rc = 0);
th = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(th))
GOTO(unlock, rc = PTR_ERR(th));
rc = dt_declare_xattr_set(env, parent, NULL, ea_buf, XATTR_NAME_LOV,
LU_XATTR_REPLACE, th);
if (rc != 0)
GOTO(stop, rc);
rc = dt_trans_start_local(env, dev, th);
if (rc != 0)
GOTO(stop, rc);
dt_write_lock(env, parent, 0);
lmm->lmm_layout_gen = cpu_to_le16(le16_to_cpu(lmm->lmm_layout_gen) + 1);
rc = lfsck_layout_refill_lovea(env, lfsck, th, parent, cfid, ea_buf,
lmm, slot, LU_XATTR_REPLACE,
ltd->ltd_index, lovea_size);
dt_write_unlock(env, parent);
GOTO(stop, rc);
stop:
dt_trans_stop(env, dev, th);
unlock:
lfsck_ibits_unlock(&lh, LCK_EX);
out:
CDEBUG(D_LFSCK,
"%s: layout LFSCK assistant replaced the conflict OST-object "DFID" on the OST %x with the orphan "DFID" on the OST %x: parent "DFID", stripe-index %u: rc = %d\n",
lfsck_lfsck2name(lfsck), PFID(cfid2), ost_idx2,
PFID(cfid), ltd->ltd_index, PFID(lfsck_dto2fid(parent)),
ea_off, rc);
return rc >= 0 ? 1 : rc;
}
/**
* lfsck_layout_recreate_lovea() - Recreate LOV EA
* @env: Lustre environment
* @com: pointer to layout lfsck component (holds metadata + state)
* @ltd: pointer to target descriptor (OST object)
* @rec: pointer to orphan record (lu_orphan_rec_v3)
* @parent: pointer to parent MDT object (dt_object) holding LOV EA
* @cfid: pointer to file identifier (lu_fid) of the child (OST) object
* @ost_idx: index of OST on which OST object resides.
* @ea_off: offset within LOV EA (OST object)
*
* Retrun:
* * %+1 repaired
* * %0 did nothing
* * %negative on error
*/
static int lfsck_layout_recreate_lovea(const struct lu_env *env,
struct lfsck_component *com,
struct lfsck_tgt_desc *ltd,
struct lu_orphan_rec_v3 *rec,
struct dt_object *parent,
struct lu_fid *cfid,
__u32 ost_idx, __u32 ea_off)
{
struct lfsck_thread_info *info = lfsck_env_info(env);
struct lu_buf *buf = &info->lti_big_buf;
struct lu_fid *fid = &info->lti_fid2;
struct ost_id *oi = &info->lti_oi;
struct lfsck_instance *lfsck = com->lc_lfsck;
struct dt_device *dt = lfsck_obj2dev(parent);
struct lfsck_bookmark *bk = &lfsck->li_bookmark_ram;
struct ost_layout *ol = &rec->lor_layout;
struct lov_comp_md_v1 *lcm = NULL;
struct lov_comp_md_entry_v1 *lcme = NULL;
struct thandle *handle = NULL;
size_t lovea_size;
struct lov_mds_md_v1 *lmm;
struct lov_ost_data_v1 *objs;
struct lustre_handle lh = { 0 };
__u32 magic;
__u32 flags = 0;
int fl = 0;
int rc = 0;
int rc1;
int i;
int pos = 0;
__u16 count;
bool locked = false;
bool new_mirror = true;
ENTRY;
if (lfsck_is_dryrun(lfsck))
RETURN(0);
rc = lfsck_ibits_lock(env, lfsck, parent, &lh,
MDS_INODELOCK_LAYOUT | MDS_INODELOCK_XATTR,
LCK_EX);
if (rc != 0) {
CDEBUG(D_LFSCK,
"%s: layout LFSCK assistant failed to recreate LOV EA for "DFID": parent "DFID", OST-index %u, stripe-index %u, comp_id %u, comp_start %llu, comp_end %llu, layout version %u, range %u: rc = %d\n",
lfsck_lfsck2name(lfsck), PFID(cfid),
PFID(lfsck_dto2fid(parent)), ost_idx, ea_off,
ol->ol_comp_id, ol->ol_comp_start,
ol->ol_comp_end, rec->lor_layout_version,
rec->lor_range, rc);
RETURN(rc);
}
again:
if (locked) {
dt_write_unlock(env, parent);
locked = false;
}
if (handle != NULL) {
dt_trans_stop(env, dt, handle);
handle = NULL;
}
if (rc < 0)
GOTO(unlock_layout, rc);
lovea_size = rc;
if (buf->lb_len < lovea_size) {
lu_buf_realloc(buf, lovea_size);
if (buf->lb_buf == NULL)
GOTO(unlock_layout, rc = -ENOMEM);
}
if (!(bk->lb_param & LPF_DRYRUN)) {
handle = lfsck_trans_create(env, dt, lfsck);
if (IS_ERR(handle))
GOTO(unlock_layout, rc = PTR_ERR(handle));
rc = dt_declare_xattr_set(env, parent, NULL, buf,
XATTR_NAME_LOV, fl, handle);
if (rc != 0)
GOTO(stop, rc);
rc = dt_trans_start_local(env, dt, handle);
if (rc != 0)
GOTO(stop, rc);
}
dt_write_lock(env, parent, 0);
locked = true;
rc = dt_xattr_get(env, parent, buf, XATTR_NAME_LOV);
if (rc == -ERANGE) {
rc = dt_xattr_get(env, parent, &LU_BUF_NULL, XATTR_NAME_LOV);
LASSERT(rc != 0);
goto again;
} else if (rc == -ENODATA || rc == 0) {
lovea_size = lfsck_lovea_size(ol, ea_off);
/* If the declared is not big enough, re-try. */
if (buf->lb_len < lovea_size) {
rc = lovea_size;
goto again;
}
fl = LU_XATTR_CREATE;
} else if (rc < 0) {
GOTO(unlock_parent, rc);
} else if (unlikely(buf->lb_len == 0)) {
goto again;
} else {
fl = LU_XATTR_REPLACE;
lovea_size = rc;
}
if (fl == LU_XATTR_CREATE) {
if (bk->lb_param & LPF_DRYRUN)
GOTO(unlock_parent, rc = 1);
LASSERT(buf->lb_len >= lovea_size);
rc = lfsck_layout_update_lovea(env, lfsck, handle, rec, parent,
cfid, buf, fl, ost_idx, ea_off);
GOTO(unlock_parent, rc);
}
lmm = buf->lb_buf;
rc1 = lfsck_layout_verify_header(parent, lmm, lovea_size);
/* If the LOV EA crashed, the rebuild it. */
if (rc1 == -EINVAL) {
if (bk->lb_param & LPF_DRYRUN)
GOTO(unlock_parent, rc = 1);
LASSERT(buf->lb_len >= lovea_size);
rc = lfsck_layout_update_lovea(env, lfsck, handle, rec, parent,
cfid, buf, fl, ost_idx, ea_off);
GOTO(unlock_parent, rc);
}
/* For other unknown magic/pattern, keep the current LOV EA. */
if (rc1 == -EOPNOTSUPP)
GOTO(unlock_parent, rc1 = 0);
if (rc1)
GOTO(unlock_parent, rc = rc1);
magic = le32_to_cpu(lmm->lmm_magic);
if (magic == LOV_MAGIC_COMP_V1 || magic == LOV_MAGIC_SEL) {
__u64 start;
__u64 end;
__u16 mirror_id0 = mirror_id_of(ol->ol_comp_id);
__u16 mirror_id1;
if (bk->lb_param & LPF_DRYRUN)
GOTO(unlock_parent, rc = 1);
lcm = buf->lb_buf;
count = le16_to_cpu(lcm->lcm_entry_count);
for (i = 0; i < count; pos = ++i) {
lcme = &lcm->lcm_entries[i];
start = le64_to_cpu(lcme->lcme_extent.e_start);
end = le64_to_cpu(lcme->lcme_extent.e_end);
mirror_id1 = mirror_id_of(le32_to_cpu(lcme->lcme_id));
if (mirror_id0 > mirror_id1)
continue;
if (mirror_id0 < mirror_id1)
break;
new_mirror = false;
if (end <= ol->ol_comp_start)
continue;
if (start >= ol->ol_comp_end)
break;
lmm = buf->lb_buf + le32_to_cpu(lcme->lcme_offset);
magic = le32_to_cpu(lmm->lmm_magic);
flags = le32_to_cpu(lcme->lcme_flags);
goto further;
}
rc = lfsck_layout_add_comp(env, lfsck, handle, rec, parent,
cfid, buf, ost_idx, ea_off, pos, new_mirror);
GOTO(unlock_parent, rc);
}
further:
count = le16_to_cpu(lmm->lmm_stripe_count);
if (count == 0)
GOTO(unlock_parent, rc = -EINVAL);
LASSERT(count > 0);
/* Exceed the current end of MDT-object layout EA. Then extend it. */
if (count <= ea_off) {
if (bk->lb_param & LPF_DRYRUN)
GOTO(unlock_parent, rc = 1);
lovea_size = lov_mds_md_size(ea_off + 1, magic);
/* If the declared is not big enough, re-try. */
if (buf->lb_len < lovea_size) {
rc = lovea_size;
goto again;
}
if (lcm) {
LASSERT(lcme);
lcme->lcme_flags = cpu_to_le32(flags | LCME_FL_INIT);
lfsck_layout_update_lcm(lcm, lcme,
rec->lor_layout_version,
rec->lor_range);
}
rc = lfsck_layout_extend_v1v3_lovea(env, lfsck, handle, ol,
parent, cfid, buf, ost_idx, ea_off);
GOTO(unlock_parent, rc);
}
LASSERTF(rc > 0, "invalid rc = %d\n", rc);
if (magic == LOV_MAGIC_V1) {
objs = &lmm->lmm_objects[0];
} else {
LASSERT(magic == LOV_MAGIC_V3);
objs = &((struct lov_mds_md_v3 *)lmm)->lmm_objects[0];
}
for (i = 0; i < count; i++, objs++) {
/* The MDT-object was created via lfsck_layout_recover_create()
* by others before, and we fill the dummy layout EA.
*/
if ((lcme && !(flags & LCME_FL_INIT)) ||
lovea_slot_is_dummy(objs)) {
if (i != ea_off)
continue;
if (bk->lb_param & LPF_DRYRUN)
GOTO(unlock_parent, rc = 1);
lmm->lmm_layout_gen =
cpu_to_le16(le16_to_cpu(lmm->lmm_layout_gen) + 1);
if (lcme) {
LASSERT(lcm);
if (le32_to_cpu(lmm->lmm_stripe_size) !=
ol->ol_stripe_size ||
le16_to_cpu(lmm->lmm_stripe_count) !=
ol->ol_stripe_count ||
le64_to_cpu(lcme->lcme_extent.e_start) !=
ol->ol_comp_start ||
le64_to_cpu(lcme->lcme_extent.e_end) !=
ol->ol_comp_end) {
CDEBUG(D_LFSCK,
"%s: found invalid component for "DFID ": parent "DFID", stripe-index %u, stripe_size %u, stripe_count %u, comp_id %u, comp_start %llu, comp_end %llu, cur_stripe_size %u, cur_stripe_count %u, cur_comp_start %llu, cur_comp_end %llu\n",
lfsck_lfsck2name(lfsck), PFID(cfid),
PFID(lfsck_dto2fid(parent)), ea_off,
ol->ol_stripe_size,
ol->ol_stripe_count, ol->ol_comp_id,
ol->ol_comp_start, ol->ol_comp_end,
le32_to_cpu(lmm->lmm_stripe_size),
le16_to_cpu(lmm->lmm_stripe_count),
le64_to_cpu(lcme->lcme_extent.e_start),
le64_to_cpu(lcme->lcme_extent.e_end));
GOTO(unlock_parent, rc = -EINVAL);
}
lovea_size = le32_to_cpu(lcm->lcm_size);
lcme->lcme_flags = cpu_to_le32(flags |
LCME_FL_INIT);
lfsck_layout_update_lcm(lcm, lcme,
rec->lor_layout_version,
rec->lor_range);
}
LASSERTF(buf->lb_len >= lovea_size,
"buffer len %d is less than real size %d\n",
(int)buf->lb_len, (int)lovea_size);
rc = lfsck_layout_refill_lovea(env, lfsck, handle,
parent, cfid, buf, lmm, objs,
fl, ost_idx, lovea_size);
CDEBUG(D_LFSCK,
"%s layout LFSCK assistant fill dummy layout slot for "DFID": parent "DFID", OST-index %u, stripe-index %u: rc = %d\n",
lfsck_lfsck2name(lfsck), PFID(cfid),
PFID(lfsck_dto2fid(parent)), ost_idx, i, rc);
GOTO(unlock_parent, rc);
}
ostid_le_to_cpu(&objs->l_ost_oi, oi);
rc = ostid_to_fid(fid, oi, le32_to_cpu(objs->l_ost_idx));
if (rc != 0) {
CDEBUG(D_LFSCK,
"%s: the parent "DFID" contains invalid layout EA at the slot %d, index %u\n",
lfsck_lfsck2name(lfsck),
PFID(lfsck_dto2fid(parent)), i,
le32_to_cpu(objs->l_ost_idx));
GOTO(unlock_parent, rc);
}
/* It should be rare case, the slot is there, but the LFSCK
* does not handle it during the first-phase cycle scanning.
*/
if (unlikely(lu_fid_eq(fid, cfid))) {
if (i == ea_off) {
GOTO(unlock_parent, rc = 0);
} else {
/* Rare case that the OST-object index
* does not match the parent MDT-object
* layout EA. We trust the later one.
*/
if (bk->lb_param & LPF_DRYRUN)
GOTO(unlock_parent, rc = 1);
dt_write_unlock(env, parent);
if (handle != NULL)
dt_trans_stop(env, dt, handle);
lfsck_ibits_unlock(&lh, LCK_EX);
rc = lfsck_layout_update_pfid(env, com, parent,
cfid, ltd->ltd_tgt,
rec, i);
CDEBUG(D_LFSCK,
"%s layout LFSCK assistant updated OST-object's pfid for "DFID": parent "DFID", OST-index %u, stripe-index %u: rc = %d\n",
lfsck_lfsck2name(lfsck), PFID(cfid),
PFID(lfsck_dto2fid(parent)),
ltd->ltd_index, i, rc);
RETURN(rc);
}
}
}
/* MDT-obj exists, but related layout EA slot is occupied by others */
if (bk->lb_param & LPF_DRYRUN)
GOTO(unlock_parent, rc = 1);
dt_write_unlock(env, parent);
if (handle != NULL)
dt_trans_stop(env, dt, handle);
lfsck_ibits_unlock(&lh, LCK_EX);
if (magic == LOV_MAGIC_V1)
objs = &lmm->lmm_objects[ea_off];
else
objs = &((struct lov_mds_md_v3 *)lmm)->lmm_objects[ea_off];
rc = lfsck_layout_conflict_create(env, com, ltd, rec, parent, cfid,
buf, lmm, objs, ea_off, lovea_size);
RETURN(rc);
unlock_parent:
if (locked)
dt_write_unlock(env, parent);
stop:
if (handle != NULL)
dt_trans_stop(env, dt, handle);
unlock_layout:
lfsck_ibits_unlock(&lh, LCK_EX);
return rc;
}
static int lfsck_layout_scan_orphan_one(const struct lu_env *env,
struct lfsck_component *com,
struct lfsck_tgt_desc *ltd,
struct lu_orphan_rec_v3 *rec,
struct lu_fid *cfid)
{
struct lfsck_layout *lo = com->lc_file_ram;
struct lu_fid *pfid = &rec->lor_rec.lor_fid;
struct dt_object *parent = NULL;
__u32 ea_off = pfid->f_stripe_idx;
int rc = 0;
ENTRY;
if (!fid_is_sane(cfid))
GOTO(out, rc = -EINVAL);
pfid->f_ver = 0;
if (fid_is_zero(pfid)) {
rc = lfsck_layout_recreate_parent(env, com, ltd, rec, cfid,
"", "N", ea_off);
GOTO(out, rc);
}
if (!fid_is_sane(pfid))
GOTO(out, rc = -EINVAL);
parent = lfsck_object_find_by_dev(env, com->lc_lfsck->li_bottom, pfid);
if (IS_ERR(parent))
GOTO(out, rc = PTR_ERR(parent));
if (unlikely(dt_object_remote(parent) != 0))
GOTO(put, rc = -EXDEV);
if (dt_object_exists(parent) == 0) {
lfsck_object_put(env, parent);
rc = lfsck_layout_recreate_parent(env, com, ltd, rec, cfid,
"", "R", ea_off);
GOTO(out, rc);
}
if (!S_ISREG(lu_object_attr(&parent->do_lu)))
GOTO(put, rc = -EISDIR);
/* The orphan OST-object claims to be the parent's stripe, then
* related dangling record in the trace file is meaningless.
*/
rc = lfsck_layout_del_dangling_rec(env, com, pfid,
rec->lor_layout.ol_comp_id, ea_off);
if (rc && rc != -ENOENT)
GOTO(put, rc);
rc = lfsck_layout_recreate_lovea(env, com, ltd, rec, parent, cfid,
ltd->ltd_index, ea_off);
GOTO(put, rc);
put:
if (rc <= 0)
lfsck_object_put(env, parent);
else
/* The layout EA is changed, need to be reloaded next time. */
dt_object_put_nocache(env, parent);
out:
down_write(&com->lc_sem);
com->lc_new_scanned++;
com->lc_new_checked++;
if (rc > 0) {
lo->ll_objs_repaired[LLIT_ORPHAN - 1]++;
rc = 0;
} else if (rc < 0) {
lo->ll_objs_failed_phase2++;
}
up_write(&com->lc_sem);
return rc;
}
static int lfsck_layout_scan_orphan(const struct lu_env *env,
struct lfsck_component *com,
struct lfsck_tgt_desc *ltd)
{
struct lfsck_assistant_data *lad = com->lc_data;
struct lfsck_instance *lfsck = com->lc_lfsck;
struct lfsck_bookmark *bk = &lfsck->li_bookmark_ram;
struct lfsck_thread_info *info = lfsck_env_info(env);
struct lu_fid *fid = &info->lti_fid;
struct dt_object *obj;
const struct dt_it_ops *iops;
struct dt_it *di;
int rc = 0;
ENTRY;
CDEBUG(D_LFSCK,
"%s: layout LFSCK assistant starts the orphan scanning for OST%04x\n",
lfsck_lfsck2name(lfsck), ltd->ltd_index);
if (test_bit(ltd->ltd_index, lad->lad_bitmap)) {
CDEBUG(D_LFSCK,
"%s: layout LFSCK assistant skip the orphan scanning for OST%04x\n",
lfsck_lfsck2name(lfsck), ltd->ltd_index);
RETURN(0);
}
fid->f_seq = fid_idif_seq(0, ltd->ltd_index);
fid->f_oid = fid->f_ver = 0;
obj = lfsck_object_find_by_dev(env, ltd->ltd_tgt, fid);
if (unlikely(IS_ERR(obj)))
GOTO(log, rc = PTR_ERR(obj));
rc = obj->do_ops->do_index_try(env, obj,
&dt_lfsck_layout_orphan_features);
if (rc != 0)
GOTO(put, rc);
iops = &obj->do_index_ops->dio_it;
di = iops->init(env, obj, 0);
if (IS_ERR(di))
GOTO(put, rc = PTR_ERR(di));
rc = iops->load(env, di, 0);
if (rc == -ESRCH) {
/* -ESRCH means that the orphan OST-objects rbtree has been
* cleanup because of the OSS server restart or other errors.
*/
lfsck_lad_set_bitmap(env, com, ltd->ltd_index);
GOTO(fini, rc);
}
if (rc == 0)
rc = iops->next(env, di);
else if (rc > 0)
rc = 0;
if (rc < 0)
GOTO(fini, rc);
if (rc > 0)
GOTO(fini, rc = 0);
while (rc == 0 && !lfsck_should_stop(lfsck)) {
struct dt_key *key;
struct lu_orphan_rec_v3 *rec = &info->lti_rec;
if (LFSCK_FAIL_TIMEOUT(lfsck, OBD_FAIL_LFSCK_DELAY3,
cfs_fail_val))
break;
key = iops->key(env, di);
com->lc_fid_latest_scanned_phase2 = *(struct lu_fid *)key;
/* Remote target OST may be runnning old LFSCK */
memset(rec, 0, sizeof(*rec));
rc = iops->rec(env, di, (struct dt_rec *)rec, 0);
if (rc == 0)
rc = lfsck_layout_scan_orphan_one(env, com, ltd, rec,
&com->lc_fid_latest_scanned_phase2);
if (rc != 0 && bk->lb_param & LPF_FAILOUT)
GOTO(fini, rc);
lfsck_control_speed_by_self(com);
do {
rc = iops->next(env, di);
} while (rc < 0 && !(bk->lb_param & LPF_FAILOUT));
}
GOTO(fini, rc);
fini:
iops->put(env, di);
iops->fini(env, di);
put:
lfsck_object_put(env, obj);
log:
CDEBUG(D_LFSCK,
"%s: layout LFSCK assistant finished the orphan scanning for OST%04x: rc = %d\n",
lfsck_lfsck2name(lfsck), ltd->ltd_index, rc);
return rc > 0 ? 0 : rc;
}
static int lfsck_lov2layout(struct lov_mds_md_v1 *lmm, struct filter_fid *ff,
__u32 comp_id)
{
struct ost_layout *ol = &ff->ff_layout;
__u32 magic = le32_to_cpu(lmm->lmm_magic);
int rc = 0;
ENTRY;
if (magic == LOV_MAGIC_V1 || magic == LOV_MAGIC_V3) {
ol->ol_stripe_size = lmm->lmm_stripe_size;
ol->ol_stripe_count = lmm->lmm_stripe_count;
ol->ol_comp_start = 0;
ol->ol_comp_end = 0;
ol->ol_comp_id = 0;
ff->ff_layout_version = 0;
ff->ff_range = 0;
} else if (magic == LOV_MAGIC_COMP_V1 || magic == LOV_MAGIC_SEL) {
struct lov_comp_md_v1 *lcm = (struct lov_comp_md_v1 *)lmm;
struct lov_comp_md_entry_v1 *lcme = NULL;
__u16 count = le16_to_cpu(lcm->lcm_entry_count);
int i;
for (i = 0; i < count; i++) {
lcme = &lcm->lcm_entries[i];
if (le32_to_cpu(lcme->lcme_id) == comp_id) {
LASSERT(le32_to_cpu(lcme->lcme_flags) &
LCME_FL_INIT);
break;
}
}
/* The comp has been removed, do nothing. */
if (i == count)
GOTO(out, rc = 1);
lmm = (void *)lmm + le32_to_cpu(lcme->lcme_offset);
ol->ol_stripe_size = le32_to_cpu(lmm->lmm_stripe_size);
ol->ol_stripe_count = le32_to_cpu(lmm->lmm_stripe_count);
ol->ol_comp_start = le64_to_cpu(lcme->lcme_extent.e_start);
ol->ol_comp_end = le64_to_cpu(lcme->lcme_extent.e_end);
ol->ol_comp_id = le32_to_cpu(lcme->lcme_id);
ff->ff_layout_version = le32_to_cpu(lcme->lcme_layout_gen);
ff->ff_range = 0;
} else {
GOTO(out, rc = -EINVAL);
}
EXIT;
out:
return rc;
}
/**
* __lfsck_layout_repair_dangling() - Repair the MDT-object with dangling
* LOV EA reference.
* @env: pointer to the thread context
* @com: the layout LFSCK component
* @parent: the MDT-object with dangling LOV EA reference
* @child: the OST-object to be created
* @comp_id: the component ID of the OST-object in the LOV EA
* @ea_off: the offset of the OST-object in the LOV EA
* @ost_idx: the index of OST on which the OST-object resides
* @log: If %true & Debug enabled. Then print debug log
*
* we need to repair the inconsistency according to the users' requirement:
*
* 1) Keep the inconsistency there and report the inconsistency case,
* then give the chance to the application to find related issues,
* and the users can make the decision about how to handle it with
* more human knownledge. (by default)
*
* 2) Re-create the missing OST-object with the FID/owner information.
*
* Return:
* * %+1 for repair successfully
* * %0 for did nothing
* * %negative error number on failure
*/
static int __lfsck_layout_repair_dangling(const struct lu_env *env,
struct lfsck_component *com,
struct dt_object *parent,
struct dt_object *child,
__u32 comp_id, __u32 ea_off,
__u32 ost_idx, bool log)
{
struct lfsck_thread_info *info = lfsck_env_info(env);
struct filter_fid *ff = &info->lti_ff;
struct dt_object_format *dof = &info->lti_dof;
struct lu_attr *la = &info->lti_la;
struct lfsck_instance *lfsck = com->lc_lfsck;
struct dt_device *dev = lfsck_obj2dev(child);
const struct lu_fid *pfid = lfsck_dto2fid(parent);
const struct lu_fid *cfid = lfsck_dto2fid(child);
struct lu_buf *tbuf = &info->lti_big_buf;
struct thandle *handle;
struct lu_buf *buf;
struct lustre_handle lh = { 0 };
int rc;
ENTRY;
if (!(lfsck->li_bookmark_ram.lb_param & LPF_CREATE_OSTOBJ))
GOTO(log, rc = 1);
if (lfsck->li_bookmark_ram.lb_param & LPF_DRYRUN)
GOTO(log, rc = 1);
rc = lfsck_ibits_lock(env, lfsck, parent, &lh,
MDS_INODELOCK_LAYOUT | MDS_INODELOCK_XATTR,
LCK_EX);
if (rc != 0)
GOTO(log, rc);
rc = dt_attr_get(env, parent, la);
if (rc != 0)
GOTO(unlock1, rc);
la->la_mode = S_IFREG | 0666;
la->la_atime = la->la_mtime = la->la_ctime = 0;
la->la_valid = LA_TYPE | LA_MODE | LA_UID | LA_GID |
LA_ATIME | LA_MTIME | LA_CTIME;
memset(dof, 0, sizeof(*dof));
ff->ff_parent.f_seq = cpu_to_le64(pfid->f_seq);
ff->ff_parent.f_oid = cpu_to_le32(pfid->f_oid);
/* Currently, the filter_fid::ff_parent::f_ver is not the real parent
* MDT-object's FID::f_ver, instead it is the OST-object index in its
* parent MDT-object's layout EA.
*/
ff->ff_parent.f_stripe_idx = cpu_to_le32(ea_off);
rc = lfsck_layout_get_lovea(env, parent, tbuf);
if (unlikely(rc == -ENODATA))
rc = 0;
if (rc <= 0)
GOTO(unlock1, rc);
rc = lfsck_lov2layout(tbuf->lb_buf, ff, comp_id);
if (rc)
GOTO(unlock1, rc);
buf = lfsck_buf_get(env, ff, sizeof(struct filter_fid));
handle = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(handle))
GOTO(unlock1, rc = PTR_ERR(handle));
rc = dt_declare_create(env, child, la, NULL, dof, handle);
if (rc != 0)
GOTO(stop, rc);
rc = dt_declare_xattr_set(env, child, NULL, buf, XATTR_NAME_FID,
LU_XATTR_CREATE, handle);
if (rc != 0)
GOTO(stop, rc);
rc = dt_trans_start_local(env, dev, handle);
if (rc != 0)
GOTO(stop, rc);
dt_read_lock(env, parent, 0);
if (unlikely(lfsck_is_dead_obj(parent)))
GOTO(unlock2, rc = 0);
if (lfsck->li_bookmark_ram.lb_param & LPF_DELAY_CREATE_OSTOBJ) {
struct ost_id *oi = &info->lti_oi;
struct lu_fid *tfid = &info->lti_fid2;
struct lu_buf *lovea = &info->lti_big_buf;
struct lov_mds_md_v1 *lmm;
struct lov_ost_data_v1 *objs;
__u32 magic;
int count;
int idx2;
rc = lfsck_layout_get_lovea(env, parent, lovea);
if (unlikely(rc == -ENODATA))
rc = 0;
if (rc <= 0)
GOTO(unlock2, rc);
lmm = lovea->lb_buf;
magic = le32_to_cpu(lmm->lmm_magic);
if (magic == LOV_MAGIC_COMP_V1 || magic == LOV_MAGIC_SEL) {
struct lov_comp_md_v1 *lcm = buf->lb_buf;
struct lov_comp_md_entry_v1 *lcme;
__u16 count = le16_to_cpu(lcm->lcm_entry_count);
int i;
for (i = 0; i < count; i++) {
lcme = &lcm->lcm_entries[i];
if (le32_to_cpu(lcme->lcme_id) == comp_id) {
LASSERT(le32_to_cpu(lcme->lcme_flags) &
LCME_FL_INIT);
lmm = lovea->lb_buf +
le32_to_cpu(lcme->lcme_offset);
magic = le32_to_cpu(lmm->lmm_magic);
goto check;
}
}
/* Someone removed the component, do nothing. */
GOTO(unlock2, rc = 0);
}
check:
count = le16_to_cpu(lmm->lmm_stripe_count);
/* Someone changed the LOV EA, do nothing. */
if (count <= ea_off)
GOTO(unlock2, rc = 0);
if (magic == LOV_MAGIC_V1) {
objs = &lmm->lmm_objects[ea_off];
} else {
LASSERT(magic == LOV_MAGIC_V3);
objs = &((struct lov_mds_md_v3 *)lmm)->\
lmm_objects[ea_off];
}
ostid_le_to_cpu(&objs->l_ost_oi, oi);
idx2 = le32_to_cpu(objs->l_ost_idx);
rc = ostid_to_fid(tfid, oi, idx2);
/* Someone changed the LOV EA, do nothing. */
if (rc != 0 || !lu_fid_eq(tfid, cfid))
GOTO(unlock2, rc);
}
rc = dt_create(env, child, la, NULL, dof, handle);
if (rc != 0)
GOTO(unlock2, rc);
rc = dt_xattr_set(env, child, buf, XATTR_NAME_FID, LU_XATTR_CREATE,
handle);
GOTO(unlock2, rc);
unlock2:
dt_read_unlock(env, parent);
stop:
rc = lfsck_layout_trans_stop(env, dev, handle, rc);
unlock1:
lfsck_ibits_unlock(&lh, LCK_EX);
log:
if (rc && log)
CDEBUG(D_LFSCK,
"%s: layout LFSCK assistant found dangling reference for: parent "DFID", child "DFID", comp_id %u, ea_off %u, ost_idx %u, %s: rc = %d\n",
lfsck_lfsck2name(lfsck), PFID(pfid), PFID(cfid),
comp_id, ea_off, ost_idx,
(lfsck->li_bookmark_ram.lb_param & LPF_CREATE_OSTOBJ) ?
"Create the lost OST-object as required" :
"Keep the MDT-object there by default", rc);
return rc;
}
/**
* lfsck_layout_repair_dangling() - Repair the MDT-object with dangling LOV EA
* reference.
* @env: pointer to the thread context
* @com: the layout LFSCK component
* @pfid: the MDT-object's FID
* @cfid: the FID for the OST-object to be created
* @comp_id: the component ID of the OST-object in the LOV EA
* @ea_off: the offset of the OST-object in the LOV EA
* @ost_idx: the index of OST on which the OST-object resides
*
* Prepare parameters and call __lfsck_layout_repair_dangling()
* to repair the dangling LOV EA reference.
*
* Return:
* * %+1 for repair successfully
* * %0 for did nothing
* * %negative error number on failure
*/
static int lfsck_layout_repair_dangling(const struct lu_env *env,
struct lfsck_component *com,
const struct lu_fid *pfid,
const struct lu_fid *cfid,
__u32 comp_id, __u32 ea_off,
__u32 ost_idx)
{
struct lfsck_instance *lfsck = com->lc_lfsck;
struct dt_object *parent = NULL;
struct dt_object *child = NULL;
struct lfsck_tgt_desc *ltd;
int rc;
ENTRY;
parent = lfsck_object_find_bottom(env, lfsck, pfid);
if (IS_ERR(parent))
GOTO(log, rc = PTR_ERR(parent));
/* The MDT-object has been removed. */
if (dt_object_exists(parent) == 0)
GOTO(log, rc = 0);
ltd = lfsck_ltd2tgt(&lfsck->li_ost_descs, ost_idx);
if (unlikely(ltd == NULL))
GOTO(log, rc = -ENODEV);
child = lfsck_object_find_by_dev(env, ltd->ltd_tgt, cfid);
if (IS_ERR(child))
GOTO(log, rc = PTR_ERR(child));
/* The OST-object has been created. */
if (unlikely(dt_object_exists(child) != 0))
GOTO(log, rc = 0);
rc = __lfsck_layout_repair_dangling(env, com, parent, child,
comp_id, ea_off, ost_idx, false);
GOTO(log, rc);
log:
if (child != NULL && !IS_ERR(child))
lfsck_object_put(env, child);
if (parent != NULL && !IS_ERR(parent))
lfsck_object_put(env, parent);
if (rc)
CDEBUG(D_LFSCK,
"%s: layout LFSCK assistant found dangling reference for: parent "DFID", child "DFID", comp_id %u, ea_off %u, ost_idx %u, %s: rc = %d\n",
lfsck_lfsck2name(lfsck), PFID(pfid), PFID(cfid),
comp_id, ea_off, ost_idx,
(lfsck->li_bookmark_ram.lb_param & LPF_CREATE_OSTOBJ) ?
"Create the lost OST-object as required" :
"Keep the MDT-object there by default", rc);
return rc;
}
/* If the OST-object does not recognize the MDT-object as its parent, and
* there is no other MDT-object claims as its parent, then just trust the
* given MDT-object as its parent. So update the OST-object filter_fid.
*/
static int lfsck_layout_repair_unmatched_pair(const struct lu_env *env,
struct lfsck_component *com,
struct dt_object *parent,
struct lfsck_layout_req *llr,
struct lu_attr *la)
{
struct lfsck_thread_info *info = lfsck_env_info(env);
struct filter_fid *ff = &info->lti_ff;
struct dt_object *child = llr->llr_child;
struct dt_device *dev = lfsck_obj2dev(child);
const struct lu_fid *tfid = lu_object_fid(&parent->do_lu);
struct lu_buf *tbuf = &info->lti_big_buf;
struct thandle *handle;
struct lu_buf *buf;
struct lustre_handle lh = { 0 };
int rc;
ENTRY;
if (com->lc_lfsck->li_bookmark_ram.lb_param & LPF_DRYRUN)
GOTO(log, rc = 0);
rc = lfsck_ibits_lock(env, com->lc_lfsck, parent, &lh,
MDS_INODELOCK_LAYOUT | MDS_INODELOCK_XATTR,
LCK_EX);
if (rc != 0)
GOTO(log, rc);
ff->ff_parent.f_seq = cpu_to_le64(tfid->f_seq);
ff->ff_parent.f_oid = cpu_to_le32(tfid->f_oid);
/* Currently, the filter_fid::ff_parent::f_ver is not the real parent
* MDT-object's FID::f_ver, instead it is the OST-object index in its
* parent MDT-object's layout EA.
*/
ff->ff_parent.f_stripe_idx = cpu_to_le32(llr->llr_lov_idx);
rc = lfsck_layout_get_lovea(env, parent, tbuf);
if (unlikely(rc == -ENODATA))
rc = 0;
if (rc <= 0)
GOTO(unlock1, rc);
rc = lfsck_lov2layout(tbuf->lb_buf, ff, llr->llr_comp_id);
if (rc)
GOTO(unlock1, rc);
buf = lfsck_buf_get(env, ff, sizeof(*ff));
handle = lfsck_trans_create(env, dev, com->lc_lfsck);
if (IS_ERR(handle))
GOTO(unlock1, rc = PTR_ERR(handle));
rc = dt_declare_xattr_set(env, child, NULL, buf, XATTR_NAME_FID, 0,
handle);
if (rc != 0)
GOTO(stop, rc);
rc = dt_attr_get(env, parent, la);
if (rc != 0)
GOTO(stop, rc);
la->la_valid = LA_UID | LA_GID;
rc = dt_declare_attr_set(env, child, la, handle);
if (rc != 0)
GOTO(stop, rc);
rc = dt_trans_start_local(env, dev, handle);
if (rc != 0)
GOTO(stop, rc);
dt_write_lock(env, parent, 0);
if (unlikely(lfsck_is_dead_obj(parent)))
GOTO(unlock2, rc = 1);
rc = dt_xattr_set(env, child, buf, XATTR_NAME_FID, 0, handle);
if (rc != 0)
GOTO(unlock2, rc);
/* Get the latest parent's owner. */
rc = dt_attr_get(env, parent, la);
if (rc != 0)
GOTO(unlock2, rc);
la->la_valid = LA_UID | LA_GID;
rc = dt_attr_set(env, child, la, handle);
GOTO(unlock2, rc);
unlock2:
dt_write_unlock(env, parent);
stop:
rc = lfsck_layout_trans_stop(env, dev, handle, rc);
unlock1:
lfsck_ibits_unlock(&lh, LCK_EX);
log:
if (rc)
CDEBUG(D_LFSCK,
"%s: layout LFSCK assistant repaired unmatched MDT-OST pair for: parent "DFID", child "DFID", comp_id %u, OST-index %u, stripe-index %u, owner %u/%u: rc = %d\n",
lfsck_lfsck2name(com->lc_lfsck),
PFID(lfsck_dto2fid(parent)),
PFID(lfsck_dto2fid(child)),
llr->llr_comp_id, llr->llr_ost_idx, llr->llr_lov_idx,
la->la_uid, la->la_gid, rc);
return rc;
}
/* If there are more than one MDT-objects claim as the OST-object's parent,
* and the OST-object only recognizes one of them, then we need to generate
* new OST-object(s) with new fid(s) for the non-recognized MDT-object(s).
*/
static int lfsck_layout_repair_multiple_references(const struct lu_env *env,
struct lfsck_component *com,
struct dt_object *parent,
struct lfsck_layout_req *llr,
struct lu_attr *la)
{
struct lfsck_thread_info *info = lfsck_env_info(env);
struct dt_allocation_hint *hint = &info->lti_hint;
struct dt_object_format *dof = &info->lti_dof;
struct ost_id *oi = &info->lti_oi;
struct lu_buf *buf = &info->lti_big_buf;
struct lfsck_instance *lfsck = com->lc_lfsck;
struct dt_device *dev;
struct lu_device *d = &lfsck_obj2dev(llr->llr_child)->dd_lu_dev;
struct lu_object *o;
struct lu_object *n;
struct dt_object *child = NULL;
struct thandle *handle = NULL;
struct lov_mds_md_v1 *lmm;
struct lov_ost_data_v1 *objs;
const struct lu_fid *pfid = lfsck_dto2fid(parent);
struct lu_fid tfid;
struct lustre_handle lh = { 0 };
__u32 magic;
__u32 index;
int rc;
ENTRY;
if (lfsck->li_bookmark_ram.lb_param & LPF_DRYRUN)
RETURN(0);
/* We use two separated transactions to repair the inconsistency.
*
* 1) create the child (OST-object).
* 2) update the parent LOV EA according to the child's FID.
*
* If 1) succeed, but 2) failed or aborted, then such OST-object will be
* handled as orphan when the layout LFSCK run next time.
*
* If 1) failed, but 2) succeed, then such OST-object will be re-created
* as dangling referened case when the layout LFSCK run next time.
*/
/* The 1st transaction. */
o = lu_object_anon(env, d, NULL);
if (IS_ERR(o))
GOTO(log, rc = PTR_ERR(o));
n = lu_object_locate(o->lo_header, d->ld_type);
if (unlikely(n == NULL)) {
lu_object_put_nocache(env, o);
GOTO(log, rc = -EINVAL);
}
child = container_of(n, struct dt_object, do_lu);
memset(hint, 0, sizeof(*hint));
rc = dt_attr_get(env, parent, la);
if (rc != 0)
GOTO(log, rc);
la->la_valid = LA_UID | LA_GID;
memset(dof, 0, sizeof(*dof));
dev = lfsck_obj2dev(child);
handle = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(handle))
GOTO(log, rc = PTR_ERR(handle));
rc = dt_declare_create(env, child, la, hint, dof, handle);
if (rc != 0)
GOTO(stop, rc);
rc = dt_trans_start_local(env, dev, handle);
if (rc != 0)
GOTO(stop, rc);
rc = dt_create(env, child, la, hint, dof, handle);
dt_trans_stop(env, dev, handle);
handle = NULL;
if (rc != 0)
GOTO(log, rc);
rc = lfsck_ibits_lock(env, lfsck, parent, &lh,
MDS_INODELOCK_LAYOUT | MDS_INODELOCK_XATTR,
LCK_EX);
if (rc != 0)
GOTO(log, rc);
/* The 2nd transaction. */
/* XXX: Generally, we should use bottom device (OSD) to update parent
* LOV EA. But because the LOD-object still references the wrong
* OSP-object that should be detached after the parent's LOV EA
* refreshed. Unfortunately, there is no suitable API for that.
* So we have to make the LOD to re-load the OSP-object(s) via
* replacing the LOV EA against the LOD-object.
*
* Once the DNE2 patches have been landed, we can replace the
* LOD device with the OSD device. LU-6230.
*/
dev = lfsck->li_next;
parent = lfsck_object_locate(dev, parent);
if (IS_ERR(parent))
GOTO(log, rc = PTR_ERR(parent));
handle = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(handle))
GOTO(log, rc = PTR_ERR(handle));
rc = dt_declare_xattr_set(env, parent, NULL, buf, XATTR_NAME_LOV,
LU_XATTR_REPLACE, handle);
if (rc != 0)
GOTO(stop, rc);
rc = dt_trans_start_local(env, dev, handle);
if (rc != 0)
GOTO(stop, rc);
dt_write_lock(env, parent, 0);
if (unlikely(lfsck_is_dead_obj(parent)))
GOTO(unlock, rc = 0);
rc = lfsck_layout_get_lovea(env, parent, buf);
if (unlikely(rc == -ENODATA))
rc = 0;
if (rc <= 0)
GOTO(unlock, rc);
lmm = buf->lb_buf;
magic = le32_to_cpu(lmm->lmm_magic);
if (magic == LOV_MAGIC_COMP_V1 || magic == LOV_MAGIC_SEL) {
struct lov_comp_md_v1 *lcm = buf->lb_buf;
struct lov_comp_md_entry_v1 *lcme;
__u16 count = le16_to_cpu(lcm->lcm_entry_count);
int i;
LASSERT(llr->llr_comp_id != 0);
for (i = 0; i < count; i++) {
lcme = &lcm->lcm_entries[i];
if (le32_to_cpu(lcme->lcme_id) == llr->llr_comp_id) {
LASSERT(le32_to_cpu(lcme->lcme_flags) &
LCME_FL_INIT);
le32_add_cpu(&lcm->lcm_layout_gen, 1);
lmm = buf->lb_buf +
le32_to_cpu(lcme->lcme_offset);
magic = le32_to_cpu(lmm->lmm_magic);
goto set;
}
}
GOTO(unlock, rc = 0);
}
set:
if (magic == LOV_MAGIC_V1) {
objs = &lmm->lmm_objects[llr->llr_lov_idx];
} else {
LASSERT(magic == LOV_MAGIC_V3);
objs =
&((struct lov_mds_md_v3 *)lmm)->lmm_objects[llr->llr_lov_idx];
}
ostid_le_to_cpu(&objs->l_ost_oi, oi);
index = le32_to_cpu(objs->l_ost_idx);
rc = ostid_to_fid(&tfid, oi, index);
/* Someone changed layout during the LFSCK, no need to repair then. */
if (rc == 0 && !lu_fid_eq(&tfid, lu_object_fid(&llr->llr_child->do_lu)))
GOTO(unlock, rc = 0);
lmm->lmm_layout_gen = cpu_to_le16(le16_to_cpu(lmm->lmm_layout_gen) + 1);
fid_to_ostid(lu_object_fid(&child->do_lu), oi);
ostid_cpu_to_le(oi, &objs->l_ost_oi);
objs->l_ost_gen = cpu_to_le32(0);
objs->l_ost_idx = cpu_to_le32(llr->llr_ost_idx);
rc = dt_xattr_set(env, parent, buf, XATTR_NAME_LOV,
LU_XATTR_REPLACE, handle);
GOTO(unlock, rc = (rc == 0 ? 1 : rc));
unlock:
dt_write_unlock(env, parent);
stop:
if (handle != NULL)
dt_trans_stop(env, dev, handle);
log:
lfsck_ibits_unlock(&lh, LCK_EX);
if (child != NULL)
lfsck_object_put(env, child);
if (rc)
CDEBUG(D_LFSCK,
"%s: layout LFSCK assistant repaired multiple references for: parent "DFID", comp_id %u, OST-index %u, stripe-index %u, owner %u/%u: rc = %d\n",
lfsck_lfsck2name(lfsck), PFID(pfid),
llr->llr_comp_id, llr->llr_ost_idx, llr->llr_lov_idx,
la->la_uid, la->la_gid, rc);
return rc;
}
/* If the MDT-object and the OST-object have different owner information,
* then trust the MDT-object, because the normal chown/chgrp handle order
* is from MDT to OST, and it is possible that some chown/chgrp operation
* is partly done.
*/
static int lfsck_layout_repair_owner(const struct lu_env *env,
struct lfsck_component *com,
struct dt_object *parent,
struct lfsck_layout_req *llr,
struct lu_attr *pla,
const struct lu_attr *cla)
{
struct lfsck_thread_info *info = lfsck_env_info(env);
struct lu_attr *tla = &info->lti_la2;
struct dt_object *child = llr->llr_child;
struct dt_device *dev = lfsck_obj2dev(child);
struct thandle *handle;
int rc;
dt_obj_version_t version;
ENTRY;
if (com->lc_lfsck->li_bookmark_ram.lb_param & LPF_DRYRUN)
RETURN(0);
tla->la_uid = pla->la_uid;
tla->la_gid = pla->la_gid;
tla->la_projid = pla->la_projid;
tla->la_valid = LA_UID | LA_GID | LA_PROJID;
handle = lfsck_trans_create(env, dev, com->lc_lfsck);
if (IS_ERR(handle))
GOTO(log, rc = PTR_ERR(handle));
rc = dt_declare_attr_set(env, child, tla, handle);
if (rc != 0)
GOTO(stop, rc);
rc = dt_trans_start_local(env, dev, handle);
if (rc != 0)
GOTO(stop, rc);
/* Use the dt_object lock to serialize with destroy and attr_set. */
dt_read_lock(env, parent, 0);
if (unlikely(lfsck_is_dead_obj(parent)))
GOTO(unlock, rc = 1);
version = dt_version_get(env, child);
if (version == -EOPNOTSUPP)
version = 0;
/* Get the latest parent's owner. */
rc = dt_attr_get(env, parent, pla);
if (rc != 0)
GOTO(unlock, rc);
/* Some others chown/chgrp during the LFSCK, needs to do nothing. */
if (unlikely((!version && tla->la_ctime == 0) ||
tla->la_uid != pla->la_uid || tla->la_gid != pla->la_gid))
rc = 1;
else
rc = dt_attr_set(env, child, tla, handle);
GOTO(unlock, rc);
unlock:
dt_read_unlock(env, parent);
stop:
rc = lfsck_layout_trans_stop(env, dev, handle, rc);
log:
if (rc != 0)
CDEBUG(D_LFSCK,
"%s: layout LFSCK assistant repaired inconsistent file owner for: parent "DFID", child "DFID", OST-index %u, stripe-index %u, old owner %u/%u, new owner %u/%u: rc = %d\n",
lfsck_lfsck2name(com->lc_lfsck),
PFID(lfsck_dto2fid(parent)), PFID(lfsck_dto2fid(child)),
llr->llr_ost_idx, llr->llr_lov_idx,
cla->la_uid, cla->la_gid, tla->la_uid, tla->la_gid, rc);
return rc;
}
#define CDEBUG_UNMATCHED_PAIR(lfsck, lso, pfid, cfid, msg) \
CDEBUG(D_LFSCK, "%s:("DFID"|"DFID")/"DFID":XATTR %s: %s\n", \
lfsck_lfsck2name(lfsck), PFID(&lso->lso_fid), PFID(pfid), \
PFID(cfid), XATTR_NAME_FID, msg);
/* Check whether the OST-object correctly back points to the
* MDT-object (@parent) via the XATTR_NAME_FID xattr (@pfid).
*/
static int lfsck_layout_check_parent(const struct lu_env *env,
struct lfsck_component *com,
struct lfsck_assistant_object *lso,
struct filter_fid *ff,
const struct lu_fid *cfid,
const struct lu_attr *cla,
struct lfsck_layout_req *llr)
{
struct lfsck_thread_info *info = lfsck_env_info(env);
struct lu_buf *buf = &info->lti_big_buf;
struct lu_fid *pfid = &info->lti_fid;
struct dt_object *tobj;
struct lov_mds_md_v1 *lmm;
struct lov_ost_data_v1 *objs;
struct lustre_handle lh = { 0 };
struct lfsck_instance *lfsck = com->lc_lfsck;
int rc;
int i;
__u32 magic;
__u32 idx;
__u16 count;
ENTRY;
*pfid = ff->ff_parent;
idx = pfid->f_stripe_idx;
pfid->f_ver = 0;
if (unlikely(!fid_is_sane(pfid))) {
CDEBUG_UNMATCHED_PAIR(lfsck, lso, pfid, cfid,
"the parent FID is invalid");
RETURN(LLIT_UNMATCHED_PAIR);
}
if (lu_fid_eq(pfid, &lso->lso_fid)) {
if (likely(llr->llr_lov_idx == idx))
RETURN(0);
CDEBUG_UNMATCHED_PAIR(lfsck, lso, pfid, cfid,
"the stripe index is unmatched");
RETURN(LLIT_UNMATCHED_PAIR);
}
tobj = lfsck_object_find_bottom(env, com->lc_lfsck, pfid);
if (IS_ERR(tobj))
RETURN(PTR_ERR(tobj));
if (dt_object_exists(tobj) == 0) {
CDEBUG_UNMATCHED_PAIR(lfsck, lso, pfid, cfid,
"the parent is nonexistent");
GOTO(out, rc = LLIT_UNMATCHED_PAIR);
}
if (lfsck_is_dead_obj(tobj)) {
CDEBUG_UNMATCHED_PAIR(lfsck, lso, pfid, cfid,
"the parent is dead object");
GOTO(out, rc = LLIT_UNMATCHED_PAIR);
}
if (!S_ISREG(lfsck_object_type(tobj))) {
CDEBUG_UNMATCHED_PAIR(lfsck, lso, pfid, cfid,
"the parent is not a regular file");
GOTO(out, rc = LLIT_UNMATCHED_PAIR);
}
/* Load the tobj's layout EA, in spite of it is a local MDT-object or
* remote one on another MDT. Then check whether the given OST-object
* is in such layout. If yes, it is multiple referenced, otherwise it
* is unmatched referenced case.
*/
rc = lfsck_layout_get_lovea(env, tobj, buf);
if (rc == 0 || rc == -ENODATA || rc == -ENOENT) {
CDEBUG_UNMATCHED_PAIR(lfsck, lso, pfid, cfid,
"the parent has no stripe data");
GOTO(out, rc = LLIT_UNMATCHED_PAIR);
}
if (unlikely(rc == -EOPNOTSUPP))
GOTO(out, rc = LLIT_NONE);
if (rc < 0)
GOTO(out, rc);
lmm = buf->lb_buf;
magic = le32_to_cpu(lmm->lmm_magic);
if (magic == LOV_MAGIC_COMP_V1 || magic == LOV_MAGIC_SEL) {
struct lov_comp_md_v1 *lcm = buf->lb_buf;
struct lov_comp_md_entry_v1 *lcme;
if (ff->ff_layout.ol_comp_id == 0) {
CDEBUG_UNMATCHED_PAIR(lfsck, lso, pfid, cfid,
"the parent has incorrect comp_id");
GOTO(out, rc = LLIT_UNMATCHED_PAIR);
}
count = le16_to_cpu(lcm->lcm_entry_count);
for (i = 0; i < count; i++) {
lcme = &lcm->lcm_entries[i];
if (le32_to_cpu(lcme->lcme_id) ==
ff->ff_layout.ol_comp_id) {
lmm = buf->lb_buf +
le32_to_cpu(lcme->lcme_offset);
magic = le32_to_cpu(lmm->lmm_magic);
if (!(le32_to_cpu(lcme->lcme_flags) &
LCME_FL_INIT)) {
CDEBUG_UNMATCHED_PAIR(lfsck, lso, pfid,
cfid,
"the parent has uninitialized component");
GOTO(out, rc = LLIT_UNMATCHED_PAIR);
}
goto further;
}
}
CDEBUG_UNMATCHED_PAIR(lfsck, lso, pfid, cfid,
"the parent has no matched comp_id");
GOTO(out, rc = LLIT_UNMATCHED_PAIR);
}
further:
if (magic == LOV_MAGIC_V1) {
objs = &lmm->lmm_objects[0];
} else {
LASSERT(magic == LOV_MAGIC_V3);
objs = &((struct lov_mds_md_v3 *)lmm)->lmm_objects[0];
}
count = le16_to_cpu(lmm->lmm_stripe_count);
for (i = 0; i < count; i++, objs++) {
struct lu_fid *tfid = &info->lti_fid2;
struct ost_id *oi = &info->lti_oi;
__u32 idx2;
if (lovea_slot_is_dummy(objs))
continue;
ostid_le_to_cpu(&objs->l_ost_oi, oi);
idx2 = le32_to_cpu(objs->l_ost_idx);
rc = ostid_to_fid(tfid, oi, idx2);
if (rc != 0) {
CDEBUG(D_LFSCK,
"%s: the parent "DFID" contains invalid layout EA at the slot %d, index %u\n",
lfsck_lfsck2name(com->lc_lfsck),
PFID(pfid), i, idx2);
GOTO(out, rc = LLIT_UNMATCHED_PAIR);
}
if (lu_fid_eq(cfid, tfid)) {
rc = lfsck_ibits_lock(env, com->lc_lfsck, tobj, &lh,
MDS_INODELOCK_UPDATE |
MDS_INODELOCK_LAYOUT |
MDS_INODELOCK_XATTR,
LCK_EX);
if (rc != 0)
GOTO(out, rc);
dt_read_lock(env, tobj, 0);
/* For local MDT-object, re-check existence
* after taken the lock.
*/
if (!dt_object_remote(tobj)) {
if (dt_object_exists(tobj) == 0 ||
lfsck_is_dead_obj(tobj)) {
CDEBUG_UNMATCHED_PAIR(lfsck, lso, pfid,
cfid,
"the parent doesn't exist anymore after lock");
rc = LLIT_UNMATCHED_PAIR;
} else {
rc = LLIT_MULTIPLE_REFERENCED;
}
GOTO(unlock, rc);
}
/* For migration case, the new MDT-object and old
* MDT-object may reference the same OST-object at
* some migration internal time.
*
* For remote MDT-object, the local MDT may not know
* whether it has been removed or not. Try checking
* for a non-existent xattr to check if this object
* has been removed or not.
*/
rc = dt_xattr_get(env, tobj, &LU_BUF_NULL,
XATTR_NAME_DUMMY);
if (unlikely(rc == -ENOENT || rc >= 0)) {
CDEBUG_UNMATCHED_PAIR(lfsck, lso, pfid, cfid,
"the parent is remote object and nonexistent after lock");
rc = LLIT_UNMATCHED_PAIR;
} else if (rc == -ENODATA) {
rc = LLIT_MULTIPLE_REFERENCED;
}
GOTO(unlock, rc);
}
}
CDEBUG_UNMATCHED_PAIR(lfsck, lso, pfid, cfid,
"the parent has no matched stripe");
GOTO(out, rc = LLIT_UNMATCHED_PAIR);
unlock:
if (lustre_handle_is_used(&lh)) {
dt_read_unlock(env, tobj);
lfsck_ibits_unlock(&lh, LCK_EX);
}
out:
lfsck_object_put(env, tobj);
return rc;
}
/*
* If the MDT-object has the LUSTRE_ENCRYPT_FL flag, it needs to be set
* on the OST-object as well.
*/
static int lfsck_layout_repair_encflag(const struct lu_env *env,
struct lfsck_component *com,
struct dt_object *parent,
struct lfsck_layout_req *llr)
{
struct lfsck_thread_info *info = lfsck_env_info(env);
struct lu_attr *tla = &info->lti_la2;
struct dt_object *child = llr->llr_child;
struct dt_device *dev = lfsck_obj2dev(child);
struct thandle *handle;
int rc;
ENTRY;
tla->la_valid = LA_FLAGS;
tla->la_flags = LUSTRE_ENCRYPT_FL;
handle = lfsck_trans_create(env, dev, com->lc_lfsck);
if (IS_ERR(handle))
GOTO(log, rc = PTR_ERR(handle));
rc = dt_declare_attr_set(env, child, tla, handle);
if (rc != 0)
GOTO(stop, rc);
rc = dt_trans_start_local(env, dev, handle);
if (rc != 0)
GOTO(stop, rc);
/* Use the dt_object lock to serialize with destroy and attr_set. */
dt_read_lock(env, parent, 0);
if (unlikely(lfsck_is_dead_obj(parent)))
GOTO(unlock, rc = 1);
rc = dt_attr_set(env, child, tla, handle);
GOTO(unlock, rc);
unlock:
dt_read_unlock(env, parent);
stop:
rc = lfsck_layout_trans_stop(env, dev, handle, rc);
log:
if (rc != 0)
CDEBUG(D_LFSCK,
"%s: layout LFSCK assistant repair of inconsistent file enc flag for: parent "DFID", child "DFID", OST-index %u, stripe-index %u: rc = %d\n",
lfsck_lfsck2name(com->lc_lfsck),
PFID(lfsck_dto2fid(parent)), PFID(lfsck_dto2fid(child)),
llr->llr_ost_idx, llr->llr_lov_idx, rc);
return rc;
}
static int lfsck_layout_assistant_handler_p1(const struct lu_env *env,
struct lfsck_component *com,
struct lfsck_assistant_req *lar)
{
struct lfsck_layout_req *llr = container_of(lar,
struct lfsck_layout_req,
llr_lar);
struct lfsck_assistant_object *lso = lar->lar_parent;
struct lfsck_layout *lo = com->lc_file_ram;
struct lfsck_thread_info *info = lfsck_env_info(env);
struct filter_fid *ff = &info->lti_ff;
struct lu_buf buf = { .lb_buf = ff, .lb_len = sizeof(*ff) };
struct dt_object *parent = NULL;
struct dt_object *child = llr->llr_child;
struct lu_attr *pla = &lso->lso_attr;
struct lu_attr *cla = &info->lti_la;
struct lfsck_instance *lfsck = com->lc_lfsck;
struct lfsck_bookmark *bk = &lfsck->li_bookmark_ram;
enum lfsck_layout_inconsistency_type type = LLIT_NONE;
int rc;
ENTRY;
if (lso->lso_dead)
RETURN(0);
CFS_FAIL_TIMEOUT(OBD_FAIL_LFSCK_ENGINE_DELAY, cfs_fail_val);
rc = dt_attr_get(env, child, cla);
if (rc == -ENOENT) {
parent = lfsck_assistant_object_load(env, lfsck, lso);
if (IS_ERR(parent)) {
rc = PTR_ERR(parent);
RETURN(rc == -ENOENT ? 0 : rc);
}
type = LLIT_DANGLING;
goto repair;
}
if (rc != 0)
GOTO(out, rc);
if (!(bk->lb_param & LPF_DRYRUN) &&
pla->la_valid & LA_FLAGS && pla->la_flags & LUSTRE_ENCRYPT_FL) {
/* MDT-inode is encrypted */
struct lu_buf lb = { .lb_buf = NULL, .lb_len = 0 };
/* if OST-inode is missing encryption.c xattr, fix it */
if (dt_xattr_get(env, child, &lb,
LL_XATTR_NAME_ENCRYPTION_CONTEXT) >= 0)
goto check_fid;
if (parent == NULL)
parent = lfsck_assistant_object_load(env, lfsck, lso);
if (!IS_ERR_OR_NULL(parent))
rc = lfsck_layout_repair_encflag(env, com, parent, llr);
down_write(&com->lc_sem);
if (rc < 0)
lfsck_layout_record_failure(env, lfsck, lo);
else if (rc > 0)
lo->ll_objs_repaired[LLIT_OTHERS - 1]++;
up_write(&com->lc_sem);
}
check_fid:
lfsck_buf_init(&buf, ff, sizeof(*ff));
rc = dt_xattr_get(env, child, &buf, XATTR_NAME_FID);
if (unlikely(rc > 0 && rc < sizeof(struct lu_fid))) {
CDEBUG(D_LFSCK,
"%s:"DFID"/"DFID": the child object's %s is corrupted\n",
lfsck_lfsck2name(lfsck), PFID(&lso->lso_fid),
PFID(lu_object_fid(&child->do_lu)),
XATTR_NAME_FID);
type = LLIT_UNMATCHED_PAIR;
goto repair;
}
if (rc < 0 && rc != -ENODATA)
GOTO(out, rc);
if (rc == 0 || rc == -ENODATA)
GOTO(check_owner, rc = 0);
filter_fid_le_to_cpu(ff, ff, sizeof(*ff));
rc = lfsck_layout_check_parent(env, com, lso, ff,
lu_object_fid(&child->do_lu), cla, llr);
if (rc > 0) {
type = rc;
goto repair;
}
if (rc < 0)
GOTO(out, rc);
check_owner:
/* Someone may has changed the owner after the parent attr pre-loaded.
* It can be handled later inside the lfsck_layout_repair_owner().
*/
if (unlikely(cla->la_uid != pla->la_uid ||
cla->la_gid != pla->la_gid ||
cla->la_projid != pla->la_projid)) {
type = LLIT_INCONSISTENT_OWNER;
goto repair;
}
repair:
if (type == LLIT_NONE)
GOTO(out, rc = 0);
if (bk->lb_param & LPF_DRYRUN)
GOTO(out, rc = 1);
if (parent == NULL) {
parent = lfsck_assistant_object_load(env, lfsck, lso);
if (IS_ERR(parent)) {
rc = PTR_ERR(parent);
if (rc == -ENOENT)
RETURN(0);
GOTO(out, rc);
}
}
switch (type) {
case LLIT_DANGLING:
if (bk->lb_param & LPF_DELAY_CREATE_OSTOBJ)
rc = lfsck_layout_ins_dangling_rec(env, com,
lfsck_dto2fid(parent), lfsck_dto2fid(child),
llr->llr_comp_id, llr->llr_lov_idx,
llr->llr_ost_idx);
else
rc = __lfsck_layout_repair_dangling(env, com, parent,
llr->llr_child,
llr->llr_comp_id,
llr->llr_lov_idx,
llr->llr_ost_idx,
true);
break;
case LLIT_UNMATCHED_PAIR:
rc = lfsck_layout_repair_unmatched_pair(env, com, parent,
llr, pla);
break;
case LLIT_MULTIPLE_REFERENCED:
rc = lfsck_layout_repair_multiple_references(env, com, parent,
llr, pla);
break;
case LLIT_INCONSISTENT_OWNER:
rc = lfsck_layout_repair_owner(env, com, parent, llr, pla, cla);
break;
default:
rc = 0;
break;
}
GOTO(out, rc);
out:
down_write(&com->lc_sem);
if (rc < 0) {
if (unlikely(lfsck_should_stop(lfsck))) {
rc = 0;
} else if (rc == -ENOTCONN || rc == -ESHUTDOWN ||
rc == -ETIMEDOUT || rc == -EHOSTDOWN ||
rc == -EHOSTUNREACH) {
/* cannot touch target server? mark LFSCK INCOMPLETE */
CDEBUG(D_LFSCK,
"%s: layout LFSCK assistant fail to talk with OST %x: rc = %d\n",
lfsck_lfsck2name(lfsck), llr->llr_ost_idx, rc);
lfsck_lad_set_bitmap(env, com, llr->llr_ost_idx);
lo->ll_objs_skipped++;
rc = 0;
} else {
lfsck_layout_record_failure(env, lfsck, lo);
}
} else if (rc > 0 && (type != LLIT_DANGLING ||
!(bk->lb_param & LPF_DELAY_CREATE_OSTOBJ))) {
LASSERTF(type > LLIT_NONE && type <= LLIT_MAX,
"unknown type = %d\n", type);
lo->ll_objs_repaired[type - 1]++;
if (bk->lb_param & LPF_DRYRUN &&
unlikely(lo->ll_pos_first_inconsistent == 0))
lo->ll_pos_first_inconsistent =
lfsck->li_obj_oit->do_index_ops->dio_it.store(env,
lfsck->li_di_oit);
}
up_write(&com->lc_sem);
if (parent != NULL && !IS_ERR(parent))
lfsck_object_put(env, parent);
return rc;
}
static int
lfsck_layout_double_scan_one_trace_file(const struct lu_env *env,
struct lfsck_component *com,
struct dt_object *obj, bool first)
{
struct lfsck_instance *lfsck = com->lc_lfsck;
struct lfsck_bookmark *bk = &lfsck->li_bookmark_ram;
struct lfsck_layout *lo = com->lc_file_ram;
const struct dt_it_ops *iops = &obj->do_index_ops->dio_it;
struct dt_it *di;
struct dt_key *key;
struct lfsck_layout_dangling_key *parent =
&lfsck_env_info(env)->lti_lldk;
struct lu_fid *cfid = &lfsck_env_info(env)->lti_fid3;
__u32 ost_idx;
int rc;
ENTRY;
di = iops->init(env, obj, 0);
if (IS_ERR(di))
RETURN(PTR_ERR(di));
if (first)
lldk_cpu_to_be(parent, &lo->ll_lldk_latest_scanned_phase2);
else
memset(parent, 0, sizeof(*parent));
rc = iops->get(env, di, (const struct dt_key *)parent);
if (rc < 0)
GOTO(fini, rc);
if (first) {
/* The start one either has been processed or does not exist,
* skip it.
*/
rc = iops->next(env, di);
if (rc != 0)
GOTO(put, rc);
}
rc = 0;
while (!lfsck_should_stop(lfsck) && rc == 0) {
if (LFSCK_FAIL_TIMEOUT(lfsck, OBD_FAIL_LFSCK_DELAY3,
cfs_fail_val))
GOTO(put, rc);
key = iops->key(env, di);
if (IS_ERR(key)) {
rc = PTR_ERR(key);
if (rc == -ENOENT)
GOTO(put, rc = 1);
goto checkpoint;
}
lldk_be_to_cpu(parent,
(const struct lfsck_layout_dangling_key *)key);
if (!fid_is_sane(&parent->lldk_fid)) {
rc = 0;
goto checkpoint;
}
rc = iops->rec(env, di, (struct dt_rec *)cfid, 0);
if (rc == 0) {
fid_be_to_cpu(cfid, cfid);
ost_idx = cfid->f_ver;
cfid->f_ver = 0;
if (!fid_is_sane(cfid)) {
rc = 0;
goto checkpoint;
}
rc = lfsck_layout_repair_dangling(env, com,
&parent->lldk_fid, cfid,
parent->lldk_comp_id,
parent->lldk_ea_off, ost_idx);
}
checkpoint:
down_write(&com->lc_sem);
com->lc_new_checked++;
com->lc_new_scanned++;
if (rc >= 0)
lo->ll_lldk_latest_scanned_phase2 = *parent;
if (rc > 0)
lo->ll_objs_repaired[LLIT_DANGLING - 1]++;
else if (rc < 0)
lo->ll_objs_failed_phase2++;
up_write(&com->lc_sem);
if (rc < 0 && bk->lb_param & LPF_FAILOUT)
GOTO(put, rc);
if (unlikely(com->lc_time_next_checkpoint <=
ktime_get_seconds()) &&
com->lc_new_checked != 0) {
down_write(&com->lc_sem);
lo->ll_run_time_phase2 += ktime_get_seconds() -
com->lc_time_last_checkpoint;
lo->ll_time_last_checkpoint = ktime_get_real_seconds();
lo->ll_objs_checked_phase2 += com->lc_new_checked;
com->lc_new_checked = 0;
lfsck_layout_store(env, com);
up_write(&com->lc_sem);
com->lc_time_last_checkpoint = ktime_get_seconds();
com->lc_time_next_checkpoint =
com->lc_time_last_checkpoint +
LFSCK_CHECKPOINT_INTERVAL;
}
lfsck_control_speed_by_self(com);
rc = iops->next(env, di);
}
GOTO(put, rc);
put:
iops->put(env, di);
fini:
iops->fini(env, di);
return rc;
}
static int lfsck_layout_assistant_handler_p2(const struct lu_env *env,
struct lfsck_component *com)
{
struct lfsck_assistant_data *lad = com->lc_data;
struct lfsck_instance *lfsck = com->lc_lfsck;
struct lfsck_bookmark *bk = &lfsck->li_bookmark_ram;
struct lfsck_tgt_descs *ltds = &lfsck->li_ost_descs;
struct lfsck_tgt_desc *ltd;
int rc = 0;
ENTRY;
CDEBUG(D_LFSCK, "%s: layout LFSCK phase2 scan start\n",
lfsck_lfsck2name(lfsck));
spin_lock(<ds->ltd_lock);
while (!list_empty(&lad->lad_ost_phase2_list) &&
!lfsck_should_stop(lfsck)) {
ltd = list_first_entry(&lad->lad_ost_phase2_list,
struct lfsck_tgt_desc,
ltd_layout_phase_list);
list_del_init(<d->ltd_layout_phase_list);
if (bk->lb_param & LPF_OST_ORPHAN) {
spin_unlock(<ds->ltd_lock);
rc = lfsck_layout_scan_orphan(env, com, ltd);
if (rc != 0 && bk->lb_param & LPF_FAILOUT)
RETURN(rc);
spin_lock(<ds->ltd_lock);
}
}
if (list_empty(&lad->lad_ost_phase1_list))
rc = 1;
else
rc = 0;
spin_unlock(<ds->ltd_lock);
if (rc == 1 && bk->lb_param & LPF_OST_ORPHAN) {
struct lfsck_layout *lo = com->lc_file_ram;
int i;
com->lc_new_checked = 0;
com->lc_new_scanned = 0;
com->lc_time_last_checkpoint = ktime_get_seconds();
com->lc_time_next_checkpoint = com->lc_time_last_checkpoint +
LFSCK_CHECKPOINT_INTERVAL;
i = lfsck_sub_trace_file_fid2idx(
&lo->ll_lldk_latest_scanned_phase2.lldk_fid);
rc = lfsck_layout_double_scan_one_trace_file(env, com,
com->lc_sub_trace_objs[i].lsto_obj, true);
while (rc > 0 && ++i < LFSCK_STF_COUNT &&
!lfsck_should_stop(lfsck))
rc = lfsck_layout_double_scan_one_trace_file(env, com,
com->lc_sub_trace_objs[i].lsto_obj, false);
CDEBUG(D_LFSCK,
"%s: layout LFSCK phase2 scan dangling stop at the No. %d trace file: rc = %d\n",
lfsck_lfsck2name(lfsck), i, rc);
}
CDEBUG(D_LFSCK, "%s: layout LFSCK phase2 scan stop: rc = %d\n",
lfsck_lfsck2name(lfsck), rc);
RETURN(rc);
}
static int
lfsck_layout_slave_async_interpret(const struct lu_env *env,
struct ptlrpc_request *req,
void *args, int rc)
{
struct lfsck_layout_slave_async_args *llsaa = args;
struct obd_export *exp = llsaa->llsaa_exp;
struct lfsck_component *com = llsaa->llsaa_com;
struct lfsck_layout_slave_target *llst = llsaa->llsaa_llst;
struct lfsck_layout_slave_data *llsd = com->lc_data;
struct lfsck_reply *lr = NULL;
bool done = false;
if (rc != 0) {
/* It is probably caused by network trouble, or target crash,
* it will try several times (depends on the obd_timeout, and
* will not less than 3 times). But to make the LFSCK can go
* ahead, we should not try for ever. After some try but still
* hit failure, it will assume that the target exit the LFSCK
* prcoessing and stop try.
*/
if (rc == -ENOTCONN || rc == -ESHUTDOWN || rc == -EAGAIN) {
int max_try = max_t(int, obd_timeout / 30, 3);
if (++(llst->llst_failures) > max_try)
done = true;
} else {
done = true;
}
} else {
llst->llst_failures = 0;
lr = req_capsule_server_get(&req->rq_pill, &RMF_LFSCK_REPLY);
if (lr->lr_status != LS_SCANNING_PHASE1 &&
lr->lr_status != LS_SCANNING_PHASE2)
done = true;
}
if (done) {
CDEBUG(D_LFSCK,
"%s: layout LFSCK slave gets the MDT %x status %d, failures_try %d\n",
lfsck_lfsck2name(com->lc_lfsck), llst->llst_index,
lr != NULL ? lr->lr_status : rc, llst->llst_failures);
lfsck_layout_llst_del(llsd, llst);
}
kref_put(&llst->llst_ref, lfsck_layout_llst_put);
lfsck_component_put(env, com);
class_export_put(exp);
return 0;
}
static int lfsck_layout_async_query(const struct lu_env *env,
struct lfsck_component *com,
struct obd_export *exp,
struct lfsck_layout_slave_target *llst,
struct lfsck_request *lr,
struct ptlrpc_request_set *set)
{
struct lfsck_layout_slave_async_args *llsaa;
struct ptlrpc_request *req;
struct lfsck_request *tmp;
int rc;
ENTRY;
req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_LFSCK_QUERY);
if (req == NULL)
RETURN(-ENOMEM);
rc = ptlrpc_request_pack(req, LUSTRE_OBD_VERSION, LFSCK_QUERY);
if (rc != 0) {
ptlrpc_request_free(req);
RETURN(rc);
}
tmp = req_capsule_client_get(&req->rq_pill, &RMF_LFSCK_REQUEST);
*tmp = *lr;
ptlrpc_request_set_replen(req);
llsaa = ptlrpc_req_async_args(llsaa, req);
llsaa->llsaa_exp = exp;
llsaa->llsaa_com = lfsck_component_get(com);
llsaa->llsaa_llst = llst;
req->rq_interpret_reply = lfsck_layout_slave_async_interpret;
req->rq_allow_intr = 1;
req->rq_no_delay = 1;
ptlrpc_set_add_req(set, req);
RETURN(0);
}
static int lfsck_layout_async_notify(const struct lu_env *env,
struct obd_export *exp,
struct lfsck_request *lr,
struct ptlrpc_request_set *set)
{
struct ptlrpc_request *req;
struct lfsck_request *tmp;
int rc;
ENTRY;
req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_LFSCK_NOTIFY);
if (req == NULL)
RETURN(-ENOMEM);
rc = ptlrpc_request_pack(req, LUSTRE_OBD_VERSION, LFSCK_NOTIFY);
if (rc != 0) {
ptlrpc_request_free(req);
RETURN(rc);
}
tmp = req_capsule_client_get(&req->rq_pill, &RMF_LFSCK_REQUEST);
*tmp = *lr;
ptlrpc_request_set_replen(req);
req->rq_allow_intr = 1;
req->rq_no_delay = 1;
ptlrpc_set_add_req(set, req);
RETURN(0);
}
static int
lfsck_layout_slave_query_master(const struct lu_env *env,
struct lfsck_component *com)
{
struct lfsck_request *lr = &lfsck_env_info(env)->lti_lr;
struct lfsck_instance *lfsck = com->lc_lfsck;
struct lfsck_layout_slave_data *llsd = com->lc_data;
struct lfsck_layout_slave_target *llst;
struct obd_export *exp;
struct ptlrpc_request_set *set;
int rc = 0;
int rc1 = 0;
ENTRY;
set = ptlrpc_prep_set();
if (set == NULL)
GOTO(log, rc = -ENOMEM);
memset(lr, 0, sizeof(*lr));
lr->lr_event = LE_QUERY;
lr->lr_active = LFSCK_TYPE_LAYOUT;
llsd->llsd_touch_gen++;
spin_lock(&llsd->llsd_lock);
while (!list_empty(&llsd->llsd_master_list)) {
llst = list_first_entry(&llsd->llsd_master_list,
struct lfsck_layout_slave_target,
llst_list);
if (llst->llst_gen == llsd->llsd_touch_gen)
break;
llst->llst_gen = llsd->llsd_touch_gen;
list_move_tail(&llst->llst_list,
&llsd->llsd_master_list);
kref_get(&llst->llst_ref);
spin_unlock(&llsd->llsd_lock);
exp = lustre_find_lwp_by_index(lfsck->li_obd->obd_name,
llst->llst_index);
if (exp == NULL) {
lfsck_layout_llst_del(llsd, llst);
kref_put(&llst->llst_ref, lfsck_layout_llst_put);
spin_lock(&llsd->llsd_lock);
continue;
}
rc = lfsck_layout_async_query(env, com, exp, llst, lr, set);
if (rc != 0) {
CDEBUG(D_LFSCK,
"%s: layout LFSCK slave fail to query %s for layout: rc = %d\n",
lfsck_lfsck2name(lfsck), exp->exp_obd->obd_name,
rc);
rc1 = rc;
kref_put(&llst->llst_ref, lfsck_layout_llst_put);
class_export_put(exp);
}
spin_lock(&llsd->llsd_lock);
}
spin_unlock(&llsd->llsd_lock);
rc = ptlrpc_set_wait(env, set);
ptlrpc_set_destroy(set);
GOTO(log, rc = (rc1 != 0 ? rc1 : rc));
log:
CDEBUG(D_LFSCK, "%s: layout LFSCK slave queries master: rc = %d\n",
lfsck_lfsck2name(com->lc_lfsck), rc);
return rc;
}
static void
lfsck_layout_slave_notify_master(const struct lu_env *env,
struct lfsck_component *com,
enum lfsck_events event, int result)
{
struct lfsck_layout *lo = com->lc_file_ram;
struct lfsck_instance *lfsck = com->lc_lfsck;
struct lfsck_layout_slave_data *llsd = com->lc_data;
struct lfsck_request *lr = &lfsck_env_info(env)->lti_lr;
struct lfsck_layout_slave_target *llst;
struct obd_export *exp;
struct ptlrpc_request_set *set;
int rc;
ENTRY;
CDEBUG(D_LFSCK, "%s: layout LFSCK slave notifies master\n",
lfsck_lfsck2name(com->lc_lfsck));
set = ptlrpc_prep_set();
if (set == NULL)
RETURN_EXIT;
memset(lr, 0, sizeof(*lr));
lr->lr_event = event;
lr->lr_flags = LEF_FROM_OST;
lr->lr_status = result;
lr->lr_index = lfsck_dev_idx(lfsck);
lr->lr_active = LFSCK_TYPE_LAYOUT;
lr->lr_flags2 = lo->ll_flags;
llsd->llsd_touch_gen++;
spin_lock(&llsd->llsd_lock);
while (!list_empty(&llsd->llsd_master_list)) {
llst = list_first_entry(&llsd->llsd_master_list,
struct lfsck_layout_slave_target,
llst_list);
if (llst->llst_gen == llsd->llsd_touch_gen)
break;
llst->llst_gen = llsd->llsd_touch_gen;
list_move_tail(&llst->llst_list,
&llsd->llsd_master_list);
kref_get(&llst->llst_ref);
spin_unlock(&llsd->llsd_lock);
exp = lustre_find_lwp_by_index(lfsck->li_obd->obd_name,
llst->llst_index);
if (exp == NULL) {
lfsck_layout_llst_del(llsd, llst);
kref_put(&llst->llst_ref, lfsck_layout_llst_put);
spin_lock(&llsd->llsd_lock);
continue;
}
rc = lfsck_layout_async_notify(env, exp, lr, set);
if (rc != 0)
CDEBUG(D_LFSCK,
"%s: layout LFSCK slave fail to notify %s for layout: rc = %d\n",
lfsck_lfsck2name(lfsck),
exp->exp_obd->obd_name, rc);
kref_put(&llst->llst_ref, lfsck_layout_llst_put);
class_export_put(exp);
spin_lock(&llsd->llsd_lock);
}
spin_unlock(&llsd->llsd_lock);
ptlrpc_set_wait(env, set);
ptlrpc_set_destroy(set);
RETURN_EXIT;
}
/*
* \ret -ENODATA: unrecognized stripe
* \ret = 0 : recognized stripe
* \ret < 0 : other failures
*/
static int lfsck_layout_master_check_pairs(const struct lu_env *env,
struct lfsck_component *com,
struct lu_fid *cfid,
struct lu_fid *pfid, __u32 comp_id)
{
struct lfsck_thread_info *info = lfsck_env_info(env);
struct lu_buf *buf = &info->lti_big_buf;
struct ost_id *oi = &info->lti_oi;
struct dt_object *obj;
struct lov_mds_md_v1 *lmm;
struct lov_ost_data_v1 *objs;
__u32 idx = pfid->f_stripe_idx;
__u32 magic;
int rc = 0;
int i;
__u16 count;
ENTRY;
pfid->f_ver = 0;
obj = lfsck_object_find_bottom(env, com->lc_lfsck, pfid);
if (IS_ERR(obj))
RETURN(PTR_ERR(obj));
dt_read_lock(env, obj, 0);
if (unlikely(dt_object_exists(obj) == 0 ||
lfsck_is_dead_obj(obj)))
GOTO(unlock, rc = -ENOENT);
if (!S_ISREG(lfsck_object_type(obj)))
GOTO(unlock, rc = -ENODATA);
rc = lfsck_layout_get_lovea(env, obj, buf);
if (rc < 0)
GOTO(unlock, rc);
lmm = buf->lb_buf;
magic = le32_to_cpu(lmm->lmm_magic);
if (magic == LOV_MAGIC_COMP_V1 || magic == LOV_MAGIC_SEL) {
struct lov_comp_md_v1 *lcm = buf->lb_buf;
struct lov_comp_md_entry_v1 *lcme;
if (comp_id == 0)
GOTO(unlock, rc = -ENODATA);
count = le16_to_cpu(lcm->lcm_entry_count);
for (i = 0; i < count; i++) {
lcme = &lcm->lcm_entries[i];
if (le32_to_cpu(lcme->lcme_id) == comp_id) {
lmm = buf->lb_buf +
le32_to_cpu(lcme->lcme_offset);
magic = le32_to_cpu(lmm->lmm_magic);
if (!(le32_to_cpu(lcme->lcme_flags) &
LCME_FL_INIT))
GOTO(unlock, rc = -ENODATA);
goto further;
}
}
GOTO(unlock, rc = -ENODATA);
}
further:
if (magic == LOV_MAGIC_V1) {
objs = &lmm->lmm_objects[0];
} else {
LASSERT(magic == LOV_MAGIC_V3);
objs = &((struct lov_mds_md_v3 *)lmm)->lmm_objects[0];
}
fid_to_ostid(cfid, oi);
count = le16_to_cpu(lmm->lmm_stripe_count);
for (i = 0; i < count; i++, objs++) {
struct ost_id oi2;
ostid_le_to_cpu(&objs->l_ost_oi, &oi2);
if (memcmp(oi, &oi2, sizeof(*oi)) == 0)
GOTO(unlock, rc = (i != idx ? -ENODATA : 0));
}
GOTO(unlock, rc = -ENODATA);
unlock:
dt_read_unlock(env, obj);
lfsck_object_put(env, obj);
return rc;
}
/*
* The LFSCK-on-OST will ask the LFSCK-on-MDT to check whether the given
* MDT-object/OST-object pairs match or not to aviod transfer MDT-object
* layout EA from MDT to OST. On one hand, the OST no need to understand
* the layout EA structure; on the other hand, it may cause trouble when
* transfer large layout EA from MDT to OST via normal OUT RPC.
*
* \ret > 0: unrecognized stripe
* \ret = 0: recognized stripe
* \ret < 0: other failures
*/
static int lfsck_layout_slave_check_pairs(const struct lu_env *env,
struct lfsck_component *com,
struct lu_fid *cfid,
struct lu_fid *pfid, __u32 comp_id)
{
struct lfsck_instance *lfsck = com->lc_lfsck;
struct obd_device *obd = lfsck->li_obd;
struct seq_server_site *ss = lfsck_dev_site(lfsck);
struct obd_export *exp = NULL;
struct ptlrpc_request *req = NULL;
struct lfsck_request *lr;
struct lu_seq_range *range = &lfsck_env_info(env)->lti_range;
int rc = 0;
ENTRY;
if (unlikely(fid_is_idif(pfid)))
RETURN(1);
fld_range_set_any(range);
rc = fld_server_lookup(env, ss->ss_server_fld, fid_seq(pfid), range);
if (rc != 0)
RETURN(rc == -ENOENT ? 1 : rc);
if (unlikely(!fld_range_is_mdt(range)))
RETURN(1);
exp = lustre_find_lwp_by_index(obd->obd_name, range->lsr_index);
if (unlikely(exp == NULL))
RETURN(1);
if (!(exp_connect_flags(exp) & OBD_CONNECT_LFSCK))
GOTO(out, rc = -EOPNOTSUPP);
req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_LFSCK_NOTIFY);
if (req == NULL)
GOTO(out, rc = -ENOMEM);
rc = ptlrpc_request_pack(req, LUSTRE_OBD_VERSION, LFSCK_NOTIFY);
if (rc != 0) {
ptlrpc_request_free(req);
GOTO(out, rc);
}
lr = req_capsule_client_get(&req->rq_pill, &RMF_LFSCK_REQUEST);
memset(lr, 0, sizeof(*lr));
lr->lr_event = LE_PAIRS_VERIFY;
lr->lr_active = LFSCK_TYPE_LAYOUT;
lr->lr_fid = *cfid; /* OST-object itself FID. */
lr->lr_fid2 = *pfid; /* The claimed parent FID. */
lr->lr_comp_id = comp_id;
ptlrpc_request_set_replen(req);
rc = ptlrpc_queue_wait(req);
ptlrpc_req_put(req);
if (rc == -ENOENT || rc == -ENODATA)
rc = 1;
GOTO(out, rc);
out:
if (exp != NULL)
class_export_put(exp);
return rc;
}
static int lfsck_layout_slave_repair_pfid(const struct lu_env *env,
struct lfsck_component *com,
struct lfsck_req_local *lrl)
{
struct dt_object *obj;
int rc = 0;
ENTRY;
obj = lfsck_object_find_bottom(env, com->lc_lfsck, &lrl->lrl_fid);
if (IS_ERR(obj))
GOTO(log, rc = PTR_ERR(obj));
rc = __lfsck_layout_update_pfid(env, com, obj,
&lrl->lrl_ff_client.ff_parent,
&lrl->lrl_ff_client.ff_layout,
lrl->lrl_ff_client.ff_layout_version,
lrl->lrl_ff_client.ff_range,
lrl->lrl_ff_client.ff_parent.f_ver);
lfsck_object_put(env, obj);
log:
CDEBUG(D_LFSCK,
"%s: layout LFSCK slave repaired pfid for "DFID", parent "DFID": rc = %d\n",
lfsck_lfsck2name(com->lc_lfsck), PFID(&lrl->lrl_fid),
PFID(&lrl->lrl_ff_client.ff_parent), rc);
return rc;
}
/* layout APIs */
static void lfsck_layout_slave_quit(const struct lu_env *env,
struct lfsck_component *com);
static int lfsck_layout_reset(const struct lu_env *env,
struct lfsck_component *com, bool init)
{
struct lfsck_layout *lo = com->lc_file_ram;
int rc;
down_write(&com->lc_sem);
if (init) {
memset(lo, 0, com->lc_file_size);
} else {
__u32 count = lo->ll_success_count;
time64_t last_time = lo->ll_time_last_complete;
memset(lo, 0, com->lc_file_size);
lo->ll_success_count = count;
lo->ll_time_last_complete = last_time;
}
lo->ll_magic = LFSCK_LAYOUT_MAGIC;
lo->ll_status = LS_INIT;
if (com->lc_lfsck->li_master) {
struct lfsck_assistant_data *lad = com->lc_data;
clear_bit(LAD_INCOMPLETE, &lad->lad_flags);
bitmap_zero(lad->lad_bitmap, lad->lad_bitmap_count);
}
rc = lfsck_layout_store(env, com);
if (rc == 0 && com->lc_lfsck->li_master)
rc = lfsck_load_sub_trace_files(env, com,
&dt_lfsck_layout_dangling_features, LFSCK_LAYOUT, true);
up_write(&com->lc_sem);
CDEBUG(D_LFSCK, "%s: layout LFSCK reset: rc = %d\n",
lfsck_lfsck2name(com->lc_lfsck), rc);
return rc;
}
static void lfsck_layout_fail(const struct lu_env *env,
struct lfsck_component *com, bool new_checked)
{
struct lfsck_layout *lo = com->lc_file_ram;
down_write(&com->lc_sem);
if (new_checked)
com->lc_new_checked++;
lfsck_layout_record_failure(env, com->lc_lfsck, lo);
up_write(&com->lc_sem);
}
static int lfsck_layout_master_checkpoint(const struct lu_env *env,
struct lfsck_component *com, bool init)
{
struct lfsck_instance *lfsck = com->lc_lfsck;
struct lfsck_layout *lo = com->lc_file_ram;
int rc;
if (!init) {
rc = lfsck_checkpoint_generic(env, com);
if (rc != 0)
return rc > 0 ? 0 : rc;
}
down_write(&com->lc_sem);
if (init) {
lo->ll_pos_latest_start =
lfsck->li_pos_checkpoint.lp_oit_cookie;
} else {
lo->ll_pos_last_checkpoint =
lfsck->li_pos_checkpoint.lp_oit_cookie;
lo->ll_run_time_phase1 += ktime_get_seconds() -
lfsck->li_time_last_checkpoint;
lo->ll_time_last_checkpoint = ktime_get_real_seconds();
lo->ll_objs_checked_phase1 += com->lc_new_checked;
com->lc_new_checked = 0;
}
rc = lfsck_layout_store(env, com);
up_write(&com->lc_sem);
CDEBUG(D_LFSCK,
"%s: layout LFSCK master checkpoint at the pos [%llu], status = %d: rc = %d\n",
lfsck_lfsck2name(lfsck), lfsck->li_pos_current.lp_oit_cookie,
lo->ll_status, rc);
return rc;
}
static int lfsck_layout_slave_checkpoint(const struct lu_env *env,
struct lfsck_component *com, bool init)
{
struct lfsck_instance *lfsck = com->lc_lfsck;
struct lfsck_layout *lo = com->lc_file_ram;
int rc;
if (com->lc_new_checked == 0 && !init)
return 0;
down_write(&com->lc_sem);
if (init) {
lo->ll_pos_latest_start =
lfsck->li_pos_checkpoint.lp_oit_cookie;
} else {
lo->ll_pos_last_checkpoint =
lfsck->li_pos_checkpoint.lp_oit_cookie;
lo->ll_run_time_phase1 += ktime_get_seconds() -
lfsck->li_time_last_checkpoint;
lo->ll_time_last_checkpoint = ktime_get_real_seconds();
lo->ll_objs_checked_phase1 += com->lc_new_checked;
com->lc_new_checked = 0;
}
rc = lfsck_layout_store(env, com);
up_write(&com->lc_sem);
CDEBUG(D_LFSCK,
"%s: layout LFSCK slave checkpoint at the pos [%llu], status = %d: rc = %d\n",
lfsck_lfsck2name(lfsck), lfsck->li_pos_current.lp_oit_cookie,
lo->ll_status, rc);
return rc;
}
static int lfsck_layout_prep(const struct lu_env *env,
struct lfsck_component *com,
struct lfsck_start *start)
{
struct lfsck_instance *lfsck = com->lc_lfsck;
struct lfsck_layout *lo = com->lc_file_ram;
struct lfsck_position *pos = &com->lc_pos_start;
fid_zero(&pos->lp_dir_parent);
pos->lp_dir_cookie = 0;
if (lo->ll_status == LS_COMPLETED ||
lo->ll_status == LS_PARTIAL ||
/* To handle orphan, must scan from the beginning. */
(start != NULL && start->ls_flags & LPF_OST_ORPHAN)) {
int rc;
rc = lfsck_layout_reset(env, com, false);
if (rc == 0)
rc = lfsck_set_param(env, lfsck, start, true);
if (rc != 0) {
CDEBUG(D_LFSCK,
"%s: layout LFSCK prep failed: rc = %d\n",
lfsck_lfsck2name(lfsck), rc);
return rc;
}
}
down_write(&com->lc_sem);
lo->ll_time_latest_start = ktime_get_real_seconds();
spin_lock(&lfsck->li_lock);
if (lo->ll_flags & LF_SCANNED_ONCE) {
if (!lfsck->li_drop_dryrun ||
lo->ll_pos_first_inconsistent == 0) {
lo->ll_status = LS_SCANNING_PHASE2;
list_move_tail(&com->lc_link,
&lfsck->li_list_double_scan);
pos->lp_oit_cookie = 0;
} else {
int i;
lo->ll_status = LS_SCANNING_PHASE1;
lo->ll_run_time_phase1 = 0;
lo->ll_run_time_phase2 = 0;
lo->ll_objs_checked_phase1 = 0;
lo->ll_objs_checked_phase2 = 0;
lo->ll_objs_failed_phase1 = 0;
lo->ll_objs_failed_phase2 = 0;
for (i = 0; i < LLIT_MAX; i++)
lo->ll_objs_repaired[i] = 0;
pos->lp_oit_cookie = lo->ll_pos_first_inconsistent;
fid_zero(&com->lc_fid_latest_scanned_phase2);
}
} else {
lo->ll_status = LS_SCANNING_PHASE1;
if (!lfsck->li_drop_dryrun ||
lo->ll_pos_first_inconsistent == 0)
pos->lp_oit_cookie = lo->ll_pos_last_checkpoint + 1;
else
pos->lp_oit_cookie = lo->ll_pos_first_inconsistent;
}
spin_unlock(&lfsck->li_lock);
up_write(&com->lc_sem);
return 0;
}
static int lfsck_layout_slave_prep(const struct lu_env *env,
struct lfsck_component *com,
struct lfsck_start_param *lsp)
{
struct lfsck_layout_slave_data *llsd = com->lc_data;
struct lfsck_instance *lfsck = com->lc_lfsck;
struct lfsck_layout *lo = com->lc_file_ram;
struct lfsck_start *start = lsp->lsp_start;
int rc;
rc = lfsck_layout_prep(env, com, start);
if (rc != 0)
return rc;
if (lo->ll_flags & LF_CRASHED_LASTID &&
list_empty(&llsd->llsd_master_list)) {
LASSERT(lfsck->li_out_notify != NULL);
lfsck->li_out_notify(env, lfsck->li_out_notify_data,
LE_LASTID_REBUILDING);
}
if (!lsp->lsp_index_valid)
return 0;
down_write(&llsd->llsd_rb_rwsem);
rc = lfsck_layout_llst_add(llsd, lsp->lsp_index);
if (rc == 0 && start != NULL && start->ls_flags & LPF_OST_ORPHAN) {
LASSERT(!llsd->llsd_rbtree_valid);
rc = lfsck_rbtree_setup(env, com);
} else if (rc == -EALREADY) {
rc = 0;
}
up_write(&llsd->llsd_rb_rwsem);
CDEBUG(D_LFSCK,
"%s: layout LFSCK slave prep done, start pos [%llu]\n",
lfsck_lfsck2name(lfsck), com->lc_pos_start.lp_oit_cookie);
return rc;
}
static int lfsck_layout_master_prep(const struct lu_env *env,
struct lfsck_component *com,
struct lfsck_start_param *lsp)
{
int rc;
ENTRY;
rc = lfsck_layout_load_bitmap(env, com);
if (rc != 0) {
rc = lfsck_layout_reset(env, com, false);
if (rc == 0)
rc = lfsck_set_param(env, com->lc_lfsck,
lsp->lsp_start, true);
if (rc != 0)
GOTO(log, rc);
}
rc = lfsck_layout_prep(env, com, lsp->lsp_start);
if (rc != 0)
RETURN(rc);
rc = lfsck_start_assistant(env, com, lsp);
GOTO(log, rc);
log:
CDEBUG(D_LFSCK,
"%s: layout LFSCK master prep done, start pos [%llu]\n",
lfsck_lfsck2name(com->lc_lfsck),
com->lc_pos_start.lp_oit_cookie);
return 0;
}
/* Pre-fetch the attribute for each stripe in the given layout EA. */
static int lfsck_layout_scan_stripes(const struct lu_env *env,
struct lfsck_component *com,
struct dt_object *parent,
struct lov_mds_md_v1 *lmm, __u32 comp_id)
{
struct lfsck_thread_info *info = lfsck_env_info(env);
struct lfsck_instance *lfsck = com->lc_lfsck;
struct lfsck_bookmark *bk = &lfsck->li_bookmark_ram;
struct lfsck_layout *lo = com->lc_file_ram;
struct lfsck_assistant_data *lad = com->lc_data;
struct lfsck_assistant_object *lso = NULL;
struct lov_ost_data_v1 *objs;
struct lfsck_tgt_descs *ltds = &lfsck->li_ost_descs;
struct lu_buf buf;
int rc = 0;
int i;
__u32 magic;
__u16 count;
ENTRY;
lfsck_buf_init(&buf, &info->lti_ff, sizeof(struct filter_fid));
magic = le32_to_cpu(lmm->lmm_magic);
if (magic == LOV_MAGIC_V1) {
objs = &lmm->lmm_objects[0];
} else {
LASSERT(magic == LOV_MAGIC_V3);
objs = &((struct lov_mds_md_v3 *)lmm)->lmm_objects[0];
}
count = le16_to_cpu(lmm->lmm_stripe_count);
for (i = 0; i < count; i++, objs++) {
struct lu_fid *fid = &info->lti_fid;
struct ost_id *oi = &info->lti_oi;
struct lfsck_layout_req *llr;
struct lfsck_tgt_desc *tgt = NULL;
struct dt_object *cobj = NULL;
__u32 index;
if (unlikely(lovea_slot_is_dummy(objs)))
continue;
wait_var_event(lfsck, lfsck_should_stop(lfsck) ||
!lad->lad_task ||
lad->lad_prefetched < bk->lb_async_windows);
if (lfsck_should_stop(lfsck) || !lad->lad_task)
GOTO(out, rc = 0);
if (unlikely(lfsck_is_dead_obj(parent)))
GOTO(out, rc = 0);
ostid_le_to_cpu(&objs->l_ost_oi, oi);
index = le32_to_cpu(objs->l_ost_idx);
rc = ostid_to_fid(fid, oi, index);
if (rc != 0) {
CDEBUG(D_LFSCK,
"%s: get invalid layout EA for "DFID": "DOSTID", idx %u, comp_id %u\n",
lfsck_lfsck2name(lfsck),
PFID(lfsck_dto2fid(parent)), POSTID(oi),
index, comp_id);
goto next;
}
tgt = lfsck_tgt_get(ltds, index);
if (unlikely(tgt == NULL)) {
CDEBUG(D_LFSCK,
"%s: cannot talk with OST %x which did not join the layout LFSCK, comp_id %u\n",
lfsck_lfsck2name(lfsck), index, comp_id);
lfsck_lad_set_bitmap(env, com, index);
goto next;
}
/* There is potential deadlock race condition between object
* destroy and layout LFSCK. Consider the following scenario:
*
* 1) The LFSCK thread obtained the parent object firstly, at
* that time, the parent object has not been destroyed yet.
*
* 2) One RPC service thread destroyed the parent and all its
* children objects. Because the LFSCK is referencing the
* parent object, then the parent object will be marked as
* dying in RAM. On the other hand, the parent object is
* referencing all its children objects, then all children
* objects will be marked as dying in RAM also.
*
* 3) The LFSCK thread tries to find some child object with
* the parent object referenced. Then it will find that the
* child object is dying. According to the object visibility
* rules: the object with dying flag cannot be returned to
* others. So the LFSCK thread has to wait until the dying
* object has been purged from RAM, then it can allocate a
* new object (with the same FID) in RAM. Unfortunately, the
* LFSCK thread itself is referencing the parent object, and
* cause the parent object cannot be purged, then cause the
* child object cannot be purged also. So the LFSCK thread
* will fall into deadlock.
*/
cobj = lfsck_object_find_by_dev(env, tgt->ltd_tgt, fid);
if (IS_ERR(cobj)) {
if (lfsck_is_dead_obj(parent)) {
kref_put(&tgt->ltd_ref, lfsck_tgt_free);
GOTO(out, rc = 0);
}
rc = PTR_ERR(cobj);
goto next;
}
rc = dt_declare_attr_get(env, cobj);
if (rc)
goto next;
rc = dt_declare_xattr_get(env, cobj, &buf, XATTR_NAME_FID);
if (rc)
goto next;
if (lso == NULL) {
struct lu_attr *attr = &info->lti_la;
rc = dt_attr_get(env, parent, attr);
if (rc != 0)
goto next;
lso = lfsck_assistant_object_init(env,
lfsck_dto2fid(parent), attr,
lfsck->li_pos_current.lp_oit_cookie, false);
if (IS_ERR(lso)) {
rc = PTR_ERR(lso);
lso = NULL;
goto next;
}
}
llr = lfsck_layout_assistant_req_init(lso, cobj, comp_id,
index, i);
if (IS_ERR(llr)) {
rc = PTR_ERR(llr);
goto next;
}
cobj = NULL;
spin_lock(&lad->lad_lock);
if (lad->lad_assistant_status < 0) {
spin_unlock(&lad->lad_lock);
lfsck_layout_assistant_req_fini(env, &llr->llr_lar);
kref_put(&tgt->ltd_ref, lfsck_tgt_free);
RETURN(lad->lad_assistant_status);
}
list_add_tail(&llr->llr_lar.lar_list, &lad->lad_req_list);
if (lad->lad_prefetched == 0)
wake_up_var(lfsck);
lad->lad_prefetched++;
spin_unlock(&lad->lad_lock);
next:
down_write(&com->lc_sem);
com->lc_new_checked++;
if (rc < 0)
lfsck_layout_record_failure(env, lfsck, lo);
up_write(&com->lc_sem);
if (cobj != NULL && !IS_ERR(cobj))
lfsck_object_put(env, cobj);
if (likely(tgt != NULL))
kref_put(&tgt->ltd_ref, lfsck_tgt_free);
if (rc < 0 && bk->lb_param & LPF_FAILOUT)
GOTO(out, rc);
}
GOTO(out, rc = 0);
out:
if (lso != NULL)
kref_put(&lso->lso_ref, lfsck_assistant_object_put);
return rc;
}
/* For the given object, read its layout EA locally. For each stripe, pre-fetch
* the OST-object's attribute and generate an structure lfsck_layout_req on the
* list ::lad_req_list.
*
* For each request on above list, the lfsck_layout_assistant thread compares
* the OST side attribute with local attribute, if inconsistent, then repair it.
*
* All above processing is async mode with pipeline.
*/
static int lfsck_layout_master_exec_oit(const struct lu_env *env,
struct lfsck_component *com,
struct dt_object *obj)
{
struct lfsck_thread_info *info = lfsck_env_info(env);
struct ost_id *oi = &info->lti_oi;
struct lfsck_layout *lo = com->lc_file_ram;
struct lfsck_assistant_data *lad = com->lc_data;
struct lfsck_instance *lfsck = com->lc_lfsck;
struct lfsck_bookmark *bk = &lfsck->li_bookmark_ram;
struct thandle *handle = NULL;
struct lu_buf *buf = &info->lti_big_buf;
struct lov_mds_md_v1 *lmm = NULL;
struct dt_device *dev = lfsck_obj2dev(obj);
struct lustre_handle lh = { 0 };
struct lu_buf ea_buf = { NULL };
struct lov_comp_md_v1 *lcm = NULL;
struct lov_comp_md_entry_v1 *lcme = NULL;
int rc = 0;
int size = 0;
__u32 magic = 0;
__u16 count = 0;
bool locked = false;
bool stripe = false;
bool bad_oi = false;
ENTRY;
if (!S_ISREG(lfsck_object_type(obj)))
GOTO(out, rc = 0);
if (lad->lad_assistant_status < 0)
GOTO(out, rc = -ESRCH);
fid_to_lmm_oi(lfsck_dto2fid(obj), oi);
lmm_oi_cpu_to_le(oi, oi);
dt_read_lock(env, obj, 0);
locked = true;
again:
bad_oi = false;
if (dt_object_exists(obj) == 0 ||
lfsck_is_dead_obj(obj))
GOTO(out, rc = 0);
rc = lfsck_layout_get_lovea(env, obj, buf);
if (rc == -EINVAL || rc == -ENODATA || rc == -EOPNOTSUPP)
/* Skip bad lov EA during the 1st cycle scanning, and
* try to recover it via orphan in the 2nd scanning.
*/
rc = 0;
if (rc <= 0)
GOTO(out, rc);
size = rc;
lmm = buf->lb_buf;
magic = le32_to_cpu(lmm->lmm_magic);
if (magic == LOV_MAGIC_COMP_V1 || magic == LOV_MAGIC_SEL) {
struct lov_mds_md_v1 *v1;
int i;
lcm = buf->lb_buf;
count = le16_to_cpu(lcm->lcm_entry_count);
for (i = 0; i < count; i++) {
lcme = &lcm->lcm_entries[i];
v1 = buf->lb_buf + le32_to_cpu(lcme->lcme_offset);
if (le32_to_cpu(v1->lmm_magic) == LOV_MAGIC_FOREIGN)
continue;
if (memcmp(oi, &v1->lmm_oi, sizeof(*oi)) != 0)
goto fix;
}
GOTO(out, stripe = true);
} else if ((magic != LOV_MAGIC_FOREIGN) &&
memcmp(oi, &lmm->lmm_oi, sizeof(*oi)) == 0) {
GOTO(out, stripe = true);
}
fix:
/* Inconsistent lmm_oi, should be repaired. */
bad_oi = true;
if (bk->lb_param & LPF_DRYRUN) {
lo->ll_objs_repaired[LLIT_OTHERS - 1]++;
GOTO(out, stripe = true);
}
if (!lustre_handle_is_used(&lh)) {
dt_read_unlock(env, obj);
locked = false;
rc = lfsck_ibits_lock(env, lfsck, obj, &lh,
MDS_INODELOCK_LAYOUT |
MDS_INODELOCK_XATTR, LCK_EX);
if (rc != 0)
GOTO(out, rc);
handle = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(handle))
GOTO(out, rc = PTR_ERR(handle));
lfsck_buf_init(&ea_buf, buf->lb_buf, size);
rc = dt_declare_xattr_set(env, obj, NULL, &ea_buf,
XATTR_NAME_LOV, LU_XATTR_REPLACE,
handle);
if (rc != 0)
GOTO(out, rc);
rc = dt_trans_start_local(env, dev, handle);
if (rc != 0)
GOTO(out, rc);
dt_write_lock(env, obj, 0);
locked = true;
goto again;
}
if (magic == LOV_MAGIC_COMP_V1 || magic == LOV_MAGIC_SEL) {
struct lov_mds_md_v1 *v1;
int i;
for (i = 0; i < count; i++) {
lcme = &lcm->lcm_entries[i];
v1 = buf->lb_buf + le32_to_cpu(lcme->lcme_offset);
if (le32_to_cpu(v1->lmm_magic) == LOV_MAGIC_FOREIGN)
continue;
v1->lmm_oi = *oi;
}
} else if (magic != LOV_MAGIC_FOREIGN) {
lmm->lmm_oi = *oi;
}
rc = dt_xattr_set(env, obj, &ea_buf, XATTR_NAME_LOV,
LU_XATTR_REPLACE, handle);
if (rc != 0)
GOTO(out, rc);
lo->ll_objs_repaired[LLIT_OTHERS - 1]++;
GOTO(out, stripe = true);
out:
if (locked) {
if (lustre_handle_is_used(&lh))
dt_write_unlock(env, obj);
else
dt_read_unlock(env, obj);
}
if (handle != NULL && !IS_ERR(handle))
dt_trans_stop(env, dev, handle);
lfsck_ibits_unlock(&lh, LCK_EX);
if (bad_oi)
CDEBUG(D_LFSCK,
"%s: layout LFSCK master %s bad lmm_oi for "DFID": rc = %d\n",
lfsck_lfsck2name(lfsck),
bk->lb_param & LPF_DRYRUN ? "found" : "repaired",
PFID(lfsck_dto2fid(obj)), rc);
if (stripe) {
if (magic == LOV_MAGIC_COMP_V1 || magic == LOV_MAGIC_SEL) {
int i;
for (i = 0; i < count; i++) {
lcme = &lcm->lcm_entries[i];
if (!(le32_to_cpu(lcme->lcme_flags) &
LCME_FL_INIT))
continue;
rc = lfsck_layout_scan_stripes(env, com, obj,
(struct lov_mds_md_v1 *)(buf->lb_buf +
le32_to_cpu(lcme->lcme_offset)),
le32_to_cpu(lcme->lcme_id));
}
} else {
rc = lfsck_layout_scan_stripes(env, com, obj, lmm, 0);
}
} else {
down_write(&com->lc_sem);
com->lc_new_checked++;
if (rc < 0)
lfsck_layout_record_failure(env, lfsck, lo);
up_write(&com->lc_sem);
}
return rc;
}
static int lfsck_layout_slave_exec_oit(const struct lu_env *env,
struct lfsck_component *com,
struct dt_object *obj)
{
struct lfsck_instance *lfsck = com->lc_lfsck;
struct lfsck_layout *lo = com->lc_file_ram;
const struct lu_fid *fid = lfsck_dto2fid(obj);
struct lfsck_layout_slave_data *llsd = com->lc_data;
struct lfsck_layout_seq *lls;
__u64 seq;
__u64 oid;
int rc;
ENTRY;
LASSERT(llsd != NULL);
if (CFS_FAIL_CHECK(OBD_FAIL_LFSCK_DELAY5) &&
cfs_fail_val == lfsck_dev_idx(lfsck))
wait_var_event_timeout(lfsck, lfsck_should_stop(lfsck),
cfs_time_seconds(1));
lfsck_rbtree_update_bitmap(env, com, fid, false);
down_write(&com->lc_sem);
if (fid_is_idif(fid))
seq = 0;
else if (!fid_is_norm(fid) ||
!fid_is_for_ostobj(env, lfsck, obj, fid))
GOTO(unlock, rc = 0);
else
seq = fid_seq(fid);
com->lc_new_checked++;
lls = lfsck_layout_seq_lookup(llsd, seq);
if (lls == NULL) {
OBD_ALLOC_PTR(lls);
if (unlikely(lls == NULL))
GOTO(unlock, rc = -ENOMEM);
INIT_LIST_HEAD(&lls->lls_list);
lls->lls_seq = seq;
rc = lfsck_layout_lastid_load(env, com, lls);
if (rc != 0) {
CDEBUG(D_LFSCK,
"%s: layout LFSCK failed to load LAST_ID for %#llx: rc = %d\n",
lfsck_lfsck2name(com->lc_lfsck), seq, rc);
lo->ll_objs_failed_phase1++;
OBD_FREE_PTR(lls);
GOTO(unlock, rc);
}
lfsck_layout_seq_insert(llsd, lls);
}
if (unlikely(fid_is_last_id(fid)))
GOTO(unlock, rc = 0);
if (fid_is_idif(fid))
oid = fid_idif_id(fid_seq(fid), fid_oid(fid), fid_ver(fid));
else
oid = fid_oid(fid);
if (oid > lls->lls_lastid_known)
lls->lls_lastid_known = oid;
if (oid > lls->lls_lastid) {
if (!(lo->ll_flags & LF_CRASHED_LASTID)) {
/* OFD may create new objects during LFSCK scanning. */
rc = lfsck_layout_lastid_reload(env, com, lls);
if (unlikely(rc != 0)) {
CDEBUG(D_LFSCK,
"%s: layout LFSCK failed to reload LAST_ID for %#llx: rc = %d\n",
lfsck_lfsck2name(com->lc_lfsck),
lls->lls_seq, rc);
GOTO(unlock, rc);
}
if (oid <= lls->lls_lastid ||
lo->ll_flags & LF_CRASHED_LASTID)
GOTO(unlock, rc = 0);
LASSERT(lfsck->li_out_notify != NULL);
lfsck->li_out_notify(env, lfsck->li_out_notify_data,
LE_LASTID_REBUILDING);
lo->ll_flags |= LF_CRASHED_LASTID;
CDEBUG(D_LFSCK,
"%s: layout LFSCK finds crashed LAST_ID file (2) for the sequence %#llx, old value %llu, known value %llu\n",
lfsck_lfsck2name(lfsck), lls->lls_seq,
lls->lls_lastid, oid);
}
lls->lls_lastid = oid;
lls->lls_dirty = 1;
}
GOTO(unlock, rc = 0);
unlock:
up_write(&com->lc_sem);
return rc;
}
static int lfsck_layout_exec_dir(const struct lu_env *env,
struct lfsck_component *com,
struct lfsck_assistant_object *lso,
struct lu_dirent *ent, __u16 type)
{
return 0;
}
static int lfsck_layout_master_post(const struct lu_env *env,
struct lfsck_component *com,
int result, bool init)
{
struct lfsck_instance *lfsck = com->lc_lfsck;
struct lfsck_layout *lo = com->lc_file_ram;
int rc;
ENTRY;
lfsck_post_generic(env, com, &result);
down_write(&com->lc_sem);
spin_lock(&lfsck->li_lock);
if (!init)
lo->ll_pos_last_checkpoint =
lfsck->li_pos_checkpoint.lp_oit_cookie;
if (result > 0) {
if (lo->ll_flags & LF_INCOMPLETE)
lo->ll_status = LS_PARTIAL;
else
lo->ll_status = LS_SCANNING_PHASE2;
lo->ll_flags |= LF_SCANNED_ONCE;
lo->ll_flags &= ~LF_UPGRADE;
list_move_tail(&com->lc_link, &lfsck->li_list_double_scan);
} else if (result == 0) {
if (lfsck->li_status != 0)
lo->ll_status = lfsck->li_status;
else
lo->ll_status = LS_STOPPED;
if (lo->ll_status != LS_PAUSED)
list_move_tail(&com->lc_link, &lfsck->li_list_idle);
} else {
lo->ll_status = LS_FAILED;
list_move_tail(&com->lc_link, &lfsck->li_list_idle);
}
spin_unlock(&lfsck->li_lock);
if (!init) {
lo->ll_run_time_phase1 += ktime_get_seconds() -
lfsck->li_time_last_checkpoint;
lo->ll_time_last_checkpoint = ktime_get_real_seconds();
lo->ll_objs_checked_phase1 += com->lc_new_checked;
com->lc_new_checked = 0;
}
rc = lfsck_layout_store(env, com);
up_write(&com->lc_sem);
CDEBUG(D_LFSCK, "%s: layout LFSCK master post done: rc = %d\n",
lfsck_lfsck2name(lfsck), rc);
RETURN(rc);
}
static int lfsck_layout_slave_post(const struct lu_env *env,
struct lfsck_component *com,
int result, bool init)
{
struct lfsck_instance *lfsck = com->lc_lfsck;
struct lfsck_layout *lo = com->lc_file_ram;
int rc;
bool done = false;
down_write(&com->lc_sem);
rc = lfsck_layout_lastid_store(env, com);
if (rc != 0)
result = rc;
LASSERT(lfsck->li_out_notify != NULL);
spin_lock(&lfsck->li_lock);
if (!init)
lo->ll_pos_last_checkpoint =
lfsck->li_pos_checkpoint.lp_oit_cookie;
if (result > 0) {
lo->ll_status = LS_SCANNING_PHASE2;
lo->ll_flags |= LF_SCANNED_ONCE;
if (lo->ll_flags & LF_CRASHED_LASTID) {
done = true;
lo->ll_flags &= ~LF_CRASHED_LASTID;
CDEBUG(D_LFSCK,
"%s: layout LFSCK has rebuilt crashed LAST_ID files successfully\n",
lfsck_lfsck2name(lfsck));
}
lo->ll_flags &= ~LF_UPGRADE;
list_move_tail(&com->lc_link, &lfsck->li_list_double_scan);
} else if (result == 0) {
if (lfsck->li_status != 0)
lo->ll_status = lfsck->li_status;
else
lo->ll_status = LS_STOPPED;
if (lo->ll_status != LS_PAUSED)
list_move_tail(&com->lc_link, &lfsck->li_list_idle);
} else {
lo->ll_status = LS_FAILED;
list_move_tail(&com->lc_link, &lfsck->li_list_idle);
}
spin_unlock(&lfsck->li_lock);
if (done)
lfsck->li_out_notify(env, lfsck->li_out_notify_data,
LE_LASTID_REBUILT);
if (!init) {
lo->ll_run_time_phase1 += ktime_get_seconds() -
lfsck->li_time_last_checkpoint;
lo->ll_time_last_checkpoint = ktime_get_real_seconds();
lo->ll_objs_checked_phase1 += com->lc_new_checked;
com->lc_new_checked = 0;
}
rc = lfsck_layout_store(env, com);
up_write(&com->lc_sem);
lfsck_layout_slave_notify_master(env, com, LE_PHASE1_DONE, result);
CDEBUG(D_LFSCK, "%s: layout LFSCK slave post done: rc = %d\n",
lfsck_lfsck2name(lfsck), rc);
return rc;
}
static void lfsck_layout_dump(const struct lu_env *env,
struct lfsck_component *com, struct seq_file *m)
{
struct lfsck_instance *lfsck = com->lc_lfsck;
struct lfsck_bookmark *bk = &lfsck->li_bookmark_ram;
struct lfsck_layout *lo = com->lc_file_ram;
const char *prefix;
down_read(&com->lc_sem);
if (bk->lb_param & LPF_DRYRUN)
prefix = "inconsistent";
else
prefix = "repaired";
seq_printf(m, "name: lfsck_layout\n"
"magic: %#x\n"
"version: %d\n"
"status: %s\n",
lo->ll_magic,
bk->lb_version,
lfsck_status2name(lo->ll_status));
lfsck_bits_dump(m, lo->ll_flags, lfsck_flags_names, "flags");
lfsck_bits_dump(m, bk->lb_param, lfsck_param_names, "param");
lfsck_time_dump(m, lo->ll_time_last_complete, "last_completed");
lfsck_time_dump(m, lo->ll_time_latest_start, "latest_start");
lfsck_time_dump(m, lo->ll_time_last_checkpoint, "last_checkpoint");
seq_printf(m, "latest_start_position: %llu\n"
"last_checkpoint_position: %llu\n"
"first_failure_position: %llu\n",
lo->ll_pos_latest_start,
lo->ll_pos_last_checkpoint,
lo->ll_pos_first_inconsistent);
seq_printf(m, "success_count: %u\n"
"%s_dangling: %llu\n"
"%s_unmatched_pair: %llu\n"
"%s_multiple_referenced: %llu\n"
"%s_orphan: %llu\n"
"%s_inconsistent_owner: %llu\n"
"%s_others: %llu\n"
"skipped: %llu\n"
"failed_phase1: %llu\n"
"failed_phase2: %llu\n",
lo->ll_success_count,
prefix, lo->ll_objs_repaired[LLIT_DANGLING - 1],
prefix, lo->ll_objs_repaired[LLIT_UNMATCHED_PAIR - 1],
prefix, lo->ll_objs_repaired[LLIT_MULTIPLE_REFERENCED - 1],
prefix, lo->ll_objs_repaired[LLIT_ORPHAN - 1],
prefix, lo->ll_objs_repaired[LLIT_INCONSISTENT_OWNER - 1],
prefix, lo->ll_objs_repaired[LLIT_OTHERS - 1],
lo->ll_objs_skipped,
lo->ll_objs_failed_phase1,
lo->ll_objs_failed_phase2);
if (lo->ll_status == LS_SCANNING_PHASE1) {
time64_t duration = ktime_get_seconds() -
lfsck->li_time_last_checkpoint;
u64 checked = lo->ll_objs_checked_phase1 +
com->lc_new_checked;
u64 speed = checked;
u64 new_checked = com->lc_new_checked;
time64_t rtime = lo->ll_run_time_phase1 + duration;
u64 pos;
if (duration != 0)
new_checked = div64_s64(new_checked, duration);
if (rtime != 0)
speed = div64_s64(speed, rtime);
seq_printf(m, "checked_phase1: %llu\n"
"checked_phase2: %llu\n"
"run_time_phase1: %lld seconds\n"
"run_time_phase2: %lld seconds\n"
"average_speed_phase1: %llu items/sec\n"
"average_speed_phase2: N/A\n"
"real_time_speed_phase1: %llu items/sec\n"
"real_time_speed_phase2: N/A\n",
checked,
lo->ll_objs_checked_phase2,
rtime,
lo->ll_run_time_phase2,
speed,
new_checked);
if (likely(lfsck->li_di_oit)) {
const struct dt_it_ops *iops =
&lfsck->li_obj_oit->do_index_ops->dio_it;
/* The low layer otable-based iteration position may NOT
* exactly match the layout-based directory traversal
* cookie. Generally, it is not a serious issue. But the
* caller should NOT make assumption on that.
*/
pos = iops->store(env, lfsck->li_di_oit);
if (!lfsck->li_current_oit_processed)
pos--;
} else {
pos = lo->ll_pos_last_checkpoint;
}
seq_printf(m, "current_position: %llu\n", pos);
} else if (lo->ll_status == LS_SCANNING_PHASE2) {
time64_t duration = ktime_get_seconds() -
com->lc_time_last_checkpoint;
u64 checked = lo->ll_objs_checked_phase2 +
com->lc_new_checked;
u64 speed1 = lo->ll_objs_checked_phase1;
u64 speed2 = checked;
u64 new_checked = com->lc_new_checked;
time64_t rtime = lo->ll_run_time_phase2 + duration;
if (duration != 0)
new_checked = div64_s64(new_checked, duration);
if (lo->ll_run_time_phase1 != 0)
speed1 = div64_s64(speed1, lo->ll_run_time_phase1);
if (rtime != 0)
speed2 = div64_s64(speed2, rtime);
seq_printf(m, "checked_phase1: %llu\n"
"checked_phase2: %llu\n"
"run_time_phase1: %lld seconds\n"
"run_time_phase2: %lld seconds\n"
"average_speed_phase1: %llu items/sec\n"
"average_speed_phase2: %llu items/sec\n"
"real_time_speed_phase1: N/A\n"
"real_time_speed_phase2: %llu items/sec\n"
"current_position: "DFID"\n",
lo->ll_objs_checked_phase1,
checked,
lo->ll_run_time_phase1,
rtime,
speed1,
speed2,
new_checked,
PFID(&com->lc_fid_latest_scanned_phase2));
} else {
__u64 speed1 = lo->ll_objs_checked_phase1;
__u64 speed2 = lo->ll_objs_checked_phase2;
if (lo->ll_run_time_phase1 != 0)
speed1 = div64_s64(speed1, lo->ll_run_time_phase1);
if (lo->ll_run_time_phase2 != 0)
speed2 = div64_s64(speed2, lo->ll_run_time_phase2);
seq_printf(m, "checked_phase1: %llu\n"
"checked_phase2: %llu\n"
"run_time_phase1: %lld seconds\n"
"run_time_phase2: %lld seconds\n"
"average_speed_phase1: %llu items/sec\n"
"average_speed_phase2: %llu objs/sec\n"
"real_time_speed_phase1: N/A\n"
"real_time_speed_phase2: N/A\n"
"current_position: N/A\n",
lo->ll_objs_checked_phase1,
lo->ll_objs_checked_phase2,
lo->ll_run_time_phase1,
lo->ll_run_time_phase2,
speed1,
speed2);
}
up_read(&com->lc_sem);
}
static int lfsck_layout_master_double_scan(const struct lu_env *env,
struct lfsck_component *com)
{
struct lfsck_layout *lo = com->lc_file_ram;
struct lfsck_assistant_data *lad = com->lc_data;
int rc;
rc = lfsck_double_scan_generic(env, com, lo->ll_status);
if (test_bit(LAD_STOPPED, &lad->lad_flags)) {
struct lfsck_instance *lfsck = com->lc_lfsck;
struct list_head *tmp;
struct list_head *next;
LASSERT(lad->lad_task == NULL);
LASSERT(list_empty(&lad->lad_req_list));
LASSERT(list_empty(&lad->lad_ost_phase1_list));
LASSERT(list_empty(&lad->lad_mdt_phase1_list));
spin_lock(&lfsck->li_mdt_descs.ltd_lock);
list_for_each_safe(tmp, next, &lad->lad_mdt_phase2_list)
list_del_init(tmp);
spin_unlock(&lfsck->li_mdt_descs.ltd_lock);
spin_lock(&lfsck->li_ost_descs.ltd_lock);
list_for_each_safe(tmp, next, &lad->lad_ost_phase2_list)
list_del_init(tmp);
spin_unlock(&lfsck->li_ost_descs.ltd_lock);
}
return rc;
}
static int lfsck_layout_slave_double_scan(const struct lu_env *env,
struct lfsck_component *com)
{
struct lfsck_instance *lfsck = com->lc_lfsck;
struct lfsck_layout_slave_data *llsd = com->lc_data;
struct lfsck_layout *lo = com->lc_file_ram;
int rc = 0;
ENTRY;
CDEBUG(D_LFSCK, "%s: layout LFSCK slave phase2 scan start\n",
lfsck_lfsck2name(lfsck));
atomic_inc(&lfsck->li_double_scan_count);
if (lo->ll_flags & LF_INCOMPLETE)
GOTO(done, rc = 1);
com->lc_new_checked = 0;
com->lc_new_scanned = 0;
com->lc_time_last_checkpoint = ktime_get_seconds();
com->lc_time_next_checkpoint = com->lc_time_last_checkpoint +
LFSCK_CHECKPOINT_INTERVAL;
while (!lfsck_should_stop(lfsck)) {
rc = lfsck_layout_slave_query_master(env, com);
if (list_empty(&llsd->llsd_master_list)) {
if (unlikely(lfsck_should_stop(lfsck)))
rc = 0;
else
rc = 1;
GOTO(done, rc);
}
if (rc < 0)
GOTO(done, rc);
rc = wait_var_event_timeout(lfsck,
lfsck_should_stop(lfsck) ||
lo->ll_flags & LF_INCOMPLETE ||
list_empty(&llsd->llsd_master_list),
cfs_time_seconds(30));
if (lo->ll_flags & LF_INCOMPLETE)
GOTO(done, rc = 1);
if (rc == 0)
continue;
GOTO(done, rc = 1);
}
done:
rc = lfsck_layout_double_scan_result(env, com, rc);
lfsck_layout_slave_notify_master(env, com, LE_PHASE2_DONE,
(rc > 0 && lo->ll_flags & LF_INCOMPLETE) ? 0 : rc);
lfsck_layout_slave_quit(env, com);
if (atomic_dec_and_test(&lfsck->li_double_scan_count))
wake_up_var(lfsck);
CDEBUG(D_LFSCK,
"%s: layout LFSCK slave phase2 scan finished, status %d: rc = %d\n",
lfsck_lfsck2name(lfsck), lo->ll_status, rc);
return rc;
}
static void lfsck_layout_master_data_release(const struct lu_env *env,
struct lfsck_component *com)
{
struct lfsck_assistant_data *lad = com->lc_data;
struct lfsck_instance *lfsck = com->lc_lfsck;
struct lfsck_tgt_descs *ltds;
struct lfsck_tgt_desc *ltd;
struct lfsck_tgt_desc *next;
LASSERT(lad != NULL);
LASSERT(!lad->lad_task);
LASSERT(list_empty(&lad->lad_req_list));
com->lc_data = NULL;
ltds = &lfsck->li_ost_descs;
spin_lock(<ds->ltd_lock);
list_for_each_entry_safe(ltd, next, &lad->lad_ost_phase1_list,
ltd_layout_phase_list) {
list_del_init(<d->ltd_layout_phase_list);
}
list_for_each_entry_safe(ltd, next, &lad->lad_ost_phase2_list,
ltd_layout_phase_list) {
list_del_init(<d->ltd_layout_phase_list);
}
list_for_each_entry_safe(ltd, next, &lad->lad_ost_list,
ltd_layout_list) {
list_del_init(<d->ltd_layout_list);
}
spin_unlock(<ds->ltd_lock);
ltds = &lfsck->li_mdt_descs;
spin_lock(<ds->ltd_lock);
list_for_each_entry_safe(ltd, next, &lad->lad_mdt_phase1_list,
ltd_layout_phase_list) {
list_del_init(<d->ltd_layout_phase_list);
}
list_for_each_entry_safe(ltd, next, &lad->lad_mdt_phase2_list,
ltd_layout_phase_list) {
list_del_init(<d->ltd_layout_phase_list);
}
list_for_each_entry_safe(ltd, next, &lad->lad_mdt_list,
ltd_layout_list) {
list_del_init(<d->ltd_layout_list);
}
spin_unlock(<ds->ltd_lock);
bitmap_free(lad->lad_bitmap);
OBD_FREE_PTR(lad);
}
static void lfsck_layout_slave_data_release(const struct lu_env *env,
struct lfsck_component *com)
{
struct lfsck_layout_slave_data *llsd = com->lc_data;
lfsck_layout_slave_quit(env, com);
com->lc_data = NULL;
OBD_FREE_PTR(llsd);
}
static void lfsck_layout_master_quit(const struct lu_env *env,
struct lfsck_component *com)
{
struct lfsck_instance *lfsck = com->lc_lfsck;
struct lfsck_assistant_data *lad = com->lc_data;
struct list_head *tmp;
struct list_head *next;
LASSERT(lad != NULL);
lfsck_stop_assistant(lad);
LASSERT(list_empty(&lad->lad_req_list));
spin_lock(&lfsck->li_mdt_descs.ltd_lock);
list_for_each_safe(tmp, next, &lad->lad_mdt_phase1_list)
list_del_init(tmp);
list_for_each_safe(tmp, next, &lad->lad_mdt_phase2_list)
list_del_init(tmp);
spin_unlock(&lfsck->li_mdt_descs.ltd_lock);
spin_lock(&lfsck->li_ost_descs.ltd_lock);
list_for_each_safe(tmp, next, &lad->lad_ost_phase1_list)
list_del_init(tmp);
list_for_each_safe(tmp, next, &lad->lad_ost_phase2_list)
list_del_init(tmp);
spin_unlock(&lfsck->li_ost_descs.ltd_lock);
}
static void lfsck_layout_slave_quit(const struct lu_env *env,
struct lfsck_component *com)
{
struct lfsck_layout_slave_data *llsd = com->lc_data;
struct lfsck_layout_seq *lls;
struct lfsck_layout_seq *next;
struct lfsck_layout_slave_target *llst;
LASSERT(llsd != NULL);
down_write(&com->lc_sem);
list_for_each_entry_safe(lls, next, &llsd->llsd_seq_list,
lls_list) {
list_del_init(&lls->lls_list);
lfsck_object_put(env, lls->lls_lastid_obj);
OBD_FREE_PTR(lls);
}
up_write(&com->lc_sem);
spin_lock(&llsd->llsd_lock);
while (!list_empty(&llsd->llsd_master_list)) {
llst = list_first_entry(&llsd->llsd_master_list,
struct lfsck_layout_slave_target,
llst_list);
list_del_init(&llst->llst_list);
spin_unlock(&llsd->llsd_lock);
kref_put(&llst->llst_ref, lfsck_layout_llst_put);
spin_lock(&llsd->llsd_lock);
}
spin_unlock(&llsd->llsd_lock);
lfsck_rbtree_cleanup(env, com);
}
static int lfsck_layout_master_in_notify(const struct lu_env *env,
struct lfsck_component *com,
struct lfsck_request *lr)
{
struct lfsck_instance *lfsck = com->lc_lfsck;
struct lfsck_layout *lo = com->lc_file_ram;
struct lfsck_assistant_data *lad = com->lc_data;
struct lfsck_tgt_descs *ltds;
struct lfsck_tgt_desc *ltd;
bool fail = false;
ENTRY;
if (lr->lr_event == LE_PAIRS_VERIFY) {
int rc;
rc = lfsck_layout_master_check_pairs(env, com, &lr->lr_fid,
&lr->lr_fid2,
lr->lr_comp_id);
RETURN(rc);
}
CDEBUG(D_LFSCK,
"%s: layout LFSCK master handles notify %u from %s %x, status %d, flags %x, flags2 %x\n",
lfsck_lfsck2name(lfsck), lr->lr_event,
(lr->lr_flags & LEF_FROM_OST) ? "OST" : "MDT",
lr->lr_index, lr->lr_status, lr->lr_flags, lr->lr_flags2);
if (lr->lr_event != LE_PHASE1_DONE &&
lr->lr_event != LE_PHASE2_DONE &&
lr->lr_event != LE_PEER_EXIT)
RETURN(-EINVAL);
if (lr->lr_flags & LEF_FROM_OST)
ltds = &lfsck->li_ost_descs;
else
ltds = &lfsck->li_mdt_descs;
spin_lock(<ds->ltd_lock);
ltd = lfsck_ltd2tgt(ltds, lr->lr_index);
if (ltd == NULL) {
spin_unlock(<ds->ltd_lock);
RETURN(-ENXIO);
}
list_del_init(<d->ltd_layout_phase_list);
switch (lr->lr_event) {
case LE_PHASE1_DONE:
if (lr->lr_status <= 0 || lr->lr_flags2 & LF_INCOMPLETE) {
if (lr->lr_flags2 & LF_INCOMPLETE) {
if (lr->lr_flags & LEF_FROM_OST)
lfsck_lad_set_bitmap(env, com,
ltd->ltd_index);
else
lo->ll_flags |= LF_INCOMPLETE;
}
ltd->ltd_layout_done = 1;
list_del_init(<d->ltd_layout_list);
fail = true;
break;
}
if (lr->lr_flags & LEF_FROM_OST) {
if (list_empty(<d->ltd_layout_list))
list_add_tail(<d->ltd_layout_list,
&lad->lad_ost_list);
list_add_tail(<d->ltd_layout_phase_list,
&lad->lad_ost_phase2_list);
} else {
if (list_empty(<d->ltd_layout_list))
list_add_tail(<d->ltd_layout_list,
&lad->lad_mdt_list);
list_add_tail(<d->ltd_layout_phase_list,
&lad->lad_mdt_phase2_list);
}
break;
case LE_PHASE2_DONE:
ltd->ltd_layout_done = 1;
if (!list_empty(<d->ltd_layout_list))
list_del_init(<d->ltd_layout_list);
if (lr->lr_flags2 & LF_INCOMPLETE) {
lfsck_lad_set_bitmap(env, com, ltd->ltd_index);
fail = true;
}
break;
case LE_PEER_EXIT:
fail = true;
ltd->ltd_layout_done = 1;
list_del_init(<d->ltd_layout_list);
if (!(lfsck->li_bookmark_ram.lb_param & LPF_FAILOUT) &&
!(lr->lr_flags & LEF_FROM_OST))
lo->ll_flags |= LF_INCOMPLETE;
break;
default:
break;
}
spin_unlock(<ds->ltd_lock);
if (fail && lfsck->li_bookmark_ram.lb_param & LPF_FAILOUT) {
struct lfsck_stop *stop = &lfsck_env_info(env)->lti_stop;
memset(stop, 0, sizeof(*stop));
stop->ls_status = lr->lr_status;
stop->ls_flags = lr->lr_param & ~LPF_BROADCAST;
lfsck_stop(env, lfsck->li_bottom, stop);
} else if (lfsck_phase2_next_ready(lad)) {
wake_up_var(lfsck);
}
RETURN(0);
}
static int lfsck_layout_slave_in_notify_local(const struct lu_env *env,
struct lfsck_component *com,
struct lfsck_req_local *lrl,
struct thandle *th)
{
ENTRY;
switch (lrl->lrl_event) {
case LEL_FID_ACCESSED:
lfsck_rbtree_update_bitmap(env, com, &lrl->lrl_fid, true);
RETURN(0);
case LEL_PAIRS_VERIFY_LOCAL: {
int rc;
lrl->lrl_status = LPVS_INIT;
/* Firstly, if the MDT-object which is claimed via OST-object
* local stored PFID xattr recognizes the OST-object, then it
* must be that the client given PFID is wrong.
*/
rc = lfsck_layout_slave_check_pairs(env, com, &lrl->lrl_fid,
&lrl->lrl_ff_local.ff_parent,
lrl->lrl_ff_local.ff_layout.ol_comp_id);
if (rc <= 0)
RETURN(0);
lrl->lrl_status = LPVS_INCONSISTENT;
/* The OST-object local stored PFID xattr is stale. We need to
* check whether the MDT-object that is claimed via the client
* given PFID information recognizes the OST-object or not. If
* matches, then need to update the OST-object's PFID xattr.
*/
rc = lfsck_layout_slave_check_pairs(env, com, &lrl->lrl_fid,
&lrl->lrl_ff_client.ff_parent,
lrl->lrl_ff_client.ff_layout.ol_comp_id);
/* For rc < 0 case:
* We are not sure whether the client given PFID information
* is correct or not, do nothing to avoid improper fixing.
*
* For rc > 0 case:
* The client given PFID information is also invalid, we can
* NOT fix the OST-object inconsistency.
*/
if (!rc) {
lrl->lrl_status = LPVS_INCONSISTENT_TOFIX;
rc = lfsck_layout_slave_repair_pfid(env, com, lrl);
}
RETURN(rc);
}
default:
break;
}
RETURN(-EOPNOTSUPP);
}
static int lfsck_layout_slave_in_notify(const struct lu_env *env,
struct lfsck_component *com,
struct lfsck_request *lr)
{
struct lfsck_instance *lfsck = com->lc_lfsck;
struct lfsck_layout_slave_data *llsd = com->lc_data;
struct lfsck_layout_slave_target *llst;
int rc;
ENTRY;
switch (lr->lr_event) {
case LE_CONDITIONAL_DESTROY:
rc = lfsck_layout_slave_conditional_destroy(env, com, lr);
RETURN(rc);
case LE_PHASE1_DONE: {
if (lr->lr_flags2 & LF_INCOMPLETE) {
struct lfsck_layout *lo = com->lc_file_ram;
lo->ll_flags |= LF_INCOMPLETE;
llst = lfsck_layout_llst_find_and_del(llsd,
lr->lr_index,
true);
if (llst != NULL) {
kref_put(&llst->llst_ref,
lfsck_layout_llst_put);
wake_up_var(lfsck);
}
}
RETURN(0);
}
case LE_PHASE2_DONE:
case LE_PEER_EXIT:
CDEBUG(D_LFSCK,
"%s: layout LFSCK slave handle notify %u from MDT %x, status %d\n",
lfsck_lfsck2name(lfsck), lr->lr_event, lr->lr_index,
lr->lr_status);
break;
default:
RETURN(-EINVAL);
}
llst = lfsck_layout_llst_find_and_del(llsd, lr->lr_index, true);
if (llst == NULL)
RETURN(0);
kref_put(&llst->llst_ref, lfsck_layout_llst_put);
if (list_empty(&llsd->llsd_master_list))
wake_up_var(lfsck);
if (lr->lr_event == LE_PEER_EXIT &&
(lfsck->li_bookmark_ram.lb_param & LPF_FAILOUT ||
(list_empty(&llsd->llsd_master_list) &&
(lr->lr_status == LS_STOPPED ||
lr->lr_status == LS_CO_STOPPED)))) {
struct lfsck_stop *stop = &lfsck_env_info(env)->lti_stop;
memset(stop, 0, sizeof(*stop));
stop->ls_status = lr->lr_status;
stop->ls_flags = lr->lr_param & ~LPF_BROADCAST;
lfsck_stop(env, lfsck->li_bottom, stop);
}
RETURN(0);
}
static void lfsck_layout_repaired(struct lfsck_layout *lo, __u64 *count)
{
int i;
for (i = 0; i < LLIT_MAX; i++)
*count += lo->ll_objs_repaired[i];
}
static int lfsck_layout_query_all(const struct lu_env *env,
struct lfsck_component *com,
__u32 *mdts_count, __u32 *osts_count,
__u64 *repaired)
{
struct lfsck_layout *lo = com->lc_file_ram;
struct lfsck_tgt_descs *ltds;
struct lfsck_tgt_desc *ltd;
int idx;
int rc;
ENTRY;
rc = lfsck_query_all(env, com);
if (rc != 0)
RETURN(rc);
ltds = &com->lc_lfsck->li_mdt_descs;
down_read(<ds->ltd_rw_sem);
for_each_set_bit(idx, ltds->ltd_tgts_bitmap, ltds->ltd_tgts_mask_len) {
ltd = lfsck_ltd2tgt(ltds, idx);
LASSERT(ltd != NULL);
mdts_count[ltd->ltd_layout_status]++;
*repaired += ltd->ltd_layout_repaired;
}
up_read(<ds->ltd_rw_sem);
ltds = &com->lc_lfsck->li_ost_descs;
down_read(<ds->ltd_rw_sem);
for_each_set_bit(idx, ltds->ltd_tgts_bitmap, ltds->ltd_tgts_mask_len) {
ltd = lfsck_ltd2tgt(ltds, idx);
LASSERT(ltd != NULL);
osts_count[ltd->ltd_layout_status]++;
*repaired += ltd->ltd_layout_repaired;
}
up_read(<ds->ltd_rw_sem);
down_read(&com->lc_sem);
mdts_count[lo->ll_status]++;
lfsck_layout_repaired(lo, repaired);
up_read(&com->lc_sem);
RETURN(0);
}
static int lfsck_layout_query(const struct lu_env *env,
struct lfsck_component *com,
struct lfsck_request *req,
struct lfsck_reply *rep,
struct lfsck_query *que, int idx)
{
struct lfsck_layout *lo = com->lc_file_ram;
int rc = 0;
if (que != NULL) {
LASSERT(com->lc_lfsck->li_master);
rc = lfsck_layout_query_all(env, com,
que->lu_mdts_count[idx],
que->lu_osts_count[idx],
&que->lu_repaired[idx]);
} else {
down_read(&com->lc_sem);
rep->lr_status = lo->ll_status;
if (req->lr_flags & LEF_QUERY_ALL)
lfsck_layout_repaired(lo, &rep->lr_repaired);
up_read(&com->lc_sem);
}
return rc;
}
/* with lfsck::li_lock held */
static int lfsck_layout_slave_join(const struct lu_env *env,
struct lfsck_component *com,
struct lfsck_start_param *lsp)
{
struct lfsck_instance *lfsck = com->lc_lfsck;
struct lfsck_layout_slave_data *llsd = com->lc_data;
struct lfsck_layout_slave_target *llst;
struct lfsck_start *start = lsp->lsp_start;
int rc = 0;
ENTRY;
if (start == NULL || !(start->ls_flags & LPF_OST_ORPHAN))
RETURN(0);
if (!lsp->lsp_index_valid)
RETURN(-EINVAL);
/* If someone is running the LFSCK without orphan handling,
* it will not maintain the object accessing rbtree. So we
* cannot join it for orphan handling.
*/
if (!llsd->llsd_rbtree_valid)
RETURN(-EBUSY);
spin_unlock(&lfsck->li_lock);
rc = lfsck_layout_llst_add(llsd, lsp->lsp_index);
spin_lock(&lfsck->li_lock);
if (rc == 0 && !lfsck->li_task) {
spin_unlock(&lfsck->li_lock);
llst = lfsck_layout_llst_find_and_del(llsd, lsp->lsp_index,
true);
if (llst != NULL)
kref_put(&llst->llst_ref, lfsck_layout_llst_put);
spin_lock(&lfsck->li_lock);
rc = -EAGAIN;
}
RETURN(rc);
}
static const struct lfsck_operations lfsck_layout_master_ops = {
.lfsck_reset = lfsck_layout_reset,
.lfsck_fail = lfsck_layout_fail,
.lfsck_checkpoint = lfsck_layout_master_checkpoint,
.lfsck_prep = lfsck_layout_master_prep,
.lfsck_exec_oit = lfsck_layout_master_exec_oit,
.lfsck_exec_dir = lfsck_layout_exec_dir,
.lfsck_post = lfsck_layout_master_post,
.lfsck_dump = lfsck_layout_dump,
.lfsck_double_scan = lfsck_layout_master_double_scan,
.lfsck_data_release = lfsck_layout_master_data_release,
.lfsck_quit = lfsck_layout_master_quit,
.lfsck_in_notify = lfsck_layout_master_in_notify,
.lfsck_query = lfsck_layout_query,
};
static const struct lfsck_operations lfsck_layout_slave_ops = {
.lfsck_reset = lfsck_layout_reset,
.lfsck_fail = lfsck_layout_fail,
.lfsck_checkpoint = lfsck_layout_slave_checkpoint,
.lfsck_prep = lfsck_layout_slave_prep,
.lfsck_exec_oit = lfsck_layout_slave_exec_oit,
.lfsck_exec_dir = lfsck_layout_exec_dir,
.lfsck_post = lfsck_layout_slave_post,
.lfsck_dump = lfsck_layout_dump,
.lfsck_double_scan = lfsck_layout_slave_double_scan,
.lfsck_data_release = lfsck_layout_slave_data_release,
.lfsck_quit = lfsck_layout_slave_quit,
.lfsck_in_notify_local = lfsck_layout_slave_in_notify_local,
.lfsck_in_notify = lfsck_layout_slave_in_notify,
.lfsck_query = lfsck_layout_query,
.lfsck_join = lfsck_layout_slave_join,
};
static void lfsck_layout_assistant_fill_pos(const struct lu_env *env,
struct lfsck_component *com,
struct lfsck_position *pos)
{
struct lfsck_assistant_data *lad = com->lc_data;
struct lfsck_layout_req *llr;
if (((struct lfsck_layout *)(com->lc_file_ram))->ll_status !=
LS_SCANNING_PHASE1)
return;
if (list_empty(&lad->lad_req_list))
return;
llr = list_first_entry(&lad->lad_req_list,
struct lfsck_layout_req,
llr_lar.lar_list);
pos->lp_oit_cookie = llr->llr_lar.lar_parent->lso_oit_cookie - 1;
}
const struct lfsck_assistant_operations lfsck_layout_assistant_ops = {
.la_handler_p1 = lfsck_layout_assistant_handler_p1,
.la_handler_p2 = lfsck_layout_assistant_handler_p2,
.la_fill_pos = lfsck_layout_assistant_fill_pos,
.la_double_scan_result = lfsck_layout_double_scan_result,
.la_req_fini = lfsck_layout_assistant_req_fini,
.la_sync_failures = lfsck_layout_assistant_sync_failures,
};
int lfsck_layout_setup(const struct lu_env *env, struct lfsck_instance *lfsck)
{
struct lfsck_component *com;
struct lfsck_layout *lo;
struct dt_object *root = NULL;
struct dt_object *obj;
int i;
int rc;
ENTRY;
OBD_ALLOC_PTR(com);
if (com == NULL)
RETURN(-ENOMEM);
INIT_LIST_HEAD(&com->lc_link);
INIT_LIST_HEAD(&com->lc_link_dir);
init_rwsem(&com->lc_sem);
atomic_set(&com->lc_ref, 1);
com->lc_lfsck = lfsck;
com->lc_type = LFSCK_TYPE_LAYOUT;
if (lfsck->li_master) {
com->lc_ops = &lfsck_layout_master_ops;
com->lc_data = lfsck_assistant_data_init(
&lfsck_layout_assistant_ops,
LFSCK_LAYOUT);
if (com->lc_data == NULL)
GOTO(out, rc = -ENOMEM);
for (i = 0; i < LFSCK_STF_COUNT; i++)
mutex_init(&com->lc_sub_trace_objs[i].lsto_mutex);
} else {
struct lfsck_layout_slave_data *llsd;
com->lc_ops = &lfsck_layout_slave_ops;
OBD_ALLOC_PTR(llsd);
if (llsd == NULL)
GOTO(out, rc = -ENOMEM);
INIT_LIST_HEAD(&llsd->llsd_seq_list);
INIT_LIST_HEAD(&llsd->llsd_master_list);
spin_lock_init(&llsd->llsd_lock);
llsd->llsd_rb_root = RB_ROOT;
init_rwsem(&llsd->llsd_rb_rwsem);
com->lc_data = llsd;
}
com->lc_file_size = sizeof(*lo);
OBD_ALLOC(com->lc_file_ram, com->lc_file_size);
if (com->lc_file_ram == NULL)
GOTO(out, rc = -ENOMEM);
OBD_ALLOC(com->lc_file_disk, com->lc_file_size);
if (com->lc_file_disk == NULL)
GOTO(out, rc = -ENOMEM);
root = dt_locate(env, lfsck->li_bottom, &lfsck->li_local_root_fid);
if (IS_ERR(root))
GOTO(out, rc = PTR_ERR(root));
if (unlikely(!dt_try_as_dir(env, root, true)))
GOTO(out, rc = -ENOTDIR);
obj = local_file_find_or_create(env, lfsck->li_los, root,
LFSCK_LAYOUT,
S_IFREG | 0644);
if (IS_ERR(obj))
GOTO(out, rc = PTR_ERR(obj));
com->lc_obj = obj;
rc = lfsck_layout_load(env, com);
if (rc > 0) {
rc = lfsck_layout_reset(env, com, true);
} else if (rc == -ENOENT) {
rc = lfsck_layout_init(env, com);
} else if (lfsck->li_master) {
rc = lfsck_load_sub_trace_files(env, com,
&dt_lfsck_layout_dangling_features,
LFSCK_LAYOUT, false);
if (rc)
rc = lfsck_layout_reset(env, com, true);
}
if (rc != 0)
GOTO(out, rc);
lo = com->lc_file_ram;
switch (lo->ll_status) {
case LS_INIT:
case LS_COMPLETED:
case LS_FAILED:
case LS_STOPPED:
case LS_PARTIAL:
spin_lock(&lfsck->li_lock);
list_add_tail(&com->lc_link, &lfsck->li_list_idle);
spin_unlock(&lfsck->li_lock);
break;
default:
CERROR("%s: unknown lfsck_layout status %d\n",
lfsck_lfsck2name(lfsck), lo->ll_status);
fallthrough;
case LS_SCANNING_PHASE1:
case LS_SCANNING_PHASE2:
/* No need to store the status to disk right now.
* If the system crashed before the status stored,
* it will be loaded back when next time.
*/
lo->ll_status = LS_CRASHED;
if (!lfsck->li_master)
lo->ll_flags |= LF_INCOMPLETE;
fallthrough;
case LS_PAUSED:
case LS_CRASHED:
case LS_CO_FAILED:
case LS_CO_STOPPED:
case LS_CO_PAUSED:
spin_lock(&lfsck->li_lock);
list_add_tail(&com->lc_link, &lfsck->li_list_scan);
spin_unlock(&lfsck->li_lock);
break;
}
if (lo->ll_flags & LF_CRASHED_LASTID) {
LASSERT(lfsck->li_out_notify != NULL);
lfsck->li_out_notify(env, lfsck->li_out_notify_data,
LE_LASTID_REBUILDING);
}
GOTO(out, rc = 0);
out:
if (root != NULL && !IS_ERR(root))
lfsck_object_put(env, root);
if (rc != 0) {
lfsck_component_cleanup(env, com);
CERROR("%s: fail to init layout LFSCK component: rc = %d\n",
lfsck_lfsck2name(lfsck), rc);
}
return rc;
}
struct lfsck_orphan_it {
struct lfsck_component *loi_com;
struct lfsck_rbtree_node *loi_lrn;
struct lfsck_layout_slave_target *loi_llst;
struct lu_fid loi_key;
struct lu_orphan_rec_v3 loi_rec;
__u64 loi_hash;
unsigned int loi_over:1;
};
static int lfsck_fid_match_idx(const struct lu_env *env,
struct lfsck_instance *lfsck,
const struct lu_fid *fid, int idx)
{
struct seq_server_site *ss;
struct lu_server_fld *sf;
struct lu_seq_range *range = &lfsck_env_info(env)->lti_range;
int rc;
/* All abnormal cases will be returned to MDT0. */
if (!fid_is_norm(fid)) {
if (idx == 0)
return 1;
return 0;
}
ss = lfsck_dev_site(lfsck);
if (unlikely(ss == NULL))
return -ENOTCONN;
sf = ss->ss_server_fld;
LASSERT(sf != NULL);
fld_range_set_any(range);
rc = fld_server_lookup(env, sf, fid_seq(fid), range);
if (rc != 0)
return rc;
if (!fld_range_is_mdt(range))
return -EINVAL;
if (range->lsr_index == idx)
return 1;
return 0;
}
static void lfsck_layout_destroy_orphan(const struct lu_env *env,
struct lfsck_instance *lfsck,
struct dt_object *obj)
{
struct dt_device *dev = lfsck_obj2dev(obj);
struct thandle *handle;
int rc;
ENTRY;
if (lfsck->li_bookmark_ram.lb_param & LPF_DRYRUN)
GOTO(log, rc = 0);
handle = lfsck_trans_create(env, dev, lfsck);
if (IS_ERR(handle))
RETURN_EXIT;
rc = dt_declare_ref_del(env, obj, handle);
if (rc != 0)
GOTO(stop, rc);
rc = dt_declare_destroy(env, obj, handle);
if (rc != 0)
GOTO(stop, rc);
rc = dt_trans_start_local(env, dev, handle);
if (rc != 0)
GOTO(stop, rc);
dt_write_lock(env, obj, 0);
rc = dt_ref_del(env, obj, handle);
if (rc == 0)
rc = dt_destroy(env, obj, handle);
dt_write_unlock(env, obj);
GOTO(stop, rc);
stop:
dt_trans_stop(env, dev, handle);
log:
CDEBUG(D_LFSCK, "destroy orphan OST-object "DFID": rc = %d\n",
PFID(lfsck_dto2fid(obj)), rc);
RETURN_EXIT;
}
static struct dt_it *lfsck_orphan_it_init(const struct lu_env *env,
struct dt_object *dt,
__u32 attr)
{
struct dt_device *dev = lu2dt_dev(dt->do_lu.lo_dev);
struct lfsck_instance *lfsck;
struct lfsck_component *com = NULL;
struct lfsck_layout_slave_data *llsd;
struct lfsck_orphan_it *it = NULL;
struct lfsck_layout *lo;
int rc = 0;
ENTRY;
lfsck = lfsck_instance_find(dev, true, false);
if (unlikely(lfsck == NULL))
RETURN(ERR_PTR(-ENXIO));
com = lfsck_component_find(lfsck, LFSCK_TYPE_LAYOUT);
if (unlikely(com == NULL))
GOTO(out, rc = -ENOENT);
lo = com->lc_file_ram;
if (lo->ll_flags & LF_INCOMPLETE)
GOTO(out, rc = -ESRCH);
llsd = com->lc_data;
if (!llsd->llsd_rbtree_valid)
GOTO(out, rc = -ESRCH);
OBD_ALLOC_PTR(it);
if (it == NULL)
GOTO(out, rc = -ENOMEM);
it->loi_llst = lfsck_layout_llst_find_and_del(llsd, attr, false);
if (it->loi_llst == NULL)
GOTO(out, rc = -ENXIO);
if (dev->dd_record_fid_accessed) {
/* The first iteration against the rbtree, scan the whole rbtree
* to remove the nodes which do NOT need to be handled.
*/
down_write(&llsd->llsd_rb_rwsem);
if (dev->dd_record_fid_accessed) {
struct rb_node *node;
struct rb_node *next;
struct lfsck_rbtree_node *lrn;
/* No need to record the fid accessing anymore. */
dev->dd_record_fid_accessed = 0;
node = rb_first(&llsd->llsd_rb_root);
while (node != NULL) {
next = rb_next(node);
lrn = rb_entry(node, struct lfsck_rbtree_node,
lrn_node);
if (atomic_read(&lrn->lrn_known_count) <=
atomic_read(&lrn->lrn_accessed_count)) {
rb_erase(node, &llsd->llsd_rb_root);
lfsck_rbtree_free(lrn);
}
node = next;
}
}
up_write(&llsd->llsd_rb_rwsem);
}
/* read lock the rbtree when init, and unlock when fini */
down_read(&llsd->llsd_rb_rwsem);
it->loi_com = com;
com = NULL;
GOTO(out, rc = 0);
out:
if (com != NULL)
lfsck_component_put(env, com);
CDEBUG(D_LFSCK, "%s: init the orphan iteration: rc = %d\n",
lfsck_lfsck2name(lfsck), rc);
lfsck_instance_put(env, lfsck);
if (rc != 0) {
OBD_FREE_PTR(it);
it = (struct lfsck_orphan_it *)ERR_PTR(rc);
}
return (struct dt_it *)it;
}
static void lfsck_orphan_it_fini(const struct lu_env *env,
struct dt_it *di)
{
struct lfsck_orphan_it *it = (struct lfsck_orphan_it *)di;
struct lfsck_component *com = it->loi_com;
struct lfsck_layout_slave_data *llsd;
struct lfsck_layout_slave_target *llst;
if (com != NULL) {
CDEBUG(D_LFSCK, "%s: fini the orphan iteration\n",
lfsck_lfsck2name(com->lc_lfsck));
llsd = com->lc_data;
up_read(&llsd->llsd_rb_rwsem);
llst = it->loi_llst;
LASSERT(llst != NULL);
/* Save the key and hash for iterate next. */
llst->llst_fid = it->loi_key;
llst->llst_hash = it->loi_hash;
kref_put(&llst->llst_ref, lfsck_layout_llst_put);
lfsck_component_put(env, com);
}
OBD_FREE_PTR(it);
}
/**
* lfsck_orphan_it_next() - Move orphan iterator forward
* @env: Lustre environment
* @di: Pointer to struct dt_it (iterator)
*
* Return:
* * %+1 the iteration finished
* * %0 on success, not finished
* * %negative on error
*/
static int lfsck_orphan_it_next(const struct lu_env *env,
struct dt_it *di)
{
struct lfsck_thread_info *info = lfsck_env_info(env);
struct filter_fid *ff = &info->lti_ff;
struct lu_attr *la = &info->lti_la;
struct lfsck_orphan_it *it = (struct lfsck_orphan_it *)di;
struct lu_fid *key = &it->loi_key;
struct lu_orphan_rec_v3 *rec = &it->loi_rec;
struct ost_layout *ol = &rec->lor_layout;
struct lfsck_component *com = it->loi_com;
struct lfsck_instance *lfsck = com->lc_lfsck;
struct lfsck_layout_slave_data *llsd = com->lc_data;
struct dt_object *obj;
struct lfsck_rbtree_node *lrn;
int pos;
int rc;
__u32 save;
__u32 idx = it->loi_llst->llst_index;
bool exact = false;
ENTRY;
if (it->loi_over)
RETURN(1);
again0:
lrn = it->loi_lrn;
if (lrn == NULL) {
lrn = lfsck_rbtree_search(llsd, key, &exact);
if (lrn == NULL) {
it->loi_over = 1;
RETURN(1);
}
it->loi_lrn = lrn;
if (!exact) {
key->f_seq = lrn->lrn_seq;
key->f_oid = lrn->lrn_first_oid;
key->f_ver = 0;
}
} else {
key->f_oid++;
if (unlikely(key->f_oid == 0)) {
key->f_seq++;
it->loi_lrn = NULL;
goto again0;
}
if (key->f_oid >=
lrn->lrn_first_oid + LFSCK_RBTREE_BITMAP_WIDTH) {
it->loi_lrn = NULL;
goto again0;
}
}
if (unlikely(atomic_read(&lrn->lrn_known_count) <=
atomic_read(&lrn->lrn_accessed_count))) {
struct rb_node *next = rb_next(&lrn->lrn_node);
while (next != NULL) {
lrn = rb_entry(next, struct lfsck_rbtree_node,
lrn_node);
if (atomic_read(&lrn->lrn_known_count) >
atomic_read(&lrn->lrn_accessed_count))
break;
next = rb_next(next);
}
if (next == NULL) {
it->loi_over = 1;
RETURN(1);
}
it->loi_lrn = lrn;
key->f_seq = lrn->lrn_seq;
key->f_oid = lrn->lrn_first_oid;
key->f_ver = 0;
}
pos = key->f_oid - lrn->lrn_first_oid;
again1:
pos = find_next_bit(lrn->lrn_known_bitmap,
LFSCK_RBTREE_BITMAP_WIDTH, pos);
if (pos >= LFSCK_RBTREE_BITMAP_WIDTH) {
key->f_oid = lrn->lrn_first_oid + pos;
if (unlikely(key->f_oid < lrn->lrn_first_oid)) {
key->f_seq++;
key->f_oid = 0;
}
it->loi_lrn = NULL;
goto again0;
}
if (test_bit(pos, lrn->lrn_accessed_bitmap)) {
pos++;
goto again1;
}
key->f_oid = lrn->lrn_first_oid + pos;
obj = lfsck_object_find_bottom(env, lfsck, key);
if (IS_ERR(obj)) {
rc = PTR_ERR(obj);
if (rc == -ENOENT) {
pos++;
goto again1;
}
RETURN(rc);
}
dt_read_lock(env, obj, 0);
if (dt_object_exists(obj) == 0 ||
lfsck_is_dead_obj(obj)) {
dt_read_unlock(env, obj);
lfsck_object_put(env, obj);
pos++;
goto again1;
}
rc = dt_attr_get(env, obj, la);
if (rc != 0)
GOTO(out, rc);
rc = dt_xattr_get(env, obj, lfsck_buf_get(env, ff, sizeof(*ff)),
XATTR_NAME_FID);
if (rc == -ENODATA) {
/* For the pre-created OST-object, update the bitmap to avoid
* others LFSCK (second phase) iteration to touch it again.
*/
if (la->la_ctime == 0) {
if (!test_and_set_bit(pos, lrn->lrn_accessed_bitmap))
atomic_inc(&lrn->lrn_accessed_count);
/* For the race between repairing dangling referenced
* MDT-object and unlink the file, it may left orphan
* OST-object there. Destroy it now!
*/
if (unlikely(!(la->la_mode & S_ISUID))) {
dt_read_unlock(env, obj);
lfsck_layout_destroy_orphan(env, lfsck, obj);
lfsck_object_put(env, obj);
pos++;
goto again1;
}
} else if (idx == 0) {
/* If the orphan OST-object has no parent information,
* regard it as referenced by the MDT-object on MDT0.
*/
fid_zero(&rec->lor_rec.lor_fid);
rec->lor_rec.lor_uid = la->la_uid;
rec->lor_rec.lor_gid = la->la_gid;
memset(ol, 0, sizeof(*ol));
rec->lor_layout_version = 0;
rec->lor_range = 0;
GOTO(out, rc = 0);
}
dt_read_unlock(env, obj);
lfsck_object_put(env, obj);
pos++;
goto again1;
}
if (rc < sizeof(struct lu_fid))
GOTO(out, rc = (rc < 0 ? rc : -EINVAL));
fid_le_to_cpu(&rec->lor_rec.lor_fid, &ff->ff_parent);
/* Currently, the filter_fid::ff_parent::f_ver is not the real parent
* MDT-object's FID::f_ver, instead it is the OST-object index in its
* parent MDT-object's layout EA.
*/
save = rec->lor_rec.lor_fid.f_stripe_idx;
rec->lor_rec.lor_fid.f_ver = 0;
rc = lfsck_fid_match_idx(env, lfsck, &rec->lor_rec.lor_fid, idx);
/* If the orphan OST-object does not claim the MDT, then next.
*
* If we do not know whether it matches or not, then return it
* to the MDT for further check.
*/
if (rc == 0) {
dt_read_unlock(env, obj);
lfsck_object_put(env, obj);
pos++;
goto again1;
}
rec->lor_rec.lor_fid.f_stripe_idx = save;
rec->lor_rec.lor_uid = la->la_uid;
rec->lor_rec.lor_gid = la->la_gid;
ost_layout_le_to_cpu(ol, &ff->ff_layout);
rec->lor_layout_version =
le32_to_cpu(ff->ff_layout_version & ~LU_LAYOUT_RESYNC);
rec->lor_range = le32_to_cpu(ff->ff_range);
CDEBUG(D_LFSCK,
"%s: return orphan "DFID", PFID "DFID", owner %u:%u, stripe size %u, stripe count %u, COMP id %u, COMP start %llu, COMP end %llu, layout version %u, range %u\n",
lfsck_lfsck2name(com->lc_lfsck), PFID(key),
PFID(&rec->lor_rec.lor_fid), rec->lor_rec.lor_uid,
rec->lor_rec.lor_gid, ol->ol_stripe_size, ol->ol_stripe_count,
ol->ol_comp_id, ol->ol_comp_start, ol->ol_comp_end,
rec->lor_layout_version, rec->lor_range);
GOTO(out, rc = 0);
out:
dt_read_unlock(env, obj);
lfsck_object_put(env, obj);
if (rc == 0)
it->loi_hash++;
return rc;
}
/**
* lfsck_orphan_it_get() - Get orphan iterator
* @env: Lustre environment
* @di: Pointer to struct dt_it (iterator)
* @key: Pointer to struct dt_key (target key)
*
* Return:
* * %+1 locate to the exactly position
* * %0 cannot locate to the exactly position, call next() to move to a valid
* position.
* * %negative on error
*/
static int lfsck_orphan_it_get(const struct lu_env *env,
struct dt_it *di,
const struct dt_key *key)
{
struct lfsck_orphan_it *it = (struct lfsck_orphan_it *)di;
int rc;
it->loi_key = *(struct lu_fid *)key;
rc = lfsck_orphan_it_next(env, di);
if (rc == 1)
return 0;
if (rc == 0)
return 1;
return rc;
}
static void lfsck_orphan_it_put(const struct lu_env *env,
struct dt_it *di)
{
}
static struct dt_key *lfsck_orphan_it_key(const struct lu_env *env,
const struct dt_it *di)
{
struct lfsck_orphan_it *it = (struct lfsck_orphan_it *)di;
return (struct dt_key *)&it->loi_key;
}
static int lfsck_orphan_it_key_size(const struct lu_env *env,
const struct dt_it *di)
{
return sizeof(struct lu_fid);
}
static int lfsck_orphan_it_rec(const struct lu_env *env,
const struct dt_it *di,
struct dt_rec *rec,
__u32 attr)
{
struct lfsck_orphan_it *it = (struct lfsck_orphan_it *)di;
*(struct lu_orphan_rec_v3 *)rec = it->loi_rec;
return 0;
}
static __u64 lfsck_orphan_it_store(const struct lu_env *env,
const struct dt_it *di)
{
struct lfsck_orphan_it *it = (struct lfsck_orphan_it *)di;
return it->loi_hash;
}
/**
* lfsck_orphan_it_load() - Load orphan iterator
* @env: Lustre environment
* @di: Pointer to struct dt_it (iterator)
* @hash: Hash value
*
* Return:
* * %+1 locate to the exactly position
* * %0 cannot locate to the exactly position, call next() to move to a valid
* position.
* * %negative on error
*/
static int lfsck_orphan_it_load(const struct lu_env *env,
const struct dt_it *di,
__u64 hash)
{
struct lfsck_orphan_it *it = (struct lfsck_orphan_it *)di;
struct lfsck_layout_slave_target *llst = it->loi_llst;
int rc;
LASSERT(llst != NULL);
if (hash != llst->llst_hash) {
CDEBUG(D_LFSCK,
"%s: the given hash %llu for orphan iteration does not match the one when fini %llu, to be reset.\n",
lfsck_lfsck2name(it->loi_com->lc_lfsck), hash,
llst->llst_hash);
fid_zero(&llst->llst_fid);
llst->llst_hash = 0;
}
it->loi_key = llst->llst_fid;
it->loi_hash = llst->llst_hash;
rc = lfsck_orphan_it_next(env, (struct dt_it *)di);
if (rc == 1)
return 0;
if (rc == 0)
return 1;
return rc;
}
static const struct dt_index_operations lfsck_orphan_index_ops = {
.dio_it = {
.init = lfsck_orphan_it_init,
.fini = lfsck_orphan_it_fini,
.get = lfsck_orphan_it_get,
.put = lfsck_orphan_it_put,
.next = lfsck_orphan_it_next,
.key = lfsck_orphan_it_key,
.key_size = lfsck_orphan_it_key_size,
.rec = lfsck_orphan_it_rec,
.store = lfsck_orphan_it_store,
.load = lfsck_orphan_it_load,
}
};