int __osd_xattr_del(const struct lu_env *env, struct osd_object *obj, const char *name, struct osd_thandle *oh) { struct osd_device *osd = osd_obj2dev(obj); udmu_objset_t *uos = &osd->od_objset; uint64_t xa_data_obj; int rc; /* try remove xattr from SA at first */ rc = __osd_sa_xattr_del(env, obj, name, oh); if (rc != -ENOENT) return rc; if (obj->oo_xattr == ZFS_NO_OBJECT) return 0; rc = -zap_lookup(uos->os, obj->oo_xattr, name, sizeof(uint64_t), 1, &xa_data_obj); if (rc == -ENOENT) { rc = 0; } else if (rc == 0) { /* * Entry exists. * We'll delete the existing object and ZAP entry. */ rc = __osd_object_free(uos, xa_data_obj, oh->ot_tx); if (rc) return rc; rc = -zap_remove(uos->os, obj->oo_xattr, name, oh->ot_tx); } return rc; }
/* * Delete a DMU object * * The transaction passed to this routine must have * dmu_tx_hold_free(tx, oid, 0, DMU_OBJECT_END) called * and then assigned to a transaction group. * * This will release db and set it to NULL to prevent further dbuf releases. */ static int __osd_object_destroy(const struct lu_env *env, struct osd_object *obj, dmu_tx_t *tx, void *tag) { struct osd_device *osd = osd_obj2dev(obj); udmu_objset_t *uos = &osd->od_objset; uint64_t xid; zap_attribute_t *za = &osd_oti_get(env)->oti_za; zap_cursor_t *zc; int rc; /* Assert that the transaction has been assigned to a transaction group. */ LASSERT(tx->tx_txg != 0); /* zap holding xattrs */ if (obj->oo_xattr != ZFS_NO_OBJECT) { rc = -udmu_zap_cursor_init(&zc, uos, obj->oo_xattr, 0); if (rc) return rc; while ((rc = -zap_cursor_retrieve(zc, za)) == 0) { BUG_ON(za->za_integer_length != sizeof(uint64_t)); BUG_ON(za->za_num_integers != 1); rc = -zap_lookup(uos->os, obj->oo_xattr, za->za_name, sizeof(uint64_t), 1, &xid); if (rc) { CERROR("%s: lookup xattr %s failed: rc = %d\n", osd->od_svname, za->za_name, rc); continue; } rc = __osd_object_free(uos, xid, tx); if (rc) CERROR("%s: fetch xattr %s failed: rc = %d\n", osd->od_svname, za->za_name, rc); zap_cursor_advance(zc); } udmu_zap_cursor_fini(zc); rc = __osd_object_free(uos, obj->oo_xattr, tx); if (rc) CERROR("%s: freeing xattr failed: rc = %d\n", osd->od_svname, rc); } return __osd_object_free(uos, obj->oo_db->db_object, tx); }
int __osd_sa_xattr_set(const struct lu_env *env, struct osd_object *obj, const struct lu_buf *buf, const char *name, int fl, struct osd_thandle *oh) { uchar_t *nv_value; size_t size; int nv_size; int rc; int too_big = 0; LASSERT(obj->oo_sa_hdl); if (obj->oo_sa_xattr == NULL) { rc = __osd_xattr_cache(env, obj); if (rc) return rc; } LASSERT(obj->oo_sa_xattr); /* Limited to 32k to keep nvpair memory allocations small */ if (buf->lb_len > DXATTR_MAX_ENTRY_SIZE) { too_big = 1; } else { /* Prevent the DXATTR SA from consuming the entire SA * region */ rc = -nvlist_size(obj->oo_sa_xattr, &size, NV_ENCODE_XDR); if (rc) return rc; if (size + buf->lb_len > DXATTR_MAX_SA_SIZE) too_big = 1; } /* even in case of -EFBIG we must lookup xattr and check can we * rewrite it then delete from SA */ rc = -nvlist_lookup_byte_array(obj->oo_sa_xattr, name, &nv_value, &nv_size); if (rc == 0) { if (fl & LU_XATTR_CREATE) { return -EEXIST; } else if (too_big) { rc = -nvlist_remove(obj->oo_sa_xattr, name, DATA_TYPE_BYTE_ARRAY); if (rc < 0) return rc; rc = __osd_sa_xattr_update(env, obj, oh); return rc == 0 ? -EFBIG : rc; } } else if (rc == -ENOENT) { if (fl & LU_XATTR_REPLACE) return -ENODATA; else if (too_big) return -EFBIG; } else { return rc; } /* Ensure xattr doesn't exist in ZAP */ if (obj->oo_xattr != ZFS_NO_OBJECT) { udmu_objset_t *uos = &osd_obj2dev(obj)->od_objset; uint64_t xa_data_obj; rc = -zap_lookup(uos->os, obj->oo_xattr, name, 8, 1, &xa_data_obj); if (rc == 0) { rc = __osd_object_free(uos, xa_data_obj, oh->ot_tx); if (rc == 0) zap_remove(uos->os, obj->oo_xattr, name, oh->ot_tx); } } rc = -nvlist_add_byte_array(obj->oo_sa_xattr, name, (uchar_t *)buf->lb_buf, buf->lb_len); if (rc) return rc; rc = __osd_sa_xattr_update(env, obj, oh); return rc; }