+ return rc;
+}
+
+/*
+ * retrieve object from backend ext fs.
+ **/
+struct inode *osd_iget(struct osd_thread_info *info, struct osd_device *dev,
+ struct osd_inode_id *id)
+{
+ struct inode *inode = NULL;
+
+ inode = ldiskfs_iget(osd_sb(dev), id->oii_ino);
+ if (IS_ERR(inode)) {
+ CDEBUG(D_INODE, "no inode: ino = %u, rc = %ld\n",
+ 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",
+ id->oii_ino, id->oii_gen, inode->i_generation);
+ iput(inode);
+ inode = ERR_PTR(-ESTALE);
+ } else if (inode->i_nlink == 0) {
+ /* 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)) {
+ CWARN("%.16s: bad inode: ino = %u\n",
+ LDISKFS_SB(osd_sb(dev))->s_es->s_volume_name, id->oii_ino);
+ iput(inode);
+ inode = ERR_PTR(-ENOENT);
+ } 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;
+ }
+ return inode;
+}
+
+struct inode *osd_iget_fid(struct osd_thread_info *info, struct osd_device *dev,
+ struct osd_inode_id *id, struct lu_fid *fid)
+{
+ struct lustre_mdt_attrs *lma = &info->oti_mdt_attrs;
+ struct inode *inode;
+ int rc;
+
+ inode = osd_iget(info, dev, id);
+ if (IS_ERR(inode))
+ return inode;
+
+ rc = osd_get_lma(inode, &info->oti_obj_dentry, lma);
+ if (rc == 0) {
+ *fid = lma->lma_self_fid;
+ } else if (rc == -ENODATA) {
+ LU_IGIF_BUILD(fid, inode->i_ino, inode->i_generation);
+ } else {
+ iput(inode);
+ inode = ERR_PTR(rc);
+ }
+ return inode;
+}
+
+static struct inode *
+osd_iget_verify(struct osd_thread_info *info, struct osd_device *dev,
+ struct osd_inode_id *id, const struct lu_fid *fid)
+{
+ struct lustre_mdt_attrs *lma = &info->oti_mdt_attrs;
+ struct inode *inode;
+ int rc;
+
+ inode = osd_iget(info, dev, id);
+ if (IS_ERR(inode))
+ return inode;
+
+ rc = osd_get_lma(inode, &info->oti_obj_dentry, lma);
+ if (rc != 0) {
+ if (rc == -ENODATA) {
+ CDEBUG(D_LFSCK, "inconsistent obj: NULL, %lu, "DFID"\n",
+ inode->i_ino, PFID(fid));
+ rc = -EREMCHG;
+ }
+ iput(inode);
+ return ERR_PTR(rc);
+ }
+
+ if (!lu_fid_eq(fid, &lma->lma_self_fid)) {
+ CDEBUG(D_LFSCK, "inconsistent obj: "DFID", %lu, "DFID"\n",
+ PFID(&lma->lma_self_fid), inode->i_ino, PFID(fid));
+ iput(inode);
+ return ERR_PTR(EREMCHG);
+ }
+ return inode;
+}
+
+static int osd_fid_lookup(const struct lu_env *env, struct osd_object *obj,
+ const struct lu_fid *fid,
+ const struct lu_object_conf *conf)
+{
+ struct osd_thread_info *info;
+ struct lu_device *ldev = obj->oo_dt.do_lu.lo_dev;
+ struct osd_device *dev;
+ struct osd_idmap_cache *oic;
+ struct osd_inode_id *id;
+ struct inode *inode;
+ struct osd_scrub *scrub;
+ struct scrub_file *sf;
+ int result;
+ int verify = 0;
+ ENTRY;
+
+ LINVRNT(osd_invariant(obj));
+ LASSERT(obj->oo_inode == NULL);
+ LASSERTF(fid_is_sane(fid) || fid_is_idif(fid), DFID, PFID(fid));
+
+ dev = osd_dev(ldev);
+ scrub = &dev->od_scrub;
+ sf = &scrub->os_file;
+ info = osd_oti_get(env);
+ LASSERT(info);
+ oic = &info->oti_cache;
+ id = &oic->oic_lid;
+
+ if (OBD_FAIL_CHECK(OBD_FAIL_OST_ENOENT))
+ RETURN(-ENOENT);
+
+ if (fid_is_norm(fid)) {
+ /* Search order: 1. per-thread cache. */
+ if (lu_fid_eq(fid, &oic->oic_fid)) {
+ goto iget;
+ } else if (!cfs_list_empty(&scrub->os_inconsistent_items)) {
+ /* Search order: 2. OI scrub pending list. */
+ result = osd_oii_lookup(dev, fid, id);
+ if (result == 0)
+ goto iget;
+ }
+
+ if (sf->sf_flags & SF_INCONSISTENT)
+ verify = 1;
+ }
+
+ fid_zero(&oic->oic_fid);
+
+ /*
+ * Objects are created as locking anchors or place holders for objects
+ * yet to be created. No need to osd_oi_lookup() at here because FID
+ * shouldn't never be re-used, if it's really a duplicate FID from
+ * unexpected reason, we should be able to detect it later by calling
+ * do_create->osd_oi_insert()
+ */
+ if (conf != NULL && (conf->loc_flags & LOC_F_NEW) != 0)
+ GOTO(out, result = 0);
+
+ /* Search order: 3. OI files. */
+ result = osd_oi_lookup(info, dev, fid, id);
+ if (result == -ENOENT) {
+ if (!fid_is_norm(fid) ||
+ !ldiskfs_test_bit(osd_oi_fid2idx(dev,fid),
+ sf->sf_oi_bitmap))
+ GOTO(out, result = 0);
+
+ goto trigger;
+ }
+
+ if (result != 0)
+ GOTO(out, result);
+
+iget:
+ if (verify == 0)
+ inode = osd_iget(info, dev, id);
+ else
+ inode = osd_iget_verify(info, dev, id, fid);
+ if (IS_ERR(inode)) {
+ result = PTR_ERR(inode);
+ if (result == -ENOENT || result == -ESTALE) {
+ result = 0;
+ } else if (result == -EREMCHG) {
+
+trigger:
+ if (thread_is_running(&scrub->os_thread)) {
+ result = -EINPROGRESS;
+ } else if (!scrub->os_no_scrub) {
+ 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);
+ if (result == 0 || result == -EALREADY)
+ result = -EINPROGRESS;
+ else
+ result = -EREMCHG;
+ }
+ }
+
+ GOTO(out, result);
+ }