};
struct lfsck_layout_master_data {
- struct list_head llmd_req_list;
spinlock_t llmd_lock;
+ struct list_head llmd_req_list;
+
+ /* list for the ost targets involve layout verification. */
+ struct list_head llmd_ost_list;
+
+ /* list for the ost targets in phase1 scanning. */
+ struct list_head llmd_ost_phase1_list;
+
+ /* list for the ost targets in phase1 scanning. */
+ struct list_head llmd_ost_phase2_list;
+
struct ptlrpc_thread llmd_thread;
atomic_t llmd_rpcs_in_flight;
+ __u32 llmd_touch_gen;
int llmd_prefetched;
int llmd_assistant_status;
int llmd_post_result;
return rc;
}
+static int lfsck_layout_master_async_interpret(const struct lu_env *env,
+ struct ptlrpc_request *req,
+ void *args, int rc)
+{
+ struct lfsck_async_interpret_args *laia = args;
+ struct lfsck_component *com = laia->laia_com;
+ struct lfsck_layout_master_data *llmd = com->lc_data;
+ struct lfsck_tgt_descs *ltds = laia->laia_ltds;
+ struct lfsck_tgt_desc *ltd = laia->laia_ltd;
+ struct lfsck_request *lr = laia->laia_lr;
+
+ switch (lr->lr_event) {
+ case LE_START:
+ if (rc == 0) {
+ LASSERT(!list_empty(<d->ltd_layout_list));
+
+ spin_lock(<ds->ltd_lock);
+ if (!ltd->ltd_dead) {
+ list_add_tail(<d->ltd_layout_list,
+ &llmd->llmd_ost_list);
+ list_add_tail(<d->ltd_layout_phase_list,
+ &llmd->llmd_ost_phase1_list);
+ }
+ spin_unlock(<ds->ltd_lock);
+ } else {
+ struct lfsck_layout *lo = com->lc_file_ram;
+
+ lo->ll_flags |= LF_INCOMPLETE;
+ }
+ lfsck_tgt_put(ltd);
+ break;
+ case LE_STOP:
+ case LE_PHASE2_DONE:
+ break;
+ case LE_QUERY:
+ spin_lock(<ds->ltd_lock);
+ if (rc == 0 && !ltd->ltd_dead) {
+ struct lfsck_reply *reply;
+
+ reply = req_capsule_server_get(&req->rq_pill,
+ &RMF_LFSCK_REPLY);
+ switch (reply->lr_status) {
+ case LS_SCANNING_PHASE1:
+ break;
+ case LS_SCANNING_PHASE2:
+ list_del(<d->ltd_layout_phase_list);
+ list_add_tail(<d->ltd_layout_phase_list,
+ &llmd->llmd_ost_phase2_list);
+ break;
+ default:
+ list_del_init(<d->ltd_layout_phase_list);
+ list_del_init(<d->ltd_layout_list);
+ break;
+ }
+ }
+ spin_unlock(<ds->ltd_lock);
+ lfsck_tgt_put(ltd);
+ break;
+ default:
+ CERROR("%s: unexpected event: rc = %d\n",
+ lfsck_lfsck2name(com->lc_lfsck), lr->lr_event);
+ break;
+ }
+
+ return 0;
+}
+
static int lfsck_layout_master_query_others(const struct lu_env *env,
struct lfsck_component *com)
{
- /* XXX: to be implemented. */
+ struct lfsck_thread_info *info = lfsck_env_info(env);
+ struct lfsck_request *lr = &info->lti_lr;
+ struct lfsck_async_interpret_args *laia = &info->lti_laia;
+ struct lfsck_instance *lfsck = com->lc_lfsck;
+ struct lfsck_layout_master_data *llmd = com->lc_data;
+ struct ptlrpc_request_set *set;
+ struct lfsck_tgt_descs *ltds;
+ struct lfsck_tgt_desc *ltd;
+ __u32 cnt = 0;
+ int rc = 0;
+ int rc1 = 0;
+ ENTRY;
- return 0;
+ set = ptlrpc_prep_set();
+ if (set == NULL)
+ RETURN(-ENOMEM);
+
+ llmd->llmd_touch_gen++;
+ ltds = &lfsck->li_ost_descs;
+ memset(lr, 0, sizeof(*lr));
+ lr->lr_index = lfsck_dev_idx(lfsck->li_bottom);
+ lr->lr_event = LE_QUERY;
+ lr->lr_active = LT_LAYOUT;
+
+ laia->laia_com = com;
+ laia->laia_ltds = ltds;
+ laia->laia_lr = lr;
+ spin_lock(<ds->ltd_lock);
+ while (!list_empty(&llmd->llmd_ost_phase1_list)) {
+ ltd = list_entry(llmd->llmd_ost_phase1_list.next,
+ struct lfsck_tgt_desc,
+ ltd_layout_phase_list);
+ if (ltd->ltd_layout_gen == llmd->llmd_touch_gen)
+ break;
+
+ ltd->ltd_layout_gen = llmd->llmd_touch_gen;
+ list_del(<d->ltd_layout_phase_list);
+ list_add_tail(<d->ltd_layout_phase_list,
+ &llmd->llmd_ost_phase1_list);
+ atomic_inc(<d->ltd_ref);
+ laia->laia_ltd = ltd;
+ spin_unlock(<ds->ltd_lock);
+ rc = lfsck_async_request(env, ltd->ltd_exp, lr, set,
+ lfsck_layout_master_async_interpret,
+ laia, LFSCK_QUERY);
+ if (rc != 0) {
+ CERROR("%s: fail to query OST %x for layout: rc = %d\n",
+ lfsck_lfsck2name(lfsck), ltd->ltd_index, rc);
+ lfsck_tgt_put(ltd);
+ rc1 = rc;
+ } else {
+ cnt++;
+ }
+ spin_lock(<ds->ltd_lock);
+ }
+ spin_unlock(<ds->ltd_lock);
+
+ if (cnt > 0)
+ rc = ptlrpc_set_wait(set);
+ ptlrpc_set_destroy(set);
+
+ RETURN(rc1 != 0 ? rc1 : rc);
}
static inline bool
lfsck_layout_master_to_orphan(struct lfsck_layout_master_data *llmd)
{
- /* XXX: to be implemented. */
-
- return 1;
+ return !list_empty(&llmd->llmd_ost_phase2_list) ||
+ list_empty(&llmd->llmd_ost_phase1_list);
}
static int lfsck_layout_master_notify_others(const struct lu_env *env,
struct lfsck_component *com,
struct lfsck_request *lr)
{
- /* XXX: to be implemented. */
+ struct lfsck_thread_info *info = lfsck_env_info(env);
+ struct lfsck_async_interpret_args *laia = &info->lti_laia;
+ struct lfsck_instance *lfsck = com->lc_lfsck;
+ struct lfsck_layout_master_data *llmd = com->lc_data;
+ struct lfsck_layout *lo = com->lc_file_ram;
+ struct ptlrpc_request_set *set;
+ struct lfsck_tgt_descs *ltds;
+ struct lfsck_tgt_desc *ltd;
+ __u32 idx;
+ __u32 cnt = 0;
+ int rc = 0;
+ ENTRY;
- return 0;
+ set = ptlrpc_prep_set();
+ if (set == NULL)
+ RETURN(-ENOMEM);
+
+ lr->lr_active = LT_LAYOUT;
+ laia->laia_com = com;
+ laia->laia_lr = lr;
+ switch (lr->lr_event) {
+ case LE_START:
+ ltds = &lfsck->li_ost_descs;
+ laia->laia_ltds = ltds;
+ down_read(<ds->ltd_rw_sem);
+ cfs_foreach_bit(ltds->ltd_tgts_bitmap, idx) {
+ ltd = lfsck_tgt_get(ltds, idx);
+ LASSERT(ltd != NULL);
+
+ laia->laia_ltd = ltd;
+ rc = lfsck_async_request(env, ltd->ltd_exp, lr, set,
+ lfsck_layout_master_async_interpret,
+ laia, LFSCK_NOTIFY);
+ if (rc != 0) {
+ CERROR("%s: fail to notify OST %x for layout "
+ "start: rc = %d\n",
+ lfsck_lfsck2name(lfsck), idx, rc);
+ lfsck_tgt_put(ltd);
+ lo->ll_flags |= LF_INCOMPLETE;
+ } else {
+ cnt++;
+ }
+ }
+ up_read(<ds->ltd_rw_sem);
+ break;
+ case LE_STOP:
+ case LE_PHASE2_DONE:
+ ltds = &lfsck->li_ost_descs;
+ laia->laia_ltds = ltds;
+ spin_lock(<ds->ltd_lock);
+ while (!list_empty(&llmd->llmd_ost_list)) {
+ ltd = list_entry(llmd->llmd_ost_list.next,
+ struct lfsck_tgt_desc,
+ ltd_layout_list);
+ list_del_init(<d->ltd_layout_phase_list);
+ list_del_init(<d->ltd_layout_list);
+ laia->laia_ltd = ltd;
+ spin_unlock(<ds->ltd_lock);
+ rc = lfsck_async_request(env, ltd->ltd_exp, lr, set,
+ lfsck_layout_master_async_interpret,
+ laia, LFSCK_NOTIFY);
+ if (rc != 0)
+ CERROR("%s: fail to notify OST %x for layout "
+ "stop/done: rc = %d\n",
+ lfsck_lfsck2name(lfsck),
+ ltd->ltd_index, rc);
+ else
+ cnt++;
+ spin_lock(<ds->ltd_lock);
+ }
+ spin_unlock(<ds->ltd_lock);
+ break;
+ case LE_PHASE1_DONE:
+ break;
+ default:
+ CERROR("%s: unexpected LFSCK event: rc = %d\n",
+ lfsck_lfsck2name(lfsck), lr->lr_event);
+ rc = -EINVAL;
+ break;
+ }
+
+ if (cnt > 0)
+ rc = ptlrpc_set_wait(set);
+ ptlrpc_set_destroy(set);
+
+ if (rc == 0 && lr->lr_event == LE_START &&
+ list_empty(&llmd->llmd_ost_list))
+ rc = -ENODEV;
+
+ RETURN(rc);
}
static int lfsck_layout_double_scan_result(const struct lu_env *env,
return rc;
}
+static int lfsck_layout_scan_orphan(const struct lu_env *env,
+ struct lfsck_component *com,
+ struct lfsck_tgt_desc *ltd)
+{
+ /* XXX: To be extended in other patch. */
+
+ return 0;
+}
+
static int lfsck_layout_assistant(void *args)
{
struct lfsck_thread_args *lta = args;
LSV_ASYNC_WINDOWS;
lr->lr_speed = bk->lb_speed_limit;
lr->lr_version = bk->lb_version;
- lr->lr_active = LT_LAYOUT;
lr->lr_param = bk->lb_param;
lr->lr_async_windows = bk->lb_async_windows;
if (pos->lp_oit_cookie <= 1)
memset(lr, 0, sizeof(*lr));
lr->lr_index = lfsck_dev_idx(lfsck->li_bottom);
- lr->lr_active = LT_LAYOUT;
lr->lr_event = LE_PHASE1_DONE;
lr->lr_status = llmd->llmd_post_result;
rc = lfsck_layout_master_notify_others(env, com, lr);
wake_up_all(&mthread->t_ctl_waitq);
while (llmd->llmd_in_double_scan) {
+ struct lfsck_tgt_descs *ltds =
+ &lfsck->li_ost_descs;
+ struct lfsck_tgt_desc *ltd;
+
rc = lfsck_layout_master_query_others(env, com);
if (lfsck_layout_master_to_orphan(llmd))
goto orphan;
GOTO(cleanup2, rc);
orphan:
- /* XXX: real double scan for ost orphans. */
-
- GOTO(cleanup2, rc = 1);
+ spin_lock(<ds->ltd_lock);
+ while (!list_empty(
+ &llmd->llmd_ost_phase2_list)) {
+ ltd = list_entry(
+ llmd->llmd_ost_phase2_list.next,
+ struct lfsck_tgt_desc,
+ ltd_layout_phase_list);
+ list_del_init(
+ <d->ltd_layout_phase_list);
+ spin_unlock(<ds->ltd_lock);
+
+ rc = lfsck_layout_scan_orphan(env, com,
+ ltd);
+ if (rc != 0 &&
+ bk->lb_param & LPF_FAILOUT)
+ GOTO(cleanup2, rc);
+
+ if (unlikely(llmd->llmd_exit ||
+ !thread_is_running(mthread)))
+ GOTO(cleanup2, rc = 0);
+
+ spin_lock(<ds->ltd_lock);
+ }
+
+ if (list_empty(&llmd->llmd_ost_phase1_list)) {
+ spin_unlock(<ds->ltd_lock);
+ GOTO(cleanup2, rc = 1);
+ }
+ spin_unlock(<ds->ltd_lock);
}
}
}
cleanup2:
memset(lr, 0, sizeof(*lr));
lr->lr_index = lfsck_dev_idx(lfsck->li_bottom);
- lr->lr_active = LT_LAYOUT;
if (rc > 0) {
lr->lr_event = LE_PHASE2_DONE;
lr->lr_status = rc;
static void lfsck_layout_master_data_release(const struct lu_env *env,
struct lfsck_component *com)
{
- struct lfsck_layout_master_data *llmd = com->lc_data;
+ struct lfsck_layout_master_data *llmd = com->lc_data;
+ struct lfsck_instance *lfsck = com->lc_lfsck;
+ struct lfsck_tgt_descs *ltds;
+ struct lfsck_tgt_desc *ltd;
+ struct lfsck_tgt_desc *next;
LASSERT(llmd != NULL);
LASSERT(thread_is_init(&llmd->llmd_thread) ||
LASSERT(atomic_read(&llmd->llmd_rpcs_in_flight) == 0);
com->lc_data = NULL;
+
+ ltds = &lfsck->li_ost_descs;
+ spin_lock(<ds->ltd_lock);
+ list_for_each_entry_safe(ltd, next, &llmd->llmd_ost_phase1_list,
+ ltd_layout_phase_list) {
+ list_del_init(<d->ltd_layout_phase_list);
+ }
+ list_for_each_entry_safe(ltd, next, &llmd->llmd_ost_phase2_list,
+ ltd_layout_phase_list) {
+ list_del_init(<d->ltd_layout_phase_list);
+ }
+ list_for_each_entry_safe(ltd, next, &llmd->llmd_ost_list,
+ ltd_layout_list) {
+ list_del_init(<d->ltd_layout_list);
+ }
+ spin_unlock(<ds->ltd_lock);
+
OBD_FREE_PTR(llmd);
}
return lo->ll_status;
}
+static int lfsck_layout_master_stop_notify(const struct lu_env *env,
+ struct lfsck_component *com,
+ struct lfsck_tgt_descs *ltds,
+ struct lfsck_tgt_desc *ltd,
+ struct ptlrpc_request_set *set)
+{
+ struct lfsck_thread_info *info = lfsck_env_info(env);
+ struct lfsck_async_interpret_args *laia = &info->lti_laia;
+ struct lfsck_request *lr = &info->lti_lr;
+ struct lfsck_instance *lfsck = com->lc_lfsck;
+ int rc;
+
+ LASSERT(list_empty(<d->ltd_layout_list));
+ LASSERT(list_empty(<d->ltd_layout_phase_list));
+
+ memset(lr, 0, sizeof(*lr));
+ lr->lr_index = lfsck_dev_idx(lfsck->li_bottom);
+ lr->lr_event = LE_STOP;
+ lr->lr_active = LT_LAYOUT;
+ lr->lr_status = LS_CO_STOPPED;
+
+ laia->laia_com = com;
+ laia->laia_ltds = ltds;
+ laia->laia_ltd = ltd;
+ laia->laia_lr = lr;
+
+ rc = lfsck_async_request(env, ltd->ltd_exp, lr, set,
+ lfsck_layout_master_async_interpret,
+ laia, LFSCK_NOTIFY);
+ if (rc != 0)
+ CERROR("%s: Fail to notify OST %x for stop: rc = %d\n",
+ lfsck_lfsck2name(lfsck), ltd->ltd_index, rc);
+
+ return rc;
+}
+
static struct lfsck_operations lfsck_layout_master_ops = {
.lfsck_reset = lfsck_layout_reset,
.lfsck_fail = lfsck_layout_fail,
.lfsck_quit = lfsck_layout_master_quit,
.lfsck_in_notify = lfsck_layout_master_in_notify,
.lfsck_query = lfsck_layout_query,
+ .lfsck_stop_notify = lfsck_layout_master_stop_notify,
};
static struct lfsck_operations lfsck_layout_slave_ops = {
GOTO(out, rc = -ENOMEM);
INIT_LIST_HEAD(&llmd->llmd_req_list);
+ INIT_LIST_HEAD(&llmd->llmd_ost_list);
+ INIT_LIST_HEAD(&llmd->llmd_ost_phase1_list);
+ INIT_LIST_HEAD(&llmd->llmd_ost_phase2_list);
spin_lock_init(&llmd->llmd_lock);
init_waitqueue_head(&llmd->llmd_thread.t_ctl_waitq);
atomic_set(&llmd->llmd_rpcs_in_flight, 0);
ltd = LTD_TGT(ltds, idx);
if (likely(ltd != NULL)) {
LASSERT(list_empty(<d->ltd_layout_list));
+ LASSERT(list_empty(<d->ltd_layout_phase_list));
ltds->ltd_tgtnr--;
cfs_bitmap_clear(ltds->ltd_tgts_bitmap, idx);
atomic_read(&lfsck->li_double_scan_count) == 0,
&lwi);
- return (rc1 != 0 ? rc1 : rc);
+ return rc1 != 0 ? rc1 : rc;
+}
+
+int lfsck_stop_notify(const struct lu_env *env, struct lfsck_instance *lfsck,
+ struct lfsck_tgt_descs *ltds, struct lfsck_tgt_desc *ltd)
+{
+ struct ptlrpc_request_set *set;
+ struct lfsck_component *com;
+ int cnt = 0;
+ int rc = 0;
+ int rc1 = 0;
+
+ set = ptlrpc_prep_set();
+ if (set == NULL)
+ return -ENOMEM;
+
+ list_for_each_entry(com, &lfsck->li_list_scan, lc_link) {
+ if (com->lc_ops->lfsck_stop_notify != NULL) {
+ rc = com->lc_ops->lfsck_stop_notify(env, com, ltds,
+ ltd, set);
+ if (rc != 0)
+ rc1 = rc;
+ else
+ cnt++;
+ }
+ }
+
+ list_for_each_entry(com, &lfsck->li_list_double_scan, lc_link) {
+ if (com->lc_ops->lfsck_stop_notify != NULL) {
+ rc = com->lc_ops->lfsck_stop_notify(env, com, ltds,
+ ltd, set);
+ if (rc != 0)
+ rc1 = rc;
+ else
+ cnt++;
+ }
+ }
+
+ if (cnt > 0)
+ rc = ptlrpc_set_wait(set);
+ ptlrpc_set_destroy(set);
+
+ return rc1 != 0 ? rc1 : rc;
}
void lfsck_quit(const struct lu_env *env, struct lfsck_instance *lfsck)
}
}
+int lfsck_async_request(const struct lu_env *env, struct obd_export *exp,
+ struct lfsck_request *lr,
+ struct ptlrpc_request_set *set,
+ ptlrpc_interpterer_t interpreter,
+ void *args, int request)
+{
+ struct lfsck_async_interpret_args *laia;
+ struct ptlrpc_request *req;
+ struct lfsck_request *tmp;
+ struct req_format *format;
+ int rc;
+
+ if (!(exp_connect_flags(exp) & OBD_CONNECT_LFSCK))
+ return -EOPNOTSUPP;
+
+ switch (request) {
+ case LFSCK_NOTIFY:
+ format = &RQF_LFSCK_NOTIFY;
+ break;
+ case LFSCK_QUERY:
+ format = &RQF_LFSCK_QUERY;
+ break;
+ default:
+ CERROR("%s: unknown async request: opc = %d\n",
+ exp->exp_obd->obd_name, request);
+ return -EINVAL;
+ }
+
+ req = ptlrpc_request_alloc(class_exp2cliimp(exp), format);
+ if (req == NULL)
+ return -ENOMEM;
+
+ rc = ptlrpc_request_pack(req, LUSTRE_OBD_VERSION, request);
+ if (rc != 0) {
+ ptlrpc_request_free(req);
+
+ return rc;
+ }
+
+ tmp = req_capsule_client_get(&req->rq_pill, &RMF_LFSCK_REQUEST);
+ *tmp = *lr;
+ ptlrpc_request_set_replen(req);
+
+ laia = ptlrpc_req_async_args(req);
+ *laia = *(struct lfsck_async_interpret_args *)args;
+ req->rq_interpret_reply = interpreter;
+ ptlrpc_set_add_req(set, req);
+
+ return 0;
+}
+
/* external interfaces */
int lfsck_get_speed(struct dt_device *key, void *buf, int len)
ltd->ltd_exp = exp;
INIT_LIST_HEAD(<d->ltd_orphan_list);
INIT_LIST_HEAD(<d->ltd_layout_list);
+ INIT_LIST_HEAD(<d->ltd_layout_phase_list);
atomic_set(<d->ltd_ref, 1);
ltd->ltd_index = index;
struct lfsck_tgt_desc *ltd;
struct list_head *head;
bool found = false;
+ bool stop = false;
if (for_ost)
head = &lfsck_ost_orphan_list;
goto unlock;
found = true;
+ spin_lock(<ds->ltd_lock);
+ ltd->ltd_dead = 1;
if (!list_empty(<d->ltd_layout_list)) {
- spin_lock(<ds->ltd_lock);
list_del_init(<d->ltd_layout_list);
- spin_unlock(<ds->ltd_lock);
+ stop = true;
+ } else {
+ LASSERT(list_empty(<d->ltd_layout_phase_list));
}
+ spin_unlock(<ds->ltd_lock);
+
+ if (stop && lfsck->li_master)
+ lfsck_stop_notify(env, lfsck, ltds, ltd);
LASSERT(ltds->ltd_tgtnr > 0);