+ * Allocate osp_xattr_entry.
+ *
+ * If total size exceeds PAGE_SIZE, name and value will allocated in a
+ * separate buf, otherwise it's allocated inline.
+ *
+ * \param[in] name pointer to XATTR name
+ * \param[in] namelen XATTR name len
+ * \param[in] vallen XATTR value len
+ * \retval oxe pointer on success
+ * \retval NULL on failure
+ */
+static struct osp_xattr_entry *osp_oac_xattr_alloc(const char *name,
+ size_t namelen,
+ size_t vallen)
+{
+ struct osp_xattr_entry *oxe;
+ size_t size;
+
+ if (!vallen)
+ vallen = OXE_DEFAULT_LEN;
+ size = sizeof(*oxe) + namelen + 1 + vallen;
+ if (likely(size <= PAGE_SIZE)) {
+ OBD_ALLOC(oxe, size);
+ if (unlikely(!oxe))
+ return NULL;
+ oxe->oxe_buflen = size;
+ oxe->oxe_value = oxe->oxe_name + namelen + 1;
+ } else {
+ char *buf;
+
+ OBD_ALLOC_LARGE(buf, vallen);
+ if (unlikely(!buf))
+ return NULL;
+
+ size -= vallen;
+ OBD_ALLOC(oxe, size);
+ if (unlikely(!oxe)) {
+ OBD_FREE(buf, size);
+ return NULL;
+ }
+ oxe->oxe_buflen = vallen;
+ oxe->oxe_value = buf;
+ oxe->oxe_largebuf = 1;
+ }
+
+ INIT_LIST_HEAD(&oxe->oxe_list);
+
+ oxe->oxe_namelen = namelen;
+ memcpy(oxe->oxe_name, name, namelen);
+ /* One ref is for the caller, the other is for the entry on the list. */
+ atomic_set(&oxe->oxe_ref, 2);
+
+ return oxe;
+}
+
+static void osp_oac_xattr_free(struct osp_xattr_entry *oxe)
+{
+ LASSERT(list_empty(&oxe->oxe_list));
+ if (unlikely(oxe->oxe_largebuf)) {
+ OBD_FREE_LARGE(oxe->oxe_value, oxe->oxe_buflen);
+ OBD_FREE(oxe, sizeof(*oxe) + oxe->oxe_namelen + 1);
+ } else {
+ OBD_FREE(oxe, oxe->oxe_buflen);
+ }
+}
+
+/**