struct dt_object *dt_locate_at(const struct lu_env *env,
struct dt_device *dev,
const struct lu_fid *fid,
- struct lu_device *top_dev);
+ struct lu_device *top_dev,
+ const struct lu_object_conf *conf);
+
static inline struct dt_object *
dt_locate(const struct lu_env *env, struct dt_device *dev,
const struct lu_fid *fid)
{
- return dt_locate_at(env, dev, fid, dev->dd_lu_dev.ld_site->ls_top_dev);
+ return dt_locate_at(env, dev, fid,
+ dev->dd_lu_dev.ld_site->ls_top_dev, NULL);
}
-
int local_oid_storage_init(const struct lu_env *env, struct dt_device *dev,
const struct lu_fid *first_fid,
struct local_oid_storage **los);
struct dt_object_format dti_dof;
struct lustre_mdt_attrs dti_lma;
struct lu_buf dti_lb;
+ struct lu_object_conf dti_conf;
loff_t dti_off;
};
GOTO(out_env, rc);
root = dt_locate_at(env, lsi->lsi_dt_dev, &rfid,
- &cli->cl_mgc_los->los_dev->dd_lu_dev);
+ &cli->cl_mgc_los->los_dev->dd_lu_dev, NULL);
if (unlikely(IS_ERR(root)))
GOTO(out_los, rc = PTR_ERR(root));
GOTO(out_los, rc);
root = dt_locate_at(env, mgs->mgs_bottom, &rfid,
- &mgs->mgs_dt_dev.dd_lu_dev);
+ &mgs->mgs_dt_dev.dd_lu_dev, NULL);
if (unlikely(IS_ERR(root)))
GOTO(out_los, rc = PTR_ERR(root));
}
fsdb = dt_locate_at(env, mgs->mgs_bottom, &fid,
- &mgs->mgs_dt_dev.dd_lu_dev);
+ &mgs->mgs_dt_dev.dd_lu_dev, NULL);
if (IS_ERR(fsdb))
RETURN(PTR_ERR(fsdb));
/* this differs from dt_locate by top_dev as parameter
* but not one from lu_site */
struct dt_object *dt_locate_at(const struct lu_env *env,
- struct dt_device *dev, const struct lu_fid *fid,
- struct lu_device *top_dev)
+ struct dt_device *dev,
+ const struct lu_fid *fid,
+ struct lu_device *top_dev,
+ const struct lu_object_conf *conf)
{
- struct lu_object *lo, *n;
- ENTRY;
+ struct lu_object *lo;
+ struct lu_object *n;
- lo = lu_object_find_at(env, top_dev, fid, NULL);
+ lo = lu_object_find_at(env, top_dev, fid, conf);
if (IS_ERR(lo))
- return (void *)lo;
+ return ERR_PTR(PTR_ERR(lo));
LASSERT(lo != NULL);
- cfs_list_for_each_entry(n, &lo->lo_header->loh_layers, lo_linkage) {
+ list_for_each_entry(n, &lo->lo_header->loh_layers, lo_linkage) {
if (n->lo_dev == &dev->dd_lu_dev)
return container_of0(n, struct dt_object, do_lu);
}
+
return ERR_PTR(-ENOENT);
}
EXPORT_SYMBOL(dt_locate_at);
GOTO(out, rc);
}
- o = ls_locate(env, ls, &lgi->lgi_fid);
+ o = ls_locate(env, ls, &lgi->lgi_fid, NULL);
if (IS_ERR(o))
GOTO(out_name, rc = PTR_ERR(o));
const char *name, struct lu_attr *attr,
struct dt_object_format *dof)
{
- struct dt_thread_info *dti = dt_info(env);
+ struct dt_thread_info *dti = dt_info(env);
+ struct lu_object_conf *conf = &dti->dti_conf;
struct dt_object *dto;
struct thandle *th;
int rc;
- dto = ls_locate(env, ls, fid);
+ /* We know that the target object does not exist, to be created,
+ * then give some hints - LOC_F_NEW to help low layer to handle
+ * that efficiently and properly. */
+ memset(conf, 0, sizeof(*conf));
+ conf->loc_flags = LOC_F_NEW;
+ dto = ls_locate(env, ls, fid, conf);
if (unlikely(IS_ERR(dto)))
RETURN(dto);
rc = dt_lookup_dir(env, parent, name, &dti->dti_fid);
if (rc == 0)
/* name is found, get the object */
- dto = ls_locate(env, dt2ls_dev(los->los_dev), &dti->dti_fid);
+ dto = ls_locate(env, dt2ls_dev(los->los_dev),
+ &dti->dti_fid, NULL);
else if (rc != -ENOENT)
dto = ERR_PTR(rc);
else {
rc = dt_lookup_dir(env, parent, name, &dti->dti_fid);
if (rc == 0) {
/* name is found, get the object */
- dto = ls_locate(env, dt2ls_dev(los->los_dev), &dti->dti_fid);
+ dto = ls_locate(env, dt2ls_dev(los->los_dev),
+ &dti->dti_fid, NULL);
} else if (rc != -ENOENT) {
dto = ERR_PTR(rc);
} else {
if (rc)
return rc;
- root = ls_locate(env, ls, &dti->dti_fid);
+ root = ls_locate(env, ls, &dti->dti_fid, NULL);
if (IS_ERR(root))
return PTR_ERR(root);
rc = dt_lookup_dir(env, root, dti->dti_buf, &dti->dti_fid);
lu_object_put_nocache(env, &root->do_lu);
if (rc == -ENOENT) {
+ struct lu_object_conf *conf = &dti->dti_conf;
+
/* old llog lastid accessed by FID only */
if (lastid_seq != FID_SEQ_LLOG)
return 0;
dti->dti_fid.f_seq = FID_SEQ_LLOG;
dti->dti_fid.f_oid = 1;
dti->dti_fid.f_ver = 0;
- o = ls_locate(env, ls, &dti->dti_fid);
+ memset(conf, 0, sizeof(*conf));
+ conf->loc_flags = LOC_F_NEW;
+ o = ls_locate(env, ls, &dti->dti_fid, conf);
if (IS_ERR(o))
return PTR_ERR(o);
} else {
CDEBUG(D_INFO, "Found old lastid file for sequence "LPX64"\n",
lastid_seq);
- o = ls_locate(env, ls, &dti->dti_fid);
+ o = ls_locate(env, ls, &dti->dti_fid, NULL);
if (IS_ERR(o))
return PTR_ERR(o);
}
dti->dti_fid.f_seq = fid_seq(first_fid);
dti->dti_fid.f_oid = LUSTRE_FID_LASTID_OID;
dti->dti_fid.f_ver = 0;
- o = ls_locate(env, ls, &dti->dti_fid);
+ o = ls_locate(env, ls, &dti->dti_fid, NULL);
if (IS_ERR(o))
GOTO(out_los, rc = PTR_ERR(o));
static inline struct dt_object *ls_locate(const struct lu_env *env,
struct ls_device *ls,
- const struct lu_fid *fid)
+ const struct lu_fid *fid,
+ const struct lu_object_conf *conf)
{
- return dt_locate_at(env, ls->ls_osd, fid, &ls->ls_top_dev.dd_lu_dev);
+ return dt_locate_at(env, ls->ls_osd, fid,
+ &ls->ls_top_dev.dd_lu_dev, conf);
}
struct ls_device *ls_device_get(struct dt_device *dev);
id->oii_ino, PTR_ERR(inode));
} else if (id->oii_gen != OSD_OII_NOGEN &&
inode->i_generation != id->oii_gen) {
- CDEBUG(D_INODE, "unmatched inode: ino = %u, gen0 = %u, "
- "gen1 = %u\n",
+ CDEBUG(D_INODE, "unmatched inode: ino = %u, oii_gen = %u, "
+ "i_generation = %u\n",
id->oii_ino, id->oii_gen, inode->i_generation);
iput(inode);
inode = ERR_PTR(-ESTALE);
/* due to parallel readdir and unlink,
* we can have dead inode here. */
CDEBUG(D_INODE, "stale inode: ino = %u\n", id->oii_ino);
- make_bad_inode(inode);
iput(inode);
inode = ERR_PTR(-ESTALE);
} else if (is_bad_inode(inode)) {
return inode;
}
+static struct inode *osd_iget_check(struct osd_thread_info *info,
+ struct osd_device *dev,
+ const struct lu_fid *fid,
+ struct osd_inode_id *id,
+ bool in_oi)
+{
+ struct inode *inode;
+ int rc = 0;
+ ENTRY;
+
+ inode = ldiskfs_iget(osd_sb(dev), id->oii_ino);
+ if (IS_ERR(inode)) {
+ rc = PTR_ERR(inode);
+ if (!in_oi || (rc != -ENOENT && rc != -ESTALE)) {
+ CDEBUG(D_INODE, "no inode: ino = %u, rc = %d\n",
+ id->oii_ino, rc);
+
+ GOTO(put, rc);
+ }
+
+ goto check_oi;
+ }
+
+ if (is_bad_inode(inode)) {
+ rc = -ENOENT;
+ if (!in_oi) {
+ CDEBUG(D_INODE, "bad inode: ino = %u\n", id->oii_ino);
+
+ GOTO(put, rc);
+ }
+
+ goto check_oi;
+ }
+
+ if (id->oii_gen != OSD_OII_NOGEN &&
+ inode->i_generation != id->oii_gen) {
+ rc = -ESTALE;
+ if (!in_oi) {
+ CDEBUG(D_INODE, "unmatched inode: ino = %u, "
+ "oii_gen = %u, i_generation = %u\n",
+ id->oii_ino, id->oii_gen, inode->i_generation);
+
+ GOTO(put, rc);
+ }
+
+ goto check_oi;
+ }
+
+ if (inode->i_nlink == 0) {
+ rc = -ENOENT;
+ if (!in_oi) {
+ CDEBUG(D_INODE, "stale inode: ino = %u\n", id->oii_ino);
+
+ GOTO(put, rc);
+ }
+
+ goto check_oi;
+ }
+
+check_oi:
+ if (rc != 0) {
+ LASSERTF(rc == -ESTALE || rc == -ENOENT, "rc = %d\n", rc);
+
+ rc = osd_oi_lookup(info, dev, fid, id, OI_CHECK_FLD);
+ /* XXX: There are three possible cases:
+ * 1. rc = 0.
+ * Backup/restore caused the OI invalid.
+ * 2. rc = 0.
+ * Someone unlinked the object but NOT removed
+ * the OI mapping, such as mount target device
+ * as ldiskfs, and modify something directly.
+ * 3. rc = -ENOENT.
+ * Someone just removed the object between the
+ * former oi_lookup and the iget. It is normal.
+ * 4. Other failure cases.
+ *
+ * Generally, when the device is mounted, it will
+ * auto check whether the system is restored from
+ * file-level backup or not. We trust such detect
+ * to distinguish the 1st case from the 2nd case. */
+ if (rc == 0) {
+ if (!IS_ERR(inode) && inode->i_generation != 0 &&
+ inode->i_generation == id->oii_gen)
+ rc = -ENOENT;
+ else
+ rc = -EREMCHG;
+ }
+ } else {
+ if (id->oii_gen == OSD_OII_NOGEN)
+ osd_id_gen(id, inode->i_ino, inode->i_generation);
+
+ /* Do not update file c/mtime in ldiskfs.
+ * NB: we don't have any lock to protect this because we don't
+ * have reference on osd_object now, but contention with
+ * another lookup + attr_set can't happen in the tiny window
+ * between if (...) and set S_NOCMTIME. */
+ if (!(inode->i_flags & S_NOCMTIME))
+ inode->i_flags |= S_NOCMTIME;
+ }
+
+ GOTO(put, rc);
+
+put:
+ if (rc != 0) {
+ if (!IS_ERR(inode))
+ iput(inode);
+
+ inode = ERR_PTR(rc);
+ }
+
+ return inode;
+}
+
/**
* \retval +v: new filter_fid, does not contain self-fid
* \retval 0: filter_fid_old, contains self-fid
in_oi = true;
iget:
- inode = osd_iget(info, dev, id);
+ inode = osd_iget_check(info, dev, fid, id, in_oi);
if (IS_ERR(inode)) {
result = PTR_ERR(inode);
if (result == -ENOENT || result == -ESTALE) {
- if (!in_oi) {
+ if (!in_oi)
fid_zero(&oic->oic_fid);
- GOTO(out, result = -ENOENT);
- }
- /* XXX: There are three possible cases:
- * 1. Backup/restore caused the OI invalid.
- * 2. Someone unlinked the object but NOT removed
- * the OI mapping, such as mount target device
- * as ldiskfs, and modify something directly.
- * 3. Someone just removed the object between the
- * former oi_lookup and the iget. It is normal.
- *
- * It is diffcult to distinguish the 2nd from the
- * 1st case. Relatively speaking, the 1st case is
- * common than the 2nd case, trigger OI scrub. */
- result = osd_oi_lookup(info, dev, fid, id, true);
- if (result == 0)
- /* It is the case 1 or 2. */
- goto trigger;
+ GOTO(out, result = -ENOENT);
} else if (result == -EREMCHG) {
trigger:
+ if (!in_oi)
+ fid_zero(&oic->oic_fid);
+
if (unlikely(triggered))
GOTO(out, result = saved);
result = -EINPROGRESS;
} else if (!dev->od_noscrub) {
result = osd_scrub_start(dev);
- LCONSOLE_ERROR("%.16s: trigger OI scrub by RPC "
- "for "DFID", rc = %d [1]\n",
- LDISKFS_SB(osd_sb(dev))->s_es->\
- s_volume_name,PFID(fid), result);
+ LCONSOLE_WARN("%.16s: trigger OI scrub by RPC "
+ "for "DFID", rc = %d [1]\n",
+ osd_name(dev), PFID(fid),result);
if (result == 0 || result == -EALREADY)
result = -EINPROGRESS;
else
if (result != 0) {
iput(inode);
obj->oo_inode = NULL;
- if (result == -EREMCHG)
+ if (result == -EREMCHG) {
+ if (!in_oi) {
+ result = osd_oi_lookup(info, dev, fid, id,
+ OI_CHECK_FLD);
+ if (result != 0) {
+ fid_zero(&oic->oic_fid);
+ GOTO(out, result);
+ }
+ }
+
goto trigger;
+ }
GOTO(out, result);
}
/* For new created object, it must be consistent,
* and it is unnecessary to scrub against it. */
ldiskfs_set_inode_state(inode, LDISKFS_STATE_LUSTRE_NOSCRUB);
+ ldiskfs_clear_inode_state(inode, LDISKFS_STATE_LUSTRE_NO_OI);
obj->oo_inode = inode;
result = 0;
} else {
RETURN(local);
}
+ ldiskfs_set_inode_state(local, LDISKFS_STATE_LUSTRE_NO_OI);
/* Set special LMA flag for local agent inode */
rc = osd_ea_fid_set(info, local, fid, 0, LMAI_AGENT);
if (rc != 0) {
}
if (!dev->od_noscrub && ++once == 1) {
- CDEBUG(D_LFSCK, "Trigger OI scrub by RPC for "DFID"\n",
- PFID(fid));
rc = osd_scrub_start(dev);
- LCONSOLE_ERROR("%.16s: trigger OI scrub by RPC for "DFID
- ", rc = %d [2]\n",
- LDISKFS_SB(osd_sb(dev))->s_es->s_volume_name,
- PFID(fid), rc);
+ LCONSOLE_WARN("%.16s: trigger OI scrub by RPC for "DFID
+ ", rc = %d [2]\n",
+ LDISKFS_SB(osd_sb(dev))->s_es->s_volume_name,
+ PFID(fid), rc);
if (rc == 0)
goto again;
}
GOTO(out, rc);
}
+ if (osd_remote_fid(env, dev, fid))
+ GOTO(out, rc = 0);
+
rc = osd_add_oi_cache(osd_oti_get(env), osd_obj2dev(obj), id,
fid);
if (rc != 0)
loff_t offset, __u64 ino, unsigned d_type);
static int osd_ios_lf_fill(void *buf, const char *name, int namelen,
loff_t offset, __u64 ino, unsigned d_type);
+static int osd_ios_dl_fill(void *buf, const char *name, int namelen,
+ loff_t offset, __u64 ino, unsigned d_type);
static int
osd_ios_general_scan(struct osd_thread_info *info, struct osd_device *dev,
{ NULL, { 0, 0, 0 }, 0, NULL, NULL }
};
+/* Add the new introduced files under .lustre/ in the list in the future. */
+static const struct osd_lf_map osd_dl_maps[] = {
+ /* .lustre/fid */
+ { "fid", { FID_SEQ_DOT_LUSTRE, FID_OID_DOT_LUSTRE_OBF, 0 }, 0,
+ NULL, NULL },
+
+ { NULL, { 0, 0, 0 }, 0, NULL, NULL }
+};
+
struct osd_ios_item {
cfs_list_t oii_list;
struct dentry *oii_dentry;
RETURN(rc);
}
+static int osd_ios_dl_fill(void *buf, const char *name, int namelen,
+ loff_t offset, __u64 ino, unsigned d_type)
+{
+ struct osd_ios_filldir_buf *fill_buf = buf;
+ struct osd_device *dev = fill_buf->oifb_dev;
+ const struct osd_lf_map *map;
+ struct dentry *child;
+ int rc = 0;
+ ENTRY;
+
+ /* skip any '.' started names */
+ if (name[0] == '.')
+ RETURN(0);
+
+ for (map = osd_dl_maps; map->olm_name != NULL; map++) {
+ if (strlen(map->olm_name) != namelen)
+ continue;
+
+ if (strncmp(map->olm_name, name, namelen) == 0)
+ break;
+ }
+
+ if (map->olm_name == NULL)
+ RETURN(0);
+
+ child = osd_ios_lookup_one_len(name, fill_buf->oifb_dentry, namelen);
+ if (IS_ERR(child))
+ RETURN(PTR_ERR(child));
+
+ rc = osd_ios_scan_one(fill_buf->oifb_info, dev, child->d_inode,
+ &map->olm_fid, map->olm_flags);
+ dput(child);
+
+ RETURN(rc);
+}
+
static int osd_ios_root_fill(void *buf, const char *name, int namelen,
loff_t offset, __u64 ino, unsigned d_type)
{
* to the solution 2). */
rc = osd_ios_scan_one(info, dev, child->d_inode,
&LU_DOT_LUSTRE_FID, 0);
+ if (rc == 0)
+ rc = osd_ios_new_item(dev, child, osd_ios_general_scan,
+ osd_ios_dl_fill);
dput(child);
}
GOTO(out, rc);
parent = dt_locate_at(env, dev, &qti->qti_fid,
- dev->dd_lu_dev.ld_site->ls_top_dev);
+ dev->dd_lu_dev.ld_site->ls_top_dev, NULL);
if (IS_ERR(parent))
GOTO(out, rc = PTR_ERR(parent));
} else {
local -a position1
for n in $(seq $MDSCOUNT); do
- positions1[$n]=$(scrub_status $n |
+ position1[$n]=$(scrub_status $n |
awk '/^latest_start_position/ {print $2}')
if [ ${position0[$n]} -ne ${position1[$n]} ]; then
error "(14) Expected position ${position0[$n]}, but" \
run_test 6 "OI scrub resumes from last checkpoint"
test_7() {
- # skip test_7 for LU-4149
- [ $MDSCOUNT -ge 2 ] && skip "skip now for >= 2 MDTs" && return
-
scrub_prep 500
scrub_backup_restore 1