+static const char remote_parent_dir[] = "REMOTE_PARENT_DIR";
+static int osd_mdt_init(const struct lu_env *env, struct osd_device *dev)
+{
+ struct lvfs_run_ctxt new;
+ struct lvfs_run_ctxt save;
+ struct dentry *parent;
+ struct osd_mdobj_map *omm;
+ struct dentry *d;
+ struct osd_thread_info *info = osd_oti_get(env);
+ struct lu_fid *fid = &info->oti_fid;
+ int rc = 0;
+ ENTRY;
+
+ OBD_ALLOC_PTR(dev->od_mdt_map);
+ if (dev->od_mdt_map == NULL)
+ RETURN(-ENOMEM);
+
+ omm = dev->od_mdt_map;
+
+ LASSERT(dev->od_fsops);
+
+ parent = osd_sb(dev)->s_root;
+ osd_push_ctxt(dev, &new, &save);
+
+ d = simple_mkdir(parent, dev->od_mnt, remote_parent_dir,
+ 0755, 1);
+ if (IS_ERR(d))
+ GOTO(cleanup, rc = PTR_ERR(d));
+
+ omm->omm_remote_parent = d;
+
+ /* 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, 0);
+ if (rc != 0)
+ GOTO(cleanup, rc);
+cleanup:
+ pop_ctxt(&save, &new, NULL);
+ 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);
+ LASSERTF(parent->d_inode->i_nlink > 1, "%s: %lu nlink %d",
+ osd_name(osd), parent->d_inode->i_ino,
+ parent->d_inode->i_nlink);
+ parent->d_inode->i_nlink++;
+ 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, &de, 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);
+ LASSERTF(parent->d_inode->i_nlink > 1, "%s: %lu nlink %d",
+ osd_name(osd), parent->d_inode->i_ino,
+ parent->d_inode->i_nlink);
+ parent->d_inode->i_nlink--;
+ 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);
+}
+