+/*
+ * as we don't know FID, we can't use LU object, so this function
+ * partially duplicate __osd_xattr_get() which is built around
+ * LU-object and uses it to cache data like regular EA dnode, etc
+ */
+static int osd_find_parent_by_dnode(const struct lu_env *env,
+ struct dt_object *o,
+ struct lu_fid *fid)
+{
+ struct lustre_mdt_attrs *lma;
+ udmu_objset_t *uos = &osd_obj2dev(osd_dt_obj(o))->od_objset;
+ struct lu_buf buf;
+ sa_handle_t *sa_hdl;
+ nvlist_t *nvbuf = NULL;
+ uchar_t *value;
+ uint64_t dnode;
+ int rc, size;
+ ENTRY;
+
+ /* first of all, get parent dnode from own attributes */
+ LASSERT(osd_dt_obj(o)->oo_db);
+ rc = -sa_handle_get(uos->os, osd_dt_obj(o)->oo_db->db_object,
+ NULL, SA_HDL_PRIVATE, &sa_hdl);
+ if (rc)
+ RETURN(rc);
+
+ dnode = ZFS_NO_OBJECT;
+ rc = -sa_lookup(sa_hdl, SA_ZPL_PARENT(uos), &dnode, 8);
+ sa_handle_destroy(sa_hdl);
+ if (rc)
+ RETURN(rc);
+
+ /* now get EA buffer */
+ rc = __osd_xattr_load(uos, dnode, &nvbuf);
+ if (rc)
+ GOTO(regular, rc);
+
+ /* XXX: if we get that far.. should we cache the result? */
+
+ /* try to find LMA attribute */
+ LASSERT(nvbuf != NULL);
+ rc = -nvlist_lookup_byte_array(nvbuf, XATTR_NAME_LMA, &value, &size);
+ if (rc == 0 && size >= sizeof(*lma)) {
+ lma = (struct lustre_mdt_attrs *)value;
+ lustre_lma_swab(lma);
+ *fid = lma->lma_self_fid;
+ GOTO(out, rc = 0);
+ }
+
+regular:
+ /* no LMA attribute in SA, let's try regular EA */
+
+ /* first of all, get parent dnode storing regular EA */
+ rc = -sa_handle_get(uos->os, dnode, NULL, SA_HDL_PRIVATE, &sa_hdl);
+ if (rc)
+ GOTO(out, rc);
+
+ dnode = ZFS_NO_OBJECT;
+ rc = -sa_lookup(sa_hdl, SA_ZPL_XATTR(uos), &dnode, 8);
+ sa_handle_destroy(sa_hdl);
+ if (rc)
+ GOTO(out, rc);
+
+ CLASSERT(sizeof(*lma) <= sizeof(osd_oti_get(env)->oti_buf));
+ buf.lb_buf = osd_oti_get(env)->oti_buf;
+ buf.lb_len = sizeof(osd_oti_get(env)->oti_buf);
+
+ /* now try to find LMA */
+ rc = __osd_xattr_get_large(env, uos, dnode, &buf,
+ XATTR_NAME_LMA, &size);
+ if (rc == 0 && size >= sizeof(*lma)) {
+ lma = buf.lb_buf;
+ lustre_lma_swab(lma);
+ *fid = lma->lma_self_fid;
+ GOTO(out, rc = 0);
+ } else if (rc < 0) {
+ GOTO(out, rc);
+ } else {
+ GOTO(out, rc = -EIO);
+ }
+
+out:
+ if (nvbuf != NULL)
+ nvlist_free(nvbuf);
+ RETURN(rc);
+}
+