+ rc = kstrtoul(buffer, 0, &val);
+ if (rc)
+ return rc;
+
+ /* XXX may need to limit/check with reasonable elapsed/idle indexes */
+ /* XXX may better allow to specify a % of full ChangeLogs */
+
+ mdd->mdd_changelog_max_idle_indexes = val;
+
+ return count;
+}
+LUSTRE_RW_ATTR(changelog_max_idle_indexes);
+
+static ssize_t changelog_min_gc_interval_show(struct kobject *kobj,
+ struct attribute *attr,
+ char *buf)
+{
+ struct mdd_device *mdd = container_of(kobj, struct mdd_device,
+ mdd_kobj);
+
+ return sprintf(buf, "%lld\n", mdd->mdd_changelog_min_gc_interval);
+}
+
+static ssize_t changelog_min_gc_interval_store(struct kobject *kobj,
+ struct attribute *attr,
+ const char *buffer,
+ size_t count)
+{
+ struct mdd_device *mdd = container_of(kobj, struct mdd_device,
+ mdd_kobj);
+ time64_t val;
+ int rc;
+
+ rc = kstrtoll(buffer, 10, &val);
+ if (rc)
+ return rc;
+
+ /* XXX may need to limit with reasonable elapsed/interval times */
+ if (val < 1)
+ return -ERANGE;
+
+ mdd->mdd_changelog_min_gc_interval = val;
+
+ return count;
+}
+LUSTRE_RW_ATTR(changelog_min_gc_interval);
+
+static ssize_t changelog_min_free_cat_entries_show(struct kobject *kobj,
+ struct attribute *attr,
+ char *buf)
+{
+ struct mdd_device *mdd = container_of(kobj, struct mdd_device,
+ mdd_kobj);
+
+ return sprintf(buf, "%u\n", mdd->mdd_changelog_min_free_cat_entries);
+}
+
+static ssize_t changelog_min_free_cat_entries_store(struct kobject *kobj,
+ struct attribute *attr,
+ const char *buffer,
+ size_t count)
+{
+ struct mdd_device *mdd = container_of(kobj, struct mdd_device,
+ mdd_kobj);
+ unsigned int val;
+ int rc;
+
+ rc = kstrtouint(buffer, 10, &val);
+ if (rc)
+ return rc;
+
+ /* XXX may need to limit with more reasonable number of free entries */
+ if (val < 1)
+ return -ERANGE;
+
+ mdd->mdd_changelog_min_free_cat_entries = val;
+
+ return count;
+}
+LUSTRE_RW_ATTR(changelog_min_free_cat_entries);
+
+static ssize_t changelog_deniednext_show(struct kobject *kobj,
+ struct attribute *attr,
+ char *buf)
+{
+ struct mdd_device *mdd = container_of(kobj, struct mdd_device,
+ mdd_kobj);
+
+ return sprintf(buf, "%u\n", mdd->mdd_cl.mc_deniednext);
+}
+
+static ssize_t changelog_deniednext_store(struct kobject *kobj,
+ struct attribute *attr,
+ const char *buffer,
+ size_t count)
+{
+ struct mdd_device *mdd = container_of(kobj, struct mdd_device,
+ mdd_kobj);
+ unsigned int time = 0;
+ int rc;
+
+ rc = kstrtouint(buffer, 0, &time);
+ if (rc)
+ return rc;
+
+ mdd->mdd_cl.mc_deniednext = time;
+ return count;
+}
+LUSTRE_RW_ATTR(changelog_deniednext);
+
+static ssize_t sync_permission_show(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ struct mdd_device *mdd = container_of(kobj, struct mdd_device,
+ mdd_kobj);
+
+ return sprintf(buf, "%d\n", mdd->mdd_sync_permission);
+}
+
+static ssize_t sync_permission_store(struct kobject *kobj,
+ struct attribute *attr,
+ const char *buffer, size_t count)
+{
+ struct mdd_device *mdd = container_of(kobj, struct mdd_device,
+ mdd_kobj);
+ bool val;
+ int rc;
+
+ rc = kstrtobool(buffer, &val);
+ if (rc)
+ return rc;
+
+ mdd->mdd_sync_permission = val;
+
+ return count;
+}
+LUSTRE_RW_ATTR(sync_permission);
+
+static ssize_t lfsck_speed_limit_show(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ struct mdd_device *mdd = container_of(kobj, struct mdd_device,
+ mdd_kobj);
+
+ return lfsck_get_speed(buf, mdd->mdd_bottom);
+}
+
+static ssize_t lfsck_speed_limit_store(struct kobject *kobj,
+ struct attribute *attr,
+ const char *buffer, size_t count)
+{
+ struct mdd_device *mdd = container_of(kobj, struct mdd_device,
+ mdd_kobj);
+ unsigned int val;
+ int rc;
+
+ rc = kstrtouint(buffer, 10, &val);