+ /* Set LMA for remote parent inode */
+ lu_local_obj_fid(fid, REMOTE_PARENT_DIR_OID);
+ rc = osd_ea_fid_set(info, d->d_inode, fid, LMAC_NOT_IN_OI, 0);
+
+ GOTO(cleanup, rc);
+
+cleanup:
+ pop_ctxt(&save, &new);
+ if (rc) {
+ if (omm->omm_remote_parent != NULL)
+ dput(omm->omm_remote_parent);
+ OBD_FREE_PTR(omm);
+ dev->od_mdt_map = NULL;
+ }
+ return rc;
+}
+
+static void osd_mdt_fini(struct osd_device *osd)
+{
+ struct osd_mdobj_map *omm = osd->od_mdt_map;
+
+ if (omm == NULL)
+ return;
+
+ if (omm->omm_remote_parent)
+ dput(omm->omm_remote_parent);
+
+ OBD_FREE_PTR(omm);
+ osd->od_ost_map = NULL;
+}
+
+int osd_add_to_remote_parent(const struct lu_env *env, struct osd_device *osd,
+ struct osd_object *obj, struct osd_thandle *oh)
+{
+ struct osd_mdobj_map *omm = osd->od_mdt_map;
+ struct osd_thread_info *oti = osd_oti_get(env);
+ struct lustre_mdt_attrs *lma = &oti->oti_mdt_attrs;
+ char *name = oti->oti_name;
+ struct dentry *dentry;
+ struct dentry *parent;
+ int rc;
+
+ /* Set REMOTE_PARENT in lma, so other process like unlink or lfsck
+ * can identify this object quickly */
+ rc = osd_get_lma(oti, obj->oo_inode, &oti->oti_obj_dentry, lma);
+ if (rc != 0)
+ RETURN(rc);
+
+ lma->lma_incompat |= LMAI_REMOTE_PARENT;
+ lustre_lma_swab(lma);
+ rc = __osd_xattr_set(oti, obj->oo_inode, XATTR_NAME_LMA, lma,
+ sizeof(*lma), XATTR_REPLACE);
+ if (rc != 0)
+ RETURN(rc);
+
+ parent = omm->omm_remote_parent;
+ sprintf(name, DFID_NOBRACE, PFID(lu_object_fid(&obj->oo_dt.do_lu)));
+ dentry = osd_child_dentry_by_inode(env, parent->d_inode,
+ name, strlen(name));
+ mutex_lock(&parent->d_inode->i_mutex);
+ rc = osd_ldiskfs_add_entry(oh->ot_handle, dentry, obj->oo_inode,
+ NULL);
+ CDEBUG(D_INODE, "%s: add %s:%lu to remote parent %lu.\n", osd_name(osd),
+ name, obj->oo_inode->i_ino, parent->d_inode->i_ino);
+ ldiskfs_inc_count(oh->ot_handle, parent->d_inode);
+ mark_inode_dirty(parent->d_inode);
+ mutex_unlock(&parent->d_inode->i_mutex);
+ RETURN(rc);
+}
+
+int osd_delete_from_remote_parent(const struct lu_env *env,
+ struct osd_device *osd,
+ struct osd_object *obj,
+ struct osd_thandle *oh)
+{
+ struct osd_mdobj_map *omm = osd->od_mdt_map;
+ struct osd_thread_info *oti = osd_oti_get(env);
+ struct lustre_mdt_attrs *lma = &oti->oti_mdt_attrs;
+ char *name = oti->oti_name;
+ struct dentry *dentry;
+ struct dentry *parent;
+ struct ldiskfs_dir_entry_2 *de;
+ struct buffer_head *bh;
+ int rc;
+
+ /* Check lma to see whether it is remote object */
+ rc = osd_get_lma(oti, obj->oo_inode, &oti->oti_obj_dentry, lma);
+ if (rc != 0)
+ RETURN(rc);
+
+ if (likely(!(lma->lma_incompat & LMAI_REMOTE_PARENT)))
+ RETURN(0);
+
+ parent = omm->omm_remote_parent;
+ sprintf(name, DFID_NOBRACE, PFID(lu_object_fid(&obj->oo_dt.do_lu)));
+ dentry = osd_child_dentry_by_inode(env, parent->d_inode,
+ name, strlen(name));
+ mutex_lock(&parent->d_inode->i_mutex);
+ bh = osd_ldiskfs_find_entry(parent->d_inode, &dentry->d_name, &de,
+ NULL, NULL);
+ if (bh == NULL) {
+ mutex_unlock(&parent->d_inode->i_mutex);
+ RETURN(-ENOENT);
+ }
+ CDEBUG(D_INODE, "%s: el %s:%lu to remote parent %lu.\n", osd_name(osd),
+ name, obj->oo_inode->i_ino, parent->d_inode->i_ino);
+ rc = ldiskfs_delete_entry(oh->ot_handle, parent->d_inode, de, bh);
+ ldiskfs_dec_count(oh->ot_handle, parent->d_inode);
+ mark_inode_dirty(parent->d_inode);
+ mutex_unlock(&parent->d_inode->i_mutex);
+ brelse(bh);
+
+ /* Get rid of REMOTE_PARENT flag from incompat */
+ lma->lma_incompat &= ~LMAI_REMOTE_PARENT;
+ lustre_lma_swab(lma);
+ rc = __osd_xattr_set(oti, obj->oo_inode, XATTR_NAME_LMA, lma,
+ sizeof(*lma), XATTR_REPLACE);
+ RETURN(rc);
+}
+
+int osd_lookup_in_remote_parent(struct osd_thread_info *oti,
+ struct osd_device *osd,
+ const struct lu_fid *fid,
+ struct osd_inode_id *id)
+{
+ struct osd_mdobj_map *omm = osd->od_mdt_map;
+ char *name = oti->oti_name;
+ struct dentry *parent;
+ struct dentry *dentry;
+ struct ldiskfs_dir_entry_2 *de;
+ struct buffer_head *bh;
+ int rc;
+ ENTRY;
+
+ parent = omm->omm_remote_parent;
+ sprintf(name, DFID_NOBRACE, PFID(fid));
+ dentry = osd_child_dentry_by_inode(oti->oti_env, parent->d_inode,
+ name, strlen(name));
+ mutex_lock(&parent->d_inode->i_mutex);
+ bh = osd_ldiskfs_find_entry(parent->d_inode, &dentry->d_name, &de,
+ NULL, NULL);
+ if (bh == NULL) {
+ rc = -ENOENT;
+ } else {
+ rc = 0;
+ osd_id_gen(id, le32_to_cpu(de->inode), OSD_OII_NOGEN);
+ brelse(bh);
+ }
+ mutex_unlock(&parent->d_inode->i_mutex);
+ if (rc == 0)
+ osd_add_oi_cache(oti, osd, id, fid);
+ RETURN(rc);