-struct inode *osd_iget(struct osd_thread_info *info,
- struct osd_device *dev,
- const struct osd_inode_id *id)
-{
- struct inode *inode = NULL;
-
- inode = ldiskfs_iget(osd_sb(dev), id->oii_ino);
- if (IS_ERR(inode)) {
- CERROR("Cannot get inode, rc = %li\n", PTR_ERR(inode));
- } else if (id->oii_gen != OSD_OII_NOGEN &&
- inode->i_generation != id->oii_gen) {
- iput(inode);
- inode = ERR_PTR(-ESTALE);
- } else if (inode->i_nlink == 0) {
- /* due to parallel readdir and unlink,
- * we can have dead inode here. */
- CWARN("stale inode\n");
- make_bad_inode(inode);
- iput(inode);
- inode = ERR_PTR(-ESTALE);
- } else if (is_bad_inode(inode)) {
- CERROR("bad inode %lx\n",inode->i_ino);
- iput(inode);
- inode = ERR_PTR(-ENOENT);
- } else {
- /* 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;
-}
-
-static int osd_fid_lookup(const struct lu_env *env,
- struct osd_object *obj, const struct lu_fid *fid)
-{
- struct osd_thread_info *info;
- struct lu_device *ldev = obj->oo_dt.do_lu.lo_dev;
- struct osd_device *dev;
- struct osd_inode_id *id;
- struct inode *inode;
- int result;
-
- LINVRNT(osd_invariant(obj));
- LASSERT(obj->oo_inode == NULL);
- LASSERTF(fid_is_sane(fid) || fid_is_idif(fid), DFID, PFID(fid));
- /*
- * This assertion checks that osd layer sees only local
- * fids. Unfortunately it is somewhat expensive (does a
- * cache-lookup). Disabling it for production/acceptance-testing.
- */
- LASSERT(1 || fid_is_local(env, ldev->ld_site, fid));
-
- ENTRY;
-
- info = osd_oti_get(env);
- LASSERT(info);
- dev = osd_dev(ldev);
- id = &info->oti_id;
+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;
+}
+
+static 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(info, inode, &info->oti_obj_dentry, lma);
+ if (rc == 0) {
+ *fid = lma->lma_self_fid;
+ } else if (rc == -ENODATA) {
+ if (unlikely(inode == osd_sb(dev)->s_root->d_inode))
+ lu_local_obj_fid(fid, OSD_FS_ROOT_OID);
+ else
+ 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(info, inode, &info->oti_obj_dentry, lma);
+ if (rc == -ENODATA)
+ return inode;
+
+ if (rc != 0) {
+ 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;
+
+ if (OBD_FAIL_CHECK(OBD_FAIL_OST_ENOENT))
+ RETURN(-ENOENT);
+
+ /* Search order: 1. per-thread cache. */
+ if (lu_fid_eq(fid, &oic->oic_fid)) {
+ id = &oic->oic_lid;
+ goto iget;
+ }
+
+ id = &info->oti_id;
+ 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;
+
+ /*
+ * 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, true);
+ 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) {
+ fid_zero(&oic->oic_fid);
+ result = 0;
+ } else if (result == -EREMCHG) {
+
+trigger:
+ if (thread_is_running(&scrub->os_thread)) {
+ 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);
+ if (result == 0 || result == -EALREADY)
+ result = -EINPROGRESS;
+ else
+ result = -EREMCHG;
+ }
+ }