+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;
+}
+