Whamcloud - gitweb
LU-14927 scrub: share osd_scrub[prep|post] code
[fs/lustre-release.git] / lustre / obdclass / scrub.c
index 24cb640..94a334d 100644 (file)
@@ -41,7 +41,8 @@
 
 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)
@@ -271,29 +272,138 @@ int scrub_checkpoint(const struct lu_env *env, struct lustre_scrub *scrub)
 }
 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,
+                     uuid_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))
@@ -305,18 +415,25 @@ again:
                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);
 }
@@ -324,25 +441,18 @@ EXPORT_SYMBOL(scrub_start);
 
 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",
@@ -353,7 +463,7 @@ const char *scrub_status_names[] = {
        NULL
 };
 
-const char *scrub_flags_names[] = {
+const char *const scrub_flags_names[] = {
        "recreated",
        "inconsistent",
        "auto",
@@ -361,13 +471,14 @@ const char *scrub_flags_names[] = {
        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;
@@ -375,7 +486,7 @@ static void scrub_bits_dump(struct seq_file *m, int bits, const char *names[],
 
        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],
@@ -454,7 +565,7 @@ void scrub_dump(struct seq_file *m, struct lustre_scrub *scrub)
                   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;
@@ -1075,6 +1186,10 @@ int lustre_index_restore(const struct lu_env *env, struct dt_device *dev,
        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);
@@ -1088,7 +1203,12 @@ int lustre_index_restore(const struct lu_env *env, struct dt_device *dev,
                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)