-/*
- * Handle the normal xattr set, including replace, delete and new.
- *
- * Note: "local" indicates the real data's locality. So we can't
- * just its bucket locality by its length.
- */
-static void ocfs2_xattr_set_entry_normal(struct inode *inode,
- struct ocfs2_xattr_info *xi,
- struct ocfs2_xattr_search *xs,
- u32 name_hash,
- int local)
-{
- struct ocfs2_xattr_entry *last, *xe;
- struct ocfs2_xattr_header *xh = xs->header;
- u16 count = le16_to_cpu(xh->xh_count), start;
- size_t blocksize = inode->i_sb->s_blocksize;
- char *val;
- size_t offs, size, new_size;
- struct ocfs2_xa_loc loc;
-
- ocfs2_init_xattr_bucket_xa_loc(&loc, xs->bucket,
- xs->not_found ? NULL : xs->here);
- last = &xh->xh_entries[count];
- if (!xs->not_found) {
- xe = xs->here;
- offs = le16_to_cpu(xe->xe_name_offset);
- size = namevalue_size_xe(xe);
-
- /*
- * If the new value will be stored outside, xi->xi_value has
- * been initalized as an empty ocfs2_xattr_value_root, and
- * the same goes with xi->xi_value_len, so we can set
- * new_size safely here.
- * See ocfs2_xattr_set_in_bucket.
- */
- new_size = namevalue_size_xi(xi);
-
- if (xi->xi_value) {
- ocfs2_xa_wipe_namevalue(&loc);
- if (new_size > size)
- goto set_new_name_value;
-
- /* Now replace the old value with new one. */
- if (local)
- xe->xe_value_size =
- cpu_to_le64(xi->xi_value_len);
- else
- xe->xe_value_size = 0;
-
- val = ocfs2_xattr_bucket_get_val(inode,
- xs->bucket, offs);
- memset(val + OCFS2_XATTR_SIZE(xi->xi_name_len), 0,
- size - OCFS2_XATTR_SIZE(xi->xi_name_len));
- if (OCFS2_XATTR_SIZE(xi->xi_value_len) > 0)
- memcpy(val + OCFS2_XATTR_SIZE(xi->xi_name_len),
- xi->xi_value, xi->xi_value_len);
-
- le16_add_cpu(&xh->xh_name_value_len, new_size);
- ocfs2_xattr_set_local(xe, local);
- return;
- } else {
- ocfs2_xa_remove_entry(&loc);
- if (!xh->xh_count)
- xh->xh_free_start =
- cpu_to_le16(OCFS2_XATTR_BUCKET_SIZE);
-
- return;
- }
- } else {
- /* find a new entry for insert. */
- int low = 0, high = count - 1, tmp;
- struct ocfs2_xattr_entry *tmp_xe;
-
- while (low <= high && count) {
- tmp = (low + high) / 2;
- tmp_xe = &xh->xh_entries[tmp];
-
- if (name_hash > le32_to_cpu(tmp_xe->xe_name_hash))
- low = tmp + 1;
- else if (name_hash <
- le32_to_cpu(tmp_xe->xe_name_hash))
- high = tmp - 1;
- else {
- low = tmp;
- break;
- }
- }
-
- xe = &xh->xh_entries[low];
- if (low != count)
- memmove(xe + 1, xe, (void *)last - (void *)xe);
-
- le16_add_cpu(&xh->xh_count, 1);
- memset(xe, 0, sizeof(struct ocfs2_xattr_entry));
- xe->xe_name_hash = cpu_to_le32(name_hash);
- xe->xe_name_len = xi->xi_name_len;
- ocfs2_xattr_set_type(xe, xi->xi_name_index);
- }
-
-set_new_name_value:
- /* Insert the new name+value. */
- size = namevalue_size_xi(xi);
-
- /*
- * We must make sure that the name/value pair
- * exists in the same block.
- */
- offs = le16_to_cpu(xh->xh_free_start);
- start = offs - size;
-
- if (start >> inode->i_sb->s_blocksize_bits !=
- (offs - 1) >> inode->i_sb->s_blocksize_bits) {
- offs = offs - offs % blocksize;
- xh->xh_free_start = cpu_to_le16(offs);
- }
-
- val = ocfs2_xattr_bucket_get_val(inode, xs->bucket, offs - size);
- xe->xe_name_offset = cpu_to_le16(offs - size);
-
- memset(val, 0, size);
- memcpy(val, xi->xi_name, xi->xi_name_len);
- memcpy(val + OCFS2_XATTR_SIZE(xi->xi_name_len), xi->xi_value,
- xi->xi_value_len);
-
- xe->xe_value_size = cpu_to_le64(xi->xi_value_len);
- ocfs2_xattr_set_local(xe, local);
- xs->here = xe;
- le16_add_cpu(&xh->xh_free_start, -size);
- le16_add_cpu(&xh->xh_name_value_len, size);
-
- return;
-}
-