#include <lustre_lib.h>
#include <lustre_net.h>
#include <lustre/lustre_user.h>
+#include <md_object.h>
#include "lfsck_internal.h"
static const char lfsck_layout_name[] = "lfsck_layout";
+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_data {
+ /* list for lfsck_layout_seq */
+ struct list_head llsd_seq_list;
+};
+
static void lfsck_layout_le_to_cpu(struct lfsck_layout *des,
const struct lfsck_layout *src)
{
return rc;
}
+static int fid_is_for_ostobj(const struct lu_env *env, struct dt_device *dt,
+ struct dt_object *obj, const struct lu_fid *fid)
+{
+ struct seq_server_site *ss = lu_site2seq(dt->dd_lu_dev.ld_site);
+ struct lu_seq_range range = { 0 };
+ struct lustre_mdt_attrs *lma;
+ 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;
+ }
+
+ lma = &lfsck_env_info(env)->lti_lma;
+ rc = dt_xattr_get(env, obj, lfsck_buf_get(env, lma, sizeof(*lma)),
+ XATTR_NAME_LMA, BYPASS_CAPA);
+ if (rc == sizeof(*lma)) {
+ lustre_lma_swab(lma);
+
+ /* Generally, the low layer OSD create handler or OI scrub
+ * will set the LMAC_FID_ON_OST for all external visible
+ * OST-objects. But to make the otable-based iteration to
+ * be independent from OI scrub in spite of it got failure
+ * or not, we check the LMAC_FID_ON_OST here to guarantee
+ * that the LFSCK will not repair something by wrong. */
+ return lma->lma_compat & LMAC_FID_ON_OST ? 1 : 0;
+ }
+
+ rc = dt_xattr_get(env, obj, &LU_BUF_NULL, XATTR_NAME_FID, BYPASS_CAPA);
+
+ 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->li_bottom;
+ struct thandle *th;
+ __u64 lastid = 0;
+ loff_t pos = 0;
+ int rc;
+ ENTRY;
+
+ CDEBUG(D_LFSCK, "To create LAST_ID for <seq> "LPX64"\n",
+ fid_seq(lfsck_dto2fid(obj)));
+
+ if (bk->lb_param & LPF_DRYRUN)
+ return 0;
+
+ memset(la, 0, sizeof(*la));
+ la->la_mode = S_IFREG | S_IRUGO | S_IWUSR;
+ la->la_valid = LA_MODE | LA_UID | LA_GID;
+ dof->dof_type = dt_mode_to_dft(S_IFREG);
+
+ th = dt_trans_create(env, dt);
+ if (IS_ERR(th))
+ RETURN(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, 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))) {
+ 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);
+
+ 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;
+ }
+ } 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;
+
+ /* XXX: Add the code back if we really found related
+ * inconsistent cases in the future. */
+#if 0
+ if (!lls->lls_dirty) {
+ /* In OFD, before the pre-creation, the LAST_ID
+ * file will be updated firstly, which may hide
+ * some potential crashed cases. For example:
+ *
+ * The old obj1's ID is higher than old LAST_ID
+ * but lower than the new LAST_ID, but the LFSCK
+ * have not touch the obj1 until the OFD updated
+ * the LAST_ID. So the LFSCK does not regard it
+ * as crashed case. But when OFD does not create
+ * successfully, it will set the LAST_ID as the
+ * real created objects' ID, then LFSCK needs to
+ * found related inconsistency. */
+ rc = lfsck_layout_lastid_reload(env, com, lls);
+ if (likely(!lls->lls_dirty))
+ continue;
+ }
+#endif
+
+ CDEBUG(D_LFSCK, "To sync the LAST_ID for <seq> "LPX64
+ " as <oid> "LPU64"\n", lls->lls_seq, lls->lls_lastid);
+
+ if (bk->lb_param & LPF_DRYRUN) {
+ lls->lls_dirty = 0;
+ continue;
+ }
+
+ th = dt_trans_create(env, dt);
+ if (IS_ERR(th)) {
+ rc1 = PTR_ERR(th);
+ CERROR("%s: (1) failed to store "LPX64": rc = %d\n",
+ lfsck_lfsck2name(com->lc_lfsck),
+ lls->lls_seq, rc1);
+ continue;
+ }
+
+ rc = dt_declare_record_write(env, lls->lls_lastid_obj,
+ sizeof(lastid), pos, th);
+ if (rc != 0)
+ goto stop;
+
+ rc = dt_trans_start_local(env, dt, th);
+ if (rc != 0)
+ goto stop;
+
+ lastid = cpu_to_le64(lls->lls_lastid);
+ 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;
+ CERROR("%s: (2) failed to store "LPX64": 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->li_bottom));
+ 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)) {
+ 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;
+
+ if (OBD_FAIL_CHECK(OBD_FAIL_LFSCK_DELAY4) &&
+ cfs_fail_val > 0) {
+ struct l_wait_info lwi = LWI_TIMEOUT(
+ cfs_time_seconds(cfs_fail_val),
+ NULL, NULL);
+
+ up_write(&com->lc_sem);
+ l_wait_event(lfsck->li_thread.t_ctl_waitq,
+ !thread_is_running(&lfsck->li_thread),
+ &lwi);
+ 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;
+ }
+
+ 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;
+}
+
/* layout APIs */
/* XXX: Some to be implemented in other patch(es). */
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++;
+ lo->ll_objs_failed_phase1++;
+ if (lo->ll_pos_first_inconsistent == 0) {
+ struct lfsck_instance *lfsck = com->lc_lfsck;
+
+ 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);
}
static int lfsck_layout_checkpoint(const struct lu_env *env,
struct lfsck_component *com, bool init)
{
- return 0;
+ 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_current.lp_oit_cookie;
+ } else {
+ lo->ll_pos_last_checkpoint =
+ lfsck->li_pos_current.lp_oit_cookie;
+ lo->ll_run_time_phase1 += cfs_duration_sec(cfs_time_current() +
+ HALF_SEC - lfsck->li_time_last_checkpoint);
+ lo->ll_time_last_checkpoint = cfs_time_current_sec();
+ 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);
+
+ return rc;
}
static int lfsck_layout_master_prep(const struct lu_env *env,
static int lfsck_layout_slave_prep(const struct lu_env *env,
struct lfsck_component *com)
{
+ struct lfsck_instance *lfsck = com->lc_lfsck;
+ struct lfsck_layout *lo = com->lc_file_ram;
+ struct lfsck_position *pos = &com->lc_pos_start;
+
+ /* XXX: For a new scanning, generate OST-objects
+ * bitmap for orphan detection. */
+
+ fid_zero(&pos->lp_dir_parent);
+ pos->lp_dir_cookie = 0;
+ if (lo->ll_status == LS_COMPLETED ||
+ lo->ll_status == LS_PARTIAL) {
+ int rc;
+
+ rc = lfsck_layout_reset(env, com, false);
+ if (rc != 0)
+ return rc;
+ }
+
+ down_write(&com->lc_sem);
+
+ lo->ll_time_latest_start = cfs_time_current_sec();
+
+ 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_del_init(&com->lc_link);
+ list_add_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;
+ }
+ } 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;
}
struct lfsck_component *com,
struct dt_object *obj)
{
- return 0;
+ 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;
+
+ /* XXX: Update OST-objects bitmap for orphan detection. */
+
+ LASSERT(llsd != NULL);
+
+ down_write(&com->lc_sem);
+ if (fid_is_idif(fid))
+ seq = 0;
+ else if (!fid_is_norm(fid) ||
+ !fid_is_for_ostobj(env, lfsck->li_next, 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) {
+ 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);
+
+ 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))
+ CWARN("%s: failed to reload LAST_ID for "LPX64
+ ": rc = %d\n",
+ lfsck_lfsck2name(com->lc_lfsck),
+ lls->lls_seq, rc);
+ if (oid <= lls->lls_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;
+ }
+
+ 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,
int result, bool init)
{
- return 0;
+ struct lfsck_instance *lfsck = com->lc_lfsck;
+ struct lfsck_layout *lo = com->lc_file_ram;
+ int rc;
+ bool done = false;
+
+ rc = lfsck_layout_lastid_store(env, com);
+ if (rc != 0)
+ result = rc;
+
+ LASSERT(lfsck->li_out_notify != NULL);
+
+ down_write(&com->lc_sem);
+
+ spin_lock(&lfsck->li_lock);
+ if (!init)
+ lo->ll_pos_last_checkpoint =
+ lfsck->li_pos_current.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;
+ }
+ lo->ll_flags &= ~LF_UPGRADE;
+ list_del_init(&com->lc_link);
+ list_add_tail(&com->lc_link, &lfsck->li_list_double_scan);
+ } else if (result == 0) {
+ if (lfsck->li_paused) {
+ lo->ll_status = LS_PAUSED;
+ } else {
+ lo->ll_status = LS_STOPPED;
+ list_del_init(&com->lc_link);
+ list_add_tail(&com->lc_link, &lfsck->li_list_idle);
+ }
+ } else {
+ lo->ll_status = LS_FAILED;
+ list_del_init(&com->lc_link);
+ list_add_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 += cfs_duration_sec(cfs_time_current() +
+ HALF_SEC - lfsck->li_time_last_checkpoint);
+ lo->ll_time_last_checkpoint = cfs_time_current_sec();
+ 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);
+
+ return rc;
}
static int lfsck_layout_dump(const struct lu_env *env,
struct lfsck_component *com, char *buf, int len)
{
- return 0;
+ struct lfsck_instance *lfsck = com->lc_lfsck;
+ struct lfsck_bookmark *bk = &lfsck->li_bookmark_ram;
+ struct lfsck_layout *lo = com->lc_file_ram;
+ int save = len;
+ int ret = -ENOSPC;
+ int rc;
+
+ down_read(&com->lc_sem);
+ rc = snprintf(buf, len,
+ "name: lfsck_layout\n"
+ "magic: %#x\n"
+ "version: %d\n"
+ "status: %s\n",
+ lo->ll_magic,
+ bk->lb_version,
+ lfsck_status2names(lo->ll_status));
+ if (rc <= 0)
+ goto out;
+
+ buf += rc;
+ len -= rc;
+ rc = lfsck_bits_dump(&buf, &len, lo->ll_flags, lfsck_flags_names,
+ "flags");
+ if (rc < 0)
+ goto out;
+
+ rc = lfsck_bits_dump(&buf, &len, bk->lb_param, lfsck_param_names,
+ "param");
+ if (rc < 0)
+ goto out;
+
+ rc = lfsck_time_dump(&buf, &len, lo->ll_time_last_complete,
+ "time_since_last_completed");
+ if (rc < 0)
+ goto out;
+
+ rc = lfsck_time_dump(&buf, &len, lo->ll_time_latest_start,
+ "time_since_latest_start");
+ if (rc < 0)
+ goto out;
+
+ rc = lfsck_time_dump(&buf, &len, lo->ll_time_last_checkpoint,
+ "time_since_last_checkpoint");
+ if (rc < 0)
+ goto out;
+
+ rc = snprintf(buf, len,
+ "latest_start_position: "LPU64"\n"
+ "last_checkpoint_position: "LPU64"\n"
+ "first_failure_position: "LPU64"\n",
+ lo->ll_pos_latest_start,
+ lo->ll_pos_last_checkpoint,
+ lo->ll_pos_first_inconsistent);
+ if (rc <= 0)
+ goto out;
+
+ buf += rc;
+ len -= rc;
+
+ rc = snprintf(buf, len,
+ "success_count: %u\n"
+ "repaired_dangling: "LPU64"\n"
+ "repaired_unmatched_pair: "LPU64"\n"
+ "repaired_multiple_referenced: "LPU64"\n"
+ "repaired_orphan: "LPU64"\n"
+ "repaired_inconsistent_owner: "LPU64"\n"
+ "repaired_others: "LPU64"\n"
+ "skipped: "LPU64"\n"
+ "failed_phase1: "LPU64"\n"
+ "failed_phase2: "LPU64"\n",
+ lo->ll_success_count,
+ lo->ll_objs_repaired[LLIT_DANGLING - 1],
+ lo->ll_objs_repaired[LLIT_UNMATCHED_PAIR - 1],
+ lo->ll_objs_repaired[LLIT_MULTIPLE_REFERENCED - 1],
+ lo->ll_objs_repaired[LLIT_ORPHAN - 1],
+ lo->ll_objs_repaired[LLIT_INCONSISTENT_OWNER - 1],
+ lo->ll_objs_repaired[LLIT_OTHERS - 1],
+ lo->ll_objs_skipped,
+ lo->ll_objs_failed_phase1,
+ lo->ll_objs_failed_phase2);
+ if (rc <= 0)
+ goto out;
+
+ buf += rc;
+ len -= rc;
+
+ if (lo->ll_status == LS_SCANNING_PHASE1) {
+ __u64 pos;
+ const struct dt_it_ops *iops;
+ cfs_duration_t duration = cfs_time_current() -
+ 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 * HZ;
+ __u32 rtime = lo->ll_run_time_phase1 +
+ cfs_duration_sec(duration + HALF_SEC);
+
+ if (duration != 0)
+ do_div(new_checked, duration);
+ if (rtime != 0)
+ do_div(speed, rtime);
+ rc = snprintf(buf, len,
+ "checked_phase1: "LPU64"\n"
+ "checked_phase2: "LPU64"\n"
+ "run_time_phase1: %u seconds\n"
+ "run_time_phase2: %u seconds\n"
+ "average_speed_phase1: "LPU64" items/sec\n"
+ "average_speed_phase2: N/A\n"
+ "real-time_speed_phase1: "LPU64" 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 (rc <= 0)
+ goto out;
+
+ buf += rc;
+ len -= rc;
+
+ LASSERT(lfsck->li_di_oit != NULL);
+
+ 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--;
+ rc = snprintf(buf, len, "current_position: "LPU64"\n", pos);
+ if (rc <= 0)
+ goto out;
+
+ buf += rc;
+ len -= rc;
+ } else {
+ /* XXX: LS_SCANNING_PHASE2 will be handled in the future. */
+ __u64 speed1 = lo->ll_objs_checked_phase1;
+ __u64 speed2 = lo->ll_objs_checked_phase2;
+
+ if (lo->ll_run_time_phase1 != 0)
+ do_div(speed1, lo->ll_run_time_phase1);
+ if (lo->ll_run_time_phase2 != 0)
+ do_div(speed2, lo->ll_run_time_phase2);
+ rc = snprintf(buf, len,
+ "checked_phase1: "LPU64"\n"
+ "checked_phase2: "LPU64"\n"
+ "run_time_phase1: %u seconds\n"
+ "run_time_phase2: %u seconds\n"
+ "average_speed_phase1: "LPU64" items/sec\n"
+ "average_speed_phase2: "LPU64" 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);
+ if (rc <= 0)
+ goto out;
+
+ buf += rc;
+ len -= rc;
+ }
+ ret = save - len;
+
+out:
+ up_read(&com->lc_sem);
+
+ return ret;
}
static int lfsck_layout_master_double_scan(const struct lu_env *env,
static int lfsck_layout_slave_double_scan(const struct lu_env *env,
struct lfsck_component *com)
{
- return 0;
+ struct lfsck_instance *lfsck = com->lc_lfsck;
+ struct lfsck_bookmark *bk = &lfsck->li_bookmark_ram;
+ struct lfsck_layout *lo = com->lc_file_ram;
+ int rc = 1;
+
+ down_write(&com->lc_sem);
+
+ lo->ll_run_time_phase2 += cfs_duration_sec(cfs_time_current() +
+ HALF_SEC - lfsck->li_time_last_checkpoint);
+ lo->ll_time_last_checkpoint = cfs_time_current_sec();
+ lo->ll_objs_checked_phase2 += com->lc_new_checked;
+
+ com->lc_new_checked = 0;
+ com->lc_new_scanned = 0;
+ com->lc_time_last_checkpoint = cfs_time_current();
+ com->lc_time_next_checkpoint = com->lc_time_last_checkpoint +
+ cfs_time_seconds(LFSCK_CHECKPOINT_INTERVAL);
+
+ if (rc > 0) {
+ com->lc_journal = 0;
+ if (lo->ll_flags & LF_INCOMPLETE)
+ lo->ll_status = LS_PARTIAL;
+ else
+ lo->ll_status = LS_COMPLETED;
+ if (!(bk->lb_param & LPF_DRYRUN))
+ lo->ll_flags &= ~(LF_SCANNED_ONCE | LF_INCONSISTENT);
+ lo->ll_time_last_complete = lo->ll_time_last_checkpoint;
+ lo->ll_success_count++;
+ } else if (rc == 0) {
+ if (lfsck->li_paused)
+ lo->ll_status = LS_PAUSED;
+ else
+ lo->ll_status = LS_STOPPED;
+ } else {
+ lo->ll_status = LS_FAILED;
+ }
+
+ if (lo->ll_status != LS_PAUSED) {
+ spin_lock(&lfsck->li_lock);
+ list_del_init(&com->lc_link);
+ list_add_tail(&com->lc_link, &lfsck->li_list_idle);
+ spin_unlock(&lfsck->li_lock);
+ }
+
+ rc = lfsck_layout_store(env, com);
+
+ up_write(&com->lc_sem);
+
+ return rc;
+}
+
+static void lfsck_layout_master_data_release(const struct lu_env *env,
+ struct lfsck_component *com)
+{
+}
+
+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;
+ struct lfsck_layout_seq *lls;
+ struct lfsck_layout_seq *next;
+
+ LASSERT(llsd != NULL);
+
+ com->lc_data = NULL;
+
+ 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);
+ }
+
+ OBD_FREE_PTR(llsd);
}
static struct lfsck_operations lfsck_layout_master_ops = {
.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,
};
static struct lfsck_operations lfsck_layout_slave_ops = {
.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,
};
int lfsck_layout_setup(const struct lu_env *env, struct lfsck_instance *lfsck)
atomic_set(&com->lc_ref, 1);
com->lc_lfsck = lfsck;
com->lc_type = LT_LAYOUT;
- if (lfsck->li_master)
+ if (lfsck->li_master) {
com->lc_ops = &lfsck_layout_master_ops;
- else
+ } 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);
+ 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)
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: