/* * GPL HEADER START * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 only, * as published by the Free Software Foundation. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License version 2 for more details. A copy is * included in the COPYING file that accompanied this code. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * GPL HEADER END */ /* * Copyright (c) 2013, Intel Corporation. */ /* * lustre/lfsck/lfsck_layout.c * * Author: Fan, Yong */ #ifndef EXPORT_SYMTAB # define EXPORT_SYMTAB #endif #define DEBUG_SUBSYSTEM S_LFSCK #include #include #include #include #include #include #include #include #include #include "lfsck_internal.h" #define LFSCK_LAYOUT_MAGIC 0xB173AE14 static const char lfsck_layout_name[] = "lfsck_layout"; static void lfsck_layout_le_to_cpu(struct lfsck_layout *des, const struct lfsck_layout *src) { int i; des->ll_magic = le32_to_cpu(src->ll_magic); des->ll_status = le32_to_cpu(src->ll_status); des->ll_flags = le32_to_cpu(src->ll_flags); des->ll_success_count = le32_to_cpu(src->ll_success_count); des->ll_run_time_phase1 = le32_to_cpu(src->ll_run_time_phase1); des->ll_run_time_phase2 = le32_to_cpu(src->ll_run_time_phase2); des->ll_time_last_complete = le64_to_cpu(src->ll_time_last_complete); des->ll_time_latest_start = le64_to_cpu(src->ll_time_latest_start); des->ll_time_last_checkpoint = le64_to_cpu(src->ll_time_last_checkpoint); des->ll_pos_latest_start = le64_to_cpu(src->ll_pos_latest_start); des->ll_pos_last_checkpoint = le64_to_cpu(src->ll_pos_last_checkpoint); des->ll_pos_first_inconsistent = le64_to_cpu(src->ll_pos_first_inconsistent); des->ll_objs_checked_phase1 = le64_to_cpu(src->ll_objs_checked_phase1); des->ll_objs_failed_phase1 = le64_to_cpu(src->ll_objs_failed_phase1); des->ll_objs_checked_phase2 = le64_to_cpu(src->ll_objs_checked_phase2); des->ll_objs_failed_phase2 = le64_to_cpu(src->ll_objs_failed_phase2); for (i = 0; i < LLIT_MAX; i++) des->ll_objs_repaired[i] = le64_to_cpu(src->ll_objs_repaired[i]); des->ll_objs_skipped = le64_to_cpu(src->ll_objs_skipped); } static void lfsck_layout_cpu_to_le(struct lfsck_layout *des, const struct lfsck_layout *src) { int i; des->ll_magic = cpu_to_le32(src->ll_magic); des->ll_status = cpu_to_le32(src->ll_status); des->ll_flags = cpu_to_le32(src->ll_flags); des->ll_success_count = cpu_to_le32(src->ll_success_count); des->ll_run_time_phase1 = cpu_to_le32(src->ll_run_time_phase1); des->ll_run_time_phase2 = cpu_to_le32(src->ll_run_time_phase2); des->ll_time_last_complete = cpu_to_le64(src->ll_time_last_complete); des->ll_time_latest_start = cpu_to_le64(src->ll_time_latest_start); des->ll_time_last_checkpoint = cpu_to_le64(src->ll_time_last_checkpoint); des->ll_pos_latest_start = cpu_to_le64(src->ll_pos_latest_start); des->ll_pos_last_checkpoint = cpu_to_le64(src->ll_pos_last_checkpoint); des->ll_pos_first_inconsistent = cpu_to_le64(src->ll_pos_first_inconsistent); des->ll_objs_checked_phase1 = cpu_to_le64(src->ll_objs_checked_phase1); des->ll_objs_failed_phase1 = cpu_to_le64(src->ll_objs_failed_phase1); des->ll_objs_checked_phase2 = cpu_to_le64(src->ll_objs_checked_phase2); des->ll_objs_failed_phase2 = cpu_to_le64(src->ll_objs_failed_phase2); for (i = 0; i < LLIT_MAX; i++) des->ll_objs_repaired[i] = cpu_to_le64(src->ll_objs_repaired[i]); des->ll_objs_skipped = cpu_to_le64(src->ll_objs_skipped); } /** * \retval +ve: the lfsck_layout is broken, the caller should reset it. * \retval 0: succeed. * \retval -ve: failed cases. */ static int lfsck_layout_load(const struct lu_env *env, struct lfsck_component *com) { struct lfsck_layout *lo = com->lc_file_ram; const struct dt_body_operations *dbo = com->lc_obj->do_body_ops; ssize_t size = com->lc_file_size; loff_t pos = 0; int rc; rc = dbo->dbo_read(env, com->lc_obj, lfsck_buf_get(env, com->lc_file_disk, size), &pos, BYPASS_CAPA); if (rc == 0) { return -ENOENT; } else if (rc < 0) { CWARN("%s: failed to load lfsck_layout: rc = %d\n", lfsck_lfsck2name(com->lc_lfsck), rc); return rc; } else if (rc != size) { CWARN("%s: crashed lfsck_layout, to be reset: rc = %d\n", lfsck_lfsck2name(com->lc_lfsck), rc); return 1; } lfsck_layout_le_to_cpu(lo, com->lc_file_disk); if (lo->ll_magic != LFSCK_LAYOUT_MAGIC) { CWARN("%s: invalid lfsck_layout magic %#x != %#x, " "to be reset\n", lfsck_lfsck2name(com->lc_lfsck), lo->ll_magic, LFSCK_LAYOUT_MAGIC); return 1; } return 0; } static int lfsck_layout_store(const struct lu_env *env, struct lfsck_component *com) { struct dt_object *obj = com->lc_obj; struct lfsck_instance *lfsck = com->lc_lfsck; struct lfsck_layout *lo = com->lc_file_disk; struct thandle *handle; ssize_t size = com->lc_file_size; loff_t pos = 0; int rc; ENTRY; lfsck_layout_cpu_to_le(lo, com->lc_file_ram); handle = dt_trans_create(env, lfsck->li_bottom); if (IS_ERR(handle)) { rc = PTR_ERR(handle); CERROR("%s: fail to create trans for storing lfsck_layout: " "rc = %d\n", lfsck_lfsck2name(lfsck), rc); RETURN(rc); } rc = dt_declare_record_write(env, obj, size, pos, handle); if (rc != 0) { CERROR("%s: fail to declare trans for storing lfsck_layout(1): " "rc = %d\n", lfsck_lfsck2name(lfsck), rc); GOTO(out, rc); } rc = dt_trans_start_local(env, lfsck->li_bottom, handle); if (rc != 0) { CERROR("%s: fail to start trans for storing lfsck_layout: " "rc = %d\n", lfsck_lfsck2name(lfsck), rc); GOTO(out, rc); } rc = dt_record_write(env, obj, lfsck_buf_get(env, lo, size), &pos, handle); if (rc != 0) CERROR("%s: fail to store lfsck_layout(1): size = %d, " "rc = %d\n", lfsck_lfsck2name(lfsck), (int)size, rc); GOTO(out, rc); out: dt_trans_stop(env, lfsck->li_bottom, handle); return rc; } static int lfsck_layout_init(const struct lu_env *env, struct lfsck_component *com) { struct lfsck_layout *lo = com->lc_file_ram; int rc; memset(lo, 0, com->lc_file_size); lo->ll_magic = LFSCK_LAYOUT_MAGIC; lo->ll_status = LS_INIT; down_write(&com->lc_sem); rc = lfsck_layout_store(env, com); up_write(&com->lc_sem); return rc; } /* layout APIs */ /* XXX: Some to be implemented in other patch(es). */ static int lfsck_layout_reset(const struct lu_env *env, struct lfsck_component *com, bool init) { struct lfsck_layout *lo = com->lc_file_ram; int rc; down_write(&com->lc_sem); if (init) { memset(lo, 0, com->lc_file_size); } else { __u32 count = lo->ll_success_count; __u64 last_time = lo->ll_time_last_complete; memset(lo, 0, com->lc_file_size); lo->ll_success_count = count; lo->ll_time_last_complete = last_time; } lo->ll_magic = LFSCK_LAYOUT_MAGIC; lo->ll_status = LS_INIT; rc = lfsck_layout_store(env, com); up_write(&com->lc_sem); return rc; } static void lfsck_layout_fail(const struct lu_env *env, struct lfsck_component *com, bool new_checked) { } static int lfsck_layout_checkpoint(const struct lu_env *env, struct lfsck_component *com, bool init) { return 0; } static int lfsck_layout_master_prep(const struct lu_env *env, struct lfsck_component *com) { return 0; } static int lfsck_layout_slave_prep(const struct lu_env *env, struct lfsck_component *com) { return 0; } static int lfsck_layout_master_exec_oit(const struct lu_env *env, struct lfsck_component *com, struct dt_object *obj) { return 0; } static int lfsck_layout_slave_exec_oit(const struct lu_env *env, struct lfsck_component *com, struct dt_object *obj) { return 0; } static int lfsck_layout_exec_dir(const struct lu_env *env, struct lfsck_component *com, struct dt_object *obj, struct lu_dirent *ent) { return 0; } static int lfsck_layout_master_post(const struct lu_env *env, struct lfsck_component *com, int result, bool init) { return 0; } static int lfsck_layout_slave_post(const struct lu_env *env, struct lfsck_component *com, int result, bool init) { return 0; } static int lfsck_layout_dump(const struct lu_env *env, struct lfsck_component *com, char *buf, int len) { return 0; } static int lfsck_layout_master_double_scan(const struct lu_env *env, struct lfsck_component *com) { return 0; } static int lfsck_layout_slave_double_scan(const struct lu_env *env, struct lfsck_component *com) { return 0; } static struct lfsck_operations lfsck_layout_master_ops = { .lfsck_reset = lfsck_layout_reset, .lfsck_fail = lfsck_layout_fail, .lfsck_checkpoint = lfsck_layout_checkpoint, .lfsck_prep = lfsck_layout_master_prep, .lfsck_exec_oit = lfsck_layout_master_exec_oit, .lfsck_exec_dir = lfsck_layout_exec_dir, .lfsck_post = lfsck_layout_master_post, .lfsck_dump = lfsck_layout_dump, .lfsck_double_scan = lfsck_layout_master_double_scan, }; static struct lfsck_operations lfsck_layout_slave_ops = { .lfsck_reset = lfsck_layout_reset, .lfsck_fail = lfsck_layout_fail, .lfsck_checkpoint = lfsck_layout_checkpoint, .lfsck_prep = lfsck_layout_slave_prep, .lfsck_exec_oit = lfsck_layout_slave_exec_oit, .lfsck_exec_dir = lfsck_layout_exec_dir, .lfsck_post = lfsck_layout_slave_post, .lfsck_dump = lfsck_layout_dump, .lfsck_double_scan = lfsck_layout_slave_double_scan, }; int lfsck_layout_setup(const struct lu_env *env, struct lfsck_instance *lfsck) { struct lfsck_component *com; struct lfsck_layout *lo; struct dt_object *root = NULL; struct dt_object *obj; int rc; ENTRY; OBD_ALLOC_PTR(com); if (com == NULL) RETURN(-ENOMEM); INIT_LIST_HEAD(&com->lc_link); INIT_LIST_HEAD(&com->lc_link_dir); init_rwsem(&com->lc_sem); atomic_set(&com->lc_ref, 1); com->lc_lfsck = lfsck; com->lc_type = LT_LAYOUT; if (lfsck->li_master) com->lc_ops = &lfsck_layout_master_ops; else com->lc_ops = &lfsck_layout_slave_ops; com->lc_file_size = sizeof(*lo); OBD_ALLOC(com->lc_file_ram, com->lc_file_size); if (com->lc_file_ram == NULL) GOTO(out, rc = -ENOMEM); OBD_ALLOC(com->lc_file_disk, com->lc_file_size); if (com->lc_file_disk == NULL) GOTO(out, rc = -ENOMEM); root = dt_locate(env, lfsck->li_bottom, &lfsck->li_local_root_fid); if (IS_ERR(root)) GOTO(out, rc = PTR_ERR(root)); if (unlikely(!dt_try_as_dir(env, root))) GOTO(out, rc = -ENOTDIR); obj = local_file_find_or_create(env, lfsck->li_los, root, lfsck_layout_name, S_IFREG | S_IRUGO | S_IWUSR); if (IS_ERR(obj)) GOTO(out, rc = PTR_ERR(obj)); com->lc_obj = obj; rc = lfsck_layout_load(env, com); if (rc > 0) rc = lfsck_layout_reset(env, com, true); else if (rc == -ENOENT) rc = lfsck_layout_init(env, com); if (rc != 0) GOTO(out, rc); lo = com->lc_file_ram; switch (lo->ll_status) { case LS_INIT: case LS_COMPLETED: case LS_FAILED: case LS_STOPPED: case LS_PARTIAL: spin_lock(&lfsck->li_lock); list_add_tail(&com->lc_link, &lfsck->li_list_idle); spin_unlock(&lfsck->li_lock); break; default: CERROR("%s: unknown lfsck_layout status: rc = %u\n", lfsck_lfsck2name(lfsck), lo->ll_status); /* fall through */ case LS_SCANNING_PHASE1: case LS_SCANNING_PHASE2: /* No need to store the status to disk right now. * If the system crashed before the status stored, * it will be loaded back when next time. */ lo->ll_status = LS_CRASHED; lo->ll_flags |= LF_INCOMPLETE; /* fall through */ case LS_PAUSED: case LS_CRASHED: spin_lock(&lfsck->li_lock); list_add_tail(&com->lc_link, &lfsck->li_list_scan); spin_unlock(&lfsck->li_lock); break; } GOTO(out, rc = 0); out: if (root != NULL && !IS_ERR(root)) lu_object_put(env, &root->do_lu); if (rc != 0) lfsck_component_cleanup(env, com); return rc; }