4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License version 2 for more details. A copy is
14 * included in the COPYING file that accompanied this code.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 * Copyright (c) 2017, Intel Corporation.
26 * lustre/osd-zfs/osd_scrub.c
28 * Top-level entry points into osd module
30 * The OI scrub is used for rebuilding Object Index files when restores MDT from
33 * The otable based iterator scans ZFS objects to feed up layer LFSCK.
35 * Author: Fan Yong <fan.yong@intel.com>
38 #define DEBUG_SUBSYSTEM S_LFSCK
40 #include <linux/kthread.h>
41 #include <uapi/linux/lustre/lustre_idl.h>
42 #include <lustre_disk.h>
43 #include <dt_object.h>
44 #include <linux/xattr.h>
45 #include <lustre_scrub.h>
46 #include <obd_class.h>
47 #include <lustre_nodemap.h>
48 #include <sys/dsl_dataset.h>
50 #include "osd_internal.h"
52 #define OSD_OTABLE_MAX_HASH ((1ULL << 48) - 1)
53 #define OTABLE_PREFETCH 256
55 #define DTO_INDEX_INSERT 1
56 #define DTO_INDEX_DELETE 2
57 #define DTO_INDEX_UPDATE 3
59 static inline bool osd_scrub_has_window(struct osd_otable_it *it)
61 return it->ooi_prefetched < OTABLE_PREFETCH;
65 * update/insert/delete the specified OI mapping (@fid @id) according to the ops
67 * \retval 1, changed nothing
68 * \retval 0, changed successfully
69 * \retval -ve, on error
71 static int osd_scrub_refresh_mapping(const struct lu_env *env,
72 struct osd_device *dev,
73 const struct lu_fid *fid,
74 uint64_t oid, int ops,
75 bool force, const char *name)
77 struct osd_thread_info *info = osd_oti_get(env);
78 struct zpl_direntry *zde = &info->oti_zde.lzd_reg;
79 char *buf = info->oti_str;
86 if (dev->od_scrub.os_file.sf_param & SP_DRYRUN && !force)
89 tx = dmu_tx_create(dev->od_os);
91 GOTO(log, rc = -ENOMEM);
93 zapid = osd_get_name_n_idx(env, dev, fid, buf,
94 sizeof(info->oti_str), &dn);
95 osd_tx_hold_zap(tx, zapid, dn,
96 ops == DTO_INDEX_INSERT ? TRUE : FALSE, NULL);
97 rc = -dmu_tx_assign(tx, TXG_WAIT);
104 case DTO_INDEX_UPDATE:
106 zde->zde_dnode = oid;
107 zde->zde_type = 0; /* The type in OI mapping is useless. */
108 rc = -zap_update(dev->od_os, zapid, buf, 8, sizeof(*zde) / 8,
110 if (unlikely(rc == -ENOENT)) {
111 /* Some unlink thread may removed the OI mapping. */
115 case DTO_INDEX_INSERT:
117 zde->zde_dnode = oid;
118 zde->zde_type = 0; /* The type in OI mapping is useless. */
119 rc = osd_zap_add(dev, zapid, dn, buf, 8, sizeof(*zde) / 8,
121 if (unlikely(rc == -EEXIST))
124 case DTO_INDEX_DELETE:
125 rc = osd_zap_remove(dev, zapid, dn, buf, tx);
127 /* It is normal that the unlink thread has removed the
128 * OI mapping already. */
133 LASSERTF(0, "Unexpected ops %d\n", ops);
142 CDEBUG(D_LFSCK, "%s: refresh OI map for scrub, op %d, force %s, "
143 DFID" => %llu (%s): rc = %d\n", osd_name(dev), ops,
144 force ? "yes" : "no", PFID(fid), oid, name ? name : "null", rc);
150 osd_scrub_check_update(const struct lu_env *env, struct osd_device *dev,
151 const struct lu_fid *fid, uint64_t oid, int val)
153 struct lustre_scrub *scrub = &dev->od_scrub;
154 struct scrub_file *sf = &scrub->os_file;
155 struct osd_inconsistent_item *oii = NULL;
156 nvlist_t *nvbuf = NULL;
159 int ops = DTO_INDEX_UPDATE;
163 down_write(&scrub->os_rwsem);
164 scrub->os_new_checked++;
168 if (scrub->os_in_prior)
169 oii = list_entry(scrub->os_inconsistent_items.next,
170 struct osd_inconsistent_item, oii_list);
172 if (oid < sf->sf_pos_latest_start && !oii)
175 if (oii && oii->oii_insert) {
176 ops = DTO_INDEX_INSERT;
180 rc = osd_fid_lookup(env, dev, fid, &oid2);
185 ops = DTO_INDEX_INSERT;
188 rc = __osd_obj2dnode(dev->od_os, oid, &dn);
190 /* Someone removed the object by race. */
191 if (rc == -ENOENT || rc == -EEXIST)
196 scrub->os_full_speed = 1;
197 sf->sf_flags |= SF_INCONSISTENT;
198 } else if (oid == oid2) {
201 struct lustre_mdt_attrs *lma = NULL;
204 rc = __osd_xattr_load_by_oid(dev, oid2, &nvbuf);
205 if (rc == -ENOENT || rc == -EEXIST || rc == -ENODATA)
210 rc = -nvlist_lookup_byte_array(nvbuf, XATTR_NAME_LMA,
211 (uchar_t **)&lma, &size);
212 if (rc == -ENOENT || rc == -EEXIST || rc == -ENODATA)
217 lustre_lma_swab(lma);
218 if (unlikely(lu_fid_eq(&lma->lma_self_fid, fid))) {
219 CDEBUG(D_LFSCK, "%s: the FID "DFID" is used by "
220 "two objects: %llu and %llu (in OI)\n",
221 osd_name(dev), PFID(fid), oid, oid2);
223 GOTO(out, rc = -EEXIST);
227 scrub->os_full_speed = 1;
228 sf->sf_flags |= SF_INCONSISTENT;
231 rc = osd_scrub_refresh_mapping(env, dev, fid, oid, ops, false, NULL);
233 if (scrub->os_in_prior)
234 sf->sf_items_updated_prior++;
236 sf->sf_items_updated++;
246 sf->sf_items_failed++;
247 if (sf->sf_pos_first_inconsistent == 0 ||
248 sf->sf_pos_first_inconsistent > oid)
249 sf->sf_pos_first_inconsistent = oid;
254 /* There may be conflict unlink during the OI scrub,
255 * if happend, then remove the new added OI mapping. */
256 if (ops == DTO_INDEX_INSERT && dn && dn->dn_free_txg)
257 osd_scrub_refresh_mapping(env, dev, fid, oid,
258 DTO_INDEX_DELETE, false, NULL);
259 up_write(&scrub->os_rwsem);
265 spin_lock(&scrub->os_lock);
266 if (likely(!list_empty(&oii->oii_list)))
267 list_del(&oii->oii_list);
268 spin_unlock(&scrub->os_lock);
272 RETURN(sf->sf_param & SP_FAILOUT ? rc : 0);
275 static int osd_scrub_prep(const struct lu_env *env, struct osd_device *dev)
277 struct lustre_scrub *scrub = &dev->od_scrub;
278 struct ptlrpc_thread *thread = &scrub->os_thread;
279 struct scrub_file *sf = &scrub->os_file;
280 __u32 flags = scrub->os_start_flags;
282 bool drop_dryrun = false;
285 CDEBUG(D_LFSCK, "%s: OI scrub prep, flags = 0x%x\n",
286 scrub->os_name, flags);
288 down_write(&scrub->os_rwsem);
289 if (flags & SS_SET_FAILOUT)
290 sf->sf_param |= SP_FAILOUT;
291 else if (flags & SS_CLEAR_FAILOUT)
292 sf->sf_param &= ~SP_FAILOUT;
294 if (flags & SS_SET_DRYRUN) {
295 sf->sf_param |= SP_DRYRUN;
296 } else if (flags & SS_CLEAR_DRYRUN && sf->sf_param & SP_DRYRUN) {
297 sf->sf_param &= ~SP_DRYRUN;
301 if (flags & SS_RESET)
302 scrub_file_reset(scrub, dev->od_uuid, 0);
304 scrub->os_partial_scan = 0;
305 if (flags & SS_AUTO_FULL) {
306 scrub->os_full_speed = 1;
307 sf->sf_flags |= SF_AUTO;
308 } else if (sf->sf_flags & (SF_RECREATED | SF_INCONSISTENT |
310 scrub->os_full_speed = 1;
312 scrub->os_full_speed = 0;
315 spin_lock(&scrub->os_lock);
316 scrub->os_in_prior = 0;
317 scrub->os_waiting = 0;
318 scrub->os_paused = 0;
319 scrub->os_in_join = 0;
320 scrub->os_full_scrub = 0;
321 spin_unlock(&scrub->os_lock);
322 scrub->os_new_checked = 0;
323 if (drop_dryrun && sf->sf_pos_first_inconsistent != 0)
324 sf->sf_pos_latest_start = sf->sf_pos_first_inconsistent;
325 else if (sf->sf_pos_last_checkpoint != 0)
326 sf->sf_pos_latest_start = sf->sf_pos_last_checkpoint + 1;
328 sf->sf_pos_latest_start = 1;
330 scrub->os_pos_current = sf->sf_pos_latest_start;
331 sf->sf_status = SS_SCANNING;
332 sf->sf_time_latest_start = cfs_time_current_sec();
333 sf->sf_time_last_checkpoint = sf->sf_time_latest_start;
334 sf->sf_pos_last_checkpoint = sf->sf_pos_latest_start - 1;
335 rc = scrub_file_store(env, scrub);
337 spin_lock(&scrub->os_lock);
338 thread_set_flags(thread, SVC_RUNNING);
339 spin_unlock(&scrub->os_lock);
340 wake_up_all(&thread->t_ctl_waitq);
342 up_write(&scrub->os_rwsem);
347 static int osd_scrub_post(const struct lu_env *env, struct osd_device *dev,
350 struct lustre_scrub *scrub = &dev->od_scrub;
351 struct scrub_file *sf = &scrub->os_file;
355 CDEBUG(D_LFSCK, "%s: OI scrub post with result = %d\n",
356 scrub->os_name, result);
358 down_write(&scrub->os_rwsem);
359 spin_lock(&scrub->os_lock);
360 thread_set_flags(&scrub->os_thread, SVC_STOPPING);
361 spin_unlock(&scrub->os_lock);
362 if (scrub->os_new_checked > 0) {
363 sf->sf_items_checked += scrub->os_new_checked;
364 scrub->os_new_checked = 0;
365 sf->sf_pos_last_checkpoint = scrub->os_pos_current;
367 sf->sf_time_last_checkpoint = cfs_time_current_sec();
369 sf->sf_status = SS_COMPLETED;
370 if (!(sf->sf_param & SP_DRYRUN)) {
371 memset(sf->sf_oi_bitmap, 0, SCRUB_OI_BITMAP_SIZE);
372 sf->sf_flags &= ~(SF_RECREATED | SF_INCONSISTENT |
373 SF_UPGRADE | SF_AUTO);
375 sf->sf_time_last_complete = sf->sf_time_last_checkpoint;
376 sf->sf_success_count++;
377 } else if (result == 0) {
378 if (scrub->os_paused)
379 sf->sf_status = SS_PAUSED;
381 sf->sf_status = SS_STOPPED;
383 sf->sf_status = SS_FAILED;
385 sf->sf_run_time += cfs_duration_sec(cfs_time_current() + HALF_SEC -
386 scrub->os_time_last_checkpoint);
387 rc = scrub_file_store(env, scrub);
388 up_write(&scrub->os_rwsem);
390 RETURN(rc < 0 ? rc : result);
393 /* iteration engine */
396 osd_scrub_wakeup(struct lustre_scrub *scrub, struct osd_otable_it *it)
398 spin_lock(&scrub->os_lock);
399 if (osd_scrub_has_window(it) ||
400 !list_empty(&scrub->os_inconsistent_items) ||
401 it->ooi_waiting || !thread_is_running(&scrub->os_thread))
402 scrub->os_waiting = 0;
404 scrub->os_waiting = 1;
405 spin_unlock(&scrub->os_lock);
407 return !scrub->os_waiting;
410 static int osd_scrub_next(const struct lu_env *env, struct osd_device *dev,
411 struct lu_fid *fid, uint64_t *oid)
413 struct l_wait_info lwi = { 0 };
414 struct lustre_scrub *scrub = &dev->od_scrub;
415 struct ptlrpc_thread *thread = &scrub->os_thread;
416 struct osd_otable_it *it = dev->od_otable_it;
417 struct lustre_mdt_attrs *lma = NULL;
418 nvlist_t *nvbuf = NULL;
423 if (OBD_FAIL_CHECK(OBD_FAIL_OSD_SCRUB_DELAY) && cfs_fail_val > 0) {
424 lwi = LWI_TIMEOUT(cfs_time_seconds(cfs_fail_val), NULL, NULL);
425 if (likely(lwi.lwi_timeout > 0)) {
426 l_wait_event(thread->t_ctl_waitq,
427 !list_empty(&scrub->os_inconsistent_items) ||
428 !thread_is_running(thread),
430 if (unlikely(!thread_is_running(thread)))
431 RETURN(SCRUB_NEXT_EXIT);
435 if (OBD_FAIL_CHECK(OBD_FAIL_OSD_SCRUB_CRASH)) {
436 spin_lock(&scrub->os_lock);
437 thread_set_flags(thread, SVC_STOPPING);
438 spin_unlock(&scrub->os_lock);
439 RETURN(SCRUB_NEXT_CRASH);
442 if (OBD_FAIL_CHECK(OBD_FAIL_OSD_SCRUB_FATAL))
443 RETURN(SCRUB_NEXT_FATAL);
452 if (!list_empty(&scrub->os_inconsistent_items)) {
453 spin_lock(&scrub->os_lock);
454 if (likely(!list_empty(&scrub->os_inconsistent_items))) {
455 struct osd_inconsistent_item *oii;
457 oii = list_entry(scrub->os_inconsistent_items.next,
458 struct osd_inconsistent_item, oii_list);
459 *fid = oii->oii_cache.oic_fid;
460 *oid = oii->oii_cache.oic_dnode;
461 scrub->os_in_prior = 1;
462 spin_unlock(&scrub->os_lock);
466 spin_unlock(&scrub->os_lock);
469 if (!scrub->os_full_speed && !osd_scrub_has_window(it)) {
470 memset(&lwi, 0, sizeof(lwi));
471 l_wait_event(thread->t_ctl_waitq,
472 osd_scrub_wakeup(scrub, it),
476 if (unlikely(!thread_is_running(thread)))
477 GOTO(out, rc = SCRUB_NEXT_EXIT);
479 rc = -dmu_object_next(dev->od_os, &scrub->os_pos_current, B_FALSE, 0);
481 GOTO(out, rc = (rc == -ESRCH ? SCRUB_NEXT_BREAK : rc));
483 rc = __osd_xattr_load_by_oid(dev, scrub->os_pos_current, &nvbuf);
484 if (rc == -ENOENT || rc == -EEXIST || rc == -ENODATA)
490 LASSERT(nvbuf != NULL);
491 rc = -nvlist_lookup_byte_array(nvbuf, XATTR_NAME_LMA,
492 (uchar_t **)&lma, &size);
494 lustre_lma_swab(lma);
495 if (likely(!(lma->lma_compat & LMAC_NOT_IN_OI) &&
496 !(lma->lma_incompat & LMAI_AGENT))) {
497 *fid = lma->lma_self_fid;
498 *oid = scrub->os_pos_current;
504 if (!scrub->os_full_speed) {
505 spin_lock(&scrub->os_lock);
506 it->ooi_prefetched++;
507 if (it->ooi_waiting) {
509 wake_up_all(&thread->t_ctl_waitq);
511 spin_unlock(&scrub->os_lock);
523 static int osd_scrub_exec(const struct lu_env *env, struct osd_device *dev,
524 const struct lu_fid *fid, uint64_t oid, int rc)
526 struct lustre_scrub *scrub = &dev->od_scrub;
527 struct ptlrpc_thread *thread = &scrub->os_thread;
528 struct osd_otable_it *it = dev->od_otable_it;
530 rc = osd_scrub_check_update(env, dev, fid, oid, rc);
531 if (!scrub->os_in_prior) {
532 if (!scrub->os_full_speed) {
533 spin_lock(&scrub->os_lock);
534 it->ooi_prefetched++;
535 if (it->ooi_waiting) {
537 wake_up_all(&thread->t_ctl_waitq);
539 spin_unlock(&scrub->os_lock);
542 scrub->os_in_prior = 0;
548 rc = scrub_checkpoint(env, scrub);
550 CDEBUG(D_LFSCK, "%s: fail to checkpoint, pos = %llu: "
551 "rc = %d\n", scrub->os_name, scrub->os_pos_current, rc);
552 /* Continue, as long as the scrub itself can go ahead. */
558 static int osd_scrub_main(void *args)
561 struct osd_device *dev = (struct osd_device *)args;
562 struct lustre_scrub *scrub = &dev->od_scrub;
563 struct ptlrpc_thread *thread = &scrub->os_thread;
569 rc = lu_env_init(&env, LCT_LOCAL | LCT_DT_THREAD);
571 CDEBUG(D_LFSCK, "%s: OI scrub fail to init env: rc = %d\n",
576 rc = osd_scrub_prep(&env, dev);
578 CDEBUG(D_LFSCK, "%s: OI scrub fail to scrub prep: rc = %d\n",
583 if (!scrub->os_full_speed) {
584 struct l_wait_info lwi = { 0 };
585 struct osd_otable_it *it = dev->od_otable_it;
587 l_wait_event(thread->t_ctl_waitq,
588 it->ooi_user_ready || !thread_is_running(thread),
590 if (unlikely(!thread_is_running(thread)))
593 scrub->os_pos_current = it->ooi_pos;
596 CDEBUG(D_LFSCK, "%s: OI scrub start, flags = 0x%x, pos = %llu\n",
597 scrub->os_name, scrub->os_start_flags,
598 scrub->os_pos_current);
600 fid = &osd_oti_get(&env)->oti_fid;
601 while (!rc && thread_is_running(thread)) {
602 rc = osd_scrub_next(&env, dev, fid, &oid);
604 case SCRUB_NEXT_EXIT:
606 case SCRUB_NEXT_CRASH:
607 spin_lock(&scrub->os_lock);
608 thread_set_flags(&scrub->os_thread, SVC_STOPPING);
609 spin_unlock(&scrub->os_lock);
610 GOTO(out, rc = -EINVAL);
611 case SCRUB_NEXT_FATAL:
612 GOTO(post, rc = -EINVAL);
613 case SCRUB_NEXT_BREAK:
617 rc = osd_scrub_exec(&env, dev, fid, oid, rc);
623 rc = osd_scrub_post(&env, dev, rc);
624 CDEBUG(D_LFSCK, "%s: OI scrub: stop, pos = %llu: rc = %d\n",
625 scrub->os_name, scrub->os_pos_current, rc);
628 while (!list_empty(&scrub->os_inconsistent_items)) {
629 struct osd_inconsistent_item *oii;
631 oii = list_entry(scrub->os_inconsistent_items.next,
632 struct osd_inconsistent_item, oii_list);
633 list_del_init(&oii->oii_list);
640 spin_lock(&scrub->os_lock);
641 thread_set_flags(thread, SVC_STOPPED);
642 wake_up_all(&thread->t_ctl_waitq);
643 spin_unlock(&scrub->os_lock);
647 /* initial OI scrub */
651 typedef int (*handle_dirent_t)(const struct lu_env *, struct osd_device *,
652 const char *, uint64_t, uint64_t,
653 enum osd_lf_flags, bool);
654 static int osd_ios_varfid_hd(const struct lu_env *, struct osd_device *,
655 const char *, uint64_t, uint64_t,
656 enum osd_lf_flags, bool);
657 static int osd_ios_uld_hd(const struct lu_env *, struct osd_device *,
658 const char *, uint64_t, uint64_t,
659 enum osd_lf_flags, bool);
661 typedef int (*scan_dir_t)(const struct lu_env *, struct osd_device *,
662 uint64_t, handle_dirent_t, enum osd_lf_flags);
663 static int osd_ios_general_sd(const struct lu_env *, struct osd_device *,
664 uint64_t, handle_dirent_t, enum osd_lf_flags);
665 static int osd_ios_ROOT_sd(const struct lu_env *, struct osd_device *,
666 uint64_t, handle_dirent_t, enum osd_lf_flags);
670 struct lu_fid olm_fid;
671 enum osd_lf_flags olm_flags;
672 scan_dir_t olm_scan_dir;
673 handle_dirent_t olm_handle_dirent;
676 /* Add the new introduced local files in the list in the future. */
677 static const struct osd_lf_map osd_lf_maps[] = {
680 .olm_name = MOUNT_CONFIGS_DIR,
682 .f_seq = FID_SEQ_LOCAL_FILE,
683 .f_oid = MGS_CONFIGS_OID,
685 .olm_flags = OLF_SCAN_SUBITEMS,
686 .olm_scan_dir = osd_ios_general_sd,
687 .olm_handle_dirent = osd_ios_varfid_hd,
690 /* NIDTBL_VERSIONS */
692 .olm_name = MGS_NIDTBL_DIR,
693 .olm_flags = OLF_SCAN_SUBITEMS,
694 .olm_scan_dir = osd_ios_general_sd,
695 .olm_handle_dirent = osd_ios_varfid_hd,
700 .olm_name = "PENDING",
707 .f_seq = FID_SEQ_ROOT,
708 .f_oid = FID_OID_ROOT,
710 .olm_flags = OLF_SCAN_SUBITEMS,
711 .olm_scan_dir = osd_ios_ROOT_sd,
718 .f_seq = FID_SEQ_LOCAL_FILE,
719 .f_oid = FLD_INDEX_OID,
723 /* changelog_catalog */
725 .olm_name = CHANGELOG_CATALOG,
728 /* changelog_users */
730 .olm_name = CHANGELOG_USERS,
736 .olm_flags = OLF_SCAN_SUBITEMS,
737 .olm_scan_dir = osd_ios_general_sd,
738 .olm_handle_dirent = osd_ios_varfid_hd,
744 .olm_flags = OLF_SCAN_SUBITEMS,
745 .olm_scan_dir = osd_ios_general_sd,
746 .olm_handle_dirent = osd_ios_varfid_hd,
751 .olm_name = LFSCK_DIR,
752 .olm_flags = OLF_SCAN_SUBITEMS,
753 .olm_scan_dir = osd_ios_general_sd,
754 .olm_handle_dirent = osd_ios_varfid_hd,
759 .olm_name = LFSCK_BOOKMARK,
764 .olm_name = LFSCK_LAYOUT,
767 /* lfsck_namespace */
769 .olm_name = LFSCK_NAMESPACE,
772 /* OSP update logs update_log{_dir} use f_seq = FID_SEQ_UPDATE_LOG{_DIR}
773 * and f_oid = index for their log files. See lu_update_log{_dir}_fid()
774 * for more details. */
778 .olm_name = "update_log",
780 .f_seq = FID_SEQ_UPDATE_LOG,
782 .olm_flags = OLF_IDX_IN_FID,
787 .olm_name = "update_log_dir",
789 .f_seq = FID_SEQ_UPDATE_LOG_DIR,
791 .olm_flags = OLF_SCAN_SUBITEMS | OLF_IDX_IN_FID,
792 .olm_scan_dir = osd_ios_general_sd,
793 .olm_handle_dirent = osd_ios_uld_hd,
798 .olm_name = HSM_ACTIONS,
803 .olm_name = LUSTRE_NODEMAP_NAME,
811 /* Add the new introduced files under .lustre/ in the list in the future. */
812 static const struct osd_lf_map osd_dl_maps[] = {
817 .f_seq = FID_SEQ_DOT_LUSTRE,
818 .f_oid = FID_OID_DOT_LUSTRE_OBF,
822 /* .lustre/lost+found */
824 .olm_name = "lost+found",
826 .f_seq = FID_SEQ_DOT_LUSTRE,
827 .f_oid = FID_OID_DOT_LUSTRE_LPF,
836 struct osd_ios_item {
837 struct list_head oii_list;
839 enum osd_lf_flags oii_flags;
840 scan_dir_t oii_scan_dir;
841 handle_dirent_t oii_handle_dirent;
844 static int osd_ios_new_item(struct osd_device *dev, uint64_t parent,
845 enum osd_lf_flags flags, scan_dir_t scan_dir,
846 handle_dirent_t handle_dirent)
848 struct osd_ios_item *item;
852 CWARN("%s: initial OI scrub failed to add item for %llu\n",
853 osd_name(dev), parent);
857 INIT_LIST_HEAD(&item->oii_list);
858 item->oii_parent = parent;
859 item->oii_flags = flags;
860 item->oii_scan_dir = scan_dir;
861 item->oii_handle_dirent = handle_dirent;
862 list_add_tail(&item->oii_list, &dev->od_ios_list);
868 * verify FID-in-LMA and OI entry for one object
870 * ios: Initial OI Scrub.
872 static int osd_ios_scan_one(const struct lu_env *env, struct osd_device *dev,
873 const struct lu_fid *fid, uint64_t parent,
874 uint64_t oid, const char *name,
875 enum osd_lf_flags flags)
877 struct lustre_scrub *scrub = &dev->od_scrub;
878 struct scrub_file *sf = &scrub->os_file;
879 struct lustre_mdt_attrs *lma = NULL;
880 nvlist_t *nvbuf = NULL;
889 rc = __osd_xattr_load_by_oid(dev, oid, &nvbuf);
890 if (unlikely(rc == -ENOENT || rc == -EEXIST))
893 if (rc && rc != -ENODATA) {
894 CWARN("%s: initial OI scrub failed to get lma for %llu: "
895 "rc = %d\n", osd_name(dev), oid, rc);
901 LASSERT(nvbuf != NULL);
902 rc = -nvlist_lookup_byte_array(nvbuf, XATTR_NAME_LMA,
903 (uchar_t **)&lma, &size);
904 if (rc || size == 0) {
905 LASSERT(lma == NULL);
908 LASSERTF(lma != NULL, "corrupted LMA, size %d\n", size);
909 lustre_lma_swab(lma);
910 if (lma->lma_compat & LMAC_NOT_IN_OI) {
915 tfid = lma->lma_self_fid;
920 if (rc == -ENODATA) {
922 /* Skip the object without FID-in-LMA */
923 CDEBUG(D_LFSCK, "%s: %llu has no FID-in-LMA, skip it\n",
929 LASSERT(!fid_is_zero(fid));
932 if (flags & OLF_IDX_IN_FID) {
933 LASSERT(dev->od_index >= 0);
935 tfid.f_oid = dev->od_index;
939 rc = osd_fid_lookup(env, dev, &tfid, &oid2);
942 CWARN("%s: initial OI scrub failed to lookup fid for "
943 DFID"=>%llu: rc = %d\n",
944 osd_name(dev), PFID(&tfid), oid, rc);
950 op = DTO_INDEX_INSERT;
955 flag = SF_INCONSISTENT;
956 op = DTO_INDEX_UPDATE;
959 if (!(sf->sf_flags & flag)) {
960 scrub_file_reset(scrub, dev->od_uuid, flag);
961 rc = scrub_file_store(env, scrub);
966 rc = osd_scrub_refresh_mapping(env, dev, &tfid, oid, op, true, name);
968 RETURN(rc > 0 ? 0 : rc);
971 static int osd_ios_varfid_hd(const struct lu_env *env, struct osd_device *dev,
972 const char *name, uint64_t parent, uint64_t oid,
973 enum osd_lf_flags flags, bool is_dir)
978 rc = osd_ios_scan_one(env, dev, NULL, parent, oid, name, 0);
980 rc = osd_ios_new_item(dev, oid, flags, osd_ios_general_sd,
986 static int osd_ios_uld_hd(const struct lu_env *env, struct osd_device *dev,
987 const char *name, uint64_t parent, uint64_t oid,
988 enum osd_lf_flags flags, bool is_dir)
994 /* skip any non-DFID format name */
998 /* skip the start '[' */
999 sscanf(&name[1], SFID, RFID(&tfid));
1000 if (fid_is_sane(&tfid))
1001 rc = osd_ios_scan_one(env, dev, &tfid, parent, oid, name, 0);
1009 * General scanner for the directories execpt /ROOT during initial OI scrub.
1010 * It scans the name entries under the given directory one by one. For each
1011 * entry, verifies its OI mapping via the given @handle_dirent.
1013 static int osd_ios_general_sd(const struct lu_env *env, struct osd_device *dev,
1014 uint64_t parent, handle_dirent_t handle_dirent,
1015 enum osd_lf_flags flags)
1017 struct osd_thread_info *info = osd_oti_get(env);
1018 struct luz_direntry *zde = &info->oti_zde;
1019 zap_attribute_t *za = &info->oti_za;
1020 zap_cursor_t *zc = &info->oti_zc;
1024 zap_cursor_init_serialized(zc, dev->od_os, parent, 0);
1025 rc = -zap_cursor_retrieve(zc, za);
1027 zap_cursor_advance(zc);
1032 rc = -zap_cursor_retrieve(zc, za);
1034 GOTO(log, rc = (rc == -ENOENT ? 0 : rc));
1036 /* skip the entry started with '.' */
1037 if (likely(za->za_name[0] != '.')) {
1038 rc = osd_zap_lookup(dev, parent, NULL, za->za_name,
1039 za->za_integer_length,
1040 sizeof(*zde) / za->za_integer_length,
1043 CWARN("%s: initial OI scrub failed to lookup "
1044 "%s under %llu: rc = %d\n",
1045 osd_name(dev), za->za_name, parent, rc);
1049 rc = handle_dirent(env, dev, za->za_name, parent,
1050 zde->lzd_reg.zde_dnode, flags,
1051 S_ISDIR(DTTOIF(zde->lzd_reg.zde_type)) ?
1053 CDEBUG(D_LFSCK, "%s: initial OI scrub handled %s under "
1055 osd_name(dev), za->za_name, parent, rc);
1058 zap_cursor_advance(zc);
1063 CWARN("%s: initial OI scrub failed to scan the directory %llu: "
1064 "rc = %d\n", osd_name(dev), parent, rc);
1065 zap_cursor_fini(zc);
1071 * The scanner for /ROOT directory. It is not all the items under /ROOT will
1072 * be scanned during the initial OI scrub, instead, only the .lustre and the
1073 * sub-items under .lustre will be handled.
1075 static int osd_ios_ROOT_sd(const struct lu_env *env, struct osd_device *dev,
1076 uint64_t parent, handle_dirent_t handle_dirent,
1077 enum osd_lf_flags flags)
1079 struct luz_direntry *zde = &osd_oti_get(env)->oti_zde;
1080 const struct osd_lf_map *map;
1086 rc = osd_zap_lookup(dev, parent, NULL, dot_lustre_name, 8,
1087 sizeof(*zde) / 8, (void *)zde);
1088 if (rc == -ENOENT) {
1089 /* The .lustre directory is lost. That is not fatal. It can
1090 * be re-created in the subsequent MDT start processing. */
1095 CWARN("%s: initial OI scrub failed to find .lustre: "
1096 "rc = %d\n", osd_name(dev), rc);
1101 oid = zde->lzd_reg.zde_dnode;
1102 rc = osd_ios_scan_one(env, dev, &LU_DOT_LUSTRE_FID, parent, oid,
1103 dot_lustre_name, 0);
1107 for (map = osd_dl_maps; map->olm_name; map++) {
1108 rc = osd_zap_lookup(dev, oid, NULL, map->olm_name, 8,
1109 sizeof(*zde) / 8, (void *)zde);
1112 CWARN("%s: initial OI scrub failed to find"
1113 "the entry %s under .lustre: rc = %d\n",
1114 osd_name(dev), map->olm_name, rc);
1115 else if (!fid_is_zero(&map->olm_fid))
1116 /* Try to remove the stale OI mapping. */
1117 osd_scrub_refresh_mapping(env, dev,
1119 DTO_INDEX_DELETE, true,
1124 rc = osd_ios_scan_one(env, dev, &map->olm_fid, oid,
1125 zde->lzd_reg.zde_dnode, map->olm_name,
1134 static void osd_initial_OI_scrub(const struct lu_env *env,
1135 struct osd_device *dev)
1137 struct luz_direntry *zde = &osd_oti_get(env)->oti_zde;
1138 const struct osd_lf_map *map;
1142 for (map = osd_lf_maps; map->olm_name; map++) {
1143 rc = osd_zap_lookup(dev, dev->od_root, NULL, map->olm_name, 8,
1144 sizeof(*zde) / 8, (void *)zde);
1147 CWARN("%s: initial OI scrub failed "
1148 "to find the entry %s: rc = %d\n",
1149 osd_name(dev), map->olm_name, rc);
1150 else if (!fid_is_zero(&map->olm_fid))
1151 /* Try to remove the stale OI mapping. */
1152 osd_scrub_refresh_mapping(env, dev,
1154 DTO_INDEX_DELETE, true,
1159 rc = osd_ios_scan_one(env, dev, &map->olm_fid, dev->od_root,
1160 zde->lzd_reg.zde_dnode, map->olm_name,
1162 if (!rc && map->olm_flags & OLF_SCAN_SUBITEMS)
1163 osd_ios_new_item(dev, zde->lzd_reg.zde_dnode,
1164 map->olm_flags, map->olm_scan_dir,
1165 map->olm_handle_dirent);
1168 while (!list_empty(&dev->od_ios_list)) {
1169 struct osd_ios_item *item;
1171 item = list_entry(dev->od_ios_list.next,
1172 struct osd_ios_item, oii_list);
1173 list_del_init(&item->oii_list);
1174 item->oii_scan_dir(env, dev, item->oii_parent,
1175 item->oii_handle_dirent, item->oii_flags);
1182 /* OI scrub start/stop */
1184 int osd_scrub_start(const struct lu_env *env, struct osd_device *dev,
1190 if (dev->od_dt_dev.dd_rdonly)
1193 /* od_otable_sem: prevent concurrent start/stop */
1194 down(&dev->od_otable_sem);
1195 rc = scrub_start(osd_scrub_main, &dev->od_scrub, dev, flags);
1196 up(&dev->od_otable_sem);
1198 RETURN(rc == -EALREADY ? 0 : rc);
1201 static void osd_scrub_stop(struct osd_device *dev)
1203 struct lustre_scrub *scrub = &dev->od_scrub;
1206 /* od_otable_sem: prevent concurrent start/stop */
1207 down(&dev->od_otable_sem);
1208 scrub->os_paused = 1;
1210 up(&dev->od_otable_sem);
1215 /* OI scrub setup/cleanup */
1217 static const char osd_scrub_name[] = "OI_scrub";
1219 int osd_scrub_setup(const struct lu_env *env, struct osd_device *dev)
1221 struct osd_thread_info *info = osd_oti_get(env);
1222 struct lustre_scrub *scrub = &dev->od_scrub;
1223 struct scrub_file *sf = &scrub->os_file;
1224 struct lu_fid *fid = &info->oti_fid;
1225 struct dt_object *obj;
1231 memcpy(dev->od_uuid,
1232 &dsl_dataset_phys(dev->od_os->os_dsl_dataset)->ds_guid,
1233 sizeof(dsl_dataset_phys(dev->od_os->os_dsl_dataset)->ds_guid));
1234 memset(&dev->od_scrub, 0, sizeof(struct lustre_scrub));
1235 init_waitqueue_head(&scrub->os_thread.t_ctl_waitq);
1236 init_rwsem(&scrub->os_rwsem);
1237 spin_lock_init(&scrub->os_lock);
1238 INIT_LIST_HEAD(&scrub->os_inconsistent_items);
1239 scrub->os_name = osd_name(dev);
1241 /* 'What the @fid is' is not imporatant, because the object
1242 * has no OI mapping, and only is visible inside the OSD.*/
1243 fid->f_seq = FID_SEQ_IGIF_MAX;
1245 fid->f_oid = ((1 << 31) | dev->od_index) + 1;
1247 fid->f_oid = dev->od_index + 1;
1249 rc = osd_obj_find_or_create(env, dev, dev->od_root,
1250 osd_scrub_name, &oid, fid, false);
1254 rc = osd_idc_find_and_init_with_oid(env, dev, fid, oid);
1258 obj = lu2dt(lu_object_find_slice(env, osd2lu_dev(dev), fid, NULL));
1259 if (IS_ERR_OR_NULL(obj))
1260 RETURN(obj ? PTR_ERR(obj) : -ENOENT);
1262 scrub->os_obj = obj;
1263 rc = scrub_file_load(env, scrub);
1264 if (rc == -ENOENT || rc == -EFAULT) {
1265 scrub_file_init(scrub, dev->od_uuid);
1267 } else if (rc < 0) {
1268 GOTO(cleanup_obj, rc);
1270 if (memcmp(sf->sf_uuid, dev->od_uuid, 16) != 0) {
1271 struct obd_uuid *old_uuid;
1272 struct obd_uuid *new_uuid;
1274 OBD_ALLOC_PTR(old_uuid);
1275 OBD_ALLOC_PTR(new_uuid);
1276 if (!old_uuid || !new_uuid) {
1277 CERROR("%s: UUID has been changed, but"
1278 "failed to allocate RAM for report\n",
1281 class_uuid_unparse(sf->sf_uuid, old_uuid);
1282 class_uuid_unparse(dev->od_uuid, new_uuid);
1283 CDEBUG(D_LFSCK, "%s: UUID has been changed "
1284 "from %s to %s\n", osd_name(dev),
1285 old_uuid->uuid, new_uuid->uuid);
1287 scrub_file_reset(scrub, dev->od_uuid, SF_INCONSISTENT);
1290 OBD_FREE_PTR(old_uuid);
1292 OBD_FREE_PTR(new_uuid);
1293 } else if (sf->sf_status == SS_SCANNING) {
1294 sf->sf_status = SS_CRASHED;
1298 if ((sf->sf_oi_count & (sf->sf_oi_count - 1)) != 0) {
1299 LCONSOLE_WARN("%s: invalid oi count %d, set it to %d\n",
1300 osd_name(dev), sf->sf_oi_count,
1302 sf->sf_oi_count = osd_oi_count;
1307 if (sf->sf_pos_last_checkpoint != 0)
1308 scrub->os_pos_current = sf->sf_pos_last_checkpoint + 1;
1310 scrub->os_pos_current = 1;
1313 rc = scrub_file_store(env, scrub);
1315 GOTO(cleanup_obj, rc);
1318 /* Initialize OI files. */
1319 rc = osd_oi_init(env, dev);
1321 GOTO(cleanup_obj, rc);
1323 if (!dev->od_dt_dev.dd_rdonly)
1324 osd_initial_OI_scrub(env, dev);
1326 if (!dev->od_dt_dev.dd_rdonly &&
1327 dev->od_auto_scrub_interval != AS_NEVER &&
1328 ((sf->sf_status == SS_PAUSED) ||
1329 (sf->sf_status == SS_CRASHED &&
1330 sf->sf_flags & (SF_RECREATED | SF_INCONSISTENT |
1331 SF_UPGRADE | SF_AUTO)) ||
1332 (sf->sf_status == SS_INIT &&
1333 sf->sf_flags & (SF_RECREATED | SF_INCONSISTENT |
1335 rc = osd_scrub_start(env, dev, SS_AUTO_FULL);
1338 GOTO(cleanup_oi, rc);
1343 osd_oi_fini(env, dev);
1345 dt_object_put_nocache(env, scrub->os_obj);
1346 scrub->os_obj = NULL;
1351 void osd_scrub_cleanup(const struct lu_env *env, struct osd_device *dev)
1353 struct lustre_scrub *scrub = &dev->od_scrub;
1355 LASSERT(!dev->od_otable_it);
1357 if (scrub->os_obj) {
1358 osd_scrub_stop(dev);
1359 dt_object_put_nocache(env, scrub->os_obj);
1360 scrub->os_obj = NULL;
1363 if (dev->od_oi_table)
1364 osd_oi_fini(env, dev);
1367 /* object table based iteration APIs */
1369 static struct dt_it *osd_otable_it_init(const struct lu_env *env,
1370 struct dt_object *dt, __u32 attr)
1372 enum dt_otable_it_flags flags = attr >> DT_OTABLE_IT_FLAGS_SHIFT;
1373 enum dt_otable_it_valid valid = attr & ~DT_OTABLE_IT_FLAGS_MASK;
1374 struct osd_device *dev = osd_dev(dt->do_lu.lo_dev);
1375 struct lustre_scrub *scrub = &dev->od_scrub;
1376 struct osd_otable_it *it;
1381 if (dev->od_dt_dev.dd_rdonly)
1382 RETURN(ERR_PTR(-EROFS));
1384 /* od_otable_sem: prevent concurrent init/fini */
1385 down(&dev->od_otable_sem);
1386 if (dev->od_otable_it)
1387 GOTO(out, it = ERR_PTR(-EALREADY));
1391 GOTO(out, it = ERR_PTR(-ENOMEM));
1393 if (flags & DOIF_OUTUSED)
1394 it->ooi_used_outside = 1;
1396 if (flags & DOIF_RESET)
1399 if (valid & DOIV_ERROR_HANDLE) {
1400 if (flags & DOIF_FAILOUT)
1401 start |= SS_SET_FAILOUT;
1403 start |= SS_CLEAR_FAILOUT;
1406 if (valid & DOIV_DRYRUN) {
1407 if (flags & DOIF_DRYRUN)
1408 start |= SS_SET_DRYRUN;
1410 start |= SS_CLEAR_DRYRUN;
1413 /* XXX: dmu_object_next() does NOT find dnodes allocated
1414 * in the current non-committed txg, so we force txg
1415 * commit to find all existing dnodes ... */
1416 txg_wait_synced(dmu_objset_pool(dev->od_os), 0ULL);
1418 dev->od_otable_it = it;
1420 rc = scrub_start(osd_scrub_main, scrub, dev, start & ~SS_AUTO_PARTIAL);
1421 if (rc == -EALREADY) {
1423 } else if (rc < 0) {
1424 dev->od_otable_it = NULL;
1428 it->ooi_pos = scrub->os_pos_current;
1434 up(&dev->od_otable_sem);
1435 return (struct dt_it *)it;
1438 static void osd_otable_it_fini(const struct lu_env *env, struct dt_it *di)
1440 struct osd_otable_it *it = (struct osd_otable_it *)di;
1441 struct osd_device *dev = it->ooi_dev;
1443 /* od_otable_sem: prevent concurrent init/fini */
1444 down(&dev->od_otable_sem);
1445 scrub_stop(&dev->od_scrub);
1446 LASSERT(dev->od_otable_it == it);
1448 dev->od_otable_it = NULL;
1449 up(&dev->od_otable_sem);
1453 static int osd_otable_it_get(const struct lu_env *env,
1454 struct dt_it *di, const struct dt_key *key)
1459 static void osd_otable_it_put(const struct lu_env *env, struct dt_it *di)
1463 static void osd_otable_it_preload(const struct lu_env *env,
1464 struct osd_otable_it *it)
1466 struct osd_device *dev = it->ooi_dev;
1469 /* can go negative on the very first access to the iterator
1470 * or if some non-Lustre objects were found */
1471 if (unlikely(it->ooi_prefetched < 0))
1472 it->ooi_prefetched = 0;
1474 if (it->ooi_prefetched >= (OTABLE_PREFETCH >> 1))
1477 if (it->ooi_prefetched_dnode == 0)
1478 it->ooi_prefetched_dnode = it->ooi_pos;
1480 while (it->ooi_prefetched < OTABLE_PREFETCH) {
1481 rc = -dmu_object_next(dev->od_os, &it->ooi_prefetched_dnode,
1486 osd_dmu_prefetch(dev->od_os, it->ooi_prefetched_dnode,
1487 0, 0, 0, ZIO_PRIORITY_ASYNC_READ);
1488 it->ooi_prefetched++;
1493 osd_otable_it_wakeup(struct lustre_scrub *scrub, struct osd_otable_it *it)
1495 spin_lock(&scrub->os_lock);
1496 if (it->ooi_pos < scrub->os_pos_current || scrub->os_waiting ||
1497 !thread_is_running(&scrub->os_thread))
1498 it->ooi_waiting = 0;
1500 it->ooi_waiting = 1;
1501 spin_unlock(&scrub->os_lock);
1503 return !it->ooi_waiting;
1506 static int osd_otable_it_next(const struct lu_env *env, struct dt_it *di)
1508 struct osd_otable_it *it = (struct osd_otable_it *)di;
1509 struct osd_device *dev = it->ooi_dev;
1510 struct lustre_scrub *scrub = &dev->od_scrub;
1511 struct ptlrpc_thread *thread = &scrub->os_thread;
1512 struct l_wait_info lwi = { 0 };
1513 struct lustre_mdt_attrs *lma = NULL;
1514 nvlist_t *nvbuf = NULL;
1519 LASSERT(it->ooi_user_ready);
1520 fid_zero(&it->ooi_fid);
1522 if (unlikely(it->ooi_all_cached))
1533 if (it->ooi_pos >= scrub->os_pos_current)
1534 l_wait_event(thread->t_ctl_waitq,
1535 osd_otable_it_wakeup(scrub, it),
1538 if (!thread_is_running(thread) && !it->ooi_used_outside)
1541 rc = -dmu_object_next(dev->od_os, &it->ooi_pos, B_FALSE, 0);
1543 if (unlikely(rc == -ESRCH)) {
1544 it->ooi_all_cached = 1;
1551 rc = __osd_xattr_load_by_oid(dev, it->ooi_pos, &nvbuf);
1553 if (!scrub->os_full_speed)
1554 spin_lock(&scrub->os_lock);
1555 it->ooi_prefetched--;
1556 if (!scrub->os_full_speed) {
1557 if (scrub->os_waiting) {
1558 scrub->os_waiting = 0;
1559 wake_up_all(&thread->t_ctl_waitq);
1561 spin_unlock(&scrub->os_lock);
1564 if (rc == -ENOENT || rc == -EEXIST || rc == -ENODATA)
1570 LASSERT(nvbuf != NULL);
1571 rc = -nvlist_lookup_byte_array(nvbuf, XATTR_NAME_LMA,
1572 (uchar_t **)&lma, &size);
1573 if (rc || size == 0)
1574 /* It is either non-Lustre object or OSD internal object,
1575 * ignore it, go ahead */
1578 LASSERTF(lma != NULL, "corrupted LMA, size %d\n", size);
1579 lustre_lma_swab(lma);
1580 if (unlikely(lma->lma_compat & LMAC_NOT_IN_OI ||
1581 lma->lma_incompat & LMAI_AGENT))
1584 it->ooi_fid = lma->lma_self_fid;
1592 if (!rc && scrub->os_full_speed)
1593 osd_otable_it_preload(env, it);
1598 static struct dt_key *osd_otable_it_key(const struct lu_env *env,
1599 const struct dt_it *di)
1604 static int osd_otable_it_key_size(const struct lu_env *env,
1605 const struct dt_it *di)
1607 return sizeof(__u64);
1610 static int osd_otable_it_rec(const struct lu_env *env, const struct dt_it *di,
1611 struct dt_rec *rec, __u32 attr)
1613 struct osd_otable_it *it = (struct osd_otable_it *)di;
1614 struct lu_fid *fid = (struct lu_fid *)rec;
1620 static __u64 osd_otable_it_store(const struct lu_env *env,
1621 const struct dt_it *di)
1623 struct osd_otable_it *it = (struct osd_otable_it *)di;
1629 * Set the OSD layer iteration start position as the specified hash.
1631 static int osd_otable_it_load(const struct lu_env *env,
1632 const struct dt_it *di, __u64 hash)
1634 struct osd_otable_it *it = (struct osd_otable_it *)di;
1635 struct osd_device *dev = it->ooi_dev;
1636 struct lustre_scrub *scrub = &dev->od_scrub;
1640 /* Forbid to set iteration position after iteration started. */
1641 if (it->ooi_user_ready)
1644 if (hash > OSD_OTABLE_MAX_HASH)
1645 hash = OSD_OTABLE_MAX_HASH;
1647 /* The hash is the last checkpoint position,
1648 * we will start from the next one. */
1649 it->ooi_pos = hash + 1;
1650 it->ooi_prefetched = 0;
1651 it->ooi_prefetched_dnode = 0;
1652 it->ooi_user_ready = 1;
1653 if (!scrub->os_full_speed)
1654 wake_up_all(&scrub->os_thread.t_ctl_waitq);
1656 /* Unplug OSD layer iteration by the first next() call. */
1657 rc = osd_otable_it_next(env, (struct dt_it *)it);
1662 static int osd_otable_it_key_rec(const struct lu_env *env,
1663 const struct dt_it *di, void *key_rec)
1668 const struct dt_index_operations osd_otable_ops = {
1670 .init = osd_otable_it_init,
1671 .fini = osd_otable_it_fini,
1672 .get = osd_otable_it_get,
1673 .put = osd_otable_it_put,
1674 .next = osd_otable_it_next,
1675 .key = osd_otable_it_key,
1676 .key_size = osd_otable_it_key_size,
1677 .rec = osd_otable_it_rec,
1678 .store = osd_otable_it_store,
1679 .load = osd_otable_it_load,
1680 .key_rec = osd_otable_it_key_rec,
1684 /* high priority inconsistent items list APIs */
1686 int osd_oii_insert(const struct lu_env *env, struct osd_device *dev,
1687 const struct lu_fid *fid, uint64_t oid, bool insert)
1689 struct lustre_scrub *scrub = &dev->od_scrub;
1690 struct ptlrpc_thread *thread = &scrub->os_thread;
1691 struct osd_inconsistent_item *oii;
1692 bool wakeup = false;
1695 osd_idc_find_and_init_with_oid(env, dev, fid, oid);
1700 INIT_LIST_HEAD(&oii->oii_list);
1701 oii->oii_cache.oic_dev = dev;
1702 oii->oii_cache.oic_fid = *fid;
1703 oii->oii_cache.oic_dnode = oid;
1704 oii->oii_insert = insert;
1706 spin_lock(&scrub->os_lock);
1707 if (unlikely(!thread_is_running(thread))) {
1708 spin_unlock(&scrub->os_lock);
1713 if (list_empty(&scrub->os_inconsistent_items))
1715 list_add_tail(&oii->oii_list, &scrub->os_inconsistent_items);
1716 spin_unlock(&scrub->os_lock);
1719 wake_up_all(&thread->t_ctl_waitq);
1724 int osd_oii_lookup(struct osd_device *dev, const struct lu_fid *fid,
1727 struct lustre_scrub *scrub = &dev->od_scrub;
1728 struct osd_inconsistent_item *oii;
1732 spin_lock(&scrub->os_lock);
1733 list_for_each_entry(oii, &scrub->os_inconsistent_items, oii_list) {
1734 if (lu_fid_eq(fid, &oii->oii_cache.oic_fid)) {
1735 *oid = oii->oii_cache.oic_dnode;
1740 spin_unlock(&scrub->os_lock);