From: Fan Yong Date: Wed, 29 Nov 2017 02:52:30 +0000 (+0800) Subject: LU-7585 scrub: general framework for OI scrub X-Git-Tag: 2.10.57~119 X-Git-Url: https://git.whamcloud.com/?a=commitdiff_plain;h=refs%2Fchanges%2F07%2F28607%2F18;p=fs%2Flustre-release.git LU-7585 scrub: general framework for OI scrub Reconstruct OI scrub code to make some data structure and functions can be shared between osd-ldiskfs and osd-ZFS. Signed-off-by: Fan Yong Change-Id: I4c4e3fcbd11078d10592136e9e55de66516a2b16 Reviewed-on: https://review.whamcloud.com/28607 Tested-by: Jenkins Reviewed-by: Andreas Dilger Tested-by: Maloo Reviewed-by: Alex Zhuravlev --- diff --git a/lustre/include/Makefile.am b/lustre/include/Makefile.am index 4613df4..1f9a990 100644 --- a/lustre/include/Makefile.am +++ b/lustre/include/Makefile.am @@ -81,6 +81,7 @@ EXTRA_DIST = \ lustre_patchless_compat.h \ lustre_quota.h \ lustre_req_layout.h \ + lustre_scrub.h \ lustre_sec.h \ lustre_swab.h \ lustre_update.h \ diff --git a/lustre/include/lustre_fid.h b/lustre/include/lustre_fid.h index e34ac94..d12e900 100644 --- a/lustre/include/lustre_fid.h +++ b/lustre/include/lustre_fid.h @@ -196,13 +196,6 @@ enum { LUSTRE_SEQ_SUPER_WIDTH = ((1ULL << 30ULL) * LUSTRE_SEQ_META_WIDTH) }; -enum { - /** 2^6 FIDs for OI containers */ - OSD_OI_FID_OID_BITS = 6, - /** reserve enough FIDs in case we want more in the future */ - OSD_OI_FID_OID_BITS_MAX = 10, -}; - /** special OID for local objects */ enum local_oid { /** \see fld_mod_init */ diff --git a/lustre/include/lustre_scrub.h b/lustre/include/lustre_scrub.h new file mode 100644 index 0000000..e858586 --- /dev/null +++ b/lustre/include/lustre_scrub.h @@ -0,0 +1,293 @@ +/* + * 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 LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; If not, see + * http://www.gnu.org/licenses/gpl-2.0.html + * + * GPL HEADER END + */ +/* + * Copyright (c) 2017, Intel Corporation. + */ +/* + * lustre/include/lustre_scrub.h + * + * Shared definitions and declarations for Lustre OI scrub. + * + * Author: Fan Yong + */ + +#ifndef _LUSTRE_SCRUB_H +# define _LUSTRE_SCRUB_H + +#include +#include + +#define OSD_OI_FID_OID_BITS_MAX 10 +#define OSD_OI_FID_NR_MAX (1UL << OSD_OI_FID_OID_BITS_MAX) +#define SCRUB_OI_BITMAP_SIZE (OSD_OI_FID_NR_MAX >> 3) + +#define SCRUB_MAGIC_V1 0x4C5FD252 +#define SCRUB_CHECKPOINT_INTERVAL 60 +#define SCRUB_WINDOW_SIZE 1024 + +#define HALF_SEC msecs_to_jiffies(MSEC_PER_SEC >> 1) + +enum scrub_next_status { + /* exit current loop and process next group */ + SCRUB_NEXT_BREAK = 1, + + /* skip current object and process next bit */ + SCRUB_NEXT_CONTINUE = 2, + + /* exit all the loops */ + SCRUB_NEXT_EXIT = 3, + + /* wait for free cache slot */ + SCRUB_NEXT_WAIT = 4, + + /* simulate system crash during OI scrub */ + SCRUB_NEXT_CRASH = 5, + + /* simulate failure during OI scrub */ + SCRUB_NEXT_FATAL = 6, + + /* new created object, no scrub on it */ + SCRUB_NEXT_NOSCRUB = 7, + + /* the object has no FID-in-LMA */ + SCRUB_NEXT_NOLMA = 8, + + /* for OST-object */ + SCRUB_NEXT_OSTOBJ = 9, + + /* old OST-object, no LMA or no FID-on-OST flags in LMA */ + SCRUB_NEXT_OSTOBJ_OLD = 10, +}; + +enum scrub_local_file_flags { + SLFF_SCAN_SUBITEMS = 0x0001, + SLFF_HIDE_FID = 0x0002, + SLFF_SHOW_NAME = 0x0004, + SLFF_NO_OI = 0x0008, + SLFF_IDX_IN_FID = 0x0010, +}; + +enum scrub_status { + /* The scrub file is new created, for new MDT, upgrading from old disk, + * or re-creating the scrub file manually. */ + SS_INIT = 0, + + /* The scrub is checking/repairing the OI files. */ + SS_SCANNING = 1, + + /* The scrub checked/repaired the OI files successfully. */ + SS_COMPLETED = 2, + + /* The scrub failed to check/repair the OI files. */ + SS_FAILED = 3, + + /* The scrub is stopped manually, the OI files may be inconsistent. */ + SS_STOPPED = 4, + + /* The scrub is paused automatically when umount. */ + SS_PAUSED = 5, + + /* The scrub crashed during the scanning, should be restarted. */ + SS_CRASHED = 6, +}; + +enum scrub_flags { + /* OI files have been recreated, OI mappings should be re-inserted. */ + SF_RECREATED = 0x0000000000000001ULL, + + /* OI files are invalid, should be rebuild ASAP */ + SF_INCONSISTENT = 0x0000000000000002ULL, + + /* OI scrub is triggered automatically. */ + SF_AUTO = 0x0000000000000004ULL, + + /* The device is upgraded from 1.8 format. */ + SF_UPGRADE = 0x0000000000000008ULL, +}; + +enum scrub_param { + /* Exit when fail. */ + SP_FAILOUT = 0x0001, + + /* Check only without repairing. */ + SP_DRYRUN = 0x0002, +}; + +enum scrub_start { + /* Set failout flag. */ + SS_SET_FAILOUT = 0x00000001, + + /* Clear failout flag. */ + SS_CLEAR_FAILOUT = 0x00000002, + + /* Reset scrub start position. */ + SS_RESET = 0x00000004, + + /* Trigger full scrub automatically. */ + SS_AUTO_FULL = 0x00000008, + + /* Trigger partial scrub automatically. */ + SS_AUTO_PARTIAL = 0x00000010, + + /* Set dryrun flag. */ + SS_SET_DRYRUN = 0x00000020, + + /* Clear dryrun flag. */ + SS_CLEAR_DRYRUN = 0x00000040, +}; + +enum osd_lf_flags { + OLF_SCAN_SUBITEMS = 0x0001, + OLF_HIDE_FID = 0x0002, + OLF_SHOW_NAME = 0x0004, + OLF_NO_OI = 0x0008, + OLF_IDX_IN_FID = 0x0010, +}; + +struct scrub_file { + /* 128-bit uuid for volume. */ + __u8 sf_uuid[16]; + + /* See 'enum scrub_flags'. */ + __u64 sf_flags; + + /* The scrub magic. */ + __u32 sf_magic; + + /* See 'enum scrub_status'. */ + __u16 sf_status; + + /* See 'enum scrub_param'. */ + __u16 sf_param; + + /* The time for the last OI scrub completed. */ + __u64 sf_time_last_complete; + + /* The time for the latest OI scrub ran. */ + __u64 sf_time_latest_start; + + /* The time for the last OI scrub checkpoint. */ + __u64 sf_time_last_checkpoint; + + /* The position for the latest OI scrub started from. */ + __u64 sf_pos_latest_start; + + /* The position for the last OI scrub checkpoint. */ + __u64 sf_pos_last_checkpoint; + + /* The position for the first should be updated object. */ + __u64 sf_pos_first_inconsistent; + + /* How many objects have been checked. */ + __u64 sf_items_checked; + + /* How many objects have been updated. */ + __u64 sf_items_updated; + + /* How many objects failed to be processed. */ + __u64 sf_items_failed; + + /* How many prior objects have been updated during scanning. */ + __u64 sf_items_updated_prior; + + /* How many objects marked as LDISKFS_STATE_LUSTRE_NOSCRUB. */ + __u64 sf_items_noscrub; + + /* How many IGIF objects. */ + __u64 sf_items_igif; + + /* How long the OI scrub has run. */ + __u32 sf_run_time; + + /* How many completed OI scrub ran on the device. */ + __u32 sf_success_count; + + /* How many OI files. */ + __u16 sf_oi_count; + + /* Keep the flags after scrub reset. See 'enum scrub_internal_flags' */ + __u16 sf_internal_flags; + + __u32 sf_reserved_1; + __u64 sf_reserved_2[16]; + + /* Bitmap for OI files recreated case. */ + __u8 sf_oi_bitmap[SCRUB_OI_BITMAP_SIZE]; +}; + +struct lustre_scrub { + struct lu_object_header os_obj_header; + /* Object for the scrub file. */ + struct dt_object *os_obj; + + struct ptlrpc_thread os_thread; + struct list_head os_inconsistent_items; + + /* write lock for scrub prep/update/post/checkpoint, + * read lock for scrub dump. */ + struct rw_semaphore os_rwsem; + spinlock_t os_lock; + + /* Scrub file in memory. */ + struct scrub_file os_file; + + /* Buffer for scrub file load/store. */ + struct scrub_file os_file_disk; + + const char *os_name; + + /* The time for last checkpoint, jiffies */ + cfs_time_t os_time_last_checkpoint; + + /* The time for next checkpoint, jiffies */ + cfs_time_t os_time_next_checkpoint; + + /* How many objects have been checked since last checkpoint. */ + __u64 os_new_checked; + __u64 os_pos_current; + __u32 os_start_flags; + unsigned int os_in_prior:1, /* process inconsistent item + * found by RPC prior */ + os_waiting:1, /* Waiting for scan window. */ + os_full_speed:1, /* run w/o speed limit */ + os_paused:1, /* The scrub is paused. */ + os_convert_igif:1, + os_partial_scan:1, + os_in_join:1, + os_full_scrub:1; +}; + +void scrub_file_init(struct lustre_scrub *scrub, __u8 *uuid); +void scrub_file_reset(struct lustre_scrub *scrub, __u8 *uuid, __u64 flags); +int scrub_file_load(const struct lu_env *env, struct lustre_scrub *scrub); +int scrub_file_store(const struct lu_env *env, struct lustre_scrub *scrub); +int scrub_checkpoint(const struct lu_env *env, struct lustre_scrub *scrub); +int scrub_start(int (*threadfn)(void *data), struct lustre_scrub *scrub, + void *data, __u32 flags); +void scrub_stop(struct lustre_scrub *scrub); +void scrub_dump(struct seq_file *m, struct lustre_scrub *scrub); + +static inline const char *osd_scrub2name(struct lustre_scrub *scrub) +{ + return scrub->os_name; +} +#endif /* _LUSTRE_SCRUB_H */ diff --git a/lustre/obdclass/Makefile.in b/lustre/obdclass/Makefile.in index 10ba72a..b684e3c 100644 --- a/lustre/obdclass/Makefile.in +++ b/lustre/obdclass/Makefile.in @@ -23,6 +23,7 @@ obdclass-all-objs += kernelcomm.o jobid.o @SERVER_TRUE@obdclass-all-objs += lu_ucred.o @SERVER_TRUE@obdclass-all-objs += md_attrs.o @SERVER_TRUE@obdclass-all-objs += obd_mount_server.o +@SERVER_TRUE@obdclass-all-objs += scrub.o obdclass-objs := $(obdclass-linux-objs) $(obdclass-all-objs) @@ -39,5 +40,6 @@ EXTRA_DIST += cl_internal.h local_storage.h @SERVER_FALSE@EXTRA_DIST += lu_ucred.c @SERVER_FALSE@EXTRA_DIST += md_attrs.c @SERVER_FALSE@EXTRA_DIST += obd_mount_server.c +@SERVER_FALSE@EXTRA_DIST += scrub.c @INCLUDE_RULES@ diff --git a/lustre/obdclass/scrub.c b/lustre/obdclass/scrub.c new file mode 100644 index 0000000..7be6a27 --- /dev/null +++ b/lustre/obdclass/scrub.c @@ -0,0 +1,496 @@ +/* + * 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 LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; If not, see + * http://www.gnu.org/licenses/gpl-2.0.html + * + * GPL HEADER END + */ +/* + * Copyright (c) 2017, Intel Corporation. + */ +/* + * lustre/obdclass/scrub.c + * + * The OI scrub is used for checking and (re)building Object Index files + * that are usually backend special. Here are some general scrub related + * functions that can be shared by different backends for OI scrub. + * + * Author: Fan Yong + */ + +#define DEBUG_SUBSYSTEM S_LFSCK + +#include +#include +#include + +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); +} + +static void scrub_file_to_cpu(struct scrub_file *des, struct scrub_file *src) +{ + memcpy(des->sf_uuid, src->sf_uuid, 16); + 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); + des->sf_param = le16_to_cpu(src->sf_param); + des->sf_time_last_complete = + le64_to_cpu(src->sf_time_last_complete); + des->sf_time_latest_start = + le64_to_cpu(src->sf_time_latest_start); + des->sf_time_last_checkpoint = + le64_to_cpu(src->sf_time_last_checkpoint); + des->sf_pos_latest_start = + le64_to_cpu(src->sf_pos_latest_start); + des->sf_pos_last_checkpoint = + le64_to_cpu(src->sf_pos_last_checkpoint); + des->sf_pos_first_inconsistent = + le64_to_cpu(src->sf_pos_first_inconsistent); + des->sf_items_checked = + le64_to_cpu(src->sf_items_checked); + des->sf_items_updated = + le64_to_cpu(src->sf_items_updated); + des->sf_items_failed = + le64_to_cpu(src->sf_items_failed); + des->sf_items_updated_prior = + le64_to_cpu(src->sf_items_updated_prior); + des->sf_run_time = le32_to_cpu(src->sf_run_time); + des->sf_success_count = le32_to_cpu(src->sf_success_count); + des->sf_oi_count = le16_to_cpu(src->sf_oi_count); + des->sf_internal_flags = le16_to_cpu(src->sf_internal_flags); + memcpy(des->sf_oi_bitmap, src->sf_oi_bitmap, SCRUB_OI_BITMAP_SIZE); +} + +static void scrub_file_to_le(struct scrub_file *des, struct scrub_file *src) +{ + memcpy(des->sf_uuid, src->sf_uuid, 16); + 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); + des->sf_param = cpu_to_le16(src->sf_param); + des->sf_time_last_complete = + cpu_to_le64(src->sf_time_last_complete); + des->sf_time_latest_start = + cpu_to_le64(src->sf_time_latest_start); + des->sf_time_last_checkpoint = + cpu_to_le64(src->sf_time_last_checkpoint); + des->sf_pos_latest_start = + cpu_to_le64(src->sf_pos_latest_start); + des->sf_pos_last_checkpoint = + cpu_to_le64(src->sf_pos_last_checkpoint); + des->sf_pos_first_inconsistent = + cpu_to_le64(src->sf_pos_first_inconsistent); + des->sf_items_checked = + cpu_to_le64(src->sf_items_checked); + des->sf_items_updated = + cpu_to_le64(src->sf_items_updated); + des->sf_items_failed = + cpu_to_le64(src->sf_items_failed); + des->sf_items_updated_prior = + cpu_to_le64(src->sf_items_updated_prior); + des->sf_run_time = cpu_to_le32(src->sf_run_time); + des->sf_success_count = cpu_to_le32(src->sf_success_count); + des->sf_oi_count = cpu_to_le16(src->sf_oi_count); + des->sf_internal_flags = cpu_to_le16(src->sf_internal_flags); + memcpy(des->sf_oi_bitmap, src->sf_oi_bitmap, SCRUB_OI_BITMAP_SIZE); +} + +void scrub_file_init(struct lustre_scrub *scrub, __u8 *uuid) +{ + struct scrub_file *sf = &scrub->os_file; + + memset(sf, 0, sizeof(*sf)); + memcpy(sf->sf_uuid, uuid, 16); + sf->sf_magic = SCRUB_MAGIC_V1; + sf->sf_status = SS_INIT; +} +EXPORT_SYMBOL(scrub_file_init); + +void scrub_file_reset(struct lustre_scrub *scrub, __u8 *uuid, __u64 flags) +{ + struct scrub_file *sf = &scrub->os_file; + + CDEBUG(D_LFSCK, "%s: reset OI scrub file, old flags = " + "%#llx, add flags = %#llx\n", + scrub->os_name, sf->sf_flags, flags); + + memcpy(sf->sf_uuid, uuid, 16); + sf->sf_status = SS_INIT; + sf->sf_flags |= flags; + sf->sf_flags &= ~SF_AUTO; + sf->sf_run_time = 0; + sf->sf_time_latest_start = 0; + sf->sf_time_last_checkpoint = 0; + sf->sf_pos_latest_start = 0; + sf->sf_pos_last_checkpoint = 0; + sf->sf_pos_first_inconsistent = 0; + sf->sf_items_checked = 0; + sf->sf_items_updated = 0; + sf->sf_items_failed = 0; + sf->sf_items_noscrub = 0; + sf->sf_items_igif = 0; + if (!scrub->os_in_join) + sf->sf_items_updated_prior = 0; +} +EXPORT_SYMBOL(scrub_file_reset); + +int scrub_file_load(const struct lu_env *env, struct lustre_scrub *scrub) +{ + struct scrub_file *sf = &scrub->os_file; + struct lu_buf buf = { + .lb_buf = &scrub->os_file_disk, + .lb_len = sizeof(scrub->os_file_disk) + }; + loff_t pos = 0; + int rc; + + rc = dt_read(env, scrub->os_obj, &buf, &pos); + /* failure */ + if (rc < 0) { + CERROR("%s: fail to load scrub file: rc = %d\n", + scrub->os_name, rc); + return rc; + } + + /* empty */ + if (!rc) + return -ENOENT; + + /* corrupted */ + if (rc < buf.lb_len) { + CDEBUG(D_LFSCK, "%s: fail to load scrub file, " + "expected = %d: rc = %d\n", + scrub->os_name, (int)buf.lb_len, rc); + return -EFAULT; + } + + 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); + return -EFAULT; + } + + return 0; +} +EXPORT_SYMBOL(scrub_file_load); + +int scrub_file_store(const struct lu_env *env, struct lustre_scrub *scrub) +{ + struct scrub_file *sf = &scrub->os_file_disk; + struct dt_object *obj = scrub->os_obj; + struct dt_device *dev = scrub_obj2dev(obj); + struct lu_buf buf = { + .lb_buf = sf, + .lb_len = sizeof(*sf) + }; + struct thandle *th; + loff_t pos = 0; + int rc; + ENTRY; + + /* Skip store under rdonly mode. */ + if (dev->dd_rdonly) + RETURN(0); + + scrub_file_to_le(sf, &scrub->os_file); + th = dt_trans_create(env, dev); + if (IS_ERR(th)) + GOTO(log, rc = PTR_ERR(th)); + + rc = dt_declare_record_write(env, obj, &buf, pos, th); + if (rc) + GOTO(stop, rc); + + rc = dt_trans_start_local(env, dev, th); + if (rc) + GOTO(stop, rc); + + rc = dt_record_write(env, obj, &buf, &pos, th); + + GOTO(stop, rc); + +stop: + dt_trans_stop(env, dev, th); + +log: + if (rc) + CERROR("%s: store scrub file: rc = %d\n", + scrub->os_name, rc); + else + CDEBUG(D_LFSCK, "%s: store scrub file: rc = %d\n", + scrub->os_name, rc); + + scrub->os_time_last_checkpoint = cfs_time_current(); + scrub->os_time_next_checkpoint = scrub->os_time_last_checkpoint + + cfs_time_seconds(SCRUB_CHECKPOINT_INTERVAL); + return rc; +} +EXPORT_SYMBOL(scrub_file_store); + +int scrub_checkpoint(const struct lu_env *env, struct lustre_scrub *scrub) +{ + struct scrub_file *sf = &scrub->os_file; + int rc; + + if (likely(cfs_time_before(cfs_time_current(), + scrub->os_time_next_checkpoint) || + scrub->os_new_checked == 0)) + return 0; + + CDEBUG(D_LFSCK, "%s: OI scrub checkpoint at pos %llu\n", + scrub->os_name, scrub->os_pos_current); + + down_write(&scrub->os_rwsem); + 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 = cfs_time_current_sec(); + sf->sf_run_time += cfs_duration_sec(cfs_time_current() + HALF_SEC - + scrub->os_time_last_checkpoint); + rc = scrub_file_store(env, scrub); + up_write(&scrub->os_rwsem); + + return rc; +} +EXPORT_SYMBOL(scrub_checkpoint); + +int scrub_start(int (*threadfn)(void *data), struct lustre_scrub *scrub, + void *data, __u32 flags) +{ + struct ptlrpc_thread *thread = &scrub->os_thread; + struct l_wait_info lwi = { 0 }; + struct task_struct *task; + int rc; + ENTRY; + +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); + } + + if (unlikely(thread_is_stopping(thread))) { + spin_unlock(&scrub->os_lock); + l_wait_event(thread->t_ctl_waitq, + thread_is_stopped(thread), + &lwi); + goto again; + } + spin_unlock(&scrub->os_lock); + + if (scrub->os_file.sf_status == SS_COMPLETED) { + if (!(flags & SS_SET_FAILOUT)) + flags |= SS_CLEAR_FAILOUT; + + if (!(flags & SS_SET_DRYRUN)) + flags |= SS_CLEAR_DRYRUN; + + flags |= SS_RESET; + } + + scrub->os_start_flags = flags; + thread_set_flags(thread, 0); + task = kthread_run(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); + } + + l_wait_event(thread->t_ctl_waitq, + thread_is_running(thread) || thread_is_stopped(thread), + &lwi); + + RETURN(0); +} +EXPORT_SYMBOL(scrub_start); + +void scrub_stop(struct lustre_scrub *scrub) +{ + struct ptlrpc_thread *thread = &scrub->os_thread; + struct l_wait_info lwi = { 0 }; + + /* 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); + l_wait_event(thread->t_ctl_waitq, + thread_is_stopped(thread), + &lwi); + /* 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); + } + spin_unlock(&scrub->os_lock); +} +EXPORT_SYMBOL(scrub_stop); + +const char *scrub_status_names[] = { + "init", + "scanning", + "completed", + "failed", + "stopped", + "paused", + "crashed", + NULL +}; + +const char *scrub_flags_names[] = { + "recreated", + "inconsistent", + "auto", + "upgrade", + NULL +}; + +const char *scrub_param_names[] = { + "failout", + "dryrun", + NULL +}; + +static void scrub_bits_dump(struct seq_file *m, int bits, const char *names[], + const char *prefix) +{ + int flag; + int i; + + seq_printf(m, "%s:%c", prefix, bits != 0 ? ' ' : '\n'); + + for (i = 0, flag = 1; bits != 0; i++, flag = 1 << i) { + if (flag & bits) { + bits &= ~flag; + seq_printf(m, "%s%c", names[i], + bits != 0 ? ',' : '\n'); + } + } +} + +static void scrub_time_dump(struct seq_file *m, __u64 time, const char *prefix) +{ + if (time != 0) + seq_printf(m, "%s: %llu seconds\n", prefix, + cfs_time_current_sec() - time); + else + seq_printf(m, "%s: N/A\n", prefix); +} + +static void scrub_pos_dump(struct seq_file *m, __u64 pos, const char *prefix) +{ + if (pos != 0) + seq_printf(m, "%s: %llu\n", prefix, pos); + else + seq_printf(m, "%s: N/A\n", prefix); +} + +void scrub_dump(struct seq_file *m, struct lustre_scrub *scrub) +{ + struct scrub_file *sf = &scrub->os_file; + __u64 checked; + __u64 speed; + + down_read(&scrub->os_rwsem); + seq_printf(m, "name: OI_scrub\n" + "magic: 0x%x\n" + "oi_files: %d\n" + "status: %s\n", + sf->sf_magic, (int)sf->sf_oi_count, + scrub_status_names[sf->sf_status]); + + scrub_bits_dump(m, sf->sf_flags, scrub_flags_names, "flags"); + + scrub_bits_dump(m, sf->sf_param, scrub_param_names, "param"); + + scrub_time_dump(m, sf->sf_time_last_complete, + "time_since_last_completed"); + + scrub_time_dump(m, sf->sf_time_latest_start, + "time_since_latest_start"); + + scrub_time_dump(m, sf->sf_time_last_checkpoint, + "time_since_last_checkpoint"); + + scrub_pos_dump(m, sf->sf_pos_latest_start, + "latest_start_position"); + + scrub_pos_dump(m, sf->sf_pos_last_checkpoint, + "last_checkpoint_position"); + + scrub_pos_dump(m, sf->sf_pos_first_inconsistent, + "first_failure_position"); + + checked = sf->sf_items_checked + scrub->os_new_checked; + seq_printf(m, "checked: %llu\n" + "%s: %llu\n" + "failed: %llu\n" + "prior_%s: %llu\n" + "noscrub: %llu\n" + "igif: %llu\n" + "success_count: %u\n", + checked, + sf->sf_param & SP_DRYRUN ? "inconsistent" : "updated", + sf->sf_items_updated, sf->sf_items_failed, + sf->sf_param & SP_DRYRUN ? "inconsistent" : "updated", + sf->sf_items_updated_prior, sf->sf_items_noscrub, + sf->sf_items_igif, sf->sf_success_count); + + speed = checked; + if (thread_is_running(&scrub->os_thread)) { + cfs_duration_t duration = cfs_time_current() - + scrub->os_time_last_checkpoint; + __u64 new_checked = msecs_to_jiffies(scrub->os_new_checked * + MSEC_PER_SEC); + __u32 rtime = sf->sf_run_time + + cfs_duration_sec(duration + HALF_SEC); + + if (duration != 0) + do_div(new_checked, duration); + if (rtime != 0) + do_div(speed, rtime); + seq_printf(m, "run_time: %u seconds\n" + "average_speed: %llu objects/sec\n" + "real-time_speed: %llu objects/sec\n" + "current_position: %llu\n" + "scrub_in_prior: %s\n" + "scrub_full_speed: %s\n" + "partial_scan: %s\n", + rtime, speed, new_checked, scrub->os_pos_current, + scrub->os_in_prior ? "yes" : "no", + scrub->os_full_speed ? "yes" : "no", + scrub->os_partial_scan ? "yes" : "no"); + } else { + if (sf->sf_run_time != 0) + do_div(speed, sf->sf_run_time); + seq_printf(m, "run_time: %u seconds\n" + "average_speed: %llu objects/sec\n" + "real-time_speed: N/A\n" + "current_position: N/A\n", + sf->sf_run_time, speed); + } + + up_read(&scrub->os_rwsem); +} +EXPORT_SYMBOL(scrub_dump); diff --git a/lustre/osd-ldiskfs/osd_handler.c b/lustre/osd-ldiskfs/osd_handler.c index 87a07d4..84edec75 100644 --- a/lustre/osd-ldiskfs/osd_handler.c +++ b/lustre/osd-ldiskfs/osd_handler.c @@ -330,11 +330,20 @@ static struct lu_object *osd_object_alloc(const struct lu_env *env, OBD_ALLOC_PTR(mo); if (mo != NULL) { struct lu_object *l; - - l = &mo->oo_dt.do_lu; - dt_object_init(&mo->oo_dt, NULL, d); + struct lu_object_header *h; + + l = &mo->oo_dt.do_lu; + h = &osd_dev(d)->od_scrub.os_scrub.os_obj_header; + if (unlikely(fid_is_zero(&h->loh_fid))) { + /* For the OI_scrub object during OSD device init. */ + lu_object_header_init(h); + lu_object_init(l, h, d); + lu_object_add_top(h, l); + } else { + dt_object_init(&mo->oo_dt, NULL, d); + } mo->oo_dt.do_ops = &osd_obj_ops; - l->lo_ops = &osd_lu_obj_ops; + l->lo_ops = &osd_lu_obj_ops; init_rwsem(&mo->oo_sem); init_rwsem(&mo->oo_ext_idx_sem); spin_lock_init(&mo->oo_guard); @@ -612,7 +621,8 @@ check_oi: } if (IS_ERR(inode)) { - if (dev->od_scrub.os_file.sf_flags & SF_INCONSISTENT) + if (dev->od_scrub.os_scrub.os_file.sf_flags & + SF_INCONSISTENT) /* It still can be the case 2, but we cannot * distinguish it from the case 1. So return * -EREMCHG to block current operation until @@ -979,7 +989,7 @@ static int osd_fid_lookup(const struct lu_env *env, struct osd_object *obj, struct osd_idmap_cache *oic; struct osd_inode_id *id; struct inode *inode = NULL; - struct osd_scrub *scrub; + struct lustre_scrub *scrub; struct scrub_file *sf; __u32 flags = SS_CLEAR_DRYRUN | SS_CLEAR_FAILOUT | SS_AUTO_FULL; __u32 saved_ino; @@ -996,7 +1006,7 @@ static int osd_fid_lookup(const struct lu_env *env, struct osd_object *obj, LASSERTF(fid_is_sane(fid) || fid_is_idif(fid), DFID"\n", PFID(fid)); dev = osd_dev(ldev); - scrub = &dev->od_scrub; + scrub = &dev->od_scrub.os_scrub; sf = &scrub->os_file; info = osd_oti_get(env); LASSERT(info); @@ -1123,7 +1133,7 @@ trigger: } join: - rc1 = osd_scrub_start(dev, flags); + rc1 = osd_scrub_start(env, dev, flags); LCONSOLE_WARN("%s: trigger OI scrub by RPC for the " DFID" with flags " "0x%x, rc = %d\n", osd_name(dev), PFID(fid), flags, rc1); if (rc1 && rc1 != -EALREADY) @@ -1279,7 +1289,14 @@ static int osd_object_init(const struct lu_env *env, struct lu_object *l, } result = osd_fid_lookup(env, obj, lu_object_fid(l), conf); - obj->oo_dt.do_body_ops = &osd_body_ops_new; + if (unlikely(l->lo_header == + &osd_obj2dev(obj)->od_scrub.os_scrub.os_obj_header)) { + /* For the OI_scrub object during OSD device init. */ + l->lo_header->loh_attr |= LOHA_EXISTS; + obj->oo_dt.do_body_ops = &osd_body_ops; + } else { + obj->oo_dt.do_body_ops = &osd_body_ops_new; + } if (result == 0 && obj->oo_inode != NULL) { struct osd_thread_info *oti = osd_oti_get(env); struct lustre_ost_attrs *loa = &oti->oti_ost_attrs; @@ -1438,15 +1455,22 @@ static void osd_oxc_fini(struct osd_object *obj) */ static void osd_object_free(const struct lu_env *env, struct lu_object *l) { - struct osd_object *obj = osd_obj(l); + struct osd_object *obj = osd_obj(l); + struct lu_object_header *h = NULL; - LINVRNT(osd_invariant(obj)); + LINVRNT(osd_invariant(obj)); + + if (unlikely(l->lo_header == + &osd_obj2dev(obj)->od_scrub.os_scrub.os_obj_header)) + h = l->lo_header; osd_oxc_fini(obj); - dt_object_fini(&obj->oo_dt); - if (obj->oo_hl_head != NULL) - ldiskfs_htree_lock_head_free(obj->oo_hl_head); - OBD_FREE_PTR(obj); + dt_object_fini(&obj->oo_dt); + if (obj->oo_hl_head != NULL) + ldiskfs_htree_lock_head_free(obj->oo_hl_head); + OBD_FREE_PTR(obj); + if (unlikely(h)) + lu_object_header_fini(h); } /* @@ -2659,7 +2683,8 @@ static int osd_attr_set(const struct lu_env *env, osd_trans_exec_op(env, handle, OSD_OT_ATTR_SET); - if (OBD_FAIL_CHECK(OBD_FAIL_OSD_FID_MAPPING)) { + if (OBD_FAIL_CHECK(OBD_FAIL_OSD_FID_MAPPING) && + !osd_obj2dev(obj)->od_is_ost) { struct osd_thread_info *oti = osd_oti_get(env); const struct lu_fid *fid0 = lu_object_fid(&dt->do_lu); struct lu_fid *fid1 = &oti->oti_fid; @@ -4974,11 +4999,11 @@ static int osd_consistency_check(struct osd_thread_info *oti, struct osd_device *dev, struct osd_idmap_cache *oic) { - struct osd_scrub *scrub = &dev->od_scrub; + struct lustre_scrub *scrub = &dev->od_scrub.os_scrub; struct lu_fid *fid = &oic->oic_fid; struct osd_inode_id *id = &oic->oic_lid; struct inode *inode = NULL; - int once = 0; + int once = 0; bool insert; int rc; ENTRY; @@ -4986,6 +5011,9 @@ osd_consistency_check(struct osd_thread_info *oti, struct osd_device *dev, if (!fid_is_norm(fid) && !fid_is_igif(fid)) RETURN(0); + if (dev->od_noscrub && !thread_is_running(&scrub->os_thread)) + RETURN(0); + if (scrub->os_pos_current > id->oii_ino) RETURN(0); @@ -5048,8 +5076,8 @@ trigger: } if (!dev->od_noscrub && ++once == 1) { - rc = osd_scrub_start(dev, SS_AUTO_PARTIAL | SS_CLEAR_DRYRUN | - SS_CLEAR_FAILOUT); + rc = osd_scrub_start(oti->oti_env, dev, SS_AUTO_PARTIAL | + SS_CLEAR_DRYRUN | SS_CLEAR_FAILOUT); CDEBUG(D_LFSCK | D_CONSOLE | D_WARNING, "%s: trigger partial OI scrub for RPC inconsistency " "checking FID "DFID": rc = %d\n", @@ -5300,8 +5328,11 @@ static int osd_ea_lookup_rec(const struct lu_env *env, struct osd_object *obj, osd_add_oi_cache(osd_oti_get(env), osd_obj2dev(obj), id, fid); rc = osd_consistency_check(oti, dev, oic); - if (rc != 0) + if (rc == -ENOENT) fid_zero(&oic->oic_fid); + else + /* Other error should not affect lookup result. */ + rc = 0; } else { rc = PTR_ERR(bh); } @@ -6339,7 +6370,7 @@ again: ent->oied_namelen); if (rc == -ENOENT || (rc == -ENODATA && - !(dev->od_scrub.os_file.sf_flags & SF_UPGRADE))) { + !(dev->od_scrub.os_scrub.os_file.sf_flags & SF_UPGRADE))) { /* linkEA does not recognize the dirent entry, * it may because the dirent entry corruption * and points to other's inode. */ @@ -6832,6 +6863,7 @@ static int osd_shutdown(const struct lu_env *env, struct osd_device *o) } osd_fid_fini(env, o); + osd_scrub_cleanup(env, o); RETURN(0); } @@ -7052,7 +7084,6 @@ static struct lu_device *osd_device_fini(const struct lu_env *env, osd_shutdown(env, o); osd_procfs_fini(o); - osd_scrub_cleanup(env, o); osd_obj_map_fini(o); osd_umount(env, o); diff --git a/lustre/osd-ldiskfs/osd_internal.h b/lustre/osd-ldiskfs/osd_internal.h index c0bf3e8..768d905 100644 --- a/lustre/osd-ldiskfs/osd_internal.h +++ b/lustre/osd-ldiskfs/osd_internal.h @@ -189,8 +189,8 @@ int osd_ldiskfs_add_entry(struct osd_thread_info *info, struct osd_device *osd, #define OSD_OTABLE_IT_CACHE_MASK (~(OSD_OTABLE_IT_CACHE_SIZE - 1)) struct osd_inconsistent_item { - /* link into osd_scrub::os_inconsistent_items, - * protected by osd_scrub::os_lock. */ + /* link into lustre_scrub::os_inconsistent_items, + * protected by lustre_scrub::os_lock. */ struct list_head oii_list; /* The right FID <=> ino#/gen mapping. */ @@ -209,10 +209,10 @@ struct osd_otable_cache { int ooc_consumer_idx; /* How many items in ooc_cache. */ - int ooc_cached_items; + __u64 ooc_cached_items; /* Position for up layer LFSCK iteration pre-loading. */ - __u32 ooc_pos_preload; + __u64 ooc_pos_preload; }; struct osd_otable_it { @@ -702,17 +702,16 @@ int osd_obj_spec_update(struct osd_thread_info *info, struct osd_device *osd, const struct lu_fid *fid, const struct osd_inode_id *id, handle_t *th); -void osd_scrub_file_reset(struct osd_scrub *scrub, __u8 *uuid, __u64 flags); -int osd_scrub_file_store(struct osd_scrub *scrub); char *osd_lf_fid2name(const struct lu_fid *fid); -int osd_scrub_start(struct osd_device *dev, __u32 flags); +int osd_scrub_start(const struct lu_env *env, struct osd_device *dev, + __u32 flags); int osd_scrub_setup(const struct lu_env *env, struct osd_device *dev); void osd_scrub_cleanup(const struct lu_env *env, struct osd_device *dev); int osd_oii_insert(struct osd_device *dev, struct osd_idmap_cache *oic, int insert); int osd_oii_lookup(struct osd_device *dev, const struct lu_fid *fid, struct osd_inode_id *id); -int osd_scrub_dump(struct seq_file *m, struct osd_device *dev); +void osd_scrub_dump(struct seq_file *m, struct osd_device *dev); int osd_fld_lookup(const struct lu_env *env, struct osd_device *osd, u64 seq, struct lu_seq_range *range); diff --git a/lustre/osd-ldiskfs/osd_lproc.c b/lustre/osd-ldiskfs/osd_lproc.c index 5a3c703..bbd5779 100644 --- a/lustre/osd-ldiskfs/osd_lproc.c +++ b/lustre/osd-ldiskfs/osd_lproc.c @@ -523,7 +523,8 @@ static int ldiskfs_osd_oi_scrub_seq_show(struct seq_file *m, void *data) if (unlikely(dev->od_mnt == NULL)) return -EINPROGRESS; - return osd_scrub_dump(m, dev); + osd_scrub_dump(m, dev); + return 0; } LPROC_SEQ_FOPS_RO(ldiskfs_osd_oi_scrub); diff --git a/lustre/osd-ldiskfs/osd_oi.c b/lustre/osd-ldiskfs/osd_oi.c index d46763d..56309f4 100644 --- a/lustre/osd-ldiskfs/osd_oi.c +++ b/lustre/osd-ldiskfs/osd_oi.c @@ -50,19 +50,16 @@ /* fid_cpu_to_be() */ #include #include +#include #include "osd_oi.h" /* osd_lookup(), struct osd_thread_info */ #include "osd_internal.h" -#include "osd_scrub.h" -static unsigned int osd_oi_count = OSD_OI_FID_NR; +unsigned int osd_oi_count = OSD_OI_FID_NR; module_param(osd_oi_count, int, 0444); MODULE_PARM_DESC(osd_oi_count, "Number of Object Index containers to be created, it's only valid for new filesystem."); -/** to serialize concurrent OI index initialization */ -static struct mutex oi_init_lock; - static struct dt_index_features oi_feat = { .dif_flags = DT_IND_UPDATE, .dif_recsize_min = sizeof(struct osd_inode_id), @@ -122,6 +119,9 @@ static int osd_oi_index_create_one(struct osd_thread_info *info, return PTR_ERR(inode); } + if (osd->od_dt_dev.dd_rdonly) + RETURN(-EROFS); + jh = osd_journal_start_sb(sb, LDISKFS_HT_MISC, 100); if (IS_ERR(jh)) return PTR_ERR(jh); @@ -224,12 +224,16 @@ static int osd_oi_open(struct osd_thread_info *info, struct osd_device *osd, if (IS_ERR(inode)) RETURN(PTR_ERR(inode)); - /* 'What the @fid is' is not imporatant, because these objects - * have no OI mappings, and only are visible inside the OSD.*/ - lu_igif_build(&info->oti_fid, inode->i_ino, inode->i_generation); - rc = osd_ea_fid_set(info, inode, &info->oti_fid, LMAC_NOT_IN_OI, 0); - if (rc != 0) - GOTO(out_inode, rc); + if (!osd->od_dt_dev.dd_rdonly) { + /* 'What the @fid is' is not imporatant, because these objects + * have no OI mappings, and only are visible inside the OSD.*/ + lu_igif_build(&info->oti_fid, inode->i_ino, + inode->i_generation); + rc = osd_ea_fid_set(info, inode, &info->oti_fid, + LMAC_NOT_IN_OI, 0); + if (rc) + GOTO(out_inode, rc); + } OBD_ALLOC_PTR(oi); if (oi == NULL) @@ -280,7 +284,7 @@ static int osd_oi_table_open(struct osd_thread_info *info, struct osd_device *osd, struct osd_oi **oi_table, unsigned oi_count, bool create) { - struct scrub_file *sf = &osd->od_scrub.os_file; + struct scrub_file *sf = &osd->od_scrub.os_scrub.os_file; int count = 0; int rc = 0; int i; @@ -354,7 +358,10 @@ static int osd_remove_ois(struct osd_thread_info *info, struct osd_device *osd) int rc; int i; - for (i = 0; i < osd->od_scrub.os_file.sf_oi_count; i++) { + if (osd->od_dt_dev.dd_rdonly) + RETURN(-EROFS); + + for (i = 0; i < OSD_OI_FID_NR_MAX; i++) { namelen = snprintf(name, sizeof(name), "%s.%d", OSD_OI_NAME_BASE, i); rc = osd_remove_oi_one(osd_sb(osd)->s_root, name, namelen); @@ -377,42 +384,63 @@ static int osd_remove_ois(struct osd_thread_info *info, struct osd_device *osd) int osd_oi_init(struct osd_thread_info *info, struct osd_device *osd, bool restored) { - struct osd_scrub *scrub = &osd->od_scrub; + struct lustre_scrub *scrub = &osd->od_scrub.os_scrub; struct scrub_file *sf = &scrub->os_file; - struct osd_oi **oi; - int rc; + struct osd_oi **oi; + int count; + int rc; ENTRY; + if (unlikely(sf->sf_oi_count & (sf->sf_oi_count - 1)) != 0) { + LCONSOLE_WARN("%s: Invalid OI count in scrub file %d\n", + osd_dev2name(osd), sf->sf_oi_count); + sf->sf_oi_count = 0; + } + if (restored) { rc = osd_remove_ois(info, osd); - if (rc != 0) - return rc; + if (rc) + RETURN(rc); } OBD_ALLOC(oi, sizeof(*oi) * OSD_OI_FID_NR_MAX); if (oi == NULL) RETURN(-ENOMEM); - mutex_lock(&oi_init_lock); /* try to open existing multiple OIs first */ - rc = osd_oi_table_open(info, osd, oi, sf->sf_oi_count, false); - if (rc < 0) - GOTO(out, rc); - - if (rc > 0) { - if (rc == sf->sf_oi_count || sf->sf_oi_count == 0) - GOTO(out, rc); + count = osd_oi_table_open(info, osd, oi, sf->sf_oi_count, false); + if (count < 0) + GOTO(out, rc = count); + + if (count > 0) { + if (count == sf->sf_oi_count) + GOTO(out, rc = count); + + if (sf->sf_oi_count == 0) { + if (likely((count & (count - 1)) == 0)) + GOTO(out, rc = count); + + LCONSOLE_WARN("%s: invalid oi count %d, remove them, " + "then set it to %d\n", osd_dev2name(osd), + count, osd_oi_count); + osd_oi_table_put(info, oi, count); + rc = osd_remove_ois(info, osd); + if (rc) + GOTO(out, rc); + + sf->sf_oi_count = osd_oi_count; + } - osd_scrub_file_reset(scrub, - LDISKFS_SB(osd_sb(osd))->s_es->s_uuid, - SF_RECREATED); - osd_oi_count = sf->sf_oi_count; + scrub_file_reset(scrub, LDISKFS_SB(osd_sb(osd))->s_es->s_uuid, + SF_RECREATED); + count = sf->sf_oi_count; goto create; } /* if previous failed then try found single OI from old filesystem */ rc = osd_oi_open(info, osd, OSD_OI_NAME_BASE, &oi[0], false); if (rc == 0) { /* found single OI from old filesystem */ + count = 1; ldiskfs_clear_bit(0, sf->sf_oi_bitmap); if (sf->sf_success_count == 0) /* XXX: There is one corner case that if the OI_scrub @@ -425,9 +453,9 @@ int osd_oi_init(struct osd_thread_info *info, struct osd_device *osd, * and restored after former upgrading from 1.8 * to 2.x. Fortunately, the osd_fid_lookup()can * verify the inode to decrease the risk. */ - osd_scrub_file_reset(scrub, - LDISKFS_SB(osd_sb(osd))->s_es->s_uuid, - SF_UPGRADE); + scrub_file_reset(scrub, + LDISKFS_SB(osd_sb(osd))->s_es->s_uuid, + SF_UPGRADE); GOTO(out, rc = 1); } else if (rc != -ENOENT) { CERROR("%s: can't open %s: rc = %d\n", @@ -438,25 +466,26 @@ int osd_oi_init(struct osd_thread_info *info, struct osd_device *osd, if (sf->sf_oi_count > 0) { int i; + count = sf->sf_oi_count; memset(sf->sf_oi_bitmap, 0, SCRUB_OI_BITMAP_SIZE); - for (i = 0; i < osd_oi_count; i++) + for (i = 0; i < count; i++) ldiskfs_set_bit(i, sf->sf_oi_bitmap); - osd_scrub_file_reset(scrub, - LDISKFS_SB(osd_sb(osd))->s_es->s_uuid, - SF_RECREATED); + scrub_file_reset(scrub, LDISKFS_SB(osd_sb(osd))->s_es->s_uuid, + SF_RECREATED); + } else { + count = sf->sf_oi_count = osd_oi_count; } - sf->sf_oi_count = osd_oi_count; create: - rc = osd_scrub_file_store(scrub); + rc = scrub_file_store(info->oti_env, scrub); if (rc < 0) { - osd_oi_table_put(info, oi, sf->sf_oi_count); + osd_oi_table_put(info, oi, count); GOTO(out, rc); } /* No OIs exist, new filesystem, create OI objects */ - rc = osd_oi_table_open(info, osd, oi, osd_oi_count, true); - LASSERT(ergo(rc >= 0, rc == osd_oi_count)); + rc = osd_oi_table_open(info, osd, oi, count, true); + LASSERT(ergo(rc >= 0, rc == count)); GOTO(out, rc); @@ -464,14 +493,15 @@ out: if (rc < 0) { OBD_FREE(oi, sizeof(*oi) * OSD_OI_FID_NR_MAX); } else { - LASSERT((rc & (rc - 1)) == 0); + LASSERTF((rc & (rc - 1)) == 0, "Invalid OI count %d\n", rc); + osd->od_oi_table = oi; osd->od_oi_count = rc; if (sf->sf_oi_count != rc) { sf->sf_oi_count = rc; - rc = osd_scrub_file_store(scrub); + rc = scrub_file_store(info->oti_env, scrub); if (rc < 0) { - osd_oi_table_put(info, oi, sf->sf_oi_count); + osd_oi_table_put(info, oi, count); OBD_FREE(oi, sizeof(*oi) * OSD_OI_FID_NR_MAX); } } else { @@ -479,20 +509,19 @@ out: } } - mutex_unlock(&oi_init_lock); return rc; } void osd_oi_fini(struct osd_thread_info *info, struct osd_device *osd) { - if (unlikely(osd->od_oi_table == NULL)) + if (unlikely(!osd->od_oi_table)) return; - osd_oi_table_put(info, osd->od_oi_table, osd->od_oi_count); + osd_oi_table_put(info, osd->od_oi_table, osd->od_oi_count); - OBD_FREE(osd->od_oi_table, - sizeof(*(osd->od_oi_table)) * OSD_OI_FID_NR_MAX); - osd->od_oi_table = NULL; + OBD_FREE(osd->od_oi_table, + sizeof(*(osd->od_oi_table)) * OSD_OI_FID_NR_MAX); + osd->od_oi_table = NULL; } static inline int fid_is_fs_root(const struct lu_fid *fid) @@ -826,15 +855,14 @@ int osd_oi_update(struct osd_thread_info *info, struct osd_device *osd, int osd_oi_mod_init(void) { - if (osd_oi_count == 0 || osd_oi_count > OSD_OI_FID_NR_MAX) - osd_oi_count = OSD_OI_FID_NR; + if (osd_oi_count == 0 || osd_oi_count > OSD_OI_FID_NR_MAX) + osd_oi_count = OSD_OI_FID_NR; - if ((osd_oi_count & (osd_oi_count - 1)) != 0) { - LCONSOLE_WARN("Round up oi_count %d to power2 %d\n", - osd_oi_count, size_roundup_power2(osd_oi_count)); - osd_oi_count = size_roundup_power2(osd_oi_count); - } + if ((osd_oi_count & (osd_oi_count - 1)) != 0) { + LCONSOLE_WARN("Round up oi_count %d to power2 %d\n", + osd_oi_count, size_roundup_power2(osd_oi_count)); + osd_oi_count = size_roundup_power2(osd_oi_count); + } - mutex_init(&oi_init_lock); - return 0; + return 0; } diff --git a/lustre/osd-ldiskfs/osd_oi.h b/lustre/osd-ldiskfs/osd_oi.h index 8bced80..697b81b 100644 --- a/lustre/osd-ldiskfs/osd_oi.h +++ b/lustre/osd-ldiskfs/osd_oi.h @@ -53,10 +53,9 @@ #include #include -#define OSD_OI_FID_NR (1UL << OSD_OI_FID_OID_BITS) -#define OSD_OI_FID_NR_MAX (1UL << OSD_OI_FID_OID_BITS_MAX) - -#define OSD_OII_NOGEN (0) +#define OSD_OI_FID_OID_BITS 6 +#define OSD_OI_FID_NR (1UL << OSD_OI_FID_OID_BITS) +#define OSD_OII_NOGEN (0) struct lu_fid; struct osd_thread_info; @@ -134,6 +133,8 @@ enum oi_check_flags { OI_KNOWN_ON_OST = 0x00000002, }; +extern unsigned int osd_oi_count; + int osd_oi_mod_init(void); int osd_oi_init(struct osd_thread_info *info, struct osd_device *osd, bool restored); diff --git a/lustre/osd-ldiskfs/osd_scrub.c b/lustre/osd-ldiskfs/osd_scrub.c index e25b521..358edc8 100644 --- a/lustre/osd-ldiskfs/osd_scrub.c +++ b/lustre/osd-ldiskfs/osd_scrub.c @@ -6,16 +6,16 @@ * 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. - + * + * 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 LICENSE 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 + * version 2 along with this program; If not, see + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ @@ -42,50 +42,21 @@ #include #include #include +#include +#include #include "osd_internal.h" #include "osd_oi.h" #include "osd_scrub.h" -#define HALF_SEC msecs_to_jiffies(MSEC_PER_SEC >> 1) - #define OSD_OTABLE_MAX_HASH 0x00000000ffffffffULL -#define SCRUB_NEXT_BREAK 1 /* exit current loop and process next group */ -#define SCRUB_NEXT_CONTINUE 2 /* skip current object and process next bit */ -#define SCRUB_NEXT_EXIT 3 /* exit all the loops */ -#define SCRUB_NEXT_WAIT 4 /* wait for free cache slot */ -#define SCRUB_NEXT_CRASH 5 /* simulate system crash during OI scrub */ -#define SCRUB_NEXT_FATAL 6 /* simulate failure during OI scrub */ -#define SCRUB_NEXT_NOSCRUB 7 /* new created object, no scrub on it */ -#define SCRUB_NEXT_NOLMA 8 /* the inode has no FID-in-LMA */ -#define SCRUB_NEXT_OSTOBJ 9 /* for OST-object */ -#define SCRUB_NEXT_OSTOBJ_OLD 10 /* old OST-object, no LMA or no FID-on-OST - * flags in LMA */ - -/* misc functions */ - -static inline struct osd_device *osd_scrub2dev(struct osd_scrub *scrub) -{ - return container_of0(scrub, struct osd_device, od_scrub); -} - -static inline struct super_block *osd_scrub2sb(struct osd_scrub *scrub) -{ - return osd_sb(osd_scrub2dev(scrub)); -} - -static inline int osd_scrub_has_window(struct osd_scrub *scrub, +static inline int osd_scrub_has_window(struct lustre_scrub *scrub, struct osd_otable_cache *ooc) { return scrub->os_pos_current < ooc->ooc_pos_preload + SCRUB_WINDOW_SIZE; } -static inline const char *osd_scrub2name(struct osd_scrub *scrub) -{ - return osd_dev2name(osd_scrub2dev(scrub)); -} - /** * update/insert/delete the specified OI mapping (@fid @id) according to the ops * @@ -104,7 +75,7 @@ static int osd_scrub_refresh_mapping(struct osd_thread_info *info, int rc; ENTRY; - if (dev->od_scrub.os_file.sf_param & SP_DRYRUN && !force) + if (dev->od_scrub.os_scrub.os_file.sf_param & SP_DRYRUN && !force) RETURN(0); /* DTO_INDEX_INSERT is enough for other two ops: @@ -188,185 +159,6 @@ static int osd_scrub_refresh_mapping(struct osd_thread_info *info, RETURN(rc); } -/* OI_scrub file ops */ - -static void osd_scrub_file_to_cpu(struct scrub_file *des, - struct scrub_file *src) -{ - memcpy(des->sf_uuid, src->sf_uuid, 16); - 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); - des->sf_param = le16_to_cpu(src->sf_param); - des->sf_time_last_complete = - le64_to_cpu(src->sf_time_last_complete); - des->sf_time_latest_start = - le64_to_cpu(src->sf_time_latest_start); - des->sf_time_last_checkpoint = - le64_to_cpu(src->sf_time_last_checkpoint); - des->sf_pos_latest_start = - le64_to_cpu(src->sf_pos_latest_start); - des->sf_pos_last_checkpoint = - le64_to_cpu(src->sf_pos_last_checkpoint); - des->sf_pos_first_inconsistent = - le64_to_cpu(src->sf_pos_first_inconsistent); - des->sf_items_checked = - le64_to_cpu(src->sf_items_checked); - des->sf_items_updated = - le64_to_cpu(src->sf_items_updated); - des->sf_items_failed = - le64_to_cpu(src->sf_items_failed); - des->sf_items_updated_prior = - le64_to_cpu(src->sf_items_updated_prior); - des->sf_run_time = le32_to_cpu(src->sf_run_time); - des->sf_success_count = le32_to_cpu(src->sf_success_count); - des->sf_oi_count = le16_to_cpu(src->sf_oi_count); - des->sf_internal_flags = le16_to_cpu(src->sf_internal_flags); - memcpy(des->sf_oi_bitmap, src->sf_oi_bitmap, SCRUB_OI_BITMAP_SIZE); -} - -static void osd_scrub_file_to_le(struct scrub_file *des, - struct scrub_file *src) -{ - memcpy(des->sf_uuid, src->sf_uuid, 16); - 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); - des->sf_param = cpu_to_le16(src->sf_param); - des->sf_time_last_complete = - cpu_to_le64(src->sf_time_last_complete); - des->sf_time_latest_start = - cpu_to_le64(src->sf_time_latest_start); - des->sf_time_last_checkpoint = - cpu_to_le64(src->sf_time_last_checkpoint); - des->sf_pos_latest_start = - cpu_to_le64(src->sf_pos_latest_start); - des->sf_pos_last_checkpoint = - cpu_to_le64(src->sf_pos_last_checkpoint); - des->sf_pos_first_inconsistent = - cpu_to_le64(src->sf_pos_first_inconsistent); - des->sf_items_checked = - cpu_to_le64(src->sf_items_checked); - des->sf_items_updated = - cpu_to_le64(src->sf_items_updated); - des->sf_items_failed = - cpu_to_le64(src->sf_items_failed); - des->sf_items_updated_prior = - cpu_to_le64(src->sf_items_updated_prior); - des->sf_run_time = cpu_to_le32(src->sf_run_time); - des->sf_success_count = cpu_to_le32(src->sf_success_count); - des->sf_oi_count = cpu_to_le16(src->sf_oi_count); - des->sf_internal_flags = cpu_to_le16(src->sf_internal_flags); - memcpy(des->sf_oi_bitmap, src->sf_oi_bitmap, SCRUB_OI_BITMAP_SIZE); -} - -static void osd_scrub_file_init(struct osd_scrub *scrub, __u8 *uuid) -{ - struct scrub_file *sf = &scrub->os_file; - - memset(sf, 0, sizeof(*sf)); - memcpy(sf->sf_uuid, uuid, 16); - sf->sf_magic = SCRUB_MAGIC_V1; - sf->sf_status = SS_INIT; -} - -void osd_scrub_file_reset(struct osd_scrub *scrub, __u8 *uuid, __u64 flags) -{ - struct scrub_file *sf = &scrub->os_file; - - CDEBUG(D_LFSCK, "%s: reset OI scrub file, old flags = " - "%#llx, add flags = %#llx\n", - osd_scrub2name(scrub), sf->sf_flags, flags); - - memcpy(sf->sf_uuid, uuid, 16); - sf->sf_status = SS_INIT; - sf->sf_flags |= flags; - sf->sf_flags &= ~SF_AUTO; - sf->sf_run_time = 0; - sf->sf_time_latest_start = 0; - sf->sf_time_last_checkpoint = 0; - sf->sf_pos_latest_start = 0; - sf->sf_pos_last_checkpoint = 0; - sf->sf_pos_first_inconsistent = 0; - sf->sf_items_checked = 0; - sf->sf_items_updated = 0; - sf->sf_items_failed = 0; - if (!scrub->os_in_join) - sf->sf_items_updated_prior = 0; - - sf->sf_items_noscrub = 0; - sf->sf_items_igif = 0; -} - -static int osd_scrub_file_load(struct osd_scrub *scrub) -{ - loff_t pos = 0; - int len = sizeof(scrub->os_file_disk); - int rc; - - rc = osd_ldiskfs_read(scrub->os_inode, &scrub->os_file_disk, len, &pos); - if (rc == len) { - struct scrub_file *sf = &scrub->os_file; - - osd_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", osd_scrub2name(scrub), - sf->sf_magic, SCRUB_MAGIC_V1); - /* Process it as new scrub file. */ - rc = -ENOENT; - } else { - rc = 0; - } - } else if (rc != 0) { - CDEBUG(D_LFSCK, "%s: fail to load scrub file, " - "expected = %d: rc = %d\n", - osd_scrub2name(scrub), len, rc); - if (rc > 0) - rc = -EFAULT; - } else { - /* return -ENOENT for empty scrub file case. */ - rc = -ENOENT; - } - - return rc; -} - -int osd_scrub_file_store(struct osd_scrub *scrub) -{ - struct osd_device *dev; - handle_t *jh; - loff_t pos = 0; - int len = sizeof(scrub->os_file_disk); - int credits; - int rc; - - dev = container_of0(scrub, struct osd_device, od_scrub); - credits = osd_dto_credits_noquota[DTO_WRITE_BASE] + - osd_dto_credits_noquota[DTO_WRITE_BLOCK]; - jh = osd_journal_start_sb(osd_sb(dev), LDISKFS_HT_MISC, credits); - if (IS_ERR(jh)) { - rc = PTR_ERR(jh); - CDEBUG(D_LFSCK, "%s: fail to start trans for scrub store: " - "rc = %d\n", osd_scrub2name(scrub), rc); - return rc; - } - - osd_scrub_file_to_le(&scrub->os_file_disk, &scrub->os_file); - rc = osd_ldiskfs_write_record(scrub->os_inode, &scrub->os_file_disk, - len, 0, &pos, jh); - ldiskfs_journal_stop(jh); - if (rc != 0) - CDEBUG(D_LFSCK, "%s: fail to store scrub file, " - "expected = %d: rc = %d\n", - osd_scrub2name(scrub), len, rc); - - scrub->os_time_last_checkpoint = cfs_time_current(); - scrub->os_time_next_checkpoint = scrub->os_time_last_checkpoint + - cfs_time_seconds(SCRUB_CHECKPOINT_INTERVAL); - return rc; -} - static int osd_scrub_convert_ff(struct osd_thread_info *info, struct osd_device *dev, struct inode *inode, const struct lu_fid *fid) @@ -380,7 +172,7 @@ osd_scrub_convert_ff(struct osd_thread_info *info, struct osd_device *dev, bool reset = false; ENTRY; - if (dev->od_scrub.os_file.sf_param & SP_DRYRUN) + if (dev->od_scrub.os_scrub.os_file.sf_param & SP_DRYRUN) RETURN(0); if (fid_is_idif(fid) && dev->od_index_in_idif == 0) { @@ -460,7 +252,7 @@ static int osd_scrub_check_update(struct osd_thread_info *info, struct osd_device *dev, struct osd_idmap_cache *oic, int val) { - struct osd_scrub *scrub = &dev->od_scrub; + struct lustre_scrub *scrub = &dev->od_scrub.os_scrub; struct scrub_file *sf = &scrub->os_file; struct lu_fid *fid = &oic->oic_fid; struct osd_inode_id *lid = &oic->oic_lid; @@ -653,11 +445,9 @@ out: RETURN(sf->sf_param & SP_FAILOUT ? rc : 0); } -/* OI scrub APIs */ - -static int osd_scrub_prep(struct osd_device *dev) +static int osd_scrub_prep(const struct lu_env *env, struct osd_device *dev) { - struct osd_scrub *scrub = &dev->od_scrub; + struct lustre_scrub *scrub = &dev->od_scrub.os_scrub; struct ptlrpc_thread *thread = &scrub->os_thread; struct scrub_file *sf = &scrub->os_file; __u32 flags = scrub->os_start_flags; @@ -682,7 +472,7 @@ static int osd_scrub_prep(struct osd_device *dev) } if (flags & SS_RESET) - osd_scrub_file_reset(scrub, + scrub_file_reset(scrub, LDISKFS_SB(osd_sb(dev))->s_es->s_uuid, 0); if (flags & SS_AUTO_FULL) { @@ -722,7 +512,7 @@ static int osd_scrub_prep(struct osd_device *dev) sf->sf_time_latest_start = cfs_time_current_sec(); sf->sf_time_last_checkpoint = sf->sf_time_latest_start; sf->sf_pos_last_checkpoint = sf->sf_pos_latest_start - 1; - rc = osd_scrub_file_store(scrub); + rc = scrub_file_store(env, scrub); if (rc == 0) { spin_lock(&scrub->os_lock); thread_set_flags(thread, SVC_RUNNING); @@ -734,36 +524,15 @@ static int osd_scrub_prep(struct osd_device *dev) RETURN(rc); } -static int osd_scrub_checkpoint(struct osd_scrub *scrub) -{ - struct scrub_file *sf = &scrub->os_file; - int rc; - - if (likely(cfs_time_before(cfs_time_current(), - scrub->os_time_next_checkpoint) || - scrub->os_new_checked == 0)) - return 0; - - down_write(&scrub->os_rwsem); - 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 = cfs_time_current_sec(); - sf->sf_run_time += cfs_duration_sec(cfs_time_current() + HALF_SEC - - scrub->os_time_last_checkpoint); - rc = osd_scrub_file_store(scrub); - up_write(&scrub->os_rwsem); - - return rc; -} - -static int osd_scrub_post(struct osd_scrub *scrub, int result) +static int osd_scrub_post(const struct lu_env *env, struct osd_device *dev, + int result) { + struct lustre_scrub *scrub = &dev->od_scrub.os_scrub; struct scrub_file *sf = &scrub->os_file; int rc; ENTRY; - CDEBUG(D_LFSCK, "%s: OI scrub post, result = %d\n", + CDEBUG(D_LFSCK, "%s: OI scrub post with result = %d\n", osd_scrub2name(scrub), result); down_write(&scrub->os_rwsem); @@ -777,9 +546,6 @@ static int osd_scrub_post(struct osd_scrub *scrub, int result) } sf->sf_time_last_checkpoint = cfs_time_current_sec(); if (result > 0) { - struct osd_device *dev = - container_of0(scrub, struct osd_device, od_scrub); - dev->od_igif_inoi = 1; dev->od_check_ff = 0; sf->sf_status = SS_COMPLETED; @@ -800,7 +566,7 @@ static int osd_scrub_post(struct osd_scrub *scrub, int result) } sf->sf_run_time += cfs_duration_sec(cfs_time_current() + HALF_SEC - scrub->os_time_last_checkpoint); - rc = osd_scrub_file_store(scrub); + rc = scrub_file_store(env, scrub); up_write(&scrub->os_rwsem); RETURN(rc < 0 ? rc : result); @@ -820,7 +586,7 @@ typedef int (*osd_iit_exec_policy)(struct osd_thread_info *info, struct osd_idmap_cache *oic, bool *noslot, int rc); -static int osd_iit_next(struct osd_iit_param *param, __u32 *pos) +static int osd_iit_next(struct osd_iit_param *param, __u64 *pos) { __u32 offset; @@ -927,7 +693,7 @@ static int osd_scrub_get_fid(struct osd_thread_info *info, return rc; if (!has_lma) { - if (dev->od_scrub.os_convert_igif) { + if (dev->od_scrub.os_scrub.os_convert_igif) { lu_igif_build(fid, inode->i_ino, inode->i_generation); if (scrub) @@ -1004,11 +770,11 @@ static int osd_scrub_next(struct osd_thread_info *info, struct osd_device *dev, struct osd_iit_param *param, struct osd_idmap_cache **oic, const bool noslot) { - struct osd_scrub *scrub = &dev->od_scrub; + struct lustre_scrub *scrub = &dev->od_scrub.os_scrub; struct ptlrpc_thread *thread = &scrub->os_thread; - struct lu_fid *fid; - struct osd_inode_id *lid; - int rc; + struct lu_fid *fid; + struct osd_inode_id *lid; + int rc; if (OBD_FAIL_CHECK(OBD_FAIL_OSD_SCRUB_DELAY) && cfs_fail_val > 0) { struct l_wait_info lwi; @@ -1058,7 +824,7 @@ static int osd_scrub_next(struct osd_thread_info *info, struct osd_device *dev, if (rc != 0) return rc; - *oic = &scrub->os_oic; + *oic = &dev->od_scrub.os_oic; fid = &(*oic)->oic_fid; lid = &(*oic)->oic_lid; rc = osd_iit_iget(info, dev, fid, lid, @@ -1071,7 +837,7 @@ static int osd_preload_next(struct osd_thread_info *info, struct osd_idmap_cache **oic, const bool noslot) { struct osd_otable_cache *ooc = &dev->od_otable_it->ooi_cache; - struct osd_scrub *scrub = &dev->od_scrub; + struct lustre_scrub *scrub = &dev->od_scrub.os_scrub; struct ptlrpc_thread *thread = &scrub->os_thread; int rc; @@ -1091,7 +857,7 @@ static int osd_preload_next(struct osd_thread_info *info, } static inline int -osd_scrub_wakeup(struct osd_scrub *scrub, struct osd_otable_it *it) +osd_scrub_wakeup(struct lustre_scrub *scrub, struct osd_otable_it *it) { spin_lock(&scrub->os_lock); if (osd_scrub_has_window(scrub, &it->ooi_cache) || @@ -1109,12 +875,12 @@ static int osd_scrub_exec(struct osd_thread_info *info, struct osd_device *dev, struct osd_iit_param *param, struct osd_idmap_cache *oic, bool *noslot, int rc) { - struct l_wait_info lwi = { 0 }; - struct osd_scrub *scrub = &dev->od_scrub; - struct scrub_file *sf = &scrub->os_file; - struct ptlrpc_thread *thread = &scrub->os_thread; - struct osd_otable_it *it = dev->od_otable_it; - struct osd_otable_cache *ooc = it ? &it->ooi_cache : NULL; + struct l_wait_info lwi = { 0 }; + struct lustre_scrub *scrub = &dev->od_scrub.os_scrub; + struct scrub_file *sf = &scrub->os_file; + struct ptlrpc_thread *thread = &scrub->os_thread; + struct osd_otable_it *it = dev->od_otable_it; + struct osd_otable_cache *ooc = it ? &it->ooi_cache : NULL; switch (rc) { case SCRUB_NEXT_NOSCRUB: @@ -1133,9 +899,9 @@ static int osd_scrub_exec(struct osd_thread_info *info, struct osd_device *dev, return rc; } - rc = osd_scrub_checkpoint(scrub); - if (rc != 0) { - CDEBUG(D_LFSCK, "%s: fail to checkpoint, pos = %u: " + rc = scrub_checkpoint(info->oti_env, scrub); + if (rc) { + CDEBUG(D_LFSCK, "%s: fail to checkpoint, pos = %llu: " "rc = %d\n", osd_scrub2name(scrub), scrub->os_pos_current, rc); /* Continue, as long as the scrub itself can go ahead. */ @@ -1191,10 +957,10 @@ static int osd_preload_exec(struct osd_thread_info *info, #define SCRUB_IT_ALL 1 #define SCRUB_IT_CRASH 2 -static void osd_scrub_join(struct osd_device *dev, __u32 flags, - bool inconsistent) +static void osd_scrub_join(const struct lu_env *env, struct osd_device *dev, + __u32 flags, bool inconsistent) { - struct osd_scrub *scrub = &dev->od_scrub; + struct lustre_scrub *scrub = &dev->od_scrub.os_scrub; struct ptlrpc_thread *thread = &scrub->os_thread; struct scrub_file *sf = &scrub->os_file; int rc; @@ -1215,8 +981,7 @@ static void osd_scrub_join(struct osd_device *dev, __u32 flags, sf->sf_param &= ~SP_DRYRUN; if (flags & SS_RESET) { - osd_scrub_file_reset(scrub, - LDISKFS_SB(osd_sb(dev))->s_es->s_uuid, + scrub_file_reset(scrub, LDISKFS_SB(osd_sb(dev))->s_es->s_uuid, inconsistent ? SF_INCONSISTENT : 0); sf->sf_status = SS_SCANNING; } @@ -1241,10 +1006,7 @@ static void osd_scrub_join(struct osd_device *dev, __u32 flags, sf->sf_time_latest_start = cfs_time_current_sec(); sf->sf_time_last_checkpoint = sf->sf_time_latest_start; sf->sf_pos_last_checkpoint = sf->sf_pos_latest_start - 1; - rc = osd_scrub_file_store(scrub); - if (rc != 0) - CDEBUG(D_LFSCK, "%s: fail to store scrub file when join " - "the OI scrub: rc = %d\n", osd_scrub2name(scrub), rc); + rc = scrub_file_store(env, scrub); spin_lock(&scrub->os_lock); scrub->os_waiting = 0; @@ -1256,31 +1018,33 @@ static void osd_scrub_join(struct osd_device *dev, __u32 flags, wake_up_all(&thread->t_ctl_waitq); up_write(&scrub->os_rwsem); + CDEBUG(D_LFSCK, "%s: joined in the OI scrub with flag %u: rc = %d\n", + osd_scrub2name(scrub), flags, rc); + EXIT; } static int osd_inode_iteration(struct osd_thread_info *info, struct osd_device *dev, __u32 max, bool preload) { - struct osd_scrub *scrub = &dev->od_scrub; + struct lustre_scrub *scrub = &dev->od_scrub.os_scrub; struct ptlrpc_thread *thread = &scrub->os_thread; - struct scrub_file *sf = &scrub->os_file; - osd_iit_next_policy next; - osd_iit_exec_policy exec; - __u32 *pos; - __u32 *count; + struct scrub_file *sf = &scrub->os_file; + osd_iit_next_policy next; + osd_iit_exec_policy exec; + __u64 *pos; + __u64 *count; struct osd_iit_param *param; - struct l_wait_info lwi = { 0 }; - __u32 limit = - le32_to_cpu(LDISKFS_SB(osd_sb(dev))->s_es->s_inodes_count); - int rc; - bool noslot = true; + struct l_wait_info lwi = { 0 }; + __u32 limit; + int rc; + bool noslot = true; ENTRY; if (preload) goto full; - param = &scrub->os_iit_param; + param = &dev->od_scrub.os_iit_param; memset(param, 0, sizeof(*param)); param->sb = osd_sb(dev); @@ -1305,8 +1069,8 @@ static int osd_inode_iteration(struct osd_thread_info *info, if (dev->od_full_scrub_ratio == OFSR_DIRECTLY || scrub->os_full_scrub) { - osd_scrub_join(dev, SS_AUTO_FULL | SS_RESET, - true); + osd_scrub_join(info->oti_env, dev, + SS_AUTO_FULL | SS_RESET, true); goto full; } @@ -1319,7 +1083,7 @@ static int osd_inode_iteration(struct osd_thread_info *info, * mappings during the partial scan, * then scan the device completely. */ if (used < dev->od_full_scrub_ratio) { - osd_scrub_join(dev, + osd_scrub_join(info->oti_env, dev, SS_AUTO_FULL | SS_RESET, true); goto full; } @@ -1392,6 +1156,7 @@ full: } rc = 0; + limit = le32_to_cpu(LDISKFS_SB(osd_sb(dev))->s_es->s_inodes_count); while (*pos <= limit && *count < max) { struct ldiskfs_group_desc *desc; bool next_group = false; @@ -1471,8 +1236,8 @@ out: static int osd_otable_it_preload(const struct lu_env *env, struct osd_otable_it *it) { - struct osd_device *dev = it->ooi_dev; - struct osd_scrub *scrub = &dev->od_scrub; + struct osd_device *dev = it->ooi_dev; + struct lustre_scrub *scrub = &dev->od_scrub.os_scrub; struct osd_otable_cache *ooc = &it->ooi_cache; int rc; ENTRY; @@ -1494,21 +1259,21 @@ static int osd_otable_it_preload(const struct lu_env *env, static int osd_scrub_main(void *args) { - struct lu_env env; - struct osd_device *dev = (struct osd_device *)args; - struct osd_scrub *scrub = &dev->od_scrub; + struct lu_env env; + struct osd_device *dev = (struct osd_device *)args; + struct lustre_scrub *scrub = &dev->od_scrub.os_scrub; struct ptlrpc_thread *thread = &scrub->os_thread; - int rc; + int rc; ENTRY; - rc = lu_env_init(&env, LCT_LOCAL); + rc = lu_env_init(&env, LCT_LOCAL | LCT_DT_THREAD); if (rc != 0) { CDEBUG(D_LFSCK, "%s: OI scrub fail to init env: rc = %d\n", osd_scrub2name(scrub), rc); GOTO(noenv, rc); } - rc = osd_scrub_prep(dev); + rc = osd_scrub_prep(&env, dev); if (rc != 0) { CDEBUG(D_LFSCK, "%s: OI scrub fail to scrub prep: rc = %d\n", osd_scrub2name(scrub), rc); @@ -1529,18 +1294,23 @@ static int osd_scrub_main(void *args) scrub->os_pos_current = ooc->ooc_pos_preload; } - CDEBUG(D_LFSCK, "%s: OI scrub start, flags = 0x%x, pos = %u\n", + CDEBUG(D_LFSCK, "%s: OI scrub start, flags = 0x%x, pos = %llu\n", osd_scrub2name(scrub), scrub->os_start_flags, scrub->os_pos_current); rc = osd_inode_iteration(osd_oti_get(&env), dev, ~0U, false); - if (unlikely(rc == SCRUB_IT_CRASH)) + if (unlikely(rc == SCRUB_IT_CRASH)) { + spin_lock(&scrub->os_lock); + thread_set_flags(&scrub->os_thread, SVC_STOPPING); + spin_unlock(&scrub->os_lock); GOTO(out, rc = -EINVAL); + } + GOTO(post, rc); post: - rc = osd_scrub_post(scrub, rc); - CDEBUG(D_LFSCK, "%s: OI scrub: stop, pos = %u: rc = %d\n", + rc = osd_scrub_post(&env, dev, rc); + CDEBUG(D_LFSCK, "%s: OI scrub: stop, pos = %llu: rc = %d\n", osd_scrub2name(scrub), scrub->os_pos_current, rc); out: @@ -1548,7 +1318,7 @@ out: struct osd_inconsistent_item *oii; oii = list_entry(scrub->os_inconsistent_items.next, - struct osd_inconsistent_item, oii_list); + struct osd_inconsistent_item, oii_list); list_del_init(&oii->oii_list); OBD_FREE_PTR(oii); } @@ -1602,14 +1372,6 @@ static int osd_ios_OBJECTS_scan(struct osd_thread_info *info, struct osd_device *dev, struct dentry *dentry, filldir_t filldir); -enum osd_lf_flags { - OLF_SCAN_SUBITEMS = 0x0001, - OLF_HIDE_FID = 0x0002, - OLF_SHOW_NAME = 0x0004, - OLF_NO_OI = 0x0008, - OLF_IDX_IN_FID = 0x0010, -}; - struct osd_lf_map { char *olm_name; struct lu_fid olm_fid; @@ -1793,6 +1555,7 @@ static const struct osd_lf_map osd_lf_maps[] = { /* LFSCK */ { .olm_name = LFSCK_DIR, + .olm_flags = OLF_SCAN_SUBITEMS, .olm_namelen = sizeof(LFSCK_DIR) - 1, .olm_scandir = osd_ios_general_scan, .olm_filldir = osd_ios_varfid_fill, @@ -1898,6 +1661,16 @@ static const struct osd_lf_map osd_lf_maps[] = { .olm_filldir = osd_ios_lf_fill, }, + /* hsm_actions */ + { + .olm_name = HSM_ACTIONS, + }, + + /* nodemap */ + { + .olm_name = LUSTRE_NODEMAP_NAME, + }, + { .olm_name = NULL } @@ -1914,6 +1687,7 @@ static const struct osd_lf_map osd_dl_maps[] = { }, .olm_namelen = sizeof("fid") - 1, }, + /* .lustre/lost+found */ { .olm_name = "lost+found", @@ -1923,6 +1697,7 @@ static const struct osd_lf_map osd_dl_maps[] = { }, .olm_namelen = sizeof("lost+found") - 1, }, + { .olm_name = NULL } @@ -2005,7 +1780,7 @@ osd_ios_scan_one(struct osd_thread_info *info, struct osd_device *dev, struct lustre_mdt_attrs *lma = &info->oti_ost_attrs.loa_lma; struct osd_inode_id *id = &info->oti_id; struct osd_inode_id *id2 = &info->oti_id2; - struct osd_scrub *scrub = &dev->od_scrub; + struct lustre_scrub *scrub = &dev->od_scrub.os_scrub; struct scrub_file *sf = &scrub->os_file; struct lu_fid tfid; int rc; @@ -2063,10 +1838,9 @@ osd_ios_scan_one(struct osd_thread_info *info, struct osd_device *dev, RETURN(0); if (!(sf->sf_flags & SF_INCONSISTENT)) { - osd_scrub_file_reset(scrub, - LDISKFS_SB(osd_sb(dev))->s_es->s_uuid, - SF_INCONSISTENT); - rc = osd_scrub_file_store(scrub); + scrub_file_reset(scrub, LDISKFS_SB(osd_sb(dev))->s_es->s_uuid, + SF_INCONSISTENT); + rc = scrub_file_store(info->oti_env, scrub); if (rc != 0) RETURN(rc); } @@ -2356,10 +2130,10 @@ static int osd_ios_ROOT_scan(struct osd_thread_info *info, struct osd_device *dev, struct dentry *dentry, filldir_t filldir) { - struct osd_scrub *scrub = &dev->od_scrub; - struct scrub_file *sf = &scrub->os_file; - struct dentry *child; - int rc; + struct lustre_scrub *scrub = &dev->od_scrub.os_scrub; + struct scrub_file *sf = &scrub->os_file; + struct dentry *child; + int rc; ENTRY; /* It is existing MDT0 device. We only allow the case of object without @@ -2383,11 +2157,11 @@ osd_ios_ROOT_scan(struct osd_thread_info *info, struct osd_device *dev, if (rc == -ENOENT) { /* It is 1.8 MDT device. */ if (!(sf->sf_flags & SF_UPGRADE)) { - osd_scrub_file_reset(scrub, + scrub_file_reset(scrub, LDISKFS_SB(osd_sb(dev))->s_es->s_uuid, SF_UPGRADE); sf->sf_internal_flags &= ~SIF_NO_HANDLE_OLD_FID; - rc = osd_scrub_file_store(scrub); + rc = scrub_file_store(info->oti_env, scrub); } else { rc = 0; } @@ -2431,15 +2205,15 @@ static int osd_ios_OBJECTS_scan(struct osd_thread_info *info, struct osd_device *dev, struct dentry *dentry, filldir_t filldir) { - struct osd_scrub *scrub = &dev->od_scrub; - struct scrub_file *sf = &scrub->os_file; - struct dentry *child; - int rc; + struct lustre_scrub *scrub = &dev->od_scrub.os_scrub; + struct scrub_file *sf = &scrub->os_file; + struct dentry *child; + int rc; ENTRY; if (unlikely(sf->sf_internal_flags & SIF_NO_HANDLE_OLD_FID)) { sf->sf_internal_flags &= ~SIF_NO_HANDLE_OLD_FID; - rc = osd_scrub_file_store(scrub); + rc = scrub_file_store(info->oti_env, scrub); if (rc != 0) RETURN(rc); } @@ -2564,115 +2338,39 @@ char *osd_lf_fid2name(const struct lu_fid *fid) /* OI scrub start/stop */ -static int do_osd_scrub_start(struct osd_device *dev, __u32 flags) +int osd_scrub_start(const struct lu_env *env, struct osd_device *dev, + __u32 flags) { - struct osd_scrub *scrub = &dev->od_scrub; - struct ptlrpc_thread *thread = &scrub->os_thread; - struct l_wait_info lwi = { 0 }; - struct task_struct *task; - int rc; + struct lustre_scrub *scrub = &dev->od_scrub.os_scrub; + int rc; ENTRY; if (dev->od_dt_dev.dd_rdonly) RETURN(-EROFS); - /* os_lock: sync status between stop and scrub thread */ - spin_lock(&scrub->os_lock); - -again: - if (thread_is_running(thread)) { - spin_unlock(&scrub->os_lock); - if (!(scrub->os_file.sf_flags & SF_AUTO || - scrub->os_partial_scan) || - (flags & SS_AUTO_PARTIAL)) - RETURN(-EALREADY); - - osd_scrub_join(dev, flags, false); - spin_lock(&scrub->os_lock); - if (!thread_is_running(thread)) - goto again; - - spin_unlock(&scrub->os_lock); - RETURN(0); - } - - if (unlikely(thread_is_stopping(thread))) { - spin_unlock(&scrub->os_lock); - l_wait_event(thread->t_ctl_waitq, - thread_is_stopped(thread), - &lwi); - spin_lock(&scrub->os_lock); - goto again; - } - spin_unlock(&scrub->os_lock); - - if (scrub->os_file.sf_status == SS_COMPLETED) { - if (!(flags & SS_SET_FAILOUT)) - flags |= SS_CLEAR_FAILOUT; - - if (!(flags & SS_SET_DRYRUN)) - flags |= SS_CLEAR_DRYRUN; - - flags |= SS_RESET; - } - - scrub->os_start_flags = flags; - thread_set_flags(thread, 0); - task = kthread_run(osd_scrub_main, dev, "OI_scrub"); - if (IS_ERR(task)) { - rc = PTR_ERR(task); - CERROR("%s: cannot start iteration thread: rc = %d\n", - osd_scrub2name(scrub), rc); - RETURN(rc); - } - - l_wait_event(thread->t_ctl_waitq, - thread_is_running(thread) || thread_is_stopped(thread), - &lwi); - - RETURN(0); -} - -int osd_scrub_start(struct osd_device *dev, __u32 flags) -{ - int rc; - ENTRY; - /* od_otable_mutex: prevent curcurrent start/stop */ mutex_lock(&dev->od_otable_mutex); - rc = do_osd_scrub_start(dev, flags); + rc = scrub_start(osd_scrub_main, scrub, dev, flags); + if (rc == -EALREADY) { + rc = 0; + if ((scrub->os_file.sf_flags & SF_AUTO || + scrub->os_partial_scan) && + !(flags & SS_AUTO_PARTIAL)) + osd_scrub_join(env, dev, flags, false); + } mutex_unlock(&dev->od_otable_mutex); - RETURN(rc == -EALREADY ? 0 : rc); -} - -static void do_osd_scrub_stop(struct osd_scrub *scrub) -{ - struct ptlrpc_thread *thread = &scrub->os_thread; - struct l_wait_info lwi = { 0 }; - - /* 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); - l_wait_event(thread->t_ctl_waitq, - thread_is_stopped(thread), - &lwi); - /* 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); - } - spin_unlock(&scrub->os_lock); + RETURN(rc); } static void osd_scrub_stop(struct osd_device *dev) { + struct lustre_scrub *scrub = &dev->od_scrub.os_scrub; + /* od_otable_mutex: prevent curcurrent start/stop */ mutex_lock(&dev->od_otable_mutex); - dev->od_scrub.os_paused = 1; - do_osd_scrub_stop(&dev->od_scrub); + scrub->os_paused = 1; + scrub_stop(scrub); mutex_unlock(&dev->od_otable_mutex); } @@ -2682,22 +2380,24 @@ static const char osd_scrub_name[] = "OI_scrub"; int osd_scrub_setup(const struct lu_env *env, struct osd_device *dev) { - struct osd_thread_info *info = osd_oti_get(env); - struct osd_scrub *scrub = &dev->od_scrub; - struct lvfs_run_ctxt *ctxt = &scrub->os_ctxt; - struct scrub_file *sf = &scrub->os_file; - struct super_block *sb = osd_sb(dev); - struct ldiskfs_super_block *es = LDISKFS_SB(sb)->s_es; - struct lvfs_run_ctxt saved; - struct file *filp; - struct inode *inode; - struct lu_fid *fid = &info->oti_fid; - bool dirty = false; - bool restored = false; - int rc = 0; + struct osd_thread_info *info = osd_oti_get(env); + struct lustre_scrub *scrub = &dev->od_scrub.os_scrub; + struct lvfs_run_ctxt *ctxt = &dev->od_scrub.os_ctxt; + struct scrub_file *sf = &scrub->os_file; + struct super_block *sb = osd_sb(dev); + struct ldiskfs_super_block *es = LDISKFS_SB(sb)->s_es; + struct lvfs_run_ctxt saved; + struct file *filp; + struct inode *inode; + struct lu_fid *fid = &info->oti_fid; + struct lu_object_conf conf; + struct dt_object *obj; + bool dirty = false; + bool restored = false; + int rc = 0; ENTRY; - memset(scrub, 0, sizeof(*scrub)); + memset(&dev->od_scrub, 0, sizeof(struct osd_scrub)); OBD_SET_CTXT_MAGIC(ctxt); ctxt->pwdmnt = dev->od_mnt; ctxt->pwd = dev->od_mnt->mnt_root; @@ -2707,32 +2407,45 @@ int osd_scrub_setup(const struct lu_env *env, struct osd_device *dev) init_rwsem(&scrub->os_rwsem); spin_lock_init(&scrub->os_lock); INIT_LIST_HEAD(&scrub->os_inconsistent_items); + scrub->os_name = osd_name(dev); push_ctxt(&saved, ctxt); - filp = filp_open(osd_scrub_name, O_RDWR | O_CREAT, 0644); + filp = filp_open(osd_scrub_name, O_RDWR | + (dev->od_dt_dev.dd_rdonly ? 0 : O_CREAT), 0644); if (IS_ERR(filp)) { pop_ctxt(&saved, ctxt); RETURN(PTR_ERR(filp)); } inode = file_inode(filp); - /* 'What the @fid is' is not imporatant, because the object - * has no OI mapping, and only is visible inside the OSD.*/ - lu_igif_build(fid, inode->i_ino, inode->i_generation); - rc = osd_ea_fid_set(info, inode, fid, LMAC_NOT_IN_OI, 0); - if (rc != 0) { - filp_close(filp, NULL); - pop_ctxt(&saved, ctxt); - RETURN(rc); + if (!dev->od_dt_dev.dd_rdonly) { + /* 'What the @fid is' is not imporatant, because the object + * has no OI mapping, and only is visible inside the OSD.*/ + lu_igif_build(fid, inode->i_ino, inode->i_generation); + rc = osd_ea_fid_set(info, inode, fid, LMAC_NOT_IN_OI, 0); + if (rc) { + filp_close(filp, NULL); + pop_ctxt(&saved, ctxt); + RETURN(rc); + } } - scrub->os_inode = igrab(inode); + igrab(inode); filp_close(filp, NULL); pop_ctxt(&saved, ctxt); - rc = osd_scrub_file_load(scrub); - if (rc == -ENOENT) { - osd_scrub_file_init(scrub, es->s_uuid); + conf.loc_flags = LOC_F_NEW; + obj = lu2dt(lu_object_find_slice(env, osd2lu_dev(dev), fid, &conf)); + if (IS_ERR_OR_NULL(obj)) { + iput(inode); + RETURN(obj == NULL ? -ENOENT : PTR_ERR(obj)); + } + + osd_dt_obj(obj)->oo_inode = inode; + scrub->os_obj = obj; + rc = scrub_file_load(env, scrub); + if (rc == -ENOENT || rc == -EFAULT) { + scrub_file_init(scrub, es->s_uuid); /* If the "/O" dir does not exist when mount (indicated by * osd_device::od_maybe_new), neither for the "/OI_scrub", * then it is quite probably that the device is a new one, @@ -2745,11 +2458,11 @@ int osd_scrub_setup(const struct lu_env *env, struct osd_device *dev) * need to check "filter_fid_old" and to convert it to * "filter_fid" for each object, and all the IGIF should * have their FID mapping in OI files already. */ - if (dev->od_maybe_new) + if (dev->od_maybe_new && rc == -ENOENT) sf->sf_internal_flags = SIF_NO_HANDLE_OLD_FID; dirty = true; - } else if (rc != 0) { - GOTO(cleanup_inode, rc); + } else if (rc < 0) { + GOTO(cleanup_obj, rc); } else { if (memcmp(sf->sf_uuid, es->s_uuid, 16) != 0) { struct obd_uuid *old_uuid; @@ -2764,11 +2477,11 @@ int osd_scrub_setup(const struct lu_env *env, struct osd_device *dev) } else { class_uuid_unparse(sf->sf_uuid, old_uuid); class_uuid_unparse(es->s_uuid, new_uuid); - CERROR("%s: UUID has been changed from " - "%s to %s\n", osd_dev2name(dev), + CDEBUG(D_LFSCK, "%s: UUID has been changed " + "from %s to %s\n", osd_dev2name(dev), old_uuid->uuid, new_uuid->uuid); } - osd_scrub_file_reset(scrub, es->s_uuid,SF_INCONSISTENT); + scrub_file_reset(scrub, es->s_uuid, SF_INCONSISTENT); dirty = true; restored = true; if (old_uuid != NULL) @@ -2779,6 +2492,14 @@ int osd_scrub_setup(const struct lu_env *env, struct osd_device *dev) sf->sf_status = SS_CRASHED; dirty = true; } + + if ((sf->sf_oi_count & (sf->sf_oi_count - 1)) != 0) { + LCONSOLE_WARN("%s: invalid oi count %d, set it to %d\n", + osd_dev2name(dev), sf->sf_oi_count, + osd_oi_count); + sf->sf_oi_count = osd_oi_count; + dirty = true; + } } if (sf->sf_pos_last_checkpoint != 0) @@ -2787,19 +2508,21 @@ int osd_scrub_setup(const struct lu_env *env, struct osd_device *dev) scrub->os_pos_current = LDISKFS_FIRST_INO(sb) + 1; if (dirty) { - rc = osd_scrub_file_store(scrub); - if (rc != 0) - GOTO(cleanup_inode, rc); + rc = scrub_file_store(env, scrub); + if (rc) + GOTO(cleanup_obj, rc); } /* Initialize OI files. */ rc = osd_oi_init(info, dev, restored); if (rc < 0) - GOTO(cleanup_inode, rc); + GOTO(cleanup_obj, rc); - rc = osd_initial_OI_scrub(info, dev); - if (rc != 0) - GOTO(cleanup_oi, rc); + if (!dev->od_dt_dev.dd_rdonly) { + rc = osd_initial_OI_scrub(info, dev); + if (rc) + GOTO(cleanup_oi, rc); + } if (sf->sf_flags & SF_UPGRADE || !(sf->sf_internal_flags & SIF_NO_HANDLE_OLD_FID || @@ -2830,7 +2553,7 @@ int osd_scrub_setup(const struct lu_env *env, struct osd_device *dev) (sf->sf_status == SS_INIT && sf->sf_flags & (SF_RECREATED | SF_INCONSISTENT | SF_UPGRADE)))) - rc = osd_scrub_start(dev, SS_AUTO_FULL); + rc = osd_scrub_start(env, dev, SS_AUTO_FULL); if (rc != 0) GOTO(cleanup_oi, rc); @@ -2845,23 +2568,23 @@ int osd_scrub_setup(const struct lu_env *env, struct osd_device *dev) RETURN(0); cleanup_oi: osd_oi_fini(info, dev); -cleanup_inode: - iput(scrub->os_inode); - scrub->os_inode = NULL; +cleanup_obj: + dt_object_put_nocache(env, scrub->os_obj); + scrub->os_obj = NULL; return rc; } void osd_scrub_cleanup(const struct lu_env *env, struct osd_device *dev) { - struct osd_scrub *scrub = &dev->od_scrub; + struct lustre_scrub *scrub = &dev->od_scrub.os_scrub; LASSERT(dev->od_otable_it == NULL); - if (scrub->os_inode != NULL) { + if (scrub->os_obj != NULL) { osd_scrub_stop(dev); - iput(scrub->os_inode); - scrub->os_inode = NULL; + dt_object_put_nocache(env, scrub->os_obj); + scrub->os_obj = NULL; } if (dev->od_oi_table != NULL) osd_oi_fini(osd_oti_get(env), dev); @@ -2875,7 +2598,7 @@ static struct dt_it *osd_otable_it_init(const struct lu_env *env, enum dt_otable_it_flags flags = attr >> DT_OTABLE_IT_FLAGS_SHIFT; enum dt_otable_it_valid valid = attr & ~DT_OTABLE_IT_FLAGS_MASK; struct osd_device *dev = osd_dev(dt->do_lu.lo_dev); - struct osd_scrub *scrub = &dev->od_scrub; + struct lustre_scrub *scrub = &dev->od_scrub.os_scrub; struct osd_otable_it *it; __u32 start = 0; int rc; @@ -2913,15 +2636,19 @@ static struct dt_it *osd_otable_it_init(const struct lu_env *env, start |= SS_CLEAR_DRYRUN; } - rc = do_osd_scrub_start(dev, start & ~SS_AUTO_PARTIAL); - if (rc < 0 && rc != -EALREADY) { + rc = scrub_start(osd_scrub_main, scrub, dev, start & ~SS_AUTO_PARTIAL); + if (rc == -EALREADY) { + it->ooi_cache.ooc_pos_preload = scrub->os_pos_current; + } else if (rc < 0) { dev->od_otable_it = NULL; OBD_FREE_PTR(it); - GOTO(out, it = ERR_PTR(rc)); + it = ERR_PTR(rc); + } else { + /* We have to start from the begining. */ + it->ooi_cache.ooc_pos_preload = + LDISKFS_FIRST_INO(osd_sb(dev)) + 1; } - it->ooi_cache.ooc_pos_preload = scrub->os_pos_current; - GOTO(out, it); out: @@ -2936,7 +2663,7 @@ static void osd_otable_it_fini(const struct lu_env *env, struct dt_it *di) /* od_otable_mutex: prevent curcurrent init/fini */ mutex_lock(&dev->od_otable_mutex); - do_osd_scrub_stop(&dev->od_scrub); + scrub_stop(&dev->od_scrub.os_scrub); LASSERT(dev->od_otable_it == it); dev->od_otable_it = NULL; @@ -2955,7 +2682,7 @@ static void osd_otable_it_put(const struct lu_env *env, struct dt_it *di) } static inline int -osd_otable_it_wakeup(struct osd_scrub *scrub, struct osd_otable_it *it) +osd_otable_it_wakeup(struct lustre_scrub *scrub, struct osd_otable_it *it) { spin_lock(&scrub->os_lock); if (it->ooi_cache.ooc_pos_preload < scrub->os_pos_current || @@ -2973,7 +2700,7 @@ static int osd_otable_it_next(const struct lu_env *env, struct dt_it *di) { struct osd_otable_it *it = (struct osd_otable_it *)di; struct osd_device *dev = it->ooi_dev; - struct osd_scrub *scrub = &dev->od_scrub; + struct lustre_scrub *scrub = &dev->od_scrub.os_scrub; struct osd_otable_cache *ooc = &it->ooi_cache; struct ptlrpc_thread *thread = &scrub->os_thread; struct l_wait_info lwi = { 0 }; @@ -3074,7 +2801,7 @@ static int osd_otable_it_load(const struct lu_env *env, struct osd_otable_it *it = (struct osd_otable_it *)di; struct osd_device *dev = it->ooi_dev; struct osd_otable_cache *ooc = &it->ooi_cache; - struct osd_scrub *scrub = &dev->od_scrub; + struct lustre_scrub *scrub = &dev->od_scrub.os_scrub; struct osd_iit_param *param = &it->ooi_iit_param; int rc; ENTRY; @@ -3143,9 +2870,10 @@ int osd_oii_insert(struct osd_device *dev, struct osd_idmap_cache *oic, int insert) { struct osd_inconsistent_item *oii; - struct osd_scrub *scrub = &dev->od_scrub; - struct ptlrpc_thread *thread = &scrub->os_thread; - int wakeup = 0; + struct osd_scrub *oscrub = &dev->od_scrub; + struct lustre_scrub *lscrub = &oscrub->os_scrub; + struct ptlrpc_thread *thread = &lscrub->os_thread; + int wakeup = 0; ENTRY; OBD_ALLOC_PTR(oii); @@ -3156,37 +2884,37 @@ int osd_oii_insert(struct osd_device *dev, struct osd_idmap_cache *oic, oii->oii_cache = *oic; oii->oii_insert = insert; - if (scrub->os_partial_scan) { + if (lscrub->os_partial_scan) { __u64 now = cfs_time_current_sec(); /* If there haven't been errors in a long time, * decay old count until either the errors are * gone or we reach the current interval. */ - while (unlikely(scrub->os_bad_oimap_count > 0 && - scrub->os_bad_oimap_time + + while (unlikely(oscrub->os_bad_oimap_count > 0 && + oscrub->os_bad_oimap_time + SCRUB_BAD_OIMAP_DECAY_INTERVAL < now)) { - scrub->os_bad_oimap_count >>= 1; - scrub->os_bad_oimap_time += + oscrub->os_bad_oimap_count >>= 1; + oscrub->os_bad_oimap_time += SCRUB_BAD_OIMAP_DECAY_INTERVAL; } - scrub->os_bad_oimap_time = now; - if (++scrub->os_bad_oimap_count > + oscrub->os_bad_oimap_time = now; + if (++oscrub->os_bad_oimap_count > dev->od_full_scrub_threshold_rate) - scrub->os_full_scrub = 1; + lscrub->os_full_scrub = 1; } - spin_lock(&scrub->os_lock); + spin_lock(&lscrub->os_lock); if (unlikely(!thread_is_running(thread))) { - spin_unlock(&scrub->os_lock); + spin_unlock(&lscrub->os_lock); OBD_FREE_PTR(oii); RETURN(-EAGAIN); } - if (list_empty(&scrub->os_inconsistent_items)) + if (list_empty(&lscrub->os_inconsistent_items)) wakeup = 1; - list_add_tail(&oii->oii_list, &scrub->os_inconsistent_items); - spin_unlock(&scrub->os_lock); + list_add_tail(&oii->oii_list, &lscrub->os_inconsistent_items); + spin_unlock(&lscrub->os_lock); if (wakeup != 0) wake_up_all(&thread->t_ctl_waitq); @@ -3197,7 +2925,7 @@ int osd_oii_insert(struct osd_device *dev, struct osd_idmap_cache *oic, int osd_oii_lookup(struct osd_device *dev, const struct lu_fid *fid, struct osd_inode_id *id) { - struct osd_scrub *scrub = &dev->od_scrub; + struct lustre_scrub *scrub = &dev->od_scrub.os_scrub; struct osd_inconsistent_item *oii; ENTRY; @@ -3214,175 +2942,17 @@ int osd_oii_lookup(struct osd_device *dev, const struct lu_fid *fid, RETURN(-ENOENT); } -/* OI scrub dump */ - -static const char *scrub_status_names[] = { - "init", - "scanning", - "completed", - "failed", - "stopped", - "paused", - "crashed", - NULL -}; - -static const char *scrub_flags_names[] = { - "recreated", - "inconsistent", - "auto", - "upgrade", - NULL -}; - -static const char *scrub_param_names[] = { - "failout", - "dryrun", - NULL -}; - -static void scrub_bits_dump(struct seq_file *m, int bits, const char *names[], - const char *prefix) -{ - int flag; - int i; - - seq_printf(m, "%s:%c", prefix, bits != 0 ? ' ' : '\n'); - - for (i = 0, flag = 1; bits != 0; i++, flag = 1 << i) { - if (flag & bits) { - bits &= ~flag; - seq_printf(m, "%s%c", names[i], - bits != 0 ? ',' : '\n'); - } - } -} - -static void scrub_time_dump(struct seq_file *m, __u64 time, const char *prefix) -{ - if (time != 0) - seq_printf(m, "%s: %llu seconds\n", prefix, - cfs_time_current_sec() - time); - else - seq_printf(m, "%s: N/A\n", prefix); -} - -static void scrub_pos_dump(struct seq_file *m, __u64 pos, const char *prefix) +void osd_scrub_dump(struct seq_file *m, struct osd_device *dev) { - if (pos != 0) - seq_printf(m, "%s: %llu\n", prefix, pos); - else - seq_printf(m, "%s: N/A\n", prefix); -} + struct osd_scrub *scrub = &dev->od_scrub; -int osd_scrub_dump(struct seq_file *m, struct osd_device *dev) -{ - struct osd_scrub *scrub = &dev->od_scrub; - struct scrub_file *sf = &scrub->os_file; - __u64 checked; - __u64 speed; - - down_read(&scrub->os_rwsem); - seq_printf(m, "name: OI_scrub\n" - "magic: 0x%x\n" - "oi_files: %d\n" - "status: %s\n", - sf->sf_magic, (int)sf->sf_oi_count, - scrub_status_names[sf->sf_status]); - - scrub_bits_dump(m, sf->sf_flags, scrub_flags_names, "flags"); - - scrub_bits_dump(m, sf->sf_param, scrub_param_names, "param"); - - scrub_time_dump(m, sf->sf_time_last_complete, - "time_since_last_completed"); - - scrub_time_dump(m, sf->sf_time_latest_start, - "time_since_latest_start"); - - scrub_time_dump(m, sf->sf_time_last_checkpoint, - "time_since_last_checkpoint"); - - scrub_pos_dump(m, sf->sf_pos_latest_start, - "latest_start_position"); - - scrub_pos_dump(m, sf->sf_pos_last_checkpoint, - "last_checkpoint_position"); - - scrub_pos_dump(m, sf->sf_pos_first_inconsistent, - "first_failure_position"); - - checked = sf->sf_items_checked + scrub->os_new_checked; - seq_printf(m, "checked: %llu\n" - "%s: %llu\n" - "failed: %llu\n" - "prior_%s: %llu\n" - "noscrub: %llu\n" - "igif: %llu\n" - "success_count: %u\n", - checked, - sf->sf_param & SP_DRYRUN ? "inconsistent" : "updated", - sf->sf_items_updated, sf->sf_items_failed, - sf->sf_param & SP_DRYRUN ? "inconsistent" : "updated", - sf->sf_items_updated_prior, sf->sf_items_noscrub, - sf->sf_items_igif, sf->sf_success_count); - - speed = checked; - if (thread_is_running(&scrub->os_thread)) { - cfs_duration_t duration = cfs_time_current() - - scrub->os_time_last_checkpoint; - __u64 new_checked = msecs_to_jiffies(scrub->os_new_checked * - MSEC_PER_SEC); - __u32 rtime = sf->sf_run_time + - cfs_duration_sec(duration + HALF_SEC); - - if (duration != 0) - do_div(new_checked, duration); - if (rtime != 0) - do_div(speed, rtime); - seq_printf(m, "run_time: %u seconds\n" - "average_speed: %llu objects/sec\n" - "real-time_speed: %llu objects/sec\n" - "current_position: %u\n" - "lf_scanned: %llu\n" - "lf_%s: %llu\n" - "lf_failed: %llu\n", - rtime, speed, new_checked, scrub->os_pos_current, - scrub->os_lf_scanned, - sf->sf_param & SP_DRYRUN ? - "inconsistent" : "repaired", - scrub->os_lf_repaired, - scrub->os_lf_failed); - seq_printf(m, "inodes_per_group: %lu\n" - "current_iit_group: %u\n" - "current_iit_base: %u\n" - "current_iit_offset: %u\n" - "scrub_in_prior: %s\n" - "scrub_full_speed: %s\n" - "partial_scan: %s\n", - LDISKFS_INODES_PER_GROUP(osd_sb(dev)), - scrub->os_iit_param.bg, - scrub->os_iit_param.gbase, - scrub->os_iit_param.offset, - scrub->os_in_prior ? "yes" : "no", - scrub->os_full_speed ? "yes" : "no", - scrub->os_partial_scan ? "yes" : "no"); - } else { - if (sf->sf_run_time != 0) - do_div(speed, sf->sf_run_time); - seq_printf(m, "run_time: %u seconds\n" - "average_speed: %llu objects/sec\n" - "real-time_speed: N/A\n" - "current_position: N/A\n" - "lf_scanned: %llu\n" - "lf_%s: %llu\n" - "lf_failed: %llu\n", - sf->sf_run_time, speed, scrub->os_lf_scanned, - sf->sf_param & SP_DRYRUN ? - "inconsistent" : "repaired", - scrub->os_lf_repaired, scrub->os_lf_failed); - } - - up_read(&scrub->os_rwsem); - return 0; + scrub_dump(m, &scrub->os_scrub); + seq_printf(m, "lf_scanned: %llu\n" + "lf_%s: %llu\n" + "lf_failed: %llu\n", + scrub->os_lf_scanned, + scrub->os_scrub.os_file.sf_param & SP_DRYRUN ? + "inconsistent" : "repaired", + scrub->os_lf_repaired, + scrub->os_lf_failed); } diff --git a/lustre/osd-ldiskfs/osd_scrub.h b/lustre/osd-ldiskfs/osd_scrub.h index a722692..32de941 100644 --- a/lustre/osd-ldiskfs/osd_scrub.h +++ b/lustre/osd-ldiskfs/osd_scrub.h @@ -6,16 +6,16 @@ * 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. - + * + * 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 LICENSE 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 + * version 2 along with this program; If not, see + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ @@ -25,7 +25,7 @@ /* * lustre/osd-ldiskfs/osd_scrub.h * - * Shared definitions and declarations for OI scrub. + * Definitions and declarations for ldiskfs backend OI scrub. * * Author: Fan Yong */ @@ -33,159 +33,15 @@ #ifndef _OSD_SCRUB_H # define _OSD_SCRUB_H +#include #include "osd_oi.h" -#define SCRUB_MAGIC_V1 0x4C5FD252 -#define SCRUB_CHECKPOINT_INTERVAL 60 -#define SCRUB_OI_BITMAP_SIZE (OSD_OI_FID_NR_MAX >> 3) -#define SCRUB_WINDOW_SIZE 1024 - -enum scrub_status { - /* The scrub file is new created, for new MDT, upgrading from old disk, - * or re-creating the scrub file manually. */ - SS_INIT = 0, - - /* The scrub is checking/repairing the OI files. */ - SS_SCANNING = 1, - - /* The scrub checked/repaired the OI files successfully. */ - SS_COMPLETED = 2, - - /* The scrub failed to check/repair the OI files. */ - SS_FAILED = 3, - - /* The scrub is stopped manually, the OI files may be inconsistent. */ - SS_STOPPED = 4, - - /* The scrub is paused automatically when umount. */ - SS_PAUSED = 5, - - /* The scrub crashed during the scanning, should be restarted. */ - SS_CRASHED = 6, -}; - -enum scrub_flags { - /* OI files have been recreated, OI mappings should be re-inserted. */ - SF_RECREATED = 0x0000000000000001ULL, - - /* OI files are invalid, should be rebuild ASAP */ - SF_INCONSISTENT = 0x0000000000000002ULL, - - /* OI scrub is triggered automatically. */ - SF_AUTO = 0x0000000000000004ULL, - - /* The device is upgraded from 1.8 format. */ - SF_UPGRADE = 0x0000000000000008ULL, -}; - -enum scrub_param { - /* Exit when fail. */ - SP_FAILOUT = 0x0001, - - /* Check only without repairing. */ - SP_DRYRUN = 0x0002, -}; - -enum scrub_start { - /* Set failout flag. */ - SS_SET_FAILOUT = 0x00000001, - - /* Clear failout flag. */ - SS_CLEAR_FAILOUT = 0x00000002, - - /* Reset scrub start position. */ - SS_RESET = 0x00000004, - - /* Trigger full scrub automatically. */ - SS_AUTO_FULL = 0x00000008, - - /* Trigger partial scrub automatically. */ - SS_AUTO_PARTIAL = 0x00000010, - - /* Set dryrun flag. */ - SS_SET_DRYRUN = 0x00000020, - - /* Clear dryrun flag. */ - SS_CLEAR_DRYRUN = 0x00000040, -}; - /* The flags here are only used inside OSD, NOT be visible by dump(). */ enum scrub_internal_flags { /* This is a new formatted device. */ SIF_NO_HANDLE_OLD_FID = 0x0001, }; -struct scrub_file { - /* 128-bit uuid for volume. */ - __u8 sf_uuid[16]; - - /* See 'enum scrub_flags'. */ - __u64 sf_flags; - - /* The scrub magic. */ - __u32 sf_magic; - - /* See 'enum scrub_status'. */ - __u16 sf_status; - - /* See 'enum scrub_param'. */ - __u16 sf_param; - - /* The time for the last OI scrub completed. */ - __u64 sf_time_last_complete; - - /* The time for the latest OI scrub ran. */ - __u64 sf_time_latest_start; - - /* The time for the last OI scrub checkpoint. */ - __u64 sf_time_last_checkpoint; - - /* The position for the latest OI scrub started from. */ - __u64 sf_pos_latest_start; - - /* The position for the last OI scrub checkpoint. */ - __u64 sf_pos_last_checkpoint; - - /* The position for the first should be updated object. */ - __u64 sf_pos_first_inconsistent; - - /* How many objects have been checked. */ - __u64 sf_items_checked; - - /* How many objects have been updated. */ - __u64 sf_items_updated; - - /* How many objects failed to be processed. */ - __u64 sf_items_failed; - - /* How many prior objects have been updated during scanning. */ - __u64 sf_items_updated_prior; - - /* How many objects marked as LDISKFS_STATE_LUSTRE_NOSCRUB. */ - __u64 sf_items_noscrub; - - /* How many IGIF objects. */ - __u64 sf_items_igif; - - /* How long the OI scrub has run. */ - __u32 sf_run_time; - - /* How many completed OI scrub ran on the device. */ - __u32 sf_success_count; - - /* How many OI files. */ - __u16 sf_oi_count; - - /* Keep the flags after scrub reset. See 'enum scrub_internal_flags' */ - __u16 sf_internal_flags; - - __u32 sf_reserved_1; - __u64 sf_reserved_2[16]; - - /* Bitmap for OI files recreated case. */ - __u8 sf_oi_bitmap[SCRUB_OI_BITMAP_SIZE]; -}; - struct osd_iit_param { struct super_block *sb; struct buffer_head *bitmap; @@ -196,31 +52,10 @@ struct osd_iit_param { }; struct osd_scrub { + struct lustre_scrub os_scrub; struct lvfs_run_ctxt os_ctxt; - struct ptlrpc_thread os_thread; struct osd_idmap_cache os_oic; struct osd_iit_param os_iit_param; - struct list_head os_inconsistent_items; - - /* write lock for scrub prep/update/post/checkpoint, - * read lock for scrub dump. */ - struct rw_semaphore os_rwsem; - spinlock_t os_lock; - - /* Scrub file in memory. */ - struct scrub_file os_file; - - /* Buffer for scrub file load/store. */ - struct scrub_file os_file_disk; - - /* Inode for the scrub file. */ - struct inode *os_inode; - - /* The time for last checkpoint, jiffies */ - cfs_time_t os_time_last_checkpoint; - - /* The time for next checkpoint, jiffies */ - cfs_time_t os_time_next_checkpoint; /* statistics for /lost+found are in ram only, it will be reset * when each time the device remount. */ @@ -232,19 +67,6 @@ struct osd_scrub { /* How many objects failed to be processed during initial OI scrub. */ __u64 os_lf_failed; - /* How many objects have been checked since last checkpoint. */ - __u32 os_new_checked; - __u32 os_pos_current; - __u32 os_start_flags; - unsigned int os_in_prior:1, /* process inconsistent item - * found by RPC prior */ - os_waiting:1, /* Waiting for scan window. */ - os_full_speed:1, /* run w/o speed limit */ - os_paused:1, /* The scrub is paused. */ - os_convert_igif:1, - os_partial_scan:1, - os_in_join:1, - os_full_scrub:1; __u64 os_bad_oimap_count; __u64 os_bad_oimap_time; }; diff --git a/lustre/osd-zfs/osd_oi.c b/lustre/osd-zfs/osd_oi.c index 010e023..4fdec4d 100644 --- a/lustre/osd-zfs/osd_oi.c +++ b/lustre/osd-zfs/osd_oi.c @@ -61,9 +61,9 @@ #include #include #include +#include #define OSD_OI_FID_NR (1UL << 7) -#define OSD_OI_FID_NR_MAX (1UL << OSD_OI_FID_OID_BITS_MAX) unsigned int osd_oi_count = OSD_OI_FID_NR; diff --git a/lustre/tests/sanity-scrub.sh b/lustre/tests/sanity-scrub.sh index 87b6f82..a78329b 100644 --- a/lustre/tests/sanity-scrub.sh +++ b/lustre/tests/sanity-scrub.sh @@ -233,13 +233,20 @@ scrub_check_params() { scrub_check_repaired() { local error_id=$1 local expected=$2 + local dryrun=$3 local actual local n for n in $(seq $MDSCOUNT); do - actual=$(do_facet mds$n $LCTL get_param -n \ - osd-ldiskfs.$(facet_svc mds$n).oi_scrub | - awk '/^updated/ { print $2 }') + if [ $dryrun -eq 1 ]; then + actual=$(do_facet mds$n $LCTL get_param -n \ + osd-ldiskfs.$(facet_svc mds$n).oi_scrub | + awk '/^inconsistent:/ { print $2 }') + else + actual=$(do_facet mds$n $LCTL get_param -n \ + osd-ldiskfs.$(facet_svc mds$n).oi_scrub | + awk '/^updated:/ { print $2 }') + fi if [ $expected -eq 0 -a $actual -ne 0 ]; then error "($error_id) Expected no repaired on mds$n, but" \ @@ -1149,7 +1156,7 @@ test_15() { scrub_check_status 6 completed scrub_check_flags 7 recreated,inconsistent scrub_check_params 8 dryrun - scrub_check_repaired 9 20 + scrub_check_repaired 9 20 1 # run under dryrun mode again if [ $server_version -lt $(version_code 2.5.58) ]; then @@ -1160,7 +1167,7 @@ test_15() { scrub_check_status 11 completed scrub_check_flags 12 recreated,inconsistent scrub_check_params 13 dryrun - scrub_check_repaired 14 20 + scrub_check_repaired 14 20 1 # run under normal mode # @@ -1175,7 +1182,7 @@ test_15() { scrub_check_status 16 completed scrub_check_flags 17 "" scrub_check_params 18 "" - scrub_check_repaired 19 20 + scrub_check_repaired 19 20 0 # run under normal mode again if [ $server_version -lt $(version_code 2.5.58) ]; then @@ -1186,7 +1193,7 @@ test_15() { scrub_check_status 21 completed scrub_check_flags 22 "" scrub_check_params 23 "" - scrub_check_repaired 24 0 + scrub_check_repaired 24 0 0 } run_test 15 "Dryrun mode OI scrub"