static inline struct dt_device *scrub_obj2dev(struct dt_object *obj)
{
- return container_of0(obj->do_lu.lo_dev, struct dt_device, dd_lu_dev);
+ return container_of_safe(obj->do_lu.lo_dev, struct dt_device,
+ dd_lu_dev);
}
static void scrub_file_to_cpu(struct scrub_file *des, struct scrub_file *src)
{
- uuid_copy(&des->sf_uuid, &src->sf_uuid);
+ guid_copy(&des->sf_uuid, &src->sf_uuid);
des->sf_flags = le64_to_cpu(src->sf_flags);
des->sf_magic = le32_to_cpu(src->sf_magic);
des->sf_status = le16_to_cpu(src->sf_status);
static void scrub_file_to_le(struct scrub_file *des, struct scrub_file *src)
{
- uuid_copy(&des->sf_uuid, &src->sf_uuid);
+ guid_copy(&des->sf_uuid, &src->sf_uuid);
des->sf_flags = cpu_to_le64(src->sf_flags);
des->sf_magic = cpu_to_le32(src->sf_magic);
des->sf_status = cpu_to_le16(src->sf_status);
memcpy(des->sf_oi_bitmap, src->sf_oi_bitmap, SCRUB_OI_BITMAP_SIZE);
}
-void scrub_file_init(struct lustre_scrub *scrub, uuid_t uuid)
+void scrub_file_init(struct lustre_scrub *scrub, guid_t uuid)
{
struct scrub_file *sf = &scrub->os_file;
memset(sf, 0, sizeof(*sf));
- uuid_copy(&sf->sf_uuid, &uuid);
- sf->sf_magic = SCRUB_MAGIC_V1;
+ guid_copy(&sf->sf_uuid, &uuid);
+ sf->sf_magic = SCRUB_MAGIC_V2;
sf->sf_status = SS_INIT;
}
EXPORT_SYMBOL(scrub_file_init);
-void scrub_file_reset(struct lustre_scrub *scrub, uuid_t uuid, u64 flags)
+void scrub_file_reset(struct lustre_scrub *scrub, guid_t uuid, u64 flags)
{
struct scrub_file *sf = &scrub->os_file;
+ ENTRY;
CDEBUG(D_LFSCK, "%s: reset OI scrub file, old flags = "
"%#llx, add flags = %#llx\n",
scrub->os_name, sf->sf_flags, flags);
- uuid_copy(&sf->sf_uuid, &uuid);
+ guid_copy(&sf->sf_uuid, &uuid);
+ sf->sf_magic = SCRUB_MAGIC_V2;
sf->sf_status = SS_INIT;
sf->sf_flags |= flags;
sf->sf_flags &= ~SF_AUTO;
sf->sf_items_igif = 0;
if (!scrub->os_in_join)
sf->sf_items_updated_prior = 0;
+ EXIT;
}
EXPORT_SYMBOL(scrub_file_reset);
}
scrub_file_to_cpu(sf, &scrub->os_file_disk);
- if (sf->sf_magic != SCRUB_MAGIC_V1) {
- CDEBUG(D_LFSCK, "%s: invalid scrub magic 0x%x != 0x%x\n",
- scrub->os_name, sf->sf_magic, SCRUB_MAGIC_V1);
+ if (sf->sf_magic == SCRUB_MAGIC_V1) {
+ CWARN("%s: reset scrub OI count for format change (LU-16655)\n",
+ scrub->os_name);
+ sf->sf_oi_count = 0;
+ } else if (sf->sf_magic != SCRUB_MAGIC_V2) {
+ CDEBUG(D_LFSCK, "%s: invalid scrub magic %#x, should be %#x\n",
+ scrub->os_name, sf->sf_magic, SCRUB_MAGIC_V2);
return -EFAULT;
}
}
EXPORT_SYMBOL(scrub_file_store);
+bool scrub_needs_check(struct lustre_scrub *scrub, const struct lu_fid *fid,
+ u64 index)
+{
+ bool check = true;
+
+ if (!fid_is_norm(fid) && !fid_is_igif(fid))
+ check = false;
+ else if (scrub->os_running && scrub->os_pos_current > index)
+ check = false;
+ else if (scrub->os_auto_scrub_interval == AS_NEVER)
+ check = false;
+ else if (ktime_get_real_seconds() <
+ scrub->os_file.sf_time_last_complete +
+ scrub->os_auto_scrub_interval)
+ check = false;
+
+ return check;
+}
+EXPORT_SYMBOL(scrub_needs_check);
+
int scrub_checkpoint(const struct lu_env *env, struct lustre_scrub *scrub)
{
struct scrub_file *sf = &scrub->os_file;
}
EXPORT_SYMBOL(scrub_checkpoint);
-int scrub_start(int (*threadfn)(void *data), struct lustre_scrub *scrub,
- void *data, __u32 flags)
+int scrub_thread_prep(const struct lu_env *env, struct lustre_scrub *scrub,
+ guid_t uuid, u64 start)
{
- struct ptlrpc_thread *thread = &scrub->os_thread;
- struct task_struct *task;
+ struct scrub_file *sf = &scrub->os_file;
+ u32 flags = scrub->os_start_flags;
+ bool drop_dryrun = false;
int rc;
+
ENTRY;
+ CDEBUG(D_LFSCK, "%s: OI scrub prep, flags = 0x%x\n",
+ scrub->os_name, flags);
+
+ down_write(&scrub->os_rwsem);
+ if (flags & SS_SET_FAILOUT)
+ sf->sf_param |= SP_FAILOUT;
+ else if (flags & SS_CLEAR_FAILOUT)
+ sf->sf_param &= ~SP_FAILOUT;
+
+ if (flags & SS_SET_DRYRUN) {
+ sf->sf_param |= SP_DRYRUN;
+ } else if (flags & SS_CLEAR_DRYRUN && sf->sf_param & SP_DRYRUN) {
+ sf->sf_param &= ~SP_DRYRUN;
+ drop_dryrun = true;
+ }
+
+ if (flags & SS_RESET)
+ scrub_file_reset(scrub, uuid, 0);
-again:
- /* os_lock: sync status between stop and scrub thread */
spin_lock(&scrub->os_lock);
- if (thread_is_running(thread)) {
- spin_unlock(&scrub->os_lock);
- RETURN(-EALREADY);
+ scrub->os_partial_scan = 0;
+ if (flags & SS_AUTO_FULL) {
+ scrub->os_full_speed = 1;
+ sf->sf_flags |= SF_AUTO;
+ } else if (flags & SS_AUTO_PARTIAL) {
+ scrub->os_full_speed = 0;
+ scrub->os_partial_scan = 1;
+ sf->sf_flags |= SF_AUTO;
+ } else if (sf->sf_flags & (SF_RECREATED | SF_INCONSISTENT |
+ SF_UPGRADE)) {
+ scrub->os_full_speed = 1;
+ } else {
+ scrub->os_full_speed = 0;
}
- if (unlikely(thread_is_stopping(thread))) {
+ scrub->os_in_prior = 0;
+ scrub->os_waiting = 0;
+ scrub->os_paused = 0;
+ scrub->os_in_join = 0;
+ scrub->os_full_scrub = 0;
+ spin_unlock(&scrub->os_lock);
+ scrub->os_new_checked = 0;
+ if (drop_dryrun && sf->sf_pos_first_inconsistent != 0)
+ sf->sf_pos_latest_start = sf->sf_pos_first_inconsistent;
+ else if (sf->sf_pos_last_checkpoint != 0)
+ sf->sf_pos_latest_start = sf->sf_pos_last_checkpoint + 1;
+ else
+ sf->sf_pos_latest_start = start;
+
+ scrub->os_pos_current = sf->sf_pos_latest_start;
+ sf->sf_status = SS_SCANNING;
+ sf->sf_time_latest_start = ktime_get_real_seconds();
+ sf->sf_time_last_checkpoint = sf->sf_time_latest_start;
+ sf->sf_pos_last_checkpoint = sf->sf_pos_latest_start - 1;
+ rc = scrub_file_store(env, scrub);
+ if (rc == 0) {
+ spin_lock(&scrub->os_lock);
+ scrub->os_running = 1;
spin_unlock(&scrub->os_lock);
- wait_event_idle(thread->t_ctl_waitq,
- thread_is_stopped(thread));
- goto again;
+ wake_up_var(scrub);
}
+ up_write(&scrub->os_rwsem);
+
+ RETURN(rc);
+}
+EXPORT_SYMBOL(scrub_thread_prep);
+
+int scrub_thread_post(const struct lu_env *env, struct lustre_scrub *scrub,
+ int result)
+{
+ struct scrub_file *sf = &scrub->os_file;
+ int rc;
+ ENTRY;
+
+ CDEBUG(D_LFSCK, "%s: OI scrub post with result = %d\n",
+ scrub->os_name, result);
+
+ down_write(&scrub->os_rwsem);
+ spin_lock(&scrub->os_lock);
+ scrub->os_running = 0;
spin_unlock(&scrub->os_lock);
+ if (scrub->os_new_checked > 0) {
+ sf->sf_items_checked += scrub->os_new_checked;
+ scrub->os_new_checked = 0;
+ sf->sf_pos_last_checkpoint = scrub->os_pos_current;
+ }
+ sf->sf_time_last_checkpoint = ktime_get_real_seconds();
+ if (result > 0) {
+ sf->sf_status = SS_COMPLETED;
+ if (!(sf->sf_param & SP_DRYRUN)) {
+ memset(sf->sf_oi_bitmap, 0, SCRUB_OI_BITMAP_SIZE);
+ sf->sf_flags &= ~(SF_RECREATED | SF_INCONSISTENT |
+ SF_UPGRADE | SF_AUTO);
+ }
+ sf->sf_time_last_complete = sf->sf_time_last_checkpoint;
+ sf->sf_success_count++;
+ } else if (result == 0) {
+ if (scrub->os_paused)
+ sf->sf_status = SS_PAUSED;
+ else
+ sf->sf_status = SS_STOPPED;
+ } else {
+ sf->sf_status = SS_FAILED;
+ }
+ sf->sf_run_time += ktime_get_seconds() -
+ scrub->os_time_last_checkpoint;
+
+ rc = scrub_file_store(env, scrub);
+ up_write(&scrub->os_rwsem);
+
+ RETURN(rc < 0 ? rc : result);
+}
+EXPORT_SYMBOL(scrub_thread_post);
+
+int scrub_start(int (*threadfn)(void *data), struct lustre_scrub *scrub,
+ void *data, __u32 flags)
+{
+ struct task_struct *task;
+ int rc;
+ ENTRY;
+
+ if (scrub->os_task)
+ RETURN(-EALREADY);
if (scrub->os_file.sf_status == SS_COMPLETED) {
if (!(flags & SS_SET_FAILOUT))
flags |= SS_RESET;
}
- scrub->os_start_flags = flags;
- thread_set_flags(thread, 0);
- task = kthread_run(threadfn, data, "OI_scrub");
+ task = kthread_create(threadfn, data, "OI_scrub");
if (IS_ERR(task)) {
rc = PTR_ERR(task);
CERROR("%s: cannot start iteration thread: rc = %d\n",
scrub->os_name, rc);
RETURN(rc);
}
-
- wait_event_idle(thread->t_ctl_waitq,
- thread_is_running(thread) || thread_is_stopped(thread));
+ spin_lock(&scrub->os_lock);
+ if (scrub->os_task) {
+ /* Lost a race */
+ spin_unlock(&scrub->os_lock);
+ kthread_stop(task);
+ RETURN(-EALREADY);
+ }
+ scrub->os_start_flags = flags;
+ scrub->os_task = task;
+ wake_up_process(task);
+ spin_unlock(&scrub->os_lock);
+ wait_var_event(scrub, scrub->os_running || !scrub->os_task);
RETURN(0);
}
void scrub_stop(struct lustre_scrub *scrub)
{
- struct ptlrpc_thread *thread = &scrub->os_thread;
+ struct task_struct *task;
- /* os_lock: sync status between stop and scrub thread */
spin_lock(&scrub->os_lock);
- if (!thread_is_init(thread) && !thread_is_stopped(thread)) {
- thread_set_flags(thread, SVC_STOPPING);
- spin_unlock(&scrub->os_lock);
- wake_up_all(&thread->t_ctl_waitq);
- wait_event_idle(thread->t_ctl_waitq,
- thread_is_stopped(thread));
- /* Do not skip the last lock/unlock, which can guarantee that
- * the caller cannot return until the OI scrub thread exit. */
- spin_lock(&scrub->os_lock);
- }
+ scrub->os_running = 0;
spin_unlock(&scrub->os_lock);
+ task = xchg(&scrub->os_task, NULL);
+ if (task)
+ kthread_stop(task);
}
EXPORT_SYMBOL(scrub_stop);
-const char *scrub_status_names[] = {
+const char *const scrub_status_names[] = {
"init",
"scanning",
"completed",
NULL
};
-const char *scrub_flags_names[] = {
+const char *const scrub_flags_names[] = {
"recreated",
"inconsistent",
"auto",
NULL
};
-const char *scrub_param_names[] = {
+const char *const scrub_param_names[] = {
"failout",
"dryrun",
NULL
};
-static void scrub_bits_dump(struct seq_file *m, int bits, const char *names[],
+static void scrub_bits_dump(struct seq_file *m, int bits,
+ const char *const names[],
const char *prefix)
{
int flag;
seq_printf(m, "%s:%c", prefix, bits != 0 ? ' ' : '\n');
- for (i = 0, flag = 1; bits != 0; i++, flag = 1 << i) {
+ for (i = 0, flag = 1; bits != 0; i++, flag = BIT(i)) {
if (flag & bits) {
bits &= ~flag;
seq_printf(m, "%s%c", names[i],
sf->sf_items_igif, sf->sf_success_count);
speed = checked;
- if (thread_is_running(&scrub->os_thread)) {
+ if (scrub->os_running) {
s64 new_checked = scrub->os_new_checked;
time64_t duration;
time64_t rtime;
seq_printf(m, "run_time: %lld seconds\n"
"average_speed: %lld objects/sec\n"
- "real-time_speed: %lld objects/sec\n"
+ "real_time_speed: %lld objects/sec\n"
"current_position: %llu\n"
"scrub_in_prior: %s\n"
"scrub_full_speed: %s\n"
} else {
if (sf->sf_run_time != 0)
speed = div_s64(speed, sf->sf_run_time);
- seq_printf(m, "run_time: %ld seconds\n"
+ seq_printf(m, "run_time: %d seconds\n"
"average_speed: %lld objects/sec\n"
- "real-time_speed: N/A\n"
+ "real_time_speed: N/A\n"
"current_position: N/A\n",
sf->sf_run_time, speed);
}
if (!rc)
rc = lustre_index_update_lma(env, tgt_obj, buf, bufsize);
- if (!rc && OBD_FAIL_CHECK(OBD_FAIL_OSD_INDEX_CRASH)) {
+ if (!rc && CFS_FAIL_CHECK(OBD_FAIL_OSD_INDEX_CRASH)) {
LASSERT(bufsize >= 512);
pos = 0;
scan:
spin_lock(lock);
while (!list_empty(head)) {
- libu = list_entry(head->next,
- struct lustre_index_backup_unit, libu_link);
+ libu = list_first_entry(head,
+ struct lustre_index_backup_unit,
+ libu_link);
list_del_init(&libu->libu_link);
spin_unlock(lock);
LASSERT(dt_object_exists(parent_obj));
- if (unlikely(!dt_try_as_dir(env, parent_obj)))
+ if (unlikely(!dt_try_as_dir(env, parent_obj, true)))
GOTO(out, rc = -ENOTDIR);
rc = dt_attr_get(env, tgt_obj, la);
if (rc)
GOTO(stop, rc);
+ rc = dt_declare_ref_del(env, tgt_obj, th);
+ if (rc)
+ GOTO(stop, rc);
+
rc = dt_declare_destroy(env, tgt_obj, th);
if (rc)
GOTO(stop, rc);
GOTO(stop, rc);
dt_write_lock(env, tgt_obj, 0);
- rc = dt_destroy(env, tgt_obj, th);
+ rc = dt_ref_del(env, tgt_obj, th);
+ if (rc == 0) {
+ if (S_ISDIR(tgt_obj->do_lu.lo_header->loh_attr))
+ dt_ref_del(env, tgt_obj, th);
+ rc = dt_destroy(env, tgt_obj, th);
+ }
dt_write_unlock(env, tgt_obj);
dt_trans_stop(env, dev, th);
if (rc)