#include "osd_oi.h"
#include "osd_scrub.h"
-#define HALF_SEC (CFS_HZ >> 1)
+#define HALF_SEC (HZ >> 1)
#define OSD_OTABLE_MAX_HASH 0x00000000ffffffffULL
struct osd_device *dev,
const struct lu_fid *fid,
const struct osd_inode_id *id,
- int ops, enum oi_check_flags flags)
+ int ops, bool force,
+ enum oi_check_flags flags)
{
- const struct lu_env *env = info->oti_env;
- struct thandle *th;
- struct osd_thandle *oh;
- int rc;
+ handle_t *th;
+ int rc;
ENTRY;
- th = dt_trans_create(env, &dev->od_dt_dev);
- if (IS_ERR(th))
- RETURN(PTR_ERR(th));
+ if (dev->od_scrub.os_file.sf_param & SP_DRYRUN && !force)
+ RETURN(0);
- oh = container_of0(th, struct osd_thandle, ot_super);
- LASSERT(oh->ot_handle == NULL);
+ /* DTO_INDEX_INSERT is enough for other two ops:
+ * delete/update, but save stack. */
+ th = ldiskfs_journal_start_sb(osd_sb(dev),
+ osd_dto_credits_noquota[DTO_INDEX_INSERT]);
+ if (IS_ERR(th)) {
+ rc = PTR_ERR(th);
+ CERROR("%s: fail to start trans for scrub %d: rc = %d\n",
+ osd_name(dev), ops, rc);
+ RETURN(rc);
+ }
switch (ops) {
case DTO_INDEX_UPDATE:
- osd_trans_declare_op(env, oh, OSD_OT_UPDATE,
- osd_dto_credits_noquota[DTO_INDEX_UPDATE]);
- rc = dt_trans_start_local(env, &dev->od_dt_dev, th);
- if (rc != 0)
- GOTO(stop, rc);
-
rc = osd_oi_update(info, dev, fid, id, th, flags);
if (unlikely(rc == -ENOENT)) {
/* Some unlink thread may removed the OI mapping. */
}
break;
case DTO_INDEX_INSERT:
- osd_trans_declare_op(env, oh, OSD_OT_INSERT,
- osd_dto_credits_noquota[DTO_INDEX_INSERT]);
- rc = dt_trans_start_local(env, &dev->od_dt_dev, th);
- if (rc != 0)
- GOTO(stop, rc);
-
rc = osd_oi_insert(info, dev, fid, id, th, flags);
if (unlikely(rc == -EEXIST)) {
rc = 1;
}
break;
case DTO_INDEX_DELETE:
- osd_trans_declare_op(env, oh, OSD_OT_DELETE,
- osd_dto_credits_noquota[DTO_INDEX_DELETE]);
- rc = dt_trans_start_local(env, &dev->od_dt_dev, th);
- if (rc != 0)
- GOTO(stop, rc);
-
rc = osd_oi_delete(info, dev, fid, th, flags);
if (rc == -ENOENT) {
/* It is normal that the unlink thread has removed the
break;
}
- GOTO(stop, rc);
-
-stop:
- dt_trans_stop(env, &dev->od_dt_dev, th);
+ ldiskfs_journal_stop(th);
return rc;
}
memcpy(sf->sf_uuid, uuid, 16);
sf->sf_status = SS_INIT;
sf->sf_flags |= flags;
- sf->sf_param = 0;
sf->sf_run_time = 0;
sf->sf_time_latest_start = 0;
sf->sf_time_last_checkpoint = 0;
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 = ldiskfs_journal_start_sb(osd_sb(dev), credits);
+ jh = osd_journal_start_sb(osd_sb(dev), LDISKFS_HT_MISC, credits);
if (IS_ERR(jh)) {
rc = PTR_ERR(jh);
CERROR("%.16s: fail to start trans for scrub store, rc = %d\n",
return rc;
}
-/* OI scrub APIs */
-
-static int osd_scrub_prep(struct osd_device *dev)
-{
- struct osd_scrub *scrub = &dev->od_scrub;
- struct ptlrpc_thread *thread = &scrub->os_thread;
- struct scrub_file *sf = &scrub->os_file;
- __u32 flags = scrub->os_start_flags;
- int rc;
- ENTRY;
-
- down_write(&scrub->os_rwsem);
- if (flags & SS_SET_FAILOUT)
- sf->sf_param |= SP_FAILOUT;
-
- if (flags & SS_CLEAR_FAILOUT)
- sf->sf_param &= ~SP_FAILOUT;
-
- if (flags & SS_RESET)
- osd_scrub_file_reset(scrub,
- LDISKFS_SB(osd_sb(dev))->s_es->s_uuid, 0);
-
- if (flags & SS_AUTO) {
- scrub->os_full_speed = 1;
- sf->sf_flags |= SF_AUTO;
- } else {
- scrub->os_full_speed = 0;
- }
-
- if (sf->sf_flags & (SF_RECREATED | SF_INCONSISTENT | SF_UPGRADE))
- scrub->os_full_speed = 1;
-
- scrub->os_in_prior = 0;
- scrub->os_waiting = 0;
- scrub->os_paused = 0;
- scrub->os_new_checked = 0;
- if (sf->sf_pos_last_checkpoint != 0)
- sf->sf_pos_latest_start = sf->sf_pos_last_checkpoint + 1;
- else
- sf->sf_pos_latest_start = LDISKFS_FIRST_INO(osd_sb(dev)) + 1;
-
- scrub->os_pos_current = sf->sf_pos_latest_start;
- sf->sf_status = SS_SCANNING;
- sf->sf_time_latest_start = cfs_time_current_sec();
- sf->sf_time_last_checkpoint = sf->sf_time_latest_start;
- rc = osd_scrub_file_store(scrub);
- if (rc == 0) {
- spin_lock(&scrub->os_lock);
- thread_set_flags(thread, SVC_RUNNING);
- spin_unlock(&scrub->os_lock);
- cfs_waitq_broadcast(&thread->t_ctl_waitq);
- }
- up_write(&scrub->os_rwsem);
-
- 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)
bool reset = true;
ENTRY;
+ if (dev->od_scrub.os_file.sf_param & SP_DRYRUN)
+ RETURN(0);
+
/* We want the LMA to fit into the 256-byte OST inode, so operate
* as following:
* 1) read old XATTR_NAME_FID and save the parent FID;
* Making the LMA to fit into the 256-byte OST inode can save time for
* normal osd_check_lma() and for other OI scrub scanning in future.
* So it is worth to make some slow conversion here. */
- jh = ldiskfs_journal_start_sb(osd_sb(dev),
+ jh = osd_journal_start_sb(osd_sb(dev), LDISKFS_HT_MISC,
osd_dto_credits_noquota[DTO_XATTR_SET] * 3);
if (IS_ERR(jh)) {
rc = PTR_ERR(jh);
rc1 = __osd_xattr_set(info, inode, XATTR_NAME_FID, ff, size,
XATTR_CREATE);
- if (rc1 != 0 && rc != 0)
+ if (rc1 != 0 && rc == 0)
rc = rc1;
}
sf->sf_internal_flags &= ~SIF_NO_HANDLE_OLD_FID;
dev->od_check_ff = 1;
rc = osd_scrub_convert_ff(info, dev, inode, fid);
- rc = osd_ea_fid_set(info, inode, fid,
- LMAC_FID_ON_OST, 0);
if (rc != 0)
GOTO(out, rc);
switch (val) {
case SCRUB_NEXT_NOLMA:
sf->sf_flags |= SF_UPGRADE;
- rc = osd_ea_fid_set(info, inode, fid, 0, 0);
- if (rc != 0)
- GOTO(out, rc);
+ if (!(sf->sf_param & SP_DRYRUN)) {
+ rc = osd_ea_fid_set(info, inode, fid, 0, 0);
+ if (rc != 0)
+ GOTO(out, rc);
+ }
if (!(sf->sf_flags & SF_INCONSISTENT))
dev->od_igif_inoi = 0;
dev->od_igif_inoi = 1;
}
- rc = osd_scrub_refresh_mapping(info, dev, fid, lid, ops,
+ rc = osd_scrub_refresh_mapping(info, dev, fid, lid, ops, false,
(val == SCRUB_NEXT_OSTOBJ ||
val == SCRUB_NEXT_OSTOBJ_OLD) ? OI_KNOWN_ON_OST : 0);
if (rc == 0) {
if (ops == DTO_INDEX_INSERT && inode != NULL && !IS_ERR(inode) &&
unlikely(inode->i_nlink == 0))
osd_scrub_refresh_mapping(info, dev, fid, lid,
- DTO_INDEX_DELETE,
+ DTO_INDEX_DELETE, false,
(val == SCRUB_NEXT_OSTOBJ ||
val == SCRUB_NEXT_OSTOBJ_OLD) ?
OI_KNOWN_ON_OST : 0);
RETURN(sf->sf_param & SP_FAILOUT ? rc : 0);
}
+/* OI scrub APIs */
+
+static int osd_scrub_prep(struct osd_device *dev)
+{
+ struct osd_scrub *scrub = &dev->od_scrub;
+ struct ptlrpc_thread *thread = &scrub->os_thread;
+ struct scrub_file *sf = &scrub->os_file;
+ __u32 flags = scrub->os_start_flags;
+ int rc;
+ bool drop_dryrun = false;
+ ENTRY;
+
+ down_write(&scrub->os_rwsem);
+ if (flags & SS_SET_FAILOUT)
+ sf->sf_param |= SP_FAILOUT;
+
+ if (flags & SS_CLEAR_FAILOUT)
+ sf->sf_param &= ~SP_FAILOUT;
+
+ if (flags & SS_SET_DRYRUN)
+ sf->sf_param |= SP_DRYRUN;
+
+ if (flags & SS_CLEAR_DRYRUN && sf->sf_param & SP_DRYRUN) {
+ sf->sf_param &= ~SP_DRYRUN;
+ drop_dryrun = true;
+ }
+
+ if (flags & SS_RESET)
+ osd_scrub_file_reset(scrub,
+ LDISKFS_SB(osd_sb(dev))->s_es->s_uuid, 0);
+
+ if (flags & SS_AUTO) {
+ scrub->os_full_speed = 1;
+ sf->sf_flags |= SF_AUTO;
+ /* For the case of OI scrub auto triggered, NOT dryrun. */
+ sf->sf_param &= ~SP_FAILOUT;
+ } else {
+ scrub->os_full_speed = 0;
+ }
+
+ if (sf->sf_flags & (SF_RECREATED | SF_INCONSISTENT | SF_UPGRADE))
+ scrub->os_full_speed = 1;
+
+ scrub->os_in_prior = 0;
+ spin_lock(&scrub->os_lock);
+ scrub->os_waiting = 0;
+ scrub->os_paused = 0;
+ spin_unlock(&scrub->os_lock);
+ scrub->os_new_checked = 0;
+ if (drop_dryrun && sf->sf_pos_first_inconsistent != 0)
+ sf->sf_pos_latest_start = sf->sf_pos_first_inconsistent;
+ else if (sf->sf_pos_last_checkpoint != 0)
+ sf->sf_pos_latest_start = sf->sf_pos_last_checkpoint + 1;
+ else
+ sf->sf_pos_latest_start = LDISKFS_FIRST_INO(osd_sb(dev)) + 1;
+
+ scrub->os_pos_current = sf->sf_pos_latest_start;
+ sf->sf_status = SS_SCANNING;
+ sf->sf_time_latest_start = cfs_time_current_sec();
+ sf->sf_time_last_checkpoint = sf->sf_time_latest_start;
+ rc = osd_scrub_file_store(scrub);
+ if (rc == 0) {
+ spin_lock(&scrub->os_lock);
+ thread_set_flags(thread, SVC_RUNNING);
+ spin_unlock(&scrub->os_lock);
+ wake_up_all(&thread->t_ctl_waitq);
+ }
+ up_write(&scrub->os_rwsem);
+
+ RETURN(rc);
+}
+
static int osd_scrub_checkpoint(struct osd_scrub *scrub)
{
struct scrub_file *sf = &scrub->os_file;
dev->od_igif_inoi = 1;
dev->od_check_ff = 0;
sf->sf_status = SS_COMPLETED;
- memset(sf->sf_oi_bitmap, 0, SCRUB_OI_BITMAP_SIZE);
- sf->sf_flags &= ~(SF_RECREATED | SF_INCONSISTENT |
- SF_UPGRADE | SF_AUTO);
+ if (!(sf->sf_param & SP_DRYRUN)) {
+ memset(sf->sf_oi_bitmap, 0, SCRUB_OI_BITMAP_SIZE);
+ sf->sf_flags &= ~(SF_RECREATED | SF_INCONSISTENT |
+ SF_UPGRADE | SF_AUTO);
+ }
sf->sf_time_last_complete = sf->sf_time_last_checkpoint;
sf->sf_success_count++;
} else if (result == 0) {
* a small local FLDB according to the <seq>. If the given FID
* is in the local FLDB, then it is FID-on-OST; otherwise it's
* quite possible for FID-on-MDT. */
- return 0;
+ if (dev->od_is_ost)
+ return SCRUB_NEXT_OSTOBJ_OLD;
+ else
+ return 0;
}
static int osd_scrub_get_fid(struct osd_thread_info *info,
scrub->os_pos_current = param->gbase + ++(param->offset);
wait:
- if (it != NULL && it->ooi_waiting &&
+ if (it != NULL && it->ooi_waiting && ooc != NULL &&
ooc->ooc_pos_preload < scrub->os_pos_current) {
spin_lock(&scrub->os_lock);
it->ooi_waiting = 0;
- cfs_waitq_broadcast(&thread->t_ctl_waitq);
+ wake_up_all(&thread->t_ctl_waitq);
spin_unlock(&scrub->os_lock);
}
ooc->ooc_pos_preload, rc);
if (scrub->os_waiting && osd_scrub_has_window(scrub, ooc)) {
+ spin_lock(&scrub->os_lock);
scrub->os_waiting = 0;
- cfs_waitq_broadcast(&scrub->os_thread.t_ctl_waitq);
+ wake_up_all(&scrub->os_thread.t_ctl_waitq);
+ spin_unlock(&scrub->os_lock);
}
RETURN(rc < 0 ? rc : ooc->ooc_cached_items);
noenv:
spin_lock(&scrub->os_lock);
thread_set_flags(thread, SVC_STOPPED);
- cfs_waitq_broadcast(&thread->t_ctl_waitq);
+ wake_up_all(&thread->t_ctl_waitq);
spin_unlock(&scrub->os_lock);
return rc;
}
{
struct dentry *dentry;
+ CDEBUG(D_LFSCK, "init lookup one: parent = %.*s, name = %.*s\n",
+ parent->d_name.len, parent->d_name.name, namelen, name);
+
dentry = ll_lookup_one_len(name, parent, namelen);
if (!IS_ERR(dentry) && dentry->d_inode == NULL) {
dput(dentry);
scandir_t scandir, filldir_t filldir)
{
struct osd_ios_item *item;
+ ENTRY;
OBD_ALLOC_PTR(item);
if (item == NULL)
- return -ENOMEM;
+ RETURN(-ENOMEM);
CFS_INIT_LIST_HEAD(&item->oii_list);
item->oii_dentry = dget(dentry);
item->oii_scandir = scandir;
item->oii_filldir = filldir;
cfs_list_add_tail(&item->oii_list, &dev->od_ios_list);
- return 0;
+
+ RETURN(0);
}
/**
int rc;
ENTRY;
+ CDEBUG(D_LFSCK, "init scan one: ino = %ld\n", inode->i_ino);
+
rc = osd_get_lma(info, inode, &info->oti_obj_dentry, lma);
if (rc != 0 && rc != -ENODATA)
RETURN(rc);
RETURN(rc);
rc = osd_scrub_refresh_mapping(info, dev, &tfid, id,
- DTO_INDEX_INSERT, 0);
+ DTO_INDEX_INSERT, true, 0);
if (rc > 0)
rc = 0;
}
rc = osd_scrub_refresh_mapping(info, dev, &tfid, id,
- DTO_INDEX_UPDATE, 0);
+ DTO_INDEX_UPDATE, true, 0);
if (rc > 0)
rc = 0;
filp->f_mapping = inode->i_mapping;
filp->f_op = fops;
filp->private_data = NULL;
+ set_file_inode(filp, inode);
rc = fops->readdir(filp, &buf, filldir);
fops->release(inode, filp);
int rc;
ENTRY;
+ /* Lookup IGIF in OI by force for initial OI scrub. */
+ dev->od_igif_inoi = 1;
+
while (1) {
rc = scandir(info, dev, dentry, filldir);
if (item != NULL) {
dput(child);
else if (PTR_ERR(child) == -ENOENT)
osd_scrub_refresh_mapping(info, dev, &map->olm_fid,
- NULL, DTO_INDEX_DELETE, 0);
+ NULL, DTO_INDEX_DELETE,
+ true, 0);
map++;
}
if (!thread_is_init(thread) && !thread_is_stopped(thread)) {
thread_set_flags(thread, SVC_STOPPING);
spin_unlock(&scrub->os_lock);
- cfs_waitq_broadcast(&thread->t_ctl_waitq);
+ wake_up_all(&thread->t_ctl_waitq);
l_wait_event(thread->t_ctl_waitq,
thread_is_stopped(thread),
&lwi);
ctxt->pwd = dev->od_mnt->mnt_root;
ctxt->fs = get_ds();
- cfs_waitq_init(&scrub->os_thread.t_ctl_waitq);
+ init_waitqueue_head(&scrub->os_thread.t_ctl_waitq);
init_rwsem(&scrub->os_rwsem);
spin_lock_init(&scrub->os_lock);
CFS_INIT_LIST_HEAD(&scrub->os_inconsistent_items);
!(sf->sf_internal_flags & SIF_NO_HANDLE_OLD_FID ||
sf->sf_success_count > 0)) {
dev->od_igif_inoi = 0;
- dev->od_check_ff = 1;
+ dev->od_check_ff = dev->od_is_ost;
} else {
dev->od_igif_inoi = 1;
dev->od_check_ff = 0;
start |= SS_CLEAR_FAILOUT;
}
+ if (valid & DOIV_DRYRUN) {
+ if (flags & DOIF_DRYRUN)
+ start |= SS_SET_DRYRUN;
+ else
+ start |= SS_CLEAR_DRYRUN;
+ }
+
rc = do_osd_scrub_start(dev, start);
if (rc < 0 && rc != -EALREADY) {
dev->od_otable_it = NULL;
if (scrub->os_waiting && osd_scrub_has_window(scrub, ooc)) {
spin_lock(&scrub->os_lock);
scrub->os_waiting = 0;
- cfs_waitq_broadcast(&scrub->os_thread.t_ctl_waitq);
+ wake_up_all(&scrub->os_thread.t_ctl_waitq);
spin_unlock(&scrub->os_lock);
}
it->ooi_user_ready = 1;
if (!scrub->os_full_speed)
- cfs_waitq_broadcast(&scrub->os_thread.t_ctl_waitq);
+ wake_up_all(&scrub->os_thread.t_ctl_waitq);
/* Unplug OSD layer iteration by the first next() call. */
rc = osd_otable_it_next(env, (struct dt_it *)it);
spin_unlock(&scrub->os_lock);
if (wakeup != 0)
- cfs_waitq_broadcast(&thread->t_ctl_waitq);
+ wake_up_all(&thread->t_ctl_waitq);
RETURN(0);
}
static const char *scrub_param_names[] = {
"failout",
+ "dryrun",
NULL
};
if (thread_is_running(&scrub->os_thread)) {
cfs_duration_t duration = cfs_time_current() -
scrub->os_time_last_checkpoint;
- __u64 new_checked = scrub->os_new_checked * CFS_HZ;
+ __u64 new_checked = scrub->os_new_checked * HZ;
__u32 rtime = sf->sf_run_time +
cfs_duration_sec(duration + HALF_SEC);