+/* lfsck_bookmark file ops */
+
+static void inline mdd_lfsck_bookmark_to_cpu(struct lfsck_bookmark *des,
+ struct lfsck_bookmark *src)
+{
+ des->lb_magic = le32_to_cpu(src->lb_magic);
+ des->lb_version = le16_to_cpu(src->lb_version);
+ des->lb_param = le16_to_cpu(src->lb_param);
+ des->lb_speed_limit = le32_to_cpu(src->lb_speed_limit);
+}
+
+static void inline mdd_lfsck_bookmark_to_le(struct lfsck_bookmark *des,
+ struct lfsck_bookmark *src)
+{
+ des->lb_magic = cpu_to_le32(src->lb_magic);
+ des->lb_version = cpu_to_le16(src->lb_version);
+ des->lb_param = cpu_to_le16(src->lb_param);
+ des->lb_speed_limit = cpu_to_le32(src->lb_speed_limit);
+}
+
+static int mdd_lfsck_bookmark_load(const struct lu_env *env,
+ struct md_lfsck *lfsck)
+{
+ loff_t pos = 0;
+ int len = sizeof(struct lfsck_bookmark);
+ int rc;
+
+ rc = dt_record_read(env, lfsck->ml_bookmark_obj,
+ mdd_buf_get(env, &lfsck->ml_bookmark_disk, len),
+ &pos);
+ if (rc == 0) {
+ struct lfsck_bookmark *bm = &lfsck->ml_bookmark_ram;
+
+ mdd_lfsck_bookmark_to_cpu(bm, &lfsck->ml_bookmark_disk);
+ if (bm->lb_magic != LFSCK_BOOKMARK_MAGIC) {
+ CWARN("%.16s: invalid lfsck_bookmark magic "
+ "0x%x != 0x%x\n", mdd_lfsck2name(lfsck),
+ bm->lb_magic, LFSCK_BOOKMARK_MAGIC);
+ /* Process it as new lfsck_bookmark. */
+ rc = -ENODATA;
+ }
+ } else {
+ if (rc == -EFAULT && pos == 0)
+ /* return -ENODATA for empty lfsck_bookmark. */
+ rc = -ENODATA;
+ else
+ CERROR("%.16s: fail to load lfsck_bookmark, "
+ "expected = %d, rc = %d\n",
+ mdd_lfsck2name(lfsck), len, rc);
+ }
+ return rc;
+}
+
+static int mdd_lfsck_bookmark_store(const struct lu_env *env,
+ struct md_lfsck *lfsck)
+{
+ struct mdd_device *mdd = mdd_lfsck2mdd(lfsck);
+ struct thandle *handle;
+ struct dt_object *obj = lfsck->ml_bookmark_obj;
+ loff_t pos = 0;
+ int len = sizeof(struct lfsck_bookmark);
+ int rc;
+ ENTRY;
+
+ mdd_lfsck_bookmark_to_le(&lfsck->ml_bookmark_disk,
+ &lfsck->ml_bookmark_ram);
+ handle = dt_trans_create(env, mdd->mdd_bottom);
+ if (IS_ERR(handle)) {
+ rc = PTR_ERR(handle);
+ CERROR("%.16s: fail to create trans for storing "
+ "lfsck_bookmark: %d\n,", mdd_lfsck2name(lfsck), rc);
+ RETURN(rc);
+ }
+
+ rc = dt_declare_record_write(env, obj, len, 0, handle);
+ if (rc != 0) {
+ CERROR("%.16s: fail to declare trans for storing "
+ "lfsck_bookmark: %d\n,", mdd_lfsck2name(lfsck), rc);
+ GOTO(out, rc);
+ }
+
+ rc = dt_trans_start_local(env, mdd->mdd_bottom, handle);
+ if (rc != 0) {
+ CERROR("%.16s: fail to start trans for storing "
+ "lfsck_bookmark: %d\n,", mdd_lfsck2name(lfsck), rc);
+ GOTO(out, rc);
+ }
+
+ rc = dt_record_write(env, obj,
+ mdd_buf_get(env, &lfsck->ml_bookmark_disk, len),
+ &pos, handle);
+ if (rc != 0)
+ CERROR("%.16s: fail to store lfsck_bookmark, expected = %d, "
+ "rc = %d\n", mdd_lfsck2name(lfsck), len, rc);
+
+ GOTO(out, rc);
+
+out:
+ dt_trans_stop(env, mdd->mdd_bottom, handle);
+ return rc;
+}
+
+static int mdd_lfsck_bookmark_init(const struct lu_env *env,
+ struct md_lfsck *lfsck)
+{
+ struct lfsck_bookmark *mb = &lfsck->ml_bookmark_ram;
+ int rc;
+
+ memset(mb, 0, sizeof(mb));
+ mb->lb_magic = LFSCK_BOOKMARK_MAGIC;
+ mb->lb_version = LFSCK_VERSION_V1;
+ mutex_lock(&lfsck->ml_mutex);
+ rc = mdd_lfsck_bookmark_store(env, lfsck);
+ mutex_unlock(&lfsck->ml_mutex);
+ return rc;
+}
+
+/* LFSCK engines */
+