Defines |
#define | SA_COPY_DATA(f, s, t, l) |
#define | SA_ATTR_HASH(attr) (zfs_crc64_table[(-1ULL ^ attr) & 0xFF]) |
#define | BUF_SPACE_NEEDED(total, header) (total + header) |
Typedefs |
typedef void( | sa_iterfunc_t )(void *hdr, void *addr, sa_attr_type_t, uint16_t length, int length_idx, boolean_t, void *userp) |
Functions |
static int | sa_build_index (sa_handle_t *hdl, sa_buf_type_t buftype) |
static void | sa_idx_tab_hold (objset_t *os, sa_idx_tab_t *idx_tab) |
static void * | sa_find_idx_tab (objset_t *os, dmu_object_type_t bonustype, void *data) |
static void | sa_idx_tab_rele (objset_t *os, void *arg) |
static void | sa_copy_data (sa_data_locator_t *func, void *start, void *target, int buflen) |
static int | sa_modify_attrs (sa_handle_t *hdl, sa_attr_type_t newattr, sa_data_op_t action, sa_data_locator_t *locator, void *datastart, uint16_t buflen, dmu_tx_t *tx) |
| Add/remove a single attribute or replace a variable-sized attribute value with a value of a different size, and then rewrite the entire set of attributes.
|
static int | sa_cache_constructor (void *buf, void *unused, int kmflag) |
static void | sa_cache_destructor (void *buf, void *unused) |
void | sa_cache_init (void) |
void | sa_cache_fini (void) |
static int | layout_num_compare (const void *arg1, const void *arg2) |
static int | layout_hash_compare (const void *arg1, const void *arg2) |
boolean_t | sa_layout_equal (sa_lot_t *tbf, sa_attr_type_t *attrs, int count) |
static uint64_t | sa_layout_info_hash (sa_attr_type_t *attrs, int attr_count) |
static int | sa_get_spill (sa_handle_t *hdl) |
int | sa_attr_op (sa_handle_t *hdl, sa_bulk_attr_t *bulk, int count, sa_data_op_t data_op, dmu_tx_t *tx) |
| Main attribute lookup/update function.
|
static sa_lot_t * | sa_add_layout_entry (objset_t *os, sa_attr_type_t *attrs, int attr_count, uint64_t lot_num, uint64_t hash, boolean_t zapadd, dmu_tx_t *tx) |
static void | sa_find_layout (objset_t *os, uint64_t hash, sa_attr_type_t *attrs, int count, dmu_tx_t *tx, sa_lot_t **lot) |
static int | sa_resize_spill (sa_handle_t *hdl, uint32_t size, dmu_tx_t *tx) |
static int | sa_find_sizes (sa_os_t *sa, sa_bulk_attr_t *attr_desc, int attr_count, dmu_buf_t *db, sa_buf_type_t buftype, int *index, int *total, boolean_t *will_spill) |
| Determine several different sizes first the sa header size the number of bytes to be stored if spill would occur the index in the attribute array is returned.
|
static int | sa_build_layouts (sa_handle_t *hdl, sa_bulk_attr_t *attr_desc, int attr_count, dmu_tx_t *tx) |
| Find layout that corresponds to ordering of attributes.
|
static void | sa_free_attr_table (sa_os_t *sa) |
static int | sa_attr_table_setup (objset_t *os, sa_attr_reg_t *reg_attrs, int count) |
int | sa_setup (objset_t *os, uint64_t sa_obj, sa_attr_reg_t *reg_attrs, int count, sa_attr_type_t **user_table) |
void | sa_tear_down (objset_t *os) |
void | sa_build_idx_tab (void *hdr, void *attr_addr, sa_attr_type_t attr, uint16_t length, int length_idx, boolean_t var_length, void *userp) |
static void | sa_attr_iter (objset_t *os, sa_hdr_phys_t *hdr, dmu_object_type_t type, sa_iterfunc_t func, sa_lot_t *tab, void *userp) |
void | sa_byteswap_cb (void *hdr, void *attr_addr, sa_attr_type_t attr, uint16_t length, int length_idx, boolean_t variable_length, void *userp) |
void | sa_byteswap (sa_handle_t *hdl, sa_buf_type_t buftype) |
void | sa_evict (dmu_buf_t *db, void *sap) |
void | sa_handle_destroy (sa_handle_t *hdl) |
int | sa_handle_get_from_db (objset_t *os, dmu_buf_t *db, void *userp, sa_handle_type_t hdl_type, sa_handle_t **handlepp) |
int | sa_handle_get (objset_t *objset, uint64_t objid, void *userp, sa_handle_type_t hdl_type, sa_handle_t **handlepp) |
int | sa_buf_hold (objset_t *objset, uint64_t obj_num, void *tag, dmu_buf_t **db) |
void | sa_buf_rele (dmu_buf_t *db, void *tag) |
int | sa_lookup_impl (sa_handle_t *hdl, sa_bulk_attr_t *bulk, int count) |
int | sa_lookup (sa_handle_t *hdl, sa_attr_type_t attr, void *buf, uint32_t buflen) |
int | sa_lookup_uio (sa_handle_t *hdl, sa_attr_type_t attr, uio_t *uio) |
void | sa_default_locator (void **dataptr, uint32_t *len, uint32_t total_len, boolean_t start, void *userdata) |
static void | sa_attr_register_sync (sa_handle_t *hdl, dmu_tx_t *tx) |
int | sa_replace_all_by_template_locked (sa_handle_t *hdl, sa_bulk_attr_t *attr_desc, int attr_count, dmu_tx_t *tx) |
| Replace all attributes with attributes specified in template.
|
int | sa_replace_all_by_template (sa_handle_t *hdl, sa_bulk_attr_t *attr_desc, int attr_count, dmu_tx_t *tx) |
static int | sa_bulk_update_impl (sa_handle_t *hdl, sa_bulk_attr_t *bulk, int count, dmu_tx_t *tx) |
int | sa_update (sa_handle_t *hdl, sa_attr_type_t type, void *buf, uint32_t buflen, dmu_tx_t *tx) |
| update or add new attribute
|
int | sa_update_from_cb (sa_handle_t *hdl, sa_attr_type_t attr, uint32_t buflen, sa_data_locator_t *locator, void *userdata, dmu_tx_t *tx) |
int | sa_size (sa_handle_t *hdl, sa_attr_type_t attr, int *size) |
| Return size of an attribute.
|
int | sa_bulk_lookup_locked (sa_handle_t *hdl, sa_bulk_attr_t *attrs, int count) |
int | sa_bulk_lookup (sa_handle_t *hdl, sa_bulk_attr_t *attrs, int count) |
int | sa_bulk_update (sa_handle_t *hdl, sa_bulk_attr_t *attrs, int count, dmu_tx_t *tx) |
int | sa_remove (sa_handle_t *hdl, sa_attr_type_t attr, dmu_tx_t *tx) |
void | sa_object_info (sa_handle_t *hdl, dmu_object_info_t *doi) |
void | sa_object_size (sa_handle_t *hdl, uint32_t *blksize, u_longlong_t *nblocks) |
void | sa_update_user (sa_handle_t *newhdl, sa_handle_t *oldhdl) |
void | sa_set_userp (sa_handle_t *hdl, void *ptr) |
dmu_buf_t * | sa_get_db (sa_handle_t *hdl) |
void * | sa_get_userdata (sa_handle_t *hdl) |
void | sa_register_update_callback_locked (objset_t *os, sa_update_cb_t *func) |
void | sa_register_update_callback (objset_t *os, sa_update_cb_t *func) |
uint64_t | sa_handle_object (sa_handle_t *hdl) |
boolean_t | sa_enabled (objset_t *os) |
int | sa_set_sa_object (objset_t *os, uint64_t sa_object) |
int | sa_hdrsize (void *arg) |
void | sa_handle_lock (sa_handle_t *hdl) |
void | sa_handle_unlock (sa_handle_t *hdl) |
Variables |
arc_byteswap_func_t * | sa_bswap_table [] |
sa_attr_reg_t | sa_legacy_attrs [] |
| List of legacy attributes.
|
sa_attr_type_t | sa_legacy_zpl_layout [] |
| ZPL legacy layout.
|
sa_attr_type_t | sa_dummy_zpl_layout [] = { 0 } |
| Special dummy layout used for buffers with no attributes.
|
static int | sa_legacy_attr_count = 16 |
static kmem_cache_t * | sa_cache = NULL |
ZFS System attributes.
A generic mechanism to allow for arbitrary attributes to be stored in a dnode. The data will be stored in the bonus buffer of the dnode and if necessary a special "spill" block will be used to handle overflow situations. The spill block will be sized to fit the data from 512 - 128K. When a spill block is used the BP (blkptr_t) for the spill block is stored at the end of the current bonus buffer. Any attributes that would be in the way of the blkptr_t will be relocated into the spill block.
Attribute registration
Stored persistently on a per dataset basis a mapping between attribute "string" names and their actual attribute numeric values, length, and byteswap function. The names are only used during registration. All attributes are known by their unique attribute id value. If an attribute can have a variable size then the value 0 will be used to indicate this.
Attribute Layout
Attribute layouts are a way to compactly store multiple attributes, but without taking the overhead associated with managing each attribute individually. Since you will typically have the same set of attributes stored in the same order a single table will be used to represent that layout. The ZPL for example will usually have only about 10 different layouts (regular files, device files, symlinks, regular files + scanstamp, files/dir with extended attributes, and then you have the possibility of all of those minus ACL, because it would be kicked out into the spill block)
Layouts are simply an array of the attributes and their ordering i.e. [0, 1, 4, 5, 2]
Each distinct layout is given a unique layout number and that is whats stored in the header at the beginning of the SA data buffer.
A layout only covers a single dbuf (bonus or spill). If a set of attributes is split up between the bonus buffer and a spill buffer then two different layouts will be used. This allows us to byteswap the spill without looking at the bonus buffer and keeps the on disk format of the bonus and spill buffer the same.
Adding a single attribute will cause the entire set of attributes to be rewritten and could result in a new layout number being constructed as part of the rewrite if no such layout exists for the new set of attribues. The new attribute will be appended to the end of the already existing attributes.
Both the attribute registration and attribute layout information are stored in normal ZAP attributes. Their should be a small number of known layouts and the set of attributes is assumed to typically be quite small.
The registered attributes and layout "table" information is maintained in core and a special "sa_os_t" is attached to the objset_t.
A special interface is provided to allow for quickly applying a large set of attributes at once. sa_replace_all_by_template() is used to set an array of attributes. This is used by the ZPL when creating a brand new file. The template that is passed into the function specifies the attribute, size for variable length attributes, location of data and special "data locator" function if the data isn't in a contiguous location.
Byteswap implications
Since the SA attributes are not entirely self describing we can't do the normal byteswap processing. The special ZAP layout attribute and attribute registration attributes define the byteswap function and the size of the attributes, unless it is variable sized. The normal ZFS byteswapping infrastructure assumes you don't need to read any objects in order to do the necessary byteswapping. Whereas SA attributes can only be properly byteswapped if the dataset is opened and the layout/attribute ZAP attributes are available. Because of this the SA attributes will be byteswapped when they are first accessed by the SA code that will read the SA data.
Definition in file sa.c.