* GPL HEADER END
*/
/*
- * Copyright (c) 2012, 2013, Intel Corporation.
+ * Copyright (c) 2013, 2014, Intel Corporation.
*/
/*
* lustre/lfsck/lfsck_namespace.c
}
/**
- * \retval +ve: the lfsck_namespace is broken, the caller should reset it.
- * \retval 0: succeed.
- * \retval -ve: failed cases.
+ * Load namespace LFSCK statistics information from the trace file.
+ *
+ * For old release (Lustre-2.6 or older), the statistics information was
+ * stored as XATTR_NAME_LFSCK_NAMESPACE_OLD EA. But in Lustre-2.7, we need
+ * more statistics information. To avoid confusing old MDT when downgrade,
+ * Lustre-2.7 stores the namespace LFSCK statistics information as new
+ * XATTR_NAME_LFSCK_NAMESPACE EA.
+ *
+ * \param[in] env pointer to the thread context
+ * \param[in] com pointer to the lfsck component
+ *
+ * \retval 0 for success
+ * \retval negative error number on failure
*/
static int lfsck_namespace_load(const struct lu_env *env,
struct lfsck_component *com)
CDEBUG(D_LFSCK, "%s: invalid lfsck_namespace magic "
"%#x != %#x\n", lfsck_lfsck2name(com->lc_lfsck),
ns->ln_magic, LFSCK_NAMESPACE_MAGIC);
- rc = 1;
+ rc = -ESTALE;
} else {
rc = 0;
}
"expected = %d: rc = %d\n",
lfsck_lfsck2name(com->lc_lfsck), len, rc);
if (rc >= 0)
- rc = 1;
+ rc = -ESTALE;
+ } else {
+ /* Check whether it is old trace file or not.
+ * If yes, it should be reset via returning -ESTALE. */
+ rc = dt_xattr_get(env, com->lc_obj,
+ lfsck_buf_get(env, com->lc_file_disk, len),
+ XATTR_NAME_LFSCK_NAMESPACE_OLD, BYPASS_CAPA);
+ if (rc >= 0)
+ rc = -ESTALE;
}
+
return rc;
}
static int lfsck_namespace_store(const struct lu_env *env,
- struct lfsck_component *com)
+ struct lfsck_component *com, bool init)
{
struct dt_object *obj = com->lc_obj;
struct lfsck_instance *lfsck = com->lc_lfsck;
__u32 nbits = 0;
int len = com->lc_file_size;
int rc;
+#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 8, 53, 0)
+ struct lu_buf tbuf = { &len, sizeof(len) };
+#endif
ENTRY;
if (lad != NULL) {
GOTO(out, rc);
}
+#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 8, 53, 0)
+ /* To be compatible with old Lustre-2.x MDT (x <= 6), generate dummy
+ * XATTR_NAME_LFSCK_NAMESPACE_OLD EA, then when downgrade to Lustre-2.x,
+ * the old LFSCK will find "invalid" XATTR_NAME_LFSCK_NAMESPACE_OLD EA,
+ * then reset the namespace LFSCK trace file. */
+ if (init) {
+ rc = dt_declare_xattr_set(env, obj, &tbuf,
+ XATTR_NAME_LFSCK_NAMESPACE_OLD,
+ LU_XATTR_CREATE, handle);
+ if (rc != 0)
+ GOTO(out, rc);
+ }
+#endif
+
rc = dt_trans_start_local(env, lfsck->li_bottom, handle);
if (rc != 0)
GOTO(out, rc);
XATTR_NAME_LFSCK_BITMAP, 0, handle,
BYPASS_CAPA);
+#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 8, 53, 0)
+ if (rc == 0 && init)
+ rc = dt_xattr_set(env, obj, &tbuf,
+ XATTR_NAME_LFSCK_NAMESPACE_OLD,
+ LU_XATTR_CREATE, handle, BYPASS_CAPA);
+#endif
+
GOTO(out, rc);
out:
ns->ln_magic = LFSCK_NAMESPACE_MAGIC;
ns->ln_status = LS_INIT;
down_write(&com->lc_sem);
- rc = lfsck_namespace_store(env, com);
+ rc = lfsck_namespace_store(env, com, true);
up_write(&com->lc_sem);
return rc;
}
return rc;
}
-static int lfsck_namespace_check_exist(const struct lu_env *env,
- struct dt_object *dir,
- struct dt_object *obj, const char *name)
+int lfsck_namespace_check_exist(const struct lu_env *env,
+ struct dt_object *dir,
+ struct dt_object *obj, const char *name)
{
struct lu_fid *fid = &lfsck_env_info(env)->lti_fid;
int rc;
}
}
- if (rc != 0)
- GOTO(unlock, rc);
-
- rc = dt_attr_set(env, orphan, la, th, BYPASS_CAPA);
+ if (rc == 0)
+ rc = dt_attr_set(env, orphan, la, th, BYPASS_CAPA);
GOTO(stop, rc = (rc == 0 ? 1 : rc));
rc = ptlrpc_queue_wait(req);
ptlrpc_req_finished(req);
- if (rc == 0)
+ if (rc == 0) {
+ orphan->do_lu.lo_header->loh_attr |= LOHA_EXISTS;
rc = 1;
- else if (rc == -EEXIST)
+ } else if (rc == -EEXIST) {
+ orphan->do_lu.lo_header->loh_attr |= LOHA_EXISTS;
rc = 0;
+ }
GOTO(out, rc);
int rc = 0;
ENTRY;
- LASSERT(!dt_object_remote(obj));
-
th = dt_trans_create(env, dev);
if (IS_ERR(th))
GOTO(log, rc = PTR_ERR(th));
GOTO(out, rc);
}
+ if (fid_is_zero(pfid))
+ GOTO(out, rc = 0);
+
/* The ".." name entry is wrong, update it. */
if (!lu_fid_eq(pfid, lfsck_dto2fid(parent))) {
if (!lustre_handle_is_used(lh) && retry != NULL) {
struct lfsck_bookmark *bk = &lfsck->li_bookmark_ram;
struct dt_object *parent = NULL;
struct linkea_data ldata_new = { 0 };
- int count = 0;
+ int dirent_count = 0;
+ int linkea_count = 0;
int rc = 0;
bool once = true;
ENTRY;
/* Drop invalid linkEA entry. */
if (!fid_is_sane(tfid)) {
linkea_del_buf(ldata, cname);
+ linkea_count++;
continue;
}
* child to be visible via other parent, then
* remove this linkEA entry. */
linkea_del_buf(ldata, cname);
+ linkea_count++;
continue;
}
if (unlikely(!dt_try_as_dir(env, parent))) {
lfsck_object_put(env, parent);
linkea_del_buf(ldata, cname);
+ linkea_count++;
continue;
}
RETURN(rc);
linkea_del_buf(ldata, cname);
+ linkea_count++;
linkea_first_entry(ldata);
/* There may be some invalid dangling name entries under
* other parent directories, remove all of them. */
goto next;
}
- count += rc;
+ dirent_count += rc;
next:
linkea_del_buf(ldata, cname);
}
- ns->ln_dirent_repaired += count;
+ ns->ln_dirent_repaired += dirent_count;
RETURN(rc);
}
linkea_del_buf(ldata, cname);
}
+ linkea_first_entry(ldata);
if (ldata->ld_leh->leh_reccount == 1) {
rc = lfsck_namespace_dsd_single(env, com, child, pfid, ldata,
lh, type, NULL);
+ if (rc == 0 && fid_is_zero(pfid) && linkea_count > 0)
+ rc = lfsck_namespace_rebuild_linkea(env, com, child,
+ ldata);
+
RETURN(rc);
}
RETURN(rc);
}
- linkea_first_entry(ldata);
/* If the dangling name entry for the orphan directory object has
* been remvoed, then just check whether the directory object is
* still under the .lustre/lost+found/MDTxxxx/ or not. */
* \param[in] env pointer to the thread context
* \param[in] com pointer to the lfsck component
* \param[in] obj pointer to the dt_object to be handled
- * \param[in,out] nlink pointer to buffer to object's hard lock count before
+ * \param[in,out] la pointer to buffer to object's attribute before
* and after the repairing
*
* \retval positive number for repaired cases
*/
static int lfsck_namespace_repair_nlink(const struct lu_env *env,
struct lfsck_component *com,
- struct dt_object *obj, __u32 *nlink)
+ struct dt_object *obj,
+ struct lu_attr *la)
{
struct lfsck_thread_info *info = lfsck_env_info(env);
- struct lu_attr *la = &info->lti_la3;
struct lu_fid *tfid = &info->lti_fid3;
struct lfsck_namespace *ns = com->lc_file_ram;
struct lfsck_instance *lfsck = com->lc_lfsck;
struct thandle *th = NULL;
struct linkea_data ldata = { 0 };
struct lustre_handle lh = { 0 };
- __u32 old = *nlink;
+ __u32 old = la->la_nlink;
int rc = 0;
__u8 flags;
ENTRY;
if (flags & LNTF_SKIP_NLINK)
GOTO(unlock, rc = 0);
- rc = lfsck_links_read2(env, child, &ldata);
- if (rc == -ENODATA)
- GOTO(unlock, rc = 0);
+ rc = dt_attr_get(env, child, la, BYPASS_CAPA);
+ if (rc != 0)
+ GOTO(unlock, rc = (rc == -ENOENT ? 0 : rc));
+ rc = lfsck_links_read2(env, child, &ldata);
if (rc != 0)
- GOTO(unlock, rc);
+ GOTO(unlock, rc = (rc == -ENODATA ? 0 : rc));
- if (*nlink == ldata.ld_leh->leh_reccount)
+ if (la->la_nlink == ldata.ld_leh->leh_reccount ||
+ unlikely(la->la_nlink == 0))
GOTO(unlock, rc = 0);
- la->la_nlink = *nlink = ldata.ld_leh->leh_reccount;
+ la->la_nlink = ldata.ld_leh->leh_reccount;
if (lfsck->li_bookmark_ram.lb_param & LPF_DRYRUN)
GOTO(unlock, rc = 1);
CDEBUG(D_LFSCK, "%s: namespace LFSCK repaired the object "DFID"'s "
"nlink count from %u to %u: rc = %d\n",
- lfsck_lfsck2name(lfsck), PFID(cfid), old, *nlink, rc);
+ lfsck_lfsck2name(lfsck), PFID(cfid), old, la->la_nlink, rc);
if (rc != 0)
ns->ln_flags |= LF_INCONSISTENT;
} else if (lfsck->li_lpf_obj != NULL &&
lu_fid_eq(pfid, lfsck_dto2fid(lfsck->li_lpf_obj))) {
lpf = true;
+ } else if (unlikely(!fid_is_sane(pfid))) {
+ fid_zero(pfid);
}
rc = lfsck_links_read(env, child, &ldata);
count = ldata.ld_leh->leh_reccount;
}
- /* If the LFSCK is marked as LF_INCOMPLETE, then means some
- * MDT has ever tried to verify some remote MDT-object that
- * resides on this MDT, but this MDT failed to respond such
- * request. So means there may be some remote name entry on
- * other MDT that references this object with another name,
- * so we cannot know whether this linkEA is valid or not.
- * So keep it there and maybe resolved when next LFSCK run. */
- if (count == 0 && !(ns->ln_flags & LF_INCOMPLETE)) {
- /* If the child becomes orphan, then insert it into
- * the global .lustre/lost+found/MDTxxxx directory. */
- rc = lfsck_namespace_insert_orphan(env, com, child, "", "O",
- &count);
- if (rc < 0)
- return rc;
+ if (count == 0) {
+ /* If the LFSCK is marked as LF_INCOMPLETE, then means some
+ * MDT has ever tried to verify some remote MDT-object that
+ * resides on this MDT, but this MDT failed to respond such
+ * request. So means there may be some remote name entry on
+ * other MDT that references this object with another name,
+ * so we cannot know whether this linkEA is valid or not.
+ * So keep it there and maybe resolved when next LFSCK run. */
+ if (!(ns->ln_flags & LF_INCOMPLETE)) {
+ /* If the child becomes orphan, then insert it into
+ * the global .lustre/lost+found/MDTxxxx directory. */
+ rc = lfsck_namespace_insert_orphan(env, com, child,
+ "", "O", &count);
+ if (rc < 0)
+ return rc;
- if (rc > 0) {
- ns->ln_mul_ref_repaired++;
- repaired = true;
+ if (rc > 0) {
+ ns->ln_mul_ref_repaired++;
+ repaired = true;
+ }
}
- }
-
- rc = dt_attr_get(env, child, la, BYPASS_CAPA);
- if (rc != 0)
- return rc;
+ } else {
+ rc = dt_attr_get(env, child, la, BYPASS_CAPA);
+ if (rc != 0)
+ return rc;
- if (la->la_nlink != count) {
- rc = lfsck_namespace_repair_nlink(env, com, child,
- &la->la_nlink);
- if (rc > 0) {
- ns->ln_objs_nlink_repaired++;
- rc = 0;
+ if (la->la_nlink != 0 && la->la_nlink != count) {
+ rc = lfsck_namespace_repair_nlink(env, com, child, la);
+ if (rc > 0) {
+ ns->ln_objs_nlink_repaired++;
+ rc = 0;
+ }
}
}
lad->lad_incomplete = 0;
CFS_RESET_BITMAP(lad->lad_bitmap);
- rc = lfsck_namespace_store(env, com);
+ rc = lfsck_namespace_store(env, com, true);
GOTO(out, rc);
com->lc_new_checked = 0;
}
- rc = lfsck_namespace_store(env, com);
+ rc = lfsck_namespace_store(env, com, false);
up_write(&com->lc_sem);
log:
struct lfsck_component *com,
struct lu_dirent *ent, __u16 type)
{
- struct lfsck_assistant_data *lad = com->lc_data;
+ struct lfsck_assistant_data *lad = com->lc_data;
+ struct lfsck_instance *lfsck = com->lc_lfsck;
struct lfsck_namespace_req *lnr;
- bool wakeup = false;
+ struct lfsck_bookmark *bk = &lfsck->li_bookmark_ram;
+ struct ptlrpc_thread *mthread = &lfsck->li_thread;
+ struct ptlrpc_thread *athread = &lad->lad_thread;
+ struct l_wait_info lwi = { 0 };
+ bool wakeup = false;
+
+ l_wait_event(mthread->t_ctl_waitq,
+ bk->lb_async_windows == 0 ||
+ lad->lad_prefetched < bk->lb_async_windows ||
+ !thread_is_running(mthread) ||
+ thread_is_stopped(athread),
+ &lwi);
+
+ if (unlikely(!thread_is_running(mthread)) ||
+ thread_is_stopped(athread))
+ return 0;
+
+ if (unlikely(lfsck_is_dead_obj(lfsck->li_obj_dir)))
+ return 0;
lnr = lfsck_namespace_assistant_req_init(com->lc_lfsck, ent, type);
if (IS_ERR(lnr)) {
com->lc_new_checked = 0;
}
- rc = lfsck_namespace_store(env, com);
+ rc = lfsck_namespace_store(env, com, false);
up_write(&com->lc_sem);
CDEBUG(D_LFSCK, "%s: namespace LFSCK post done: rc = %d\n",
lfsck->li_time_last_checkpoint;
__u64 checked = ns->ln_items_checked + com->lc_new_checked;
__u64 speed = checked;
- __u64 new_checked = com->lc_new_checked * HZ;
+ __u64 new_checked = com->lc_new_checked *
+ msecs_to_jiffies(MSEC_PER_SEC);
__u32 rtime = ns->ln_run_time_phase1 +
cfs_duration_sec(duration + HALF_SEC);
com->lc_new_checked;
__u64 speed1 = ns->ln_items_checked;
__u64 speed2 = checked;
- __u64 new_checked = com->lc_new_checked * HZ;
+ __u64 new_checked = com->lc_new_checked *
+ msecs_to_jiffies(MSEC_PER_SEC);
__u32 rtime = ns->ln_run_time_phase2 +
cfs_duration_sec(duration + HALF_SEC);
RETURN(rc > 0 ? 0 : rc);
}
+ case LE_SET_LMV_SLAVE: {
+ if (!(lr->lr_flags & LEF_RECHECK_NAME_HASH))
+ ns->ln_striped_shards_repaired++;
+
+ rc = lfsck_namespace_trace_update(env, com, &lr->lr_fid,
+ LNTF_RECHECK_NAME_HASH, true);
+
+ RETURN(rc > 0 ? 0 : rc);
+ }
case LE_PHASE1_DONE:
case LE_PHASE2_DONE:
case LE_PEER_EXIT:
(lnr->lnr_namelen == 1 || fid_seq_is_dot(fid_seq(&lnr->lnr_fid))))
GOTO(out, rc = 0);
+ if (lnr->lnr_lmv != NULL && lnr->lnr_lmv->ll_lmv_master) {
+ rc = lfsck_namespace_handle_striped_master(env, com, lnr);
+
+ RETURN(rc);
+ }
+
idx = lfsck_find_mdt_idx_by_fid(env, lfsck, &lnr->lnr_fid);
if (idx < 0)
GOTO(out, rc = idx);
*
* Sometimes, the master LMV EA of the striped directory maybe lost, so when
* the namespace LFSCK engine scan the striped directory for the first time,
- * it will be reguarded as a normal directory. As the LFSCK processing, some
+ * it will be regarded as a normal directory. As the LFSCK processing, some
* other LFSCK instance on other MDT will find the shard of this striped dir,
* and find that the master MDT-object of the striped directory lost its LMV
* EA, then such remote LFSCK instance will regenerate the master LMV EA and
goto next;
}
- if (ent->lde_attrs & LUDA_IGNORE &&
- strcmp(ent->lde_name, dotdot) != 0)
+ if (name_is_dot_or_dotdot(ent->lde_name, ent->lde_namelen))
goto next;
lnr = lfsck_namespace_assistant_req_init(lfsck, ent, type);
ns->ln_time_last_checkpoint = cfs_time_current_sec();
ns->ln_objs_checked_phase2 += com->lc_new_checked;
com->lc_new_checked = 0;
- rc = lfsck_namespace_store(env, com);
+ rc = lfsck_namespace_store(env, com, false);
up_write(&com->lc_sem);
if (rc != 0)
GOTO(put, rc);
ns->ln_status = LS_FAILED;
}
- rc = lfsck_namespace_store(env, com);
+ rc = lfsck_namespace_store(env, com, false);
up_write(&com->lc_sem);
return rc;
GOTO(out, rc);
rc = lfsck_namespace_load(env, com);
- if (rc > 0)
- rc = lfsck_namespace_reset(env, com, true);
- else if (rc == -ENODATA)
+ if (rc == -ENODATA)
rc = lfsck_namespace_init(env, com);
+ else if (rc < 0)
+ rc = lfsck_namespace_reset(env, com, true);
if (rc != 0)
GOTO(out, rc);