+/**
+ * Update the specified OI mapping.
+ *
+ * \retval 1, changed nothing
+ * \retval 0, changed successfully
+ * \retval -ve, on error
+ */
+static int osd_obj_update_entry(struct osd_thread_info *info,
+ struct osd_device *osd,
+ struct dentry *dir, const char *name,
+ const struct lu_fid *fid,
+ const struct osd_inode_id *id,
+ struct thandle *th)
+{
+ struct inode *parent = dir->d_inode;
+ struct osd_thandle *oh;
+ struct dentry *child;
+ struct ldiskfs_dir_entry_2 *de;
+ struct buffer_head *bh;
+ struct inode *inode;
+ struct dentry *dentry = &info->oti_obj_dentry;
+ struct osd_inode_id *oi_id = &info->oti_id3;
+ struct lustre_mdt_attrs *lma = &info->oti_mdt_attrs;
+ struct lu_fid *oi_fid = &lma->lma_self_fid;
+ int rc;
+ ENTRY;
+
+ oh = container_of(th, struct osd_thandle, ot_super);
+ LASSERT(oh->ot_handle != NULL);
+ LASSERT(oh->ot_handle->h_transaction != NULL);
+
+ child = &info->oti_child_dentry;
+ child->d_parent = dir;
+ child->d_name.hash = 0;
+ child->d_name.name = name;
+ child->d_name.len = strlen(name);
+
+ ll_vfs_dq_init(parent);
+ mutex_lock(&parent->i_mutex);
+ bh = osd_ldiskfs_find_entry(parent, child, &de, NULL);
+ if (bh == NULL)
+ GOTO(out, rc = -ENOENT);
+
+ if (le32_to_cpu(de->inode) == id->oii_ino)
+ GOTO(out, rc = 1);
+
+ osd_id_gen(oi_id, le32_to_cpu(de->inode), OSD_OII_NOGEN);
+ inode = osd_iget(info, osd, oi_id);
+ if (IS_ERR(inode)) {
+ rc = PTR_ERR(inode);
+ if (rc == -ENOENT || rc == -ESTALE)
+ goto update;
+ GOTO(out, rc);
+ }
+
+ rc = osd_get_lma(info, inode, dentry, lma);
+ if (rc == -ENODATA) {
+ rc = osd_get_idif(info, inode, dentry, oi_fid);
+ if (rc > 0) {
+ oi_fid = NULL;
+ rc = 0;
+ }
+ }
+ iput(inode);
+
+ /* If the OST-object has neither FID-in-LMA nor FID-in-ff, it is
+ * either a crashed object or a uninitialized one. Replace it. */
+ if (rc == -ENODATA || oi_fid == NULL)
+ goto update;
+
+ if (rc != 0)
+ GOTO(out, rc);
+
+ if (lu_fid_eq(fid, oi_fid)) {
+ CERROR("%s: the FID "DFID" is used by two objects: "
+ "%u/%u %u/%u\n", osd_name(osd), PFID(fid),
+ oi_id->oii_ino, oi_id->oii_gen,
+ id->oii_ino, id->oii_gen);
+ GOTO(out, rc = -EEXIST);
+ }
+
+update:
+ /* There may be temporary inconsistency: On one hand, the new
+ * object may be referenced by multiple entries, which is out
+ * of our control unless we traverse the whole /O completely,
+ * which is non-flat order and inefficient, should be avoided;
+ * On the other hand, the old object may become orphan if it
+ * is still valid. Since it was referenced by an invalid entry,
+ * making it as invisible temporary may be not worse. OI scrub
+ * will process it later. */
+ rc = ldiskfs_journal_get_write_access(oh->ot_handle, bh);
+ if (rc != 0)
+ GOTO(out, rc);
+
+ de->inode = cpu_to_le32(id->oii_ino);
+ rc = ldiskfs_journal_dirty_metadata(oh->ot_handle, bh);
+
+ GOTO(out, rc);
+
+out:
+ brelse(bh);
+ mutex_unlock(&parent->i_mutex);
+ return rc;
+}
+