+static int mdd_path_current(const struct lu_env *env,
+ struct path_lookup_info *pli)
+{
+ struct mdd_device *mdd = mdo2mdd(&pli->pli_mdd_obj->mod_obj);
+ struct mdd_object *mdd_obj;
+ struct lu_buf *buf = NULL;
+ struct link_ea_header *leh;
+ struct link_ea_entry *lee;
+ struct lu_name *tmpname = &mdd_env_info(env)->mti_name;
+ struct lu_fid *tmpfid = &mdd_env_info(env)->mti_fid;
+ char *ptr;
+ int reclen;
+ int rc;
+ ENTRY;
+
+ ptr = pli->pli_path + pli->pli_pathlen - 1;
+ *ptr = 0;
+ --ptr;
+ pli->pli_fidcount = 0;
+ pli->pli_fids[0] = *(struct lu_fid *)mdd_object_fid(pli->pli_mdd_obj);
+
+ while (!mdd_is_root(mdd, &pli->pli_fids[pli->pli_fidcount])) {
+ mdd_obj = mdd_object_find(env, mdd,
+ &pli->pli_fids[pli->pli_fidcount]);
+ if (mdd_obj == NULL)
+ GOTO(out, rc = -EREMOTE);
+ if (IS_ERR(mdd_obj))
+ GOTO(out, rc = -PTR_ERR(mdd_obj));
+ rc = lu_object_exists(&mdd_obj->mod_obj.mo_lu);
+ if (rc <= 0) {
+ mdd_object_put(env, mdd_obj);
+ if (rc == -1)
+ rc = -EREMOTE;
+ else if (rc == 0)
+ /* Do I need to error out here? */
+ rc = -ENOENT;
+ GOTO(out, rc);
+ }
+
+ /* Get parent fid and object name */
+ mdd_read_lock(env, mdd_obj, MOR_TGT_CHILD);
+ buf = mdd_links_get(env, mdd_obj);
+ mdd_read_unlock(env, mdd_obj);
+ mdd_object_put(env, mdd_obj);
+ if (IS_ERR(buf))
+ GOTO(out, rc = PTR_ERR(buf));
+
+ leh = buf->lb_buf;
+ lee = (struct link_ea_entry *)(leh + 1); /* link #0 */
+ mdd_lee_unpack(lee, &reclen, tmpname, tmpfid);
+
+ /* If set, use link #linkno for path lookup, otherwise use
+ link #0. Only do this for the final path element. */
+ if ((pli->pli_fidcount == 0) &&
+ (pli->pli_linkno < leh->leh_reccount)) {
+ int count;
+ for (count = 0; count < pli->pli_linkno; count++) {
+ lee = (struct link_ea_entry *)
+ ((char *)lee + reclen);
+ mdd_lee_unpack(lee, &reclen, tmpname, tmpfid);
+ }
+ if (pli->pli_linkno < leh->leh_reccount - 1)
+ /* indicate to user there are more links */
+ pli->pli_linkno++;
+ }
+
+ /* Pack the name in the end of the buffer */
+ ptr -= tmpname->ln_namelen;
+ if (ptr - 1 <= pli->pli_path)
+ GOTO(out, rc = -EOVERFLOW);
+ strncpy(ptr, tmpname->ln_name, tmpname->ln_namelen);
+ *(--ptr) = '/';
+
+ /* Store the parent fid for historic lookup */
+ if (++pli->pli_fidcount >= MAX_PATH_DEPTH)
+ GOTO(out, rc = -EOVERFLOW);
+ pli->pli_fids[pli->pli_fidcount] = *tmpfid;
+ }
+
+ /* Verify that our path hasn't changed since we started the lookup.
+ Record the current index, and verify the path resolves to the
+ same fid. If it does, then the path is correct as of this index. */
+ spin_lock(&mdd->mdd_cl.mc_lock);
+ pli->pli_currec = mdd->mdd_cl.mc_index;
+ spin_unlock(&mdd->mdd_cl.mc_lock);
+ rc = mdd_path2fid(env, mdd, ptr, &pli->pli_fid);
+ if (rc) {
+ CDEBUG(D_INFO, "mdd_path2fid(%s) failed %d\n", ptr, rc);
+ GOTO (out, rc = -EAGAIN);
+ }
+ if (!lu_fid_eq(&pli->pli_fids[0], &pli->pli_fid)) {
+ CDEBUG(D_INFO, "mdd_path2fid(%s) found another FID o="DFID
+ " n="DFID"\n", ptr, PFID(&pli->pli_fids[0]),
+ PFID(&pli->pli_fid));
+ GOTO(out, rc = -EAGAIN);
+ }
+
+ memmove(pli->pli_path, ptr, pli->pli_path + pli->pli_pathlen - ptr);
+
+ EXIT;
+out:
+ if (buf && !IS_ERR(buf) && buf->lb_vmalloc)
+ /* if we vmalloced a large buffer drop it */
+ mdd_buf_put(buf);
+
+ return rc;
+}
+
+static int mdd_path_historic(const struct lu_env *env,
+ struct path_lookup_info *pli)