+/* similar to mdt_attr_get_complex */
+static int echo_big_lmm_get(const struct lu_env *env, struct md_object *o,
+ struct md_attr *ma)
+{
+ struct echo_thread_info *info = echo_env_info(env);
+ int rc;
+
+ ENTRY;
+
+ LASSERT(ma->ma_lmm_size > 0);
+
+ rc = mo_xattr_get(env, o, &LU_BUF_NULL, XATTR_NAME_LOV);
+ if (rc < 0)
+ RETURN(rc);
+
+ /* big_lmm may need to be grown */
+ if (info->eti_big_lmmsize < rc) {
+ int size = size_roundup_power2(rc);
+
+ if (info->eti_big_lmmsize > 0) {
+ /* free old buffer */
+ LASSERT(info->eti_big_lmm);
+ OBD_FREE_LARGE(info->eti_big_lmm,
+ info->eti_big_lmmsize);
+ info->eti_big_lmm = NULL;
+ info->eti_big_lmmsize = 0;
+ }
+
+ OBD_ALLOC_LARGE(info->eti_big_lmm, size);
+ if (info->eti_big_lmm == NULL)
+ RETURN(-ENOMEM);
+ info->eti_big_lmmsize = size;
+ }
+ LASSERT(info->eti_big_lmmsize >= rc);
+
+ info->eti_buf.lb_buf = info->eti_big_lmm;
+ info->eti_buf.lb_len = info->eti_big_lmmsize;
+ rc = mo_xattr_get(env, o, &info->eti_buf, XATTR_NAME_LOV);
+ if (rc < 0)
+ RETURN(rc);
+
+ ma->ma_valid |= MA_LOV;
+ ma->ma_lmm = info->eti_big_lmm;
+ ma->ma_lmm_size = rc;
+
+ RETURN(0);
+}
+
+int echo_attr_get_complex(const struct lu_env *env, struct md_object *next,
+ struct md_attr *ma)
+{
+ struct echo_thread_info *info = echo_env_info(env);
+ struct lu_buf *buf = &info->eti_buf;
+ cfs_umode_t mode = lu_object_attr(&next->mo_lu);
+ int need = ma->ma_need;
+ int rc = 0, rc2;
+
+ ENTRY;
+
+ ma->ma_valid = 0;
+
+ if (need & MA_INODE) {
+ ma->ma_need = MA_INODE;
+ rc = mo_attr_get(env, next, ma);
+ if (rc)
+ GOTO(out, rc);
+ ma->ma_valid |= MA_INODE;
+ }
+
+ if (need & MA_LOV) {
+ if (S_ISREG(mode) || S_ISDIR(mode)) {
+ LASSERT(ma->ma_lmm_size > 0);
+ buf->lb_buf = ma->ma_lmm;
+ buf->lb_len = ma->ma_lmm_size;
+ rc2 = mo_xattr_get(env, next, buf, XATTR_NAME_LOV);
+ if (rc2 > 0) {
+ ma->ma_lmm_size = rc2;
+ ma->ma_valid |= MA_LOV;
+ } else if (rc2 == -ENODATA) {
+ /* no LOV EA */
+ ma->ma_lmm_size = 0;
+ } else if (rc2 == -ERANGE) {
+ rc2 = echo_big_lmm_get(env, next, ma);
+ if (rc2 < 0)
+ GOTO(out, rc = rc2);
+ } else {
+ GOTO(out, rc = rc2);
+ }
+ }
+ }
+
+#ifdef CONFIG_FS_POSIX_ACL
+ if (need & MA_ACL_DEF && S_ISDIR(mode)) {
+ buf->lb_buf = ma->ma_acl;
+ buf->lb_len = ma->ma_acl_size;
+ rc2 = mo_xattr_get(env, next, buf, XATTR_NAME_ACL_DEFAULT);
+ if (rc2 > 0) {
+ ma->ma_acl_size = rc2;
+ ma->ma_valid |= MA_ACL_DEF;
+ } else if (rc2 == -ENODATA) {
+ /* no ACLs */
+ ma->ma_acl_size = 0;
+ } else {
+ GOTO(out, rc = rc2);
+ }
+ }
+#endif
+out:
+ ma->ma_need = need;
+ CDEBUG(D_INODE, "after getattr rc = %d, ma_valid = "LPX64" ma_lmm=%p\n",
+ rc, ma->ma_valid, ma->ma_lmm);
+ RETURN(rc);
+}
+