+ lu_buf_free(&xbuf);
+ RETURN(rc);
+}
+
+typedef int (*mdd_linkea_cb)(const struct lu_env *env,
+ struct mdd_object *sobj,
+ struct mdd_object *tobj,
+ const struct lu_name *sname,
+ const struct lu_fid *sfid,
+ const struct lu_name *lname,
+ const struct lu_fid *fid,
+ void *opaque,
+ struct thandle *handle);
+
+static int mdd_declare_update_link(const struct lu_env *env,
+ struct mdd_object *sobj,
+ struct mdd_object *tobj,
+ const struct lu_name *tname,
+ const struct lu_fid *tpfid,
+ const struct lu_name *lname,
+ const struct lu_fid *fid,
+ void *unused,
+ struct thandle *handle)
+{
+ struct mdd_device *mdd = mdo2mdd(&sobj->mod_obj);
+ struct mdd_object *pobj;
+ int rc;
+
+ /* ignore tobj */
+ if (lu_fid_eq(tpfid, fid) && tname->ln_namelen == lname->ln_namelen &&
+ !strcmp(tname->ln_name, lname->ln_name))
+ return 0;
+
+ pobj = mdd_object_find(env, mdd, fid);
+ if (IS_ERR(pobj))
+ return PTR_ERR(pobj);
+
+
+ rc = mdo_declare_index_delete(env, pobj, lname->ln_name, handle);
+ if (!rc)
+ rc = mdo_declare_index_insert(env, pobj, mdo2fid(tobj),
+ mdd_object_type(sobj),
+ lname->ln_name, handle);
+ mdd_object_put(env, pobj);
+ if (rc)
+ return rc;
+
+ rc = mdo_declare_ref_add(env, tobj, handle);
+ if (rc)
+ return rc;
+
+ rc = mdo_declare_ref_del(env, sobj, handle);
+ return rc;
+}
+
+static int mdd_update_link(const struct lu_env *env,
+ struct mdd_object *sobj,
+ struct mdd_object *tobj,
+ const struct lu_name *tname,
+ const struct lu_fid *tpfid,
+ const struct lu_name *lname,
+ const struct lu_fid *fid,
+ void *unused,
+ struct thandle *handle)
+{
+ struct mdd_device *mdd = mdo2mdd(&sobj->mod_obj);
+ struct mdd_object *pobj;
+ int rc;
+
+ ENTRY;
+
+ LASSERT(lu_name_is_valid(lname));
+
+ /* ignore tobj */
+ if (lu_fid_eq(tpfid, fid) && tname->ln_namelen == lname->ln_namelen &&
+ !strncmp(tname->ln_name, lname->ln_name, lname->ln_namelen))
+ RETURN(0);
+
+ CDEBUG(D_INFO, "update "DFID"/"DNAME":"DFID"\n",
+ PFID(fid), PNAME(lname), PFID(mdo2fid(tobj)));
+
+ pobj = mdd_object_find(env, mdd, fid);
+ if (IS_ERR(pobj)) {
+ CWARN("%s: cannot find obj "DFID": %ld\n",
+ mdd2obd_dev(mdd)->obd_name, PFID(fid), PTR_ERR(pobj));
+ RETURN(PTR_ERR(pobj));
+ }
+
+ if (!mdd_object_exists(pobj)) {
+ CDEBUG(D_INFO, DFID" doesn't exist\n", PFID(fid));
+ mdd_object_put(env, pobj);
+ RETURN(-ENOENT);
+ }
+
+ mdd_write_lock(env, pobj, DT_TGT_PARENT);
+ rc = __mdd_index_delete_only(env, pobj, lname->ln_name, handle);
+ if (!rc)
+ rc = __mdd_index_insert_only(env, pobj, mdo2fid(tobj),
+ mdd_object_type(sobj),
+ lname->ln_name, handle);
+ mdd_write_unlock(env, pobj);
+ mdd_object_put(env, pobj);
+ if (rc)
+ RETURN(rc);
+
+ mdd_write_lock(env, tobj, DT_TGT_CHILD);
+ rc = mdo_ref_add(env, tobj, handle);
+ mdd_write_unlock(env, tobj);
+ if (rc)
+ RETURN(rc);
+
+ mdd_write_lock(env, sobj, DT_SRC_CHILD);
+ rc = mdo_ref_del(env, sobj, handle);
+ mdd_write_unlock(env, sobj);
+
+ RETURN(rc);
+}
+
+static inline int mdd_fld_lookup(const struct lu_env *env,
+ struct mdd_device *mdd,
+ const struct lu_fid *fid,
+ __u32 *mdt_index)
+{
+ struct lu_seq_range *range = &mdd_env_info(env)->mti_range;
+ struct seq_server_site *ss;
+ int rc;
+
+ ss = mdd->mdd_md_dev.md_lu_dev.ld_site->ld_seq_site;
+
+ range->lsr_flags = LU_SEQ_RANGE_MDT;
+ rc = fld_server_lookup(env, ss->ss_server_fld, fid->f_seq, range);
+ if (rc)
+ return rc;
+
+ *mdt_index = range->lsr_index;
+
+ return 0;
+}
+
+static int mdd_is_link_on_source_mdt(const struct lu_env *env,
+ struct mdd_object *sobj,
+ struct mdd_object *tobj,
+ const struct lu_name *tname,
+ const struct lu_fid *tpfid,
+ const struct lu_name *lname,
+ const struct lu_fid *fid,
+ void *opaque,
+ struct thandle *handle)
+{
+ struct mdd_device *mdd = mdo2mdd(&sobj->mod_obj);
+ __u32 source_mdt_index = *(__u32 *)opaque;
+ __u32 link_mdt_index;
+ int rc;
+
+ ENTRY;
+
+ /* ignore tobj */
+ if (lu_fid_eq(tpfid, fid) && tname->ln_namelen == lname->ln_namelen &&
+ !strcmp(tname->ln_name, lname->ln_name))
+ return 0;
+
+ rc = mdd_fld_lookup(env, mdd, fid, &link_mdt_index);
+ if (rc)
+ RETURN(rc);
+
+ RETURN(link_mdt_index == source_mdt_index);
+}
+
+static int mdd_iterate_linkea(const struct lu_env *env,
+ struct mdd_object *sobj,
+ struct mdd_object *tobj,
+ const struct lu_name *tname,
+ const struct lu_fid *tpfid,
+ struct linkea_data *ldata,
+ void *opaque,
+ struct thandle *handle,
+ mdd_linkea_cb cb)
+{
+ struct mdd_thread_info *info = mdd_env_info(env);
+ char *filename = info->mti_name;
+ struct lu_name lname;
+ struct lu_fid fid;
+ int rc = 0;
+
+ if (!ldata->ld_buf)
+ return 0;
+
+ for (linkea_first_entry(ldata); ldata->ld_lee && !rc;
+ linkea_next_entry(ldata)) {
+ linkea_entry_unpack(ldata->ld_lee, &ldata->ld_reclen, &lname,
+ &fid);
+
+ /* Note: lname might miss \0 at the end */
+ snprintf(filename, sizeof(info->mti_name), "%.*s",
+ lname.ln_namelen, lname.ln_name);
+ lname.ln_name = filename;
+
+ CDEBUG(D_INFO, DFID"/"DNAME"\n", PFID(&fid), PNAME(&lname));
+
+ rc = cb(env, sobj, tobj, tname, tpfid, &lname, &fid, opaque,
+ handle);
+ }
+