/** * Copy an extended attribute into the buffer provided, or compute * the required buffer size if \a buf is NULL. * * On success, the number of bytes used or required is stored in \a sizep. * * Note that no locking is done here. * * \param[in] env execution environment * \param[in] obj object for which to retrieve xattr * \param[out] buf buffer to store xattr value in * \param[in] name name of xattr to copy * \param[out] sizep bytes used or required to store xattr * * \retval 0 on success * \retval negative negated errno on failure */ int __osd_xattr_get(const struct lu_env *env, struct osd_object *obj, struct lu_buf *buf, const char *name, int *sizep) { int rc; /* check SA_ZPL_DXATTR first then fallback to directory xattr */ rc = __osd_sa_xattr_get(env, obj, buf, name, sizep); if (rc != -ENOENT) return rc; return __osd_xattr_get_large(env, osd_obj2dev(obj), obj->oo_xattr, buf, name, sizep); }
int __osd_xattr_get(const struct lu_env *env, struct osd_object *obj, struct lu_buf *buf, const char *name, int *sizep) { struct osd_device *osd = osd_obj2dev(obj); udmu_objset_t *uos = &osd->od_objset; uint64_t xa_data_obj; dmu_buf_t *xa_data_db; sa_handle_t *sa_hdl = NULL; uint64_t size; int rc; /* check SA_ZPL_DXATTR first then fallback to directory xattr */ rc = __osd_sa_xattr_get(env, obj, buf, name, sizep); if (rc != -ENOENT) return rc; /* are there any extended attributes? */ if (obj->oo_xattr == ZFS_NO_OBJECT) return -ENOENT; /* Lookup the object number containing the xattr data */ rc = -zap_lookup(uos->os, obj->oo_xattr, name, sizeof(uint64_t), 1, &xa_data_obj); if (rc) return rc; rc = __osd_obj2dbuf(env, uos->os, xa_data_obj, &xa_data_db, FTAG); if (rc) return rc; rc = -sa_handle_get(uos->os, xa_data_obj, NULL, SA_HDL_PRIVATE, &sa_hdl); if (rc) goto out_rele; /* Get the xattr value length / object size */ rc = -sa_lookup(sa_hdl, SA_ZPL_SIZE(uos), &size, 8); if (rc) goto out; if (size > INT_MAX) { rc = -EOVERFLOW; goto out; } *sizep = (int)size; if (buf == NULL || buf->lb_buf == NULL) { /* We only need to return the required size */ goto out; } if (*sizep > buf->lb_len) { rc = -ERANGE; /* match ldiskfs error */ goto out; } rc = -dmu_read(uos->os, xa_data_db->db_object, 0, size, buf->lb_buf, DMU_READ_PREFETCH); out: sa_handle_destroy(sa_hdl); out_rele: dmu_buf_rele(xa_data_db, FTAG); return rc; }