xref: /kernel/linux/linux-5.10/fs/ocfs2/xattr.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/* -*- mode: c; c-basic-offset: 8; -*-
38c2ecf20Sopenharmony_ci * vim: noexpandtab sw=8 ts=8 sts=0:
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * xattr.c
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright (C) 2004, 2008 Oracle.  All rights reserved.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * CREDITS:
108c2ecf20Sopenharmony_ci * Lots of code in this file is copy from linux/fs/ext3/xattr.c.
118c2ecf20Sopenharmony_ci * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <linux/capability.h>
158c2ecf20Sopenharmony_ci#include <linux/fs.h>
168c2ecf20Sopenharmony_ci#include <linux/types.h>
178c2ecf20Sopenharmony_ci#include <linux/slab.h>
188c2ecf20Sopenharmony_ci#include <linux/highmem.h>
198c2ecf20Sopenharmony_ci#include <linux/pagemap.h>
208c2ecf20Sopenharmony_ci#include <linux/uio.h>
218c2ecf20Sopenharmony_ci#include <linux/sched.h>
228c2ecf20Sopenharmony_ci#include <linux/splice.h>
238c2ecf20Sopenharmony_ci#include <linux/mount.h>
248c2ecf20Sopenharmony_ci#include <linux/writeback.h>
258c2ecf20Sopenharmony_ci#include <linux/falloc.h>
268c2ecf20Sopenharmony_ci#include <linux/sort.h>
278c2ecf20Sopenharmony_ci#include <linux/init.h>
288c2ecf20Sopenharmony_ci#include <linux/module.h>
298c2ecf20Sopenharmony_ci#include <linux/string.h>
308c2ecf20Sopenharmony_ci#include <linux/security.h>
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#include <cluster/masklog.h>
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#include "ocfs2.h"
358c2ecf20Sopenharmony_ci#include "alloc.h"
368c2ecf20Sopenharmony_ci#include "blockcheck.h"
378c2ecf20Sopenharmony_ci#include "dlmglue.h"
388c2ecf20Sopenharmony_ci#include "file.h"
398c2ecf20Sopenharmony_ci#include "symlink.h"
408c2ecf20Sopenharmony_ci#include "sysfile.h"
418c2ecf20Sopenharmony_ci#include "inode.h"
428c2ecf20Sopenharmony_ci#include "journal.h"
438c2ecf20Sopenharmony_ci#include "ocfs2_fs.h"
448c2ecf20Sopenharmony_ci#include "suballoc.h"
458c2ecf20Sopenharmony_ci#include "uptodate.h"
468c2ecf20Sopenharmony_ci#include "buffer_head_io.h"
478c2ecf20Sopenharmony_ci#include "super.h"
488c2ecf20Sopenharmony_ci#include "xattr.h"
498c2ecf20Sopenharmony_ci#include "refcounttree.h"
508c2ecf20Sopenharmony_ci#include "acl.h"
518c2ecf20Sopenharmony_ci#include "ocfs2_trace.h"
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistruct ocfs2_xattr_def_value_root {
548c2ecf20Sopenharmony_ci	struct ocfs2_xattr_value_root	xv;
558c2ecf20Sopenharmony_ci	struct ocfs2_extent_rec		er;
568c2ecf20Sopenharmony_ci};
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistruct ocfs2_xattr_bucket {
598c2ecf20Sopenharmony_ci	/* The inode these xattrs are associated with */
608c2ecf20Sopenharmony_ci	struct inode *bu_inode;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	/* The actual buffers that make up the bucket */
638c2ecf20Sopenharmony_ci	struct buffer_head *bu_bhs[OCFS2_XATTR_MAX_BLOCKS_PER_BUCKET];
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	/* How many blocks make up one bucket for this filesystem */
668c2ecf20Sopenharmony_ci	int bu_blocks;
678c2ecf20Sopenharmony_ci};
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistruct ocfs2_xattr_set_ctxt {
708c2ecf20Sopenharmony_ci	handle_t *handle;
718c2ecf20Sopenharmony_ci	struct ocfs2_alloc_context *meta_ac;
728c2ecf20Sopenharmony_ci	struct ocfs2_alloc_context *data_ac;
738c2ecf20Sopenharmony_ci	struct ocfs2_cached_dealloc_ctxt dealloc;
748c2ecf20Sopenharmony_ci	int set_abort;
758c2ecf20Sopenharmony_ci};
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci#define OCFS2_XATTR_ROOT_SIZE	(sizeof(struct ocfs2_xattr_def_value_root))
788c2ecf20Sopenharmony_ci#define OCFS2_XATTR_INLINE_SIZE	80
798c2ecf20Sopenharmony_ci#define OCFS2_XATTR_HEADER_GAP	4
808c2ecf20Sopenharmony_ci#define OCFS2_XATTR_FREE_IN_IBODY	(OCFS2_MIN_XATTR_INLINE_SIZE \
818c2ecf20Sopenharmony_ci					 - sizeof(struct ocfs2_xattr_header) \
828c2ecf20Sopenharmony_ci					 - OCFS2_XATTR_HEADER_GAP)
838c2ecf20Sopenharmony_ci#define OCFS2_XATTR_FREE_IN_BLOCK(ptr)	((ptr)->i_sb->s_blocksize \
848c2ecf20Sopenharmony_ci					 - sizeof(struct ocfs2_xattr_block) \
858c2ecf20Sopenharmony_ci					 - sizeof(struct ocfs2_xattr_header) \
868c2ecf20Sopenharmony_ci					 - OCFS2_XATTR_HEADER_GAP)
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistatic struct ocfs2_xattr_def_value_root def_xv = {
898c2ecf20Sopenharmony_ci	.xv.xr_list.l_count = cpu_to_le16(1),
908c2ecf20Sopenharmony_ci};
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ciconst struct xattr_handler *ocfs2_xattr_handlers[] = {
938c2ecf20Sopenharmony_ci	&ocfs2_xattr_user_handler,
948c2ecf20Sopenharmony_ci	&posix_acl_access_xattr_handler,
958c2ecf20Sopenharmony_ci	&posix_acl_default_xattr_handler,
968c2ecf20Sopenharmony_ci	&ocfs2_xattr_trusted_handler,
978c2ecf20Sopenharmony_ci	&ocfs2_xattr_security_handler,
988c2ecf20Sopenharmony_ci	NULL
998c2ecf20Sopenharmony_ci};
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistatic const struct xattr_handler *ocfs2_xattr_handler_map[OCFS2_XATTR_MAX] = {
1028c2ecf20Sopenharmony_ci	[OCFS2_XATTR_INDEX_USER]	= &ocfs2_xattr_user_handler,
1038c2ecf20Sopenharmony_ci	[OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS]
1048c2ecf20Sopenharmony_ci					= &posix_acl_access_xattr_handler,
1058c2ecf20Sopenharmony_ci	[OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT]
1068c2ecf20Sopenharmony_ci					= &posix_acl_default_xattr_handler,
1078c2ecf20Sopenharmony_ci	[OCFS2_XATTR_INDEX_TRUSTED]	= &ocfs2_xattr_trusted_handler,
1088c2ecf20Sopenharmony_ci	[OCFS2_XATTR_INDEX_SECURITY]	= &ocfs2_xattr_security_handler,
1098c2ecf20Sopenharmony_ci};
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistruct ocfs2_xattr_info {
1128c2ecf20Sopenharmony_ci	int		xi_name_index;
1138c2ecf20Sopenharmony_ci	const char	*xi_name;
1148c2ecf20Sopenharmony_ci	int		xi_name_len;
1158c2ecf20Sopenharmony_ci	const void	*xi_value;
1168c2ecf20Sopenharmony_ci	size_t		xi_value_len;
1178c2ecf20Sopenharmony_ci};
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistruct ocfs2_xattr_search {
1208c2ecf20Sopenharmony_ci	struct buffer_head *inode_bh;
1218c2ecf20Sopenharmony_ci	/*
1228c2ecf20Sopenharmony_ci	 * xattr_bh point to the block buffer head which has extended attribute
1238c2ecf20Sopenharmony_ci	 * when extended attribute in inode, xattr_bh is equal to inode_bh.
1248c2ecf20Sopenharmony_ci	 */
1258c2ecf20Sopenharmony_ci	struct buffer_head *xattr_bh;
1268c2ecf20Sopenharmony_ci	struct ocfs2_xattr_header *header;
1278c2ecf20Sopenharmony_ci	struct ocfs2_xattr_bucket *bucket;
1288c2ecf20Sopenharmony_ci	void *base;
1298c2ecf20Sopenharmony_ci	void *end;
1308c2ecf20Sopenharmony_ci	struct ocfs2_xattr_entry *here;
1318c2ecf20Sopenharmony_ci	int not_found;
1328c2ecf20Sopenharmony_ci};
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci/* Operations on struct ocfs2_xa_entry */
1358c2ecf20Sopenharmony_cistruct ocfs2_xa_loc;
1368c2ecf20Sopenharmony_cistruct ocfs2_xa_loc_operations {
1378c2ecf20Sopenharmony_ci	/*
1388c2ecf20Sopenharmony_ci	 * Journal functions
1398c2ecf20Sopenharmony_ci	 */
1408c2ecf20Sopenharmony_ci	int (*xlo_journal_access)(handle_t *handle, struct ocfs2_xa_loc *loc,
1418c2ecf20Sopenharmony_ci				  int type);
1428c2ecf20Sopenharmony_ci	void (*xlo_journal_dirty)(handle_t *handle, struct ocfs2_xa_loc *loc);
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	/*
1458c2ecf20Sopenharmony_ci	 * Return a pointer to the appropriate buffer in loc->xl_storage
1468c2ecf20Sopenharmony_ci	 * at the given offset from loc->xl_header.
1478c2ecf20Sopenharmony_ci	 */
1488c2ecf20Sopenharmony_ci	void *(*xlo_offset_pointer)(struct ocfs2_xa_loc *loc, int offset);
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	/* Can we reuse the existing entry for the new value? */
1518c2ecf20Sopenharmony_ci	int (*xlo_can_reuse)(struct ocfs2_xa_loc *loc,
1528c2ecf20Sopenharmony_ci			     struct ocfs2_xattr_info *xi);
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	/* How much space is needed for the new value? */
1558c2ecf20Sopenharmony_ci	int (*xlo_check_space)(struct ocfs2_xa_loc *loc,
1568c2ecf20Sopenharmony_ci			       struct ocfs2_xattr_info *xi);
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	/*
1598c2ecf20Sopenharmony_ci	 * Return the offset of the first name+value pair.  This is
1608c2ecf20Sopenharmony_ci	 * the start of our downward-filling free space.
1618c2ecf20Sopenharmony_ci	 */
1628c2ecf20Sopenharmony_ci	int (*xlo_get_free_start)(struct ocfs2_xa_loc *loc);
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	/*
1658c2ecf20Sopenharmony_ci	 * Remove the name+value at this location.  Do whatever is
1668c2ecf20Sopenharmony_ci	 * appropriate with the remaining name+value pairs.
1678c2ecf20Sopenharmony_ci	 */
1688c2ecf20Sopenharmony_ci	void (*xlo_wipe_namevalue)(struct ocfs2_xa_loc *loc);
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	/* Fill xl_entry with a new entry */
1718c2ecf20Sopenharmony_ci	void (*xlo_add_entry)(struct ocfs2_xa_loc *loc, u32 name_hash);
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	/* Add name+value storage to an entry */
1748c2ecf20Sopenharmony_ci	void (*xlo_add_namevalue)(struct ocfs2_xa_loc *loc, int size);
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	/*
1778c2ecf20Sopenharmony_ci	 * Initialize the value buf's access and bh fields for this entry.
1788c2ecf20Sopenharmony_ci	 * ocfs2_xa_fill_value_buf() will handle the xv pointer.
1798c2ecf20Sopenharmony_ci	 */
1808c2ecf20Sopenharmony_ci	void (*xlo_fill_value_buf)(struct ocfs2_xa_loc *loc,
1818c2ecf20Sopenharmony_ci				   struct ocfs2_xattr_value_buf *vb);
1828c2ecf20Sopenharmony_ci};
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci/*
1858c2ecf20Sopenharmony_ci * Describes an xattr entry location.  This is a memory structure
1868c2ecf20Sopenharmony_ci * tracking the on-disk structure.
1878c2ecf20Sopenharmony_ci */
1888c2ecf20Sopenharmony_cistruct ocfs2_xa_loc {
1898c2ecf20Sopenharmony_ci	/* This xattr belongs to this inode */
1908c2ecf20Sopenharmony_ci	struct inode *xl_inode;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	/* The ocfs2_xattr_header inside the on-disk storage. Not NULL. */
1938c2ecf20Sopenharmony_ci	struct ocfs2_xattr_header *xl_header;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	/* Bytes from xl_header to the end of the storage */
1968c2ecf20Sopenharmony_ci	int xl_size;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	/*
1998c2ecf20Sopenharmony_ci	 * The ocfs2_xattr_entry this location describes.  If this is
2008c2ecf20Sopenharmony_ci	 * NULL, this location describes the on-disk structure where it
2018c2ecf20Sopenharmony_ci	 * would have been.
2028c2ecf20Sopenharmony_ci	 */
2038c2ecf20Sopenharmony_ci	struct ocfs2_xattr_entry *xl_entry;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	/*
2068c2ecf20Sopenharmony_ci	 * Internal housekeeping
2078c2ecf20Sopenharmony_ci	 */
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	/* Buffer(s) containing this entry */
2108c2ecf20Sopenharmony_ci	void *xl_storage;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	/* Operations on the storage backing this location */
2138c2ecf20Sopenharmony_ci	const struct ocfs2_xa_loc_operations *xl_ops;
2148c2ecf20Sopenharmony_ci};
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci/*
2178c2ecf20Sopenharmony_ci * Convenience functions to calculate how much space is needed for a
2188c2ecf20Sopenharmony_ci * given name+value pair
2198c2ecf20Sopenharmony_ci */
2208c2ecf20Sopenharmony_cistatic int namevalue_size(int name_len, uint64_t value_len)
2218c2ecf20Sopenharmony_ci{
2228c2ecf20Sopenharmony_ci	if (value_len > OCFS2_XATTR_INLINE_SIZE)
2238c2ecf20Sopenharmony_ci		return OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_ROOT_SIZE;
2248c2ecf20Sopenharmony_ci	else
2258c2ecf20Sopenharmony_ci		return OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_SIZE(value_len);
2268c2ecf20Sopenharmony_ci}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_cistatic int namevalue_size_xi(struct ocfs2_xattr_info *xi)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	return namevalue_size(xi->xi_name_len, xi->xi_value_len);
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_cistatic int namevalue_size_xe(struct ocfs2_xattr_entry *xe)
2348c2ecf20Sopenharmony_ci{
2358c2ecf20Sopenharmony_ci	u64 value_len = le64_to_cpu(xe->xe_value_size);
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	BUG_ON((value_len > OCFS2_XATTR_INLINE_SIZE) &&
2388c2ecf20Sopenharmony_ci	       ocfs2_xattr_is_local(xe));
2398c2ecf20Sopenharmony_ci	return namevalue_size(xe->xe_name_len, value_len);
2408c2ecf20Sopenharmony_ci}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_cistatic int ocfs2_xattr_bucket_get_name_value(struct super_block *sb,
2448c2ecf20Sopenharmony_ci					     struct ocfs2_xattr_header *xh,
2458c2ecf20Sopenharmony_ci					     int index,
2468c2ecf20Sopenharmony_ci					     int *block_off,
2478c2ecf20Sopenharmony_ci					     int *new_offset);
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_cistatic int ocfs2_xattr_block_find(struct inode *inode,
2508c2ecf20Sopenharmony_ci				  int name_index,
2518c2ecf20Sopenharmony_ci				  const char *name,
2528c2ecf20Sopenharmony_ci				  struct ocfs2_xattr_search *xs);
2538c2ecf20Sopenharmony_cistatic int ocfs2_xattr_index_block_find(struct inode *inode,
2548c2ecf20Sopenharmony_ci					struct buffer_head *root_bh,
2558c2ecf20Sopenharmony_ci					int name_index,
2568c2ecf20Sopenharmony_ci					const char *name,
2578c2ecf20Sopenharmony_ci					struct ocfs2_xattr_search *xs);
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_cistatic int ocfs2_xattr_tree_list_index_block(struct inode *inode,
2608c2ecf20Sopenharmony_ci					struct buffer_head *blk_bh,
2618c2ecf20Sopenharmony_ci					char *buffer,
2628c2ecf20Sopenharmony_ci					size_t buffer_size);
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_cistatic int ocfs2_xattr_create_index_block(struct inode *inode,
2658c2ecf20Sopenharmony_ci					  struct ocfs2_xattr_search *xs,
2668c2ecf20Sopenharmony_ci					  struct ocfs2_xattr_set_ctxt *ctxt);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_cistatic int ocfs2_xattr_set_entry_index_block(struct inode *inode,
2698c2ecf20Sopenharmony_ci					     struct ocfs2_xattr_info *xi,
2708c2ecf20Sopenharmony_ci					     struct ocfs2_xattr_search *xs,
2718c2ecf20Sopenharmony_ci					     struct ocfs2_xattr_set_ctxt *ctxt);
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_citypedef int (xattr_tree_rec_func)(struct inode *inode,
2748c2ecf20Sopenharmony_ci				  struct buffer_head *root_bh,
2758c2ecf20Sopenharmony_ci				  u64 blkno, u32 cpos, u32 len, void *para);
2768c2ecf20Sopenharmony_cistatic int ocfs2_iterate_xattr_index_block(struct inode *inode,
2778c2ecf20Sopenharmony_ci					   struct buffer_head *root_bh,
2788c2ecf20Sopenharmony_ci					   xattr_tree_rec_func *rec_func,
2798c2ecf20Sopenharmony_ci					   void *para);
2808c2ecf20Sopenharmony_cistatic int ocfs2_delete_xattr_in_bucket(struct inode *inode,
2818c2ecf20Sopenharmony_ci					struct ocfs2_xattr_bucket *bucket,
2828c2ecf20Sopenharmony_ci					void *para);
2838c2ecf20Sopenharmony_cistatic int ocfs2_rm_xattr_cluster(struct inode *inode,
2848c2ecf20Sopenharmony_ci				  struct buffer_head *root_bh,
2858c2ecf20Sopenharmony_ci				  u64 blkno,
2868c2ecf20Sopenharmony_ci				  u32 cpos,
2878c2ecf20Sopenharmony_ci				  u32 len,
2888c2ecf20Sopenharmony_ci				  void *para);
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_cistatic int ocfs2_mv_xattr_buckets(struct inode *inode, handle_t *handle,
2918c2ecf20Sopenharmony_ci				  u64 src_blk, u64 last_blk, u64 to_blk,
2928c2ecf20Sopenharmony_ci				  unsigned int start_bucket,
2938c2ecf20Sopenharmony_ci				  u32 *first_hash);
2948c2ecf20Sopenharmony_cistatic int ocfs2_prepare_refcount_xattr(struct inode *inode,
2958c2ecf20Sopenharmony_ci					struct ocfs2_dinode *di,
2968c2ecf20Sopenharmony_ci					struct ocfs2_xattr_info *xi,
2978c2ecf20Sopenharmony_ci					struct ocfs2_xattr_search *xis,
2988c2ecf20Sopenharmony_ci					struct ocfs2_xattr_search *xbs,
2998c2ecf20Sopenharmony_ci					struct ocfs2_refcount_tree **ref_tree,
3008c2ecf20Sopenharmony_ci					int *meta_need,
3018c2ecf20Sopenharmony_ci					int *credits);
3028c2ecf20Sopenharmony_cistatic int ocfs2_get_xattr_tree_value_root(struct super_block *sb,
3038c2ecf20Sopenharmony_ci					   struct ocfs2_xattr_bucket *bucket,
3048c2ecf20Sopenharmony_ci					   int offset,
3058c2ecf20Sopenharmony_ci					   struct ocfs2_xattr_value_root **xv,
3068c2ecf20Sopenharmony_ci					   struct buffer_head **bh);
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_cistatic inline u16 ocfs2_xattr_buckets_per_cluster(struct ocfs2_super *osb)
3098c2ecf20Sopenharmony_ci{
3108c2ecf20Sopenharmony_ci	return (1 << osb->s_clustersize_bits) / OCFS2_XATTR_BUCKET_SIZE;
3118c2ecf20Sopenharmony_ci}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_cistatic inline u16 ocfs2_blocks_per_xattr_bucket(struct super_block *sb)
3148c2ecf20Sopenharmony_ci{
3158c2ecf20Sopenharmony_ci	return OCFS2_XATTR_BUCKET_SIZE / (1 << sb->s_blocksize_bits);
3168c2ecf20Sopenharmony_ci}
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci#define bucket_blkno(_b) ((_b)->bu_bhs[0]->b_blocknr)
3198c2ecf20Sopenharmony_ci#define bucket_block(_b, _n) ((_b)->bu_bhs[(_n)]->b_data)
3208c2ecf20Sopenharmony_ci#define bucket_xh(_b) ((struct ocfs2_xattr_header *)bucket_block((_b), 0))
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_cistatic struct ocfs2_xattr_bucket *ocfs2_xattr_bucket_new(struct inode *inode)
3238c2ecf20Sopenharmony_ci{
3248c2ecf20Sopenharmony_ci	struct ocfs2_xattr_bucket *bucket;
3258c2ecf20Sopenharmony_ci	int blks = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	BUG_ON(blks > OCFS2_XATTR_MAX_BLOCKS_PER_BUCKET);
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	bucket = kzalloc(sizeof(struct ocfs2_xattr_bucket), GFP_NOFS);
3308c2ecf20Sopenharmony_ci	if (bucket) {
3318c2ecf20Sopenharmony_ci		bucket->bu_inode = inode;
3328c2ecf20Sopenharmony_ci		bucket->bu_blocks = blks;
3338c2ecf20Sopenharmony_ci	}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	return bucket;
3368c2ecf20Sopenharmony_ci}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_cistatic void ocfs2_xattr_bucket_relse(struct ocfs2_xattr_bucket *bucket)
3398c2ecf20Sopenharmony_ci{
3408c2ecf20Sopenharmony_ci	int i;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	for (i = 0; i < bucket->bu_blocks; i++) {
3438c2ecf20Sopenharmony_ci		brelse(bucket->bu_bhs[i]);
3448c2ecf20Sopenharmony_ci		bucket->bu_bhs[i] = NULL;
3458c2ecf20Sopenharmony_ci	}
3468c2ecf20Sopenharmony_ci}
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_cistatic void ocfs2_xattr_bucket_free(struct ocfs2_xattr_bucket *bucket)
3498c2ecf20Sopenharmony_ci{
3508c2ecf20Sopenharmony_ci	if (bucket) {
3518c2ecf20Sopenharmony_ci		ocfs2_xattr_bucket_relse(bucket);
3528c2ecf20Sopenharmony_ci		bucket->bu_inode = NULL;
3538c2ecf20Sopenharmony_ci		kfree(bucket);
3548c2ecf20Sopenharmony_ci	}
3558c2ecf20Sopenharmony_ci}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci/*
3588c2ecf20Sopenharmony_ci * A bucket that has never been written to disk doesn't need to be
3598c2ecf20Sopenharmony_ci * read.  We just need the buffer_heads.  Don't call this for
3608c2ecf20Sopenharmony_ci * buckets that are already on disk.  ocfs2_read_xattr_bucket() initializes
3618c2ecf20Sopenharmony_ci * them fully.
3628c2ecf20Sopenharmony_ci */
3638c2ecf20Sopenharmony_cistatic int ocfs2_init_xattr_bucket(struct ocfs2_xattr_bucket *bucket,
3648c2ecf20Sopenharmony_ci				   u64 xb_blkno, int new)
3658c2ecf20Sopenharmony_ci{
3668c2ecf20Sopenharmony_ci	int i, rc = 0;
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	for (i = 0; i < bucket->bu_blocks; i++) {
3698c2ecf20Sopenharmony_ci		bucket->bu_bhs[i] = sb_getblk(bucket->bu_inode->i_sb,
3708c2ecf20Sopenharmony_ci					      xb_blkno + i);
3718c2ecf20Sopenharmony_ci		if (!bucket->bu_bhs[i]) {
3728c2ecf20Sopenharmony_ci			rc = -ENOMEM;
3738c2ecf20Sopenharmony_ci			mlog_errno(rc);
3748c2ecf20Sopenharmony_ci			break;
3758c2ecf20Sopenharmony_ci		}
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci		if (!ocfs2_buffer_uptodate(INODE_CACHE(bucket->bu_inode),
3788c2ecf20Sopenharmony_ci					   bucket->bu_bhs[i])) {
3798c2ecf20Sopenharmony_ci			if (new)
3808c2ecf20Sopenharmony_ci				ocfs2_set_new_buffer_uptodate(INODE_CACHE(bucket->bu_inode),
3818c2ecf20Sopenharmony_ci							      bucket->bu_bhs[i]);
3828c2ecf20Sopenharmony_ci			else {
3838c2ecf20Sopenharmony_ci				set_buffer_uptodate(bucket->bu_bhs[i]);
3848c2ecf20Sopenharmony_ci				ocfs2_set_buffer_uptodate(INODE_CACHE(bucket->bu_inode),
3858c2ecf20Sopenharmony_ci							  bucket->bu_bhs[i]);
3868c2ecf20Sopenharmony_ci			}
3878c2ecf20Sopenharmony_ci		}
3888c2ecf20Sopenharmony_ci	}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	if (rc)
3918c2ecf20Sopenharmony_ci		ocfs2_xattr_bucket_relse(bucket);
3928c2ecf20Sopenharmony_ci	return rc;
3938c2ecf20Sopenharmony_ci}
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci/* Read the xattr bucket at xb_blkno */
3968c2ecf20Sopenharmony_cistatic int ocfs2_read_xattr_bucket(struct ocfs2_xattr_bucket *bucket,
3978c2ecf20Sopenharmony_ci				   u64 xb_blkno)
3988c2ecf20Sopenharmony_ci{
3998c2ecf20Sopenharmony_ci	int rc;
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	rc = ocfs2_read_blocks(INODE_CACHE(bucket->bu_inode), xb_blkno,
4028c2ecf20Sopenharmony_ci			       bucket->bu_blocks, bucket->bu_bhs, 0,
4038c2ecf20Sopenharmony_ci			       NULL);
4048c2ecf20Sopenharmony_ci	if (!rc) {
4058c2ecf20Sopenharmony_ci		spin_lock(&OCFS2_SB(bucket->bu_inode->i_sb)->osb_xattr_lock);
4068c2ecf20Sopenharmony_ci		rc = ocfs2_validate_meta_ecc_bhs(bucket->bu_inode->i_sb,
4078c2ecf20Sopenharmony_ci						 bucket->bu_bhs,
4088c2ecf20Sopenharmony_ci						 bucket->bu_blocks,
4098c2ecf20Sopenharmony_ci						 &bucket_xh(bucket)->xh_check);
4108c2ecf20Sopenharmony_ci		spin_unlock(&OCFS2_SB(bucket->bu_inode->i_sb)->osb_xattr_lock);
4118c2ecf20Sopenharmony_ci		if (rc)
4128c2ecf20Sopenharmony_ci			mlog_errno(rc);
4138c2ecf20Sopenharmony_ci	}
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	if (rc)
4168c2ecf20Sopenharmony_ci		ocfs2_xattr_bucket_relse(bucket);
4178c2ecf20Sopenharmony_ci	return rc;
4188c2ecf20Sopenharmony_ci}
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_cistatic int ocfs2_xattr_bucket_journal_access(handle_t *handle,
4218c2ecf20Sopenharmony_ci					     struct ocfs2_xattr_bucket *bucket,
4228c2ecf20Sopenharmony_ci					     int type)
4238c2ecf20Sopenharmony_ci{
4248c2ecf20Sopenharmony_ci	int i, rc = 0;
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	for (i = 0; i < bucket->bu_blocks; i++) {
4278c2ecf20Sopenharmony_ci		rc = ocfs2_journal_access(handle,
4288c2ecf20Sopenharmony_ci					  INODE_CACHE(bucket->bu_inode),
4298c2ecf20Sopenharmony_ci					  bucket->bu_bhs[i], type);
4308c2ecf20Sopenharmony_ci		if (rc) {
4318c2ecf20Sopenharmony_ci			mlog_errno(rc);
4328c2ecf20Sopenharmony_ci			break;
4338c2ecf20Sopenharmony_ci		}
4348c2ecf20Sopenharmony_ci	}
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	return rc;
4378c2ecf20Sopenharmony_ci}
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_cistatic void ocfs2_xattr_bucket_journal_dirty(handle_t *handle,
4408c2ecf20Sopenharmony_ci					     struct ocfs2_xattr_bucket *bucket)
4418c2ecf20Sopenharmony_ci{
4428c2ecf20Sopenharmony_ci	int i;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	spin_lock(&OCFS2_SB(bucket->bu_inode->i_sb)->osb_xattr_lock);
4458c2ecf20Sopenharmony_ci	ocfs2_compute_meta_ecc_bhs(bucket->bu_inode->i_sb,
4468c2ecf20Sopenharmony_ci				   bucket->bu_bhs, bucket->bu_blocks,
4478c2ecf20Sopenharmony_ci				   &bucket_xh(bucket)->xh_check);
4488c2ecf20Sopenharmony_ci	spin_unlock(&OCFS2_SB(bucket->bu_inode->i_sb)->osb_xattr_lock);
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	for (i = 0; i < bucket->bu_blocks; i++)
4518c2ecf20Sopenharmony_ci		ocfs2_journal_dirty(handle, bucket->bu_bhs[i]);
4528c2ecf20Sopenharmony_ci}
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_cistatic void ocfs2_xattr_bucket_copy_data(struct ocfs2_xattr_bucket *dest,
4558c2ecf20Sopenharmony_ci					 struct ocfs2_xattr_bucket *src)
4568c2ecf20Sopenharmony_ci{
4578c2ecf20Sopenharmony_ci	int i;
4588c2ecf20Sopenharmony_ci	int blocksize = src->bu_inode->i_sb->s_blocksize;
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	BUG_ON(dest->bu_blocks != src->bu_blocks);
4618c2ecf20Sopenharmony_ci	BUG_ON(dest->bu_inode != src->bu_inode);
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	for (i = 0; i < src->bu_blocks; i++) {
4648c2ecf20Sopenharmony_ci		memcpy(bucket_block(dest, i), bucket_block(src, i),
4658c2ecf20Sopenharmony_ci		       blocksize);
4668c2ecf20Sopenharmony_ci	}
4678c2ecf20Sopenharmony_ci}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_cistatic int ocfs2_validate_xattr_block(struct super_block *sb,
4708c2ecf20Sopenharmony_ci				      struct buffer_head *bh)
4718c2ecf20Sopenharmony_ci{
4728c2ecf20Sopenharmony_ci	int rc;
4738c2ecf20Sopenharmony_ci	struct ocfs2_xattr_block *xb =
4748c2ecf20Sopenharmony_ci		(struct ocfs2_xattr_block *)bh->b_data;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	trace_ocfs2_validate_xattr_block((unsigned long long)bh->b_blocknr);
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	BUG_ON(!buffer_uptodate(bh));
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	/*
4818c2ecf20Sopenharmony_ci	 * If the ecc fails, we return the error but otherwise
4828c2ecf20Sopenharmony_ci	 * leave the filesystem running.  We know any error is
4838c2ecf20Sopenharmony_ci	 * local to this block.
4848c2ecf20Sopenharmony_ci	 */
4858c2ecf20Sopenharmony_ci	rc = ocfs2_validate_meta_ecc(sb, bh->b_data, &xb->xb_check);
4868c2ecf20Sopenharmony_ci	if (rc)
4878c2ecf20Sopenharmony_ci		return rc;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	/*
4908c2ecf20Sopenharmony_ci	 * Errors after here are fatal
4918c2ecf20Sopenharmony_ci	 */
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	if (!OCFS2_IS_VALID_XATTR_BLOCK(xb)) {
4948c2ecf20Sopenharmony_ci		return ocfs2_error(sb,
4958c2ecf20Sopenharmony_ci				   "Extended attribute block #%llu has bad signature %.*s\n",
4968c2ecf20Sopenharmony_ci				   (unsigned long long)bh->b_blocknr, 7,
4978c2ecf20Sopenharmony_ci				   xb->xb_signature);
4988c2ecf20Sopenharmony_ci	}
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	if (le64_to_cpu(xb->xb_blkno) != bh->b_blocknr) {
5018c2ecf20Sopenharmony_ci		return ocfs2_error(sb,
5028c2ecf20Sopenharmony_ci				   "Extended attribute block #%llu has an invalid xb_blkno of %llu\n",
5038c2ecf20Sopenharmony_ci				   (unsigned long long)bh->b_blocknr,
5048c2ecf20Sopenharmony_ci				   (unsigned long long)le64_to_cpu(xb->xb_blkno));
5058c2ecf20Sopenharmony_ci	}
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	if (le32_to_cpu(xb->xb_fs_generation) != OCFS2_SB(sb)->fs_generation) {
5088c2ecf20Sopenharmony_ci		return ocfs2_error(sb,
5098c2ecf20Sopenharmony_ci				   "Extended attribute block #%llu has an invalid xb_fs_generation of #%u\n",
5108c2ecf20Sopenharmony_ci				   (unsigned long long)bh->b_blocknr,
5118c2ecf20Sopenharmony_ci				   le32_to_cpu(xb->xb_fs_generation));
5128c2ecf20Sopenharmony_ci	}
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	return 0;
5158c2ecf20Sopenharmony_ci}
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_cistatic int ocfs2_read_xattr_block(struct inode *inode, u64 xb_blkno,
5188c2ecf20Sopenharmony_ci				  struct buffer_head **bh)
5198c2ecf20Sopenharmony_ci{
5208c2ecf20Sopenharmony_ci	int rc;
5218c2ecf20Sopenharmony_ci	struct buffer_head *tmp = *bh;
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	rc = ocfs2_read_block(INODE_CACHE(inode), xb_blkno, &tmp,
5248c2ecf20Sopenharmony_ci			      ocfs2_validate_xattr_block);
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	/* If ocfs2_read_block() got us a new bh, pass it up. */
5278c2ecf20Sopenharmony_ci	if (!rc && !*bh)
5288c2ecf20Sopenharmony_ci		*bh = tmp;
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	return rc;
5318c2ecf20Sopenharmony_ci}
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_cistatic inline const char *ocfs2_xattr_prefix(int name_index)
5348c2ecf20Sopenharmony_ci{
5358c2ecf20Sopenharmony_ci	const struct xattr_handler *handler = NULL;
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	if (name_index > 0 && name_index < OCFS2_XATTR_MAX)
5388c2ecf20Sopenharmony_ci		handler = ocfs2_xattr_handler_map[name_index];
5398c2ecf20Sopenharmony_ci	return handler ? xattr_prefix(handler) : NULL;
5408c2ecf20Sopenharmony_ci}
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_cistatic u32 ocfs2_xattr_name_hash(struct inode *inode,
5438c2ecf20Sopenharmony_ci				 const char *name,
5448c2ecf20Sopenharmony_ci				 int name_len)
5458c2ecf20Sopenharmony_ci{
5468c2ecf20Sopenharmony_ci	/* Get hash value of uuid from super block */
5478c2ecf20Sopenharmony_ci	u32 hash = OCFS2_SB(inode->i_sb)->uuid_hash;
5488c2ecf20Sopenharmony_ci	int i;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	/* hash extended attribute name */
5518c2ecf20Sopenharmony_ci	for (i = 0; i < name_len; i++) {
5528c2ecf20Sopenharmony_ci		hash = (hash << OCFS2_HASH_SHIFT) ^
5538c2ecf20Sopenharmony_ci		       (hash >> (8*sizeof(hash) - OCFS2_HASH_SHIFT)) ^
5548c2ecf20Sopenharmony_ci		       *name++;
5558c2ecf20Sopenharmony_ci	}
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	return hash;
5588c2ecf20Sopenharmony_ci}
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_cistatic int ocfs2_xattr_entry_real_size(int name_len, size_t value_len)
5618c2ecf20Sopenharmony_ci{
5628c2ecf20Sopenharmony_ci	return namevalue_size(name_len, value_len) +
5638c2ecf20Sopenharmony_ci		sizeof(struct ocfs2_xattr_entry);
5648c2ecf20Sopenharmony_ci}
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_cistatic int ocfs2_xi_entry_usage(struct ocfs2_xattr_info *xi)
5678c2ecf20Sopenharmony_ci{
5688c2ecf20Sopenharmony_ci	return namevalue_size_xi(xi) +
5698c2ecf20Sopenharmony_ci		sizeof(struct ocfs2_xattr_entry);
5708c2ecf20Sopenharmony_ci}
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_cistatic int ocfs2_xe_entry_usage(struct ocfs2_xattr_entry *xe)
5738c2ecf20Sopenharmony_ci{
5748c2ecf20Sopenharmony_ci	return namevalue_size_xe(xe) +
5758c2ecf20Sopenharmony_ci		sizeof(struct ocfs2_xattr_entry);
5768c2ecf20Sopenharmony_ci}
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ciint ocfs2_calc_security_init(struct inode *dir,
5798c2ecf20Sopenharmony_ci			     struct ocfs2_security_xattr_info *si,
5808c2ecf20Sopenharmony_ci			     int *want_clusters,
5818c2ecf20Sopenharmony_ci			     int *xattr_credits,
5828c2ecf20Sopenharmony_ci			     struct ocfs2_alloc_context **xattr_ac)
5838c2ecf20Sopenharmony_ci{
5848c2ecf20Sopenharmony_ci	int ret = 0;
5858c2ecf20Sopenharmony_ci	struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
5868c2ecf20Sopenharmony_ci	int s_size = ocfs2_xattr_entry_real_size(strlen(si->name),
5878c2ecf20Sopenharmony_ci						 si->value_len);
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	/*
5908c2ecf20Sopenharmony_ci	 * The max space of security xattr taken inline is
5918c2ecf20Sopenharmony_ci	 * 256(name) + 80(value) + 16(entry) = 352 bytes,
5928c2ecf20Sopenharmony_ci	 * So reserve one metadata block for it is ok.
5938c2ecf20Sopenharmony_ci	 */
5948c2ecf20Sopenharmony_ci	if (dir->i_sb->s_blocksize == OCFS2_MIN_BLOCKSIZE ||
5958c2ecf20Sopenharmony_ci	    s_size > OCFS2_XATTR_FREE_IN_IBODY) {
5968c2ecf20Sopenharmony_ci		ret = ocfs2_reserve_new_metadata_blocks(osb, 1, xattr_ac);
5978c2ecf20Sopenharmony_ci		if (ret) {
5988c2ecf20Sopenharmony_ci			mlog_errno(ret);
5998c2ecf20Sopenharmony_ci			return ret;
6008c2ecf20Sopenharmony_ci		}
6018c2ecf20Sopenharmony_ci		*xattr_credits += OCFS2_XATTR_BLOCK_CREATE_CREDITS;
6028c2ecf20Sopenharmony_ci	}
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	/* reserve clusters for xattr value which will be set in B tree*/
6058c2ecf20Sopenharmony_ci	if (si->value_len > OCFS2_XATTR_INLINE_SIZE) {
6068c2ecf20Sopenharmony_ci		int new_clusters = ocfs2_clusters_for_bytes(dir->i_sb,
6078c2ecf20Sopenharmony_ci							    si->value_len);
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci		*xattr_credits += ocfs2_clusters_to_blocks(dir->i_sb,
6108c2ecf20Sopenharmony_ci							   new_clusters);
6118c2ecf20Sopenharmony_ci		*want_clusters += new_clusters;
6128c2ecf20Sopenharmony_ci	}
6138c2ecf20Sopenharmony_ci	return ret;
6148c2ecf20Sopenharmony_ci}
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ciint ocfs2_calc_xattr_init(struct inode *dir,
6178c2ecf20Sopenharmony_ci			  struct buffer_head *dir_bh,
6188c2ecf20Sopenharmony_ci			  umode_t mode,
6198c2ecf20Sopenharmony_ci			  struct ocfs2_security_xattr_info *si,
6208c2ecf20Sopenharmony_ci			  int *want_clusters,
6218c2ecf20Sopenharmony_ci			  int *xattr_credits,
6228c2ecf20Sopenharmony_ci			  int *want_meta)
6238c2ecf20Sopenharmony_ci{
6248c2ecf20Sopenharmony_ci	int ret = 0;
6258c2ecf20Sopenharmony_ci	struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
6268c2ecf20Sopenharmony_ci	int s_size = 0, a_size = 0, acl_len = 0, new_clusters;
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	if (si->enable)
6298c2ecf20Sopenharmony_ci		s_size = ocfs2_xattr_entry_real_size(strlen(si->name),
6308c2ecf20Sopenharmony_ci						     si->value_len);
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) {
6338c2ecf20Sopenharmony_ci		down_read(&OCFS2_I(dir)->ip_xattr_sem);
6348c2ecf20Sopenharmony_ci		acl_len = ocfs2_xattr_get_nolock(dir, dir_bh,
6358c2ecf20Sopenharmony_ci					OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT,
6368c2ecf20Sopenharmony_ci					"", NULL, 0);
6378c2ecf20Sopenharmony_ci		up_read(&OCFS2_I(dir)->ip_xattr_sem);
6388c2ecf20Sopenharmony_ci		if (acl_len > 0) {
6398c2ecf20Sopenharmony_ci			a_size = ocfs2_xattr_entry_real_size(0, acl_len);
6408c2ecf20Sopenharmony_ci			if (S_ISDIR(mode))
6418c2ecf20Sopenharmony_ci				a_size <<= 1;
6428c2ecf20Sopenharmony_ci		} else if (acl_len != 0 && acl_len != -ENODATA) {
6438c2ecf20Sopenharmony_ci			ret = acl_len;
6448c2ecf20Sopenharmony_ci			mlog_errno(ret);
6458c2ecf20Sopenharmony_ci			return ret;
6468c2ecf20Sopenharmony_ci		}
6478c2ecf20Sopenharmony_ci	}
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	if (!(s_size + a_size))
6508c2ecf20Sopenharmony_ci		return ret;
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	/*
6538c2ecf20Sopenharmony_ci	 * The max space of security xattr taken inline is
6548c2ecf20Sopenharmony_ci	 * 256(name) + 80(value) + 16(entry) = 352 bytes,
6558c2ecf20Sopenharmony_ci	 * The max space of acl xattr taken inline is
6568c2ecf20Sopenharmony_ci	 * 80(value) + 16(entry) * 2(if directory) = 192 bytes,
6578c2ecf20Sopenharmony_ci	 * when blocksize = 512, may reserve one more cluser for
6588c2ecf20Sopenharmony_ci	 * xattr bucket, otherwise reserve one metadata block
6598c2ecf20Sopenharmony_ci	 * for them is ok.
6608c2ecf20Sopenharmony_ci	 * If this is a new directory with inline data,
6618c2ecf20Sopenharmony_ci	 * we choose to reserve the entire inline area for
6628c2ecf20Sopenharmony_ci	 * directory contents and force an external xattr block.
6638c2ecf20Sopenharmony_ci	 */
6648c2ecf20Sopenharmony_ci	if (dir->i_sb->s_blocksize == OCFS2_MIN_BLOCKSIZE ||
6658c2ecf20Sopenharmony_ci	    (S_ISDIR(mode) && ocfs2_supports_inline_data(osb)) ||
6668c2ecf20Sopenharmony_ci	    (s_size + a_size) > OCFS2_XATTR_FREE_IN_IBODY) {
6678c2ecf20Sopenharmony_ci		*want_meta = *want_meta + 1;
6688c2ecf20Sopenharmony_ci		*xattr_credits += OCFS2_XATTR_BLOCK_CREATE_CREDITS;
6698c2ecf20Sopenharmony_ci	}
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci	if (dir->i_sb->s_blocksize == OCFS2_MIN_BLOCKSIZE &&
6728c2ecf20Sopenharmony_ci	    (s_size + a_size) > OCFS2_XATTR_FREE_IN_BLOCK(dir)) {
6738c2ecf20Sopenharmony_ci		*want_clusters += 1;
6748c2ecf20Sopenharmony_ci		*xattr_credits += ocfs2_blocks_per_xattr_bucket(dir->i_sb);
6758c2ecf20Sopenharmony_ci	}
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci	/*
6788c2ecf20Sopenharmony_ci	 * reserve credits and clusters for xattrs which has large value
6798c2ecf20Sopenharmony_ci	 * and have to be set outside
6808c2ecf20Sopenharmony_ci	 */
6818c2ecf20Sopenharmony_ci	if (si->enable && si->value_len > OCFS2_XATTR_INLINE_SIZE) {
6828c2ecf20Sopenharmony_ci		new_clusters = ocfs2_clusters_for_bytes(dir->i_sb,
6838c2ecf20Sopenharmony_ci							si->value_len);
6848c2ecf20Sopenharmony_ci		*xattr_credits += ocfs2_clusters_to_blocks(dir->i_sb,
6858c2ecf20Sopenharmony_ci							   new_clusters);
6868c2ecf20Sopenharmony_ci		*want_clusters += new_clusters;
6878c2ecf20Sopenharmony_ci	}
6888c2ecf20Sopenharmony_ci	if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL &&
6898c2ecf20Sopenharmony_ci	    acl_len > OCFS2_XATTR_INLINE_SIZE) {
6908c2ecf20Sopenharmony_ci		/* for directory, it has DEFAULT and ACCESS two types of acls */
6918c2ecf20Sopenharmony_ci		new_clusters = (S_ISDIR(mode) ? 2 : 1) *
6928c2ecf20Sopenharmony_ci				ocfs2_clusters_for_bytes(dir->i_sb, acl_len);
6938c2ecf20Sopenharmony_ci		*xattr_credits += ocfs2_clusters_to_blocks(dir->i_sb,
6948c2ecf20Sopenharmony_ci							   new_clusters);
6958c2ecf20Sopenharmony_ci		*want_clusters += new_clusters;
6968c2ecf20Sopenharmony_ci	}
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	return ret;
6998c2ecf20Sopenharmony_ci}
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_cistatic int ocfs2_xattr_extend_allocation(struct inode *inode,
7028c2ecf20Sopenharmony_ci					 u32 clusters_to_add,
7038c2ecf20Sopenharmony_ci					 struct ocfs2_xattr_value_buf *vb,
7048c2ecf20Sopenharmony_ci					 struct ocfs2_xattr_set_ctxt *ctxt)
7058c2ecf20Sopenharmony_ci{
7068c2ecf20Sopenharmony_ci	int status = 0, credits;
7078c2ecf20Sopenharmony_ci	handle_t *handle = ctxt->handle;
7088c2ecf20Sopenharmony_ci	enum ocfs2_alloc_restarted why;
7098c2ecf20Sopenharmony_ci	u32 prev_clusters, logical_start = le32_to_cpu(vb->vb_xv->xr_clusters);
7108c2ecf20Sopenharmony_ci	struct ocfs2_extent_tree et;
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	ocfs2_init_xattr_value_extent_tree(&et, INODE_CACHE(inode), vb);
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	while (clusters_to_add) {
7158c2ecf20Sopenharmony_ci		trace_ocfs2_xattr_extend_allocation(clusters_to_add);
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci		status = vb->vb_access(handle, INODE_CACHE(inode), vb->vb_bh,
7188c2ecf20Sopenharmony_ci				       OCFS2_JOURNAL_ACCESS_WRITE);
7198c2ecf20Sopenharmony_ci		if (status < 0) {
7208c2ecf20Sopenharmony_ci			mlog_errno(status);
7218c2ecf20Sopenharmony_ci			break;
7228c2ecf20Sopenharmony_ci		}
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci		prev_clusters = le32_to_cpu(vb->vb_xv->xr_clusters);
7258c2ecf20Sopenharmony_ci		status = ocfs2_add_clusters_in_btree(handle,
7268c2ecf20Sopenharmony_ci						     &et,
7278c2ecf20Sopenharmony_ci						     &logical_start,
7288c2ecf20Sopenharmony_ci						     clusters_to_add,
7298c2ecf20Sopenharmony_ci						     0,
7308c2ecf20Sopenharmony_ci						     ctxt->data_ac,
7318c2ecf20Sopenharmony_ci						     ctxt->meta_ac,
7328c2ecf20Sopenharmony_ci						     &why);
7338c2ecf20Sopenharmony_ci		if ((status < 0) && (status != -EAGAIN)) {
7348c2ecf20Sopenharmony_ci			if (status != -ENOSPC)
7358c2ecf20Sopenharmony_ci				mlog_errno(status);
7368c2ecf20Sopenharmony_ci			break;
7378c2ecf20Sopenharmony_ci		}
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci		ocfs2_journal_dirty(handle, vb->vb_bh);
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci		clusters_to_add -= le32_to_cpu(vb->vb_xv->xr_clusters) -
7428c2ecf20Sopenharmony_ci					 prev_clusters;
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci		if (why != RESTART_NONE && clusters_to_add) {
7458c2ecf20Sopenharmony_ci			/*
7468c2ecf20Sopenharmony_ci			 * We can only fail in case the alloc file doesn't give
7478c2ecf20Sopenharmony_ci			 * up enough clusters.
7488c2ecf20Sopenharmony_ci			 */
7498c2ecf20Sopenharmony_ci			BUG_ON(why == RESTART_META);
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci			credits = ocfs2_calc_extend_credits(inode->i_sb,
7528c2ecf20Sopenharmony_ci							    &vb->vb_xv->xr_list);
7538c2ecf20Sopenharmony_ci			status = ocfs2_extend_trans(handle, credits);
7548c2ecf20Sopenharmony_ci			if (status < 0) {
7558c2ecf20Sopenharmony_ci				status = -ENOMEM;
7568c2ecf20Sopenharmony_ci				mlog_errno(status);
7578c2ecf20Sopenharmony_ci				break;
7588c2ecf20Sopenharmony_ci			}
7598c2ecf20Sopenharmony_ci		}
7608c2ecf20Sopenharmony_ci	}
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	return status;
7638c2ecf20Sopenharmony_ci}
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_cistatic int __ocfs2_remove_xattr_range(struct inode *inode,
7668c2ecf20Sopenharmony_ci				      struct ocfs2_xattr_value_buf *vb,
7678c2ecf20Sopenharmony_ci				      u32 cpos, u32 phys_cpos, u32 len,
7688c2ecf20Sopenharmony_ci				      unsigned int ext_flags,
7698c2ecf20Sopenharmony_ci				      struct ocfs2_xattr_set_ctxt *ctxt)
7708c2ecf20Sopenharmony_ci{
7718c2ecf20Sopenharmony_ci	int ret;
7728c2ecf20Sopenharmony_ci	u64 phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos);
7738c2ecf20Sopenharmony_ci	handle_t *handle = ctxt->handle;
7748c2ecf20Sopenharmony_ci	struct ocfs2_extent_tree et;
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	ocfs2_init_xattr_value_extent_tree(&et, INODE_CACHE(inode), vb);
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	ret = vb->vb_access(handle, INODE_CACHE(inode), vb->vb_bh,
7798c2ecf20Sopenharmony_ci			    OCFS2_JOURNAL_ACCESS_WRITE);
7808c2ecf20Sopenharmony_ci	if (ret) {
7818c2ecf20Sopenharmony_ci		mlog_errno(ret);
7828c2ecf20Sopenharmony_ci		goto out;
7838c2ecf20Sopenharmony_ci	}
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci	ret = ocfs2_remove_extent(handle, &et, cpos, len, ctxt->meta_ac,
7868c2ecf20Sopenharmony_ci				  &ctxt->dealloc);
7878c2ecf20Sopenharmony_ci	if (ret) {
7888c2ecf20Sopenharmony_ci		mlog_errno(ret);
7898c2ecf20Sopenharmony_ci		goto out;
7908c2ecf20Sopenharmony_ci	}
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci	le32_add_cpu(&vb->vb_xv->xr_clusters, -len);
7938c2ecf20Sopenharmony_ci	ocfs2_journal_dirty(handle, vb->vb_bh);
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci	if (ext_flags & OCFS2_EXT_REFCOUNTED)
7968c2ecf20Sopenharmony_ci		ret = ocfs2_decrease_refcount(inode, handle,
7978c2ecf20Sopenharmony_ci					ocfs2_blocks_to_clusters(inode->i_sb,
7988c2ecf20Sopenharmony_ci								 phys_blkno),
7998c2ecf20Sopenharmony_ci					len, ctxt->meta_ac, &ctxt->dealloc, 1);
8008c2ecf20Sopenharmony_ci	else
8018c2ecf20Sopenharmony_ci		ret = ocfs2_cache_cluster_dealloc(&ctxt->dealloc,
8028c2ecf20Sopenharmony_ci						  phys_blkno, len);
8038c2ecf20Sopenharmony_ci	if (ret)
8048c2ecf20Sopenharmony_ci		mlog_errno(ret);
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ciout:
8078c2ecf20Sopenharmony_ci	return ret;
8088c2ecf20Sopenharmony_ci}
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_cistatic int ocfs2_xattr_shrink_size(struct inode *inode,
8118c2ecf20Sopenharmony_ci				   u32 old_clusters,
8128c2ecf20Sopenharmony_ci				   u32 new_clusters,
8138c2ecf20Sopenharmony_ci				   struct ocfs2_xattr_value_buf *vb,
8148c2ecf20Sopenharmony_ci				   struct ocfs2_xattr_set_ctxt *ctxt)
8158c2ecf20Sopenharmony_ci{
8168c2ecf20Sopenharmony_ci	int ret = 0;
8178c2ecf20Sopenharmony_ci	unsigned int ext_flags;
8188c2ecf20Sopenharmony_ci	u32 trunc_len, cpos, phys_cpos, alloc_size;
8198c2ecf20Sopenharmony_ci	u64 block;
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci	if (old_clusters <= new_clusters)
8228c2ecf20Sopenharmony_ci		return 0;
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci	cpos = new_clusters;
8258c2ecf20Sopenharmony_ci	trunc_len = old_clusters - new_clusters;
8268c2ecf20Sopenharmony_ci	while (trunc_len) {
8278c2ecf20Sopenharmony_ci		ret = ocfs2_xattr_get_clusters(inode, cpos, &phys_cpos,
8288c2ecf20Sopenharmony_ci					       &alloc_size,
8298c2ecf20Sopenharmony_ci					       &vb->vb_xv->xr_list, &ext_flags);
8308c2ecf20Sopenharmony_ci		if (ret) {
8318c2ecf20Sopenharmony_ci			mlog_errno(ret);
8328c2ecf20Sopenharmony_ci			goto out;
8338c2ecf20Sopenharmony_ci		}
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci		if (alloc_size > trunc_len)
8368c2ecf20Sopenharmony_ci			alloc_size = trunc_len;
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci		ret = __ocfs2_remove_xattr_range(inode, vb, cpos,
8398c2ecf20Sopenharmony_ci						 phys_cpos, alloc_size,
8408c2ecf20Sopenharmony_ci						 ext_flags, ctxt);
8418c2ecf20Sopenharmony_ci		if (ret) {
8428c2ecf20Sopenharmony_ci			mlog_errno(ret);
8438c2ecf20Sopenharmony_ci			goto out;
8448c2ecf20Sopenharmony_ci		}
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci		block = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos);
8478c2ecf20Sopenharmony_ci		ocfs2_remove_xattr_clusters_from_cache(INODE_CACHE(inode),
8488c2ecf20Sopenharmony_ci						       block, alloc_size);
8498c2ecf20Sopenharmony_ci		cpos += alloc_size;
8508c2ecf20Sopenharmony_ci		trunc_len -= alloc_size;
8518c2ecf20Sopenharmony_ci	}
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ciout:
8548c2ecf20Sopenharmony_ci	return ret;
8558c2ecf20Sopenharmony_ci}
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_cistatic int ocfs2_xattr_value_truncate(struct inode *inode,
8588c2ecf20Sopenharmony_ci				      struct ocfs2_xattr_value_buf *vb,
8598c2ecf20Sopenharmony_ci				      int len,
8608c2ecf20Sopenharmony_ci				      struct ocfs2_xattr_set_ctxt *ctxt)
8618c2ecf20Sopenharmony_ci{
8628c2ecf20Sopenharmony_ci	int ret;
8638c2ecf20Sopenharmony_ci	u32 new_clusters = ocfs2_clusters_for_bytes(inode->i_sb, len);
8648c2ecf20Sopenharmony_ci	u32 old_clusters = le32_to_cpu(vb->vb_xv->xr_clusters);
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	if (new_clusters == old_clusters)
8678c2ecf20Sopenharmony_ci		return 0;
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci	if (new_clusters > old_clusters)
8708c2ecf20Sopenharmony_ci		ret = ocfs2_xattr_extend_allocation(inode,
8718c2ecf20Sopenharmony_ci						    new_clusters - old_clusters,
8728c2ecf20Sopenharmony_ci						    vb, ctxt);
8738c2ecf20Sopenharmony_ci	else
8748c2ecf20Sopenharmony_ci		ret = ocfs2_xattr_shrink_size(inode,
8758c2ecf20Sopenharmony_ci					      old_clusters, new_clusters,
8768c2ecf20Sopenharmony_ci					      vb, ctxt);
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	return ret;
8798c2ecf20Sopenharmony_ci}
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_cistatic int ocfs2_xattr_list_entry(struct super_block *sb,
8828c2ecf20Sopenharmony_ci				  char *buffer, size_t size,
8838c2ecf20Sopenharmony_ci				  size_t *result, int type,
8848c2ecf20Sopenharmony_ci				  const char *name, int name_len)
8858c2ecf20Sopenharmony_ci{
8868c2ecf20Sopenharmony_ci	char *p = buffer + *result;
8878c2ecf20Sopenharmony_ci	const char *prefix;
8888c2ecf20Sopenharmony_ci	int prefix_len;
8898c2ecf20Sopenharmony_ci	int total_len;
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci	switch(type) {
8928c2ecf20Sopenharmony_ci	case OCFS2_XATTR_INDEX_USER:
8938c2ecf20Sopenharmony_ci		if (OCFS2_SB(sb)->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR)
8948c2ecf20Sopenharmony_ci			return 0;
8958c2ecf20Sopenharmony_ci		break;
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	case OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS:
8988c2ecf20Sopenharmony_ci	case OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT:
8998c2ecf20Sopenharmony_ci		if (!(sb->s_flags & SB_POSIXACL))
9008c2ecf20Sopenharmony_ci			return 0;
9018c2ecf20Sopenharmony_ci		break;
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	case OCFS2_XATTR_INDEX_TRUSTED:
9048c2ecf20Sopenharmony_ci		if (!capable(CAP_SYS_ADMIN))
9058c2ecf20Sopenharmony_ci			return 0;
9068c2ecf20Sopenharmony_ci		break;
9078c2ecf20Sopenharmony_ci	}
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	prefix = ocfs2_xattr_prefix(type);
9108c2ecf20Sopenharmony_ci	if (!prefix)
9118c2ecf20Sopenharmony_ci		return 0;
9128c2ecf20Sopenharmony_ci	prefix_len = strlen(prefix);
9138c2ecf20Sopenharmony_ci	total_len = prefix_len + name_len + 1;
9148c2ecf20Sopenharmony_ci	*result += total_len;
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	/* we are just looking for how big our buffer needs to be */
9178c2ecf20Sopenharmony_ci	if (!size)
9188c2ecf20Sopenharmony_ci		return 0;
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci	if (*result > size)
9218c2ecf20Sopenharmony_ci		return -ERANGE;
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci	memcpy(p, prefix, prefix_len);
9248c2ecf20Sopenharmony_ci	memcpy(p + prefix_len, name, name_len);
9258c2ecf20Sopenharmony_ci	p[prefix_len + name_len] = '\0';
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci	return 0;
9288c2ecf20Sopenharmony_ci}
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_cistatic int ocfs2_xattr_list_entries(struct inode *inode,
9318c2ecf20Sopenharmony_ci				    struct ocfs2_xattr_header *header,
9328c2ecf20Sopenharmony_ci				    char *buffer, size_t buffer_size)
9338c2ecf20Sopenharmony_ci{
9348c2ecf20Sopenharmony_ci	size_t result = 0;
9358c2ecf20Sopenharmony_ci	int i, type, ret;
9368c2ecf20Sopenharmony_ci	const char *name;
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci	for (i = 0 ; i < le16_to_cpu(header->xh_count); i++) {
9398c2ecf20Sopenharmony_ci		struct ocfs2_xattr_entry *entry = &header->xh_entries[i];
9408c2ecf20Sopenharmony_ci		type = ocfs2_xattr_get_type(entry);
9418c2ecf20Sopenharmony_ci		name = (const char *)header +
9428c2ecf20Sopenharmony_ci			le16_to_cpu(entry->xe_name_offset);
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ci		ret = ocfs2_xattr_list_entry(inode->i_sb,
9458c2ecf20Sopenharmony_ci					     buffer, buffer_size,
9468c2ecf20Sopenharmony_ci					     &result, type, name,
9478c2ecf20Sopenharmony_ci					     entry->xe_name_len);
9488c2ecf20Sopenharmony_ci		if (ret)
9498c2ecf20Sopenharmony_ci			return ret;
9508c2ecf20Sopenharmony_ci	}
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci	return result;
9538c2ecf20Sopenharmony_ci}
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ciint ocfs2_has_inline_xattr_value_outside(struct inode *inode,
9568c2ecf20Sopenharmony_ci					 struct ocfs2_dinode *di)
9578c2ecf20Sopenharmony_ci{
9588c2ecf20Sopenharmony_ci	struct ocfs2_xattr_header *xh;
9598c2ecf20Sopenharmony_ci	int i;
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	xh = (struct ocfs2_xattr_header *)
9628c2ecf20Sopenharmony_ci		 ((void *)di + inode->i_sb->s_blocksize -
9638c2ecf20Sopenharmony_ci		 le16_to_cpu(di->i_xattr_inline_size));
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	for (i = 0; i < le16_to_cpu(xh->xh_count); i++)
9668c2ecf20Sopenharmony_ci		if (!ocfs2_xattr_is_local(&xh->xh_entries[i]))
9678c2ecf20Sopenharmony_ci			return 1;
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci	return 0;
9708c2ecf20Sopenharmony_ci}
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_cistatic int ocfs2_xattr_ibody_list(struct inode *inode,
9738c2ecf20Sopenharmony_ci				  struct ocfs2_dinode *di,
9748c2ecf20Sopenharmony_ci				  char *buffer,
9758c2ecf20Sopenharmony_ci				  size_t buffer_size)
9768c2ecf20Sopenharmony_ci{
9778c2ecf20Sopenharmony_ci	struct ocfs2_xattr_header *header = NULL;
9788c2ecf20Sopenharmony_ci	struct ocfs2_inode_info *oi = OCFS2_I(inode);
9798c2ecf20Sopenharmony_ci	int ret = 0;
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL))
9828c2ecf20Sopenharmony_ci		return ret;
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ci	header = (struct ocfs2_xattr_header *)
9858c2ecf20Sopenharmony_ci		 ((void *)di + inode->i_sb->s_blocksize -
9868c2ecf20Sopenharmony_ci		 le16_to_cpu(di->i_xattr_inline_size));
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci	ret = ocfs2_xattr_list_entries(inode, header, buffer, buffer_size);
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci	return ret;
9918c2ecf20Sopenharmony_ci}
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_cistatic int ocfs2_xattr_block_list(struct inode *inode,
9948c2ecf20Sopenharmony_ci				  struct ocfs2_dinode *di,
9958c2ecf20Sopenharmony_ci				  char *buffer,
9968c2ecf20Sopenharmony_ci				  size_t buffer_size)
9978c2ecf20Sopenharmony_ci{
9988c2ecf20Sopenharmony_ci	struct buffer_head *blk_bh = NULL;
9998c2ecf20Sopenharmony_ci	struct ocfs2_xattr_block *xb;
10008c2ecf20Sopenharmony_ci	int ret = 0;
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci	if (!di->i_xattr_loc)
10038c2ecf20Sopenharmony_ci		return ret;
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci	ret = ocfs2_read_xattr_block(inode, le64_to_cpu(di->i_xattr_loc),
10068c2ecf20Sopenharmony_ci				     &blk_bh);
10078c2ecf20Sopenharmony_ci	if (ret < 0) {
10088c2ecf20Sopenharmony_ci		mlog_errno(ret);
10098c2ecf20Sopenharmony_ci		return ret;
10108c2ecf20Sopenharmony_ci	}
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci	xb = (struct ocfs2_xattr_block *)blk_bh->b_data;
10138c2ecf20Sopenharmony_ci	if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) {
10148c2ecf20Sopenharmony_ci		struct ocfs2_xattr_header *header = &xb->xb_attrs.xb_header;
10158c2ecf20Sopenharmony_ci		ret = ocfs2_xattr_list_entries(inode, header,
10168c2ecf20Sopenharmony_ci					       buffer, buffer_size);
10178c2ecf20Sopenharmony_ci	} else
10188c2ecf20Sopenharmony_ci		ret = ocfs2_xattr_tree_list_index_block(inode, blk_bh,
10198c2ecf20Sopenharmony_ci						   buffer, buffer_size);
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ci	brelse(blk_bh);
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_ci	return ret;
10248c2ecf20Sopenharmony_ci}
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_cissize_t ocfs2_listxattr(struct dentry *dentry,
10278c2ecf20Sopenharmony_ci			char *buffer,
10288c2ecf20Sopenharmony_ci			size_t size)
10298c2ecf20Sopenharmony_ci{
10308c2ecf20Sopenharmony_ci	int ret = 0, i_ret = 0, b_ret = 0;
10318c2ecf20Sopenharmony_ci	struct buffer_head *di_bh = NULL;
10328c2ecf20Sopenharmony_ci	struct ocfs2_dinode *di = NULL;
10338c2ecf20Sopenharmony_ci	struct ocfs2_inode_info *oi = OCFS2_I(d_inode(dentry));
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	if (!ocfs2_supports_xattr(OCFS2_SB(dentry->d_sb)))
10368c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci	if (!(oi->ip_dyn_features & OCFS2_HAS_XATTR_FL))
10398c2ecf20Sopenharmony_ci		return ret;
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci	ret = ocfs2_inode_lock(d_inode(dentry), &di_bh, 0);
10428c2ecf20Sopenharmony_ci	if (ret < 0) {
10438c2ecf20Sopenharmony_ci		mlog_errno(ret);
10448c2ecf20Sopenharmony_ci		return ret;
10458c2ecf20Sopenharmony_ci	}
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci	di = (struct ocfs2_dinode *)di_bh->b_data;
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	down_read(&oi->ip_xattr_sem);
10508c2ecf20Sopenharmony_ci	i_ret = ocfs2_xattr_ibody_list(d_inode(dentry), di, buffer, size);
10518c2ecf20Sopenharmony_ci	if (i_ret < 0)
10528c2ecf20Sopenharmony_ci		b_ret = 0;
10538c2ecf20Sopenharmony_ci	else {
10548c2ecf20Sopenharmony_ci		if (buffer) {
10558c2ecf20Sopenharmony_ci			buffer += i_ret;
10568c2ecf20Sopenharmony_ci			size -= i_ret;
10578c2ecf20Sopenharmony_ci		}
10588c2ecf20Sopenharmony_ci		b_ret = ocfs2_xattr_block_list(d_inode(dentry), di,
10598c2ecf20Sopenharmony_ci					       buffer, size);
10608c2ecf20Sopenharmony_ci		if (b_ret < 0)
10618c2ecf20Sopenharmony_ci			i_ret = 0;
10628c2ecf20Sopenharmony_ci	}
10638c2ecf20Sopenharmony_ci	up_read(&oi->ip_xattr_sem);
10648c2ecf20Sopenharmony_ci	ocfs2_inode_unlock(d_inode(dentry), 0);
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci	brelse(di_bh);
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci	return i_ret + b_ret;
10698c2ecf20Sopenharmony_ci}
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_cistatic int ocfs2_xattr_find_entry(int name_index,
10728c2ecf20Sopenharmony_ci				  const char *name,
10738c2ecf20Sopenharmony_ci				  struct ocfs2_xattr_search *xs)
10748c2ecf20Sopenharmony_ci{
10758c2ecf20Sopenharmony_ci	struct ocfs2_xattr_entry *entry;
10768c2ecf20Sopenharmony_ci	size_t name_len;
10778c2ecf20Sopenharmony_ci	int i, cmp = 1;
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci	if (name == NULL)
10808c2ecf20Sopenharmony_ci		return -EINVAL;
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_ci	name_len = strlen(name);
10838c2ecf20Sopenharmony_ci	entry = xs->here;
10848c2ecf20Sopenharmony_ci	for (i = 0; i < le16_to_cpu(xs->header->xh_count); i++) {
10858c2ecf20Sopenharmony_ci		cmp = name_index - ocfs2_xattr_get_type(entry);
10868c2ecf20Sopenharmony_ci		if (!cmp)
10878c2ecf20Sopenharmony_ci			cmp = name_len - entry->xe_name_len;
10888c2ecf20Sopenharmony_ci		if (!cmp)
10898c2ecf20Sopenharmony_ci			cmp = memcmp(name, (xs->base +
10908c2ecf20Sopenharmony_ci				     le16_to_cpu(entry->xe_name_offset)),
10918c2ecf20Sopenharmony_ci				     name_len);
10928c2ecf20Sopenharmony_ci		if (cmp == 0)
10938c2ecf20Sopenharmony_ci			break;
10948c2ecf20Sopenharmony_ci		entry += 1;
10958c2ecf20Sopenharmony_ci	}
10968c2ecf20Sopenharmony_ci	xs->here = entry;
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci	return cmp ? -ENODATA : 0;
10998c2ecf20Sopenharmony_ci}
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_cistatic int ocfs2_xattr_get_value_outside(struct inode *inode,
11028c2ecf20Sopenharmony_ci					 struct ocfs2_xattr_value_root *xv,
11038c2ecf20Sopenharmony_ci					 void *buffer,
11048c2ecf20Sopenharmony_ci					 size_t len)
11058c2ecf20Sopenharmony_ci{
11068c2ecf20Sopenharmony_ci	u32 cpos, p_cluster, num_clusters, bpc, clusters;
11078c2ecf20Sopenharmony_ci	u64 blkno;
11088c2ecf20Sopenharmony_ci	int i, ret = 0;
11098c2ecf20Sopenharmony_ci	size_t cplen, blocksize;
11108c2ecf20Sopenharmony_ci	struct buffer_head *bh = NULL;
11118c2ecf20Sopenharmony_ci	struct ocfs2_extent_list *el;
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_ci	el = &xv->xr_list;
11148c2ecf20Sopenharmony_ci	clusters = le32_to_cpu(xv->xr_clusters);
11158c2ecf20Sopenharmony_ci	bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1);
11168c2ecf20Sopenharmony_ci	blocksize = inode->i_sb->s_blocksize;
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci	cpos = 0;
11198c2ecf20Sopenharmony_ci	while (cpos < clusters) {
11208c2ecf20Sopenharmony_ci		ret = ocfs2_xattr_get_clusters(inode, cpos, &p_cluster,
11218c2ecf20Sopenharmony_ci					       &num_clusters, el, NULL);
11228c2ecf20Sopenharmony_ci		if (ret) {
11238c2ecf20Sopenharmony_ci			mlog_errno(ret);
11248c2ecf20Sopenharmony_ci			goto out;
11258c2ecf20Sopenharmony_ci		}
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ci		blkno = ocfs2_clusters_to_blocks(inode->i_sb, p_cluster);
11288c2ecf20Sopenharmony_ci		/* Copy ocfs2_xattr_value */
11298c2ecf20Sopenharmony_ci		for (i = 0; i < num_clusters * bpc; i++, blkno++) {
11308c2ecf20Sopenharmony_ci			ret = ocfs2_read_block(INODE_CACHE(inode), blkno,
11318c2ecf20Sopenharmony_ci					       &bh, NULL);
11328c2ecf20Sopenharmony_ci			if (ret) {
11338c2ecf20Sopenharmony_ci				mlog_errno(ret);
11348c2ecf20Sopenharmony_ci				goto out;
11358c2ecf20Sopenharmony_ci			}
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_ci			cplen = len >= blocksize ? blocksize : len;
11388c2ecf20Sopenharmony_ci			memcpy(buffer, bh->b_data, cplen);
11398c2ecf20Sopenharmony_ci			len -= cplen;
11408c2ecf20Sopenharmony_ci			buffer += cplen;
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_ci			brelse(bh);
11438c2ecf20Sopenharmony_ci			bh = NULL;
11448c2ecf20Sopenharmony_ci			if (len == 0)
11458c2ecf20Sopenharmony_ci				break;
11468c2ecf20Sopenharmony_ci		}
11478c2ecf20Sopenharmony_ci		cpos += num_clusters;
11488c2ecf20Sopenharmony_ci	}
11498c2ecf20Sopenharmony_ciout:
11508c2ecf20Sopenharmony_ci	return ret;
11518c2ecf20Sopenharmony_ci}
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_cistatic int ocfs2_xattr_ibody_get(struct inode *inode,
11548c2ecf20Sopenharmony_ci				 int name_index,
11558c2ecf20Sopenharmony_ci				 const char *name,
11568c2ecf20Sopenharmony_ci				 void *buffer,
11578c2ecf20Sopenharmony_ci				 size_t buffer_size,
11588c2ecf20Sopenharmony_ci				 struct ocfs2_xattr_search *xs)
11598c2ecf20Sopenharmony_ci{
11608c2ecf20Sopenharmony_ci	struct ocfs2_inode_info *oi = OCFS2_I(inode);
11618c2ecf20Sopenharmony_ci	struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data;
11628c2ecf20Sopenharmony_ci	struct ocfs2_xattr_value_root *xv;
11638c2ecf20Sopenharmony_ci	size_t size;
11648c2ecf20Sopenharmony_ci	int ret = 0;
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_ci	if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL))
11678c2ecf20Sopenharmony_ci		return -ENODATA;
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_ci	xs->end = (void *)di + inode->i_sb->s_blocksize;
11708c2ecf20Sopenharmony_ci	xs->header = (struct ocfs2_xattr_header *)
11718c2ecf20Sopenharmony_ci			(xs->end - le16_to_cpu(di->i_xattr_inline_size));
11728c2ecf20Sopenharmony_ci	xs->base = (void *)xs->header;
11738c2ecf20Sopenharmony_ci	xs->here = xs->header->xh_entries;
11748c2ecf20Sopenharmony_ci
11758c2ecf20Sopenharmony_ci	ret = ocfs2_xattr_find_entry(name_index, name, xs);
11768c2ecf20Sopenharmony_ci	if (ret)
11778c2ecf20Sopenharmony_ci		return ret;
11788c2ecf20Sopenharmony_ci	size = le64_to_cpu(xs->here->xe_value_size);
11798c2ecf20Sopenharmony_ci	if (buffer) {
11808c2ecf20Sopenharmony_ci		if (size > buffer_size)
11818c2ecf20Sopenharmony_ci			return -ERANGE;
11828c2ecf20Sopenharmony_ci		if (ocfs2_xattr_is_local(xs->here)) {
11838c2ecf20Sopenharmony_ci			memcpy(buffer, (void *)xs->base +
11848c2ecf20Sopenharmony_ci			       le16_to_cpu(xs->here->xe_name_offset) +
11858c2ecf20Sopenharmony_ci			       OCFS2_XATTR_SIZE(xs->here->xe_name_len), size);
11868c2ecf20Sopenharmony_ci		} else {
11878c2ecf20Sopenharmony_ci			xv = (struct ocfs2_xattr_value_root *)
11888c2ecf20Sopenharmony_ci				(xs->base + le16_to_cpu(
11898c2ecf20Sopenharmony_ci				 xs->here->xe_name_offset) +
11908c2ecf20Sopenharmony_ci				OCFS2_XATTR_SIZE(xs->here->xe_name_len));
11918c2ecf20Sopenharmony_ci			ret = ocfs2_xattr_get_value_outside(inode, xv,
11928c2ecf20Sopenharmony_ci							    buffer, size);
11938c2ecf20Sopenharmony_ci			if (ret < 0) {
11948c2ecf20Sopenharmony_ci				mlog_errno(ret);
11958c2ecf20Sopenharmony_ci				return ret;
11968c2ecf20Sopenharmony_ci			}
11978c2ecf20Sopenharmony_ci		}
11988c2ecf20Sopenharmony_ci	}
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci	return size;
12018c2ecf20Sopenharmony_ci}
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_cistatic int ocfs2_xattr_block_get(struct inode *inode,
12048c2ecf20Sopenharmony_ci				 int name_index,
12058c2ecf20Sopenharmony_ci				 const char *name,
12068c2ecf20Sopenharmony_ci				 void *buffer,
12078c2ecf20Sopenharmony_ci				 size_t buffer_size,
12088c2ecf20Sopenharmony_ci				 struct ocfs2_xattr_search *xs)
12098c2ecf20Sopenharmony_ci{
12108c2ecf20Sopenharmony_ci	struct ocfs2_xattr_block *xb;
12118c2ecf20Sopenharmony_ci	struct ocfs2_xattr_value_root *xv;
12128c2ecf20Sopenharmony_ci	size_t size;
12138c2ecf20Sopenharmony_ci	int ret = -ENODATA, name_offset, name_len, i;
12148c2ecf20Sopenharmony_ci	int block_off;
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci	xs->bucket = ocfs2_xattr_bucket_new(inode);
12178c2ecf20Sopenharmony_ci	if (!xs->bucket) {
12188c2ecf20Sopenharmony_ci		ret = -ENOMEM;
12198c2ecf20Sopenharmony_ci		mlog_errno(ret);
12208c2ecf20Sopenharmony_ci		goto cleanup;
12218c2ecf20Sopenharmony_ci	}
12228c2ecf20Sopenharmony_ci
12238c2ecf20Sopenharmony_ci	ret = ocfs2_xattr_block_find(inode, name_index, name, xs);
12248c2ecf20Sopenharmony_ci	if (ret) {
12258c2ecf20Sopenharmony_ci		mlog_errno(ret);
12268c2ecf20Sopenharmony_ci		goto cleanup;
12278c2ecf20Sopenharmony_ci	}
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_ci	if (xs->not_found) {
12308c2ecf20Sopenharmony_ci		ret = -ENODATA;
12318c2ecf20Sopenharmony_ci		goto cleanup;
12328c2ecf20Sopenharmony_ci	}
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci	xb = (struct ocfs2_xattr_block *)xs->xattr_bh->b_data;
12358c2ecf20Sopenharmony_ci	size = le64_to_cpu(xs->here->xe_value_size);
12368c2ecf20Sopenharmony_ci	if (buffer) {
12378c2ecf20Sopenharmony_ci		ret = -ERANGE;
12388c2ecf20Sopenharmony_ci		if (size > buffer_size)
12398c2ecf20Sopenharmony_ci			goto cleanup;
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_ci		name_offset = le16_to_cpu(xs->here->xe_name_offset);
12428c2ecf20Sopenharmony_ci		name_len = OCFS2_XATTR_SIZE(xs->here->xe_name_len);
12438c2ecf20Sopenharmony_ci		i = xs->here - xs->header->xh_entries;
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_ci		if (le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED) {
12468c2ecf20Sopenharmony_ci			ret = ocfs2_xattr_bucket_get_name_value(inode->i_sb,
12478c2ecf20Sopenharmony_ci								bucket_xh(xs->bucket),
12488c2ecf20Sopenharmony_ci								i,
12498c2ecf20Sopenharmony_ci								&block_off,
12508c2ecf20Sopenharmony_ci								&name_offset);
12518c2ecf20Sopenharmony_ci			if (ret) {
12528c2ecf20Sopenharmony_ci				mlog_errno(ret);
12538c2ecf20Sopenharmony_ci				goto cleanup;
12548c2ecf20Sopenharmony_ci			}
12558c2ecf20Sopenharmony_ci			xs->base = bucket_block(xs->bucket, block_off);
12568c2ecf20Sopenharmony_ci		}
12578c2ecf20Sopenharmony_ci		if (ocfs2_xattr_is_local(xs->here)) {
12588c2ecf20Sopenharmony_ci			memcpy(buffer, (void *)xs->base +
12598c2ecf20Sopenharmony_ci			       name_offset + name_len, size);
12608c2ecf20Sopenharmony_ci		} else {
12618c2ecf20Sopenharmony_ci			xv = (struct ocfs2_xattr_value_root *)
12628c2ecf20Sopenharmony_ci				(xs->base + name_offset + name_len);
12638c2ecf20Sopenharmony_ci			ret = ocfs2_xattr_get_value_outside(inode, xv,
12648c2ecf20Sopenharmony_ci							    buffer, size);
12658c2ecf20Sopenharmony_ci			if (ret < 0) {
12668c2ecf20Sopenharmony_ci				mlog_errno(ret);
12678c2ecf20Sopenharmony_ci				goto cleanup;
12688c2ecf20Sopenharmony_ci			}
12698c2ecf20Sopenharmony_ci		}
12708c2ecf20Sopenharmony_ci	}
12718c2ecf20Sopenharmony_ci	ret = size;
12728c2ecf20Sopenharmony_cicleanup:
12738c2ecf20Sopenharmony_ci	ocfs2_xattr_bucket_free(xs->bucket);
12748c2ecf20Sopenharmony_ci
12758c2ecf20Sopenharmony_ci	brelse(xs->xattr_bh);
12768c2ecf20Sopenharmony_ci	xs->xattr_bh = NULL;
12778c2ecf20Sopenharmony_ci	return ret;
12788c2ecf20Sopenharmony_ci}
12798c2ecf20Sopenharmony_ci
12808c2ecf20Sopenharmony_ciint ocfs2_xattr_get_nolock(struct inode *inode,
12818c2ecf20Sopenharmony_ci			   struct buffer_head *di_bh,
12828c2ecf20Sopenharmony_ci			   int name_index,
12838c2ecf20Sopenharmony_ci			   const char *name,
12848c2ecf20Sopenharmony_ci			   void *buffer,
12858c2ecf20Sopenharmony_ci			   size_t buffer_size)
12868c2ecf20Sopenharmony_ci{
12878c2ecf20Sopenharmony_ci	int ret;
12888c2ecf20Sopenharmony_ci	struct ocfs2_dinode *di = NULL;
12898c2ecf20Sopenharmony_ci	struct ocfs2_inode_info *oi = OCFS2_I(inode);
12908c2ecf20Sopenharmony_ci	struct ocfs2_xattr_search xis = {
12918c2ecf20Sopenharmony_ci		.not_found = -ENODATA,
12928c2ecf20Sopenharmony_ci	};
12938c2ecf20Sopenharmony_ci	struct ocfs2_xattr_search xbs = {
12948c2ecf20Sopenharmony_ci		.not_found = -ENODATA,
12958c2ecf20Sopenharmony_ci	};
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_ci	if (!ocfs2_supports_xattr(OCFS2_SB(inode->i_sb)))
12988c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci	if (!(oi->ip_dyn_features & OCFS2_HAS_XATTR_FL))
13018c2ecf20Sopenharmony_ci		return -ENODATA;
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci	xis.inode_bh = xbs.inode_bh = di_bh;
13048c2ecf20Sopenharmony_ci	di = (struct ocfs2_dinode *)di_bh->b_data;
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_ci	ret = ocfs2_xattr_ibody_get(inode, name_index, name, buffer,
13078c2ecf20Sopenharmony_ci				    buffer_size, &xis);
13088c2ecf20Sopenharmony_ci	if (ret == -ENODATA && di->i_xattr_loc)
13098c2ecf20Sopenharmony_ci		ret = ocfs2_xattr_block_get(inode, name_index, name, buffer,
13108c2ecf20Sopenharmony_ci					    buffer_size, &xbs);
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci	return ret;
13138c2ecf20Sopenharmony_ci}
13148c2ecf20Sopenharmony_ci
13158c2ecf20Sopenharmony_ci/* ocfs2_xattr_get()
13168c2ecf20Sopenharmony_ci *
13178c2ecf20Sopenharmony_ci * Copy an extended attribute into the buffer provided.
13188c2ecf20Sopenharmony_ci * Buffer is NULL to compute the size of buffer required.
13198c2ecf20Sopenharmony_ci */
13208c2ecf20Sopenharmony_cistatic int ocfs2_xattr_get(struct inode *inode,
13218c2ecf20Sopenharmony_ci			   int name_index,
13228c2ecf20Sopenharmony_ci			   const char *name,
13238c2ecf20Sopenharmony_ci			   void *buffer,
13248c2ecf20Sopenharmony_ci			   size_t buffer_size)
13258c2ecf20Sopenharmony_ci{
13268c2ecf20Sopenharmony_ci	int ret, had_lock;
13278c2ecf20Sopenharmony_ci	struct buffer_head *di_bh = NULL;
13288c2ecf20Sopenharmony_ci	struct ocfs2_lock_holder oh;
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_ci	had_lock = ocfs2_inode_lock_tracker(inode, &di_bh, 0, &oh);
13318c2ecf20Sopenharmony_ci	if (had_lock < 0) {
13328c2ecf20Sopenharmony_ci		mlog_errno(had_lock);
13338c2ecf20Sopenharmony_ci		return had_lock;
13348c2ecf20Sopenharmony_ci	}
13358c2ecf20Sopenharmony_ci	down_read(&OCFS2_I(inode)->ip_xattr_sem);
13368c2ecf20Sopenharmony_ci	ret = ocfs2_xattr_get_nolock(inode, di_bh, name_index,
13378c2ecf20Sopenharmony_ci				     name, buffer, buffer_size);
13388c2ecf20Sopenharmony_ci	up_read(&OCFS2_I(inode)->ip_xattr_sem);
13398c2ecf20Sopenharmony_ci
13408c2ecf20Sopenharmony_ci	ocfs2_inode_unlock_tracker(inode, 0, &oh, had_lock);
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ci	brelse(di_bh);
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci	return ret;
13458c2ecf20Sopenharmony_ci}
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_cistatic int __ocfs2_xattr_set_value_outside(struct inode *inode,
13488c2ecf20Sopenharmony_ci					   handle_t *handle,
13498c2ecf20Sopenharmony_ci					   struct ocfs2_xattr_value_buf *vb,
13508c2ecf20Sopenharmony_ci					   const void *value,
13518c2ecf20Sopenharmony_ci					   int value_len)
13528c2ecf20Sopenharmony_ci{
13538c2ecf20Sopenharmony_ci	int ret = 0, i, cp_len;
13548c2ecf20Sopenharmony_ci	u16 blocksize = inode->i_sb->s_blocksize;
13558c2ecf20Sopenharmony_ci	u32 p_cluster, num_clusters;
13568c2ecf20Sopenharmony_ci	u32 cpos = 0, bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1);
13578c2ecf20Sopenharmony_ci	u32 clusters = ocfs2_clusters_for_bytes(inode->i_sb, value_len);
13588c2ecf20Sopenharmony_ci	u64 blkno;
13598c2ecf20Sopenharmony_ci	struct buffer_head *bh = NULL;
13608c2ecf20Sopenharmony_ci	unsigned int ext_flags;
13618c2ecf20Sopenharmony_ci	struct ocfs2_xattr_value_root *xv = vb->vb_xv;
13628c2ecf20Sopenharmony_ci
13638c2ecf20Sopenharmony_ci	BUG_ON(clusters > le32_to_cpu(xv->xr_clusters));
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci	while (cpos < clusters) {
13668c2ecf20Sopenharmony_ci		ret = ocfs2_xattr_get_clusters(inode, cpos, &p_cluster,
13678c2ecf20Sopenharmony_ci					       &num_clusters, &xv->xr_list,
13688c2ecf20Sopenharmony_ci					       &ext_flags);
13698c2ecf20Sopenharmony_ci		if (ret) {
13708c2ecf20Sopenharmony_ci			mlog_errno(ret);
13718c2ecf20Sopenharmony_ci			goto out;
13728c2ecf20Sopenharmony_ci		}
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_ci		BUG_ON(ext_flags & OCFS2_EXT_REFCOUNTED);
13758c2ecf20Sopenharmony_ci
13768c2ecf20Sopenharmony_ci		blkno = ocfs2_clusters_to_blocks(inode->i_sb, p_cluster);
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci		for (i = 0; i < num_clusters * bpc; i++, blkno++) {
13798c2ecf20Sopenharmony_ci			ret = ocfs2_read_block(INODE_CACHE(inode), blkno,
13808c2ecf20Sopenharmony_ci					       &bh, NULL);
13818c2ecf20Sopenharmony_ci			if (ret) {
13828c2ecf20Sopenharmony_ci				mlog_errno(ret);
13838c2ecf20Sopenharmony_ci				goto out;
13848c2ecf20Sopenharmony_ci			}
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ci			ret = ocfs2_journal_access(handle,
13878c2ecf20Sopenharmony_ci						   INODE_CACHE(inode),
13888c2ecf20Sopenharmony_ci						   bh,
13898c2ecf20Sopenharmony_ci						   OCFS2_JOURNAL_ACCESS_WRITE);
13908c2ecf20Sopenharmony_ci			if (ret < 0) {
13918c2ecf20Sopenharmony_ci				mlog_errno(ret);
13928c2ecf20Sopenharmony_ci				goto out;
13938c2ecf20Sopenharmony_ci			}
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_ci			cp_len = value_len > blocksize ? blocksize : value_len;
13968c2ecf20Sopenharmony_ci			memcpy(bh->b_data, value, cp_len);
13978c2ecf20Sopenharmony_ci			value_len -= cp_len;
13988c2ecf20Sopenharmony_ci			value += cp_len;
13998c2ecf20Sopenharmony_ci			if (cp_len < blocksize)
14008c2ecf20Sopenharmony_ci				memset(bh->b_data + cp_len, 0,
14018c2ecf20Sopenharmony_ci				       blocksize - cp_len);
14028c2ecf20Sopenharmony_ci
14038c2ecf20Sopenharmony_ci			ocfs2_journal_dirty(handle, bh);
14048c2ecf20Sopenharmony_ci			brelse(bh);
14058c2ecf20Sopenharmony_ci			bh = NULL;
14068c2ecf20Sopenharmony_ci
14078c2ecf20Sopenharmony_ci			/*
14088c2ecf20Sopenharmony_ci			 * XXX: do we need to empty all the following
14098c2ecf20Sopenharmony_ci			 * blocks in this cluster?
14108c2ecf20Sopenharmony_ci			 */
14118c2ecf20Sopenharmony_ci			if (!value_len)
14128c2ecf20Sopenharmony_ci				break;
14138c2ecf20Sopenharmony_ci		}
14148c2ecf20Sopenharmony_ci		cpos += num_clusters;
14158c2ecf20Sopenharmony_ci	}
14168c2ecf20Sopenharmony_ciout:
14178c2ecf20Sopenharmony_ci	brelse(bh);
14188c2ecf20Sopenharmony_ci
14198c2ecf20Sopenharmony_ci	return ret;
14208c2ecf20Sopenharmony_ci}
14218c2ecf20Sopenharmony_ci
14228c2ecf20Sopenharmony_cistatic int ocfs2_xa_check_space_helper(int needed_space, int free_start,
14238c2ecf20Sopenharmony_ci				       int num_entries)
14248c2ecf20Sopenharmony_ci{
14258c2ecf20Sopenharmony_ci	int free_space;
14268c2ecf20Sopenharmony_ci
14278c2ecf20Sopenharmony_ci	if (!needed_space)
14288c2ecf20Sopenharmony_ci		return 0;
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_ci	free_space = free_start -
14318c2ecf20Sopenharmony_ci		sizeof(struct ocfs2_xattr_header) -
14328c2ecf20Sopenharmony_ci		(num_entries * sizeof(struct ocfs2_xattr_entry)) -
14338c2ecf20Sopenharmony_ci		OCFS2_XATTR_HEADER_GAP;
14348c2ecf20Sopenharmony_ci	if (free_space < 0)
14358c2ecf20Sopenharmony_ci		return -EIO;
14368c2ecf20Sopenharmony_ci	if (free_space < needed_space)
14378c2ecf20Sopenharmony_ci		return -ENOSPC;
14388c2ecf20Sopenharmony_ci
14398c2ecf20Sopenharmony_ci	return 0;
14408c2ecf20Sopenharmony_ci}
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_cistatic int ocfs2_xa_journal_access(handle_t *handle, struct ocfs2_xa_loc *loc,
14438c2ecf20Sopenharmony_ci				   int type)
14448c2ecf20Sopenharmony_ci{
14458c2ecf20Sopenharmony_ci	return loc->xl_ops->xlo_journal_access(handle, loc, type);
14468c2ecf20Sopenharmony_ci}
14478c2ecf20Sopenharmony_ci
14488c2ecf20Sopenharmony_cistatic void ocfs2_xa_journal_dirty(handle_t *handle, struct ocfs2_xa_loc *loc)
14498c2ecf20Sopenharmony_ci{
14508c2ecf20Sopenharmony_ci	loc->xl_ops->xlo_journal_dirty(handle, loc);
14518c2ecf20Sopenharmony_ci}
14528c2ecf20Sopenharmony_ci
14538c2ecf20Sopenharmony_ci/* Give a pointer into the storage for the given offset */
14548c2ecf20Sopenharmony_cistatic void *ocfs2_xa_offset_pointer(struct ocfs2_xa_loc *loc, int offset)
14558c2ecf20Sopenharmony_ci{
14568c2ecf20Sopenharmony_ci	BUG_ON(offset >= loc->xl_size);
14578c2ecf20Sopenharmony_ci	return loc->xl_ops->xlo_offset_pointer(loc, offset);
14588c2ecf20Sopenharmony_ci}
14598c2ecf20Sopenharmony_ci
14608c2ecf20Sopenharmony_ci/*
14618c2ecf20Sopenharmony_ci * Wipe the name+value pair and allow the storage to reclaim it.  This
14628c2ecf20Sopenharmony_ci * must be followed by either removal of the entry or a call to
14638c2ecf20Sopenharmony_ci * ocfs2_xa_add_namevalue().
14648c2ecf20Sopenharmony_ci */
14658c2ecf20Sopenharmony_cistatic void ocfs2_xa_wipe_namevalue(struct ocfs2_xa_loc *loc)
14668c2ecf20Sopenharmony_ci{
14678c2ecf20Sopenharmony_ci	loc->xl_ops->xlo_wipe_namevalue(loc);
14688c2ecf20Sopenharmony_ci}
14698c2ecf20Sopenharmony_ci
14708c2ecf20Sopenharmony_ci/*
14718c2ecf20Sopenharmony_ci * Find lowest offset to a name+value pair.  This is the start of our
14728c2ecf20Sopenharmony_ci * downward-growing free space.
14738c2ecf20Sopenharmony_ci */
14748c2ecf20Sopenharmony_cistatic int ocfs2_xa_get_free_start(struct ocfs2_xa_loc *loc)
14758c2ecf20Sopenharmony_ci{
14768c2ecf20Sopenharmony_ci	return loc->xl_ops->xlo_get_free_start(loc);
14778c2ecf20Sopenharmony_ci}
14788c2ecf20Sopenharmony_ci
14798c2ecf20Sopenharmony_ci/* Can we reuse loc->xl_entry for xi? */
14808c2ecf20Sopenharmony_cistatic int ocfs2_xa_can_reuse_entry(struct ocfs2_xa_loc *loc,
14818c2ecf20Sopenharmony_ci				    struct ocfs2_xattr_info *xi)
14828c2ecf20Sopenharmony_ci{
14838c2ecf20Sopenharmony_ci	return loc->xl_ops->xlo_can_reuse(loc, xi);
14848c2ecf20Sopenharmony_ci}
14858c2ecf20Sopenharmony_ci
14868c2ecf20Sopenharmony_ci/* How much free space is needed to set the new value */
14878c2ecf20Sopenharmony_cistatic int ocfs2_xa_check_space(struct ocfs2_xa_loc *loc,
14888c2ecf20Sopenharmony_ci				struct ocfs2_xattr_info *xi)
14898c2ecf20Sopenharmony_ci{
14908c2ecf20Sopenharmony_ci	return loc->xl_ops->xlo_check_space(loc, xi);
14918c2ecf20Sopenharmony_ci}
14928c2ecf20Sopenharmony_ci
14938c2ecf20Sopenharmony_cistatic void ocfs2_xa_add_entry(struct ocfs2_xa_loc *loc, u32 name_hash)
14948c2ecf20Sopenharmony_ci{
14958c2ecf20Sopenharmony_ci	loc->xl_ops->xlo_add_entry(loc, name_hash);
14968c2ecf20Sopenharmony_ci	loc->xl_entry->xe_name_hash = cpu_to_le32(name_hash);
14978c2ecf20Sopenharmony_ci	/*
14988c2ecf20Sopenharmony_ci	 * We can't leave the new entry's xe_name_offset at zero or
14998c2ecf20Sopenharmony_ci	 * add_namevalue() will go nuts.  We set it to the size of our
15008c2ecf20Sopenharmony_ci	 * storage so that it can never be less than any other entry.
15018c2ecf20Sopenharmony_ci	 */
15028c2ecf20Sopenharmony_ci	loc->xl_entry->xe_name_offset = cpu_to_le16(loc->xl_size);
15038c2ecf20Sopenharmony_ci}
15048c2ecf20Sopenharmony_ci
15058c2ecf20Sopenharmony_cistatic void ocfs2_xa_add_namevalue(struct ocfs2_xa_loc *loc,
15068c2ecf20Sopenharmony_ci				   struct ocfs2_xattr_info *xi)
15078c2ecf20Sopenharmony_ci{
15088c2ecf20Sopenharmony_ci	int size = namevalue_size_xi(xi);
15098c2ecf20Sopenharmony_ci	int nameval_offset;
15108c2ecf20Sopenharmony_ci	char *nameval_buf;
15118c2ecf20Sopenharmony_ci
15128c2ecf20Sopenharmony_ci	loc->xl_ops->xlo_add_namevalue(loc, size);
15138c2ecf20Sopenharmony_ci	loc->xl_entry->xe_value_size = cpu_to_le64(xi->xi_value_len);
15148c2ecf20Sopenharmony_ci	loc->xl_entry->xe_name_len = xi->xi_name_len;
15158c2ecf20Sopenharmony_ci	ocfs2_xattr_set_type(loc->xl_entry, xi->xi_name_index);
15168c2ecf20Sopenharmony_ci	ocfs2_xattr_set_local(loc->xl_entry,
15178c2ecf20Sopenharmony_ci			      xi->xi_value_len <= OCFS2_XATTR_INLINE_SIZE);
15188c2ecf20Sopenharmony_ci
15198c2ecf20Sopenharmony_ci	nameval_offset = le16_to_cpu(loc->xl_entry->xe_name_offset);
15208c2ecf20Sopenharmony_ci	nameval_buf = ocfs2_xa_offset_pointer(loc, nameval_offset);
15218c2ecf20Sopenharmony_ci	memset(nameval_buf, 0, size);
15228c2ecf20Sopenharmony_ci	memcpy(nameval_buf, xi->xi_name, xi->xi_name_len);
15238c2ecf20Sopenharmony_ci}
15248c2ecf20Sopenharmony_ci
15258c2ecf20Sopenharmony_cistatic void ocfs2_xa_fill_value_buf(struct ocfs2_xa_loc *loc,
15268c2ecf20Sopenharmony_ci				    struct ocfs2_xattr_value_buf *vb)
15278c2ecf20Sopenharmony_ci{
15288c2ecf20Sopenharmony_ci	int nameval_offset = le16_to_cpu(loc->xl_entry->xe_name_offset);
15298c2ecf20Sopenharmony_ci	int name_size = OCFS2_XATTR_SIZE(loc->xl_entry->xe_name_len);
15308c2ecf20Sopenharmony_ci
15318c2ecf20Sopenharmony_ci	/* Value bufs are for value trees */
15328c2ecf20Sopenharmony_ci	BUG_ON(ocfs2_xattr_is_local(loc->xl_entry));
15338c2ecf20Sopenharmony_ci	BUG_ON(namevalue_size_xe(loc->xl_entry) !=
15348c2ecf20Sopenharmony_ci	       (name_size + OCFS2_XATTR_ROOT_SIZE));
15358c2ecf20Sopenharmony_ci
15368c2ecf20Sopenharmony_ci	loc->xl_ops->xlo_fill_value_buf(loc, vb);
15378c2ecf20Sopenharmony_ci	vb->vb_xv =
15388c2ecf20Sopenharmony_ci		(struct ocfs2_xattr_value_root *)ocfs2_xa_offset_pointer(loc,
15398c2ecf20Sopenharmony_ci							nameval_offset +
15408c2ecf20Sopenharmony_ci							name_size);
15418c2ecf20Sopenharmony_ci}
15428c2ecf20Sopenharmony_ci
15438c2ecf20Sopenharmony_cistatic int ocfs2_xa_block_journal_access(handle_t *handle,
15448c2ecf20Sopenharmony_ci					 struct ocfs2_xa_loc *loc, int type)
15458c2ecf20Sopenharmony_ci{
15468c2ecf20Sopenharmony_ci	struct buffer_head *bh = loc->xl_storage;
15478c2ecf20Sopenharmony_ci	ocfs2_journal_access_func access;
15488c2ecf20Sopenharmony_ci
15498c2ecf20Sopenharmony_ci	if (loc->xl_size == (bh->b_size -
15508c2ecf20Sopenharmony_ci			     offsetof(struct ocfs2_xattr_block,
15518c2ecf20Sopenharmony_ci				      xb_attrs.xb_header)))
15528c2ecf20Sopenharmony_ci		access = ocfs2_journal_access_xb;
15538c2ecf20Sopenharmony_ci	else
15548c2ecf20Sopenharmony_ci		access = ocfs2_journal_access_di;
15558c2ecf20Sopenharmony_ci	return access(handle, INODE_CACHE(loc->xl_inode), bh, type);
15568c2ecf20Sopenharmony_ci}
15578c2ecf20Sopenharmony_ci
15588c2ecf20Sopenharmony_cistatic void ocfs2_xa_block_journal_dirty(handle_t *handle,
15598c2ecf20Sopenharmony_ci					 struct ocfs2_xa_loc *loc)
15608c2ecf20Sopenharmony_ci{
15618c2ecf20Sopenharmony_ci	struct buffer_head *bh = loc->xl_storage;
15628c2ecf20Sopenharmony_ci
15638c2ecf20Sopenharmony_ci	ocfs2_journal_dirty(handle, bh);
15648c2ecf20Sopenharmony_ci}
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_cistatic void *ocfs2_xa_block_offset_pointer(struct ocfs2_xa_loc *loc,
15678c2ecf20Sopenharmony_ci					   int offset)
15688c2ecf20Sopenharmony_ci{
15698c2ecf20Sopenharmony_ci	return (char *)loc->xl_header + offset;
15708c2ecf20Sopenharmony_ci}
15718c2ecf20Sopenharmony_ci
15728c2ecf20Sopenharmony_cistatic int ocfs2_xa_block_can_reuse(struct ocfs2_xa_loc *loc,
15738c2ecf20Sopenharmony_ci				    struct ocfs2_xattr_info *xi)
15748c2ecf20Sopenharmony_ci{
15758c2ecf20Sopenharmony_ci	/*
15768c2ecf20Sopenharmony_ci	 * Block storage is strict.  If the sizes aren't exact, we will
15778c2ecf20Sopenharmony_ci	 * remove the old one and reinsert the new.
15788c2ecf20Sopenharmony_ci	 */
15798c2ecf20Sopenharmony_ci	return namevalue_size_xe(loc->xl_entry) ==
15808c2ecf20Sopenharmony_ci		namevalue_size_xi(xi);
15818c2ecf20Sopenharmony_ci}
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_cistatic int ocfs2_xa_block_get_free_start(struct ocfs2_xa_loc *loc)
15848c2ecf20Sopenharmony_ci{
15858c2ecf20Sopenharmony_ci	struct ocfs2_xattr_header *xh = loc->xl_header;
15868c2ecf20Sopenharmony_ci	int i, count = le16_to_cpu(xh->xh_count);
15878c2ecf20Sopenharmony_ci	int offset, free_start = loc->xl_size;
15888c2ecf20Sopenharmony_ci
15898c2ecf20Sopenharmony_ci	for (i = 0; i < count; i++) {
15908c2ecf20Sopenharmony_ci		offset = le16_to_cpu(xh->xh_entries[i].xe_name_offset);
15918c2ecf20Sopenharmony_ci		if (offset < free_start)
15928c2ecf20Sopenharmony_ci			free_start = offset;
15938c2ecf20Sopenharmony_ci	}
15948c2ecf20Sopenharmony_ci
15958c2ecf20Sopenharmony_ci	return free_start;
15968c2ecf20Sopenharmony_ci}
15978c2ecf20Sopenharmony_ci
15988c2ecf20Sopenharmony_cistatic int ocfs2_xa_block_check_space(struct ocfs2_xa_loc *loc,
15998c2ecf20Sopenharmony_ci				      struct ocfs2_xattr_info *xi)
16008c2ecf20Sopenharmony_ci{
16018c2ecf20Sopenharmony_ci	int count = le16_to_cpu(loc->xl_header->xh_count);
16028c2ecf20Sopenharmony_ci	int free_start = ocfs2_xa_get_free_start(loc);
16038c2ecf20Sopenharmony_ci	int needed_space = ocfs2_xi_entry_usage(xi);
16048c2ecf20Sopenharmony_ci
16058c2ecf20Sopenharmony_ci	/*
16068c2ecf20Sopenharmony_ci	 * Block storage will reclaim the original entry before inserting
16078c2ecf20Sopenharmony_ci	 * the new value, so we only need the difference.  If the new
16088c2ecf20Sopenharmony_ci	 * entry is smaller than the old one, we don't need anything.
16098c2ecf20Sopenharmony_ci	 */
16108c2ecf20Sopenharmony_ci	if (loc->xl_entry) {
16118c2ecf20Sopenharmony_ci		/* Don't need space if we're reusing! */
16128c2ecf20Sopenharmony_ci		if (ocfs2_xa_can_reuse_entry(loc, xi))
16138c2ecf20Sopenharmony_ci			needed_space = 0;
16148c2ecf20Sopenharmony_ci		else
16158c2ecf20Sopenharmony_ci			needed_space -= ocfs2_xe_entry_usage(loc->xl_entry);
16168c2ecf20Sopenharmony_ci	}
16178c2ecf20Sopenharmony_ci	if (needed_space < 0)
16188c2ecf20Sopenharmony_ci		needed_space = 0;
16198c2ecf20Sopenharmony_ci	return ocfs2_xa_check_space_helper(needed_space, free_start, count);
16208c2ecf20Sopenharmony_ci}
16218c2ecf20Sopenharmony_ci
16228c2ecf20Sopenharmony_ci/*
16238c2ecf20Sopenharmony_ci * Block storage for xattrs keeps the name+value pairs compacted.  When
16248c2ecf20Sopenharmony_ci * we remove one, we have to shift any that preceded it towards the end.
16258c2ecf20Sopenharmony_ci */
16268c2ecf20Sopenharmony_cistatic void ocfs2_xa_block_wipe_namevalue(struct ocfs2_xa_loc *loc)
16278c2ecf20Sopenharmony_ci{
16288c2ecf20Sopenharmony_ci	int i, offset;
16298c2ecf20Sopenharmony_ci	int namevalue_offset, first_namevalue_offset, namevalue_size;
16308c2ecf20Sopenharmony_ci	struct ocfs2_xattr_entry *entry = loc->xl_entry;
16318c2ecf20Sopenharmony_ci	struct ocfs2_xattr_header *xh = loc->xl_header;
16328c2ecf20Sopenharmony_ci	int count = le16_to_cpu(xh->xh_count);
16338c2ecf20Sopenharmony_ci
16348c2ecf20Sopenharmony_ci	namevalue_offset = le16_to_cpu(entry->xe_name_offset);
16358c2ecf20Sopenharmony_ci	namevalue_size = namevalue_size_xe(entry);
16368c2ecf20Sopenharmony_ci	first_namevalue_offset = ocfs2_xa_get_free_start(loc);
16378c2ecf20Sopenharmony_ci
16388c2ecf20Sopenharmony_ci	/* Shift the name+value pairs */
16398c2ecf20Sopenharmony_ci	memmove((char *)xh + first_namevalue_offset + namevalue_size,
16408c2ecf20Sopenharmony_ci		(char *)xh + first_namevalue_offset,
16418c2ecf20Sopenharmony_ci		namevalue_offset - first_namevalue_offset);
16428c2ecf20Sopenharmony_ci	memset((char *)xh + first_namevalue_offset, 0, namevalue_size);
16438c2ecf20Sopenharmony_ci
16448c2ecf20Sopenharmony_ci	/* Now tell xh->xh_entries about it */
16458c2ecf20Sopenharmony_ci	for (i = 0; i < count; i++) {
16468c2ecf20Sopenharmony_ci		offset = le16_to_cpu(xh->xh_entries[i].xe_name_offset);
16478c2ecf20Sopenharmony_ci		if (offset <= namevalue_offset)
16488c2ecf20Sopenharmony_ci			le16_add_cpu(&xh->xh_entries[i].xe_name_offset,
16498c2ecf20Sopenharmony_ci				     namevalue_size);
16508c2ecf20Sopenharmony_ci	}
16518c2ecf20Sopenharmony_ci
16528c2ecf20Sopenharmony_ci	/*
16538c2ecf20Sopenharmony_ci	 * Note that we don't update xh_free_start or xh_name_value_len
16548c2ecf20Sopenharmony_ci	 * because they're not used in block-stored xattrs.
16558c2ecf20Sopenharmony_ci	 */
16568c2ecf20Sopenharmony_ci}
16578c2ecf20Sopenharmony_ci
16588c2ecf20Sopenharmony_cistatic void ocfs2_xa_block_add_entry(struct ocfs2_xa_loc *loc, u32 name_hash)
16598c2ecf20Sopenharmony_ci{
16608c2ecf20Sopenharmony_ci	int count = le16_to_cpu(loc->xl_header->xh_count);
16618c2ecf20Sopenharmony_ci	loc->xl_entry = &(loc->xl_header->xh_entries[count]);
16628c2ecf20Sopenharmony_ci	le16_add_cpu(&loc->xl_header->xh_count, 1);
16638c2ecf20Sopenharmony_ci	memset(loc->xl_entry, 0, sizeof(struct ocfs2_xattr_entry));
16648c2ecf20Sopenharmony_ci}
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_cistatic void ocfs2_xa_block_add_namevalue(struct ocfs2_xa_loc *loc, int size)
16678c2ecf20Sopenharmony_ci{
16688c2ecf20Sopenharmony_ci	int free_start = ocfs2_xa_get_free_start(loc);
16698c2ecf20Sopenharmony_ci
16708c2ecf20Sopenharmony_ci	loc->xl_entry->xe_name_offset = cpu_to_le16(free_start - size);
16718c2ecf20Sopenharmony_ci}
16728c2ecf20Sopenharmony_ci
16738c2ecf20Sopenharmony_cistatic void ocfs2_xa_block_fill_value_buf(struct ocfs2_xa_loc *loc,
16748c2ecf20Sopenharmony_ci					  struct ocfs2_xattr_value_buf *vb)
16758c2ecf20Sopenharmony_ci{
16768c2ecf20Sopenharmony_ci	struct buffer_head *bh = loc->xl_storage;
16778c2ecf20Sopenharmony_ci
16788c2ecf20Sopenharmony_ci	if (loc->xl_size == (bh->b_size -
16798c2ecf20Sopenharmony_ci			     offsetof(struct ocfs2_xattr_block,
16808c2ecf20Sopenharmony_ci				      xb_attrs.xb_header)))
16818c2ecf20Sopenharmony_ci		vb->vb_access = ocfs2_journal_access_xb;
16828c2ecf20Sopenharmony_ci	else
16838c2ecf20Sopenharmony_ci		vb->vb_access = ocfs2_journal_access_di;
16848c2ecf20Sopenharmony_ci	vb->vb_bh = bh;
16858c2ecf20Sopenharmony_ci}
16868c2ecf20Sopenharmony_ci
16878c2ecf20Sopenharmony_ci/*
16888c2ecf20Sopenharmony_ci * Operations for xattrs stored in blocks.  This includes inline inode
16898c2ecf20Sopenharmony_ci * storage and unindexed ocfs2_xattr_blocks.
16908c2ecf20Sopenharmony_ci */
16918c2ecf20Sopenharmony_cistatic const struct ocfs2_xa_loc_operations ocfs2_xa_block_loc_ops = {
16928c2ecf20Sopenharmony_ci	.xlo_journal_access	= ocfs2_xa_block_journal_access,
16938c2ecf20Sopenharmony_ci	.xlo_journal_dirty	= ocfs2_xa_block_journal_dirty,
16948c2ecf20Sopenharmony_ci	.xlo_offset_pointer	= ocfs2_xa_block_offset_pointer,
16958c2ecf20Sopenharmony_ci	.xlo_check_space	= ocfs2_xa_block_check_space,
16968c2ecf20Sopenharmony_ci	.xlo_can_reuse		= ocfs2_xa_block_can_reuse,
16978c2ecf20Sopenharmony_ci	.xlo_get_free_start	= ocfs2_xa_block_get_free_start,
16988c2ecf20Sopenharmony_ci	.xlo_wipe_namevalue	= ocfs2_xa_block_wipe_namevalue,
16998c2ecf20Sopenharmony_ci	.xlo_add_entry		= ocfs2_xa_block_add_entry,
17008c2ecf20Sopenharmony_ci	.xlo_add_namevalue	= ocfs2_xa_block_add_namevalue,
17018c2ecf20Sopenharmony_ci	.xlo_fill_value_buf	= ocfs2_xa_block_fill_value_buf,
17028c2ecf20Sopenharmony_ci};
17038c2ecf20Sopenharmony_ci
17048c2ecf20Sopenharmony_cistatic int ocfs2_xa_bucket_journal_access(handle_t *handle,
17058c2ecf20Sopenharmony_ci					  struct ocfs2_xa_loc *loc, int type)
17068c2ecf20Sopenharmony_ci{
17078c2ecf20Sopenharmony_ci	struct ocfs2_xattr_bucket *bucket = loc->xl_storage;
17088c2ecf20Sopenharmony_ci
17098c2ecf20Sopenharmony_ci	return ocfs2_xattr_bucket_journal_access(handle, bucket, type);
17108c2ecf20Sopenharmony_ci}
17118c2ecf20Sopenharmony_ci
17128c2ecf20Sopenharmony_cistatic void ocfs2_xa_bucket_journal_dirty(handle_t *handle,
17138c2ecf20Sopenharmony_ci					  struct ocfs2_xa_loc *loc)
17148c2ecf20Sopenharmony_ci{
17158c2ecf20Sopenharmony_ci	struct ocfs2_xattr_bucket *bucket = loc->xl_storage;
17168c2ecf20Sopenharmony_ci
17178c2ecf20Sopenharmony_ci	ocfs2_xattr_bucket_journal_dirty(handle, bucket);
17188c2ecf20Sopenharmony_ci}
17198c2ecf20Sopenharmony_ci
17208c2ecf20Sopenharmony_cistatic void *ocfs2_xa_bucket_offset_pointer(struct ocfs2_xa_loc *loc,
17218c2ecf20Sopenharmony_ci					    int offset)
17228c2ecf20Sopenharmony_ci{
17238c2ecf20Sopenharmony_ci	struct ocfs2_xattr_bucket *bucket = loc->xl_storage;
17248c2ecf20Sopenharmony_ci	int block, block_offset;
17258c2ecf20Sopenharmony_ci
17268c2ecf20Sopenharmony_ci	/* The header is at the front of the bucket */
17278c2ecf20Sopenharmony_ci	block = offset >> loc->xl_inode->i_sb->s_blocksize_bits;
17288c2ecf20Sopenharmony_ci	block_offset = offset % loc->xl_inode->i_sb->s_blocksize;
17298c2ecf20Sopenharmony_ci
17308c2ecf20Sopenharmony_ci	return bucket_block(bucket, block) + block_offset;
17318c2ecf20Sopenharmony_ci}
17328c2ecf20Sopenharmony_ci
17338c2ecf20Sopenharmony_cistatic int ocfs2_xa_bucket_can_reuse(struct ocfs2_xa_loc *loc,
17348c2ecf20Sopenharmony_ci				     struct ocfs2_xattr_info *xi)
17358c2ecf20Sopenharmony_ci{
17368c2ecf20Sopenharmony_ci	return namevalue_size_xe(loc->xl_entry) >=
17378c2ecf20Sopenharmony_ci		namevalue_size_xi(xi);
17388c2ecf20Sopenharmony_ci}
17398c2ecf20Sopenharmony_ci
17408c2ecf20Sopenharmony_cistatic int ocfs2_xa_bucket_get_free_start(struct ocfs2_xa_loc *loc)
17418c2ecf20Sopenharmony_ci{
17428c2ecf20Sopenharmony_ci	struct ocfs2_xattr_bucket *bucket = loc->xl_storage;
17438c2ecf20Sopenharmony_ci	return le16_to_cpu(bucket_xh(bucket)->xh_free_start);
17448c2ecf20Sopenharmony_ci}
17458c2ecf20Sopenharmony_ci
17468c2ecf20Sopenharmony_cistatic int ocfs2_bucket_align_free_start(struct super_block *sb,
17478c2ecf20Sopenharmony_ci					 int free_start, int size)
17488c2ecf20Sopenharmony_ci{
17498c2ecf20Sopenharmony_ci	/*
17508c2ecf20Sopenharmony_ci	 * We need to make sure that the name+value pair fits within
17518c2ecf20Sopenharmony_ci	 * one block.
17528c2ecf20Sopenharmony_ci	 */
17538c2ecf20Sopenharmony_ci	if (((free_start - size) >> sb->s_blocksize_bits) !=
17548c2ecf20Sopenharmony_ci	    ((free_start - 1) >> sb->s_blocksize_bits))
17558c2ecf20Sopenharmony_ci		free_start -= free_start % sb->s_blocksize;
17568c2ecf20Sopenharmony_ci
17578c2ecf20Sopenharmony_ci	return free_start;
17588c2ecf20Sopenharmony_ci}
17598c2ecf20Sopenharmony_ci
17608c2ecf20Sopenharmony_cistatic int ocfs2_xa_bucket_check_space(struct ocfs2_xa_loc *loc,
17618c2ecf20Sopenharmony_ci				       struct ocfs2_xattr_info *xi)
17628c2ecf20Sopenharmony_ci{
17638c2ecf20Sopenharmony_ci	int rc;
17648c2ecf20Sopenharmony_ci	int count = le16_to_cpu(loc->xl_header->xh_count);
17658c2ecf20Sopenharmony_ci	int free_start = ocfs2_xa_get_free_start(loc);
17668c2ecf20Sopenharmony_ci	int needed_space = ocfs2_xi_entry_usage(xi);
17678c2ecf20Sopenharmony_ci	int size = namevalue_size_xi(xi);
17688c2ecf20Sopenharmony_ci	struct super_block *sb = loc->xl_inode->i_sb;
17698c2ecf20Sopenharmony_ci
17708c2ecf20Sopenharmony_ci	/*
17718c2ecf20Sopenharmony_ci	 * Bucket storage does not reclaim name+value pairs it cannot
17728c2ecf20Sopenharmony_ci	 * reuse.  They live as holes until the bucket fills, and then
17738c2ecf20Sopenharmony_ci	 * the bucket is defragmented.  However, the bucket can reclaim
17748c2ecf20Sopenharmony_ci	 * the ocfs2_xattr_entry.
17758c2ecf20Sopenharmony_ci	 */
17768c2ecf20Sopenharmony_ci	if (loc->xl_entry) {
17778c2ecf20Sopenharmony_ci		/* Don't need space if we're reusing! */
17788c2ecf20Sopenharmony_ci		if (ocfs2_xa_can_reuse_entry(loc, xi))
17798c2ecf20Sopenharmony_ci			needed_space = 0;
17808c2ecf20Sopenharmony_ci		else
17818c2ecf20Sopenharmony_ci			needed_space -= sizeof(struct ocfs2_xattr_entry);
17828c2ecf20Sopenharmony_ci	}
17838c2ecf20Sopenharmony_ci	BUG_ON(needed_space < 0);
17848c2ecf20Sopenharmony_ci
17858c2ecf20Sopenharmony_ci	if (free_start < size) {
17868c2ecf20Sopenharmony_ci		if (needed_space)
17878c2ecf20Sopenharmony_ci			return -ENOSPC;
17888c2ecf20Sopenharmony_ci	} else {
17898c2ecf20Sopenharmony_ci		/*
17908c2ecf20Sopenharmony_ci		 * First we check if it would fit in the first place.
17918c2ecf20Sopenharmony_ci		 * Below, we align the free start to a block.  This may
17928c2ecf20Sopenharmony_ci		 * slide us below the minimum gap.  By checking unaligned
17938c2ecf20Sopenharmony_ci		 * first, we avoid that error.
17948c2ecf20Sopenharmony_ci		 */
17958c2ecf20Sopenharmony_ci		rc = ocfs2_xa_check_space_helper(needed_space, free_start,
17968c2ecf20Sopenharmony_ci						 count);
17978c2ecf20Sopenharmony_ci		if (rc)
17988c2ecf20Sopenharmony_ci			return rc;
17998c2ecf20Sopenharmony_ci		free_start = ocfs2_bucket_align_free_start(sb, free_start,
18008c2ecf20Sopenharmony_ci							   size);
18018c2ecf20Sopenharmony_ci	}
18028c2ecf20Sopenharmony_ci	return ocfs2_xa_check_space_helper(needed_space, free_start, count);
18038c2ecf20Sopenharmony_ci}
18048c2ecf20Sopenharmony_ci
18058c2ecf20Sopenharmony_cistatic void ocfs2_xa_bucket_wipe_namevalue(struct ocfs2_xa_loc *loc)
18068c2ecf20Sopenharmony_ci{
18078c2ecf20Sopenharmony_ci	le16_add_cpu(&loc->xl_header->xh_name_value_len,
18088c2ecf20Sopenharmony_ci		     -namevalue_size_xe(loc->xl_entry));
18098c2ecf20Sopenharmony_ci}
18108c2ecf20Sopenharmony_ci
18118c2ecf20Sopenharmony_cistatic void ocfs2_xa_bucket_add_entry(struct ocfs2_xa_loc *loc, u32 name_hash)
18128c2ecf20Sopenharmony_ci{
18138c2ecf20Sopenharmony_ci	struct ocfs2_xattr_header *xh = loc->xl_header;
18148c2ecf20Sopenharmony_ci	int count = le16_to_cpu(xh->xh_count);
18158c2ecf20Sopenharmony_ci	int low = 0, high = count - 1, tmp;
18168c2ecf20Sopenharmony_ci	struct ocfs2_xattr_entry *tmp_xe;
18178c2ecf20Sopenharmony_ci
18188c2ecf20Sopenharmony_ci	/*
18198c2ecf20Sopenharmony_ci	 * We keep buckets sorted by name_hash, so we need to find
18208c2ecf20Sopenharmony_ci	 * our insert place.
18218c2ecf20Sopenharmony_ci	 */
18228c2ecf20Sopenharmony_ci	while (low <= high && count) {
18238c2ecf20Sopenharmony_ci		tmp = (low + high) / 2;
18248c2ecf20Sopenharmony_ci		tmp_xe = &xh->xh_entries[tmp];
18258c2ecf20Sopenharmony_ci
18268c2ecf20Sopenharmony_ci		if (name_hash > le32_to_cpu(tmp_xe->xe_name_hash))
18278c2ecf20Sopenharmony_ci			low = tmp + 1;
18288c2ecf20Sopenharmony_ci		else if (name_hash < le32_to_cpu(tmp_xe->xe_name_hash))
18298c2ecf20Sopenharmony_ci			high = tmp - 1;
18308c2ecf20Sopenharmony_ci		else {
18318c2ecf20Sopenharmony_ci			low = tmp;
18328c2ecf20Sopenharmony_ci			break;
18338c2ecf20Sopenharmony_ci		}
18348c2ecf20Sopenharmony_ci	}
18358c2ecf20Sopenharmony_ci
18368c2ecf20Sopenharmony_ci	if (low != count)
18378c2ecf20Sopenharmony_ci		memmove(&xh->xh_entries[low + 1],
18388c2ecf20Sopenharmony_ci			&xh->xh_entries[low],
18398c2ecf20Sopenharmony_ci			((count - low) * sizeof(struct ocfs2_xattr_entry)));
18408c2ecf20Sopenharmony_ci
18418c2ecf20Sopenharmony_ci	le16_add_cpu(&xh->xh_count, 1);
18428c2ecf20Sopenharmony_ci	loc->xl_entry = &xh->xh_entries[low];
18438c2ecf20Sopenharmony_ci	memset(loc->xl_entry, 0, sizeof(struct ocfs2_xattr_entry));
18448c2ecf20Sopenharmony_ci}
18458c2ecf20Sopenharmony_ci
18468c2ecf20Sopenharmony_cistatic void ocfs2_xa_bucket_add_namevalue(struct ocfs2_xa_loc *loc, int size)
18478c2ecf20Sopenharmony_ci{
18488c2ecf20Sopenharmony_ci	int free_start = ocfs2_xa_get_free_start(loc);
18498c2ecf20Sopenharmony_ci	struct ocfs2_xattr_header *xh = loc->xl_header;
18508c2ecf20Sopenharmony_ci	struct super_block *sb = loc->xl_inode->i_sb;
18518c2ecf20Sopenharmony_ci	int nameval_offset;
18528c2ecf20Sopenharmony_ci
18538c2ecf20Sopenharmony_ci	free_start = ocfs2_bucket_align_free_start(sb, free_start, size);
18548c2ecf20Sopenharmony_ci	nameval_offset = free_start - size;
18558c2ecf20Sopenharmony_ci	loc->xl_entry->xe_name_offset = cpu_to_le16(nameval_offset);
18568c2ecf20Sopenharmony_ci	xh->xh_free_start = cpu_to_le16(nameval_offset);
18578c2ecf20Sopenharmony_ci	le16_add_cpu(&xh->xh_name_value_len, size);
18588c2ecf20Sopenharmony_ci
18598c2ecf20Sopenharmony_ci}
18608c2ecf20Sopenharmony_ci
18618c2ecf20Sopenharmony_cistatic void ocfs2_xa_bucket_fill_value_buf(struct ocfs2_xa_loc *loc,
18628c2ecf20Sopenharmony_ci					   struct ocfs2_xattr_value_buf *vb)
18638c2ecf20Sopenharmony_ci{
18648c2ecf20Sopenharmony_ci	struct ocfs2_xattr_bucket *bucket = loc->xl_storage;
18658c2ecf20Sopenharmony_ci	struct super_block *sb = loc->xl_inode->i_sb;
18668c2ecf20Sopenharmony_ci	int nameval_offset = le16_to_cpu(loc->xl_entry->xe_name_offset);
18678c2ecf20Sopenharmony_ci	int size = namevalue_size_xe(loc->xl_entry);
18688c2ecf20Sopenharmony_ci	int block_offset = nameval_offset >> sb->s_blocksize_bits;
18698c2ecf20Sopenharmony_ci
18708c2ecf20Sopenharmony_ci	/* Values are not allowed to straddle block boundaries */
18718c2ecf20Sopenharmony_ci	BUG_ON(block_offset !=
18728c2ecf20Sopenharmony_ci	       ((nameval_offset + size - 1) >> sb->s_blocksize_bits));
18738c2ecf20Sopenharmony_ci	/* We expect the bucket to be filled in */
18748c2ecf20Sopenharmony_ci	BUG_ON(!bucket->bu_bhs[block_offset]);
18758c2ecf20Sopenharmony_ci
18768c2ecf20Sopenharmony_ci	vb->vb_access = ocfs2_journal_access;
18778c2ecf20Sopenharmony_ci	vb->vb_bh = bucket->bu_bhs[block_offset];
18788c2ecf20Sopenharmony_ci}
18798c2ecf20Sopenharmony_ci
18808c2ecf20Sopenharmony_ci/* Operations for xattrs stored in buckets. */
18818c2ecf20Sopenharmony_cistatic const struct ocfs2_xa_loc_operations ocfs2_xa_bucket_loc_ops = {
18828c2ecf20Sopenharmony_ci	.xlo_journal_access	= ocfs2_xa_bucket_journal_access,
18838c2ecf20Sopenharmony_ci	.xlo_journal_dirty	= ocfs2_xa_bucket_journal_dirty,
18848c2ecf20Sopenharmony_ci	.xlo_offset_pointer	= ocfs2_xa_bucket_offset_pointer,
18858c2ecf20Sopenharmony_ci	.xlo_check_space	= ocfs2_xa_bucket_check_space,
18868c2ecf20Sopenharmony_ci	.xlo_can_reuse		= ocfs2_xa_bucket_can_reuse,
18878c2ecf20Sopenharmony_ci	.xlo_get_free_start	= ocfs2_xa_bucket_get_free_start,
18888c2ecf20Sopenharmony_ci	.xlo_wipe_namevalue	= ocfs2_xa_bucket_wipe_namevalue,
18898c2ecf20Sopenharmony_ci	.xlo_add_entry		= ocfs2_xa_bucket_add_entry,
18908c2ecf20Sopenharmony_ci	.xlo_add_namevalue	= ocfs2_xa_bucket_add_namevalue,
18918c2ecf20Sopenharmony_ci	.xlo_fill_value_buf	= ocfs2_xa_bucket_fill_value_buf,
18928c2ecf20Sopenharmony_ci};
18938c2ecf20Sopenharmony_ci
18948c2ecf20Sopenharmony_cistatic unsigned int ocfs2_xa_value_clusters(struct ocfs2_xa_loc *loc)
18958c2ecf20Sopenharmony_ci{
18968c2ecf20Sopenharmony_ci	struct ocfs2_xattr_value_buf vb;
18978c2ecf20Sopenharmony_ci
18988c2ecf20Sopenharmony_ci	if (ocfs2_xattr_is_local(loc->xl_entry))
18998c2ecf20Sopenharmony_ci		return 0;
19008c2ecf20Sopenharmony_ci
19018c2ecf20Sopenharmony_ci	ocfs2_xa_fill_value_buf(loc, &vb);
19028c2ecf20Sopenharmony_ci	return le32_to_cpu(vb.vb_xv->xr_clusters);
19038c2ecf20Sopenharmony_ci}
19048c2ecf20Sopenharmony_ci
19058c2ecf20Sopenharmony_cistatic int ocfs2_xa_value_truncate(struct ocfs2_xa_loc *loc, u64 bytes,
19068c2ecf20Sopenharmony_ci				   struct ocfs2_xattr_set_ctxt *ctxt)
19078c2ecf20Sopenharmony_ci{
19088c2ecf20Sopenharmony_ci	int trunc_rc, access_rc;
19098c2ecf20Sopenharmony_ci	struct ocfs2_xattr_value_buf vb;
19108c2ecf20Sopenharmony_ci
19118c2ecf20Sopenharmony_ci	ocfs2_xa_fill_value_buf(loc, &vb);
19128c2ecf20Sopenharmony_ci	trunc_rc = ocfs2_xattr_value_truncate(loc->xl_inode, &vb, bytes,
19138c2ecf20Sopenharmony_ci					      ctxt);
19148c2ecf20Sopenharmony_ci
19158c2ecf20Sopenharmony_ci	/*
19168c2ecf20Sopenharmony_ci	 * The caller of ocfs2_xa_value_truncate() has already called
19178c2ecf20Sopenharmony_ci	 * ocfs2_xa_journal_access on the loc.  However, The truncate code
19188c2ecf20Sopenharmony_ci	 * calls ocfs2_extend_trans().  This may commit the previous
19198c2ecf20Sopenharmony_ci	 * transaction and open a new one.  If this is a bucket, truncate
19208c2ecf20Sopenharmony_ci	 * could leave only vb->vb_bh set up for journaling.  Meanwhile,
19218c2ecf20Sopenharmony_ci	 * the caller is expecting to dirty the entire bucket.  So we must
19228c2ecf20Sopenharmony_ci	 * reset the journal work.  We do this even if truncate has failed,
19238c2ecf20Sopenharmony_ci	 * as it could have failed after committing the extend.
19248c2ecf20Sopenharmony_ci	 */
19258c2ecf20Sopenharmony_ci	access_rc = ocfs2_xa_journal_access(ctxt->handle, loc,
19268c2ecf20Sopenharmony_ci					    OCFS2_JOURNAL_ACCESS_WRITE);
19278c2ecf20Sopenharmony_ci
19288c2ecf20Sopenharmony_ci	/* Errors in truncate take precedence */
19298c2ecf20Sopenharmony_ci	return trunc_rc ? trunc_rc : access_rc;
19308c2ecf20Sopenharmony_ci}
19318c2ecf20Sopenharmony_ci
19328c2ecf20Sopenharmony_cistatic void ocfs2_xa_remove_entry(struct ocfs2_xa_loc *loc)
19338c2ecf20Sopenharmony_ci{
19348c2ecf20Sopenharmony_ci	int index, count;
19358c2ecf20Sopenharmony_ci	struct ocfs2_xattr_header *xh = loc->xl_header;
19368c2ecf20Sopenharmony_ci	struct ocfs2_xattr_entry *entry = loc->xl_entry;
19378c2ecf20Sopenharmony_ci
19388c2ecf20Sopenharmony_ci	ocfs2_xa_wipe_namevalue(loc);
19398c2ecf20Sopenharmony_ci	loc->xl_entry = NULL;
19408c2ecf20Sopenharmony_ci
19418c2ecf20Sopenharmony_ci	le16_add_cpu(&xh->xh_count, -1);
19428c2ecf20Sopenharmony_ci	count = le16_to_cpu(xh->xh_count);
19438c2ecf20Sopenharmony_ci
19448c2ecf20Sopenharmony_ci	/*
19458c2ecf20Sopenharmony_ci	 * Only zero out the entry if there are more remaining.  This is
19468c2ecf20Sopenharmony_ci	 * important for an empty bucket, as it keeps track of the
19478c2ecf20Sopenharmony_ci	 * bucket's hash value.  It doesn't hurt empty block storage.
19488c2ecf20Sopenharmony_ci	 */
19498c2ecf20Sopenharmony_ci	if (count) {
19508c2ecf20Sopenharmony_ci		index = ((char *)entry - (char *)&xh->xh_entries) /
19518c2ecf20Sopenharmony_ci			sizeof(struct ocfs2_xattr_entry);
19528c2ecf20Sopenharmony_ci		memmove(&xh->xh_entries[index], &xh->xh_entries[index + 1],
19538c2ecf20Sopenharmony_ci			(count - index) * sizeof(struct ocfs2_xattr_entry));
19548c2ecf20Sopenharmony_ci		memset(&xh->xh_entries[count], 0,
19558c2ecf20Sopenharmony_ci		       sizeof(struct ocfs2_xattr_entry));
19568c2ecf20Sopenharmony_ci	}
19578c2ecf20Sopenharmony_ci}
19588c2ecf20Sopenharmony_ci
19598c2ecf20Sopenharmony_ci/*
19608c2ecf20Sopenharmony_ci * If we have a problem adjusting the size of an external value during
19618c2ecf20Sopenharmony_ci * ocfs2_xa_prepare_entry() or ocfs2_xa_remove(), we may have an xattr
19628c2ecf20Sopenharmony_ci * in an intermediate state.  For example, the value may be partially
19638c2ecf20Sopenharmony_ci * truncated.
19648c2ecf20Sopenharmony_ci *
19658c2ecf20Sopenharmony_ci * If the value tree hasn't changed, the extend/truncate went nowhere.
19668c2ecf20Sopenharmony_ci * We have nothing to do.  The caller can treat it as a straight error.
19678c2ecf20Sopenharmony_ci *
19688c2ecf20Sopenharmony_ci * If the value tree got partially truncated, we now have a corrupted
19698c2ecf20Sopenharmony_ci * extended attribute.  We're going to wipe its entry and leak the
19708c2ecf20Sopenharmony_ci * clusters.  Better to leak some storage than leave a corrupt entry.
19718c2ecf20Sopenharmony_ci *
19728c2ecf20Sopenharmony_ci * If the value tree grew, it obviously didn't grow enough for the
19738c2ecf20Sopenharmony_ci * new entry.  We're not going to try and reclaim those clusters either.
19748c2ecf20Sopenharmony_ci * If there was already an external value there (orig_clusters != 0),
19758c2ecf20Sopenharmony_ci * the new clusters are attached safely and we can just leave the old
19768c2ecf20Sopenharmony_ci * value in place.  If there was no external value there, we remove
19778c2ecf20Sopenharmony_ci * the entry.
19788c2ecf20Sopenharmony_ci *
19798c2ecf20Sopenharmony_ci * This way, the xattr block we store in the journal will be consistent.
19808c2ecf20Sopenharmony_ci * If the size change broke because of the journal, no changes will hit
19818c2ecf20Sopenharmony_ci * disk anyway.
19828c2ecf20Sopenharmony_ci */
19838c2ecf20Sopenharmony_cistatic void ocfs2_xa_cleanup_value_truncate(struct ocfs2_xa_loc *loc,
19848c2ecf20Sopenharmony_ci					    const char *what,
19858c2ecf20Sopenharmony_ci					    unsigned int orig_clusters)
19868c2ecf20Sopenharmony_ci{
19878c2ecf20Sopenharmony_ci	unsigned int new_clusters = ocfs2_xa_value_clusters(loc);
19888c2ecf20Sopenharmony_ci	char *nameval_buf = ocfs2_xa_offset_pointer(loc,
19898c2ecf20Sopenharmony_ci				le16_to_cpu(loc->xl_entry->xe_name_offset));
19908c2ecf20Sopenharmony_ci
19918c2ecf20Sopenharmony_ci	if (new_clusters < orig_clusters) {
19928c2ecf20Sopenharmony_ci		mlog(ML_ERROR,
19938c2ecf20Sopenharmony_ci		     "Partial truncate while %s xattr %.*s.  Leaking "
19948c2ecf20Sopenharmony_ci		     "%u clusters and removing the entry\n",
19958c2ecf20Sopenharmony_ci		     what, loc->xl_entry->xe_name_len, nameval_buf,
19968c2ecf20Sopenharmony_ci		     orig_clusters - new_clusters);
19978c2ecf20Sopenharmony_ci		ocfs2_xa_remove_entry(loc);
19988c2ecf20Sopenharmony_ci	} else if (!orig_clusters) {
19998c2ecf20Sopenharmony_ci		mlog(ML_ERROR,
20008c2ecf20Sopenharmony_ci		     "Unable to allocate an external value for xattr "
20018c2ecf20Sopenharmony_ci		     "%.*s safely.  Leaking %u clusters and removing the "
20028c2ecf20Sopenharmony_ci		     "entry\n",
20038c2ecf20Sopenharmony_ci		     loc->xl_entry->xe_name_len, nameval_buf,
20048c2ecf20Sopenharmony_ci		     new_clusters - orig_clusters);
20058c2ecf20Sopenharmony_ci		ocfs2_xa_remove_entry(loc);
20068c2ecf20Sopenharmony_ci	} else if (new_clusters > orig_clusters)
20078c2ecf20Sopenharmony_ci		mlog(ML_ERROR,
20088c2ecf20Sopenharmony_ci		     "Unable to grow xattr %.*s safely.  %u new clusters "
20098c2ecf20Sopenharmony_ci		     "have been added, but the value will not be "
20108c2ecf20Sopenharmony_ci		     "modified\n",
20118c2ecf20Sopenharmony_ci		     loc->xl_entry->xe_name_len, nameval_buf,
20128c2ecf20Sopenharmony_ci		     new_clusters - orig_clusters);
20138c2ecf20Sopenharmony_ci}
20148c2ecf20Sopenharmony_ci
20158c2ecf20Sopenharmony_cistatic int ocfs2_xa_remove(struct ocfs2_xa_loc *loc,
20168c2ecf20Sopenharmony_ci			   struct ocfs2_xattr_set_ctxt *ctxt)
20178c2ecf20Sopenharmony_ci{
20188c2ecf20Sopenharmony_ci	int rc = 0;
20198c2ecf20Sopenharmony_ci	unsigned int orig_clusters;
20208c2ecf20Sopenharmony_ci
20218c2ecf20Sopenharmony_ci	if (!ocfs2_xattr_is_local(loc->xl_entry)) {
20228c2ecf20Sopenharmony_ci		orig_clusters = ocfs2_xa_value_clusters(loc);
20238c2ecf20Sopenharmony_ci		rc = ocfs2_xa_value_truncate(loc, 0, ctxt);
20248c2ecf20Sopenharmony_ci		if (rc) {
20258c2ecf20Sopenharmony_ci			mlog_errno(rc);
20268c2ecf20Sopenharmony_ci			/*
20278c2ecf20Sopenharmony_ci			 * Since this is remove, we can return 0 if
20288c2ecf20Sopenharmony_ci			 * ocfs2_xa_cleanup_value_truncate() is going to
20298c2ecf20Sopenharmony_ci			 * wipe the entry anyway.  So we check the
20308c2ecf20Sopenharmony_ci			 * cluster count as well.
20318c2ecf20Sopenharmony_ci			 */
20328c2ecf20Sopenharmony_ci			if (orig_clusters != ocfs2_xa_value_clusters(loc))
20338c2ecf20Sopenharmony_ci				rc = 0;
20348c2ecf20Sopenharmony_ci			ocfs2_xa_cleanup_value_truncate(loc, "removing",
20358c2ecf20Sopenharmony_ci							orig_clusters);
20368c2ecf20Sopenharmony_ci			if (rc)
20378c2ecf20Sopenharmony_ci				goto out;
20388c2ecf20Sopenharmony_ci		}
20398c2ecf20Sopenharmony_ci	}
20408c2ecf20Sopenharmony_ci
20418c2ecf20Sopenharmony_ci	ocfs2_xa_remove_entry(loc);
20428c2ecf20Sopenharmony_ci
20438c2ecf20Sopenharmony_ciout:
20448c2ecf20Sopenharmony_ci	return rc;
20458c2ecf20Sopenharmony_ci}
20468c2ecf20Sopenharmony_ci
20478c2ecf20Sopenharmony_cistatic void ocfs2_xa_install_value_root(struct ocfs2_xa_loc *loc)
20488c2ecf20Sopenharmony_ci{
20498c2ecf20Sopenharmony_ci	int name_size = OCFS2_XATTR_SIZE(loc->xl_entry->xe_name_len);
20508c2ecf20Sopenharmony_ci	char *nameval_buf;
20518c2ecf20Sopenharmony_ci
20528c2ecf20Sopenharmony_ci	nameval_buf = ocfs2_xa_offset_pointer(loc,
20538c2ecf20Sopenharmony_ci				le16_to_cpu(loc->xl_entry->xe_name_offset));
20548c2ecf20Sopenharmony_ci	memcpy(nameval_buf + name_size, &def_xv, OCFS2_XATTR_ROOT_SIZE);
20558c2ecf20Sopenharmony_ci}
20568c2ecf20Sopenharmony_ci
20578c2ecf20Sopenharmony_ci/*
20588c2ecf20Sopenharmony_ci * Take an existing entry and make it ready for the new value.  This
20598c2ecf20Sopenharmony_ci * won't allocate space, but it may free space.  It should be ready for
20608c2ecf20Sopenharmony_ci * ocfs2_xa_prepare_entry() to finish the work.
20618c2ecf20Sopenharmony_ci */
20628c2ecf20Sopenharmony_cistatic int ocfs2_xa_reuse_entry(struct ocfs2_xa_loc *loc,
20638c2ecf20Sopenharmony_ci				struct ocfs2_xattr_info *xi,
20648c2ecf20Sopenharmony_ci				struct ocfs2_xattr_set_ctxt *ctxt)
20658c2ecf20Sopenharmony_ci{
20668c2ecf20Sopenharmony_ci	int rc = 0;
20678c2ecf20Sopenharmony_ci	int name_size = OCFS2_XATTR_SIZE(xi->xi_name_len);
20688c2ecf20Sopenharmony_ci	unsigned int orig_clusters;
20698c2ecf20Sopenharmony_ci	char *nameval_buf;
20708c2ecf20Sopenharmony_ci	int xe_local = ocfs2_xattr_is_local(loc->xl_entry);
20718c2ecf20Sopenharmony_ci	int xi_local = xi->xi_value_len <= OCFS2_XATTR_INLINE_SIZE;
20728c2ecf20Sopenharmony_ci
20738c2ecf20Sopenharmony_ci	BUG_ON(OCFS2_XATTR_SIZE(loc->xl_entry->xe_name_len) !=
20748c2ecf20Sopenharmony_ci	       name_size);
20758c2ecf20Sopenharmony_ci
20768c2ecf20Sopenharmony_ci	nameval_buf = ocfs2_xa_offset_pointer(loc,
20778c2ecf20Sopenharmony_ci				le16_to_cpu(loc->xl_entry->xe_name_offset));
20788c2ecf20Sopenharmony_ci	if (xe_local) {
20798c2ecf20Sopenharmony_ci		memset(nameval_buf + name_size, 0,
20808c2ecf20Sopenharmony_ci		       namevalue_size_xe(loc->xl_entry) - name_size);
20818c2ecf20Sopenharmony_ci		if (!xi_local)
20828c2ecf20Sopenharmony_ci			ocfs2_xa_install_value_root(loc);
20838c2ecf20Sopenharmony_ci	} else {
20848c2ecf20Sopenharmony_ci		orig_clusters = ocfs2_xa_value_clusters(loc);
20858c2ecf20Sopenharmony_ci		if (xi_local) {
20868c2ecf20Sopenharmony_ci			rc = ocfs2_xa_value_truncate(loc, 0, ctxt);
20878c2ecf20Sopenharmony_ci			if (rc < 0)
20888c2ecf20Sopenharmony_ci				mlog_errno(rc);
20898c2ecf20Sopenharmony_ci			else
20908c2ecf20Sopenharmony_ci				memset(nameval_buf + name_size, 0,
20918c2ecf20Sopenharmony_ci				       namevalue_size_xe(loc->xl_entry) -
20928c2ecf20Sopenharmony_ci				       name_size);
20938c2ecf20Sopenharmony_ci		} else if (le64_to_cpu(loc->xl_entry->xe_value_size) >
20948c2ecf20Sopenharmony_ci			   xi->xi_value_len) {
20958c2ecf20Sopenharmony_ci			rc = ocfs2_xa_value_truncate(loc, xi->xi_value_len,
20968c2ecf20Sopenharmony_ci						     ctxt);
20978c2ecf20Sopenharmony_ci			if (rc < 0)
20988c2ecf20Sopenharmony_ci				mlog_errno(rc);
20998c2ecf20Sopenharmony_ci		}
21008c2ecf20Sopenharmony_ci
21018c2ecf20Sopenharmony_ci		if (rc) {
21028c2ecf20Sopenharmony_ci			ocfs2_xa_cleanup_value_truncate(loc, "reusing",
21038c2ecf20Sopenharmony_ci							orig_clusters);
21048c2ecf20Sopenharmony_ci			goto out;
21058c2ecf20Sopenharmony_ci		}
21068c2ecf20Sopenharmony_ci	}
21078c2ecf20Sopenharmony_ci
21088c2ecf20Sopenharmony_ci	loc->xl_entry->xe_value_size = cpu_to_le64(xi->xi_value_len);
21098c2ecf20Sopenharmony_ci	ocfs2_xattr_set_local(loc->xl_entry, xi_local);
21108c2ecf20Sopenharmony_ci
21118c2ecf20Sopenharmony_ciout:
21128c2ecf20Sopenharmony_ci	return rc;
21138c2ecf20Sopenharmony_ci}
21148c2ecf20Sopenharmony_ci
21158c2ecf20Sopenharmony_ci/*
21168c2ecf20Sopenharmony_ci * Prepares loc->xl_entry to receive the new xattr.  This includes
21178c2ecf20Sopenharmony_ci * properly setting up the name+value pair region.  If loc->xl_entry
21188c2ecf20Sopenharmony_ci * already exists, it will take care of modifying it appropriately.
21198c2ecf20Sopenharmony_ci *
21208c2ecf20Sopenharmony_ci * Note that this modifies the data.  You did journal_access already,
21218c2ecf20Sopenharmony_ci * right?
21228c2ecf20Sopenharmony_ci */
21238c2ecf20Sopenharmony_cistatic int ocfs2_xa_prepare_entry(struct ocfs2_xa_loc *loc,
21248c2ecf20Sopenharmony_ci				  struct ocfs2_xattr_info *xi,
21258c2ecf20Sopenharmony_ci				  u32 name_hash,
21268c2ecf20Sopenharmony_ci				  struct ocfs2_xattr_set_ctxt *ctxt)
21278c2ecf20Sopenharmony_ci{
21288c2ecf20Sopenharmony_ci	int rc = 0;
21298c2ecf20Sopenharmony_ci	unsigned int orig_clusters;
21308c2ecf20Sopenharmony_ci	__le64 orig_value_size = 0;
21318c2ecf20Sopenharmony_ci
21328c2ecf20Sopenharmony_ci	rc = ocfs2_xa_check_space(loc, xi);
21338c2ecf20Sopenharmony_ci	if (rc)
21348c2ecf20Sopenharmony_ci		goto out;
21358c2ecf20Sopenharmony_ci
21368c2ecf20Sopenharmony_ci	if (loc->xl_entry) {
21378c2ecf20Sopenharmony_ci		if (ocfs2_xa_can_reuse_entry(loc, xi)) {
21388c2ecf20Sopenharmony_ci			orig_value_size = loc->xl_entry->xe_value_size;
21398c2ecf20Sopenharmony_ci			rc = ocfs2_xa_reuse_entry(loc, xi, ctxt);
21408c2ecf20Sopenharmony_ci			if (rc)
21418c2ecf20Sopenharmony_ci				goto out;
21428c2ecf20Sopenharmony_ci			goto alloc_value;
21438c2ecf20Sopenharmony_ci		}
21448c2ecf20Sopenharmony_ci
21458c2ecf20Sopenharmony_ci		if (!ocfs2_xattr_is_local(loc->xl_entry)) {
21468c2ecf20Sopenharmony_ci			orig_clusters = ocfs2_xa_value_clusters(loc);
21478c2ecf20Sopenharmony_ci			rc = ocfs2_xa_value_truncate(loc, 0, ctxt);
21488c2ecf20Sopenharmony_ci			if (rc) {
21498c2ecf20Sopenharmony_ci				mlog_errno(rc);
21508c2ecf20Sopenharmony_ci				ocfs2_xa_cleanup_value_truncate(loc,
21518c2ecf20Sopenharmony_ci								"overwriting",
21528c2ecf20Sopenharmony_ci								orig_clusters);
21538c2ecf20Sopenharmony_ci				goto out;
21548c2ecf20Sopenharmony_ci			}
21558c2ecf20Sopenharmony_ci		}
21568c2ecf20Sopenharmony_ci		ocfs2_xa_wipe_namevalue(loc);
21578c2ecf20Sopenharmony_ci	} else
21588c2ecf20Sopenharmony_ci		ocfs2_xa_add_entry(loc, name_hash);
21598c2ecf20Sopenharmony_ci
21608c2ecf20Sopenharmony_ci	/*
21618c2ecf20Sopenharmony_ci	 * If we get here, we have a blank entry.  Fill it.  We grow our
21628c2ecf20Sopenharmony_ci	 * name+value pair back from the end.
21638c2ecf20Sopenharmony_ci	 */
21648c2ecf20Sopenharmony_ci	ocfs2_xa_add_namevalue(loc, xi);
21658c2ecf20Sopenharmony_ci	if (xi->xi_value_len > OCFS2_XATTR_INLINE_SIZE)
21668c2ecf20Sopenharmony_ci		ocfs2_xa_install_value_root(loc);
21678c2ecf20Sopenharmony_ci
21688c2ecf20Sopenharmony_cialloc_value:
21698c2ecf20Sopenharmony_ci	if (xi->xi_value_len > OCFS2_XATTR_INLINE_SIZE) {
21708c2ecf20Sopenharmony_ci		orig_clusters = ocfs2_xa_value_clusters(loc);
21718c2ecf20Sopenharmony_ci		rc = ocfs2_xa_value_truncate(loc, xi->xi_value_len, ctxt);
21728c2ecf20Sopenharmony_ci		if (rc < 0) {
21738c2ecf20Sopenharmony_ci			ctxt->set_abort = 1;
21748c2ecf20Sopenharmony_ci			ocfs2_xa_cleanup_value_truncate(loc, "growing",
21758c2ecf20Sopenharmony_ci							orig_clusters);
21768c2ecf20Sopenharmony_ci			/*
21778c2ecf20Sopenharmony_ci			 * If we were growing an existing value,
21788c2ecf20Sopenharmony_ci			 * ocfs2_xa_cleanup_value_truncate() won't remove
21798c2ecf20Sopenharmony_ci			 * the entry. We need to restore the original value
21808c2ecf20Sopenharmony_ci			 * size.
21818c2ecf20Sopenharmony_ci			 */
21828c2ecf20Sopenharmony_ci			if (loc->xl_entry) {
21838c2ecf20Sopenharmony_ci				BUG_ON(!orig_value_size);
21848c2ecf20Sopenharmony_ci				loc->xl_entry->xe_value_size = orig_value_size;
21858c2ecf20Sopenharmony_ci			}
21868c2ecf20Sopenharmony_ci			mlog_errno(rc);
21878c2ecf20Sopenharmony_ci		}
21888c2ecf20Sopenharmony_ci	}
21898c2ecf20Sopenharmony_ci
21908c2ecf20Sopenharmony_ciout:
21918c2ecf20Sopenharmony_ci	return rc;
21928c2ecf20Sopenharmony_ci}
21938c2ecf20Sopenharmony_ci
21948c2ecf20Sopenharmony_ci/*
21958c2ecf20Sopenharmony_ci * Store the value portion of the name+value pair.  This will skip
21968c2ecf20Sopenharmony_ci * values that are stored externally.  Their tree roots were set up
21978c2ecf20Sopenharmony_ci * by ocfs2_xa_prepare_entry().
21988c2ecf20Sopenharmony_ci */
21998c2ecf20Sopenharmony_cistatic int ocfs2_xa_store_value(struct ocfs2_xa_loc *loc,
22008c2ecf20Sopenharmony_ci				struct ocfs2_xattr_info *xi,
22018c2ecf20Sopenharmony_ci				struct ocfs2_xattr_set_ctxt *ctxt)
22028c2ecf20Sopenharmony_ci{
22038c2ecf20Sopenharmony_ci	int rc = 0;
22048c2ecf20Sopenharmony_ci	int nameval_offset = le16_to_cpu(loc->xl_entry->xe_name_offset);
22058c2ecf20Sopenharmony_ci	int name_size = OCFS2_XATTR_SIZE(xi->xi_name_len);
22068c2ecf20Sopenharmony_ci	char *nameval_buf;
22078c2ecf20Sopenharmony_ci	struct ocfs2_xattr_value_buf vb;
22088c2ecf20Sopenharmony_ci
22098c2ecf20Sopenharmony_ci	nameval_buf = ocfs2_xa_offset_pointer(loc, nameval_offset);
22108c2ecf20Sopenharmony_ci	if (xi->xi_value_len > OCFS2_XATTR_INLINE_SIZE) {
22118c2ecf20Sopenharmony_ci		ocfs2_xa_fill_value_buf(loc, &vb);
22128c2ecf20Sopenharmony_ci		rc = __ocfs2_xattr_set_value_outside(loc->xl_inode,
22138c2ecf20Sopenharmony_ci						     ctxt->handle, &vb,
22148c2ecf20Sopenharmony_ci						     xi->xi_value,
22158c2ecf20Sopenharmony_ci						     xi->xi_value_len);
22168c2ecf20Sopenharmony_ci	} else
22178c2ecf20Sopenharmony_ci		memcpy(nameval_buf + name_size, xi->xi_value, xi->xi_value_len);
22188c2ecf20Sopenharmony_ci
22198c2ecf20Sopenharmony_ci	return rc;
22208c2ecf20Sopenharmony_ci}
22218c2ecf20Sopenharmony_ci
22228c2ecf20Sopenharmony_cistatic int ocfs2_xa_set(struct ocfs2_xa_loc *loc,
22238c2ecf20Sopenharmony_ci			struct ocfs2_xattr_info *xi,
22248c2ecf20Sopenharmony_ci			struct ocfs2_xattr_set_ctxt *ctxt)
22258c2ecf20Sopenharmony_ci{
22268c2ecf20Sopenharmony_ci	int ret;
22278c2ecf20Sopenharmony_ci	u32 name_hash = ocfs2_xattr_name_hash(loc->xl_inode, xi->xi_name,
22288c2ecf20Sopenharmony_ci					      xi->xi_name_len);
22298c2ecf20Sopenharmony_ci
22308c2ecf20Sopenharmony_ci	ret = ocfs2_xa_journal_access(ctxt->handle, loc,
22318c2ecf20Sopenharmony_ci				      OCFS2_JOURNAL_ACCESS_WRITE);
22328c2ecf20Sopenharmony_ci	if (ret) {
22338c2ecf20Sopenharmony_ci		mlog_errno(ret);
22348c2ecf20Sopenharmony_ci		goto out;
22358c2ecf20Sopenharmony_ci	}
22368c2ecf20Sopenharmony_ci
22378c2ecf20Sopenharmony_ci	/*
22388c2ecf20Sopenharmony_ci	 * From here on out, everything is going to modify the buffer a
22398c2ecf20Sopenharmony_ci	 * little.  Errors are going to leave the xattr header in a
22408c2ecf20Sopenharmony_ci	 * sane state.  Thus, even with errors we dirty the sucker.
22418c2ecf20Sopenharmony_ci	 */
22428c2ecf20Sopenharmony_ci
22438c2ecf20Sopenharmony_ci	/* Don't worry, we are never called with !xi_value and !xl_entry */
22448c2ecf20Sopenharmony_ci	if (!xi->xi_value) {
22458c2ecf20Sopenharmony_ci		ret = ocfs2_xa_remove(loc, ctxt);
22468c2ecf20Sopenharmony_ci		goto out_dirty;
22478c2ecf20Sopenharmony_ci	}
22488c2ecf20Sopenharmony_ci
22498c2ecf20Sopenharmony_ci	ret = ocfs2_xa_prepare_entry(loc, xi, name_hash, ctxt);
22508c2ecf20Sopenharmony_ci	if (ret) {
22518c2ecf20Sopenharmony_ci		if (ret != -ENOSPC)
22528c2ecf20Sopenharmony_ci			mlog_errno(ret);
22538c2ecf20Sopenharmony_ci		goto out_dirty;
22548c2ecf20Sopenharmony_ci	}
22558c2ecf20Sopenharmony_ci
22568c2ecf20Sopenharmony_ci	ret = ocfs2_xa_store_value(loc, xi, ctxt);
22578c2ecf20Sopenharmony_ci	if (ret)
22588c2ecf20Sopenharmony_ci		mlog_errno(ret);
22598c2ecf20Sopenharmony_ci
22608c2ecf20Sopenharmony_ciout_dirty:
22618c2ecf20Sopenharmony_ci	ocfs2_xa_journal_dirty(ctxt->handle, loc);
22628c2ecf20Sopenharmony_ci
22638c2ecf20Sopenharmony_ciout:
22648c2ecf20Sopenharmony_ci	return ret;
22658c2ecf20Sopenharmony_ci}
22668c2ecf20Sopenharmony_ci
22678c2ecf20Sopenharmony_cistatic void ocfs2_init_dinode_xa_loc(struct ocfs2_xa_loc *loc,
22688c2ecf20Sopenharmony_ci				     struct inode *inode,
22698c2ecf20Sopenharmony_ci				     struct buffer_head *bh,
22708c2ecf20Sopenharmony_ci				     struct ocfs2_xattr_entry *entry)
22718c2ecf20Sopenharmony_ci{
22728c2ecf20Sopenharmony_ci	struct ocfs2_dinode *di = (struct ocfs2_dinode *)bh->b_data;
22738c2ecf20Sopenharmony_ci
22748c2ecf20Sopenharmony_ci	BUG_ON(!(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_XATTR_FL));
22758c2ecf20Sopenharmony_ci
22768c2ecf20Sopenharmony_ci	loc->xl_inode = inode;
22778c2ecf20Sopenharmony_ci	loc->xl_ops = &ocfs2_xa_block_loc_ops;
22788c2ecf20Sopenharmony_ci	loc->xl_storage = bh;
22798c2ecf20Sopenharmony_ci	loc->xl_entry = entry;
22808c2ecf20Sopenharmony_ci	loc->xl_size = le16_to_cpu(di->i_xattr_inline_size);
22818c2ecf20Sopenharmony_ci	loc->xl_header =
22828c2ecf20Sopenharmony_ci		(struct ocfs2_xattr_header *)(bh->b_data + bh->b_size -
22838c2ecf20Sopenharmony_ci					      loc->xl_size);
22848c2ecf20Sopenharmony_ci}
22858c2ecf20Sopenharmony_ci
22868c2ecf20Sopenharmony_cistatic void ocfs2_init_xattr_block_xa_loc(struct ocfs2_xa_loc *loc,
22878c2ecf20Sopenharmony_ci					  struct inode *inode,
22888c2ecf20Sopenharmony_ci					  struct buffer_head *bh,
22898c2ecf20Sopenharmony_ci					  struct ocfs2_xattr_entry *entry)
22908c2ecf20Sopenharmony_ci{
22918c2ecf20Sopenharmony_ci	struct ocfs2_xattr_block *xb =
22928c2ecf20Sopenharmony_ci		(struct ocfs2_xattr_block *)bh->b_data;
22938c2ecf20Sopenharmony_ci
22948c2ecf20Sopenharmony_ci	BUG_ON(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED);
22958c2ecf20Sopenharmony_ci
22968c2ecf20Sopenharmony_ci	loc->xl_inode = inode;
22978c2ecf20Sopenharmony_ci	loc->xl_ops = &ocfs2_xa_block_loc_ops;
22988c2ecf20Sopenharmony_ci	loc->xl_storage = bh;
22998c2ecf20Sopenharmony_ci	loc->xl_header = &(xb->xb_attrs.xb_header);
23008c2ecf20Sopenharmony_ci	loc->xl_entry = entry;
23018c2ecf20Sopenharmony_ci	loc->xl_size = bh->b_size - offsetof(struct ocfs2_xattr_block,
23028c2ecf20Sopenharmony_ci					     xb_attrs.xb_header);
23038c2ecf20Sopenharmony_ci}
23048c2ecf20Sopenharmony_ci
23058c2ecf20Sopenharmony_cistatic void ocfs2_init_xattr_bucket_xa_loc(struct ocfs2_xa_loc *loc,
23068c2ecf20Sopenharmony_ci					   struct ocfs2_xattr_bucket *bucket,
23078c2ecf20Sopenharmony_ci					   struct ocfs2_xattr_entry *entry)
23088c2ecf20Sopenharmony_ci{
23098c2ecf20Sopenharmony_ci	loc->xl_inode = bucket->bu_inode;
23108c2ecf20Sopenharmony_ci	loc->xl_ops = &ocfs2_xa_bucket_loc_ops;
23118c2ecf20Sopenharmony_ci	loc->xl_storage = bucket;
23128c2ecf20Sopenharmony_ci	loc->xl_header = bucket_xh(bucket);
23138c2ecf20Sopenharmony_ci	loc->xl_entry = entry;
23148c2ecf20Sopenharmony_ci	loc->xl_size = OCFS2_XATTR_BUCKET_SIZE;
23158c2ecf20Sopenharmony_ci}
23168c2ecf20Sopenharmony_ci
23178c2ecf20Sopenharmony_ci/*
23188c2ecf20Sopenharmony_ci * In xattr remove, if it is stored outside and refcounted, we may have
23198c2ecf20Sopenharmony_ci * the chance to split the refcount tree. So need the allocators.
23208c2ecf20Sopenharmony_ci */
23218c2ecf20Sopenharmony_cistatic int ocfs2_lock_xattr_remove_allocators(struct inode *inode,
23228c2ecf20Sopenharmony_ci					struct ocfs2_xattr_value_root *xv,
23238c2ecf20Sopenharmony_ci					struct ocfs2_caching_info *ref_ci,
23248c2ecf20Sopenharmony_ci					struct buffer_head *ref_root_bh,
23258c2ecf20Sopenharmony_ci					struct ocfs2_alloc_context **meta_ac,
23268c2ecf20Sopenharmony_ci					int *ref_credits)
23278c2ecf20Sopenharmony_ci{
23288c2ecf20Sopenharmony_ci	int ret, meta_add = 0;
23298c2ecf20Sopenharmony_ci	u32 p_cluster, num_clusters;
23308c2ecf20Sopenharmony_ci	unsigned int ext_flags;
23318c2ecf20Sopenharmony_ci
23328c2ecf20Sopenharmony_ci	*ref_credits = 0;
23338c2ecf20Sopenharmony_ci	ret = ocfs2_xattr_get_clusters(inode, 0, &p_cluster,
23348c2ecf20Sopenharmony_ci				       &num_clusters,
23358c2ecf20Sopenharmony_ci				       &xv->xr_list,
23368c2ecf20Sopenharmony_ci				       &ext_flags);
23378c2ecf20Sopenharmony_ci	if (ret) {
23388c2ecf20Sopenharmony_ci		mlog_errno(ret);
23398c2ecf20Sopenharmony_ci		goto out;
23408c2ecf20Sopenharmony_ci	}
23418c2ecf20Sopenharmony_ci
23428c2ecf20Sopenharmony_ci	if (!(ext_flags & OCFS2_EXT_REFCOUNTED))
23438c2ecf20Sopenharmony_ci		goto out;
23448c2ecf20Sopenharmony_ci
23458c2ecf20Sopenharmony_ci	ret = ocfs2_refcounted_xattr_delete_need(inode, ref_ci,
23468c2ecf20Sopenharmony_ci						 ref_root_bh, xv,
23478c2ecf20Sopenharmony_ci						 &meta_add, ref_credits);
23488c2ecf20Sopenharmony_ci	if (ret) {
23498c2ecf20Sopenharmony_ci		mlog_errno(ret);
23508c2ecf20Sopenharmony_ci		goto out;
23518c2ecf20Sopenharmony_ci	}
23528c2ecf20Sopenharmony_ci
23538c2ecf20Sopenharmony_ci	ret = ocfs2_reserve_new_metadata_blocks(OCFS2_SB(inode->i_sb),
23548c2ecf20Sopenharmony_ci						meta_add, meta_ac);
23558c2ecf20Sopenharmony_ci	if (ret)
23568c2ecf20Sopenharmony_ci		mlog_errno(ret);
23578c2ecf20Sopenharmony_ci
23588c2ecf20Sopenharmony_ciout:
23598c2ecf20Sopenharmony_ci	return ret;
23608c2ecf20Sopenharmony_ci}
23618c2ecf20Sopenharmony_ci
23628c2ecf20Sopenharmony_cistatic int ocfs2_remove_value_outside(struct inode*inode,
23638c2ecf20Sopenharmony_ci				      struct ocfs2_xattr_value_buf *vb,
23648c2ecf20Sopenharmony_ci				      struct ocfs2_xattr_header *header,
23658c2ecf20Sopenharmony_ci				      struct ocfs2_caching_info *ref_ci,
23668c2ecf20Sopenharmony_ci				      struct buffer_head *ref_root_bh)
23678c2ecf20Sopenharmony_ci{
23688c2ecf20Sopenharmony_ci	int ret = 0, i, ref_credits;
23698c2ecf20Sopenharmony_ci	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
23708c2ecf20Sopenharmony_ci	struct ocfs2_xattr_set_ctxt ctxt = { NULL, NULL, };
23718c2ecf20Sopenharmony_ci	void *val;
23728c2ecf20Sopenharmony_ci
23738c2ecf20Sopenharmony_ci	ocfs2_init_dealloc_ctxt(&ctxt.dealloc);
23748c2ecf20Sopenharmony_ci
23758c2ecf20Sopenharmony_ci	for (i = 0; i < le16_to_cpu(header->xh_count); i++) {
23768c2ecf20Sopenharmony_ci		struct ocfs2_xattr_entry *entry = &header->xh_entries[i];
23778c2ecf20Sopenharmony_ci
23788c2ecf20Sopenharmony_ci		if (ocfs2_xattr_is_local(entry))
23798c2ecf20Sopenharmony_ci			continue;
23808c2ecf20Sopenharmony_ci
23818c2ecf20Sopenharmony_ci		val = (void *)header +
23828c2ecf20Sopenharmony_ci			le16_to_cpu(entry->xe_name_offset);
23838c2ecf20Sopenharmony_ci		vb->vb_xv = (struct ocfs2_xattr_value_root *)
23848c2ecf20Sopenharmony_ci			(val + OCFS2_XATTR_SIZE(entry->xe_name_len));
23858c2ecf20Sopenharmony_ci
23868c2ecf20Sopenharmony_ci		ret = ocfs2_lock_xattr_remove_allocators(inode, vb->vb_xv,
23878c2ecf20Sopenharmony_ci							 ref_ci, ref_root_bh,
23888c2ecf20Sopenharmony_ci							 &ctxt.meta_ac,
23898c2ecf20Sopenharmony_ci							 &ref_credits);
23908c2ecf20Sopenharmony_ci
23918c2ecf20Sopenharmony_ci		ctxt.handle = ocfs2_start_trans(osb, ref_credits +
23928c2ecf20Sopenharmony_ci					ocfs2_remove_extent_credits(osb->sb));
23938c2ecf20Sopenharmony_ci		if (IS_ERR(ctxt.handle)) {
23948c2ecf20Sopenharmony_ci			ret = PTR_ERR(ctxt.handle);
23958c2ecf20Sopenharmony_ci			mlog_errno(ret);
23968c2ecf20Sopenharmony_ci			break;
23978c2ecf20Sopenharmony_ci		}
23988c2ecf20Sopenharmony_ci
23998c2ecf20Sopenharmony_ci		ret = ocfs2_xattr_value_truncate(inode, vb, 0, &ctxt);
24008c2ecf20Sopenharmony_ci
24018c2ecf20Sopenharmony_ci		ocfs2_commit_trans(osb, ctxt.handle);
24028c2ecf20Sopenharmony_ci		if (ctxt.meta_ac) {
24038c2ecf20Sopenharmony_ci			ocfs2_free_alloc_context(ctxt.meta_ac);
24048c2ecf20Sopenharmony_ci			ctxt.meta_ac = NULL;
24058c2ecf20Sopenharmony_ci		}
24068c2ecf20Sopenharmony_ci
24078c2ecf20Sopenharmony_ci		if (ret < 0) {
24088c2ecf20Sopenharmony_ci			mlog_errno(ret);
24098c2ecf20Sopenharmony_ci			break;
24108c2ecf20Sopenharmony_ci		}
24118c2ecf20Sopenharmony_ci
24128c2ecf20Sopenharmony_ci	}
24138c2ecf20Sopenharmony_ci
24148c2ecf20Sopenharmony_ci	if (ctxt.meta_ac)
24158c2ecf20Sopenharmony_ci		ocfs2_free_alloc_context(ctxt.meta_ac);
24168c2ecf20Sopenharmony_ci	ocfs2_schedule_truncate_log_flush(osb, 1);
24178c2ecf20Sopenharmony_ci	ocfs2_run_deallocs(osb, &ctxt.dealloc);
24188c2ecf20Sopenharmony_ci	return ret;
24198c2ecf20Sopenharmony_ci}
24208c2ecf20Sopenharmony_ci
24218c2ecf20Sopenharmony_cistatic int ocfs2_xattr_ibody_remove(struct inode *inode,
24228c2ecf20Sopenharmony_ci				    struct buffer_head *di_bh,
24238c2ecf20Sopenharmony_ci				    struct ocfs2_caching_info *ref_ci,
24248c2ecf20Sopenharmony_ci				    struct buffer_head *ref_root_bh)
24258c2ecf20Sopenharmony_ci{
24268c2ecf20Sopenharmony_ci
24278c2ecf20Sopenharmony_ci	struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
24288c2ecf20Sopenharmony_ci	struct ocfs2_xattr_header *header;
24298c2ecf20Sopenharmony_ci	int ret;
24308c2ecf20Sopenharmony_ci	struct ocfs2_xattr_value_buf vb = {
24318c2ecf20Sopenharmony_ci		.vb_bh = di_bh,
24328c2ecf20Sopenharmony_ci		.vb_access = ocfs2_journal_access_di,
24338c2ecf20Sopenharmony_ci	};
24348c2ecf20Sopenharmony_ci
24358c2ecf20Sopenharmony_ci	header = (struct ocfs2_xattr_header *)
24368c2ecf20Sopenharmony_ci		 ((void *)di + inode->i_sb->s_blocksize -
24378c2ecf20Sopenharmony_ci		 le16_to_cpu(di->i_xattr_inline_size));
24388c2ecf20Sopenharmony_ci
24398c2ecf20Sopenharmony_ci	ret = ocfs2_remove_value_outside(inode, &vb, header,
24408c2ecf20Sopenharmony_ci					 ref_ci, ref_root_bh);
24418c2ecf20Sopenharmony_ci
24428c2ecf20Sopenharmony_ci	return ret;
24438c2ecf20Sopenharmony_ci}
24448c2ecf20Sopenharmony_ci
24458c2ecf20Sopenharmony_cistruct ocfs2_rm_xattr_bucket_para {
24468c2ecf20Sopenharmony_ci	struct ocfs2_caching_info *ref_ci;
24478c2ecf20Sopenharmony_ci	struct buffer_head *ref_root_bh;
24488c2ecf20Sopenharmony_ci};
24498c2ecf20Sopenharmony_ci
24508c2ecf20Sopenharmony_cistatic int ocfs2_xattr_block_remove(struct inode *inode,
24518c2ecf20Sopenharmony_ci				    struct buffer_head *blk_bh,
24528c2ecf20Sopenharmony_ci				    struct ocfs2_caching_info *ref_ci,
24538c2ecf20Sopenharmony_ci				    struct buffer_head *ref_root_bh)
24548c2ecf20Sopenharmony_ci{
24558c2ecf20Sopenharmony_ci	struct ocfs2_xattr_block *xb;
24568c2ecf20Sopenharmony_ci	int ret = 0;
24578c2ecf20Sopenharmony_ci	struct ocfs2_xattr_value_buf vb = {
24588c2ecf20Sopenharmony_ci		.vb_bh = blk_bh,
24598c2ecf20Sopenharmony_ci		.vb_access = ocfs2_journal_access_xb,
24608c2ecf20Sopenharmony_ci	};
24618c2ecf20Sopenharmony_ci	struct ocfs2_rm_xattr_bucket_para args = {
24628c2ecf20Sopenharmony_ci		.ref_ci = ref_ci,
24638c2ecf20Sopenharmony_ci		.ref_root_bh = ref_root_bh,
24648c2ecf20Sopenharmony_ci	};
24658c2ecf20Sopenharmony_ci
24668c2ecf20Sopenharmony_ci	xb = (struct ocfs2_xattr_block *)blk_bh->b_data;
24678c2ecf20Sopenharmony_ci	if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) {
24688c2ecf20Sopenharmony_ci		struct ocfs2_xattr_header *header = &(xb->xb_attrs.xb_header);
24698c2ecf20Sopenharmony_ci		ret = ocfs2_remove_value_outside(inode, &vb, header,
24708c2ecf20Sopenharmony_ci						 ref_ci, ref_root_bh);
24718c2ecf20Sopenharmony_ci	} else
24728c2ecf20Sopenharmony_ci		ret = ocfs2_iterate_xattr_index_block(inode,
24738c2ecf20Sopenharmony_ci						blk_bh,
24748c2ecf20Sopenharmony_ci						ocfs2_rm_xattr_cluster,
24758c2ecf20Sopenharmony_ci						&args);
24768c2ecf20Sopenharmony_ci
24778c2ecf20Sopenharmony_ci	return ret;
24788c2ecf20Sopenharmony_ci}
24798c2ecf20Sopenharmony_ci
24808c2ecf20Sopenharmony_cistatic int ocfs2_xattr_free_block(struct inode *inode,
24818c2ecf20Sopenharmony_ci				  u64 block,
24828c2ecf20Sopenharmony_ci				  struct ocfs2_caching_info *ref_ci,
24838c2ecf20Sopenharmony_ci				  struct buffer_head *ref_root_bh)
24848c2ecf20Sopenharmony_ci{
24858c2ecf20Sopenharmony_ci	struct inode *xb_alloc_inode;
24868c2ecf20Sopenharmony_ci	struct buffer_head *xb_alloc_bh = NULL;
24878c2ecf20Sopenharmony_ci	struct buffer_head *blk_bh = NULL;
24888c2ecf20Sopenharmony_ci	struct ocfs2_xattr_block *xb;
24898c2ecf20Sopenharmony_ci	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
24908c2ecf20Sopenharmony_ci	handle_t *handle;
24918c2ecf20Sopenharmony_ci	int ret = 0;
24928c2ecf20Sopenharmony_ci	u64 blk, bg_blkno;
24938c2ecf20Sopenharmony_ci	u16 bit;
24948c2ecf20Sopenharmony_ci
24958c2ecf20Sopenharmony_ci	ret = ocfs2_read_xattr_block(inode, block, &blk_bh);
24968c2ecf20Sopenharmony_ci	if (ret < 0) {
24978c2ecf20Sopenharmony_ci		mlog_errno(ret);
24988c2ecf20Sopenharmony_ci		goto out;
24998c2ecf20Sopenharmony_ci	}
25008c2ecf20Sopenharmony_ci
25018c2ecf20Sopenharmony_ci	ret = ocfs2_xattr_block_remove(inode, blk_bh, ref_ci, ref_root_bh);
25028c2ecf20Sopenharmony_ci	if (ret < 0) {
25038c2ecf20Sopenharmony_ci		mlog_errno(ret);
25048c2ecf20Sopenharmony_ci		goto out;
25058c2ecf20Sopenharmony_ci	}
25068c2ecf20Sopenharmony_ci
25078c2ecf20Sopenharmony_ci	xb = (struct ocfs2_xattr_block *)blk_bh->b_data;
25088c2ecf20Sopenharmony_ci	blk = le64_to_cpu(xb->xb_blkno);
25098c2ecf20Sopenharmony_ci	bit = le16_to_cpu(xb->xb_suballoc_bit);
25108c2ecf20Sopenharmony_ci	if (xb->xb_suballoc_loc)
25118c2ecf20Sopenharmony_ci		bg_blkno = le64_to_cpu(xb->xb_suballoc_loc);
25128c2ecf20Sopenharmony_ci	else
25138c2ecf20Sopenharmony_ci		bg_blkno = ocfs2_which_suballoc_group(blk, bit);
25148c2ecf20Sopenharmony_ci
25158c2ecf20Sopenharmony_ci	xb_alloc_inode = ocfs2_get_system_file_inode(osb,
25168c2ecf20Sopenharmony_ci				EXTENT_ALLOC_SYSTEM_INODE,
25178c2ecf20Sopenharmony_ci				le16_to_cpu(xb->xb_suballoc_slot));
25188c2ecf20Sopenharmony_ci	if (!xb_alloc_inode) {
25198c2ecf20Sopenharmony_ci		ret = -ENOMEM;
25208c2ecf20Sopenharmony_ci		mlog_errno(ret);
25218c2ecf20Sopenharmony_ci		goto out;
25228c2ecf20Sopenharmony_ci	}
25238c2ecf20Sopenharmony_ci	inode_lock(xb_alloc_inode);
25248c2ecf20Sopenharmony_ci
25258c2ecf20Sopenharmony_ci	ret = ocfs2_inode_lock(xb_alloc_inode, &xb_alloc_bh, 1);
25268c2ecf20Sopenharmony_ci	if (ret < 0) {
25278c2ecf20Sopenharmony_ci		mlog_errno(ret);
25288c2ecf20Sopenharmony_ci		goto out_mutex;
25298c2ecf20Sopenharmony_ci	}
25308c2ecf20Sopenharmony_ci
25318c2ecf20Sopenharmony_ci	handle = ocfs2_start_trans(osb, OCFS2_SUBALLOC_FREE);
25328c2ecf20Sopenharmony_ci	if (IS_ERR(handle)) {
25338c2ecf20Sopenharmony_ci		ret = PTR_ERR(handle);
25348c2ecf20Sopenharmony_ci		mlog_errno(ret);
25358c2ecf20Sopenharmony_ci		goto out_unlock;
25368c2ecf20Sopenharmony_ci	}
25378c2ecf20Sopenharmony_ci
25388c2ecf20Sopenharmony_ci	ret = ocfs2_free_suballoc_bits(handle, xb_alloc_inode, xb_alloc_bh,
25398c2ecf20Sopenharmony_ci				       bit, bg_blkno, 1);
25408c2ecf20Sopenharmony_ci	if (ret < 0)
25418c2ecf20Sopenharmony_ci		mlog_errno(ret);
25428c2ecf20Sopenharmony_ci
25438c2ecf20Sopenharmony_ci	ocfs2_commit_trans(osb, handle);
25448c2ecf20Sopenharmony_ciout_unlock:
25458c2ecf20Sopenharmony_ci	ocfs2_inode_unlock(xb_alloc_inode, 1);
25468c2ecf20Sopenharmony_ci	brelse(xb_alloc_bh);
25478c2ecf20Sopenharmony_ciout_mutex:
25488c2ecf20Sopenharmony_ci	inode_unlock(xb_alloc_inode);
25498c2ecf20Sopenharmony_ci	iput(xb_alloc_inode);
25508c2ecf20Sopenharmony_ciout:
25518c2ecf20Sopenharmony_ci	brelse(blk_bh);
25528c2ecf20Sopenharmony_ci	return ret;
25538c2ecf20Sopenharmony_ci}
25548c2ecf20Sopenharmony_ci
25558c2ecf20Sopenharmony_ci/*
25568c2ecf20Sopenharmony_ci * ocfs2_xattr_remove()
25578c2ecf20Sopenharmony_ci *
25588c2ecf20Sopenharmony_ci * Free extended attribute resources associated with this inode.
25598c2ecf20Sopenharmony_ci */
25608c2ecf20Sopenharmony_ciint ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh)
25618c2ecf20Sopenharmony_ci{
25628c2ecf20Sopenharmony_ci	struct ocfs2_inode_info *oi = OCFS2_I(inode);
25638c2ecf20Sopenharmony_ci	struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
25648c2ecf20Sopenharmony_ci	struct ocfs2_refcount_tree *ref_tree = NULL;
25658c2ecf20Sopenharmony_ci	struct buffer_head *ref_root_bh = NULL;
25668c2ecf20Sopenharmony_ci	struct ocfs2_caching_info *ref_ci = NULL;
25678c2ecf20Sopenharmony_ci	handle_t *handle;
25688c2ecf20Sopenharmony_ci	int ret;
25698c2ecf20Sopenharmony_ci
25708c2ecf20Sopenharmony_ci	if (!ocfs2_supports_xattr(OCFS2_SB(inode->i_sb)))
25718c2ecf20Sopenharmony_ci		return 0;
25728c2ecf20Sopenharmony_ci
25738c2ecf20Sopenharmony_ci	if (!(oi->ip_dyn_features & OCFS2_HAS_XATTR_FL))
25748c2ecf20Sopenharmony_ci		return 0;
25758c2ecf20Sopenharmony_ci
25768c2ecf20Sopenharmony_ci	if (ocfs2_is_refcount_inode(inode)) {
25778c2ecf20Sopenharmony_ci		ret = ocfs2_lock_refcount_tree(OCFS2_SB(inode->i_sb),
25788c2ecf20Sopenharmony_ci					       le64_to_cpu(di->i_refcount_loc),
25798c2ecf20Sopenharmony_ci					       1, &ref_tree, &ref_root_bh);
25808c2ecf20Sopenharmony_ci		if (ret) {
25818c2ecf20Sopenharmony_ci			mlog_errno(ret);
25828c2ecf20Sopenharmony_ci			goto out;
25838c2ecf20Sopenharmony_ci		}
25848c2ecf20Sopenharmony_ci		ref_ci = &ref_tree->rf_ci;
25858c2ecf20Sopenharmony_ci
25868c2ecf20Sopenharmony_ci	}
25878c2ecf20Sopenharmony_ci
25888c2ecf20Sopenharmony_ci	if (oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL) {
25898c2ecf20Sopenharmony_ci		ret = ocfs2_xattr_ibody_remove(inode, di_bh,
25908c2ecf20Sopenharmony_ci					       ref_ci, ref_root_bh);
25918c2ecf20Sopenharmony_ci		if (ret < 0) {
25928c2ecf20Sopenharmony_ci			mlog_errno(ret);
25938c2ecf20Sopenharmony_ci			goto out;
25948c2ecf20Sopenharmony_ci		}
25958c2ecf20Sopenharmony_ci	}
25968c2ecf20Sopenharmony_ci
25978c2ecf20Sopenharmony_ci	if (di->i_xattr_loc) {
25988c2ecf20Sopenharmony_ci		ret = ocfs2_xattr_free_block(inode,
25998c2ecf20Sopenharmony_ci					     le64_to_cpu(di->i_xattr_loc),
26008c2ecf20Sopenharmony_ci					     ref_ci, ref_root_bh);
26018c2ecf20Sopenharmony_ci		if (ret < 0) {
26028c2ecf20Sopenharmony_ci			mlog_errno(ret);
26038c2ecf20Sopenharmony_ci			goto out;
26048c2ecf20Sopenharmony_ci		}
26058c2ecf20Sopenharmony_ci	}
26068c2ecf20Sopenharmony_ci
26078c2ecf20Sopenharmony_ci	handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)),
26088c2ecf20Sopenharmony_ci				   OCFS2_INODE_UPDATE_CREDITS);
26098c2ecf20Sopenharmony_ci	if (IS_ERR(handle)) {
26108c2ecf20Sopenharmony_ci		ret = PTR_ERR(handle);
26118c2ecf20Sopenharmony_ci		mlog_errno(ret);
26128c2ecf20Sopenharmony_ci		goto out;
26138c2ecf20Sopenharmony_ci	}
26148c2ecf20Sopenharmony_ci	ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh,
26158c2ecf20Sopenharmony_ci				      OCFS2_JOURNAL_ACCESS_WRITE);
26168c2ecf20Sopenharmony_ci	if (ret) {
26178c2ecf20Sopenharmony_ci		mlog_errno(ret);
26188c2ecf20Sopenharmony_ci		goto out_commit;
26198c2ecf20Sopenharmony_ci	}
26208c2ecf20Sopenharmony_ci
26218c2ecf20Sopenharmony_ci	di->i_xattr_loc = 0;
26228c2ecf20Sopenharmony_ci
26238c2ecf20Sopenharmony_ci	spin_lock(&oi->ip_lock);
26248c2ecf20Sopenharmony_ci	oi->ip_dyn_features &= ~(OCFS2_INLINE_XATTR_FL | OCFS2_HAS_XATTR_FL);
26258c2ecf20Sopenharmony_ci	di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features);
26268c2ecf20Sopenharmony_ci	spin_unlock(&oi->ip_lock);
26278c2ecf20Sopenharmony_ci	ocfs2_update_inode_fsync_trans(handle, inode, 0);
26288c2ecf20Sopenharmony_ci
26298c2ecf20Sopenharmony_ci	ocfs2_journal_dirty(handle, di_bh);
26308c2ecf20Sopenharmony_ciout_commit:
26318c2ecf20Sopenharmony_ci	ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
26328c2ecf20Sopenharmony_ciout:
26338c2ecf20Sopenharmony_ci	if (ref_tree)
26348c2ecf20Sopenharmony_ci		ocfs2_unlock_refcount_tree(OCFS2_SB(inode->i_sb), ref_tree, 1);
26358c2ecf20Sopenharmony_ci	brelse(ref_root_bh);
26368c2ecf20Sopenharmony_ci	return ret;
26378c2ecf20Sopenharmony_ci}
26388c2ecf20Sopenharmony_ci
26398c2ecf20Sopenharmony_cistatic int ocfs2_xattr_has_space_inline(struct inode *inode,
26408c2ecf20Sopenharmony_ci					struct ocfs2_dinode *di)
26418c2ecf20Sopenharmony_ci{
26428c2ecf20Sopenharmony_ci	struct ocfs2_inode_info *oi = OCFS2_I(inode);
26438c2ecf20Sopenharmony_ci	unsigned int xattrsize = OCFS2_SB(inode->i_sb)->s_xattr_inline_size;
26448c2ecf20Sopenharmony_ci	int free;
26458c2ecf20Sopenharmony_ci
26468c2ecf20Sopenharmony_ci	if (xattrsize < OCFS2_MIN_XATTR_INLINE_SIZE)
26478c2ecf20Sopenharmony_ci		return 0;
26488c2ecf20Sopenharmony_ci
26498c2ecf20Sopenharmony_ci	if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
26508c2ecf20Sopenharmony_ci		struct ocfs2_inline_data *idata = &di->id2.i_data;
26518c2ecf20Sopenharmony_ci		free = le16_to_cpu(idata->id_count) - le64_to_cpu(di->i_size);
26528c2ecf20Sopenharmony_ci	} else if (ocfs2_inode_is_fast_symlink(inode)) {
26538c2ecf20Sopenharmony_ci		free = ocfs2_fast_symlink_chars(inode->i_sb) -
26548c2ecf20Sopenharmony_ci			le64_to_cpu(di->i_size);
26558c2ecf20Sopenharmony_ci	} else {
26568c2ecf20Sopenharmony_ci		struct ocfs2_extent_list *el = &di->id2.i_list;
26578c2ecf20Sopenharmony_ci		free = (le16_to_cpu(el->l_count) -
26588c2ecf20Sopenharmony_ci			le16_to_cpu(el->l_next_free_rec)) *
26598c2ecf20Sopenharmony_ci			sizeof(struct ocfs2_extent_rec);
26608c2ecf20Sopenharmony_ci	}
26618c2ecf20Sopenharmony_ci	if (free >= xattrsize)
26628c2ecf20Sopenharmony_ci		return 1;
26638c2ecf20Sopenharmony_ci
26648c2ecf20Sopenharmony_ci	return 0;
26658c2ecf20Sopenharmony_ci}
26668c2ecf20Sopenharmony_ci
26678c2ecf20Sopenharmony_ci/*
26688c2ecf20Sopenharmony_ci * ocfs2_xattr_ibody_find()
26698c2ecf20Sopenharmony_ci *
26708c2ecf20Sopenharmony_ci * Find extended attribute in inode block and
26718c2ecf20Sopenharmony_ci * fill search info into struct ocfs2_xattr_search.
26728c2ecf20Sopenharmony_ci */
26738c2ecf20Sopenharmony_cistatic int ocfs2_xattr_ibody_find(struct inode *inode,
26748c2ecf20Sopenharmony_ci				  int name_index,
26758c2ecf20Sopenharmony_ci				  const char *name,
26768c2ecf20Sopenharmony_ci				  struct ocfs2_xattr_search *xs)
26778c2ecf20Sopenharmony_ci{
26788c2ecf20Sopenharmony_ci	struct ocfs2_inode_info *oi = OCFS2_I(inode);
26798c2ecf20Sopenharmony_ci	struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data;
26808c2ecf20Sopenharmony_ci	int ret;
26818c2ecf20Sopenharmony_ci	int has_space = 0;
26828c2ecf20Sopenharmony_ci
26838c2ecf20Sopenharmony_ci	if (inode->i_sb->s_blocksize == OCFS2_MIN_BLOCKSIZE)
26848c2ecf20Sopenharmony_ci		return 0;
26858c2ecf20Sopenharmony_ci
26868c2ecf20Sopenharmony_ci	if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL)) {
26878c2ecf20Sopenharmony_ci		down_read(&oi->ip_alloc_sem);
26888c2ecf20Sopenharmony_ci		has_space = ocfs2_xattr_has_space_inline(inode, di);
26898c2ecf20Sopenharmony_ci		up_read(&oi->ip_alloc_sem);
26908c2ecf20Sopenharmony_ci		if (!has_space)
26918c2ecf20Sopenharmony_ci			return 0;
26928c2ecf20Sopenharmony_ci	}
26938c2ecf20Sopenharmony_ci
26948c2ecf20Sopenharmony_ci	xs->xattr_bh = xs->inode_bh;
26958c2ecf20Sopenharmony_ci	xs->end = (void *)di + inode->i_sb->s_blocksize;
26968c2ecf20Sopenharmony_ci	if (oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL)
26978c2ecf20Sopenharmony_ci		xs->header = (struct ocfs2_xattr_header *)
26988c2ecf20Sopenharmony_ci			(xs->end - le16_to_cpu(di->i_xattr_inline_size));
26998c2ecf20Sopenharmony_ci	else
27008c2ecf20Sopenharmony_ci		xs->header = (struct ocfs2_xattr_header *)
27018c2ecf20Sopenharmony_ci			(xs->end - OCFS2_SB(inode->i_sb)->s_xattr_inline_size);
27028c2ecf20Sopenharmony_ci	xs->base = (void *)xs->header;
27038c2ecf20Sopenharmony_ci	xs->here = xs->header->xh_entries;
27048c2ecf20Sopenharmony_ci
27058c2ecf20Sopenharmony_ci	/* Find the named attribute. */
27068c2ecf20Sopenharmony_ci	if (oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL) {
27078c2ecf20Sopenharmony_ci		ret = ocfs2_xattr_find_entry(name_index, name, xs);
27088c2ecf20Sopenharmony_ci		if (ret && ret != -ENODATA)
27098c2ecf20Sopenharmony_ci			return ret;
27108c2ecf20Sopenharmony_ci		xs->not_found = ret;
27118c2ecf20Sopenharmony_ci	}
27128c2ecf20Sopenharmony_ci
27138c2ecf20Sopenharmony_ci	return 0;
27148c2ecf20Sopenharmony_ci}
27158c2ecf20Sopenharmony_ci
27168c2ecf20Sopenharmony_cistatic int ocfs2_xattr_ibody_init(struct inode *inode,
27178c2ecf20Sopenharmony_ci				  struct buffer_head *di_bh,
27188c2ecf20Sopenharmony_ci				  struct ocfs2_xattr_set_ctxt *ctxt)
27198c2ecf20Sopenharmony_ci{
27208c2ecf20Sopenharmony_ci	int ret;
27218c2ecf20Sopenharmony_ci	struct ocfs2_inode_info *oi = OCFS2_I(inode);
27228c2ecf20Sopenharmony_ci	struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
27238c2ecf20Sopenharmony_ci	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
27248c2ecf20Sopenharmony_ci	unsigned int xattrsize = osb->s_xattr_inline_size;
27258c2ecf20Sopenharmony_ci
27268c2ecf20Sopenharmony_ci	if (!ocfs2_xattr_has_space_inline(inode, di)) {
27278c2ecf20Sopenharmony_ci		ret = -ENOSPC;
27288c2ecf20Sopenharmony_ci		goto out;
27298c2ecf20Sopenharmony_ci	}
27308c2ecf20Sopenharmony_ci
27318c2ecf20Sopenharmony_ci	ret = ocfs2_journal_access_di(ctxt->handle, INODE_CACHE(inode), di_bh,
27328c2ecf20Sopenharmony_ci				      OCFS2_JOURNAL_ACCESS_WRITE);
27338c2ecf20Sopenharmony_ci	if (ret) {
27348c2ecf20Sopenharmony_ci		mlog_errno(ret);
27358c2ecf20Sopenharmony_ci		goto out;
27368c2ecf20Sopenharmony_ci	}
27378c2ecf20Sopenharmony_ci
27388c2ecf20Sopenharmony_ci	/*
27398c2ecf20Sopenharmony_ci	 * Adjust extent record count or inline data size
27408c2ecf20Sopenharmony_ci	 * to reserve space for extended attribute.
27418c2ecf20Sopenharmony_ci	 */
27428c2ecf20Sopenharmony_ci	if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
27438c2ecf20Sopenharmony_ci		struct ocfs2_inline_data *idata = &di->id2.i_data;
27448c2ecf20Sopenharmony_ci		le16_add_cpu(&idata->id_count, -xattrsize);
27458c2ecf20Sopenharmony_ci	} else if (!(ocfs2_inode_is_fast_symlink(inode))) {
27468c2ecf20Sopenharmony_ci		struct ocfs2_extent_list *el = &di->id2.i_list;
27478c2ecf20Sopenharmony_ci		le16_add_cpu(&el->l_count, -(xattrsize /
27488c2ecf20Sopenharmony_ci					     sizeof(struct ocfs2_extent_rec)));
27498c2ecf20Sopenharmony_ci	}
27508c2ecf20Sopenharmony_ci	di->i_xattr_inline_size = cpu_to_le16(xattrsize);
27518c2ecf20Sopenharmony_ci
27528c2ecf20Sopenharmony_ci	spin_lock(&oi->ip_lock);
27538c2ecf20Sopenharmony_ci	oi->ip_dyn_features |= OCFS2_INLINE_XATTR_FL|OCFS2_HAS_XATTR_FL;
27548c2ecf20Sopenharmony_ci	di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features);
27558c2ecf20Sopenharmony_ci	spin_unlock(&oi->ip_lock);
27568c2ecf20Sopenharmony_ci
27578c2ecf20Sopenharmony_ci	ocfs2_journal_dirty(ctxt->handle, di_bh);
27588c2ecf20Sopenharmony_ci
27598c2ecf20Sopenharmony_ciout:
27608c2ecf20Sopenharmony_ci	return ret;
27618c2ecf20Sopenharmony_ci}
27628c2ecf20Sopenharmony_ci
27638c2ecf20Sopenharmony_ci/*
27648c2ecf20Sopenharmony_ci * ocfs2_xattr_ibody_set()
27658c2ecf20Sopenharmony_ci *
27668c2ecf20Sopenharmony_ci * Set, replace or remove an extended attribute into inode block.
27678c2ecf20Sopenharmony_ci *
27688c2ecf20Sopenharmony_ci */
27698c2ecf20Sopenharmony_cistatic int ocfs2_xattr_ibody_set(struct inode *inode,
27708c2ecf20Sopenharmony_ci				 struct ocfs2_xattr_info *xi,
27718c2ecf20Sopenharmony_ci				 struct ocfs2_xattr_search *xs,
27728c2ecf20Sopenharmony_ci				 struct ocfs2_xattr_set_ctxt *ctxt)
27738c2ecf20Sopenharmony_ci{
27748c2ecf20Sopenharmony_ci	int ret;
27758c2ecf20Sopenharmony_ci	struct ocfs2_inode_info *oi = OCFS2_I(inode);
27768c2ecf20Sopenharmony_ci	struct ocfs2_xa_loc loc;
27778c2ecf20Sopenharmony_ci
27788c2ecf20Sopenharmony_ci	if (inode->i_sb->s_blocksize == OCFS2_MIN_BLOCKSIZE)
27798c2ecf20Sopenharmony_ci		return -ENOSPC;
27808c2ecf20Sopenharmony_ci
27818c2ecf20Sopenharmony_ci	down_write(&oi->ip_alloc_sem);
27828c2ecf20Sopenharmony_ci	if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL)) {
27838c2ecf20Sopenharmony_ci		ret = ocfs2_xattr_ibody_init(inode, xs->inode_bh, ctxt);
27848c2ecf20Sopenharmony_ci		if (ret) {
27858c2ecf20Sopenharmony_ci			if (ret != -ENOSPC)
27868c2ecf20Sopenharmony_ci				mlog_errno(ret);
27878c2ecf20Sopenharmony_ci			goto out;
27888c2ecf20Sopenharmony_ci		}
27898c2ecf20Sopenharmony_ci	}
27908c2ecf20Sopenharmony_ci
27918c2ecf20Sopenharmony_ci	ocfs2_init_dinode_xa_loc(&loc, inode, xs->inode_bh,
27928c2ecf20Sopenharmony_ci				 xs->not_found ? NULL : xs->here);
27938c2ecf20Sopenharmony_ci	ret = ocfs2_xa_set(&loc, xi, ctxt);
27948c2ecf20Sopenharmony_ci	if (ret) {
27958c2ecf20Sopenharmony_ci		if (ret != -ENOSPC)
27968c2ecf20Sopenharmony_ci			mlog_errno(ret);
27978c2ecf20Sopenharmony_ci		goto out;
27988c2ecf20Sopenharmony_ci	}
27998c2ecf20Sopenharmony_ci	xs->here = loc.xl_entry;
28008c2ecf20Sopenharmony_ci
28018c2ecf20Sopenharmony_ciout:
28028c2ecf20Sopenharmony_ci	up_write(&oi->ip_alloc_sem);
28038c2ecf20Sopenharmony_ci
28048c2ecf20Sopenharmony_ci	return ret;
28058c2ecf20Sopenharmony_ci}
28068c2ecf20Sopenharmony_ci
28078c2ecf20Sopenharmony_ci/*
28088c2ecf20Sopenharmony_ci * ocfs2_xattr_block_find()
28098c2ecf20Sopenharmony_ci *
28108c2ecf20Sopenharmony_ci * Find extended attribute in external block and
28118c2ecf20Sopenharmony_ci * fill search info into struct ocfs2_xattr_search.
28128c2ecf20Sopenharmony_ci */
28138c2ecf20Sopenharmony_cistatic int ocfs2_xattr_block_find(struct inode *inode,
28148c2ecf20Sopenharmony_ci				  int name_index,
28158c2ecf20Sopenharmony_ci				  const char *name,
28168c2ecf20Sopenharmony_ci				  struct ocfs2_xattr_search *xs)
28178c2ecf20Sopenharmony_ci{
28188c2ecf20Sopenharmony_ci	struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data;
28198c2ecf20Sopenharmony_ci	struct buffer_head *blk_bh = NULL;
28208c2ecf20Sopenharmony_ci	struct ocfs2_xattr_block *xb;
28218c2ecf20Sopenharmony_ci	int ret = 0;
28228c2ecf20Sopenharmony_ci
28238c2ecf20Sopenharmony_ci	if (!di->i_xattr_loc)
28248c2ecf20Sopenharmony_ci		return ret;
28258c2ecf20Sopenharmony_ci
28268c2ecf20Sopenharmony_ci	ret = ocfs2_read_xattr_block(inode, le64_to_cpu(di->i_xattr_loc),
28278c2ecf20Sopenharmony_ci				     &blk_bh);
28288c2ecf20Sopenharmony_ci	if (ret < 0) {
28298c2ecf20Sopenharmony_ci		mlog_errno(ret);
28308c2ecf20Sopenharmony_ci		return ret;
28318c2ecf20Sopenharmony_ci	}
28328c2ecf20Sopenharmony_ci
28338c2ecf20Sopenharmony_ci	xs->xattr_bh = blk_bh;
28348c2ecf20Sopenharmony_ci	xb = (struct ocfs2_xattr_block *)blk_bh->b_data;
28358c2ecf20Sopenharmony_ci
28368c2ecf20Sopenharmony_ci	if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) {
28378c2ecf20Sopenharmony_ci		xs->header = &xb->xb_attrs.xb_header;
28388c2ecf20Sopenharmony_ci		xs->base = (void *)xs->header;
28398c2ecf20Sopenharmony_ci		xs->end = (void *)(blk_bh->b_data) + blk_bh->b_size;
28408c2ecf20Sopenharmony_ci		xs->here = xs->header->xh_entries;
28418c2ecf20Sopenharmony_ci
28428c2ecf20Sopenharmony_ci		ret = ocfs2_xattr_find_entry(name_index, name, xs);
28438c2ecf20Sopenharmony_ci	} else
28448c2ecf20Sopenharmony_ci		ret = ocfs2_xattr_index_block_find(inode, blk_bh,
28458c2ecf20Sopenharmony_ci						   name_index,
28468c2ecf20Sopenharmony_ci						   name, xs);
28478c2ecf20Sopenharmony_ci
28488c2ecf20Sopenharmony_ci	if (ret && ret != -ENODATA) {
28498c2ecf20Sopenharmony_ci		xs->xattr_bh = NULL;
28508c2ecf20Sopenharmony_ci		goto cleanup;
28518c2ecf20Sopenharmony_ci	}
28528c2ecf20Sopenharmony_ci	xs->not_found = ret;
28538c2ecf20Sopenharmony_ci	return 0;
28548c2ecf20Sopenharmony_cicleanup:
28558c2ecf20Sopenharmony_ci	brelse(blk_bh);
28568c2ecf20Sopenharmony_ci
28578c2ecf20Sopenharmony_ci	return ret;
28588c2ecf20Sopenharmony_ci}
28598c2ecf20Sopenharmony_ci
28608c2ecf20Sopenharmony_cistatic int ocfs2_create_xattr_block(struct inode *inode,
28618c2ecf20Sopenharmony_ci				    struct buffer_head *inode_bh,
28628c2ecf20Sopenharmony_ci				    struct ocfs2_xattr_set_ctxt *ctxt,
28638c2ecf20Sopenharmony_ci				    int indexed,
28648c2ecf20Sopenharmony_ci				    struct buffer_head **ret_bh)
28658c2ecf20Sopenharmony_ci{
28668c2ecf20Sopenharmony_ci	int ret;
28678c2ecf20Sopenharmony_ci	u16 suballoc_bit_start;
28688c2ecf20Sopenharmony_ci	u32 num_got;
28698c2ecf20Sopenharmony_ci	u64 suballoc_loc, first_blkno;
28708c2ecf20Sopenharmony_ci	struct ocfs2_dinode *di =  (struct ocfs2_dinode *)inode_bh->b_data;
28718c2ecf20Sopenharmony_ci	struct buffer_head *new_bh = NULL;
28728c2ecf20Sopenharmony_ci	struct ocfs2_xattr_block *xblk;
28738c2ecf20Sopenharmony_ci
28748c2ecf20Sopenharmony_ci	ret = ocfs2_journal_access_di(ctxt->handle, INODE_CACHE(inode),
28758c2ecf20Sopenharmony_ci				      inode_bh, OCFS2_JOURNAL_ACCESS_CREATE);
28768c2ecf20Sopenharmony_ci	if (ret < 0) {
28778c2ecf20Sopenharmony_ci		mlog_errno(ret);
28788c2ecf20Sopenharmony_ci		goto end;
28798c2ecf20Sopenharmony_ci	}
28808c2ecf20Sopenharmony_ci
28818c2ecf20Sopenharmony_ci	ret = ocfs2_claim_metadata(ctxt->handle, ctxt->meta_ac, 1,
28828c2ecf20Sopenharmony_ci				   &suballoc_loc, &suballoc_bit_start,
28838c2ecf20Sopenharmony_ci				   &num_got, &first_blkno);
28848c2ecf20Sopenharmony_ci	if (ret < 0) {
28858c2ecf20Sopenharmony_ci		mlog_errno(ret);
28868c2ecf20Sopenharmony_ci		goto end;
28878c2ecf20Sopenharmony_ci	}
28888c2ecf20Sopenharmony_ci
28898c2ecf20Sopenharmony_ci	new_bh = sb_getblk(inode->i_sb, first_blkno);
28908c2ecf20Sopenharmony_ci	if (!new_bh) {
28918c2ecf20Sopenharmony_ci		ret = -ENOMEM;
28928c2ecf20Sopenharmony_ci		mlog_errno(ret);
28938c2ecf20Sopenharmony_ci		goto end;
28948c2ecf20Sopenharmony_ci	}
28958c2ecf20Sopenharmony_ci
28968c2ecf20Sopenharmony_ci	ocfs2_set_new_buffer_uptodate(INODE_CACHE(inode), new_bh);
28978c2ecf20Sopenharmony_ci
28988c2ecf20Sopenharmony_ci	ret = ocfs2_journal_access_xb(ctxt->handle, INODE_CACHE(inode),
28998c2ecf20Sopenharmony_ci				      new_bh,
29008c2ecf20Sopenharmony_ci				      OCFS2_JOURNAL_ACCESS_CREATE);
29018c2ecf20Sopenharmony_ci	if (ret < 0) {
29028c2ecf20Sopenharmony_ci		mlog_errno(ret);
29038c2ecf20Sopenharmony_ci		goto end;
29048c2ecf20Sopenharmony_ci	}
29058c2ecf20Sopenharmony_ci
29068c2ecf20Sopenharmony_ci	/* Initialize ocfs2_xattr_block */
29078c2ecf20Sopenharmony_ci	xblk = (struct ocfs2_xattr_block *)new_bh->b_data;
29088c2ecf20Sopenharmony_ci	memset(xblk, 0, inode->i_sb->s_blocksize);
29098c2ecf20Sopenharmony_ci	strcpy((void *)xblk, OCFS2_XATTR_BLOCK_SIGNATURE);
29108c2ecf20Sopenharmony_ci	xblk->xb_suballoc_slot = cpu_to_le16(ctxt->meta_ac->ac_alloc_slot);
29118c2ecf20Sopenharmony_ci	xblk->xb_suballoc_loc = cpu_to_le64(suballoc_loc);
29128c2ecf20Sopenharmony_ci	xblk->xb_suballoc_bit = cpu_to_le16(suballoc_bit_start);
29138c2ecf20Sopenharmony_ci	xblk->xb_fs_generation =
29148c2ecf20Sopenharmony_ci		cpu_to_le32(OCFS2_SB(inode->i_sb)->fs_generation);
29158c2ecf20Sopenharmony_ci	xblk->xb_blkno = cpu_to_le64(first_blkno);
29168c2ecf20Sopenharmony_ci	if (indexed) {
29178c2ecf20Sopenharmony_ci		struct ocfs2_xattr_tree_root *xr = &xblk->xb_attrs.xb_root;
29188c2ecf20Sopenharmony_ci		xr->xt_clusters = cpu_to_le32(1);
29198c2ecf20Sopenharmony_ci		xr->xt_last_eb_blk = 0;
29208c2ecf20Sopenharmony_ci		xr->xt_list.l_tree_depth = 0;
29218c2ecf20Sopenharmony_ci		xr->xt_list.l_count = cpu_to_le16(
29228c2ecf20Sopenharmony_ci					ocfs2_xattr_recs_per_xb(inode->i_sb));
29238c2ecf20Sopenharmony_ci		xr->xt_list.l_next_free_rec = cpu_to_le16(1);
29248c2ecf20Sopenharmony_ci		xblk->xb_flags = cpu_to_le16(OCFS2_XATTR_INDEXED);
29258c2ecf20Sopenharmony_ci	}
29268c2ecf20Sopenharmony_ci	ocfs2_journal_dirty(ctxt->handle, new_bh);
29278c2ecf20Sopenharmony_ci
29288c2ecf20Sopenharmony_ci	/* Add it to the inode */
29298c2ecf20Sopenharmony_ci	di->i_xattr_loc = cpu_to_le64(first_blkno);
29308c2ecf20Sopenharmony_ci
29318c2ecf20Sopenharmony_ci	spin_lock(&OCFS2_I(inode)->ip_lock);
29328c2ecf20Sopenharmony_ci	OCFS2_I(inode)->ip_dyn_features |= OCFS2_HAS_XATTR_FL;
29338c2ecf20Sopenharmony_ci	di->i_dyn_features = cpu_to_le16(OCFS2_I(inode)->ip_dyn_features);
29348c2ecf20Sopenharmony_ci	spin_unlock(&OCFS2_I(inode)->ip_lock);
29358c2ecf20Sopenharmony_ci
29368c2ecf20Sopenharmony_ci	ocfs2_journal_dirty(ctxt->handle, inode_bh);
29378c2ecf20Sopenharmony_ci
29388c2ecf20Sopenharmony_ci	*ret_bh = new_bh;
29398c2ecf20Sopenharmony_ci	new_bh = NULL;
29408c2ecf20Sopenharmony_ci
29418c2ecf20Sopenharmony_ciend:
29428c2ecf20Sopenharmony_ci	brelse(new_bh);
29438c2ecf20Sopenharmony_ci	return ret;
29448c2ecf20Sopenharmony_ci}
29458c2ecf20Sopenharmony_ci
29468c2ecf20Sopenharmony_ci/*
29478c2ecf20Sopenharmony_ci * ocfs2_xattr_block_set()
29488c2ecf20Sopenharmony_ci *
29498c2ecf20Sopenharmony_ci * Set, replace or remove an extended attribute into external block.
29508c2ecf20Sopenharmony_ci *
29518c2ecf20Sopenharmony_ci */
29528c2ecf20Sopenharmony_cistatic int ocfs2_xattr_block_set(struct inode *inode,
29538c2ecf20Sopenharmony_ci				 struct ocfs2_xattr_info *xi,
29548c2ecf20Sopenharmony_ci				 struct ocfs2_xattr_search *xs,
29558c2ecf20Sopenharmony_ci				 struct ocfs2_xattr_set_ctxt *ctxt)
29568c2ecf20Sopenharmony_ci{
29578c2ecf20Sopenharmony_ci	struct buffer_head *new_bh = NULL;
29588c2ecf20Sopenharmony_ci	struct ocfs2_xattr_block *xblk = NULL;
29598c2ecf20Sopenharmony_ci	int ret;
29608c2ecf20Sopenharmony_ci	struct ocfs2_xa_loc loc;
29618c2ecf20Sopenharmony_ci
29628c2ecf20Sopenharmony_ci	if (!xs->xattr_bh) {
29638c2ecf20Sopenharmony_ci		ret = ocfs2_create_xattr_block(inode, xs->inode_bh, ctxt,
29648c2ecf20Sopenharmony_ci					       0, &new_bh);
29658c2ecf20Sopenharmony_ci		if (ret) {
29668c2ecf20Sopenharmony_ci			mlog_errno(ret);
29678c2ecf20Sopenharmony_ci			goto end;
29688c2ecf20Sopenharmony_ci		}
29698c2ecf20Sopenharmony_ci
29708c2ecf20Sopenharmony_ci		xs->xattr_bh = new_bh;
29718c2ecf20Sopenharmony_ci		xblk = (struct ocfs2_xattr_block *)xs->xattr_bh->b_data;
29728c2ecf20Sopenharmony_ci		xs->header = &xblk->xb_attrs.xb_header;
29738c2ecf20Sopenharmony_ci		xs->base = (void *)xs->header;
29748c2ecf20Sopenharmony_ci		xs->end = (void *)xblk + inode->i_sb->s_blocksize;
29758c2ecf20Sopenharmony_ci		xs->here = xs->header->xh_entries;
29768c2ecf20Sopenharmony_ci	} else
29778c2ecf20Sopenharmony_ci		xblk = (struct ocfs2_xattr_block *)xs->xattr_bh->b_data;
29788c2ecf20Sopenharmony_ci
29798c2ecf20Sopenharmony_ci	if (!(le16_to_cpu(xblk->xb_flags) & OCFS2_XATTR_INDEXED)) {
29808c2ecf20Sopenharmony_ci		ocfs2_init_xattr_block_xa_loc(&loc, inode, xs->xattr_bh,
29818c2ecf20Sopenharmony_ci					      xs->not_found ? NULL : xs->here);
29828c2ecf20Sopenharmony_ci
29838c2ecf20Sopenharmony_ci		ret = ocfs2_xa_set(&loc, xi, ctxt);
29848c2ecf20Sopenharmony_ci		if (!ret)
29858c2ecf20Sopenharmony_ci			xs->here = loc.xl_entry;
29868c2ecf20Sopenharmony_ci		else if ((ret != -ENOSPC) || ctxt->set_abort)
29878c2ecf20Sopenharmony_ci			goto end;
29888c2ecf20Sopenharmony_ci		else {
29898c2ecf20Sopenharmony_ci			ret = ocfs2_xattr_create_index_block(inode, xs, ctxt);
29908c2ecf20Sopenharmony_ci			if (ret)
29918c2ecf20Sopenharmony_ci				goto end;
29928c2ecf20Sopenharmony_ci		}
29938c2ecf20Sopenharmony_ci	}
29948c2ecf20Sopenharmony_ci
29958c2ecf20Sopenharmony_ci	if (le16_to_cpu(xblk->xb_flags) & OCFS2_XATTR_INDEXED)
29968c2ecf20Sopenharmony_ci		ret = ocfs2_xattr_set_entry_index_block(inode, xi, xs, ctxt);
29978c2ecf20Sopenharmony_ci
29988c2ecf20Sopenharmony_ciend:
29998c2ecf20Sopenharmony_ci	return ret;
30008c2ecf20Sopenharmony_ci}
30018c2ecf20Sopenharmony_ci
30028c2ecf20Sopenharmony_ci/* Check whether the new xattr can be inserted into the inode. */
30038c2ecf20Sopenharmony_cistatic int ocfs2_xattr_can_be_in_inode(struct inode *inode,
30048c2ecf20Sopenharmony_ci				       struct ocfs2_xattr_info *xi,
30058c2ecf20Sopenharmony_ci				       struct ocfs2_xattr_search *xs)
30068c2ecf20Sopenharmony_ci{
30078c2ecf20Sopenharmony_ci	struct ocfs2_xattr_entry *last;
30088c2ecf20Sopenharmony_ci	int free, i;
30098c2ecf20Sopenharmony_ci	size_t min_offs = xs->end - xs->base;
30108c2ecf20Sopenharmony_ci
30118c2ecf20Sopenharmony_ci	if (!xs->header)
30128c2ecf20Sopenharmony_ci		return 0;
30138c2ecf20Sopenharmony_ci
30148c2ecf20Sopenharmony_ci	last = xs->header->xh_entries;
30158c2ecf20Sopenharmony_ci
30168c2ecf20Sopenharmony_ci	for (i = 0; i < le16_to_cpu(xs->header->xh_count); i++) {
30178c2ecf20Sopenharmony_ci		size_t offs = le16_to_cpu(last->xe_name_offset);
30188c2ecf20Sopenharmony_ci		if (offs < min_offs)
30198c2ecf20Sopenharmony_ci			min_offs = offs;
30208c2ecf20Sopenharmony_ci		last += 1;
30218c2ecf20Sopenharmony_ci	}
30228c2ecf20Sopenharmony_ci
30238c2ecf20Sopenharmony_ci	free = min_offs - ((void *)last - xs->base) - OCFS2_XATTR_HEADER_GAP;
30248c2ecf20Sopenharmony_ci	if (free < 0)
30258c2ecf20Sopenharmony_ci		return 0;
30268c2ecf20Sopenharmony_ci
30278c2ecf20Sopenharmony_ci	BUG_ON(!xs->not_found);
30288c2ecf20Sopenharmony_ci
30298c2ecf20Sopenharmony_ci	if (free >= (sizeof(struct ocfs2_xattr_entry) + namevalue_size_xi(xi)))
30308c2ecf20Sopenharmony_ci		return 1;
30318c2ecf20Sopenharmony_ci
30328c2ecf20Sopenharmony_ci	return 0;
30338c2ecf20Sopenharmony_ci}
30348c2ecf20Sopenharmony_ci
30358c2ecf20Sopenharmony_cistatic int ocfs2_calc_xattr_set_need(struct inode *inode,
30368c2ecf20Sopenharmony_ci				     struct ocfs2_dinode *di,
30378c2ecf20Sopenharmony_ci				     struct ocfs2_xattr_info *xi,
30388c2ecf20Sopenharmony_ci				     struct ocfs2_xattr_search *xis,
30398c2ecf20Sopenharmony_ci				     struct ocfs2_xattr_search *xbs,
30408c2ecf20Sopenharmony_ci				     int *clusters_need,
30418c2ecf20Sopenharmony_ci				     int *meta_need,
30428c2ecf20Sopenharmony_ci				     int *credits_need)
30438c2ecf20Sopenharmony_ci{
30448c2ecf20Sopenharmony_ci	int ret = 0, old_in_xb = 0;
30458c2ecf20Sopenharmony_ci	int clusters_add = 0, meta_add = 0, credits = 0;
30468c2ecf20Sopenharmony_ci	struct buffer_head *bh = NULL;
30478c2ecf20Sopenharmony_ci	struct ocfs2_xattr_block *xb = NULL;
30488c2ecf20Sopenharmony_ci	struct ocfs2_xattr_entry *xe = NULL;
30498c2ecf20Sopenharmony_ci	struct ocfs2_xattr_value_root *xv = NULL;
30508c2ecf20Sopenharmony_ci	char *base = NULL;
30518c2ecf20Sopenharmony_ci	int name_offset, name_len = 0;
30528c2ecf20Sopenharmony_ci	u32 new_clusters = ocfs2_clusters_for_bytes(inode->i_sb,
30538c2ecf20Sopenharmony_ci						    xi->xi_value_len);
30548c2ecf20Sopenharmony_ci	u64 value_size;
30558c2ecf20Sopenharmony_ci
30568c2ecf20Sopenharmony_ci	/*
30578c2ecf20Sopenharmony_ci	 * Calculate the clusters we need to write.
30588c2ecf20Sopenharmony_ci	 * No matter whether we replace an old one or add a new one,
30598c2ecf20Sopenharmony_ci	 * we need this for writing.
30608c2ecf20Sopenharmony_ci	 */
30618c2ecf20Sopenharmony_ci	if (xi->xi_value_len > OCFS2_XATTR_INLINE_SIZE)
30628c2ecf20Sopenharmony_ci		credits += new_clusters *
30638c2ecf20Sopenharmony_ci			   ocfs2_clusters_to_blocks(inode->i_sb, 1);
30648c2ecf20Sopenharmony_ci
30658c2ecf20Sopenharmony_ci	if (xis->not_found && xbs->not_found) {
30668c2ecf20Sopenharmony_ci		credits += ocfs2_blocks_per_xattr_bucket(inode->i_sb);
30678c2ecf20Sopenharmony_ci
30688c2ecf20Sopenharmony_ci		if (xi->xi_value_len > OCFS2_XATTR_INLINE_SIZE) {
30698c2ecf20Sopenharmony_ci			clusters_add += new_clusters;
30708c2ecf20Sopenharmony_ci			credits += ocfs2_calc_extend_credits(inode->i_sb,
30718c2ecf20Sopenharmony_ci							&def_xv.xv.xr_list);
30728c2ecf20Sopenharmony_ci		}
30738c2ecf20Sopenharmony_ci
30748c2ecf20Sopenharmony_ci		goto meta_guess;
30758c2ecf20Sopenharmony_ci	}
30768c2ecf20Sopenharmony_ci
30778c2ecf20Sopenharmony_ci	if (!xis->not_found) {
30788c2ecf20Sopenharmony_ci		xe = xis->here;
30798c2ecf20Sopenharmony_ci		name_offset = le16_to_cpu(xe->xe_name_offset);
30808c2ecf20Sopenharmony_ci		name_len = OCFS2_XATTR_SIZE(xe->xe_name_len);
30818c2ecf20Sopenharmony_ci		base = xis->base;
30828c2ecf20Sopenharmony_ci		credits += OCFS2_INODE_UPDATE_CREDITS;
30838c2ecf20Sopenharmony_ci	} else {
30848c2ecf20Sopenharmony_ci		int i, block_off = 0;
30858c2ecf20Sopenharmony_ci		xb = (struct ocfs2_xattr_block *)xbs->xattr_bh->b_data;
30868c2ecf20Sopenharmony_ci		xe = xbs->here;
30878c2ecf20Sopenharmony_ci		name_offset = le16_to_cpu(xe->xe_name_offset);
30888c2ecf20Sopenharmony_ci		name_len = OCFS2_XATTR_SIZE(xe->xe_name_len);
30898c2ecf20Sopenharmony_ci		i = xbs->here - xbs->header->xh_entries;
30908c2ecf20Sopenharmony_ci		old_in_xb = 1;
30918c2ecf20Sopenharmony_ci
30928c2ecf20Sopenharmony_ci		if (le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED) {
30938c2ecf20Sopenharmony_ci			ret = ocfs2_xattr_bucket_get_name_value(inode->i_sb,
30948c2ecf20Sopenharmony_ci							bucket_xh(xbs->bucket),
30958c2ecf20Sopenharmony_ci							i, &block_off,
30968c2ecf20Sopenharmony_ci							&name_offset);
30978c2ecf20Sopenharmony_ci			base = bucket_block(xbs->bucket, block_off);
30988c2ecf20Sopenharmony_ci			credits += ocfs2_blocks_per_xattr_bucket(inode->i_sb);
30998c2ecf20Sopenharmony_ci		} else {
31008c2ecf20Sopenharmony_ci			base = xbs->base;
31018c2ecf20Sopenharmony_ci			credits += OCFS2_XATTR_BLOCK_UPDATE_CREDITS;
31028c2ecf20Sopenharmony_ci		}
31038c2ecf20Sopenharmony_ci	}
31048c2ecf20Sopenharmony_ci
31058c2ecf20Sopenharmony_ci	/*
31068c2ecf20Sopenharmony_ci	 * delete a xattr doesn't need metadata and cluster allocation.
31078c2ecf20Sopenharmony_ci	 * so just calculate the credits and return.
31088c2ecf20Sopenharmony_ci	 *
31098c2ecf20Sopenharmony_ci	 * The credits for removing the value tree will be extended
31108c2ecf20Sopenharmony_ci	 * by ocfs2_remove_extent itself.
31118c2ecf20Sopenharmony_ci	 */
31128c2ecf20Sopenharmony_ci	if (!xi->xi_value) {
31138c2ecf20Sopenharmony_ci		if (!ocfs2_xattr_is_local(xe))
31148c2ecf20Sopenharmony_ci			credits += ocfs2_remove_extent_credits(inode->i_sb);
31158c2ecf20Sopenharmony_ci
31168c2ecf20Sopenharmony_ci		goto out;
31178c2ecf20Sopenharmony_ci	}
31188c2ecf20Sopenharmony_ci
31198c2ecf20Sopenharmony_ci	/* do cluster allocation guess first. */
31208c2ecf20Sopenharmony_ci	value_size = le64_to_cpu(xe->xe_value_size);
31218c2ecf20Sopenharmony_ci
31228c2ecf20Sopenharmony_ci	if (old_in_xb) {
31238c2ecf20Sopenharmony_ci		/*
31248c2ecf20Sopenharmony_ci		 * In xattr set, we always try to set the xe in inode first,
31258c2ecf20Sopenharmony_ci		 * so if it can be inserted into inode successfully, the old
31268c2ecf20Sopenharmony_ci		 * one will be removed from the xattr block, and this xattr
31278c2ecf20Sopenharmony_ci		 * will be inserted into inode as a new xattr in inode.
31288c2ecf20Sopenharmony_ci		 */
31298c2ecf20Sopenharmony_ci		if (ocfs2_xattr_can_be_in_inode(inode, xi, xis)) {
31308c2ecf20Sopenharmony_ci			clusters_add += new_clusters;
31318c2ecf20Sopenharmony_ci			credits += ocfs2_remove_extent_credits(inode->i_sb) +
31328c2ecf20Sopenharmony_ci				    OCFS2_INODE_UPDATE_CREDITS;
31338c2ecf20Sopenharmony_ci			if (!ocfs2_xattr_is_local(xe))
31348c2ecf20Sopenharmony_ci				credits += ocfs2_calc_extend_credits(
31358c2ecf20Sopenharmony_ci							inode->i_sb,
31368c2ecf20Sopenharmony_ci							&def_xv.xv.xr_list);
31378c2ecf20Sopenharmony_ci			goto out;
31388c2ecf20Sopenharmony_ci		}
31398c2ecf20Sopenharmony_ci	}
31408c2ecf20Sopenharmony_ci
31418c2ecf20Sopenharmony_ci	if (xi->xi_value_len > OCFS2_XATTR_INLINE_SIZE) {
31428c2ecf20Sopenharmony_ci		/* the new values will be stored outside. */
31438c2ecf20Sopenharmony_ci		u32 old_clusters = 0;
31448c2ecf20Sopenharmony_ci
31458c2ecf20Sopenharmony_ci		if (!ocfs2_xattr_is_local(xe)) {
31468c2ecf20Sopenharmony_ci			old_clusters =	ocfs2_clusters_for_bytes(inode->i_sb,
31478c2ecf20Sopenharmony_ci								 value_size);
31488c2ecf20Sopenharmony_ci			xv = (struct ocfs2_xattr_value_root *)
31498c2ecf20Sopenharmony_ci			     (base + name_offset + name_len);
31508c2ecf20Sopenharmony_ci			value_size = OCFS2_XATTR_ROOT_SIZE;
31518c2ecf20Sopenharmony_ci		} else
31528c2ecf20Sopenharmony_ci			xv = &def_xv.xv;
31538c2ecf20Sopenharmony_ci
31548c2ecf20Sopenharmony_ci		if (old_clusters >= new_clusters) {
31558c2ecf20Sopenharmony_ci			credits += ocfs2_remove_extent_credits(inode->i_sb);
31568c2ecf20Sopenharmony_ci			goto out;
31578c2ecf20Sopenharmony_ci		} else {
31588c2ecf20Sopenharmony_ci			meta_add += ocfs2_extend_meta_needed(&xv->xr_list);
31598c2ecf20Sopenharmony_ci			clusters_add += new_clusters - old_clusters;
31608c2ecf20Sopenharmony_ci			credits += ocfs2_calc_extend_credits(inode->i_sb,
31618c2ecf20Sopenharmony_ci							     &xv->xr_list);
31628c2ecf20Sopenharmony_ci			if (value_size >= OCFS2_XATTR_ROOT_SIZE)
31638c2ecf20Sopenharmony_ci				goto out;
31648c2ecf20Sopenharmony_ci		}
31658c2ecf20Sopenharmony_ci	} else {
31668c2ecf20Sopenharmony_ci		/*
31678c2ecf20Sopenharmony_ci		 * Now the new value will be stored inside. So if the new
31688c2ecf20Sopenharmony_ci		 * value is smaller than the size of value root or the old
31698c2ecf20Sopenharmony_ci		 * value, we don't need any allocation, otherwise we have
31708c2ecf20Sopenharmony_ci		 * to guess metadata allocation.
31718c2ecf20Sopenharmony_ci		 */
31728c2ecf20Sopenharmony_ci		if ((ocfs2_xattr_is_local(xe) &&
31738c2ecf20Sopenharmony_ci		     (value_size >= xi->xi_value_len)) ||
31748c2ecf20Sopenharmony_ci		    (!ocfs2_xattr_is_local(xe) &&
31758c2ecf20Sopenharmony_ci		     OCFS2_XATTR_ROOT_SIZE >= xi->xi_value_len))
31768c2ecf20Sopenharmony_ci			goto out;
31778c2ecf20Sopenharmony_ci	}
31788c2ecf20Sopenharmony_ci
31798c2ecf20Sopenharmony_cimeta_guess:
31808c2ecf20Sopenharmony_ci	/* calculate metadata allocation. */
31818c2ecf20Sopenharmony_ci	if (di->i_xattr_loc) {
31828c2ecf20Sopenharmony_ci		if (!xbs->xattr_bh) {
31838c2ecf20Sopenharmony_ci			ret = ocfs2_read_xattr_block(inode,
31848c2ecf20Sopenharmony_ci						     le64_to_cpu(di->i_xattr_loc),
31858c2ecf20Sopenharmony_ci						     &bh);
31868c2ecf20Sopenharmony_ci			if (ret) {
31878c2ecf20Sopenharmony_ci				mlog_errno(ret);
31888c2ecf20Sopenharmony_ci				goto out;
31898c2ecf20Sopenharmony_ci			}
31908c2ecf20Sopenharmony_ci
31918c2ecf20Sopenharmony_ci			xb = (struct ocfs2_xattr_block *)bh->b_data;
31928c2ecf20Sopenharmony_ci		} else
31938c2ecf20Sopenharmony_ci			xb = (struct ocfs2_xattr_block *)xbs->xattr_bh->b_data;
31948c2ecf20Sopenharmony_ci
31958c2ecf20Sopenharmony_ci		/*
31968c2ecf20Sopenharmony_ci		 * If there is already an xattr tree, good, we can calculate
31978c2ecf20Sopenharmony_ci		 * like other b-trees. Otherwise we may have the chance of
31988c2ecf20Sopenharmony_ci		 * create a tree, the credit calculation is borrowed from
31998c2ecf20Sopenharmony_ci		 * ocfs2_calc_extend_credits with root_el = NULL. And the
32008c2ecf20Sopenharmony_ci		 * new tree will be cluster based, so no meta is needed.
32018c2ecf20Sopenharmony_ci		 */
32028c2ecf20Sopenharmony_ci		if (le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED) {
32038c2ecf20Sopenharmony_ci			struct ocfs2_extent_list *el =
32048c2ecf20Sopenharmony_ci				 &xb->xb_attrs.xb_root.xt_list;
32058c2ecf20Sopenharmony_ci			meta_add += ocfs2_extend_meta_needed(el);
32068c2ecf20Sopenharmony_ci			credits += ocfs2_calc_extend_credits(inode->i_sb,
32078c2ecf20Sopenharmony_ci							     el);
32088c2ecf20Sopenharmony_ci		} else
32098c2ecf20Sopenharmony_ci			credits += OCFS2_SUBALLOC_ALLOC + 1;
32108c2ecf20Sopenharmony_ci
32118c2ecf20Sopenharmony_ci		/*
32128c2ecf20Sopenharmony_ci		 * This cluster will be used either for new bucket or for
32138c2ecf20Sopenharmony_ci		 * new xattr block.
32148c2ecf20Sopenharmony_ci		 * If the cluster size is the same as the bucket size, one
32158c2ecf20Sopenharmony_ci		 * more is needed since we may need to extend the bucket
32168c2ecf20Sopenharmony_ci		 * also.
32178c2ecf20Sopenharmony_ci		 */
32188c2ecf20Sopenharmony_ci		clusters_add += 1;
32198c2ecf20Sopenharmony_ci		credits += ocfs2_blocks_per_xattr_bucket(inode->i_sb);
32208c2ecf20Sopenharmony_ci		if (OCFS2_XATTR_BUCKET_SIZE ==
32218c2ecf20Sopenharmony_ci			OCFS2_SB(inode->i_sb)->s_clustersize) {
32228c2ecf20Sopenharmony_ci			credits += ocfs2_blocks_per_xattr_bucket(inode->i_sb);
32238c2ecf20Sopenharmony_ci			clusters_add += 1;
32248c2ecf20Sopenharmony_ci		}
32258c2ecf20Sopenharmony_ci	} else {
32268c2ecf20Sopenharmony_ci		credits += OCFS2_XATTR_BLOCK_CREATE_CREDITS;
32278c2ecf20Sopenharmony_ci		if (xi->xi_value_len > OCFS2_XATTR_INLINE_SIZE) {
32288c2ecf20Sopenharmony_ci			struct ocfs2_extent_list *el = &def_xv.xv.xr_list;
32298c2ecf20Sopenharmony_ci			meta_add += ocfs2_extend_meta_needed(el);
32308c2ecf20Sopenharmony_ci			credits += ocfs2_calc_extend_credits(inode->i_sb,
32318c2ecf20Sopenharmony_ci							     el);
32328c2ecf20Sopenharmony_ci		} else {
32338c2ecf20Sopenharmony_ci			meta_add += 1;
32348c2ecf20Sopenharmony_ci		}
32358c2ecf20Sopenharmony_ci	}
32368c2ecf20Sopenharmony_ciout:
32378c2ecf20Sopenharmony_ci	if (clusters_need)
32388c2ecf20Sopenharmony_ci		*clusters_need = clusters_add;
32398c2ecf20Sopenharmony_ci	if (meta_need)
32408c2ecf20Sopenharmony_ci		*meta_need = meta_add;
32418c2ecf20Sopenharmony_ci	if (credits_need)
32428c2ecf20Sopenharmony_ci		*credits_need = credits;
32438c2ecf20Sopenharmony_ci	brelse(bh);
32448c2ecf20Sopenharmony_ci	return ret;
32458c2ecf20Sopenharmony_ci}
32468c2ecf20Sopenharmony_ci
32478c2ecf20Sopenharmony_cistatic int ocfs2_init_xattr_set_ctxt(struct inode *inode,
32488c2ecf20Sopenharmony_ci				     struct ocfs2_dinode *di,
32498c2ecf20Sopenharmony_ci				     struct ocfs2_xattr_info *xi,
32508c2ecf20Sopenharmony_ci				     struct ocfs2_xattr_search *xis,
32518c2ecf20Sopenharmony_ci				     struct ocfs2_xattr_search *xbs,
32528c2ecf20Sopenharmony_ci				     struct ocfs2_xattr_set_ctxt *ctxt,
32538c2ecf20Sopenharmony_ci				     int extra_meta,
32548c2ecf20Sopenharmony_ci				     int *credits)
32558c2ecf20Sopenharmony_ci{
32568c2ecf20Sopenharmony_ci	int clusters_add, meta_add, ret;
32578c2ecf20Sopenharmony_ci	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
32588c2ecf20Sopenharmony_ci
32598c2ecf20Sopenharmony_ci	memset(ctxt, 0, sizeof(struct ocfs2_xattr_set_ctxt));
32608c2ecf20Sopenharmony_ci
32618c2ecf20Sopenharmony_ci	ocfs2_init_dealloc_ctxt(&ctxt->dealloc);
32628c2ecf20Sopenharmony_ci
32638c2ecf20Sopenharmony_ci	ret = ocfs2_calc_xattr_set_need(inode, di, xi, xis, xbs,
32648c2ecf20Sopenharmony_ci					&clusters_add, &meta_add, credits);
32658c2ecf20Sopenharmony_ci	if (ret) {
32668c2ecf20Sopenharmony_ci		mlog_errno(ret);
32678c2ecf20Sopenharmony_ci		return ret;
32688c2ecf20Sopenharmony_ci	}
32698c2ecf20Sopenharmony_ci
32708c2ecf20Sopenharmony_ci	meta_add += extra_meta;
32718c2ecf20Sopenharmony_ci	trace_ocfs2_init_xattr_set_ctxt(xi->xi_name, meta_add,
32728c2ecf20Sopenharmony_ci					clusters_add, *credits);
32738c2ecf20Sopenharmony_ci
32748c2ecf20Sopenharmony_ci	if (meta_add) {
32758c2ecf20Sopenharmony_ci		ret = ocfs2_reserve_new_metadata_blocks(osb, meta_add,
32768c2ecf20Sopenharmony_ci							&ctxt->meta_ac);
32778c2ecf20Sopenharmony_ci		if (ret) {
32788c2ecf20Sopenharmony_ci			mlog_errno(ret);
32798c2ecf20Sopenharmony_ci			goto out;
32808c2ecf20Sopenharmony_ci		}
32818c2ecf20Sopenharmony_ci	}
32828c2ecf20Sopenharmony_ci
32838c2ecf20Sopenharmony_ci	if (clusters_add) {
32848c2ecf20Sopenharmony_ci		ret = ocfs2_reserve_clusters(osb, clusters_add, &ctxt->data_ac);
32858c2ecf20Sopenharmony_ci		if (ret)
32868c2ecf20Sopenharmony_ci			mlog_errno(ret);
32878c2ecf20Sopenharmony_ci	}
32888c2ecf20Sopenharmony_ciout:
32898c2ecf20Sopenharmony_ci	if (ret) {
32908c2ecf20Sopenharmony_ci		if (ctxt->meta_ac) {
32918c2ecf20Sopenharmony_ci			ocfs2_free_alloc_context(ctxt->meta_ac);
32928c2ecf20Sopenharmony_ci			ctxt->meta_ac = NULL;
32938c2ecf20Sopenharmony_ci		}
32948c2ecf20Sopenharmony_ci
32958c2ecf20Sopenharmony_ci		/*
32968c2ecf20Sopenharmony_ci		 * We cannot have an error and a non null ctxt->data_ac.
32978c2ecf20Sopenharmony_ci		 */
32988c2ecf20Sopenharmony_ci	}
32998c2ecf20Sopenharmony_ci
33008c2ecf20Sopenharmony_ci	return ret;
33018c2ecf20Sopenharmony_ci}
33028c2ecf20Sopenharmony_ci
33038c2ecf20Sopenharmony_cistatic int __ocfs2_xattr_set_handle(struct inode *inode,
33048c2ecf20Sopenharmony_ci				    struct ocfs2_dinode *di,
33058c2ecf20Sopenharmony_ci				    struct ocfs2_xattr_info *xi,
33068c2ecf20Sopenharmony_ci				    struct ocfs2_xattr_search *xis,
33078c2ecf20Sopenharmony_ci				    struct ocfs2_xattr_search *xbs,
33088c2ecf20Sopenharmony_ci				    struct ocfs2_xattr_set_ctxt *ctxt)
33098c2ecf20Sopenharmony_ci{
33108c2ecf20Sopenharmony_ci	int ret = 0, credits, old_found;
33118c2ecf20Sopenharmony_ci
33128c2ecf20Sopenharmony_ci	if (!xi->xi_value) {
33138c2ecf20Sopenharmony_ci		/* Remove existing extended attribute */
33148c2ecf20Sopenharmony_ci		if (!xis->not_found)
33158c2ecf20Sopenharmony_ci			ret = ocfs2_xattr_ibody_set(inode, xi, xis, ctxt);
33168c2ecf20Sopenharmony_ci		else if (!xbs->not_found)
33178c2ecf20Sopenharmony_ci			ret = ocfs2_xattr_block_set(inode, xi, xbs, ctxt);
33188c2ecf20Sopenharmony_ci	} else {
33198c2ecf20Sopenharmony_ci		/* We always try to set extended attribute into inode first*/
33208c2ecf20Sopenharmony_ci		ret = ocfs2_xattr_ibody_set(inode, xi, xis, ctxt);
33218c2ecf20Sopenharmony_ci		if (!ret && !xbs->not_found) {
33228c2ecf20Sopenharmony_ci			/*
33238c2ecf20Sopenharmony_ci			 * If succeed and that extended attribute existing in
33248c2ecf20Sopenharmony_ci			 * external block, then we will remove it.
33258c2ecf20Sopenharmony_ci			 */
33268c2ecf20Sopenharmony_ci			xi->xi_value = NULL;
33278c2ecf20Sopenharmony_ci			xi->xi_value_len = 0;
33288c2ecf20Sopenharmony_ci
33298c2ecf20Sopenharmony_ci			old_found = xis->not_found;
33308c2ecf20Sopenharmony_ci			xis->not_found = -ENODATA;
33318c2ecf20Sopenharmony_ci			ret = ocfs2_calc_xattr_set_need(inode,
33328c2ecf20Sopenharmony_ci							di,
33338c2ecf20Sopenharmony_ci							xi,
33348c2ecf20Sopenharmony_ci							xis,
33358c2ecf20Sopenharmony_ci							xbs,
33368c2ecf20Sopenharmony_ci							NULL,
33378c2ecf20Sopenharmony_ci							NULL,
33388c2ecf20Sopenharmony_ci							&credits);
33398c2ecf20Sopenharmony_ci			xis->not_found = old_found;
33408c2ecf20Sopenharmony_ci			if (ret) {
33418c2ecf20Sopenharmony_ci				mlog_errno(ret);
33428c2ecf20Sopenharmony_ci				goto out;
33438c2ecf20Sopenharmony_ci			}
33448c2ecf20Sopenharmony_ci
33458c2ecf20Sopenharmony_ci			ret = ocfs2_extend_trans(ctxt->handle, credits);
33468c2ecf20Sopenharmony_ci			if (ret) {
33478c2ecf20Sopenharmony_ci				mlog_errno(ret);
33488c2ecf20Sopenharmony_ci				goto out;
33498c2ecf20Sopenharmony_ci			}
33508c2ecf20Sopenharmony_ci			ret = ocfs2_xattr_block_set(inode, xi, xbs, ctxt);
33518c2ecf20Sopenharmony_ci		} else if ((ret == -ENOSPC) && !ctxt->set_abort) {
33528c2ecf20Sopenharmony_ci			if (di->i_xattr_loc && !xbs->xattr_bh) {
33538c2ecf20Sopenharmony_ci				ret = ocfs2_xattr_block_find(inode,
33548c2ecf20Sopenharmony_ci							     xi->xi_name_index,
33558c2ecf20Sopenharmony_ci							     xi->xi_name, xbs);
33568c2ecf20Sopenharmony_ci				if (ret)
33578c2ecf20Sopenharmony_ci					goto out;
33588c2ecf20Sopenharmony_ci
33598c2ecf20Sopenharmony_ci				old_found = xis->not_found;
33608c2ecf20Sopenharmony_ci				xis->not_found = -ENODATA;
33618c2ecf20Sopenharmony_ci				ret = ocfs2_calc_xattr_set_need(inode,
33628c2ecf20Sopenharmony_ci								di,
33638c2ecf20Sopenharmony_ci								xi,
33648c2ecf20Sopenharmony_ci								xis,
33658c2ecf20Sopenharmony_ci								xbs,
33668c2ecf20Sopenharmony_ci								NULL,
33678c2ecf20Sopenharmony_ci								NULL,
33688c2ecf20Sopenharmony_ci								&credits);
33698c2ecf20Sopenharmony_ci				xis->not_found = old_found;
33708c2ecf20Sopenharmony_ci				if (ret) {
33718c2ecf20Sopenharmony_ci					mlog_errno(ret);
33728c2ecf20Sopenharmony_ci					goto out;
33738c2ecf20Sopenharmony_ci				}
33748c2ecf20Sopenharmony_ci
33758c2ecf20Sopenharmony_ci				ret = ocfs2_extend_trans(ctxt->handle, credits);
33768c2ecf20Sopenharmony_ci				if (ret) {
33778c2ecf20Sopenharmony_ci					mlog_errno(ret);
33788c2ecf20Sopenharmony_ci					goto out;
33798c2ecf20Sopenharmony_ci				}
33808c2ecf20Sopenharmony_ci			}
33818c2ecf20Sopenharmony_ci			/*
33828c2ecf20Sopenharmony_ci			 * If no space in inode, we will set extended attribute
33838c2ecf20Sopenharmony_ci			 * into external block.
33848c2ecf20Sopenharmony_ci			 */
33858c2ecf20Sopenharmony_ci			ret = ocfs2_xattr_block_set(inode, xi, xbs, ctxt);
33868c2ecf20Sopenharmony_ci			if (ret)
33878c2ecf20Sopenharmony_ci				goto out;
33888c2ecf20Sopenharmony_ci			if (!xis->not_found) {
33898c2ecf20Sopenharmony_ci				/*
33908c2ecf20Sopenharmony_ci				 * If succeed and that extended attribute
33918c2ecf20Sopenharmony_ci				 * existing in inode, we will remove it.
33928c2ecf20Sopenharmony_ci				 */
33938c2ecf20Sopenharmony_ci				xi->xi_value = NULL;
33948c2ecf20Sopenharmony_ci				xi->xi_value_len = 0;
33958c2ecf20Sopenharmony_ci				xbs->not_found = -ENODATA;
33968c2ecf20Sopenharmony_ci				ret = ocfs2_calc_xattr_set_need(inode,
33978c2ecf20Sopenharmony_ci								di,
33988c2ecf20Sopenharmony_ci								xi,
33998c2ecf20Sopenharmony_ci								xis,
34008c2ecf20Sopenharmony_ci								xbs,
34018c2ecf20Sopenharmony_ci								NULL,
34028c2ecf20Sopenharmony_ci								NULL,
34038c2ecf20Sopenharmony_ci								&credits);
34048c2ecf20Sopenharmony_ci				if (ret) {
34058c2ecf20Sopenharmony_ci					mlog_errno(ret);
34068c2ecf20Sopenharmony_ci					goto out;
34078c2ecf20Sopenharmony_ci				}
34088c2ecf20Sopenharmony_ci
34098c2ecf20Sopenharmony_ci				ret = ocfs2_extend_trans(ctxt->handle, credits);
34108c2ecf20Sopenharmony_ci				if (ret) {
34118c2ecf20Sopenharmony_ci					mlog_errno(ret);
34128c2ecf20Sopenharmony_ci					goto out;
34138c2ecf20Sopenharmony_ci				}
34148c2ecf20Sopenharmony_ci				ret = ocfs2_xattr_ibody_set(inode, xi,
34158c2ecf20Sopenharmony_ci							    xis, ctxt);
34168c2ecf20Sopenharmony_ci			}
34178c2ecf20Sopenharmony_ci		}
34188c2ecf20Sopenharmony_ci	}
34198c2ecf20Sopenharmony_ci
34208c2ecf20Sopenharmony_ci	if (!ret) {
34218c2ecf20Sopenharmony_ci		/* Update inode ctime. */
34228c2ecf20Sopenharmony_ci		ret = ocfs2_journal_access_di(ctxt->handle, INODE_CACHE(inode),
34238c2ecf20Sopenharmony_ci					      xis->inode_bh,
34248c2ecf20Sopenharmony_ci					      OCFS2_JOURNAL_ACCESS_WRITE);
34258c2ecf20Sopenharmony_ci		if (ret) {
34268c2ecf20Sopenharmony_ci			mlog_errno(ret);
34278c2ecf20Sopenharmony_ci			goto out;
34288c2ecf20Sopenharmony_ci		}
34298c2ecf20Sopenharmony_ci
34308c2ecf20Sopenharmony_ci		inode->i_ctime = current_time(inode);
34318c2ecf20Sopenharmony_ci		di->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec);
34328c2ecf20Sopenharmony_ci		di->i_ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
34338c2ecf20Sopenharmony_ci		ocfs2_journal_dirty(ctxt->handle, xis->inode_bh);
34348c2ecf20Sopenharmony_ci	}
34358c2ecf20Sopenharmony_ciout:
34368c2ecf20Sopenharmony_ci	return ret;
34378c2ecf20Sopenharmony_ci}
34388c2ecf20Sopenharmony_ci
34398c2ecf20Sopenharmony_ci/*
34408c2ecf20Sopenharmony_ci * This function only called duing creating inode
34418c2ecf20Sopenharmony_ci * for init security/acl xattrs of the new inode.
34428c2ecf20Sopenharmony_ci * All transanction credits have been reserved in mknod.
34438c2ecf20Sopenharmony_ci */
34448c2ecf20Sopenharmony_ciint ocfs2_xattr_set_handle(handle_t *handle,
34458c2ecf20Sopenharmony_ci			   struct inode *inode,
34468c2ecf20Sopenharmony_ci			   struct buffer_head *di_bh,
34478c2ecf20Sopenharmony_ci			   int name_index,
34488c2ecf20Sopenharmony_ci			   const char *name,
34498c2ecf20Sopenharmony_ci			   const void *value,
34508c2ecf20Sopenharmony_ci			   size_t value_len,
34518c2ecf20Sopenharmony_ci			   int flags,
34528c2ecf20Sopenharmony_ci			   struct ocfs2_alloc_context *meta_ac,
34538c2ecf20Sopenharmony_ci			   struct ocfs2_alloc_context *data_ac)
34548c2ecf20Sopenharmony_ci{
34558c2ecf20Sopenharmony_ci	struct ocfs2_dinode *di;
34568c2ecf20Sopenharmony_ci	int ret;
34578c2ecf20Sopenharmony_ci
34588c2ecf20Sopenharmony_ci	struct ocfs2_xattr_info xi = {
34598c2ecf20Sopenharmony_ci		.xi_name_index = name_index,
34608c2ecf20Sopenharmony_ci		.xi_name = name,
34618c2ecf20Sopenharmony_ci		.xi_name_len = strlen(name),
34628c2ecf20Sopenharmony_ci		.xi_value = value,
34638c2ecf20Sopenharmony_ci		.xi_value_len = value_len,
34648c2ecf20Sopenharmony_ci	};
34658c2ecf20Sopenharmony_ci
34668c2ecf20Sopenharmony_ci	struct ocfs2_xattr_search xis = {
34678c2ecf20Sopenharmony_ci		.not_found = -ENODATA,
34688c2ecf20Sopenharmony_ci	};
34698c2ecf20Sopenharmony_ci
34708c2ecf20Sopenharmony_ci	struct ocfs2_xattr_search xbs = {
34718c2ecf20Sopenharmony_ci		.not_found = -ENODATA,
34728c2ecf20Sopenharmony_ci	};
34738c2ecf20Sopenharmony_ci
34748c2ecf20Sopenharmony_ci	struct ocfs2_xattr_set_ctxt ctxt = {
34758c2ecf20Sopenharmony_ci		.handle = handle,
34768c2ecf20Sopenharmony_ci		.meta_ac = meta_ac,
34778c2ecf20Sopenharmony_ci		.data_ac = data_ac,
34788c2ecf20Sopenharmony_ci	};
34798c2ecf20Sopenharmony_ci
34808c2ecf20Sopenharmony_ci	if (!ocfs2_supports_xattr(OCFS2_SB(inode->i_sb)))
34818c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
34828c2ecf20Sopenharmony_ci
34838c2ecf20Sopenharmony_ci	/*
34848c2ecf20Sopenharmony_ci	 * In extreme situation, may need xattr bucket when
34858c2ecf20Sopenharmony_ci	 * block size is too small. And we have already reserved
34868c2ecf20Sopenharmony_ci	 * the credits for bucket in mknod.
34878c2ecf20Sopenharmony_ci	 */
34888c2ecf20Sopenharmony_ci	if (inode->i_sb->s_blocksize == OCFS2_MIN_BLOCKSIZE) {
34898c2ecf20Sopenharmony_ci		xbs.bucket = ocfs2_xattr_bucket_new(inode);
34908c2ecf20Sopenharmony_ci		if (!xbs.bucket) {
34918c2ecf20Sopenharmony_ci			mlog_errno(-ENOMEM);
34928c2ecf20Sopenharmony_ci			return -ENOMEM;
34938c2ecf20Sopenharmony_ci		}
34948c2ecf20Sopenharmony_ci	}
34958c2ecf20Sopenharmony_ci
34968c2ecf20Sopenharmony_ci	xis.inode_bh = xbs.inode_bh = di_bh;
34978c2ecf20Sopenharmony_ci	di = (struct ocfs2_dinode *)di_bh->b_data;
34988c2ecf20Sopenharmony_ci
34998c2ecf20Sopenharmony_ci	down_write(&OCFS2_I(inode)->ip_xattr_sem);
35008c2ecf20Sopenharmony_ci
35018c2ecf20Sopenharmony_ci	ret = ocfs2_xattr_ibody_find(inode, name_index, name, &xis);
35028c2ecf20Sopenharmony_ci	if (ret)
35038c2ecf20Sopenharmony_ci		goto cleanup;
35048c2ecf20Sopenharmony_ci	if (xis.not_found) {
35058c2ecf20Sopenharmony_ci		ret = ocfs2_xattr_block_find(inode, name_index, name, &xbs);
35068c2ecf20Sopenharmony_ci		if (ret)
35078c2ecf20Sopenharmony_ci			goto cleanup;
35088c2ecf20Sopenharmony_ci	}
35098c2ecf20Sopenharmony_ci
35108c2ecf20Sopenharmony_ci	ret = __ocfs2_xattr_set_handle(inode, di, &xi, &xis, &xbs, &ctxt);
35118c2ecf20Sopenharmony_ci
35128c2ecf20Sopenharmony_cicleanup:
35138c2ecf20Sopenharmony_ci	up_write(&OCFS2_I(inode)->ip_xattr_sem);
35148c2ecf20Sopenharmony_ci	brelse(xbs.xattr_bh);
35158c2ecf20Sopenharmony_ci	ocfs2_xattr_bucket_free(xbs.bucket);
35168c2ecf20Sopenharmony_ci
35178c2ecf20Sopenharmony_ci	return ret;
35188c2ecf20Sopenharmony_ci}
35198c2ecf20Sopenharmony_ci
35208c2ecf20Sopenharmony_ci/*
35218c2ecf20Sopenharmony_ci * ocfs2_xattr_set()
35228c2ecf20Sopenharmony_ci *
35238c2ecf20Sopenharmony_ci * Set, replace or remove an extended attribute for this inode.
35248c2ecf20Sopenharmony_ci * value is NULL to remove an existing extended attribute, else either
35258c2ecf20Sopenharmony_ci * create or replace an extended attribute.
35268c2ecf20Sopenharmony_ci */
35278c2ecf20Sopenharmony_ciint ocfs2_xattr_set(struct inode *inode,
35288c2ecf20Sopenharmony_ci		    int name_index,
35298c2ecf20Sopenharmony_ci		    const char *name,
35308c2ecf20Sopenharmony_ci		    const void *value,
35318c2ecf20Sopenharmony_ci		    size_t value_len,
35328c2ecf20Sopenharmony_ci		    int flags)
35338c2ecf20Sopenharmony_ci{
35348c2ecf20Sopenharmony_ci	struct buffer_head *di_bh = NULL;
35358c2ecf20Sopenharmony_ci	struct ocfs2_dinode *di;
35368c2ecf20Sopenharmony_ci	int ret, credits, had_lock, ref_meta = 0, ref_credits = 0;
35378c2ecf20Sopenharmony_ci	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
35388c2ecf20Sopenharmony_ci	struct inode *tl_inode = osb->osb_tl_inode;
35398c2ecf20Sopenharmony_ci	struct ocfs2_xattr_set_ctxt ctxt = { NULL, NULL, NULL, };
35408c2ecf20Sopenharmony_ci	struct ocfs2_refcount_tree *ref_tree = NULL;
35418c2ecf20Sopenharmony_ci	struct ocfs2_lock_holder oh;
35428c2ecf20Sopenharmony_ci
35438c2ecf20Sopenharmony_ci	struct ocfs2_xattr_info xi = {
35448c2ecf20Sopenharmony_ci		.xi_name_index = name_index,
35458c2ecf20Sopenharmony_ci		.xi_name = name,
35468c2ecf20Sopenharmony_ci		.xi_name_len = strlen(name),
35478c2ecf20Sopenharmony_ci		.xi_value = value,
35488c2ecf20Sopenharmony_ci		.xi_value_len = value_len,
35498c2ecf20Sopenharmony_ci	};
35508c2ecf20Sopenharmony_ci
35518c2ecf20Sopenharmony_ci	struct ocfs2_xattr_search xis = {
35528c2ecf20Sopenharmony_ci		.not_found = -ENODATA,
35538c2ecf20Sopenharmony_ci	};
35548c2ecf20Sopenharmony_ci
35558c2ecf20Sopenharmony_ci	struct ocfs2_xattr_search xbs = {
35568c2ecf20Sopenharmony_ci		.not_found = -ENODATA,
35578c2ecf20Sopenharmony_ci	};
35588c2ecf20Sopenharmony_ci
35598c2ecf20Sopenharmony_ci	if (!ocfs2_supports_xattr(osb))
35608c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
35618c2ecf20Sopenharmony_ci
35628c2ecf20Sopenharmony_ci	/*
35638c2ecf20Sopenharmony_ci	 * Only xbs will be used on indexed trees.  xis doesn't need a
35648c2ecf20Sopenharmony_ci	 * bucket.
35658c2ecf20Sopenharmony_ci	 */
35668c2ecf20Sopenharmony_ci	xbs.bucket = ocfs2_xattr_bucket_new(inode);
35678c2ecf20Sopenharmony_ci	if (!xbs.bucket) {
35688c2ecf20Sopenharmony_ci		mlog_errno(-ENOMEM);
35698c2ecf20Sopenharmony_ci		return -ENOMEM;
35708c2ecf20Sopenharmony_ci	}
35718c2ecf20Sopenharmony_ci
35728c2ecf20Sopenharmony_ci	had_lock = ocfs2_inode_lock_tracker(inode, &di_bh, 1, &oh);
35738c2ecf20Sopenharmony_ci	if (had_lock < 0) {
35748c2ecf20Sopenharmony_ci		ret = had_lock;
35758c2ecf20Sopenharmony_ci		mlog_errno(ret);
35768c2ecf20Sopenharmony_ci		goto cleanup_nolock;
35778c2ecf20Sopenharmony_ci	}
35788c2ecf20Sopenharmony_ci	xis.inode_bh = xbs.inode_bh = di_bh;
35798c2ecf20Sopenharmony_ci	di = (struct ocfs2_dinode *)di_bh->b_data;
35808c2ecf20Sopenharmony_ci
35818c2ecf20Sopenharmony_ci	down_write(&OCFS2_I(inode)->ip_xattr_sem);
35828c2ecf20Sopenharmony_ci	/*
35838c2ecf20Sopenharmony_ci	 * Scan inode and external block to find the same name
35848c2ecf20Sopenharmony_ci	 * extended attribute and collect search information.
35858c2ecf20Sopenharmony_ci	 */
35868c2ecf20Sopenharmony_ci	ret = ocfs2_xattr_ibody_find(inode, name_index, name, &xis);
35878c2ecf20Sopenharmony_ci	if (ret)
35888c2ecf20Sopenharmony_ci		goto cleanup;
35898c2ecf20Sopenharmony_ci	if (xis.not_found) {
35908c2ecf20Sopenharmony_ci		ret = ocfs2_xattr_block_find(inode, name_index, name, &xbs);
35918c2ecf20Sopenharmony_ci		if (ret)
35928c2ecf20Sopenharmony_ci			goto cleanup;
35938c2ecf20Sopenharmony_ci	}
35948c2ecf20Sopenharmony_ci
35958c2ecf20Sopenharmony_ci	if (xis.not_found && xbs.not_found) {
35968c2ecf20Sopenharmony_ci		ret = -ENODATA;
35978c2ecf20Sopenharmony_ci		if (flags & XATTR_REPLACE)
35988c2ecf20Sopenharmony_ci			goto cleanup;
35998c2ecf20Sopenharmony_ci		ret = 0;
36008c2ecf20Sopenharmony_ci		if (!value)
36018c2ecf20Sopenharmony_ci			goto cleanup;
36028c2ecf20Sopenharmony_ci	} else {
36038c2ecf20Sopenharmony_ci		ret = -EEXIST;
36048c2ecf20Sopenharmony_ci		if (flags & XATTR_CREATE)
36058c2ecf20Sopenharmony_ci			goto cleanup;
36068c2ecf20Sopenharmony_ci	}
36078c2ecf20Sopenharmony_ci
36088c2ecf20Sopenharmony_ci	/* Check whether the value is refcounted and do some preparation. */
36098c2ecf20Sopenharmony_ci	if (ocfs2_is_refcount_inode(inode) &&
36108c2ecf20Sopenharmony_ci	    (!xis.not_found || !xbs.not_found)) {
36118c2ecf20Sopenharmony_ci		ret = ocfs2_prepare_refcount_xattr(inode, di, &xi,
36128c2ecf20Sopenharmony_ci						   &xis, &xbs, &ref_tree,
36138c2ecf20Sopenharmony_ci						   &ref_meta, &ref_credits);
36148c2ecf20Sopenharmony_ci		if (ret) {
36158c2ecf20Sopenharmony_ci			mlog_errno(ret);
36168c2ecf20Sopenharmony_ci			goto cleanup;
36178c2ecf20Sopenharmony_ci		}
36188c2ecf20Sopenharmony_ci	}
36198c2ecf20Sopenharmony_ci
36208c2ecf20Sopenharmony_ci	inode_lock(tl_inode);
36218c2ecf20Sopenharmony_ci
36228c2ecf20Sopenharmony_ci	if (ocfs2_truncate_log_needs_flush(osb)) {
36238c2ecf20Sopenharmony_ci		ret = __ocfs2_flush_truncate_log(osb);
36248c2ecf20Sopenharmony_ci		if (ret < 0) {
36258c2ecf20Sopenharmony_ci			inode_unlock(tl_inode);
36268c2ecf20Sopenharmony_ci			mlog_errno(ret);
36278c2ecf20Sopenharmony_ci			goto cleanup;
36288c2ecf20Sopenharmony_ci		}
36298c2ecf20Sopenharmony_ci	}
36308c2ecf20Sopenharmony_ci	inode_unlock(tl_inode);
36318c2ecf20Sopenharmony_ci
36328c2ecf20Sopenharmony_ci	ret = ocfs2_init_xattr_set_ctxt(inode, di, &xi, &xis,
36338c2ecf20Sopenharmony_ci					&xbs, &ctxt, ref_meta, &credits);
36348c2ecf20Sopenharmony_ci	if (ret) {
36358c2ecf20Sopenharmony_ci		mlog_errno(ret);
36368c2ecf20Sopenharmony_ci		goto cleanup;
36378c2ecf20Sopenharmony_ci	}
36388c2ecf20Sopenharmony_ci
36398c2ecf20Sopenharmony_ci	/* we need to update inode's ctime field, so add credit for it. */
36408c2ecf20Sopenharmony_ci	credits += OCFS2_INODE_UPDATE_CREDITS;
36418c2ecf20Sopenharmony_ci	ctxt.handle = ocfs2_start_trans(osb, credits + ref_credits);
36428c2ecf20Sopenharmony_ci	if (IS_ERR(ctxt.handle)) {
36438c2ecf20Sopenharmony_ci		ret = PTR_ERR(ctxt.handle);
36448c2ecf20Sopenharmony_ci		mlog_errno(ret);
36458c2ecf20Sopenharmony_ci		goto out_free_ac;
36468c2ecf20Sopenharmony_ci	}
36478c2ecf20Sopenharmony_ci
36488c2ecf20Sopenharmony_ci	ret = __ocfs2_xattr_set_handle(inode, di, &xi, &xis, &xbs, &ctxt);
36498c2ecf20Sopenharmony_ci	ocfs2_update_inode_fsync_trans(ctxt.handle, inode, 0);
36508c2ecf20Sopenharmony_ci
36518c2ecf20Sopenharmony_ci	ocfs2_commit_trans(osb, ctxt.handle);
36528c2ecf20Sopenharmony_ci
36538c2ecf20Sopenharmony_ciout_free_ac:
36548c2ecf20Sopenharmony_ci	if (ctxt.data_ac)
36558c2ecf20Sopenharmony_ci		ocfs2_free_alloc_context(ctxt.data_ac);
36568c2ecf20Sopenharmony_ci	if (ctxt.meta_ac)
36578c2ecf20Sopenharmony_ci		ocfs2_free_alloc_context(ctxt.meta_ac);
36588c2ecf20Sopenharmony_ci	if (ocfs2_dealloc_has_cluster(&ctxt.dealloc))
36598c2ecf20Sopenharmony_ci		ocfs2_schedule_truncate_log_flush(osb, 1);
36608c2ecf20Sopenharmony_ci	ocfs2_run_deallocs(osb, &ctxt.dealloc);
36618c2ecf20Sopenharmony_ci
36628c2ecf20Sopenharmony_cicleanup:
36638c2ecf20Sopenharmony_ci	if (ref_tree)
36648c2ecf20Sopenharmony_ci		ocfs2_unlock_refcount_tree(osb, ref_tree, 1);
36658c2ecf20Sopenharmony_ci	up_write(&OCFS2_I(inode)->ip_xattr_sem);
36668c2ecf20Sopenharmony_ci	if (!value && !ret) {
36678c2ecf20Sopenharmony_ci		ret = ocfs2_try_remove_refcount_tree(inode, di_bh);
36688c2ecf20Sopenharmony_ci		if (ret)
36698c2ecf20Sopenharmony_ci			mlog_errno(ret);
36708c2ecf20Sopenharmony_ci	}
36718c2ecf20Sopenharmony_ci	ocfs2_inode_unlock_tracker(inode, 1, &oh, had_lock);
36728c2ecf20Sopenharmony_cicleanup_nolock:
36738c2ecf20Sopenharmony_ci	brelse(di_bh);
36748c2ecf20Sopenharmony_ci	brelse(xbs.xattr_bh);
36758c2ecf20Sopenharmony_ci	ocfs2_xattr_bucket_free(xbs.bucket);
36768c2ecf20Sopenharmony_ci
36778c2ecf20Sopenharmony_ci	return ret;
36788c2ecf20Sopenharmony_ci}
36798c2ecf20Sopenharmony_ci
36808c2ecf20Sopenharmony_ci/*
36818c2ecf20Sopenharmony_ci * Find the xattr extent rec which may contains name_hash.
36828c2ecf20Sopenharmony_ci * e_cpos will be the first name hash of the xattr rec.
36838c2ecf20Sopenharmony_ci * el must be the ocfs2_xattr_header.xb_attrs.xb_root.xt_list.
36848c2ecf20Sopenharmony_ci */
36858c2ecf20Sopenharmony_cistatic int ocfs2_xattr_get_rec(struct inode *inode,
36868c2ecf20Sopenharmony_ci			       u32 name_hash,
36878c2ecf20Sopenharmony_ci			       u64 *p_blkno,
36888c2ecf20Sopenharmony_ci			       u32 *e_cpos,
36898c2ecf20Sopenharmony_ci			       u32 *num_clusters,
36908c2ecf20Sopenharmony_ci			       struct ocfs2_extent_list *el)
36918c2ecf20Sopenharmony_ci{
36928c2ecf20Sopenharmony_ci	int ret = 0, i;
36938c2ecf20Sopenharmony_ci	struct buffer_head *eb_bh = NULL;
36948c2ecf20Sopenharmony_ci	struct ocfs2_extent_block *eb;
36958c2ecf20Sopenharmony_ci	struct ocfs2_extent_rec *rec = NULL;
36968c2ecf20Sopenharmony_ci	u64 e_blkno = 0;
36978c2ecf20Sopenharmony_ci
36988c2ecf20Sopenharmony_ci	if (el->l_tree_depth) {
36998c2ecf20Sopenharmony_ci		ret = ocfs2_find_leaf(INODE_CACHE(inode), el, name_hash,
37008c2ecf20Sopenharmony_ci				      &eb_bh);
37018c2ecf20Sopenharmony_ci		if (ret) {
37028c2ecf20Sopenharmony_ci			mlog_errno(ret);
37038c2ecf20Sopenharmony_ci			goto out;
37048c2ecf20Sopenharmony_ci		}
37058c2ecf20Sopenharmony_ci
37068c2ecf20Sopenharmony_ci		eb = (struct ocfs2_extent_block *) eb_bh->b_data;
37078c2ecf20Sopenharmony_ci		el = &eb->h_list;
37088c2ecf20Sopenharmony_ci
37098c2ecf20Sopenharmony_ci		if (el->l_tree_depth) {
37108c2ecf20Sopenharmony_ci			ret = ocfs2_error(inode->i_sb,
37118c2ecf20Sopenharmony_ci					  "Inode %lu has non zero tree depth in xattr tree block %llu\n",
37128c2ecf20Sopenharmony_ci					  inode->i_ino,
37138c2ecf20Sopenharmony_ci					  (unsigned long long)eb_bh->b_blocknr);
37148c2ecf20Sopenharmony_ci			goto out;
37158c2ecf20Sopenharmony_ci		}
37168c2ecf20Sopenharmony_ci	}
37178c2ecf20Sopenharmony_ci
37188c2ecf20Sopenharmony_ci	for (i = le16_to_cpu(el->l_next_free_rec) - 1; i >= 0; i--) {
37198c2ecf20Sopenharmony_ci		rec = &el->l_recs[i];
37208c2ecf20Sopenharmony_ci
37218c2ecf20Sopenharmony_ci		if (le32_to_cpu(rec->e_cpos) <= name_hash) {
37228c2ecf20Sopenharmony_ci			e_blkno = le64_to_cpu(rec->e_blkno);
37238c2ecf20Sopenharmony_ci			break;
37248c2ecf20Sopenharmony_ci		}
37258c2ecf20Sopenharmony_ci	}
37268c2ecf20Sopenharmony_ci
37278c2ecf20Sopenharmony_ci	if (!e_blkno) {
37288c2ecf20Sopenharmony_ci		ret = ocfs2_error(inode->i_sb, "Inode %lu has bad extent record (%u, %u, 0) in xattr\n",
37298c2ecf20Sopenharmony_ci				  inode->i_ino,
37308c2ecf20Sopenharmony_ci				  le32_to_cpu(rec->e_cpos),
37318c2ecf20Sopenharmony_ci				  ocfs2_rec_clusters(el, rec));
37328c2ecf20Sopenharmony_ci		goto out;
37338c2ecf20Sopenharmony_ci	}
37348c2ecf20Sopenharmony_ci
37358c2ecf20Sopenharmony_ci	*p_blkno = le64_to_cpu(rec->e_blkno);
37368c2ecf20Sopenharmony_ci	*num_clusters = le16_to_cpu(rec->e_leaf_clusters);
37378c2ecf20Sopenharmony_ci	if (e_cpos)
37388c2ecf20Sopenharmony_ci		*e_cpos = le32_to_cpu(rec->e_cpos);
37398c2ecf20Sopenharmony_ciout:
37408c2ecf20Sopenharmony_ci	brelse(eb_bh);
37418c2ecf20Sopenharmony_ci	return ret;
37428c2ecf20Sopenharmony_ci}
37438c2ecf20Sopenharmony_ci
37448c2ecf20Sopenharmony_citypedef int (xattr_bucket_func)(struct inode *inode,
37458c2ecf20Sopenharmony_ci				struct ocfs2_xattr_bucket *bucket,
37468c2ecf20Sopenharmony_ci				void *para);
37478c2ecf20Sopenharmony_ci
37488c2ecf20Sopenharmony_cistatic int ocfs2_find_xe_in_bucket(struct inode *inode,
37498c2ecf20Sopenharmony_ci				   struct ocfs2_xattr_bucket *bucket,
37508c2ecf20Sopenharmony_ci				   int name_index,
37518c2ecf20Sopenharmony_ci				   const char *name,
37528c2ecf20Sopenharmony_ci				   u32 name_hash,
37538c2ecf20Sopenharmony_ci				   u16 *xe_index,
37548c2ecf20Sopenharmony_ci				   int *found)
37558c2ecf20Sopenharmony_ci{
37568c2ecf20Sopenharmony_ci	int i, ret = 0, cmp = 1, block_off, new_offset;
37578c2ecf20Sopenharmony_ci	struct ocfs2_xattr_header *xh = bucket_xh(bucket);
37588c2ecf20Sopenharmony_ci	size_t name_len = strlen(name);
37598c2ecf20Sopenharmony_ci	struct ocfs2_xattr_entry *xe = NULL;
37608c2ecf20Sopenharmony_ci	char *xe_name;
37618c2ecf20Sopenharmony_ci
37628c2ecf20Sopenharmony_ci	/*
37638c2ecf20Sopenharmony_ci	 * We don't use binary search in the bucket because there
37648c2ecf20Sopenharmony_ci	 * may be multiple entries with the same name hash.
37658c2ecf20Sopenharmony_ci	 */
37668c2ecf20Sopenharmony_ci	for (i = 0; i < le16_to_cpu(xh->xh_count); i++) {
37678c2ecf20Sopenharmony_ci		xe = &xh->xh_entries[i];
37688c2ecf20Sopenharmony_ci
37698c2ecf20Sopenharmony_ci		if (name_hash > le32_to_cpu(xe->xe_name_hash))
37708c2ecf20Sopenharmony_ci			continue;
37718c2ecf20Sopenharmony_ci		else if (name_hash < le32_to_cpu(xe->xe_name_hash))
37728c2ecf20Sopenharmony_ci			break;
37738c2ecf20Sopenharmony_ci
37748c2ecf20Sopenharmony_ci		cmp = name_index - ocfs2_xattr_get_type(xe);
37758c2ecf20Sopenharmony_ci		if (!cmp)
37768c2ecf20Sopenharmony_ci			cmp = name_len - xe->xe_name_len;
37778c2ecf20Sopenharmony_ci		if (cmp)
37788c2ecf20Sopenharmony_ci			continue;
37798c2ecf20Sopenharmony_ci
37808c2ecf20Sopenharmony_ci		ret = ocfs2_xattr_bucket_get_name_value(inode->i_sb,
37818c2ecf20Sopenharmony_ci							xh,
37828c2ecf20Sopenharmony_ci							i,
37838c2ecf20Sopenharmony_ci							&block_off,
37848c2ecf20Sopenharmony_ci							&new_offset);
37858c2ecf20Sopenharmony_ci		if (ret) {
37868c2ecf20Sopenharmony_ci			mlog_errno(ret);
37878c2ecf20Sopenharmony_ci			break;
37888c2ecf20Sopenharmony_ci		}
37898c2ecf20Sopenharmony_ci
37908c2ecf20Sopenharmony_ci
37918c2ecf20Sopenharmony_ci		xe_name = bucket_block(bucket, block_off) + new_offset;
37928c2ecf20Sopenharmony_ci		if (!memcmp(name, xe_name, name_len)) {
37938c2ecf20Sopenharmony_ci			*xe_index = i;
37948c2ecf20Sopenharmony_ci			*found = 1;
37958c2ecf20Sopenharmony_ci			ret = 0;
37968c2ecf20Sopenharmony_ci			break;
37978c2ecf20Sopenharmony_ci		}
37988c2ecf20Sopenharmony_ci	}
37998c2ecf20Sopenharmony_ci
38008c2ecf20Sopenharmony_ci	return ret;
38018c2ecf20Sopenharmony_ci}
38028c2ecf20Sopenharmony_ci
38038c2ecf20Sopenharmony_ci/*
38048c2ecf20Sopenharmony_ci * Find the specified xattr entry in a series of buckets.
38058c2ecf20Sopenharmony_ci * This series start from p_blkno and last for num_clusters.
38068c2ecf20Sopenharmony_ci * The ocfs2_xattr_header.xh_num_buckets of the first bucket contains
38078c2ecf20Sopenharmony_ci * the num of the valid buckets.
38088c2ecf20Sopenharmony_ci *
38098c2ecf20Sopenharmony_ci * Return the buffer_head this xattr should reside in. And if the xattr's
38108c2ecf20Sopenharmony_ci * hash is in the gap of 2 buckets, return the lower bucket.
38118c2ecf20Sopenharmony_ci */
38128c2ecf20Sopenharmony_cistatic int ocfs2_xattr_bucket_find(struct inode *inode,
38138c2ecf20Sopenharmony_ci				   int name_index,
38148c2ecf20Sopenharmony_ci				   const char *name,
38158c2ecf20Sopenharmony_ci				   u32 name_hash,
38168c2ecf20Sopenharmony_ci				   u64 p_blkno,
38178c2ecf20Sopenharmony_ci				   u32 first_hash,
38188c2ecf20Sopenharmony_ci				   u32 num_clusters,
38198c2ecf20Sopenharmony_ci				   struct ocfs2_xattr_search *xs)
38208c2ecf20Sopenharmony_ci{
38218c2ecf20Sopenharmony_ci	int ret, found = 0;
38228c2ecf20Sopenharmony_ci	struct ocfs2_xattr_header *xh = NULL;
38238c2ecf20Sopenharmony_ci	struct ocfs2_xattr_entry *xe = NULL;
38248c2ecf20Sopenharmony_ci	u16 index = 0;
38258c2ecf20Sopenharmony_ci	u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
38268c2ecf20Sopenharmony_ci	int low_bucket = 0, bucket, high_bucket;
38278c2ecf20Sopenharmony_ci	struct ocfs2_xattr_bucket *search;
38288c2ecf20Sopenharmony_ci	u64 blkno, lower_blkno = 0;
38298c2ecf20Sopenharmony_ci
38308c2ecf20Sopenharmony_ci	search = ocfs2_xattr_bucket_new(inode);
38318c2ecf20Sopenharmony_ci	if (!search) {
38328c2ecf20Sopenharmony_ci		ret = -ENOMEM;
38338c2ecf20Sopenharmony_ci		mlog_errno(ret);
38348c2ecf20Sopenharmony_ci		goto out;
38358c2ecf20Sopenharmony_ci	}
38368c2ecf20Sopenharmony_ci
38378c2ecf20Sopenharmony_ci	ret = ocfs2_read_xattr_bucket(search, p_blkno);
38388c2ecf20Sopenharmony_ci	if (ret) {
38398c2ecf20Sopenharmony_ci		mlog_errno(ret);
38408c2ecf20Sopenharmony_ci		goto out;
38418c2ecf20Sopenharmony_ci	}
38428c2ecf20Sopenharmony_ci
38438c2ecf20Sopenharmony_ci	xh = bucket_xh(search);
38448c2ecf20Sopenharmony_ci	high_bucket = le16_to_cpu(xh->xh_num_buckets) - 1;
38458c2ecf20Sopenharmony_ci	while (low_bucket <= high_bucket) {
38468c2ecf20Sopenharmony_ci		ocfs2_xattr_bucket_relse(search);
38478c2ecf20Sopenharmony_ci
38488c2ecf20Sopenharmony_ci		bucket = (low_bucket + high_bucket) / 2;
38498c2ecf20Sopenharmony_ci		blkno = p_blkno + bucket * blk_per_bucket;
38508c2ecf20Sopenharmony_ci		ret = ocfs2_read_xattr_bucket(search, blkno);
38518c2ecf20Sopenharmony_ci		if (ret) {
38528c2ecf20Sopenharmony_ci			mlog_errno(ret);
38538c2ecf20Sopenharmony_ci			goto out;
38548c2ecf20Sopenharmony_ci		}
38558c2ecf20Sopenharmony_ci
38568c2ecf20Sopenharmony_ci		xh = bucket_xh(search);
38578c2ecf20Sopenharmony_ci		xe = &xh->xh_entries[0];
38588c2ecf20Sopenharmony_ci		if (name_hash < le32_to_cpu(xe->xe_name_hash)) {
38598c2ecf20Sopenharmony_ci			high_bucket = bucket - 1;
38608c2ecf20Sopenharmony_ci			continue;
38618c2ecf20Sopenharmony_ci		}
38628c2ecf20Sopenharmony_ci
38638c2ecf20Sopenharmony_ci		/*
38648c2ecf20Sopenharmony_ci		 * Check whether the hash of the last entry in our
38658c2ecf20Sopenharmony_ci		 * bucket is larger than the search one. for an empty
38668c2ecf20Sopenharmony_ci		 * bucket, the last one is also the first one.
38678c2ecf20Sopenharmony_ci		 */
38688c2ecf20Sopenharmony_ci		if (xh->xh_count)
38698c2ecf20Sopenharmony_ci			xe = &xh->xh_entries[le16_to_cpu(xh->xh_count) - 1];
38708c2ecf20Sopenharmony_ci
38718c2ecf20Sopenharmony_ci		/* record lower_blkno which may be the insert place. */
38728c2ecf20Sopenharmony_ci		lower_blkno = blkno;
38738c2ecf20Sopenharmony_ci
38748c2ecf20Sopenharmony_ci		if (name_hash > le32_to_cpu(xe->xe_name_hash)) {
38758c2ecf20Sopenharmony_ci			low_bucket = bucket + 1;
38768c2ecf20Sopenharmony_ci			continue;
38778c2ecf20Sopenharmony_ci		}
38788c2ecf20Sopenharmony_ci
38798c2ecf20Sopenharmony_ci		/* the searched xattr should reside in this bucket if exists. */
38808c2ecf20Sopenharmony_ci		ret = ocfs2_find_xe_in_bucket(inode, search,
38818c2ecf20Sopenharmony_ci					      name_index, name, name_hash,
38828c2ecf20Sopenharmony_ci					      &index, &found);
38838c2ecf20Sopenharmony_ci		if (ret) {
38848c2ecf20Sopenharmony_ci			mlog_errno(ret);
38858c2ecf20Sopenharmony_ci			goto out;
38868c2ecf20Sopenharmony_ci		}
38878c2ecf20Sopenharmony_ci		break;
38888c2ecf20Sopenharmony_ci	}
38898c2ecf20Sopenharmony_ci
38908c2ecf20Sopenharmony_ci	/*
38918c2ecf20Sopenharmony_ci	 * Record the bucket we have found.
38928c2ecf20Sopenharmony_ci	 * When the xattr's hash value is in the gap of 2 buckets, we will
38938c2ecf20Sopenharmony_ci	 * always set it to the previous bucket.
38948c2ecf20Sopenharmony_ci	 */
38958c2ecf20Sopenharmony_ci	if (!lower_blkno)
38968c2ecf20Sopenharmony_ci		lower_blkno = p_blkno;
38978c2ecf20Sopenharmony_ci
38988c2ecf20Sopenharmony_ci	/* This should be in cache - we just read it during the search */
38998c2ecf20Sopenharmony_ci	ret = ocfs2_read_xattr_bucket(xs->bucket, lower_blkno);
39008c2ecf20Sopenharmony_ci	if (ret) {
39018c2ecf20Sopenharmony_ci		mlog_errno(ret);
39028c2ecf20Sopenharmony_ci		goto out;
39038c2ecf20Sopenharmony_ci	}
39048c2ecf20Sopenharmony_ci
39058c2ecf20Sopenharmony_ci	xs->header = bucket_xh(xs->bucket);
39068c2ecf20Sopenharmony_ci	xs->base = bucket_block(xs->bucket, 0);
39078c2ecf20Sopenharmony_ci	xs->end = xs->base + inode->i_sb->s_blocksize;
39088c2ecf20Sopenharmony_ci
39098c2ecf20Sopenharmony_ci	if (found) {
39108c2ecf20Sopenharmony_ci		xs->here = &xs->header->xh_entries[index];
39118c2ecf20Sopenharmony_ci		trace_ocfs2_xattr_bucket_find(OCFS2_I(inode)->ip_blkno,
39128c2ecf20Sopenharmony_ci			name, name_index, name_hash,
39138c2ecf20Sopenharmony_ci			(unsigned long long)bucket_blkno(xs->bucket),
39148c2ecf20Sopenharmony_ci			index);
39158c2ecf20Sopenharmony_ci	} else
39168c2ecf20Sopenharmony_ci		ret = -ENODATA;
39178c2ecf20Sopenharmony_ci
39188c2ecf20Sopenharmony_ciout:
39198c2ecf20Sopenharmony_ci	ocfs2_xattr_bucket_free(search);
39208c2ecf20Sopenharmony_ci	return ret;
39218c2ecf20Sopenharmony_ci}
39228c2ecf20Sopenharmony_ci
39238c2ecf20Sopenharmony_cistatic int ocfs2_xattr_index_block_find(struct inode *inode,
39248c2ecf20Sopenharmony_ci					struct buffer_head *root_bh,
39258c2ecf20Sopenharmony_ci					int name_index,
39268c2ecf20Sopenharmony_ci					const char *name,
39278c2ecf20Sopenharmony_ci					struct ocfs2_xattr_search *xs)
39288c2ecf20Sopenharmony_ci{
39298c2ecf20Sopenharmony_ci	int ret;
39308c2ecf20Sopenharmony_ci	struct ocfs2_xattr_block *xb =
39318c2ecf20Sopenharmony_ci			(struct ocfs2_xattr_block *)root_bh->b_data;
39328c2ecf20Sopenharmony_ci	struct ocfs2_xattr_tree_root *xb_root = &xb->xb_attrs.xb_root;
39338c2ecf20Sopenharmony_ci	struct ocfs2_extent_list *el = &xb_root->xt_list;
39348c2ecf20Sopenharmony_ci	u64 p_blkno = 0;
39358c2ecf20Sopenharmony_ci	u32 first_hash, num_clusters = 0;
39368c2ecf20Sopenharmony_ci	u32 name_hash = ocfs2_xattr_name_hash(inode, name, strlen(name));
39378c2ecf20Sopenharmony_ci
39388c2ecf20Sopenharmony_ci	if (le16_to_cpu(el->l_next_free_rec) == 0)
39398c2ecf20Sopenharmony_ci		return -ENODATA;
39408c2ecf20Sopenharmony_ci
39418c2ecf20Sopenharmony_ci	trace_ocfs2_xattr_index_block_find(OCFS2_I(inode)->ip_blkno,
39428c2ecf20Sopenharmony_ci					name, name_index, name_hash,
39438c2ecf20Sopenharmony_ci					(unsigned long long)root_bh->b_blocknr,
39448c2ecf20Sopenharmony_ci					-1);
39458c2ecf20Sopenharmony_ci
39468c2ecf20Sopenharmony_ci	ret = ocfs2_xattr_get_rec(inode, name_hash, &p_blkno, &first_hash,
39478c2ecf20Sopenharmony_ci				  &num_clusters, el);
39488c2ecf20Sopenharmony_ci	if (ret) {
39498c2ecf20Sopenharmony_ci		mlog_errno(ret);
39508c2ecf20Sopenharmony_ci		goto out;
39518c2ecf20Sopenharmony_ci	}
39528c2ecf20Sopenharmony_ci
39538c2ecf20Sopenharmony_ci	BUG_ON(p_blkno == 0 || num_clusters == 0 || first_hash > name_hash);
39548c2ecf20Sopenharmony_ci
39558c2ecf20Sopenharmony_ci	trace_ocfs2_xattr_index_block_find_rec(OCFS2_I(inode)->ip_blkno,
39568c2ecf20Sopenharmony_ci					name, name_index, first_hash,
39578c2ecf20Sopenharmony_ci					(unsigned long long)p_blkno,
39588c2ecf20Sopenharmony_ci					num_clusters);
39598c2ecf20Sopenharmony_ci
39608c2ecf20Sopenharmony_ci	ret = ocfs2_xattr_bucket_find(inode, name_index, name, name_hash,
39618c2ecf20Sopenharmony_ci				      p_blkno, first_hash, num_clusters, xs);
39628c2ecf20Sopenharmony_ci
39638c2ecf20Sopenharmony_ciout:
39648c2ecf20Sopenharmony_ci	return ret;
39658c2ecf20Sopenharmony_ci}
39668c2ecf20Sopenharmony_ci
39678c2ecf20Sopenharmony_cistatic int ocfs2_iterate_xattr_buckets(struct inode *inode,
39688c2ecf20Sopenharmony_ci				       u64 blkno,
39698c2ecf20Sopenharmony_ci				       u32 clusters,
39708c2ecf20Sopenharmony_ci				       xattr_bucket_func *func,
39718c2ecf20Sopenharmony_ci				       void *para)
39728c2ecf20Sopenharmony_ci{
39738c2ecf20Sopenharmony_ci	int i, ret = 0;
39748c2ecf20Sopenharmony_ci	u32 bpc = ocfs2_xattr_buckets_per_cluster(OCFS2_SB(inode->i_sb));
39758c2ecf20Sopenharmony_ci	u32 num_buckets = clusters * bpc;
39768c2ecf20Sopenharmony_ci	struct ocfs2_xattr_bucket *bucket;
39778c2ecf20Sopenharmony_ci
39788c2ecf20Sopenharmony_ci	bucket = ocfs2_xattr_bucket_new(inode);
39798c2ecf20Sopenharmony_ci	if (!bucket) {
39808c2ecf20Sopenharmony_ci		mlog_errno(-ENOMEM);
39818c2ecf20Sopenharmony_ci		return -ENOMEM;
39828c2ecf20Sopenharmony_ci	}
39838c2ecf20Sopenharmony_ci
39848c2ecf20Sopenharmony_ci	trace_ocfs2_iterate_xattr_buckets(
39858c2ecf20Sopenharmony_ci		(unsigned long long)OCFS2_I(inode)->ip_blkno,
39868c2ecf20Sopenharmony_ci		(unsigned long long)blkno, clusters);
39878c2ecf20Sopenharmony_ci
39888c2ecf20Sopenharmony_ci	for (i = 0; i < num_buckets; i++, blkno += bucket->bu_blocks) {
39898c2ecf20Sopenharmony_ci		ret = ocfs2_read_xattr_bucket(bucket, blkno);
39908c2ecf20Sopenharmony_ci		if (ret) {
39918c2ecf20Sopenharmony_ci			mlog_errno(ret);
39928c2ecf20Sopenharmony_ci			break;
39938c2ecf20Sopenharmony_ci		}
39948c2ecf20Sopenharmony_ci
39958c2ecf20Sopenharmony_ci		/*
39968c2ecf20Sopenharmony_ci		 * The real bucket num in this series of blocks is stored
39978c2ecf20Sopenharmony_ci		 * in the 1st bucket.
39988c2ecf20Sopenharmony_ci		 */
39998c2ecf20Sopenharmony_ci		if (i == 0)
40008c2ecf20Sopenharmony_ci			num_buckets = le16_to_cpu(bucket_xh(bucket)->xh_num_buckets);
40018c2ecf20Sopenharmony_ci
40028c2ecf20Sopenharmony_ci		trace_ocfs2_iterate_xattr_bucket((unsigned long long)blkno,
40038c2ecf20Sopenharmony_ci		     le32_to_cpu(bucket_xh(bucket)->xh_entries[0].xe_name_hash));
40048c2ecf20Sopenharmony_ci		if (func) {
40058c2ecf20Sopenharmony_ci			ret = func(inode, bucket, para);
40068c2ecf20Sopenharmony_ci			if (ret && ret != -ERANGE)
40078c2ecf20Sopenharmony_ci				mlog_errno(ret);
40088c2ecf20Sopenharmony_ci			/* Fall through to bucket_relse() */
40098c2ecf20Sopenharmony_ci		}
40108c2ecf20Sopenharmony_ci
40118c2ecf20Sopenharmony_ci		ocfs2_xattr_bucket_relse(bucket);
40128c2ecf20Sopenharmony_ci		if (ret)
40138c2ecf20Sopenharmony_ci			break;
40148c2ecf20Sopenharmony_ci	}
40158c2ecf20Sopenharmony_ci
40168c2ecf20Sopenharmony_ci	ocfs2_xattr_bucket_free(bucket);
40178c2ecf20Sopenharmony_ci	return ret;
40188c2ecf20Sopenharmony_ci}
40198c2ecf20Sopenharmony_ci
40208c2ecf20Sopenharmony_cistruct ocfs2_xattr_tree_list {
40218c2ecf20Sopenharmony_ci	char *buffer;
40228c2ecf20Sopenharmony_ci	size_t buffer_size;
40238c2ecf20Sopenharmony_ci	size_t result;
40248c2ecf20Sopenharmony_ci};
40258c2ecf20Sopenharmony_ci
40268c2ecf20Sopenharmony_cistatic int ocfs2_xattr_bucket_get_name_value(struct super_block *sb,
40278c2ecf20Sopenharmony_ci					     struct ocfs2_xattr_header *xh,
40288c2ecf20Sopenharmony_ci					     int index,
40298c2ecf20Sopenharmony_ci					     int *block_off,
40308c2ecf20Sopenharmony_ci					     int *new_offset)
40318c2ecf20Sopenharmony_ci{
40328c2ecf20Sopenharmony_ci	u16 name_offset;
40338c2ecf20Sopenharmony_ci
40348c2ecf20Sopenharmony_ci	if (index < 0 || index >= le16_to_cpu(xh->xh_count))
40358c2ecf20Sopenharmony_ci		return -EINVAL;
40368c2ecf20Sopenharmony_ci
40378c2ecf20Sopenharmony_ci	name_offset = le16_to_cpu(xh->xh_entries[index].xe_name_offset);
40388c2ecf20Sopenharmony_ci
40398c2ecf20Sopenharmony_ci	*block_off = name_offset >> sb->s_blocksize_bits;
40408c2ecf20Sopenharmony_ci	*new_offset = name_offset % sb->s_blocksize;
40418c2ecf20Sopenharmony_ci
40428c2ecf20Sopenharmony_ci	return 0;
40438c2ecf20Sopenharmony_ci}
40448c2ecf20Sopenharmony_ci
40458c2ecf20Sopenharmony_cistatic int ocfs2_list_xattr_bucket(struct inode *inode,
40468c2ecf20Sopenharmony_ci				   struct ocfs2_xattr_bucket *bucket,
40478c2ecf20Sopenharmony_ci				   void *para)
40488c2ecf20Sopenharmony_ci{
40498c2ecf20Sopenharmony_ci	int ret = 0, type;
40508c2ecf20Sopenharmony_ci	struct ocfs2_xattr_tree_list *xl = (struct ocfs2_xattr_tree_list *)para;
40518c2ecf20Sopenharmony_ci	int i, block_off, new_offset;
40528c2ecf20Sopenharmony_ci	const char *name;
40538c2ecf20Sopenharmony_ci
40548c2ecf20Sopenharmony_ci	for (i = 0 ; i < le16_to_cpu(bucket_xh(bucket)->xh_count); i++) {
40558c2ecf20Sopenharmony_ci		struct ocfs2_xattr_entry *entry = &bucket_xh(bucket)->xh_entries[i];
40568c2ecf20Sopenharmony_ci		type = ocfs2_xattr_get_type(entry);
40578c2ecf20Sopenharmony_ci
40588c2ecf20Sopenharmony_ci		ret = ocfs2_xattr_bucket_get_name_value(inode->i_sb,
40598c2ecf20Sopenharmony_ci							bucket_xh(bucket),
40608c2ecf20Sopenharmony_ci							i,
40618c2ecf20Sopenharmony_ci							&block_off,
40628c2ecf20Sopenharmony_ci							&new_offset);
40638c2ecf20Sopenharmony_ci		if (ret)
40648c2ecf20Sopenharmony_ci			break;
40658c2ecf20Sopenharmony_ci
40668c2ecf20Sopenharmony_ci		name = (const char *)bucket_block(bucket, block_off) +
40678c2ecf20Sopenharmony_ci			new_offset;
40688c2ecf20Sopenharmony_ci		ret = ocfs2_xattr_list_entry(inode->i_sb,
40698c2ecf20Sopenharmony_ci					     xl->buffer,
40708c2ecf20Sopenharmony_ci					     xl->buffer_size,
40718c2ecf20Sopenharmony_ci					     &xl->result,
40728c2ecf20Sopenharmony_ci					     type, name,
40738c2ecf20Sopenharmony_ci					     entry->xe_name_len);
40748c2ecf20Sopenharmony_ci		if (ret)
40758c2ecf20Sopenharmony_ci			break;
40768c2ecf20Sopenharmony_ci	}
40778c2ecf20Sopenharmony_ci
40788c2ecf20Sopenharmony_ci	return ret;
40798c2ecf20Sopenharmony_ci}
40808c2ecf20Sopenharmony_ci
40818c2ecf20Sopenharmony_cistatic int ocfs2_iterate_xattr_index_block(struct inode *inode,
40828c2ecf20Sopenharmony_ci					   struct buffer_head *blk_bh,
40838c2ecf20Sopenharmony_ci					   xattr_tree_rec_func *rec_func,
40848c2ecf20Sopenharmony_ci					   void *para)
40858c2ecf20Sopenharmony_ci{
40868c2ecf20Sopenharmony_ci	struct ocfs2_xattr_block *xb =
40878c2ecf20Sopenharmony_ci			(struct ocfs2_xattr_block *)blk_bh->b_data;
40888c2ecf20Sopenharmony_ci	struct ocfs2_extent_list *el = &xb->xb_attrs.xb_root.xt_list;
40898c2ecf20Sopenharmony_ci	int ret = 0;
40908c2ecf20Sopenharmony_ci	u32 name_hash = UINT_MAX, e_cpos = 0, num_clusters = 0;
40918c2ecf20Sopenharmony_ci	u64 p_blkno = 0;
40928c2ecf20Sopenharmony_ci
40938c2ecf20Sopenharmony_ci	if (!el->l_next_free_rec || !rec_func)
40948c2ecf20Sopenharmony_ci		return 0;
40958c2ecf20Sopenharmony_ci
40968c2ecf20Sopenharmony_ci	while (name_hash > 0) {
40978c2ecf20Sopenharmony_ci		ret = ocfs2_xattr_get_rec(inode, name_hash, &p_blkno,
40988c2ecf20Sopenharmony_ci					  &e_cpos, &num_clusters, el);
40998c2ecf20Sopenharmony_ci		if (ret) {
41008c2ecf20Sopenharmony_ci			mlog_errno(ret);
41018c2ecf20Sopenharmony_ci			break;
41028c2ecf20Sopenharmony_ci		}
41038c2ecf20Sopenharmony_ci
41048c2ecf20Sopenharmony_ci		ret = rec_func(inode, blk_bh, p_blkno, e_cpos,
41058c2ecf20Sopenharmony_ci			       num_clusters, para);
41068c2ecf20Sopenharmony_ci		if (ret) {
41078c2ecf20Sopenharmony_ci			if (ret != -ERANGE)
41088c2ecf20Sopenharmony_ci				mlog_errno(ret);
41098c2ecf20Sopenharmony_ci			break;
41108c2ecf20Sopenharmony_ci		}
41118c2ecf20Sopenharmony_ci
41128c2ecf20Sopenharmony_ci		if (e_cpos == 0)
41138c2ecf20Sopenharmony_ci			break;
41148c2ecf20Sopenharmony_ci
41158c2ecf20Sopenharmony_ci		name_hash = e_cpos - 1;
41168c2ecf20Sopenharmony_ci	}
41178c2ecf20Sopenharmony_ci
41188c2ecf20Sopenharmony_ci	return ret;
41198c2ecf20Sopenharmony_ci
41208c2ecf20Sopenharmony_ci}
41218c2ecf20Sopenharmony_ci
41228c2ecf20Sopenharmony_cistatic int ocfs2_list_xattr_tree_rec(struct inode *inode,
41238c2ecf20Sopenharmony_ci				     struct buffer_head *root_bh,
41248c2ecf20Sopenharmony_ci				     u64 blkno, u32 cpos, u32 len, void *para)
41258c2ecf20Sopenharmony_ci{
41268c2ecf20Sopenharmony_ci	return ocfs2_iterate_xattr_buckets(inode, blkno, len,
41278c2ecf20Sopenharmony_ci					   ocfs2_list_xattr_bucket, para);
41288c2ecf20Sopenharmony_ci}
41298c2ecf20Sopenharmony_ci
41308c2ecf20Sopenharmony_cistatic int ocfs2_xattr_tree_list_index_block(struct inode *inode,
41318c2ecf20Sopenharmony_ci					     struct buffer_head *blk_bh,
41328c2ecf20Sopenharmony_ci					     char *buffer,
41338c2ecf20Sopenharmony_ci					     size_t buffer_size)
41348c2ecf20Sopenharmony_ci{
41358c2ecf20Sopenharmony_ci	int ret;
41368c2ecf20Sopenharmony_ci	struct ocfs2_xattr_tree_list xl = {
41378c2ecf20Sopenharmony_ci		.buffer = buffer,
41388c2ecf20Sopenharmony_ci		.buffer_size = buffer_size,
41398c2ecf20Sopenharmony_ci		.result = 0,
41408c2ecf20Sopenharmony_ci	};
41418c2ecf20Sopenharmony_ci
41428c2ecf20Sopenharmony_ci	ret = ocfs2_iterate_xattr_index_block(inode, blk_bh,
41438c2ecf20Sopenharmony_ci					      ocfs2_list_xattr_tree_rec, &xl);
41448c2ecf20Sopenharmony_ci	if (ret) {
41458c2ecf20Sopenharmony_ci		mlog_errno(ret);
41468c2ecf20Sopenharmony_ci		goto out;
41478c2ecf20Sopenharmony_ci	}
41488c2ecf20Sopenharmony_ci
41498c2ecf20Sopenharmony_ci	ret = xl.result;
41508c2ecf20Sopenharmony_ciout:
41518c2ecf20Sopenharmony_ci	return ret;
41528c2ecf20Sopenharmony_ci}
41538c2ecf20Sopenharmony_ci
41548c2ecf20Sopenharmony_cistatic int cmp_xe(const void *a, const void *b)
41558c2ecf20Sopenharmony_ci{
41568c2ecf20Sopenharmony_ci	const struct ocfs2_xattr_entry *l = a, *r = b;
41578c2ecf20Sopenharmony_ci	u32 l_hash = le32_to_cpu(l->xe_name_hash);
41588c2ecf20Sopenharmony_ci	u32 r_hash = le32_to_cpu(r->xe_name_hash);
41598c2ecf20Sopenharmony_ci
41608c2ecf20Sopenharmony_ci	if (l_hash > r_hash)
41618c2ecf20Sopenharmony_ci		return 1;
41628c2ecf20Sopenharmony_ci	if (l_hash < r_hash)
41638c2ecf20Sopenharmony_ci		return -1;
41648c2ecf20Sopenharmony_ci	return 0;
41658c2ecf20Sopenharmony_ci}
41668c2ecf20Sopenharmony_ci
41678c2ecf20Sopenharmony_cistatic void swap_xe(void *a, void *b, int size)
41688c2ecf20Sopenharmony_ci{
41698c2ecf20Sopenharmony_ci	struct ocfs2_xattr_entry *l = a, *r = b, tmp;
41708c2ecf20Sopenharmony_ci
41718c2ecf20Sopenharmony_ci	tmp = *l;
41728c2ecf20Sopenharmony_ci	memcpy(l, r, sizeof(struct ocfs2_xattr_entry));
41738c2ecf20Sopenharmony_ci	memcpy(r, &tmp, sizeof(struct ocfs2_xattr_entry));
41748c2ecf20Sopenharmony_ci}
41758c2ecf20Sopenharmony_ci
41768c2ecf20Sopenharmony_ci/*
41778c2ecf20Sopenharmony_ci * When the ocfs2_xattr_block is filled up, new bucket will be created
41788c2ecf20Sopenharmony_ci * and all the xattr entries will be moved to the new bucket.
41798c2ecf20Sopenharmony_ci * The header goes at the start of the bucket, and the names+values are
41808c2ecf20Sopenharmony_ci * filled from the end.  This is why *target starts as the last buffer.
41818c2ecf20Sopenharmony_ci * Note: we need to sort the entries since they are not saved in order
41828c2ecf20Sopenharmony_ci * in the ocfs2_xattr_block.
41838c2ecf20Sopenharmony_ci */
41848c2ecf20Sopenharmony_cistatic void ocfs2_cp_xattr_block_to_bucket(struct inode *inode,
41858c2ecf20Sopenharmony_ci					   struct buffer_head *xb_bh,
41868c2ecf20Sopenharmony_ci					   struct ocfs2_xattr_bucket *bucket)
41878c2ecf20Sopenharmony_ci{
41888c2ecf20Sopenharmony_ci	int i, blocksize = inode->i_sb->s_blocksize;
41898c2ecf20Sopenharmony_ci	int blks = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
41908c2ecf20Sopenharmony_ci	u16 offset, size, off_change;
41918c2ecf20Sopenharmony_ci	struct ocfs2_xattr_entry *xe;
41928c2ecf20Sopenharmony_ci	struct ocfs2_xattr_block *xb =
41938c2ecf20Sopenharmony_ci				(struct ocfs2_xattr_block *)xb_bh->b_data;
41948c2ecf20Sopenharmony_ci	struct ocfs2_xattr_header *xb_xh = &xb->xb_attrs.xb_header;
41958c2ecf20Sopenharmony_ci	struct ocfs2_xattr_header *xh = bucket_xh(bucket);
41968c2ecf20Sopenharmony_ci	u16 count = le16_to_cpu(xb_xh->xh_count);
41978c2ecf20Sopenharmony_ci	char *src = xb_bh->b_data;
41988c2ecf20Sopenharmony_ci	char *target = bucket_block(bucket, blks - 1);
41998c2ecf20Sopenharmony_ci
42008c2ecf20Sopenharmony_ci	trace_ocfs2_cp_xattr_block_to_bucket_begin(
42018c2ecf20Sopenharmony_ci				(unsigned long long)xb_bh->b_blocknr,
42028c2ecf20Sopenharmony_ci				(unsigned long long)bucket_blkno(bucket));
42038c2ecf20Sopenharmony_ci
42048c2ecf20Sopenharmony_ci	for (i = 0; i < blks; i++)
42058c2ecf20Sopenharmony_ci		memset(bucket_block(bucket, i), 0, blocksize);
42068c2ecf20Sopenharmony_ci
42078c2ecf20Sopenharmony_ci	/*
42088c2ecf20Sopenharmony_ci	 * Since the xe_name_offset is based on ocfs2_xattr_header,
42098c2ecf20Sopenharmony_ci	 * there is a offset change corresponding to the change of
42108c2ecf20Sopenharmony_ci	 * ocfs2_xattr_header's position.
42118c2ecf20Sopenharmony_ci	 */
42128c2ecf20Sopenharmony_ci	off_change = offsetof(struct ocfs2_xattr_block, xb_attrs.xb_header);
42138c2ecf20Sopenharmony_ci	xe = &xb_xh->xh_entries[count - 1];
42148c2ecf20Sopenharmony_ci	offset = le16_to_cpu(xe->xe_name_offset) + off_change;
42158c2ecf20Sopenharmony_ci	size = blocksize - offset;
42168c2ecf20Sopenharmony_ci
42178c2ecf20Sopenharmony_ci	/* copy all the names and values. */
42188c2ecf20Sopenharmony_ci	memcpy(target + offset, src + offset, size);
42198c2ecf20Sopenharmony_ci
42208c2ecf20Sopenharmony_ci	/* Init new header now. */
42218c2ecf20Sopenharmony_ci	xh->xh_count = xb_xh->xh_count;
42228c2ecf20Sopenharmony_ci	xh->xh_num_buckets = cpu_to_le16(1);
42238c2ecf20Sopenharmony_ci	xh->xh_name_value_len = cpu_to_le16(size);
42248c2ecf20Sopenharmony_ci	xh->xh_free_start = cpu_to_le16(OCFS2_XATTR_BUCKET_SIZE - size);
42258c2ecf20Sopenharmony_ci
42268c2ecf20Sopenharmony_ci	/* copy all the entries. */
42278c2ecf20Sopenharmony_ci	target = bucket_block(bucket, 0);
42288c2ecf20Sopenharmony_ci	offset = offsetof(struct ocfs2_xattr_header, xh_entries);
42298c2ecf20Sopenharmony_ci	size = count * sizeof(struct ocfs2_xattr_entry);
42308c2ecf20Sopenharmony_ci	memcpy(target + offset, (char *)xb_xh + offset, size);
42318c2ecf20Sopenharmony_ci
42328c2ecf20Sopenharmony_ci	/* Change the xe offset for all the xe because of the move. */
42338c2ecf20Sopenharmony_ci	off_change = OCFS2_XATTR_BUCKET_SIZE - blocksize +
42348c2ecf20Sopenharmony_ci		 offsetof(struct ocfs2_xattr_block, xb_attrs.xb_header);
42358c2ecf20Sopenharmony_ci	for (i = 0; i < count; i++)
42368c2ecf20Sopenharmony_ci		le16_add_cpu(&xh->xh_entries[i].xe_name_offset, off_change);
42378c2ecf20Sopenharmony_ci
42388c2ecf20Sopenharmony_ci	trace_ocfs2_cp_xattr_block_to_bucket_end(offset, size, off_change);
42398c2ecf20Sopenharmony_ci
42408c2ecf20Sopenharmony_ci	sort(target + offset, count, sizeof(struct ocfs2_xattr_entry),
42418c2ecf20Sopenharmony_ci	     cmp_xe, swap_xe);
42428c2ecf20Sopenharmony_ci}
42438c2ecf20Sopenharmony_ci
42448c2ecf20Sopenharmony_ci/*
42458c2ecf20Sopenharmony_ci * After we move xattr from block to index btree, we have to
42468c2ecf20Sopenharmony_ci * update ocfs2_xattr_search to the new xe and base.
42478c2ecf20Sopenharmony_ci *
42488c2ecf20Sopenharmony_ci * When the entry is in xattr block, xattr_bh indicates the storage place.
42498c2ecf20Sopenharmony_ci * While if the entry is in index b-tree, "bucket" indicates the
42508c2ecf20Sopenharmony_ci * real place of the xattr.
42518c2ecf20Sopenharmony_ci */
42528c2ecf20Sopenharmony_cistatic void ocfs2_xattr_update_xattr_search(struct inode *inode,
42538c2ecf20Sopenharmony_ci					    struct ocfs2_xattr_search *xs,
42548c2ecf20Sopenharmony_ci					    struct buffer_head *old_bh)
42558c2ecf20Sopenharmony_ci{
42568c2ecf20Sopenharmony_ci	char *buf = old_bh->b_data;
42578c2ecf20Sopenharmony_ci	struct ocfs2_xattr_block *old_xb = (struct ocfs2_xattr_block *)buf;
42588c2ecf20Sopenharmony_ci	struct ocfs2_xattr_header *old_xh = &old_xb->xb_attrs.xb_header;
42598c2ecf20Sopenharmony_ci	int i;
42608c2ecf20Sopenharmony_ci
42618c2ecf20Sopenharmony_ci	xs->header = bucket_xh(xs->bucket);
42628c2ecf20Sopenharmony_ci	xs->base = bucket_block(xs->bucket, 0);
42638c2ecf20Sopenharmony_ci	xs->end = xs->base + inode->i_sb->s_blocksize;
42648c2ecf20Sopenharmony_ci
42658c2ecf20Sopenharmony_ci	if (xs->not_found)
42668c2ecf20Sopenharmony_ci		return;
42678c2ecf20Sopenharmony_ci
42688c2ecf20Sopenharmony_ci	i = xs->here - old_xh->xh_entries;
42698c2ecf20Sopenharmony_ci	xs->here = &xs->header->xh_entries[i];
42708c2ecf20Sopenharmony_ci}
42718c2ecf20Sopenharmony_ci
42728c2ecf20Sopenharmony_cistatic int ocfs2_xattr_create_index_block(struct inode *inode,
42738c2ecf20Sopenharmony_ci					  struct ocfs2_xattr_search *xs,
42748c2ecf20Sopenharmony_ci					  struct ocfs2_xattr_set_ctxt *ctxt)
42758c2ecf20Sopenharmony_ci{
42768c2ecf20Sopenharmony_ci	int ret;
42778c2ecf20Sopenharmony_ci	u32 bit_off, len;
42788c2ecf20Sopenharmony_ci	u64 blkno;
42798c2ecf20Sopenharmony_ci	handle_t *handle = ctxt->handle;
42808c2ecf20Sopenharmony_ci	struct ocfs2_inode_info *oi = OCFS2_I(inode);
42818c2ecf20Sopenharmony_ci	struct buffer_head *xb_bh = xs->xattr_bh;
42828c2ecf20Sopenharmony_ci	struct ocfs2_xattr_block *xb =
42838c2ecf20Sopenharmony_ci			(struct ocfs2_xattr_block *)xb_bh->b_data;
42848c2ecf20Sopenharmony_ci	struct ocfs2_xattr_tree_root *xr;
42858c2ecf20Sopenharmony_ci	u16 xb_flags = le16_to_cpu(xb->xb_flags);
42868c2ecf20Sopenharmony_ci
42878c2ecf20Sopenharmony_ci	trace_ocfs2_xattr_create_index_block_begin(
42888c2ecf20Sopenharmony_ci				(unsigned long long)xb_bh->b_blocknr);
42898c2ecf20Sopenharmony_ci
42908c2ecf20Sopenharmony_ci	BUG_ON(xb_flags & OCFS2_XATTR_INDEXED);
42918c2ecf20Sopenharmony_ci	BUG_ON(!xs->bucket);
42928c2ecf20Sopenharmony_ci
42938c2ecf20Sopenharmony_ci	/*
42948c2ecf20Sopenharmony_ci	 * XXX:
42958c2ecf20Sopenharmony_ci	 * We can use this lock for now, and maybe move to a dedicated mutex
42968c2ecf20Sopenharmony_ci	 * if performance becomes a problem later.
42978c2ecf20Sopenharmony_ci	 */
42988c2ecf20Sopenharmony_ci	down_write(&oi->ip_alloc_sem);
42998c2ecf20Sopenharmony_ci
43008c2ecf20Sopenharmony_ci	ret = ocfs2_journal_access_xb(handle, INODE_CACHE(inode), xb_bh,
43018c2ecf20Sopenharmony_ci				      OCFS2_JOURNAL_ACCESS_WRITE);
43028c2ecf20Sopenharmony_ci	if (ret) {
43038c2ecf20Sopenharmony_ci		mlog_errno(ret);
43048c2ecf20Sopenharmony_ci		goto out;
43058c2ecf20Sopenharmony_ci	}
43068c2ecf20Sopenharmony_ci
43078c2ecf20Sopenharmony_ci	ret = __ocfs2_claim_clusters(handle, ctxt->data_ac,
43088c2ecf20Sopenharmony_ci				     1, 1, &bit_off, &len);
43098c2ecf20Sopenharmony_ci	if (ret) {
43108c2ecf20Sopenharmony_ci		mlog_errno(ret);
43118c2ecf20Sopenharmony_ci		goto out;
43128c2ecf20Sopenharmony_ci	}
43138c2ecf20Sopenharmony_ci
43148c2ecf20Sopenharmony_ci	/*
43158c2ecf20Sopenharmony_ci	 * The bucket may spread in many blocks, and
43168c2ecf20Sopenharmony_ci	 * we will only touch the 1st block and the last block
43178c2ecf20Sopenharmony_ci	 * in the whole bucket(one for entry and one for data).
43188c2ecf20Sopenharmony_ci	 */
43198c2ecf20Sopenharmony_ci	blkno = ocfs2_clusters_to_blocks(inode->i_sb, bit_off);
43208c2ecf20Sopenharmony_ci
43218c2ecf20Sopenharmony_ci	trace_ocfs2_xattr_create_index_block((unsigned long long)blkno);
43228c2ecf20Sopenharmony_ci
43238c2ecf20Sopenharmony_ci	ret = ocfs2_init_xattr_bucket(xs->bucket, blkno, 1);
43248c2ecf20Sopenharmony_ci	if (ret) {
43258c2ecf20Sopenharmony_ci		mlog_errno(ret);
43268c2ecf20Sopenharmony_ci		goto out;
43278c2ecf20Sopenharmony_ci	}
43288c2ecf20Sopenharmony_ci
43298c2ecf20Sopenharmony_ci	ret = ocfs2_xattr_bucket_journal_access(handle, xs->bucket,
43308c2ecf20Sopenharmony_ci						OCFS2_JOURNAL_ACCESS_CREATE);
43318c2ecf20Sopenharmony_ci	if (ret) {
43328c2ecf20Sopenharmony_ci		mlog_errno(ret);
43338c2ecf20Sopenharmony_ci		goto out;
43348c2ecf20Sopenharmony_ci	}
43358c2ecf20Sopenharmony_ci
43368c2ecf20Sopenharmony_ci	ocfs2_cp_xattr_block_to_bucket(inode, xb_bh, xs->bucket);
43378c2ecf20Sopenharmony_ci	ocfs2_xattr_bucket_journal_dirty(handle, xs->bucket);
43388c2ecf20Sopenharmony_ci
43398c2ecf20Sopenharmony_ci	ocfs2_xattr_update_xattr_search(inode, xs, xb_bh);
43408c2ecf20Sopenharmony_ci
43418c2ecf20Sopenharmony_ci	/* Change from ocfs2_xattr_header to ocfs2_xattr_tree_root */
43428c2ecf20Sopenharmony_ci	memset(&xb->xb_attrs, 0, inode->i_sb->s_blocksize -
43438c2ecf20Sopenharmony_ci	       offsetof(struct ocfs2_xattr_block, xb_attrs));
43448c2ecf20Sopenharmony_ci
43458c2ecf20Sopenharmony_ci	xr = &xb->xb_attrs.xb_root;
43468c2ecf20Sopenharmony_ci	xr->xt_clusters = cpu_to_le32(1);
43478c2ecf20Sopenharmony_ci	xr->xt_last_eb_blk = 0;
43488c2ecf20Sopenharmony_ci	xr->xt_list.l_tree_depth = 0;
43498c2ecf20Sopenharmony_ci	xr->xt_list.l_count = cpu_to_le16(ocfs2_xattr_recs_per_xb(inode->i_sb));
43508c2ecf20Sopenharmony_ci	xr->xt_list.l_next_free_rec = cpu_to_le16(1);
43518c2ecf20Sopenharmony_ci
43528c2ecf20Sopenharmony_ci	xr->xt_list.l_recs[0].e_cpos = 0;
43538c2ecf20Sopenharmony_ci	xr->xt_list.l_recs[0].e_blkno = cpu_to_le64(blkno);
43548c2ecf20Sopenharmony_ci	xr->xt_list.l_recs[0].e_leaf_clusters = cpu_to_le16(1);
43558c2ecf20Sopenharmony_ci
43568c2ecf20Sopenharmony_ci	xb->xb_flags = cpu_to_le16(xb_flags | OCFS2_XATTR_INDEXED);
43578c2ecf20Sopenharmony_ci
43588c2ecf20Sopenharmony_ci	ocfs2_journal_dirty(handle, xb_bh);
43598c2ecf20Sopenharmony_ci
43608c2ecf20Sopenharmony_ciout:
43618c2ecf20Sopenharmony_ci	up_write(&oi->ip_alloc_sem);
43628c2ecf20Sopenharmony_ci
43638c2ecf20Sopenharmony_ci	return ret;
43648c2ecf20Sopenharmony_ci}
43658c2ecf20Sopenharmony_ci
43668c2ecf20Sopenharmony_cistatic int cmp_xe_offset(const void *a, const void *b)
43678c2ecf20Sopenharmony_ci{
43688c2ecf20Sopenharmony_ci	const struct ocfs2_xattr_entry *l = a, *r = b;
43698c2ecf20Sopenharmony_ci	u32 l_name_offset = le16_to_cpu(l->xe_name_offset);
43708c2ecf20Sopenharmony_ci	u32 r_name_offset = le16_to_cpu(r->xe_name_offset);
43718c2ecf20Sopenharmony_ci
43728c2ecf20Sopenharmony_ci	if (l_name_offset < r_name_offset)
43738c2ecf20Sopenharmony_ci		return 1;
43748c2ecf20Sopenharmony_ci	if (l_name_offset > r_name_offset)
43758c2ecf20Sopenharmony_ci		return -1;
43768c2ecf20Sopenharmony_ci	return 0;
43778c2ecf20Sopenharmony_ci}
43788c2ecf20Sopenharmony_ci
43798c2ecf20Sopenharmony_ci/*
43808c2ecf20Sopenharmony_ci * defrag a xattr bucket if we find that the bucket has some
43818c2ecf20Sopenharmony_ci * holes beteen name/value pairs.
43828c2ecf20Sopenharmony_ci * We will move all the name/value pairs to the end of the bucket
43838c2ecf20Sopenharmony_ci * so that we can spare some space for insertion.
43848c2ecf20Sopenharmony_ci */
43858c2ecf20Sopenharmony_cistatic int ocfs2_defrag_xattr_bucket(struct inode *inode,
43868c2ecf20Sopenharmony_ci				     handle_t *handle,
43878c2ecf20Sopenharmony_ci				     struct ocfs2_xattr_bucket *bucket)
43888c2ecf20Sopenharmony_ci{
43898c2ecf20Sopenharmony_ci	int ret, i;
43908c2ecf20Sopenharmony_ci	size_t end, offset, len;
43918c2ecf20Sopenharmony_ci	struct ocfs2_xattr_header *xh;
43928c2ecf20Sopenharmony_ci	char *entries, *buf, *bucket_buf = NULL;
43938c2ecf20Sopenharmony_ci	u64 blkno = bucket_blkno(bucket);
43948c2ecf20Sopenharmony_ci	u16 xh_free_start;
43958c2ecf20Sopenharmony_ci	size_t blocksize = inode->i_sb->s_blocksize;
43968c2ecf20Sopenharmony_ci	struct ocfs2_xattr_entry *xe;
43978c2ecf20Sopenharmony_ci
43988c2ecf20Sopenharmony_ci	/*
43998c2ecf20Sopenharmony_ci	 * In order to make the operation more efficient and generic,
44008c2ecf20Sopenharmony_ci	 * we copy all the blocks into a contiguous memory and do the
44018c2ecf20Sopenharmony_ci	 * defragment there, so if anything is error, we will not touch
44028c2ecf20Sopenharmony_ci	 * the real block.
44038c2ecf20Sopenharmony_ci	 */
44048c2ecf20Sopenharmony_ci	bucket_buf = kmalloc(OCFS2_XATTR_BUCKET_SIZE, GFP_NOFS);
44058c2ecf20Sopenharmony_ci	if (!bucket_buf) {
44068c2ecf20Sopenharmony_ci		ret = -EIO;
44078c2ecf20Sopenharmony_ci		goto out;
44088c2ecf20Sopenharmony_ci	}
44098c2ecf20Sopenharmony_ci
44108c2ecf20Sopenharmony_ci	buf = bucket_buf;
44118c2ecf20Sopenharmony_ci	for (i = 0; i < bucket->bu_blocks; i++, buf += blocksize)
44128c2ecf20Sopenharmony_ci		memcpy(buf, bucket_block(bucket, i), blocksize);
44138c2ecf20Sopenharmony_ci
44148c2ecf20Sopenharmony_ci	ret = ocfs2_xattr_bucket_journal_access(handle, bucket,
44158c2ecf20Sopenharmony_ci						OCFS2_JOURNAL_ACCESS_WRITE);
44168c2ecf20Sopenharmony_ci	if (ret < 0) {
44178c2ecf20Sopenharmony_ci		mlog_errno(ret);
44188c2ecf20Sopenharmony_ci		goto out;
44198c2ecf20Sopenharmony_ci	}
44208c2ecf20Sopenharmony_ci
44218c2ecf20Sopenharmony_ci	xh = (struct ocfs2_xattr_header *)bucket_buf;
44228c2ecf20Sopenharmony_ci	entries = (char *)xh->xh_entries;
44238c2ecf20Sopenharmony_ci	xh_free_start = le16_to_cpu(xh->xh_free_start);
44248c2ecf20Sopenharmony_ci
44258c2ecf20Sopenharmony_ci	trace_ocfs2_defrag_xattr_bucket(
44268c2ecf20Sopenharmony_ci	     (unsigned long long)blkno, le16_to_cpu(xh->xh_count),
44278c2ecf20Sopenharmony_ci	     xh_free_start, le16_to_cpu(xh->xh_name_value_len));
44288c2ecf20Sopenharmony_ci
44298c2ecf20Sopenharmony_ci	/*
44308c2ecf20Sopenharmony_ci	 * sort all the entries by their offset.
44318c2ecf20Sopenharmony_ci	 * the largest will be the first, so that we can
44328c2ecf20Sopenharmony_ci	 * move them to the end one by one.
44338c2ecf20Sopenharmony_ci	 */
44348c2ecf20Sopenharmony_ci	sort(entries, le16_to_cpu(xh->xh_count),
44358c2ecf20Sopenharmony_ci	     sizeof(struct ocfs2_xattr_entry),
44368c2ecf20Sopenharmony_ci	     cmp_xe_offset, swap_xe);
44378c2ecf20Sopenharmony_ci
44388c2ecf20Sopenharmony_ci	/* Move all name/values to the end of the bucket. */
44398c2ecf20Sopenharmony_ci	xe = xh->xh_entries;
44408c2ecf20Sopenharmony_ci	end = OCFS2_XATTR_BUCKET_SIZE;
44418c2ecf20Sopenharmony_ci	for (i = 0; i < le16_to_cpu(xh->xh_count); i++, xe++) {
44428c2ecf20Sopenharmony_ci		offset = le16_to_cpu(xe->xe_name_offset);
44438c2ecf20Sopenharmony_ci		len = namevalue_size_xe(xe);
44448c2ecf20Sopenharmony_ci
44458c2ecf20Sopenharmony_ci		/*
44468c2ecf20Sopenharmony_ci		 * We must make sure that the name/value pair
44478c2ecf20Sopenharmony_ci		 * exist in the same block. So adjust end to
44488c2ecf20Sopenharmony_ci		 * the previous block end if needed.
44498c2ecf20Sopenharmony_ci		 */
44508c2ecf20Sopenharmony_ci		if (((end - len) / blocksize !=
44518c2ecf20Sopenharmony_ci			(end - 1) / blocksize))
44528c2ecf20Sopenharmony_ci			end = end - end % blocksize;
44538c2ecf20Sopenharmony_ci
44548c2ecf20Sopenharmony_ci		if (end > offset + len) {
44558c2ecf20Sopenharmony_ci			memmove(bucket_buf + end - len,
44568c2ecf20Sopenharmony_ci				bucket_buf + offset, len);
44578c2ecf20Sopenharmony_ci			xe->xe_name_offset = cpu_to_le16(end - len);
44588c2ecf20Sopenharmony_ci		}
44598c2ecf20Sopenharmony_ci
44608c2ecf20Sopenharmony_ci		mlog_bug_on_msg(end < offset + len, "Defrag check failed for "
44618c2ecf20Sopenharmony_ci				"bucket %llu\n", (unsigned long long)blkno);
44628c2ecf20Sopenharmony_ci
44638c2ecf20Sopenharmony_ci		end -= len;
44648c2ecf20Sopenharmony_ci	}
44658c2ecf20Sopenharmony_ci
44668c2ecf20Sopenharmony_ci	mlog_bug_on_msg(xh_free_start > end, "Defrag check failed for "
44678c2ecf20Sopenharmony_ci			"bucket %llu\n", (unsigned long long)blkno);
44688c2ecf20Sopenharmony_ci
44698c2ecf20Sopenharmony_ci	if (xh_free_start == end)
44708c2ecf20Sopenharmony_ci		goto out;
44718c2ecf20Sopenharmony_ci
44728c2ecf20Sopenharmony_ci	memset(bucket_buf + xh_free_start, 0, end - xh_free_start);
44738c2ecf20Sopenharmony_ci	xh->xh_free_start = cpu_to_le16(end);
44748c2ecf20Sopenharmony_ci
44758c2ecf20Sopenharmony_ci	/* sort the entries by their name_hash. */
44768c2ecf20Sopenharmony_ci	sort(entries, le16_to_cpu(xh->xh_count),
44778c2ecf20Sopenharmony_ci	     sizeof(struct ocfs2_xattr_entry),
44788c2ecf20Sopenharmony_ci	     cmp_xe, swap_xe);
44798c2ecf20Sopenharmony_ci
44808c2ecf20Sopenharmony_ci	buf = bucket_buf;
44818c2ecf20Sopenharmony_ci	for (i = 0; i < bucket->bu_blocks; i++, buf += blocksize)
44828c2ecf20Sopenharmony_ci		memcpy(bucket_block(bucket, i), buf, blocksize);
44838c2ecf20Sopenharmony_ci	ocfs2_xattr_bucket_journal_dirty(handle, bucket);
44848c2ecf20Sopenharmony_ci
44858c2ecf20Sopenharmony_ciout:
44868c2ecf20Sopenharmony_ci	kfree(bucket_buf);
44878c2ecf20Sopenharmony_ci	return ret;
44888c2ecf20Sopenharmony_ci}
44898c2ecf20Sopenharmony_ci
44908c2ecf20Sopenharmony_ci/*
44918c2ecf20Sopenharmony_ci * prev_blkno points to the start of an existing extent.  new_blkno
44928c2ecf20Sopenharmony_ci * points to a newly allocated extent.  Because we know each of our
44938c2ecf20Sopenharmony_ci * clusters contains more than bucket, we can easily split one cluster
44948c2ecf20Sopenharmony_ci * at a bucket boundary.  So we take the last cluster of the existing
44958c2ecf20Sopenharmony_ci * extent and split it down the middle.  We move the last half of the
44968c2ecf20Sopenharmony_ci * buckets in the last cluster of the existing extent over to the new
44978c2ecf20Sopenharmony_ci * extent.
44988c2ecf20Sopenharmony_ci *
44998c2ecf20Sopenharmony_ci * first_bh is the buffer at prev_blkno so we can update the existing
45008c2ecf20Sopenharmony_ci * extent's bucket count.  header_bh is the bucket were we were hoping
45018c2ecf20Sopenharmony_ci * to insert our xattr.  If the bucket move places the target in the new
45028c2ecf20Sopenharmony_ci * extent, we'll update first_bh and header_bh after modifying the old
45038c2ecf20Sopenharmony_ci * extent.
45048c2ecf20Sopenharmony_ci *
45058c2ecf20Sopenharmony_ci * first_hash will be set as the 1st xe's name_hash in the new extent.
45068c2ecf20Sopenharmony_ci */
45078c2ecf20Sopenharmony_cistatic int ocfs2_mv_xattr_bucket_cross_cluster(struct inode *inode,
45088c2ecf20Sopenharmony_ci					       handle_t *handle,
45098c2ecf20Sopenharmony_ci					       struct ocfs2_xattr_bucket *first,
45108c2ecf20Sopenharmony_ci					       struct ocfs2_xattr_bucket *target,
45118c2ecf20Sopenharmony_ci					       u64 new_blkno,
45128c2ecf20Sopenharmony_ci					       u32 num_clusters,
45138c2ecf20Sopenharmony_ci					       u32 *first_hash)
45148c2ecf20Sopenharmony_ci{
45158c2ecf20Sopenharmony_ci	int ret;
45168c2ecf20Sopenharmony_ci	struct super_block *sb = inode->i_sb;
45178c2ecf20Sopenharmony_ci	int blks_per_bucket = ocfs2_blocks_per_xattr_bucket(sb);
45188c2ecf20Sopenharmony_ci	int num_buckets = ocfs2_xattr_buckets_per_cluster(OCFS2_SB(sb));
45198c2ecf20Sopenharmony_ci	int to_move = num_buckets / 2;
45208c2ecf20Sopenharmony_ci	u64 src_blkno;
45218c2ecf20Sopenharmony_ci	u64 last_cluster_blkno = bucket_blkno(first) +
45228c2ecf20Sopenharmony_ci		((num_clusters - 1) * ocfs2_clusters_to_blocks(sb, 1));
45238c2ecf20Sopenharmony_ci
45248c2ecf20Sopenharmony_ci	BUG_ON(le16_to_cpu(bucket_xh(first)->xh_num_buckets) < num_buckets);
45258c2ecf20Sopenharmony_ci	BUG_ON(OCFS2_XATTR_BUCKET_SIZE == OCFS2_SB(sb)->s_clustersize);
45268c2ecf20Sopenharmony_ci
45278c2ecf20Sopenharmony_ci	trace_ocfs2_mv_xattr_bucket_cross_cluster(
45288c2ecf20Sopenharmony_ci				(unsigned long long)last_cluster_blkno,
45298c2ecf20Sopenharmony_ci				(unsigned long long)new_blkno);
45308c2ecf20Sopenharmony_ci
45318c2ecf20Sopenharmony_ci	ret = ocfs2_mv_xattr_buckets(inode, handle, bucket_blkno(first),
45328c2ecf20Sopenharmony_ci				     last_cluster_blkno, new_blkno,
45338c2ecf20Sopenharmony_ci				     to_move, first_hash);
45348c2ecf20Sopenharmony_ci	if (ret) {
45358c2ecf20Sopenharmony_ci		mlog_errno(ret);
45368c2ecf20Sopenharmony_ci		goto out;
45378c2ecf20Sopenharmony_ci	}
45388c2ecf20Sopenharmony_ci
45398c2ecf20Sopenharmony_ci	/* This is the first bucket that got moved */
45408c2ecf20Sopenharmony_ci	src_blkno = last_cluster_blkno + (to_move * blks_per_bucket);
45418c2ecf20Sopenharmony_ci
45428c2ecf20Sopenharmony_ci	/*
45438c2ecf20Sopenharmony_ci	 * If the target bucket was part of the moved buckets, we need to
45448c2ecf20Sopenharmony_ci	 * update first and target.
45458c2ecf20Sopenharmony_ci	 */
45468c2ecf20Sopenharmony_ci	if (bucket_blkno(target) >= src_blkno) {
45478c2ecf20Sopenharmony_ci		/* Find the block for the new target bucket */
45488c2ecf20Sopenharmony_ci		src_blkno = new_blkno +
45498c2ecf20Sopenharmony_ci			(bucket_blkno(target) - src_blkno);
45508c2ecf20Sopenharmony_ci
45518c2ecf20Sopenharmony_ci		ocfs2_xattr_bucket_relse(first);
45528c2ecf20Sopenharmony_ci		ocfs2_xattr_bucket_relse(target);
45538c2ecf20Sopenharmony_ci
45548c2ecf20Sopenharmony_ci		/*
45558c2ecf20Sopenharmony_ci		 * These shouldn't fail - the buffers are in the
45568c2ecf20Sopenharmony_ci		 * journal from ocfs2_cp_xattr_bucket().
45578c2ecf20Sopenharmony_ci		 */
45588c2ecf20Sopenharmony_ci		ret = ocfs2_read_xattr_bucket(first, new_blkno);
45598c2ecf20Sopenharmony_ci		if (ret) {
45608c2ecf20Sopenharmony_ci			mlog_errno(ret);
45618c2ecf20Sopenharmony_ci			goto out;
45628c2ecf20Sopenharmony_ci		}
45638c2ecf20Sopenharmony_ci		ret = ocfs2_read_xattr_bucket(target, src_blkno);
45648c2ecf20Sopenharmony_ci		if (ret)
45658c2ecf20Sopenharmony_ci			mlog_errno(ret);
45668c2ecf20Sopenharmony_ci
45678c2ecf20Sopenharmony_ci	}
45688c2ecf20Sopenharmony_ci
45698c2ecf20Sopenharmony_ciout:
45708c2ecf20Sopenharmony_ci	return ret;
45718c2ecf20Sopenharmony_ci}
45728c2ecf20Sopenharmony_ci
45738c2ecf20Sopenharmony_ci/*
45748c2ecf20Sopenharmony_ci * Find the suitable pos when we divide a bucket into 2.
45758c2ecf20Sopenharmony_ci * We have to make sure the xattrs with the same hash value exist
45768c2ecf20Sopenharmony_ci * in the same bucket.
45778c2ecf20Sopenharmony_ci *
45788c2ecf20Sopenharmony_ci * If this ocfs2_xattr_header covers more than one hash value, find a
45798c2ecf20Sopenharmony_ci * place where the hash value changes.  Try to find the most even split.
45808c2ecf20Sopenharmony_ci * The most common case is that all entries have different hash values,
45818c2ecf20Sopenharmony_ci * and the first check we make will find a place to split.
45828c2ecf20Sopenharmony_ci */
45838c2ecf20Sopenharmony_cistatic int ocfs2_xattr_find_divide_pos(struct ocfs2_xattr_header *xh)
45848c2ecf20Sopenharmony_ci{
45858c2ecf20Sopenharmony_ci	struct ocfs2_xattr_entry *entries = xh->xh_entries;
45868c2ecf20Sopenharmony_ci	int count = le16_to_cpu(xh->xh_count);
45878c2ecf20Sopenharmony_ci	int delta, middle = count / 2;
45888c2ecf20Sopenharmony_ci
45898c2ecf20Sopenharmony_ci	/*
45908c2ecf20Sopenharmony_ci	 * We start at the middle.  Each step gets farther away in both
45918c2ecf20Sopenharmony_ci	 * directions.  We therefore hit the change in hash value
45928c2ecf20Sopenharmony_ci	 * nearest to the middle.  Note that this loop does not execute for
45938c2ecf20Sopenharmony_ci	 * count < 2.
45948c2ecf20Sopenharmony_ci	 */
45958c2ecf20Sopenharmony_ci	for (delta = 0; delta < middle; delta++) {
45968c2ecf20Sopenharmony_ci		/* Let's check delta earlier than middle */
45978c2ecf20Sopenharmony_ci		if (cmp_xe(&entries[middle - delta - 1],
45988c2ecf20Sopenharmony_ci			   &entries[middle - delta]))
45998c2ecf20Sopenharmony_ci			return middle - delta;
46008c2ecf20Sopenharmony_ci
46018c2ecf20Sopenharmony_ci		/* For even counts, don't walk off the end */
46028c2ecf20Sopenharmony_ci		if ((middle + delta + 1) == count)
46038c2ecf20Sopenharmony_ci			continue;
46048c2ecf20Sopenharmony_ci
46058c2ecf20Sopenharmony_ci		/* Now try delta past middle */
46068c2ecf20Sopenharmony_ci		if (cmp_xe(&entries[middle + delta],
46078c2ecf20Sopenharmony_ci			   &entries[middle + delta + 1]))
46088c2ecf20Sopenharmony_ci			return middle + delta + 1;
46098c2ecf20Sopenharmony_ci	}
46108c2ecf20Sopenharmony_ci
46118c2ecf20Sopenharmony_ci	/* Every entry had the same hash */
46128c2ecf20Sopenharmony_ci	return count;
46138c2ecf20Sopenharmony_ci}
46148c2ecf20Sopenharmony_ci
46158c2ecf20Sopenharmony_ci/*
46168c2ecf20Sopenharmony_ci * Move some xattrs in old bucket(blk) to new bucket(new_blk).
46178c2ecf20Sopenharmony_ci * first_hash will record the 1st hash of the new bucket.
46188c2ecf20Sopenharmony_ci *
46198c2ecf20Sopenharmony_ci * Normally half of the xattrs will be moved.  But we have to make
46208c2ecf20Sopenharmony_ci * sure that the xattrs with the same hash value are stored in the
46218c2ecf20Sopenharmony_ci * same bucket. If all the xattrs in this bucket have the same hash
46228c2ecf20Sopenharmony_ci * value, the new bucket will be initialized as an empty one and the
46238c2ecf20Sopenharmony_ci * first_hash will be initialized as (hash_value+1).
46248c2ecf20Sopenharmony_ci */
46258c2ecf20Sopenharmony_cistatic int ocfs2_divide_xattr_bucket(struct inode *inode,
46268c2ecf20Sopenharmony_ci				    handle_t *handle,
46278c2ecf20Sopenharmony_ci				    u64 blk,
46288c2ecf20Sopenharmony_ci				    u64 new_blk,
46298c2ecf20Sopenharmony_ci				    u32 *first_hash,
46308c2ecf20Sopenharmony_ci				    int new_bucket_head)
46318c2ecf20Sopenharmony_ci{
46328c2ecf20Sopenharmony_ci	int ret, i;
46338c2ecf20Sopenharmony_ci	int count, start, len, name_value_len = 0, name_offset = 0;
46348c2ecf20Sopenharmony_ci	struct ocfs2_xattr_bucket *s_bucket = NULL, *t_bucket = NULL;
46358c2ecf20Sopenharmony_ci	struct ocfs2_xattr_header *xh;
46368c2ecf20Sopenharmony_ci	struct ocfs2_xattr_entry *xe;
46378c2ecf20Sopenharmony_ci	int blocksize = inode->i_sb->s_blocksize;
46388c2ecf20Sopenharmony_ci
46398c2ecf20Sopenharmony_ci	trace_ocfs2_divide_xattr_bucket_begin((unsigned long long)blk,
46408c2ecf20Sopenharmony_ci					      (unsigned long long)new_blk);
46418c2ecf20Sopenharmony_ci
46428c2ecf20Sopenharmony_ci	s_bucket = ocfs2_xattr_bucket_new(inode);
46438c2ecf20Sopenharmony_ci	t_bucket = ocfs2_xattr_bucket_new(inode);
46448c2ecf20Sopenharmony_ci	if (!s_bucket || !t_bucket) {
46458c2ecf20Sopenharmony_ci		ret = -ENOMEM;
46468c2ecf20Sopenharmony_ci		mlog_errno(ret);
46478c2ecf20Sopenharmony_ci		goto out;
46488c2ecf20Sopenharmony_ci	}
46498c2ecf20Sopenharmony_ci
46508c2ecf20Sopenharmony_ci	ret = ocfs2_read_xattr_bucket(s_bucket, blk);
46518c2ecf20Sopenharmony_ci	if (ret) {
46528c2ecf20Sopenharmony_ci		mlog_errno(ret);
46538c2ecf20Sopenharmony_ci		goto out;
46548c2ecf20Sopenharmony_ci	}
46558c2ecf20Sopenharmony_ci
46568c2ecf20Sopenharmony_ci	ret = ocfs2_xattr_bucket_journal_access(handle, s_bucket,
46578c2ecf20Sopenharmony_ci						OCFS2_JOURNAL_ACCESS_WRITE);
46588c2ecf20Sopenharmony_ci	if (ret) {
46598c2ecf20Sopenharmony_ci		mlog_errno(ret);
46608c2ecf20Sopenharmony_ci		goto out;
46618c2ecf20Sopenharmony_ci	}
46628c2ecf20Sopenharmony_ci
46638c2ecf20Sopenharmony_ci	/*
46648c2ecf20Sopenharmony_ci	 * Even if !new_bucket_head, we're overwriting t_bucket.  Thus,
46658c2ecf20Sopenharmony_ci	 * there's no need to read it.
46668c2ecf20Sopenharmony_ci	 */
46678c2ecf20Sopenharmony_ci	ret = ocfs2_init_xattr_bucket(t_bucket, new_blk, new_bucket_head);
46688c2ecf20Sopenharmony_ci	if (ret) {
46698c2ecf20Sopenharmony_ci		mlog_errno(ret);
46708c2ecf20Sopenharmony_ci		goto out;
46718c2ecf20Sopenharmony_ci	}
46728c2ecf20Sopenharmony_ci
46738c2ecf20Sopenharmony_ci	/*
46748c2ecf20Sopenharmony_ci	 * Hey, if we're overwriting t_bucket, what difference does
46758c2ecf20Sopenharmony_ci	 * ACCESS_CREATE vs ACCESS_WRITE make?  See the comment in the
46768c2ecf20Sopenharmony_ci	 * same part of ocfs2_cp_xattr_bucket().
46778c2ecf20Sopenharmony_ci	 */
46788c2ecf20Sopenharmony_ci	ret = ocfs2_xattr_bucket_journal_access(handle, t_bucket,
46798c2ecf20Sopenharmony_ci						new_bucket_head ?
46808c2ecf20Sopenharmony_ci						OCFS2_JOURNAL_ACCESS_CREATE :
46818c2ecf20Sopenharmony_ci						OCFS2_JOURNAL_ACCESS_WRITE);
46828c2ecf20Sopenharmony_ci	if (ret) {
46838c2ecf20Sopenharmony_ci		mlog_errno(ret);
46848c2ecf20Sopenharmony_ci		goto out;
46858c2ecf20Sopenharmony_ci	}
46868c2ecf20Sopenharmony_ci
46878c2ecf20Sopenharmony_ci	xh = bucket_xh(s_bucket);
46888c2ecf20Sopenharmony_ci	count = le16_to_cpu(xh->xh_count);
46898c2ecf20Sopenharmony_ci	start = ocfs2_xattr_find_divide_pos(xh);
46908c2ecf20Sopenharmony_ci
46918c2ecf20Sopenharmony_ci	if (start == count) {
46928c2ecf20Sopenharmony_ci		xe = &xh->xh_entries[start-1];
46938c2ecf20Sopenharmony_ci
46948c2ecf20Sopenharmony_ci		/*
46958c2ecf20Sopenharmony_ci		 * initialized a new empty bucket here.
46968c2ecf20Sopenharmony_ci		 * The hash value is set as one larger than
46978c2ecf20Sopenharmony_ci		 * that of the last entry in the previous bucket.
46988c2ecf20Sopenharmony_ci		 */
46998c2ecf20Sopenharmony_ci		for (i = 0; i < t_bucket->bu_blocks; i++)
47008c2ecf20Sopenharmony_ci			memset(bucket_block(t_bucket, i), 0, blocksize);
47018c2ecf20Sopenharmony_ci
47028c2ecf20Sopenharmony_ci		xh = bucket_xh(t_bucket);
47038c2ecf20Sopenharmony_ci		xh->xh_free_start = cpu_to_le16(blocksize);
47048c2ecf20Sopenharmony_ci		xh->xh_entries[0].xe_name_hash = xe->xe_name_hash;
47058c2ecf20Sopenharmony_ci		le32_add_cpu(&xh->xh_entries[0].xe_name_hash, 1);
47068c2ecf20Sopenharmony_ci
47078c2ecf20Sopenharmony_ci		goto set_num_buckets;
47088c2ecf20Sopenharmony_ci	}
47098c2ecf20Sopenharmony_ci
47108c2ecf20Sopenharmony_ci	/* copy the whole bucket to the new first. */
47118c2ecf20Sopenharmony_ci	ocfs2_xattr_bucket_copy_data(t_bucket, s_bucket);
47128c2ecf20Sopenharmony_ci
47138c2ecf20Sopenharmony_ci	/* update the new bucket. */
47148c2ecf20Sopenharmony_ci	xh = bucket_xh(t_bucket);
47158c2ecf20Sopenharmony_ci
47168c2ecf20Sopenharmony_ci	/*
47178c2ecf20Sopenharmony_ci	 * Calculate the total name/value len and xh_free_start for
47188c2ecf20Sopenharmony_ci	 * the old bucket first.
47198c2ecf20Sopenharmony_ci	 */
47208c2ecf20Sopenharmony_ci	name_offset = OCFS2_XATTR_BUCKET_SIZE;
47218c2ecf20Sopenharmony_ci	name_value_len = 0;
47228c2ecf20Sopenharmony_ci	for (i = 0; i < start; i++) {
47238c2ecf20Sopenharmony_ci		xe = &xh->xh_entries[i];
47248c2ecf20Sopenharmony_ci		name_value_len += namevalue_size_xe(xe);
47258c2ecf20Sopenharmony_ci		if (le16_to_cpu(xe->xe_name_offset) < name_offset)
47268c2ecf20Sopenharmony_ci			name_offset = le16_to_cpu(xe->xe_name_offset);
47278c2ecf20Sopenharmony_ci	}
47288c2ecf20Sopenharmony_ci
47298c2ecf20Sopenharmony_ci	/*
47308c2ecf20Sopenharmony_ci	 * Now begin the modification to the new bucket.
47318c2ecf20Sopenharmony_ci	 *
47328c2ecf20Sopenharmony_ci	 * In the new bucket, We just move the xattr entry to the beginning
47338c2ecf20Sopenharmony_ci	 * and don't touch the name/value. So there will be some holes in the
47348c2ecf20Sopenharmony_ci	 * bucket, and they will be removed when ocfs2_defrag_xattr_bucket is
47358c2ecf20Sopenharmony_ci	 * called.
47368c2ecf20Sopenharmony_ci	 */
47378c2ecf20Sopenharmony_ci	xe = &xh->xh_entries[start];
47388c2ecf20Sopenharmony_ci	len = sizeof(struct ocfs2_xattr_entry) * (count - start);
47398c2ecf20Sopenharmony_ci	trace_ocfs2_divide_xattr_bucket_move(len,
47408c2ecf20Sopenharmony_ci			(int)((char *)xe - (char *)xh),
47418c2ecf20Sopenharmony_ci			(int)((char *)xh->xh_entries - (char *)xh));
47428c2ecf20Sopenharmony_ci	memmove((char *)xh->xh_entries, (char *)xe, len);
47438c2ecf20Sopenharmony_ci	xe = &xh->xh_entries[count - start];
47448c2ecf20Sopenharmony_ci	len = sizeof(struct ocfs2_xattr_entry) * start;
47458c2ecf20Sopenharmony_ci	memset((char *)xe, 0, len);
47468c2ecf20Sopenharmony_ci
47478c2ecf20Sopenharmony_ci	le16_add_cpu(&xh->xh_count, -start);
47488c2ecf20Sopenharmony_ci	le16_add_cpu(&xh->xh_name_value_len, -name_value_len);
47498c2ecf20Sopenharmony_ci
47508c2ecf20Sopenharmony_ci	/* Calculate xh_free_start for the new bucket. */
47518c2ecf20Sopenharmony_ci	xh->xh_free_start = cpu_to_le16(OCFS2_XATTR_BUCKET_SIZE);
47528c2ecf20Sopenharmony_ci	for (i = 0; i < le16_to_cpu(xh->xh_count); i++) {
47538c2ecf20Sopenharmony_ci		xe = &xh->xh_entries[i];
47548c2ecf20Sopenharmony_ci		if (le16_to_cpu(xe->xe_name_offset) <
47558c2ecf20Sopenharmony_ci		    le16_to_cpu(xh->xh_free_start))
47568c2ecf20Sopenharmony_ci			xh->xh_free_start = xe->xe_name_offset;
47578c2ecf20Sopenharmony_ci	}
47588c2ecf20Sopenharmony_ci
47598c2ecf20Sopenharmony_ciset_num_buckets:
47608c2ecf20Sopenharmony_ci	/* set xh->xh_num_buckets for the new xh. */
47618c2ecf20Sopenharmony_ci	if (new_bucket_head)
47628c2ecf20Sopenharmony_ci		xh->xh_num_buckets = cpu_to_le16(1);
47638c2ecf20Sopenharmony_ci	else
47648c2ecf20Sopenharmony_ci		xh->xh_num_buckets = 0;
47658c2ecf20Sopenharmony_ci
47668c2ecf20Sopenharmony_ci	ocfs2_xattr_bucket_journal_dirty(handle, t_bucket);
47678c2ecf20Sopenharmony_ci
47688c2ecf20Sopenharmony_ci	/* store the first_hash of the new bucket. */
47698c2ecf20Sopenharmony_ci	if (first_hash)
47708c2ecf20Sopenharmony_ci		*first_hash = le32_to_cpu(xh->xh_entries[0].xe_name_hash);
47718c2ecf20Sopenharmony_ci
47728c2ecf20Sopenharmony_ci	/*
47738c2ecf20Sopenharmony_ci	 * Now only update the 1st block of the old bucket.  If we
47748c2ecf20Sopenharmony_ci	 * just added a new empty bucket, there is no need to modify
47758c2ecf20Sopenharmony_ci	 * it.
47768c2ecf20Sopenharmony_ci	 */
47778c2ecf20Sopenharmony_ci	if (start == count)
47788c2ecf20Sopenharmony_ci		goto out;
47798c2ecf20Sopenharmony_ci
47808c2ecf20Sopenharmony_ci	xh = bucket_xh(s_bucket);
47818c2ecf20Sopenharmony_ci	memset(&xh->xh_entries[start], 0,
47828c2ecf20Sopenharmony_ci	       sizeof(struct ocfs2_xattr_entry) * (count - start));
47838c2ecf20Sopenharmony_ci	xh->xh_count = cpu_to_le16(start);
47848c2ecf20Sopenharmony_ci	xh->xh_free_start = cpu_to_le16(name_offset);
47858c2ecf20Sopenharmony_ci	xh->xh_name_value_len = cpu_to_le16(name_value_len);
47868c2ecf20Sopenharmony_ci
47878c2ecf20Sopenharmony_ci	ocfs2_xattr_bucket_journal_dirty(handle, s_bucket);
47888c2ecf20Sopenharmony_ci
47898c2ecf20Sopenharmony_ciout:
47908c2ecf20Sopenharmony_ci	ocfs2_xattr_bucket_free(s_bucket);
47918c2ecf20Sopenharmony_ci	ocfs2_xattr_bucket_free(t_bucket);
47928c2ecf20Sopenharmony_ci
47938c2ecf20Sopenharmony_ci	return ret;
47948c2ecf20Sopenharmony_ci}
47958c2ecf20Sopenharmony_ci
47968c2ecf20Sopenharmony_ci/*
47978c2ecf20Sopenharmony_ci * Copy xattr from one bucket to another bucket.
47988c2ecf20Sopenharmony_ci *
47998c2ecf20Sopenharmony_ci * The caller must make sure that the journal transaction
48008c2ecf20Sopenharmony_ci * has enough space for journaling.
48018c2ecf20Sopenharmony_ci */
48028c2ecf20Sopenharmony_cistatic int ocfs2_cp_xattr_bucket(struct inode *inode,
48038c2ecf20Sopenharmony_ci				 handle_t *handle,
48048c2ecf20Sopenharmony_ci				 u64 s_blkno,
48058c2ecf20Sopenharmony_ci				 u64 t_blkno,
48068c2ecf20Sopenharmony_ci				 int t_is_new)
48078c2ecf20Sopenharmony_ci{
48088c2ecf20Sopenharmony_ci	int ret;
48098c2ecf20Sopenharmony_ci	struct ocfs2_xattr_bucket *s_bucket = NULL, *t_bucket = NULL;
48108c2ecf20Sopenharmony_ci
48118c2ecf20Sopenharmony_ci	BUG_ON(s_blkno == t_blkno);
48128c2ecf20Sopenharmony_ci
48138c2ecf20Sopenharmony_ci	trace_ocfs2_cp_xattr_bucket((unsigned long long)s_blkno,
48148c2ecf20Sopenharmony_ci				    (unsigned long long)t_blkno,
48158c2ecf20Sopenharmony_ci				    t_is_new);
48168c2ecf20Sopenharmony_ci
48178c2ecf20Sopenharmony_ci	s_bucket = ocfs2_xattr_bucket_new(inode);
48188c2ecf20Sopenharmony_ci	t_bucket = ocfs2_xattr_bucket_new(inode);
48198c2ecf20Sopenharmony_ci	if (!s_bucket || !t_bucket) {
48208c2ecf20Sopenharmony_ci		ret = -ENOMEM;
48218c2ecf20Sopenharmony_ci		mlog_errno(ret);
48228c2ecf20Sopenharmony_ci		goto out;
48238c2ecf20Sopenharmony_ci	}
48248c2ecf20Sopenharmony_ci
48258c2ecf20Sopenharmony_ci	ret = ocfs2_read_xattr_bucket(s_bucket, s_blkno);
48268c2ecf20Sopenharmony_ci	if (ret)
48278c2ecf20Sopenharmony_ci		goto out;
48288c2ecf20Sopenharmony_ci
48298c2ecf20Sopenharmony_ci	/*
48308c2ecf20Sopenharmony_ci	 * Even if !t_is_new, we're overwriting t_bucket.  Thus,
48318c2ecf20Sopenharmony_ci	 * there's no need to read it.
48328c2ecf20Sopenharmony_ci	 */
48338c2ecf20Sopenharmony_ci	ret = ocfs2_init_xattr_bucket(t_bucket, t_blkno, t_is_new);
48348c2ecf20Sopenharmony_ci	if (ret)
48358c2ecf20Sopenharmony_ci		goto out;
48368c2ecf20Sopenharmony_ci
48378c2ecf20Sopenharmony_ci	/*
48388c2ecf20Sopenharmony_ci	 * Hey, if we're overwriting t_bucket, what difference does
48398c2ecf20Sopenharmony_ci	 * ACCESS_CREATE vs ACCESS_WRITE make?  Well, if we allocated a new
48408c2ecf20Sopenharmony_ci	 * cluster to fill, we came here from
48418c2ecf20Sopenharmony_ci	 * ocfs2_mv_xattr_buckets(), and it is really new -
48428c2ecf20Sopenharmony_ci	 * ACCESS_CREATE is required.  But we also might have moved data
48438c2ecf20Sopenharmony_ci	 * out of t_bucket before extending back into it.
48448c2ecf20Sopenharmony_ci	 * ocfs2_add_new_xattr_bucket() can do this - its call to
48458c2ecf20Sopenharmony_ci	 * ocfs2_add_new_xattr_cluster() may have created a new extent
48468c2ecf20Sopenharmony_ci	 * and copied out the end of the old extent.  Then it re-extends
48478c2ecf20Sopenharmony_ci	 * the old extent back to create space for new xattrs.  That's
48488c2ecf20Sopenharmony_ci	 * how we get here, and the bucket isn't really new.
48498c2ecf20Sopenharmony_ci	 */
48508c2ecf20Sopenharmony_ci	ret = ocfs2_xattr_bucket_journal_access(handle, t_bucket,
48518c2ecf20Sopenharmony_ci						t_is_new ?
48528c2ecf20Sopenharmony_ci						OCFS2_JOURNAL_ACCESS_CREATE :
48538c2ecf20Sopenharmony_ci						OCFS2_JOURNAL_ACCESS_WRITE);
48548c2ecf20Sopenharmony_ci	if (ret)
48558c2ecf20Sopenharmony_ci		goto out;
48568c2ecf20Sopenharmony_ci
48578c2ecf20Sopenharmony_ci	ocfs2_xattr_bucket_copy_data(t_bucket, s_bucket);
48588c2ecf20Sopenharmony_ci	ocfs2_xattr_bucket_journal_dirty(handle, t_bucket);
48598c2ecf20Sopenharmony_ci
48608c2ecf20Sopenharmony_ciout:
48618c2ecf20Sopenharmony_ci	ocfs2_xattr_bucket_free(t_bucket);
48628c2ecf20Sopenharmony_ci	ocfs2_xattr_bucket_free(s_bucket);
48638c2ecf20Sopenharmony_ci
48648c2ecf20Sopenharmony_ci	return ret;
48658c2ecf20Sopenharmony_ci}
48668c2ecf20Sopenharmony_ci
48678c2ecf20Sopenharmony_ci/*
48688c2ecf20Sopenharmony_ci * src_blk points to the start of an existing extent.  last_blk points to
48698c2ecf20Sopenharmony_ci * last cluster in that extent.  to_blk points to a newly allocated
48708c2ecf20Sopenharmony_ci * extent.  We copy the buckets from the cluster at last_blk to the new
48718c2ecf20Sopenharmony_ci * extent.  If start_bucket is non-zero, we skip that many buckets before
48728c2ecf20Sopenharmony_ci * we start copying.  The new extent's xh_num_buckets gets set to the
48738c2ecf20Sopenharmony_ci * number of buckets we copied.  The old extent's xh_num_buckets shrinks
48748c2ecf20Sopenharmony_ci * by the same amount.
48758c2ecf20Sopenharmony_ci */
48768c2ecf20Sopenharmony_cistatic int ocfs2_mv_xattr_buckets(struct inode *inode, handle_t *handle,
48778c2ecf20Sopenharmony_ci				  u64 src_blk, u64 last_blk, u64 to_blk,
48788c2ecf20Sopenharmony_ci				  unsigned int start_bucket,
48798c2ecf20Sopenharmony_ci				  u32 *first_hash)
48808c2ecf20Sopenharmony_ci{
48818c2ecf20Sopenharmony_ci	int i, ret, credits;
48828c2ecf20Sopenharmony_ci	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
48838c2ecf20Sopenharmony_ci	int blks_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
48848c2ecf20Sopenharmony_ci	int num_buckets = ocfs2_xattr_buckets_per_cluster(osb);
48858c2ecf20Sopenharmony_ci	struct ocfs2_xattr_bucket *old_first, *new_first;
48868c2ecf20Sopenharmony_ci
48878c2ecf20Sopenharmony_ci	trace_ocfs2_mv_xattr_buckets((unsigned long long)last_blk,
48888c2ecf20Sopenharmony_ci				     (unsigned long long)to_blk);
48898c2ecf20Sopenharmony_ci
48908c2ecf20Sopenharmony_ci	BUG_ON(start_bucket >= num_buckets);
48918c2ecf20Sopenharmony_ci	if (start_bucket) {
48928c2ecf20Sopenharmony_ci		num_buckets -= start_bucket;
48938c2ecf20Sopenharmony_ci		last_blk += (start_bucket * blks_per_bucket);
48948c2ecf20Sopenharmony_ci	}
48958c2ecf20Sopenharmony_ci
48968c2ecf20Sopenharmony_ci	/* The first bucket of the original extent */
48978c2ecf20Sopenharmony_ci	old_first = ocfs2_xattr_bucket_new(inode);
48988c2ecf20Sopenharmony_ci	/* The first bucket of the new extent */
48998c2ecf20Sopenharmony_ci	new_first = ocfs2_xattr_bucket_new(inode);
49008c2ecf20Sopenharmony_ci	if (!old_first || !new_first) {
49018c2ecf20Sopenharmony_ci		ret = -ENOMEM;
49028c2ecf20Sopenharmony_ci		mlog_errno(ret);
49038c2ecf20Sopenharmony_ci		goto out;
49048c2ecf20Sopenharmony_ci	}
49058c2ecf20Sopenharmony_ci
49068c2ecf20Sopenharmony_ci	ret = ocfs2_read_xattr_bucket(old_first, src_blk);
49078c2ecf20Sopenharmony_ci	if (ret) {
49088c2ecf20Sopenharmony_ci		mlog_errno(ret);
49098c2ecf20Sopenharmony_ci		goto out;
49108c2ecf20Sopenharmony_ci	}
49118c2ecf20Sopenharmony_ci
49128c2ecf20Sopenharmony_ci	/*
49138c2ecf20Sopenharmony_ci	 * We need to update the first bucket of the old extent and all
49148c2ecf20Sopenharmony_ci	 * the buckets going to the new extent.
49158c2ecf20Sopenharmony_ci	 */
49168c2ecf20Sopenharmony_ci	credits = ((num_buckets + 1) * blks_per_bucket);
49178c2ecf20Sopenharmony_ci	ret = ocfs2_extend_trans(handle, credits);
49188c2ecf20Sopenharmony_ci	if (ret) {
49198c2ecf20Sopenharmony_ci		mlog_errno(ret);
49208c2ecf20Sopenharmony_ci		goto out;
49218c2ecf20Sopenharmony_ci	}
49228c2ecf20Sopenharmony_ci
49238c2ecf20Sopenharmony_ci	ret = ocfs2_xattr_bucket_journal_access(handle, old_first,
49248c2ecf20Sopenharmony_ci						OCFS2_JOURNAL_ACCESS_WRITE);
49258c2ecf20Sopenharmony_ci	if (ret) {
49268c2ecf20Sopenharmony_ci		mlog_errno(ret);
49278c2ecf20Sopenharmony_ci		goto out;
49288c2ecf20Sopenharmony_ci	}
49298c2ecf20Sopenharmony_ci
49308c2ecf20Sopenharmony_ci	for (i = 0; i < num_buckets; i++) {
49318c2ecf20Sopenharmony_ci		ret = ocfs2_cp_xattr_bucket(inode, handle,
49328c2ecf20Sopenharmony_ci					    last_blk + (i * blks_per_bucket),
49338c2ecf20Sopenharmony_ci					    to_blk + (i * blks_per_bucket),
49348c2ecf20Sopenharmony_ci					    1);
49358c2ecf20Sopenharmony_ci		if (ret) {
49368c2ecf20Sopenharmony_ci			mlog_errno(ret);
49378c2ecf20Sopenharmony_ci			goto out;
49388c2ecf20Sopenharmony_ci		}
49398c2ecf20Sopenharmony_ci	}
49408c2ecf20Sopenharmony_ci
49418c2ecf20Sopenharmony_ci	/*
49428c2ecf20Sopenharmony_ci	 * Get the new bucket ready before we dirty anything
49438c2ecf20Sopenharmony_ci	 * (This actually shouldn't fail, because we already dirtied
49448c2ecf20Sopenharmony_ci	 * it once in ocfs2_cp_xattr_bucket()).
49458c2ecf20Sopenharmony_ci	 */
49468c2ecf20Sopenharmony_ci	ret = ocfs2_read_xattr_bucket(new_first, to_blk);
49478c2ecf20Sopenharmony_ci	if (ret) {
49488c2ecf20Sopenharmony_ci		mlog_errno(ret);
49498c2ecf20Sopenharmony_ci		goto out;
49508c2ecf20Sopenharmony_ci	}
49518c2ecf20Sopenharmony_ci	ret = ocfs2_xattr_bucket_journal_access(handle, new_first,
49528c2ecf20Sopenharmony_ci						OCFS2_JOURNAL_ACCESS_WRITE);
49538c2ecf20Sopenharmony_ci	if (ret) {
49548c2ecf20Sopenharmony_ci		mlog_errno(ret);
49558c2ecf20Sopenharmony_ci		goto out;
49568c2ecf20Sopenharmony_ci	}
49578c2ecf20Sopenharmony_ci
49588c2ecf20Sopenharmony_ci	/* Now update the headers */
49598c2ecf20Sopenharmony_ci	le16_add_cpu(&bucket_xh(old_first)->xh_num_buckets, -num_buckets);
49608c2ecf20Sopenharmony_ci	ocfs2_xattr_bucket_journal_dirty(handle, old_first);
49618c2ecf20Sopenharmony_ci
49628c2ecf20Sopenharmony_ci	bucket_xh(new_first)->xh_num_buckets = cpu_to_le16(num_buckets);
49638c2ecf20Sopenharmony_ci	ocfs2_xattr_bucket_journal_dirty(handle, new_first);
49648c2ecf20Sopenharmony_ci
49658c2ecf20Sopenharmony_ci	if (first_hash)
49668c2ecf20Sopenharmony_ci		*first_hash = le32_to_cpu(bucket_xh(new_first)->xh_entries[0].xe_name_hash);
49678c2ecf20Sopenharmony_ci
49688c2ecf20Sopenharmony_ciout:
49698c2ecf20Sopenharmony_ci	ocfs2_xattr_bucket_free(new_first);
49708c2ecf20Sopenharmony_ci	ocfs2_xattr_bucket_free(old_first);
49718c2ecf20Sopenharmony_ci	return ret;
49728c2ecf20Sopenharmony_ci}
49738c2ecf20Sopenharmony_ci
49748c2ecf20Sopenharmony_ci/*
49758c2ecf20Sopenharmony_ci * Move some xattrs in this cluster to the new cluster.
49768c2ecf20Sopenharmony_ci * This function should only be called when bucket size == cluster size.
49778c2ecf20Sopenharmony_ci * Otherwise ocfs2_mv_xattr_bucket_cross_cluster should be used instead.
49788c2ecf20Sopenharmony_ci */
49798c2ecf20Sopenharmony_cistatic int ocfs2_divide_xattr_cluster(struct inode *inode,
49808c2ecf20Sopenharmony_ci				      handle_t *handle,
49818c2ecf20Sopenharmony_ci				      u64 prev_blk,
49828c2ecf20Sopenharmony_ci				      u64 new_blk,
49838c2ecf20Sopenharmony_ci				      u32 *first_hash)
49848c2ecf20Sopenharmony_ci{
49858c2ecf20Sopenharmony_ci	u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
49868c2ecf20Sopenharmony_ci	int ret, credits = 2 * blk_per_bucket;
49878c2ecf20Sopenharmony_ci
49888c2ecf20Sopenharmony_ci	BUG_ON(OCFS2_XATTR_BUCKET_SIZE < OCFS2_SB(inode->i_sb)->s_clustersize);
49898c2ecf20Sopenharmony_ci
49908c2ecf20Sopenharmony_ci	ret = ocfs2_extend_trans(handle, credits);
49918c2ecf20Sopenharmony_ci	if (ret) {
49928c2ecf20Sopenharmony_ci		mlog_errno(ret);
49938c2ecf20Sopenharmony_ci		return ret;
49948c2ecf20Sopenharmony_ci	}
49958c2ecf20Sopenharmony_ci
49968c2ecf20Sopenharmony_ci	/* Move half of the xattr in start_blk to the next bucket. */
49978c2ecf20Sopenharmony_ci	return  ocfs2_divide_xattr_bucket(inode, handle, prev_blk,
49988c2ecf20Sopenharmony_ci					  new_blk, first_hash, 1);
49998c2ecf20Sopenharmony_ci}
50008c2ecf20Sopenharmony_ci
50018c2ecf20Sopenharmony_ci/*
50028c2ecf20Sopenharmony_ci * Move some xattrs from the old cluster to the new one since they are not
50038c2ecf20Sopenharmony_ci * contiguous in ocfs2 xattr tree.
50048c2ecf20Sopenharmony_ci *
50058c2ecf20Sopenharmony_ci * new_blk starts a new separate cluster, and we will move some xattrs from
50068c2ecf20Sopenharmony_ci * prev_blk to it. v_start will be set as the first name hash value in this
50078c2ecf20Sopenharmony_ci * new cluster so that it can be used as e_cpos during tree insertion and
50088c2ecf20Sopenharmony_ci * don't collide with our original b-tree operations. first_bh and header_bh
50098c2ecf20Sopenharmony_ci * will also be updated since they will be used in ocfs2_extend_xattr_bucket
50108c2ecf20Sopenharmony_ci * to extend the insert bucket.
50118c2ecf20Sopenharmony_ci *
50128c2ecf20Sopenharmony_ci * The problem is how much xattr should we move to the new one and when should
50138c2ecf20Sopenharmony_ci * we update first_bh and header_bh?
50148c2ecf20Sopenharmony_ci * 1. If cluster size > bucket size, that means the previous cluster has more
50158c2ecf20Sopenharmony_ci *    than 1 bucket, so just move half nums of bucket into the new cluster and
50168c2ecf20Sopenharmony_ci *    update the first_bh and header_bh if the insert bucket has been moved
50178c2ecf20Sopenharmony_ci *    to the new cluster.
50188c2ecf20Sopenharmony_ci * 2. If cluster_size == bucket_size:
50198c2ecf20Sopenharmony_ci *    a) If the previous extent rec has more than one cluster and the insert
50208c2ecf20Sopenharmony_ci *       place isn't in the last cluster, copy the entire last cluster to the
50218c2ecf20Sopenharmony_ci *       new one. This time, we don't need to upate the first_bh and header_bh
50228c2ecf20Sopenharmony_ci *       since they will not be moved into the new cluster.
50238c2ecf20Sopenharmony_ci *    b) Otherwise, move the bottom half of the xattrs in the last cluster into
50248c2ecf20Sopenharmony_ci *       the new one. And we set the extend flag to zero if the insert place is
50258c2ecf20Sopenharmony_ci *       moved into the new allocated cluster since no extend is needed.
50268c2ecf20Sopenharmony_ci */
50278c2ecf20Sopenharmony_cistatic int ocfs2_adjust_xattr_cross_cluster(struct inode *inode,
50288c2ecf20Sopenharmony_ci					    handle_t *handle,
50298c2ecf20Sopenharmony_ci					    struct ocfs2_xattr_bucket *first,
50308c2ecf20Sopenharmony_ci					    struct ocfs2_xattr_bucket *target,
50318c2ecf20Sopenharmony_ci					    u64 new_blk,
50328c2ecf20Sopenharmony_ci					    u32 prev_clusters,
50338c2ecf20Sopenharmony_ci					    u32 *v_start,
50348c2ecf20Sopenharmony_ci					    int *extend)
50358c2ecf20Sopenharmony_ci{
50368c2ecf20Sopenharmony_ci	int ret;
50378c2ecf20Sopenharmony_ci
50388c2ecf20Sopenharmony_ci	trace_ocfs2_adjust_xattr_cross_cluster(
50398c2ecf20Sopenharmony_ci			(unsigned long long)bucket_blkno(first),
50408c2ecf20Sopenharmony_ci			(unsigned long long)new_blk, prev_clusters);
50418c2ecf20Sopenharmony_ci
50428c2ecf20Sopenharmony_ci	if (ocfs2_xattr_buckets_per_cluster(OCFS2_SB(inode->i_sb)) > 1) {
50438c2ecf20Sopenharmony_ci		ret = ocfs2_mv_xattr_bucket_cross_cluster(inode,
50448c2ecf20Sopenharmony_ci							  handle,
50458c2ecf20Sopenharmony_ci							  first, target,
50468c2ecf20Sopenharmony_ci							  new_blk,
50478c2ecf20Sopenharmony_ci							  prev_clusters,
50488c2ecf20Sopenharmony_ci							  v_start);
50498c2ecf20Sopenharmony_ci		if (ret)
50508c2ecf20Sopenharmony_ci			mlog_errno(ret);
50518c2ecf20Sopenharmony_ci	} else {
50528c2ecf20Sopenharmony_ci		/* The start of the last cluster in the first extent */
50538c2ecf20Sopenharmony_ci		u64 last_blk = bucket_blkno(first) +
50548c2ecf20Sopenharmony_ci			((prev_clusters - 1) *
50558c2ecf20Sopenharmony_ci			 ocfs2_clusters_to_blocks(inode->i_sb, 1));
50568c2ecf20Sopenharmony_ci
50578c2ecf20Sopenharmony_ci		if (prev_clusters > 1 && bucket_blkno(target) != last_blk) {
50588c2ecf20Sopenharmony_ci			ret = ocfs2_mv_xattr_buckets(inode, handle,
50598c2ecf20Sopenharmony_ci						     bucket_blkno(first),
50608c2ecf20Sopenharmony_ci						     last_blk, new_blk, 0,
50618c2ecf20Sopenharmony_ci						     v_start);
50628c2ecf20Sopenharmony_ci			if (ret)
50638c2ecf20Sopenharmony_ci				mlog_errno(ret);
50648c2ecf20Sopenharmony_ci		} else {
50658c2ecf20Sopenharmony_ci			ret = ocfs2_divide_xattr_cluster(inode, handle,
50668c2ecf20Sopenharmony_ci							 last_blk, new_blk,
50678c2ecf20Sopenharmony_ci							 v_start);
50688c2ecf20Sopenharmony_ci			if (ret)
50698c2ecf20Sopenharmony_ci				mlog_errno(ret);
50708c2ecf20Sopenharmony_ci
50718c2ecf20Sopenharmony_ci			if ((bucket_blkno(target) == last_blk) && extend)
50728c2ecf20Sopenharmony_ci				*extend = 0;
50738c2ecf20Sopenharmony_ci		}
50748c2ecf20Sopenharmony_ci	}
50758c2ecf20Sopenharmony_ci
50768c2ecf20Sopenharmony_ci	return ret;
50778c2ecf20Sopenharmony_ci}
50788c2ecf20Sopenharmony_ci
50798c2ecf20Sopenharmony_ci/*
50808c2ecf20Sopenharmony_ci * Add a new cluster for xattr storage.
50818c2ecf20Sopenharmony_ci *
50828c2ecf20Sopenharmony_ci * If the new cluster is contiguous with the previous one, it will be
50838c2ecf20Sopenharmony_ci * appended to the same extent record, and num_clusters will be updated.
50848c2ecf20Sopenharmony_ci * If not, we will insert a new extent for it and move some xattrs in
50858c2ecf20Sopenharmony_ci * the last cluster into the new allocated one.
50868c2ecf20Sopenharmony_ci * We also need to limit the maximum size of a btree leaf, otherwise we'll
50878c2ecf20Sopenharmony_ci * lose the benefits of hashing because we'll have to search large leaves.
50888c2ecf20Sopenharmony_ci * So now the maximum size is OCFS2_MAX_XATTR_TREE_LEAF_SIZE(or clustersize,
50898c2ecf20Sopenharmony_ci * if it's bigger).
50908c2ecf20Sopenharmony_ci *
50918c2ecf20Sopenharmony_ci * first_bh is the first block of the previous extent rec and header_bh
50928c2ecf20Sopenharmony_ci * indicates the bucket we will insert the new xattrs. They will be updated
50938c2ecf20Sopenharmony_ci * when the header_bh is moved into the new cluster.
50948c2ecf20Sopenharmony_ci */
50958c2ecf20Sopenharmony_cistatic int ocfs2_add_new_xattr_cluster(struct inode *inode,
50968c2ecf20Sopenharmony_ci				       struct buffer_head *root_bh,
50978c2ecf20Sopenharmony_ci				       struct ocfs2_xattr_bucket *first,
50988c2ecf20Sopenharmony_ci				       struct ocfs2_xattr_bucket *target,
50998c2ecf20Sopenharmony_ci				       u32 *num_clusters,
51008c2ecf20Sopenharmony_ci				       u32 prev_cpos,
51018c2ecf20Sopenharmony_ci				       int *extend,
51028c2ecf20Sopenharmony_ci				       struct ocfs2_xattr_set_ctxt *ctxt)
51038c2ecf20Sopenharmony_ci{
51048c2ecf20Sopenharmony_ci	int ret;
51058c2ecf20Sopenharmony_ci	u16 bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1);
51068c2ecf20Sopenharmony_ci	u32 prev_clusters = *num_clusters;
51078c2ecf20Sopenharmony_ci	u32 clusters_to_add = 1, bit_off, num_bits, v_start = 0;
51088c2ecf20Sopenharmony_ci	u64 block;
51098c2ecf20Sopenharmony_ci	handle_t *handle = ctxt->handle;
51108c2ecf20Sopenharmony_ci	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
51118c2ecf20Sopenharmony_ci	struct ocfs2_extent_tree et;
51128c2ecf20Sopenharmony_ci
51138c2ecf20Sopenharmony_ci	trace_ocfs2_add_new_xattr_cluster_begin(
51148c2ecf20Sopenharmony_ci		(unsigned long long)OCFS2_I(inode)->ip_blkno,
51158c2ecf20Sopenharmony_ci		(unsigned long long)bucket_blkno(first),
51168c2ecf20Sopenharmony_ci		prev_cpos, prev_clusters);
51178c2ecf20Sopenharmony_ci
51188c2ecf20Sopenharmony_ci	ocfs2_init_xattr_tree_extent_tree(&et, INODE_CACHE(inode), root_bh);
51198c2ecf20Sopenharmony_ci
51208c2ecf20Sopenharmony_ci	ret = ocfs2_journal_access_xb(handle, INODE_CACHE(inode), root_bh,
51218c2ecf20Sopenharmony_ci				      OCFS2_JOURNAL_ACCESS_WRITE);
51228c2ecf20Sopenharmony_ci	if (ret < 0) {
51238c2ecf20Sopenharmony_ci		mlog_errno(ret);
51248c2ecf20Sopenharmony_ci		goto leave;
51258c2ecf20Sopenharmony_ci	}
51268c2ecf20Sopenharmony_ci
51278c2ecf20Sopenharmony_ci	ret = __ocfs2_claim_clusters(handle, ctxt->data_ac, 1,
51288c2ecf20Sopenharmony_ci				     clusters_to_add, &bit_off, &num_bits);
51298c2ecf20Sopenharmony_ci	if (ret < 0) {
51308c2ecf20Sopenharmony_ci		if (ret != -ENOSPC)
51318c2ecf20Sopenharmony_ci			mlog_errno(ret);
51328c2ecf20Sopenharmony_ci		goto leave;
51338c2ecf20Sopenharmony_ci	}
51348c2ecf20Sopenharmony_ci
51358c2ecf20Sopenharmony_ci	BUG_ON(num_bits > clusters_to_add);
51368c2ecf20Sopenharmony_ci
51378c2ecf20Sopenharmony_ci	block = ocfs2_clusters_to_blocks(osb->sb, bit_off);
51388c2ecf20Sopenharmony_ci	trace_ocfs2_add_new_xattr_cluster((unsigned long long)block, num_bits);
51398c2ecf20Sopenharmony_ci
51408c2ecf20Sopenharmony_ci	if (bucket_blkno(first) + (prev_clusters * bpc) == block &&
51418c2ecf20Sopenharmony_ci	    (prev_clusters + num_bits) << osb->s_clustersize_bits <=
51428c2ecf20Sopenharmony_ci	     OCFS2_MAX_XATTR_TREE_LEAF_SIZE) {
51438c2ecf20Sopenharmony_ci		/*
51448c2ecf20Sopenharmony_ci		 * If this cluster is contiguous with the old one and
51458c2ecf20Sopenharmony_ci		 * adding this new cluster, we don't surpass the limit of
51468c2ecf20Sopenharmony_ci		 * OCFS2_MAX_XATTR_TREE_LEAF_SIZE, cool. We will let it be
51478c2ecf20Sopenharmony_ci		 * initialized and used like other buckets in the previous
51488c2ecf20Sopenharmony_ci		 * cluster.
51498c2ecf20Sopenharmony_ci		 * So add it as a contiguous one. The caller will handle
51508c2ecf20Sopenharmony_ci		 * its init process.
51518c2ecf20Sopenharmony_ci		 */
51528c2ecf20Sopenharmony_ci		v_start = prev_cpos + prev_clusters;
51538c2ecf20Sopenharmony_ci		*num_clusters = prev_clusters + num_bits;
51548c2ecf20Sopenharmony_ci	} else {
51558c2ecf20Sopenharmony_ci		ret = ocfs2_adjust_xattr_cross_cluster(inode,
51568c2ecf20Sopenharmony_ci						       handle,
51578c2ecf20Sopenharmony_ci						       first,
51588c2ecf20Sopenharmony_ci						       target,
51598c2ecf20Sopenharmony_ci						       block,
51608c2ecf20Sopenharmony_ci						       prev_clusters,
51618c2ecf20Sopenharmony_ci						       &v_start,
51628c2ecf20Sopenharmony_ci						       extend);
51638c2ecf20Sopenharmony_ci		if (ret) {
51648c2ecf20Sopenharmony_ci			mlog_errno(ret);
51658c2ecf20Sopenharmony_ci			goto leave;
51668c2ecf20Sopenharmony_ci		}
51678c2ecf20Sopenharmony_ci	}
51688c2ecf20Sopenharmony_ci
51698c2ecf20Sopenharmony_ci	trace_ocfs2_add_new_xattr_cluster_insert((unsigned long long)block,
51708c2ecf20Sopenharmony_ci						 v_start, num_bits);
51718c2ecf20Sopenharmony_ci	ret = ocfs2_insert_extent(handle, &et, v_start, block,
51728c2ecf20Sopenharmony_ci				  num_bits, 0, ctxt->meta_ac);
51738c2ecf20Sopenharmony_ci	if (ret < 0) {
51748c2ecf20Sopenharmony_ci		mlog_errno(ret);
51758c2ecf20Sopenharmony_ci		goto leave;
51768c2ecf20Sopenharmony_ci	}
51778c2ecf20Sopenharmony_ci
51788c2ecf20Sopenharmony_ci	ocfs2_journal_dirty(handle, root_bh);
51798c2ecf20Sopenharmony_ci
51808c2ecf20Sopenharmony_cileave:
51818c2ecf20Sopenharmony_ci	return ret;
51828c2ecf20Sopenharmony_ci}
51838c2ecf20Sopenharmony_ci
51848c2ecf20Sopenharmony_ci/*
51858c2ecf20Sopenharmony_ci * We are given an extent.  'first' is the bucket at the very front of
51868c2ecf20Sopenharmony_ci * the extent.  The extent has space for an additional bucket past
51878c2ecf20Sopenharmony_ci * bucket_xh(first)->xh_num_buckets.  'target_blkno' is the block number
51888c2ecf20Sopenharmony_ci * of the target bucket.  We wish to shift every bucket past the target
51898c2ecf20Sopenharmony_ci * down one, filling in that additional space.  When we get back to the
51908c2ecf20Sopenharmony_ci * target, we split the target between itself and the now-empty bucket
51918c2ecf20Sopenharmony_ci * at target+1 (aka, target_blkno + blks_per_bucket).
51928c2ecf20Sopenharmony_ci */
51938c2ecf20Sopenharmony_cistatic int ocfs2_extend_xattr_bucket(struct inode *inode,
51948c2ecf20Sopenharmony_ci				     handle_t *handle,
51958c2ecf20Sopenharmony_ci				     struct ocfs2_xattr_bucket *first,
51968c2ecf20Sopenharmony_ci				     u64 target_blk,
51978c2ecf20Sopenharmony_ci				     u32 num_clusters)
51988c2ecf20Sopenharmony_ci{
51998c2ecf20Sopenharmony_ci	int ret, credits;
52008c2ecf20Sopenharmony_ci	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
52018c2ecf20Sopenharmony_ci	u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
52028c2ecf20Sopenharmony_ci	u64 end_blk;
52038c2ecf20Sopenharmony_ci	u16 new_bucket = le16_to_cpu(bucket_xh(first)->xh_num_buckets);
52048c2ecf20Sopenharmony_ci
52058c2ecf20Sopenharmony_ci	trace_ocfs2_extend_xattr_bucket((unsigned long long)target_blk,
52068c2ecf20Sopenharmony_ci					(unsigned long long)bucket_blkno(first),
52078c2ecf20Sopenharmony_ci					num_clusters, new_bucket);
52088c2ecf20Sopenharmony_ci
52098c2ecf20Sopenharmony_ci	/* The extent must have room for an additional bucket */
52108c2ecf20Sopenharmony_ci	BUG_ON(new_bucket >=
52118c2ecf20Sopenharmony_ci	       (num_clusters * ocfs2_xattr_buckets_per_cluster(osb)));
52128c2ecf20Sopenharmony_ci
52138c2ecf20Sopenharmony_ci	/* end_blk points to the last existing bucket */
52148c2ecf20Sopenharmony_ci	end_blk = bucket_blkno(first) + ((new_bucket - 1) * blk_per_bucket);
52158c2ecf20Sopenharmony_ci
52168c2ecf20Sopenharmony_ci	/*
52178c2ecf20Sopenharmony_ci	 * end_blk is the start of the last existing bucket.
52188c2ecf20Sopenharmony_ci	 * Thus, (end_blk - target_blk) covers the target bucket and
52198c2ecf20Sopenharmony_ci	 * every bucket after it up to, but not including, the last
52208c2ecf20Sopenharmony_ci	 * existing bucket.  Then we add the last existing bucket, the
52218c2ecf20Sopenharmony_ci	 * new bucket, and the first bucket (3 * blk_per_bucket).
52228c2ecf20Sopenharmony_ci	 */
52238c2ecf20Sopenharmony_ci	credits = (end_blk - target_blk) + (3 * blk_per_bucket);
52248c2ecf20Sopenharmony_ci	ret = ocfs2_extend_trans(handle, credits);
52258c2ecf20Sopenharmony_ci	if (ret) {
52268c2ecf20Sopenharmony_ci		mlog_errno(ret);
52278c2ecf20Sopenharmony_ci		goto out;
52288c2ecf20Sopenharmony_ci	}
52298c2ecf20Sopenharmony_ci
52308c2ecf20Sopenharmony_ci	ret = ocfs2_xattr_bucket_journal_access(handle, first,
52318c2ecf20Sopenharmony_ci						OCFS2_JOURNAL_ACCESS_WRITE);
52328c2ecf20Sopenharmony_ci	if (ret) {
52338c2ecf20Sopenharmony_ci		mlog_errno(ret);
52348c2ecf20Sopenharmony_ci		goto out;
52358c2ecf20Sopenharmony_ci	}
52368c2ecf20Sopenharmony_ci
52378c2ecf20Sopenharmony_ci	while (end_blk != target_blk) {
52388c2ecf20Sopenharmony_ci		ret = ocfs2_cp_xattr_bucket(inode, handle, end_blk,
52398c2ecf20Sopenharmony_ci					    end_blk + blk_per_bucket, 0);
52408c2ecf20Sopenharmony_ci		if (ret)
52418c2ecf20Sopenharmony_ci			goto out;
52428c2ecf20Sopenharmony_ci		end_blk -= blk_per_bucket;
52438c2ecf20Sopenharmony_ci	}
52448c2ecf20Sopenharmony_ci
52458c2ecf20Sopenharmony_ci	/* Move half of the xattr in target_blkno to the next bucket. */
52468c2ecf20Sopenharmony_ci	ret = ocfs2_divide_xattr_bucket(inode, handle, target_blk,
52478c2ecf20Sopenharmony_ci					target_blk + blk_per_bucket, NULL, 0);
52488c2ecf20Sopenharmony_ci
52498c2ecf20Sopenharmony_ci	le16_add_cpu(&bucket_xh(first)->xh_num_buckets, 1);
52508c2ecf20Sopenharmony_ci	ocfs2_xattr_bucket_journal_dirty(handle, first);
52518c2ecf20Sopenharmony_ci
52528c2ecf20Sopenharmony_ciout:
52538c2ecf20Sopenharmony_ci	return ret;
52548c2ecf20Sopenharmony_ci}
52558c2ecf20Sopenharmony_ci
52568c2ecf20Sopenharmony_ci/*
52578c2ecf20Sopenharmony_ci * Add new xattr bucket in an extent record and adjust the buckets
52588c2ecf20Sopenharmony_ci * accordingly.  xb_bh is the ocfs2_xattr_block, and target is the
52598c2ecf20Sopenharmony_ci * bucket we want to insert into.
52608c2ecf20Sopenharmony_ci *
52618c2ecf20Sopenharmony_ci * In the easy case, we will move all the buckets after target down by
52628c2ecf20Sopenharmony_ci * one. Half of target's xattrs will be moved to the next bucket.
52638c2ecf20Sopenharmony_ci *
52648c2ecf20Sopenharmony_ci * If current cluster is full, we'll allocate a new one.  This may not
52658c2ecf20Sopenharmony_ci * be contiguous.  The underlying calls will make sure that there is
52668c2ecf20Sopenharmony_ci * space for the insert, shifting buckets around if necessary.
52678c2ecf20Sopenharmony_ci * 'target' may be moved by those calls.
52688c2ecf20Sopenharmony_ci */
52698c2ecf20Sopenharmony_cistatic int ocfs2_add_new_xattr_bucket(struct inode *inode,
52708c2ecf20Sopenharmony_ci				      struct buffer_head *xb_bh,
52718c2ecf20Sopenharmony_ci				      struct ocfs2_xattr_bucket *target,
52728c2ecf20Sopenharmony_ci				      struct ocfs2_xattr_set_ctxt *ctxt)
52738c2ecf20Sopenharmony_ci{
52748c2ecf20Sopenharmony_ci	struct ocfs2_xattr_block *xb =
52758c2ecf20Sopenharmony_ci			(struct ocfs2_xattr_block *)xb_bh->b_data;
52768c2ecf20Sopenharmony_ci	struct ocfs2_xattr_tree_root *xb_root = &xb->xb_attrs.xb_root;
52778c2ecf20Sopenharmony_ci	struct ocfs2_extent_list *el = &xb_root->xt_list;
52788c2ecf20Sopenharmony_ci	u32 name_hash =
52798c2ecf20Sopenharmony_ci		le32_to_cpu(bucket_xh(target)->xh_entries[0].xe_name_hash);
52808c2ecf20Sopenharmony_ci	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
52818c2ecf20Sopenharmony_ci	int ret, num_buckets, extend = 1;
52828c2ecf20Sopenharmony_ci	u64 p_blkno;
52838c2ecf20Sopenharmony_ci	u32 e_cpos, num_clusters;
52848c2ecf20Sopenharmony_ci	/* The bucket at the front of the extent */
52858c2ecf20Sopenharmony_ci	struct ocfs2_xattr_bucket *first;
52868c2ecf20Sopenharmony_ci
52878c2ecf20Sopenharmony_ci	trace_ocfs2_add_new_xattr_bucket(
52888c2ecf20Sopenharmony_ci				(unsigned long long)bucket_blkno(target));
52898c2ecf20Sopenharmony_ci
52908c2ecf20Sopenharmony_ci	/* The first bucket of the original extent */
52918c2ecf20Sopenharmony_ci	first = ocfs2_xattr_bucket_new(inode);
52928c2ecf20Sopenharmony_ci	if (!first) {
52938c2ecf20Sopenharmony_ci		ret = -ENOMEM;
52948c2ecf20Sopenharmony_ci		mlog_errno(ret);
52958c2ecf20Sopenharmony_ci		goto out;
52968c2ecf20Sopenharmony_ci	}
52978c2ecf20Sopenharmony_ci
52988c2ecf20Sopenharmony_ci	ret = ocfs2_xattr_get_rec(inode, name_hash, &p_blkno, &e_cpos,
52998c2ecf20Sopenharmony_ci				  &num_clusters, el);
53008c2ecf20Sopenharmony_ci	if (ret) {
53018c2ecf20Sopenharmony_ci		mlog_errno(ret);
53028c2ecf20Sopenharmony_ci		goto out;
53038c2ecf20Sopenharmony_ci	}
53048c2ecf20Sopenharmony_ci
53058c2ecf20Sopenharmony_ci	ret = ocfs2_read_xattr_bucket(first, p_blkno);
53068c2ecf20Sopenharmony_ci	if (ret) {
53078c2ecf20Sopenharmony_ci		mlog_errno(ret);
53088c2ecf20Sopenharmony_ci		goto out;
53098c2ecf20Sopenharmony_ci	}
53108c2ecf20Sopenharmony_ci
53118c2ecf20Sopenharmony_ci	num_buckets = ocfs2_xattr_buckets_per_cluster(osb) * num_clusters;
53128c2ecf20Sopenharmony_ci	if (num_buckets == le16_to_cpu(bucket_xh(first)->xh_num_buckets)) {
53138c2ecf20Sopenharmony_ci		/*
53148c2ecf20Sopenharmony_ci		 * This can move first+target if the target bucket moves
53158c2ecf20Sopenharmony_ci		 * to the new extent.
53168c2ecf20Sopenharmony_ci		 */
53178c2ecf20Sopenharmony_ci		ret = ocfs2_add_new_xattr_cluster(inode,
53188c2ecf20Sopenharmony_ci						  xb_bh,
53198c2ecf20Sopenharmony_ci						  first,
53208c2ecf20Sopenharmony_ci						  target,
53218c2ecf20Sopenharmony_ci						  &num_clusters,
53228c2ecf20Sopenharmony_ci						  e_cpos,
53238c2ecf20Sopenharmony_ci						  &extend,
53248c2ecf20Sopenharmony_ci						  ctxt);
53258c2ecf20Sopenharmony_ci		if (ret) {
53268c2ecf20Sopenharmony_ci			mlog_errno(ret);
53278c2ecf20Sopenharmony_ci			goto out;
53288c2ecf20Sopenharmony_ci		}
53298c2ecf20Sopenharmony_ci	}
53308c2ecf20Sopenharmony_ci
53318c2ecf20Sopenharmony_ci	if (extend) {
53328c2ecf20Sopenharmony_ci		ret = ocfs2_extend_xattr_bucket(inode,
53338c2ecf20Sopenharmony_ci						ctxt->handle,
53348c2ecf20Sopenharmony_ci						first,
53358c2ecf20Sopenharmony_ci						bucket_blkno(target),
53368c2ecf20Sopenharmony_ci						num_clusters);
53378c2ecf20Sopenharmony_ci		if (ret)
53388c2ecf20Sopenharmony_ci			mlog_errno(ret);
53398c2ecf20Sopenharmony_ci	}
53408c2ecf20Sopenharmony_ci
53418c2ecf20Sopenharmony_ciout:
53428c2ecf20Sopenharmony_ci	ocfs2_xattr_bucket_free(first);
53438c2ecf20Sopenharmony_ci
53448c2ecf20Sopenharmony_ci	return ret;
53458c2ecf20Sopenharmony_ci}
53468c2ecf20Sopenharmony_ci
53478c2ecf20Sopenharmony_ci/*
53488c2ecf20Sopenharmony_ci * Truncate the specified xe_off entry in xattr bucket.
53498c2ecf20Sopenharmony_ci * bucket is indicated by header_bh and len is the new length.
53508c2ecf20Sopenharmony_ci * Both the ocfs2_xattr_value_root and the entry will be updated here.
53518c2ecf20Sopenharmony_ci *
53528c2ecf20Sopenharmony_ci * Copy the new updated xe and xe_value_root to new_xe and new_xv if needed.
53538c2ecf20Sopenharmony_ci */
53548c2ecf20Sopenharmony_cistatic int ocfs2_xattr_bucket_value_truncate(struct inode *inode,
53558c2ecf20Sopenharmony_ci					     struct ocfs2_xattr_bucket *bucket,
53568c2ecf20Sopenharmony_ci					     int xe_off,
53578c2ecf20Sopenharmony_ci					     int len,
53588c2ecf20Sopenharmony_ci					     struct ocfs2_xattr_set_ctxt *ctxt)
53598c2ecf20Sopenharmony_ci{
53608c2ecf20Sopenharmony_ci	int ret, offset;
53618c2ecf20Sopenharmony_ci	u64 value_blk;
53628c2ecf20Sopenharmony_ci	struct ocfs2_xattr_entry *xe;
53638c2ecf20Sopenharmony_ci	struct ocfs2_xattr_header *xh = bucket_xh(bucket);
53648c2ecf20Sopenharmony_ci	size_t blocksize = inode->i_sb->s_blocksize;
53658c2ecf20Sopenharmony_ci	struct ocfs2_xattr_value_buf vb = {
53668c2ecf20Sopenharmony_ci		.vb_access = ocfs2_journal_access,
53678c2ecf20Sopenharmony_ci	};
53688c2ecf20Sopenharmony_ci
53698c2ecf20Sopenharmony_ci	xe = &xh->xh_entries[xe_off];
53708c2ecf20Sopenharmony_ci
53718c2ecf20Sopenharmony_ci	BUG_ON(!xe || ocfs2_xattr_is_local(xe));
53728c2ecf20Sopenharmony_ci
53738c2ecf20Sopenharmony_ci	offset = le16_to_cpu(xe->xe_name_offset) +
53748c2ecf20Sopenharmony_ci		 OCFS2_XATTR_SIZE(xe->xe_name_len);
53758c2ecf20Sopenharmony_ci
53768c2ecf20Sopenharmony_ci	value_blk = offset / blocksize;
53778c2ecf20Sopenharmony_ci
53788c2ecf20Sopenharmony_ci	/* We don't allow ocfs2_xattr_value to be stored in different block. */
53798c2ecf20Sopenharmony_ci	BUG_ON(value_blk != (offset + OCFS2_XATTR_ROOT_SIZE - 1) / blocksize);
53808c2ecf20Sopenharmony_ci
53818c2ecf20Sopenharmony_ci	vb.vb_bh = bucket->bu_bhs[value_blk];
53828c2ecf20Sopenharmony_ci	BUG_ON(!vb.vb_bh);
53838c2ecf20Sopenharmony_ci
53848c2ecf20Sopenharmony_ci	vb.vb_xv = (struct ocfs2_xattr_value_root *)
53858c2ecf20Sopenharmony_ci		(vb.vb_bh->b_data + offset % blocksize);
53868c2ecf20Sopenharmony_ci
53878c2ecf20Sopenharmony_ci	/*
53888c2ecf20Sopenharmony_ci	 * From here on out we have to dirty the bucket.  The generic
53898c2ecf20Sopenharmony_ci	 * value calls only modify one of the bucket's bhs, but we need
53908c2ecf20Sopenharmony_ci	 * to send the bucket at once.  So if they error, they *could* have
53918c2ecf20Sopenharmony_ci	 * modified something.  We have to assume they did, and dirty
53928c2ecf20Sopenharmony_ci	 * the whole bucket.  This leaves us in a consistent state.
53938c2ecf20Sopenharmony_ci	 */
53948c2ecf20Sopenharmony_ci	trace_ocfs2_xattr_bucket_value_truncate(
53958c2ecf20Sopenharmony_ci			(unsigned long long)bucket_blkno(bucket), xe_off, len);
53968c2ecf20Sopenharmony_ci	ret = ocfs2_xattr_value_truncate(inode, &vb, len, ctxt);
53978c2ecf20Sopenharmony_ci	if (ret) {
53988c2ecf20Sopenharmony_ci		mlog_errno(ret);
53998c2ecf20Sopenharmony_ci		goto out;
54008c2ecf20Sopenharmony_ci	}
54018c2ecf20Sopenharmony_ci
54028c2ecf20Sopenharmony_ci	ret = ocfs2_xattr_bucket_journal_access(ctxt->handle, bucket,
54038c2ecf20Sopenharmony_ci						OCFS2_JOURNAL_ACCESS_WRITE);
54048c2ecf20Sopenharmony_ci	if (ret) {
54058c2ecf20Sopenharmony_ci		mlog_errno(ret);
54068c2ecf20Sopenharmony_ci		goto out;
54078c2ecf20Sopenharmony_ci	}
54088c2ecf20Sopenharmony_ci
54098c2ecf20Sopenharmony_ci	xe->xe_value_size = cpu_to_le64(len);
54108c2ecf20Sopenharmony_ci
54118c2ecf20Sopenharmony_ci	ocfs2_xattr_bucket_journal_dirty(ctxt->handle, bucket);
54128c2ecf20Sopenharmony_ci
54138c2ecf20Sopenharmony_ciout:
54148c2ecf20Sopenharmony_ci	return ret;
54158c2ecf20Sopenharmony_ci}
54168c2ecf20Sopenharmony_ci
54178c2ecf20Sopenharmony_cistatic int ocfs2_rm_xattr_cluster(struct inode *inode,
54188c2ecf20Sopenharmony_ci				  struct buffer_head *root_bh,
54198c2ecf20Sopenharmony_ci				  u64 blkno,
54208c2ecf20Sopenharmony_ci				  u32 cpos,
54218c2ecf20Sopenharmony_ci				  u32 len,
54228c2ecf20Sopenharmony_ci				  void *para)
54238c2ecf20Sopenharmony_ci{
54248c2ecf20Sopenharmony_ci	int ret;
54258c2ecf20Sopenharmony_ci	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
54268c2ecf20Sopenharmony_ci	struct inode *tl_inode = osb->osb_tl_inode;
54278c2ecf20Sopenharmony_ci	handle_t *handle;
54288c2ecf20Sopenharmony_ci	struct ocfs2_xattr_block *xb =
54298c2ecf20Sopenharmony_ci			(struct ocfs2_xattr_block *)root_bh->b_data;
54308c2ecf20Sopenharmony_ci	struct ocfs2_alloc_context *meta_ac = NULL;
54318c2ecf20Sopenharmony_ci	struct ocfs2_cached_dealloc_ctxt dealloc;
54328c2ecf20Sopenharmony_ci	struct ocfs2_extent_tree et;
54338c2ecf20Sopenharmony_ci
54348c2ecf20Sopenharmony_ci	ret = ocfs2_iterate_xattr_buckets(inode, blkno, len,
54358c2ecf20Sopenharmony_ci					  ocfs2_delete_xattr_in_bucket, para);
54368c2ecf20Sopenharmony_ci	if (ret) {
54378c2ecf20Sopenharmony_ci		mlog_errno(ret);
54388c2ecf20Sopenharmony_ci		return ret;
54398c2ecf20Sopenharmony_ci	}
54408c2ecf20Sopenharmony_ci
54418c2ecf20Sopenharmony_ci	ocfs2_init_xattr_tree_extent_tree(&et, INODE_CACHE(inode), root_bh);
54428c2ecf20Sopenharmony_ci
54438c2ecf20Sopenharmony_ci	ocfs2_init_dealloc_ctxt(&dealloc);
54448c2ecf20Sopenharmony_ci
54458c2ecf20Sopenharmony_ci	trace_ocfs2_rm_xattr_cluster(
54468c2ecf20Sopenharmony_ci			(unsigned long long)OCFS2_I(inode)->ip_blkno,
54478c2ecf20Sopenharmony_ci			(unsigned long long)blkno, cpos, len);
54488c2ecf20Sopenharmony_ci
54498c2ecf20Sopenharmony_ci	ocfs2_remove_xattr_clusters_from_cache(INODE_CACHE(inode), blkno,
54508c2ecf20Sopenharmony_ci					       len);
54518c2ecf20Sopenharmony_ci
54528c2ecf20Sopenharmony_ci	ret = ocfs2_lock_allocators(inode, &et, 0, 1, NULL, &meta_ac);
54538c2ecf20Sopenharmony_ci	if (ret) {
54548c2ecf20Sopenharmony_ci		mlog_errno(ret);
54558c2ecf20Sopenharmony_ci		return ret;
54568c2ecf20Sopenharmony_ci	}
54578c2ecf20Sopenharmony_ci
54588c2ecf20Sopenharmony_ci	inode_lock(tl_inode);
54598c2ecf20Sopenharmony_ci
54608c2ecf20Sopenharmony_ci	if (ocfs2_truncate_log_needs_flush(osb)) {
54618c2ecf20Sopenharmony_ci		ret = __ocfs2_flush_truncate_log(osb);
54628c2ecf20Sopenharmony_ci		if (ret < 0) {
54638c2ecf20Sopenharmony_ci			mlog_errno(ret);
54648c2ecf20Sopenharmony_ci			goto out;
54658c2ecf20Sopenharmony_ci		}
54668c2ecf20Sopenharmony_ci	}
54678c2ecf20Sopenharmony_ci
54688c2ecf20Sopenharmony_ci	handle = ocfs2_start_trans(osb, ocfs2_remove_extent_credits(osb->sb));
54698c2ecf20Sopenharmony_ci	if (IS_ERR(handle)) {
54708c2ecf20Sopenharmony_ci		ret = -ENOMEM;
54718c2ecf20Sopenharmony_ci		mlog_errno(ret);
54728c2ecf20Sopenharmony_ci		goto out;
54738c2ecf20Sopenharmony_ci	}
54748c2ecf20Sopenharmony_ci
54758c2ecf20Sopenharmony_ci	ret = ocfs2_journal_access_xb(handle, INODE_CACHE(inode), root_bh,
54768c2ecf20Sopenharmony_ci				      OCFS2_JOURNAL_ACCESS_WRITE);
54778c2ecf20Sopenharmony_ci	if (ret) {
54788c2ecf20Sopenharmony_ci		mlog_errno(ret);
54798c2ecf20Sopenharmony_ci		goto out_commit;
54808c2ecf20Sopenharmony_ci	}
54818c2ecf20Sopenharmony_ci
54828c2ecf20Sopenharmony_ci	ret = ocfs2_remove_extent(handle, &et, cpos, len, meta_ac,
54838c2ecf20Sopenharmony_ci				  &dealloc);
54848c2ecf20Sopenharmony_ci	if (ret) {
54858c2ecf20Sopenharmony_ci		mlog_errno(ret);
54868c2ecf20Sopenharmony_ci		goto out_commit;
54878c2ecf20Sopenharmony_ci	}
54888c2ecf20Sopenharmony_ci
54898c2ecf20Sopenharmony_ci	le32_add_cpu(&xb->xb_attrs.xb_root.xt_clusters, -len);
54908c2ecf20Sopenharmony_ci	ocfs2_journal_dirty(handle, root_bh);
54918c2ecf20Sopenharmony_ci
54928c2ecf20Sopenharmony_ci	ret = ocfs2_truncate_log_append(osb, handle, blkno, len);
54938c2ecf20Sopenharmony_ci	if (ret)
54948c2ecf20Sopenharmony_ci		mlog_errno(ret);
54958c2ecf20Sopenharmony_ci	ocfs2_update_inode_fsync_trans(handle, inode, 0);
54968c2ecf20Sopenharmony_ci
54978c2ecf20Sopenharmony_ciout_commit:
54988c2ecf20Sopenharmony_ci	ocfs2_commit_trans(osb, handle);
54998c2ecf20Sopenharmony_ciout:
55008c2ecf20Sopenharmony_ci	ocfs2_schedule_truncate_log_flush(osb, 1);
55018c2ecf20Sopenharmony_ci
55028c2ecf20Sopenharmony_ci	inode_unlock(tl_inode);
55038c2ecf20Sopenharmony_ci
55048c2ecf20Sopenharmony_ci	if (meta_ac)
55058c2ecf20Sopenharmony_ci		ocfs2_free_alloc_context(meta_ac);
55068c2ecf20Sopenharmony_ci
55078c2ecf20Sopenharmony_ci	ocfs2_run_deallocs(osb, &dealloc);
55088c2ecf20Sopenharmony_ci
55098c2ecf20Sopenharmony_ci	return ret;
55108c2ecf20Sopenharmony_ci}
55118c2ecf20Sopenharmony_ci
55128c2ecf20Sopenharmony_ci/*
55138c2ecf20Sopenharmony_ci * check whether the xattr bucket is filled up with the same hash value.
55148c2ecf20Sopenharmony_ci * If we want to insert the xattr with the same hash, return -ENOSPC.
55158c2ecf20Sopenharmony_ci * If we want to insert a xattr with different hash value, go ahead
55168c2ecf20Sopenharmony_ci * and ocfs2_divide_xattr_bucket will handle this.
55178c2ecf20Sopenharmony_ci */
55188c2ecf20Sopenharmony_cistatic int ocfs2_check_xattr_bucket_collision(struct inode *inode,
55198c2ecf20Sopenharmony_ci					      struct ocfs2_xattr_bucket *bucket,
55208c2ecf20Sopenharmony_ci					      const char *name)
55218c2ecf20Sopenharmony_ci{
55228c2ecf20Sopenharmony_ci	struct ocfs2_xattr_header *xh = bucket_xh(bucket);
55238c2ecf20Sopenharmony_ci	u32 name_hash = ocfs2_xattr_name_hash(inode, name, strlen(name));
55248c2ecf20Sopenharmony_ci
55258c2ecf20Sopenharmony_ci	if (name_hash != le32_to_cpu(xh->xh_entries[0].xe_name_hash))
55268c2ecf20Sopenharmony_ci		return 0;
55278c2ecf20Sopenharmony_ci
55288c2ecf20Sopenharmony_ci	if (xh->xh_entries[le16_to_cpu(xh->xh_count) - 1].xe_name_hash ==
55298c2ecf20Sopenharmony_ci	    xh->xh_entries[0].xe_name_hash) {
55308c2ecf20Sopenharmony_ci		mlog(ML_ERROR, "Too much hash collision in xattr bucket %llu, "
55318c2ecf20Sopenharmony_ci		     "hash = %u\n",
55328c2ecf20Sopenharmony_ci		     (unsigned long long)bucket_blkno(bucket),
55338c2ecf20Sopenharmony_ci		     le32_to_cpu(xh->xh_entries[0].xe_name_hash));
55348c2ecf20Sopenharmony_ci		return -ENOSPC;
55358c2ecf20Sopenharmony_ci	}
55368c2ecf20Sopenharmony_ci
55378c2ecf20Sopenharmony_ci	return 0;
55388c2ecf20Sopenharmony_ci}
55398c2ecf20Sopenharmony_ci
55408c2ecf20Sopenharmony_ci/*
55418c2ecf20Sopenharmony_ci * Try to set the entry in the current bucket.  If we fail, the caller
55428c2ecf20Sopenharmony_ci * will handle getting us another bucket.
55438c2ecf20Sopenharmony_ci */
55448c2ecf20Sopenharmony_cistatic int ocfs2_xattr_set_entry_bucket(struct inode *inode,
55458c2ecf20Sopenharmony_ci					struct ocfs2_xattr_info *xi,
55468c2ecf20Sopenharmony_ci					struct ocfs2_xattr_search *xs,
55478c2ecf20Sopenharmony_ci					struct ocfs2_xattr_set_ctxt *ctxt)
55488c2ecf20Sopenharmony_ci{
55498c2ecf20Sopenharmony_ci	int ret;
55508c2ecf20Sopenharmony_ci	struct ocfs2_xa_loc loc;
55518c2ecf20Sopenharmony_ci
55528c2ecf20Sopenharmony_ci	trace_ocfs2_xattr_set_entry_bucket(xi->xi_name);
55538c2ecf20Sopenharmony_ci
55548c2ecf20Sopenharmony_ci	ocfs2_init_xattr_bucket_xa_loc(&loc, xs->bucket,
55558c2ecf20Sopenharmony_ci				       xs->not_found ? NULL : xs->here);
55568c2ecf20Sopenharmony_ci	ret = ocfs2_xa_set(&loc, xi, ctxt);
55578c2ecf20Sopenharmony_ci	if (!ret) {
55588c2ecf20Sopenharmony_ci		xs->here = loc.xl_entry;
55598c2ecf20Sopenharmony_ci		goto out;
55608c2ecf20Sopenharmony_ci	}
55618c2ecf20Sopenharmony_ci	if (ret != -ENOSPC) {
55628c2ecf20Sopenharmony_ci		mlog_errno(ret);
55638c2ecf20Sopenharmony_ci		goto out;
55648c2ecf20Sopenharmony_ci	}
55658c2ecf20Sopenharmony_ci
55668c2ecf20Sopenharmony_ci	/* Ok, we need space.  Let's try defragmenting the bucket. */
55678c2ecf20Sopenharmony_ci	ret = ocfs2_defrag_xattr_bucket(inode, ctxt->handle,
55688c2ecf20Sopenharmony_ci					xs->bucket);
55698c2ecf20Sopenharmony_ci	if (ret) {
55708c2ecf20Sopenharmony_ci		mlog_errno(ret);
55718c2ecf20Sopenharmony_ci		goto out;
55728c2ecf20Sopenharmony_ci	}
55738c2ecf20Sopenharmony_ci
55748c2ecf20Sopenharmony_ci	ret = ocfs2_xa_set(&loc, xi, ctxt);
55758c2ecf20Sopenharmony_ci	if (!ret) {
55768c2ecf20Sopenharmony_ci		xs->here = loc.xl_entry;
55778c2ecf20Sopenharmony_ci		goto out;
55788c2ecf20Sopenharmony_ci	}
55798c2ecf20Sopenharmony_ci	if (ret != -ENOSPC)
55808c2ecf20Sopenharmony_ci		mlog_errno(ret);
55818c2ecf20Sopenharmony_ci
55828c2ecf20Sopenharmony_ci
55838c2ecf20Sopenharmony_ciout:
55848c2ecf20Sopenharmony_ci	return ret;
55858c2ecf20Sopenharmony_ci}
55868c2ecf20Sopenharmony_ci
55878c2ecf20Sopenharmony_cistatic int ocfs2_xattr_set_entry_index_block(struct inode *inode,
55888c2ecf20Sopenharmony_ci					     struct ocfs2_xattr_info *xi,
55898c2ecf20Sopenharmony_ci					     struct ocfs2_xattr_search *xs,
55908c2ecf20Sopenharmony_ci					     struct ocfs2_xattr_set_ctxt *ctxt)
55918c2ecf20Sopenharmony_ci{
55928c2ecf20Sopenharmony_ci	int ret;
55938c2ecf20Sopenharmony_ci
55948c2ecf20Sopenharmony_ci	trace_ocfs2_xattr_set_entry_index_block(xi->xi_name);
55958c2ecf20Sopenharmony_ci
55968c2ecf20Sopenharmony_ci	ret = ocfs2_xattr_set_entry_bucket(inode, xi, xs, ctxt);
55978c2ecf20Sopenharmony_ci	if (!ret)
55988c2ecf20Sopenharmony_ci		goto out;
55998c2ecf20Sopenharmony_ci	if (ret != -ENOSPC) {
56008c2ecf20Sopenharmony_ci		mlog_errno(ret);
56018c2ecf20Sopenharmony_ci		goto out;
56028c2ecf20Sopenharmony_ci	}
56038c2ecf20Sopenharmony_ci
56048c2ecf20Sopenharmony_ci	/* Ack, need more space.  Let's try to get another bucket! */
56058c2ecf20Sopenharmony_ci
56068c2ecf20Sopenharmony_ci	/*
56078c2ecf20Sopenharmony_ci	 * We do not allow for overlapping ranges between buckets. And
56088c2ecf20Sopenharmony_ci	 * the maximum number of collisions we will allow for then is
56098c2ecf20Sopenharmony_ci	 * one bucket's worth, so check it here whether we need to
56108c2ecf20Sopenharmony_ci	 * add a new bucket for the insert.
56118c2ecf20Sopenharmony_ci	 */
56128c2ecf20Sopenharmony_ci	ret = ocfs2_check_xattr_bucket_collision(inode,
56138c2ecf20Sopenharmony_ci						 xs->bucket,
56148c2ecf20Sopenharmony_ci						 xi->xi_name);
56158c2ecf20Sopenharmony_ci	if (ret) {
56168c2ecf20Sopenharmony_ci		mlog_errno(ret);
56178c2ecf20Sopenharmony_ci		goto out;
56188c2ecf20Sopenharmony_ci	}
56198c2ecf20Sopenharmony_ci
56208c2ecf20Sopenharmony_ci	ret = ocfs2_add_new_xattr_bucket(inode,
56218c2ecf20Sopenharmony_ci					 xs->xattr_bh,
56228c2ecf20Sopenharmony_ci					 xs->bucket,
56238c2ecf20Sopenharmony_ci					 ctxt);
56248c2ecf20Sopenharmony_ci	if (ret) {
56258c2ecf20Sopenharmony_ci		mlog_errno(ret);
56268c2ecf20Sopenharmony_ci		goto out;
56278c2ecf20Sopenharmony_ci	}
56288c2ecf20Sopenharmony_ci
56298c2ecf20Sopenharmony_ci	/*
56308c2ecf20Sopenharmony_ci	 * ocfs2_add_new_xattr_bucket() will have updated
56318c2ecf20Sopenharmony_ci	 * xs->bucket if it moved, but it will not have updated
56328c2ecf20Sopenharmony_ci	 * any of the other search fields.  Thus, we drop it and
56338c2ecf20Sopenharmony_ci	 * re-search.  Everything should be cached, so it'll be
56348c2ecf20Sopenharmony_ci	 * quick.
56358c2ecf20Sopenharmony_ci	 */
56368c2ecf20Sopenharmony_ci	ocfs2_xattr_bucket_relse(xs->bucket);
56378c2ecf20Sopenharmony_ci	ret = ocfs2_xattr_index_block_find(inode, xs->xattr_bh,
56388c2ecf20Sopenharmony_ci					   xi->xi_name_index,
56398c2ecf20Sopenharmony_ci					   xi->xi_name, xs);
56408c2ecf20Sopenharmony_ci	if (ret && ret != -ENODATA)
56418c2ecf20Sopenharmony_ci		goto out;
56428c2ecf20Sopenharmony_ci	xs->not_found = ret;
56438c2ecf20Sopenharmony_ci
56448c2ecf20Sopenharmony_ci	/* Ok, we have a new bucket, let's try again */
56458c2ecf20Sopenharmony_ci	ret = ocfs2_xattr_set_entry_bucket(inode, xi, xs, ctxt);
56468c2ecf20Sopenharmony_ci	if (ret && (ret != -ENOSPC))
56478c2ecf20Sopenharmony_ci		mlog_errno(ret);
56488c2ecf20Sopenharmony_ci
56498c2ecf20Sopenharmony_ciout:
56508c2ecf20Sopenharmony_ci	return ret;
56518c2ecf20Sopenharmony_ci}
56528c2ecf20Sopenharmony_ci
56538c2ecf20Sopenharmony_cistatic int ocfs2_delete_xattr_in_bucket(struct inode *inode,
56548c2ecf20Sopenharmony_ci					struct ocfs2_xattr_bucket *bucket,
56558c2ecf20Sopenharmony_ci					void *para)
56568c2ecf20Sopenharmony_ci{
56578c2ecf20Sopenharmony_ci	int ret = 0, ref_credits;
56588c2ecf20Sopenharmony_ci	struct ocfs2_xattr_header *xh = bucket_xh(bucket);
56598c2ecf20Sopenharmony_ci	u16 i;
56608c2ecf20Sopenharmony_ci	struct ocfs2_xattr_entry *xe;
56618c2ecf20Sopenharmony_ci	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
56628c2ecf20Sopenharmony_ci	struct ocfs2_xattr_set_ctxt ctxt = {NULL, NULL,};
56638c2ecf20Sopenharmony_ci	int credits = ocfs2_remove_extent_credits(osb->sb) +
56648c2ecf20Sopenharmony_ci		ocfs2_blocks_per_xattr_bucket(inode->i_sb);
56658c2ecf20Sopenharmony_ci	struct ocfs2_xattr_value_root *xv;
56668c2ecf20Sopenharmony_ci	struct ocfs2_rm_xattr_bucket_para *args =
56678c2ecf20Sopenharmony_ci			(struct ocfs2_rm_xattr_bucket_para *)para;
56688c2ecf20Sopenharmony_ci
56698c2ecf20Sopenharmony_ci	ocfs2_init_dealloc_ctxt(&ctxt.dealloc);
56708c2ecf20Sopenharmony_ci
56718c2ecf20Sopenharmony_ci	for (i = 0; i < le16_to_cpu(xh->xh_count); i++) {
56728c2ecf20Sopenharmony_ci		xe = &xh->xh_entries[i];
56738c2ecf20Sopenharmony_ci		if (ocfs2_xattr_is_local(xe))
56748c2ecf20Sopenharmony_ci			continue;
56758c2ecf20Sopenharmony_ci
56768c2ecf20Sopenharmony_ci		ret = ocfs2_get_xattr_tree_value_root(inode->i_sb, bucket,
56778c2ecf20Sopenharmony_ci						      i, &xv, NULL);
56788c2ecf20Sopenharmony_ci		if (ret) {
56798c2ecf20Sopenharmony_ci			mlog_errno(ret);
56808c2ecf20Sopenharmony_ci			break;
56818c2ecf20Sopenharmony_ci		}
56828c2ecf20Sopenharmony_ci
56838c2ecf20Sopenharmony_ci		ret = ocfs2_lock_xattr_remove_allocators(inode, xv,
56848c2ecf20Sopenharmony_ci							 args->ref_ci,
56858c2ecf20Sopenharmony_ci							 args->ref_root_bh,
56868c2ecf20Sopenharmony_ci							 &ctxt.meta_ac,
56878c2ecf20Sopenharmony_ci							 &ref_credits);
56888c2ecf20Sopenharmony_ci
56898c2ecf20Sopenharmony_ci		ctxt.handle = ocfs2_start_trans(osb, credits + ref_credits);
56908c2ecf20Sopenharmony_ci		if (IS_ERR(ctxt.handle)) {
56918c2ecf20Sopenharmony_ci			ret = PTR_ERR(ctxt.handle);
56928c2ecf20Sopenharmony_ci			mlog_errno(ret);
56938c2ecf20Sopenharmony_ci			break;
56948c2ecf20Sopenharmony_ci		}
56958c2ecf20Sopenharmony_ci
56968c2ecf20Sopenharmony_ci		ret = ocfs2_xattr_bucket_value_truncate(inode, bucket,
56978c2ecf20Sopenharmony_ci							i, 0, &ctxt);
56988c2ecf20Sopenharmony_ci
56998c2ecf20Sopenharmony_ci		ocfs2_commit_trans(osb, ctxt.handle);
57008c2ecf20Sopenharmony_ci		if (ctxt.meta_ac) {
57018c2ecf20Sopenharmony_ci			ocfs2_free_alloc_context(ctxt.meta_ac);
57028c2ecf20Sopenharmony_ci			ctxt.meta_ac = NULL;
57038c2ecf20Sopenharmony_ci		}
57048c2ecf20Sopenharmony_ci		if (ret) {
57058c2ecf20Sopenharmony_ci			mlog_errno(ret);
57068c2ecf20Sopenharmony_ci			break;
57078c2ecf20Sopenharmony_ci		}
57088c2ecf20Sopenharmony_ci	}
57098c2ecf20Sopenharmony_ci
57108c2ecf20Sopenharmony_ci	if (ctxt.meta_ac)
57118c2ecf20Sopenharmony_ci		ocfs2_free_alloc_context(ctxt.meta_ac);
57128c2ecf20Sopenharmony_ci	ocfs2_schedule_truncate_log_flush(osb, 1);
57138c2ecf20Sopenharmony_ci	ocfs2_run_deallocs(osb, &ctxt.dealloc);
57148c2ecf20Sopenharmony_ci	return ret;
57158c2ecf20Sopenharmony_ci}
57168c2ecf20Sopenharmony_ci
57178c2ecf20Sopenharmony_ci/*
57188c2ecf20Sopenharmony_ci * Whenever we modify a xattr value root in the bucket(e.g, CoW
57198c2ecf20Sopenharmony_ci * or change the extent record flag), we need to recalculate
57208c2ecf20Sopenharmony_ci * the metaecc for the whole bucket. So it is done here.
57218c2ecf20Sopenharmony_ci *
57228c2ecf20Sopenharmony_ci * Note:
57238c2ecf20Sopenharmony_ci * We have to give the extra credits for the caller.
57248c2ecf20Sopenharmony_ci */
57258c2ecf20Sopenharmony_cistatic int ocfs2_xattr_bucket_post_refcount(struct inode *inode,
57268c2ecf20Sopenharmony_ci					    handle_t *handle,
57278c2ecf20Sopenharmony_ci					    void *para)
57288c2ecf20Sopenharmony_ci{
57298c2ecf20Sopenharmony_ci	int ret;
57308c2ecf20Sopenharmony_ci	struct ocfs2_xattr_bucket *bucket =
57318c2ecf20Sopenharmony_ci			(struct ocfs2_xattr_bucket *)para;
57328c2ecf20Sopenharmony_ci
57338c2ecf20Sopenharmony_ci	ret = ocfs2_xattr_bucket_journal_access(handle, bucket,
57348c2ecf20Sopenharmony_ci						OCFS2_JOURNAL_ACCESS_WRITE);
57358c2ecf20Sopenharmony_ci	if (ret) {
57368c2ecf20Sopenharmony_ci		mlog_errno(ret);
57378c2ecf20Sopenharmony_ci		return ret;
57388c2ecf20Sopenharmony_ci	}
57398c2ecf20Sopenharmony_ci
57408c2ecf20Sopenharmony_ci	ocfs2_xattr_bucket_journal_dirty(handle, bucket);
57418c2ecf20Sopenharmony_ci
57428c2ecf20Sopenharmony_ci	return 0;
57438c2ecf20Sopenharmony_ci}
57448c2ecf20Sopenharmony_ci
57458c2ecf20Sopenharmony_ci/*
57468c2ecf20Sopenharmony_ci * Special action we need if the xattr value is refcounted.
57478c2ecf20Sopenharmony_ci *
57488c2ecf20Sopenharmony_ci * 1. If the xattr is refcounted, lock the tree.
57498c2ecf20Sopenharmony_ci * 2. CoW the xattr if we are setting the new value and the value
57508c2ecf20Sopenharmony_ci *    will be stored outside.
57518c2ecf20Sopenharmony_ci * 3. In other case, decrease_refcount will work for us, so just
57528c2ecf20Sopenharmony_ci *    lock the refcount tree, calculate the meta and credits is OK.
57538c2ecf20Sopenharmony_ci *
57548c2ecf20Sopenharmony_ci * We have to do CoW before ocfs2_init_xattr_set_ctxt since
57558c2ecf20Sopenharmony_ci * currently CoW is a completed transaction, while this function
57568c2ecf20Sopenharmony_ci * will also lock the allocators and let us deadlock. So we will
57578c2ecf20Sopenharmony_ci * CoW the whole xattr value.
57588c2ecf20Sopenharmony_ci */
57598c2ecf20Sopenharmony_cistatic int ocfs2_prepare_refcount_xattr(struct inode *inode,
57608c2ecf20Sopenharmony_ci					struct ocfs2_dinode *di,
57618c2ecf20Sopenharmony_ci					struct ocfs2_xattr_info *xi,
57628c2ecf20Sopenharmony_ci					struct ocfs2_xattr_search *xis,
57638c2ecf20Sopenharmony_ci					struct ocfs2_xattr_search *xbs,
57648c2ecf20Sopenharmony_ci					struct ocfs2_refcount_tree **ref_tree,
57658c2ecf20Sopenharmony_ci					int *meta_add,
57668c2ecf20Sopenharmony_ci					int *credits)
57678c2ecf20Sopenharmony_ci{
57688c2ecf20Sopenharmony_ci	int ret = 0;
57698c2ecf20Sopenharmony_ci	struct ocfs2_xattr_block *xb;
57708c2ecf20Sopenharmony_ci	struct ocfs2_xattr_entry *xe;
57718c2ecf20Sopenharmony_ci	char *base;
57728c2ecf20Sopenharmony_ci	u32 p_cluster, num_clusters;
57738c2ecf20Sopenharmony_ci	unsigned int ext_flags;
57748c2ecf20Sopenharmony_ci	int name_offset, name_len;
57758c2ecf20Sopenharmony_ci	struct ocfs2_xattr_value_buf vb;
57768c2ecf20Sopenharmony_ci	struct ocfs2_xattr_bucket *bucket = NULL;
57778c2ecf20Sopenharmony_ci	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
57788c2ecf20Sopenharmony_ci	struct ocfs2_post_refcount refcount;
57798c2ecf20Sopenharmony_ci	struct ocfs2_post_refcount *p = NULL;
57808c2ecf20Sopenharmony_ci	struct buffer_head *ref_root_bh = NULL;
57818c2ecf20Sopenharmony_ci
57828c2ecf20Sopenharmony_ci	if (!xis->not_found) {
57838c2ecf20Sopenharmony_ci		xe = xis->here;
57848c2ecf20Sopenharmony_ci		name_offset = le16_to_cpu(xe->xe_name_offset);
57858c2ecf20Sopenharmony_ci		name_len = OCFS2_XATTR_SIZE(xe->xe_name_len);
57868c2ecf20Sopenharmony_ci		base = xis->base;
57878c2ecf20Sopenharmony_ci		vb.vb_bh = xis->inode_bh;
57888c2ecf20Sopenharmony_ci		vb.vb_access = ocfs2_journal_access_di;
57898c2ecf20Sopenharmony_ci	} else {
57908c2ecf20Sopenharmony_ci		int i, block_off = 0;
57918c2ecf20Sopenharmony_ci		xb = (struct ocfs2_xattr_block *)xbs->xattr_bh->b_data;
57928c2ecf20Sopenharmony_ci		xe = xbs->here;
57938c2ecf20Sopenharmony_ci		name_offset = le16_to_cpu(xe->xe_name_offset);
57948c2ecf20Sopenharmony_ci		name_len = OCFS2_XATTR_SIZE(xe->xe_name_len);
57958c2ecf20Sopenharmony_ci		i = xbs->here - xbs->header->xh_entries;
57968c2ecf20Sopenharmony_ci
57978c2ecf20Sopenharmony_ci		if (le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED) {
57988c2ecf20Sopenharmony_ci			ret = ocfs2_xattr_bucket_get_name_value(inode->i_sb,
57998c2ecf20Sopenharmony_ci							bucket_xh(xbs->bucket),
58008c2ecf20Sopenharmony_ci							i, &block_off,
58018c2ecf20Sopenharmony_ci							&name_offset);
58028c2ecf20Sopenharmony_ci			if (ret) {
58038c2ecf20Sopenharmony_ci				mlog_errno(ret);
58048c2ecf20Sopenharmony_ci				goto out;
58058c2ecf20Sopenharmony_ci			}
58068c2ecf20Sopenharmony_ci			base = bucket_block(xbs->bucket, block_off);
58078c2ecf20Sopenharmony_ci			vb.vb_bh = xbs->bucket->bu_bhs[block_off];
58088c2ecf20Sopenharmony_ci			vb.vb_access = ocfs2_journal_access;
58098c2ecf20Sopenharmony_ci
58108c2ecf20Sopenharmony_ci			if (ocfs2_meta_ecc(osb)) {
58118c2ecf20Sopenharmony_ci				/*create parameters for ocfs2_post_refcount. */
58128c2ecf20Sopenharmony_ci				bucket = xbs->bucket;
58138c2ecf20Sopenharmony_ci				refcount.credits = bucket->bu_blocks;
58148c2ecf20Sopenharmony_ci				refcount.para = bucket;
58158c2ecf20Sopenharmony_ci				refcount.func =
58168c2ecf20Sopenharmony_ci					ocfs2_xattr_bucket_post_refcount;
58178c2ecf20Sopenharmony_ci				p = &refcount;
58188c2ecf20Sopenharmony_ci			}
58198c2ecf20Sopenharmony_ci		} else {
58208c2ecf20Sopenharmony_ci			base = xbs->base;
58218c2ecf20Sopenharmony_ci			vb.vb_bh = xbs->xattr_bh;
58228c2ecf20Sopenharmony_ci			vb.vb_access = ocfs2_journal_access_xb;
58238c2ecf20Sopenharmony_ci		}
58248c2ecf20Sopenharmony_ci	}
58258c2ecf20Sopenharmony_ci
58268c2ecf20Sopenharmony_ci	if (ocfs2_xattr_is_local(xe))
58278c2ecf20Sopenharmony_ci		goto out;
58288c2ecf20Sopenharmony_ci
58298c2ecf20Sopenharmony_ci	vb.vb_xv = (struct ocfs2_xattr_value_root *)
58308c2ecf20Sopenharmony_ci				(base + name_offset + name_len);
58318c2ecf20Sopenharmony_ci
58328c2ecf20Sopenharmony_ci	ret = ocfs2_xattr_get_clusters(inode, 0, &p_cluster,
58338c2ecf20Sopenharmony_ci				       &num_clusters, &vb.vb_xv->xr_list,
58348c2ecf20Sopenharmony_ci				       &ext_flags);
58358c2ecf20Sopenharmony_ci	if (ret) {
58368c2ecf20Sopenharmony_ci		mlog_errno(ret);
58378c2ecf20Sopenharmony_ci		goto out;
58388c2ecf20Sopenharmony_ci	}
58398c2ecf20Sopenharmony_ci
58408c2ecf20Sopenharmony_ci	/*
58418c2ecf20Sopenharmony_ci	 * We just need to check the 1st extent record, since we always
58428c2ecf20Sopenharmony_ci	 * CoW the whole xattr. So there shouldn't be a xattr with
58438c2ecf20Sopenharmony_ci	 * some REFCOUNT extent recs after the 1st one.
58448c2ecf20Sopenharmony_ci	 */
58458c2ecf20Sopenharmony_ci	if (!(ext_flags & OCFS2_EXT_REFCOUNTED))
58468c2ecf20Sopenharmony_ci		goto out;
58478c2ecf20Sopenharmony_ci
58488c2ecf20Sopenharmony_ci	ret = ocfs2_lock_refcount_tree(osb, le64_to_cpu(di->i_refcount_loc),
58498c2ecf20Sopenharmony_ci				       1, ref_tree, &ref_root_bh);
58508c2ecf20Sopenharmony_ci	if (ret) {
58518c2ecf20Sopenharmony_ci		mlog_errno(ret);
58528c2ecf20Sopenharmony_ci		goto out;
58538c2ecf20Sopenharmony_ci	}
58548c2ecf20Sopenharmony_ci
58558c2ecf20Sopenharmony_ci	/*
58568c2ecf20Sopenharmony_ci	 * If we are deleting the xattr or the new size will be stored inside,
58578c2ecf20Sopenharmony_ci	 * cool, leave it there, the xattr truncate process will remove them
58588c2ecf20Sopenharmony_ci	 * for us(it still needs the refcount tree lock and the meta, credits).
58598c2ecf20Sopenharmony_ci	 * And the worse case is that every cluster truncate will split the
58608c2ecf20Sopenharmony_ci	 * refcount tree, and make the original extent become 3. So we will need
58618c2ecf20Sopenharmony_ci	 * 2 * cluster more extent recs at most.
58628c2ecf20Sopenharmony_ci	 */
58638c2ecf20Sopenharmony_ci	if (!xi->xi_value || xi->xi_value_len <= OCFS2_XATTR_INLINE_SIZE) {
58648c2ecf20Sopenharmony_ci
58658c2ecf20Sopenharmony_ci		ret = ocfs2_refcounted_xattr_delete_need(inode,
58668c2ecf20Sopenharmony_ci							 &(*ref_tree)->rf_ci,
58678c2ecf20Sopenharmony_ci							 ref_root_bh, vb.vb_xv,
58688c2ecf20Sopenharmony_ci							 meta_add, credits);
58698c2ecf20Sopenharmony_ci		if (ret)
58708c2ecf20Sopenharmony_ci			mlog_errno(ret);
58718c2ecf20Sopenharmony_ci		goto out;
58728c2ecf20Sopenharmony_ci	}
58738c2ecf20Sopenharmony_ci
58748c2ecf20Sopenharmony_ci	ret = ocfs2_refcount_cow_xattr(inode, di, &vb,
58758c2ecf20Sopenharmony_ci				       *ref_tree, ref_root_bh, 0,
58768c2ecf20Sopenharmony_ci				       le32_to_cpu(vb.vb_xv->xr_clusters), p);
58778c2ecf20Sopenharmony_ci	if (ret)
58788c2ecf20Sopenharmony_ci		mlog_errno(ret);
58798c2ecf20Sopenharmony_ci
58808c2ecf20Sopenharmony_ciout:
58818c2ecf20Sopenharmony_ci	brelse(ref_root_bh);
58828c2ecf20Sopenharmony_ci	return ret;
58838c2ecf20Sopenharmony_ci}
58848c2ecf20Sopenharmony_ci
58858c2ecf20Sopenharmony_ci/*
58868c2ecf20Sopenharmony_ci * Add the REFCOUNTED flags for all the extent rec in ocfs2_xattr_value_root.
58878c2ecf20Sopenharmony_ci * The physical clusters will be added to refcount tree.
58888c2ecf20Sopenharmony_ci */
58898c2ecf20Sopenharmony_cistatic int ocfs2_xattr_value_attach_refcount(struct inode *inode,
58908c2ecf20Sopenharmony_ci				struct ocfs2_xattr_value_root *xv,
58918c2ecf20Sopenharmony_ci				struct ocfs2_extent_tree *value_et,
58928c2ecf20Sopenharmony_ci				struct ocfs2_caching_info *ref_ci,
58938c2ecf20Sopenharmony_ci				struct buffer_head *ref_root_bh,
58948c2ecf20Sopenharmony_ci				struct ocfs2_cached_dealloc_ctxt *dealloc,
58958c2ecf20Sopenharmony_ci				struct ocfs2_post_refcount *refcount)
58968c2ecf20Sopenharmony_ci{
58978c2ecf20Sopenharmony_ci	int ret = 0;
58988c2ecf20Sopenharmony_ci	u32 clusters = le32_to_cpu(xv->xr_clusters);
58998c2ecf20Sopenharmony_ci	u32 cpos, p_cluster, num_clusters;
59008c2ecf20Sopenharmony_ci	struct ocfs2_extent_list *el = &xv->xr_list;
59018c2ecf20Sopenharmony_ci	unsigned int ext_flags;
59028c2ecf20Sopenharmony_ci
59038c2ecf20Sopenharmony_ci	cpos = 0;
59048c2ecf20Sopenharmony_ci	while (cpos < clusters) {
59058c2ecf20Sopenharmony_ci		ret = ocfs2_xattr_get_clusters(inode, cpos, &p_cluster,
59068c2ecf20Sopenharmony_ci					       &num_clusters, el, &ext_flags);
59078c2ecf20Sopenharmony_ci		if (ret) {
59088c2ecf20Sopenharmony_ci			mlog_errno(ret);
59098c2ecf20Sopenharmony_ci			break;
59108c2ecf20Sopenharmony_ci		}
59118c2ecf20Sopenharmony_ci
59128c2ecf20Sopenharmony_ci		cpos += num_clusters;
59138c2ecf20Sopenharmony_ci		if ((ext_flags & OCFS2_EXT_REFCOUNTED))
59148c2ecf20Sopenharmony_ci			continue;
59158c2ecf20Sopenharmony_ci
59168c2ecf20Sopenharmony_ci		BUG_ON(!p_cluster);
59178c2ecf20Sopenharmony_ci
59188c2ecf20Sopenharmony_ci		ret = ocfs2_add_refcount_flag(inode, value_et,
59198c2ecf20Sopenharmony_ci					      ref_ci, ref_root_bh,
59208c2ecf20Sopenharmony_ci					      cpos - num_clusters,
59218c2ecf20Sopenharmony_ci					      p_cluster, num_clusters,
59228c2ecf20Sopenharmony_ci					      dealloc, refcount);
59238c2ecf20Sopenharmony_ci		if (ret) {
59248c2ecf20Sopenharmony_ci			mlog_errno(ret);
59258c2ecf20Sopenharmony_ci			break;
59268c2ecf20Sopenharmony_ci		}
59278c2ecf20Sopenharmony_ci	}
59288c2ecf20Sopenharmony_ci
59298c2ecf20Sopenharmony_ci	return ret;
59308c2ecf20Sopenharmony_ci}
59318c2ecf20Sopenharmony_ci
59328c2ecf20Sopenharmony_ci/*
59338c2ecf20Sopenharmony_ci * Given a normal ocfs2_xattr_header, refcount all the entries which
59348c2ecf20Sopenharmony_ci * have value stored outside.
59358c2ecf20Sopenharmony_ci * Used for xattrs stored in inode and ocfs2_xattr_block.
59368c2ecf20Sopenharmony_ci */
59378c2ecf20Sopenharmony_cistatic int ocfs2_xattr_attach_refcount_normal(struct inode *inode,
59388c2ecf20Sopenharmony_ci				struct ocfs2_xattr_value_buf *vb,
59398c2ecf20Sopenharmony_ci				struct ocfs2_xattr_header *header,
59408c2ecf20Sopenharmony_ci				struct ocfs2_caching_info *ref_ci,
59418c2ecf20Sopenharmony_ci				struct buffer_head *ref_root_bh,
59428c2ecf20Sopenharmony_ci				struct ocfs2_cached_dealloc_ctxt *dealloc)
59438c2ecf20Sopenharmony_ci{
59448c2ecf20Sopenharmony_ci
59458c2ecf20Sopenharmony_ci	struct ocfs2_xattr_entry *xe;
59468c2ecf20Sopenharmony_ci	struct ocfs2_xattr_value_root *xv;
59478c2ecf20Sopenharmony_ci	struct ocfs2_extent_tree et;
59488c2ecf20Sopenharmony_ci	int i, ret = 0;
59498c2ecf20Sopenharmony_ci
59508c2ecf20Sopenharmony_ci	for (i = 0; i < le16_to_cpu(header->xh_count); i++) {
59518c2ecf20Sopenharmony_ci		xe = &header->xh_entries[i];
59528c2ecf20Sopenharmony_ci
59538c2ecf20Sopenharmony_ci		if (ocfs2_xattr_is_local(xe))
59548c2ecf20Sopenharmony_ci			continue;
59558c2ecf20Sopenharmony_ci
59568c2ecf20Sopenharmony_ci		xv = (struct ocfs2_xattr_value_root *)((void *)header +
59578c2ecf20Sopenharmony_ci			le16_to_cpu(xe->xe_name_offset) +
59588c2ecf20Sopenharmony_ci			OCFS2_XATTR_SIZE(xe->xe_name_len));
59598c2ecf20Sopenharmony_ci
59608c2ecf20Sopenharmony_ci		vb->vb_xv = xv;
59618c2ecf20Sopenharmony_ci		ocfs2_init_xattr_value_extent_tree(&et, INODE_CACHE(inode), vb);
59628c2ecf20Sopenharmony_ci
59638c2ecf20Sopenharmony_ci		ret = ocfs2_xattr_value_attach_refcount(inode, xv, &et,
59648c2ecf20Sopenharmony_ci							ref_ci, ref_root_bh,
59658c2ecf20Sopenharmony_ci							dealloc, NULL);
59668c2ecf20Sopenharmony_ci		if (ret) {
59678c2ecf20Sopenharmony_ci			mlog_errno(ret);
59688c2ecf20Sopenharmony_ci			break;
59698c2ecf20Sopenharmony_ci		}
59708c2ecf20Sopenharmony_ci	}
59718c2ecf20Sopenharmony_ci
59728c2ecf20Sopenharmony_ci	return ret;
59738c2ecf20Sopenharmony_ci}
59748c2ecf20Sopenharmony_ci
59758c2ecf20Sopenharmony_cistatic int ocfs2_xattr_inline_attach_refcount(struct inode *inode,
59768c2ecf20Sopenharmony_ci				struct buffer_head *fe_bh,
59778c2ecf20Sopenharmony_ci				struct ocfs2_caching_info *ref_ci,
59788c2ecf20Sopenharmony_ci				struct buffer_head *ref_root_bh,
59798c2ecf20Sopenharmony_ci				struct ocfs2_cached_dealloc_ctxt *dealloc)
59808c2ecf20Sopenharmony_ci{
59818c2ecf20Sopenharmony_ci	struct ocfs2_dinode *di = (struct ocfs2_dinode *)fe_bh->b_data;
59828c2ecf20Sopenharmony_ci	struct ocfs2_xattr_header *header = (struct ocfs2_xattr_header *)
59838c2ecf20Sopenharmony_ci				(fe_bh->b_data + inode->i_sb->s_blocksize -
59848c2ecf20Sopenharmony_ci				le16_to_cpu(di->i_xattr_inline_size));
59858c2ecf20Sopenharmony_ci	struct ocfs2_xattr_value_buf vb = {
59868c2ecf20Sopenharmony_ci		.vb_bh = fe_bh,
59878c2ecf20Sopenharmony_ci		.vb_access = ocfs2_journal_access_di,
59888c2ecf20Sopenharmony_ci	};
59898c2ecf20Sopenharmony_ci
59908c2ecf20Sopenharmony_ci	return ocfs2_xattr_attach_refcount_normal(inode, &vb, header,
59918c2ecf20Sopenharmony_ci						  ref_ci, ref_root_bh, dealloc);
59928c2ecf20Sopenharmony_ci}
59938c2ecf20Sopenharmony_ci
59948c2ecf20Sopenharmony_cistruct ocfs2_xattr_tree_value_refcount_para {
59958c2ecf20Sopenharmony_ci	struct ocfs2_caching_info *ref_ci;
59968c2ecf20Sopenharmony_ci	struct buffer_head *ref_root_bh;
59978c2ecf20Sopenharmony_ci	struct ocfs2_cached_dealloc_ctxt *dealloc;
59988c2ecf20Sopenharmony_ci};
59998c2ecf20Sopenharmony_ci
60008c2ecf20Sopenharmony_cistatic int ocfs2_get_xattr_tree_value_root(struct super_block *sb,
60018c2ecf20Sopenharmony_ci					   struct ocfs2_xattr_bucket *bucket,
60028c2ecf20Sopenharmony_ci					   int offset,
60038c2ecf20Sopenharmony_ci					   struct ocfs2_xattr_value_root **xv,
60048c2ecf20Sopenharmony_ci					   struct buffer_head **bh)
60058c2ecf20Sopenharmony_ci{
60068c2ecf20Sopenharmony_ci	int ret, block_off, name_offset;
60078c2ecf20Sopenharmony_ci	struct ocfs2_xattr_header *xh = bucket_xh(bucket);
60088c2ecf20Sopenharmony_ci	struct ocfs2_xattr_entry *xe = &xh->xh_entries[offset];
60098c2ecf20Sopenharmony_ci	void *base;
60108c2ecf20Sopenharmony_ci
60118c2ecf20Sopenharmony_ci	ret = ocfs2_xattr_bucket_get_name_value(sb,
60128c2ecf20Sopenharmony_ci						bucket_xh(bucket),
60138c2ecf20Sopenharmony_ci						offset,
60148c2ecf20Sopenharmony_ci						&block_off,
60158c2ecf20Sopenharmony_ci						&name_offset);
60168c2ecf20Sopenharmony_ci	if (ret) {
60178c2ecf20Sopenharmony_ci		mlog_errno(ret);
60188c2ecf20Sopenharmony_ci		goto out;
60198c2ecf20Sopenharmony_ci	}
60208c2ecf20Sopenharmony_ci
60218c2ecf20Sopenharmony_ci	base = bucket_block(bucket, block_off);
60228c2ecf20Sopenharmony_ci
60238c2ecf20Sopenharmony_ci	*xv = (struct ocfs2_xattr_value_root *)(base + name_offset +
60248c2ecf20Sopenharmony_ci			 OCFS2_XATTR_SIZE(xe->xe_name_len));
60258c2ecf20Sopenharmony_ci
60268c2ecf20Sopenharmony_ci	if (bh)
60278c2ecf20Sopenharmony_ci		*bh = bucket->bu_bhs[block_off];
60288c2ecf20Sopenharmony_ciout:
60298c2ecf20Sopenharmony_ci	return ret;
60308c2ecf20Sopenharmony_ci}
60318c2ecf20Sopenharmony_ci
60328c2ecf20Sopenharmony_ci/*
60338c2ecf20Sopenharmony_ci * For a given xattr bucket, refcount all the entries which
60348c2ecf20Sopenharmony_ci * have value stored outside.
60358c2ecf20Sopenharmony_ci */
60368c2ecf20Sopenharmony_cistatic int ocfs2_xattr_bucket_value_refcount(struct inode *inode,
60378c2ecf20Sopenharmony_ci					     struct ocfs2_xattr_bucket *bucket,
60388c2ecf20Sopenharmony_ci					     void *para)
60398c2ecf20Sopenharmony_ci{
60408c2ecf20Sopenharmony_ci	int i, ret = 0;
60418c2ecf20Sopenharmony_ci	struct ocfs2_extent_tree et;
60428c2ecf20Sopenharmony_ci	struct ocfs2_xattr_tree_value_refcount_para *ref =
60438c2ecf20Sopenharmony_ci			(struct ocfs2_xattr_tree_value_refcount_para *)para;
60448c2ecf20Sopenharmony_ci	struct ocfs2_xattr_header *xh =
60458c2ecf20Sopenharmony_ci			(struct ocfs2_xattr_header *)bucket->bu_bhs[0]->b_data;
60468c2ecf20Sopenharmony_ci	struct ocfs2_xattr_entry *xe;
60478c2ecf20Sopenharmony_ci	struct ocfs2_xattr_value_buf vb = {
60488c2ecf20Sopenharmony_ci		.vb_access = ocfs2_journal_access,
60498c2ecf20Sopenharmony_ci	};
60508c2ecf20Sopenharmony_ci	struct ocfs2_post_refcount refcount = {
60518c2ecf20Sopenharmony_ci		.credits = bucket->bu_blocks,
60528c2ecf20Sopenharmony_ci		.para = bucket,
60538c2ecf20Sopenharmony_ci		.func = ocfs2_xattr_bucket_post_refcount,
60548c2ecf20Sopenharmony_ci	};
60558c2ecf20Sopenharmony_ci	struct ocfs2_post_refcount *p = NULL;
60568c2ecf20Sopenharmony_ci
60578c2ecf20Sopenharmony_ci	/* We only need post_refcount if we support metaecc. */
60588c2ecf20Sopenharmony_ci	if (ocfs2_meta_ecc(OCFS2_SB(inode->i_sb)))
60598c2ecf20Sopenharmony_ci		p = &refcount;
60608c2ecf20Sopenharmony_ci
60618c2ecf20Sopenharmony_ci	trace_ocfs2_xattr_bucket_value_refcount(
60628c2ecf20Sopenharmony_ci				(unsigned long long)bucket_blkno(bucket),
60638c2ecf20Sopenharmony_ci				le16_to_cpu(xh->xh_count));
60648c2ecf20Sopenharmony_ci	for (i = 0; i < le16_to_cpu(xh->xh_count); i++) {
60658c2ecf20Sopenharmony_ci		xe = &xh->xh_entries[i];
60668c2ecf20Sopenharmony_ci
60678c2ecf20Sopenharmony_ci		if (ocfs2_xattr_is_local(xe))
60688c2ecf20Sopenharmony_ci			continue;
60698c2ecf20Sopenharmony_ci
60708c2ecf20Sopenharmony_ci		ret = ocfs2_get_xattr_tree_value_root(inode->i_sb, bucket, i,
60718c2ecf20Sopenharmony_ci						      &vb.vb_xv, &vb.vb_bh);
60728c2ecf20Sopenharmony_ci		if (ret) {
60738c2ecf20Sopenharmony_ci			mlog_errno(ret);
60748c2ecf20Sopenharmony_ci			break;
60758c2ecf20Sopenharmony_ci		}
60768c2ecf20Sopenharmony_ci
60778c2ecf20Sopenharmony_ci		ocfs2_init_xattr_value_extent_tree(&et,
60788c2ecf20Sopenharmony_ci						   INODE_CACHE(inode), &vb);
60798c2ecf20Sopenharmony_ci
60808c2ecf20Sopenharmony_ci		ret = ocfs2_xattr_value_attach_refcount(inode, vb.vb_xv,
60818c2ecf20Sopenharmony_ci							&et, ref->ref_ci,
60828c2ecf20Sopenharmony_ci							ref->ref_root_bh,
60838c2ecf20Sopenharmony_ci							ref->dealloc, p);
60848c2ecf20Sopenharmony_ci		if (ret) {
60858c2ecf20Sopenharmony_ci			mlog_errno(ret);
60868c2ecf20Sopenharmony_ci			break;
60878c2ecf20Sopenharmony_ci		}
60888c2ecf20Sopenharmony_ci	}
60898c2ecf20Sopenharmony_ci
60908c2ecf20Sopenharmony_ci	return ret;
60918c2ecf20Sopenharmony_ci
60928c2ecf20Sopenharmony_ci}
60938c2ecf20Sopenharmony_ci
60948c2ecf20Sopenharmony_cistatic int ocfs2_refcount_xattr_tree_rec(struct inode *inode,
60958c2ecf20Sopenharmony_ci				     struct buffer_head *root_bh,
60968c2ecf20Sopenharmony_ci				     u64 blkno, u32 cpos, u32 len, void *para)
60978c2ecf20Sopenharmony_ci{
60988c2ecf20Sopenharmony_ci	return ocfs2_iterate_xattr_buckets(inode, blkno, len,
60998c2ecf20Sopenharmony_ci					   ocfs2_xattr_bucket_value_refcount,
61008c2ecf20Sopenharmony_ci					   para);
61018c2ecf20Sopenharmony_ci}
61028c2ecf20Sopenharmony_ci
61038c2ecf20Sopenharmony_cistatic int ocfs2_xattr_block_attach_refcount(struct inode *inode,
61048c2ecf20Sopenharmony_ci				struct buffer_head *blk_bh,
61058c2ecf20Sopenharmony_ci				struct ocfs2_caching_info *ref_ci,
61068c2ecf20Sopenharmony_ci				struct buffer_head *ref_root_bh,
61078c2ecf20Sopenharmony_ci				struct ocfs2_cached_dealloc_ctxt *dealloc)
61088c2ecf20Sopenharmony_ci{
61098c2ecf20Sopenharmony_ci	int ret = 0;
61108c2ecf20Sopenharmony_ci	struct ocfs2_xattr_block *xb =
61118c2ecf20Sopenharmony_ci				(struct ocfs2_xattr_block *)blk_bh->b_data;
61128c2ecf20Sopenharmony_ci
61138c2ecf20Sopenharmony_ci	if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) {
61148c2ecf20Sopenharmony_ci		struct ocfs2_xattr_header *header = &xb->xb_attrs.xb_header;
61158c2ecf20Sopenharmony_ci		struct ocfs2_xattr_value_buf vb = {
61168c2ecf20Sopenharmony_ci			.vb_bh = blk_bh,
61178c2ecf20Sopenharmony_ci			.vb_access = ocfs2_journal_access_xb,
61188c2ecf20Sopenharmony_ci		};
61198c2ecf20Sopenharmony_ci
61208c2ecf20Sopenharmony_ci		ret = ocfs2_xattr_attach_refcount_normal(inode, &vb, header,
61218c2ecf20Sopenharmony_ci							 ref_ci, ref_root_bh,
61228c2ecf20Sopenharmony_ci							 dealloc);
61238c2ecf20Sopenharmony_ci	} else {
61248c2ecf20Sopenharmony_ci		struct ocfs2_xattr_tree_value_refcount_para para = {
61258c2ecf20Sopenharmony_ci			.ref_ci = ref_ci,
61268c2ecf20Sopenharmony_ci			.ref_root_bh = ref_root_bh,
61278c2ecf20Sopenharmony_ci			.dealloc = dealloc,
61288c2ecf20Sopenharmony_ci		};
61298c2ecf20Sopenharmony_ci
61308c2ecf20Sopenharmony_ci		ret = ocfs2_iterate_xattr_index_block(inode, blk_bh,
61318c2ecf20Sopenharmony_ci						ocfs2_refcount_xattr_tree_rec,
61328c2ecf20Sopenharmony_ci						&para);
61338c2ecf20Sopenharmony_ci	}
61348c2ecf20Sopenharmony_ci
61358c2ecf20Sopenharmony_ci	return ret;
61368c2ecf20Sopenharmony_ci}
61378c2ecf20Sopenharmony_ci
61388c2ecf20Sopenharmony_ciint ocfs2_xattr_attach_refcount_tree(struct inode *inode,
61398c2ecf20Sopenharmony_ci				     struct buffer_head *fe_bh,
61408c2ecf20Sopenharmony_ci				     struct ocfs2_caching_info *ref_ci,
61418c2ecf20Sopenharmony_ci				     struct buffer_head *ref_root_bh,
61428c2ecf20Sopenharmony_ci				     struct ocfs2_cached_dealloc_ctxt *dealloc)
61438c2ecf20Sopenharmony_ci{
61448c2ecf20Sopenharmony_ci	int ret = 0;
61458c2ecf20Sopenharmony_ci	struct ocfs2_inode_info *oi = OCFS2_I(inode);
61468c2ecf20Sopenharmony_ci	struct ocfs2_dinode *di = (struct ocfs2_dinode *)fe_bh->b_data;
61478c2ecf20Sopenharmony_ci	struct buffer_head *blk_bh = NULL;
61488c2ecf20Sopenharmony_ci
61498c2ecf20Sopenharmony_ci	if (oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL) {
61508c2ecf20Sopenharmony_ci		ret = ocfs2_xattr_inline_attach_refcount(inode, fe_bh,
61518c2ecf20Sopenharmony_ci							 ref_ci, ref_root_bh,
61528c2ecf20Sopenharmony_ci							 dealloc);
61538c2ecf20Sopenharmony_ci		if (ret) {
61548c2ecf20Sopenharmony_ci			mlog_errno(ret);
61558c2ecf20Sopenharmony_ci			goto out;
61568c2ecf20Sopenharmony_ci		}
61578c2ecf20Sopenharmony_ci	}
61588c2ecf20Sopenharmony_ci
61598c2ecf20Sopenharmony_ci	if (!di->i_xattr_loc)
61608c2ecf20Sopenharmony_ci		goto out;
61618c2ecf20Sopenharmony_ci
61628c2ecf20Sopenharmony_ci	ret = ocfs2_read_xattr_block(inode, le64_to_cpu(di->i_xattr_loc),
61638c2ecf20Sopenharmony_ci				     &blk_bh);
61648c2ecf20Sopenharmony_ci	if (ret < 0) {
61658c2ecf20Sopenharmony_ci		mlog_errno(ret);
61668c2ecf20Sopenharmony_ci		goto out;
61678c2ecf20Sopenharmony_ci	}
61688c2ecf20Sopenharmony_ci
61698c2ecf20Sopenharmony_ci	ret = ocfs2_xattr_block_attach_refcount(inode, blk_bh, ref_ci,
61708c2ecf20Sopenharmony_ci						ref_root_bh, dealloc);
61718c2ecf20Sopenharmony_ci	if (ret)
61728c2ecf20Sopenharmony_ci		mlog_errno(ret);
61738c2ecf20Sopenharmony_ci
61748c2ecf20Sopenharmony_ci	brelse(blk_bh);
61758c2ecf20Sopenharmony_ciout:
61768c2ecf20Sopenharmony_ci
61778c2ecf20Sopenharmony_ci	return ret;
61788c2ecf20Sopenharmony_ci}
61798c2ecf20Sopenharmony_ci
61808c2ecf20Sopenharmony_citypedef int (should_xattr_reflinked)(struct ocfs2_xattr_entry *xe);
61818c2ecf20Sopenharmony_ci/*
61828c2ecf20Sopenharmony_ci * Store the information we need in xattr reflink.
61838c2ecf20Sopenharmony_ci * old_bh and new_bh are inode bh for the old and new inode.
61848c2ecf20Sopenharmony_ci */
61858c2ecf20Sopenharmony_cistruct ocfs2_xattr_reflink {
61868c2ecf20Sopenharmony_ci	struct inode *old_inode;
61878c2ecf20Sopenharmony_ci	struct inode *new_inode;
61888c2ecf20Sopenharmony_ci	struct buffer_head *old_bh;
61898c2ecf20Sopenharmony_ci	struct buffer_head *new_bh;
61908c2ecf20Sopenharmony_ci	struct ocfs2_caching_info *ref_ci;
61918c2ecf20Sopenharmony_ci	struct buffer_head *ref_root_bh;
61928c2ecf20Sopenharmony_ci	struct ocfs2_cached_dealloc_ctxt *dealloc;
61938c2ecf20Sopenharmony_ci	should_xattr_reflinked *xattr_reflinked;
61948c2ecf20Sopenharmony_ci};
61958c2ecf20Sopenharmony_ci
61968c2ecf20Sopenharmony_ci/*
61978c2ecf20Sopenharmony_ci * Given a xattr header and xe offset,
61988c2ecf20Sopenharmony_ci * return the proper xv and the corresponding bh.
61998c2ecf20Sopenharmony_ci * xattr in inode, block and xattr tree have different implementaions.
62008c2ecf20Sopenharmony_ci */
62018c2ecf20Sopenharmony_citypedef int (get_xattr_value_root)(struct super_block *sb,
62028c2ecf20Sopenharmony_ci				   struct buffer_head *bh,
62038c2ecf20Sopenharmony_ci				   struct ocfs2_xattr_header *xh,
62048c2ecf20Sopenharmony_ci				   int offset,
62058c2ecf20Sopenharmony_ci				   struct ocfs2_xattr_value_root **xv,
62068c2ecf20Sopenharmony_ci				   struct buffer_head **ret_bh,
62078c2ecf20Sopenharmony_ci				   void *para);
62088c2ecf20Sopenharmony_ci
62098c2ecf20Sopenharmony_ci/*
62108c2ecf20Sopenharmony_ci * Calculate all the xattr value root metadata stored in this xattr header and
62118c2ecf20Sopenharmony_ci * credits we need if we create them from the scratch.
62128c2ecf20Sopenharmony_ci * We use get_xattr_value_root so that all types of xattr container can use it.
62138c2ecf20Sopenharmony_ci */
62148c2ecf20Sopenharmony_cistatic int ocfs2_value_metas_in_xattr_header(struct super_block *sb,
62158c2ecf20Sopenharmony_ci					     struct buffer_head *bh,
62168c2ecf20Sopenharmony_ci					     struct ocfs2_xattr_header *xh,
62178c2ecf20Sopenharmony_ci					     int *metas, int *credits,
62188c2ecf20Sopenharmony_ci					     int *num_recs,
62198c2ecf20Sopenharmony_ci					     get_xattr_value_root *func,
62208c2ecf20Sopenharmony_ci					     void *para)
62218c2ecf20Sopenharmony_ci{
62228c2ecf20Sopenharmony_ci	int i, ret = 0;
62238c2ecf20Sopenharmony_ci	struct ocfs2_xattr_value_root *xv;
62248c2ecf20Sopenharmony_ci	struct ocfs2_xattr_entry *xe;
62258c2ecf20Sopenharmony_ci
62268c2ecf20Sopenharmony_ci	for (i = 0; i < le16_to_cpu(xh->xh_count); i++) {
62278c2ecf20Sopenharmony_ci		xe = &xh->xh_entries[i];
62288c2ecf20Sopenharmony_ci		if (ocfs2_xattr_is_local(xe))
62298c2ecf20Sopenharmony_ci			continue;
62308c2ecf20Sopenharmony_ci
62318c2ecf20Sopenharmony_ci		ret = func(sb, bh, xh, i, &xv, NULL, para);
62328c2ecf20Sopenharmony_ci		if (ret) {
62338c2ecf20Sopenharmony_ci			mlog_errno(ret);
62348c2ecf20Sopenharmony_ci			break;
62358c2ecf20Sopenharmony_ci		}
62368c2ecf20Sopenharmony_ci
62378c2ecf20Sopenharmony_ci		*metas += le16_to_cpu(xv->xr_list.l_tree_depth) *
62388c2ecf20Sopenharmony_ci			  le16_to_cpu(xv->xr_list.l_next_free_rec);
62398c2ecf20Sopenharmony_ci
62408c2ecf20Sopenharmony_ci		*credits += ocfs2_calc_extend_credits(sb,
62418c2ecf20Sopenharmony_ci						&def_xv.xv.xr_list);
62428c2ecf20Sopenharmony_ci
62438c2ecf20Sopenharmony_ci		/*
62448c2ecf20Sopenharmony_ci		 * If the value is a tree with depth > 1, We don't go deep
62458c2ecf20Sopenharmony_ci		 * to the extent block, so just calculate a maximum record num.
62468c2ecf20Sopenharmony_ci		 */
62478c2ecf20Sopenharmony_ci		if (!xv->xr_list.l_tree_depth)
62488c2ecf20Sopenharmony_ci			*num_recs += le16_to_cpu(xv->xr_list.l_next_free_rec);
62498c2ecf20Sopenharmony_ci		else
62508c2ecf20Sopenharmony_ci			*num_recs += ocfs2_clusters_for_bytes(sb,
62518c2ecf20Sopenharmony_ci							      XATTR_SIZE_MAX);
62528c2ecf20Sopenharmony_ci	}
62538c2ecf20Sopenharmony_ci
62548c2ecf20Sopenharmony_ci	return ret;
62558c2ecf20Sopenharmony_ci}
62568c2ecf20Sopenharmony_ci
62578c2ecf20Sopenharmony_ci/* Used by xattr inode and block to return the right xv and buffer_head. */
62588c2ecf20Sopenharmony_cistatic int ocfs2_get_xattr_value_root(struct super_block *sb,
62598c2ecf20Sopenharmony_ci				      struct buffer_head *bh,
62608c2ecf20Sopenharmony_ci				      struct ocfs2_xattr_header *xh,
62618c2ecf20Sopenharmony_ci				      int offset,
62628c2ecf20Sopenharmony_ci				      struct ocfs2_xattr_value_root **xv,
62638c2ecf20Sopenharmony_ci				      struct buffer_head **ret_bh,
62648c2ecf20Sopenharmony_ci				      void *para)
62658c2ecf20Sopenharmony_ci{
62668c2ecf20Sopenharmony_ci	struct ocfs2_xattr_entry *xe = &xh->xh_entries[offset];
62678c2ecf20Sopenharmony_ci
62688c2ecf20Sopenharmony_ci	*xv = (struct ocfs2_xattr_value_root *)((void *)xh +
62698c2ecf20Sopenharmony_ci		le16_to_cpu(xe->xe_name_offset) +
62708c2ecf20Sopenharmony_ci		OCFS2_XATTR_SIZE(xe->xe_name_len));
62718c2ecf20Sopenharmony_ci
62728c2ecf20Sopenharmony_ci	if (ret_bh)
62738c2ecf20Sopenharmony_ci		*ret_bh = bh;
62748c2ecf20Sopenharmony_ci
62758c2ecf20Sopenharmony_ci	return 0;
62768c2ecf20Sopenharmony_ci}
62778c2ecf20Sopenharmony_ci
62788c2ecf20Sopenharmony_ci/*
62798c2ecf20Sopenharmony_ci * Lock the meta_ac and caculate how much credits we need for reflink xattrs.
62808c2ecf20Sopenharmony_ci * It is only used for inline xattr and xattr block.
62818c2ecf20Sopenharmony_ci */
62828c2ecf20Sopenharmony_cistatic int ocfs2_reflink_lock_xattr_allocators(struct ocfs2_super *osb,
62838c2ecf20Sopenharmony_ci					struct ocfs2_xattr_header *xh,
62848c2ecf20Sopenharmony_ci					struct buffer_head *ref_root_bh,
62858c2ecf20Sopenharmony_ci					int *credits,
62868c2ecf20Sopenharmony_ci					struct ocfs2_alloc_context **meta_ac)
62878c2ecf20Sopenharmony_ci{
62888c2ecf20Sopenharmony_ci	int ret, meta_add = 0, num_recs = 0;
62898c2ecf20Sopenharmony_ci	struct ocfs2_refcount_block *rb =
62908c2ecf20Sopenharmony_ci			(struct ocfs2_refcount_block *)ref_root_bh->b_data;
62918c2ecf20Sopenharmony_ci
62928c2ecf20Sopenharmony_ci	*credits = 0;
62938c2ecf20Sopenharmony_ci
62948c2ecf20Sopenharmony_ci	ret = ocfs2_value_metas_in_xattr_header(osb->sb, NULL, xh,
62958c2ecf20Sopenharmony_ci						&meta_add, credits, &num_recs,
62968c2ecf20Sopenharmony_ci						ocfs2_get_xattr_value_root,
62978c2ecf20Sopenharmony_ci						NULL);
62988c2ecf20Sopenharmony_ci	if (ret) {
62998c2ecf20Sopenharmony_ci		mlog_errno(ret);
63008c2ecf20Sopenharmony_ci		goto out;
63018c2ecf20Sopenharmony_ci	}
63028c2ecf20Sopenharmony_ci
63038c2ecf20Sopenharmony_ci	/*
63048c2ecf20Sopenharmony_ci	 * We need to add/modify num_recs in refcount tree, so just calculate
63058c2ecf20Sopenharmony_ci	 * an approximate number we need for refcount tree change.
63068c2ecf20Sopenharmony_ci	 * Sometimes we need to split the tree, and after split,  half recs
63078c2ecf20Sopenharmony_ci	 * will be moved to the new block, and a new block can only provide
63088c2ecf20Sopenharmony_ci	 * half number of recs. So we multiple new blocks by 2.
63098c2ecf20Sopenharmony_ci	 */
63108c2ecf20Sopenharmony_ci	num_recs = num_recs / ocfs2_refcount_recs_per_rb(osb->sb) * 2;
63118c2ecf20Sopenharmony_ci	meta_add += num_recs;
63128c2ecf20Sopenharmony_ci	*credits += num_recs + num_recs * OCFS2_EXPAND_REFCOUNT_TREE_CREDITS;
63138c2ecf20Sopenharmony_ci	if (le32_to_cpu(rb->rf_flags) & OCFS2_REFCOUNT_TREE_FL)
63148c2ecf20Sopenharmony_ci		*credits += le16_to_cpu(rb->rf_list.l_tree_depth) *
63158c2ecf20Sopenharmony_ci			    le16_to_cpu(rb->rf_list.l_next_free_rec) + 1;
63168c2ecf20Sopenharmony_ci	else
63178c2ecf20Sopenharmony_ci		*credits += 1;
63188c2ecf20Sopenharmony_ci
63198c2ecf20Sopenharmony_ci	ret = ocfs2_reserve_new_metadata_blocks(osb, meta_add, meta_ac);
63208c2ecf20Sopenharmony_ci	if (ret)
63218c2ecf20Sopenharmony_ci		mlog_errno(ret);
63228c2ecf20Sopenharmony_ci
63238c2ecf20Sopenharmony_ciout:
63248c2ecf20Sopenharmony_ci	return ret;
63258c2ecf20Sopenharmony_ci}
63268c2ecf20Sopenharmony_ci
63278c2ecf20Sopenharmony_ci/*
63288c2ecf20Sopenharmony_ci * Given a xattr header, reflink all the xattrs in this container.
63298c2ecf20Sopenharmony_ci * It can be used for inode, block and bucket.
63308c2ecf20Sopenharmony_ci *
63318c2ecf20Sopenharmony_ci * NOTE:
63328c2ecf20Sopenharmony_ci * Before we call this function, the caller has memcpy the xattr in
63338c2ecf20Sopenharmony_ci * old_xh to the new_xh.
63348c2ecf20Sopenharmony_ci *
63358c2ecf20Sopenharmony_ci * If args.xattr_reflinked is set, call it to decide whether the xe should
63368c2ecf20Sopenharmony_ci * be reflinked or not. If not, remove it from the new xattr header.
63378c2ecf20Sopenharmony_ci */
63388c2ecf20Sopenharmony_cistatic int ocfs2_reflink_xattr_header(handle_t *handle,
63398c2ecf20Sopenharmony_ci				      struct ocfs2_xattr_reflink *args,
63408c2ecf20Sopenharmony_ci				      struct buffer_head *old_bh,
63418c2ecf20Sopenharmony_ci				      struct ocfs2_xattr_header *xh,
63428c2ecf20Sopenharmony_ci				      struct buffer_head *new_bh,
63438c2ecf20Sopenharmony_ci				      struct ocfs2_xattr_header *new_xh,
63448c2ecf20Sopenharmony_ci				      struct ocfs2_xattr_value_buf *vb,
63458c2ecf20Sopenharmony_ci				      struct ocfs2_alloc_context *meta_ac,
63468c2ecf20Sopenharmony_ci				      get_xattr_value_root *func,
63478c2ecf20Sopenharmony_ci				      void *para)
63488c2ecf20Sopenharmony_ci{
63498c2ecf20Sopenharmony_ci	int ret = 0, i, j;
63508c2ecf20Sopenharmony_ci	struct super_block *sb = args->old_inode->i_sb;
63518c2ecf20Sopenharmony_ci	struct buffer_head *value_bh;
63528c2ecf20Sopenharmony_ci	struct ocfs2_xattr_entry *xe, *last;
63538c2ecf20Sopenharmony_ci	struct ocfs2_xattr_value_root *xv, *new_xv;
63548c2ecf20Sopenharmony_ci	struct ocfs2_extent_tree data_et;
63558c2ecf20Sopenharmony_ci	u32 clusters, cpos, p_cluster, num_clusters;
63568c2ecf20Sopenharmony_ci	unsigned int ext_flags = 0;
63578c2ecf20Sopenharmony_ci
63588c2ecf20Sopenharmony_ci	trace_ocfs2_reflink_xattr_header((unsigned long long)old_bh->b_blocknr,
63598c2ecf20Sopenharmony_ci					 le16_to_cpu(xh->xh_count));
63608c2ecf20Sopenharmony_ci
63618c2ecf20Sopenharmony_ci	last = &new_xh->xh_entries[le16_to_cpu(new_xh->xh_count)];
63628c2ecf20Sopenharmony_ci	for (i = 0, j = 0; i < le16_to_cpu(xh->xh_count); i++, j++) {
63638c2ecf20Sopenharmony_ci		xe = &xh->xh_entries[i];
63648c2ecf20Sopenharmony_ci
63658c2ecf20Sopenharmony_ci		if (args->xattr_reflinked && !args->xattr_reflinked(xe)) {
63668c2ecf20Sopenharmony_ci			xe = &new_xh->xh_entries[j];
63678c2ecf20Sopenharmony_ci
63688c2ecf20Sopenharmony_ci			le16_add_cpu(&new_xh->xh_count, -1);
63698c2ecf20Sopenharmony_ci			if (new_xh->xh_count) {
63708c2ecf20Sopenharmony_ci				memmove(xe, xe + 1,
63718c2ecf20Sopenharmony_ci					(void *)last - (void *)xe);
63728c2ecf20Sopenharmony_ci				memset(last, 0,
63738c2ecf20Sopenharmony_ci				       sizeof(struct ocfs2_xattr_entry));
63748c2ecf20Sopenharmony_ci			}
63758c2ecf20Sopenharmony_ci
63768c2ecf20Sopenharmony_ci			/*
63778c2ecf20Sopenharmony_ci			 * We don't want j to increase in the next round since
63788c2ecf20Sopenharmony_ci			 * it is already moved ahead.
63798c2ecf20Sopenharmony_ci			 */
63808c2ecf20Sopenharmony_ci			j--;
63818c2ecf20Sopenharmony_ci			continue;
63828c2ecf20Sopenharmony_ci		}
63838c2ecf20Sopenharmony_ci
63848c2ecf20Sopenharmony_ci		if (ocfs2_xattr_is_local(xe))
63858c2ecf20Sopenharmony_ci			continue;
63868c2ecf20Sopenharmony_ci
63878c2ecf20Sopenharmony_ci		ret = func(sb, old_bh, xh, i, &xv, NULL, para);
63888c2ecf20Sopenharmony_ci		if (ret) {
63898c2ecf20Sopenharmony_ci			mlog_errno(ret);
63908c2ecf20Sopenharmony_ci			break;
63918c2ecf20Sopenharmony_ci		}
63928c2ecf20Sopenharmony_ci
63938c2ecf20Sopenharmony_ci		ret = func(sb, new_bh, new_xh, j, &new_xv, &value_bh, para);
63948c2ecf20Sopenharmony_ci		if (ret) {
63958c2ecf20Sopenharmony_ci			mlog_errno(ret);
63968c2ecf20Sopenharmony_ci			break;
63978c2ecf20Sopenharmony_ci		}
63988c2ecf20Sopenharmony_ci
63998c2ecf20Sopenharmony_ci		/*
64008c2ecf20Sopenharmony_ci		 * For the xattr which has l_tree_depth = 0, all the extent
64018c2ecf20Sopenharmony_ci		 * recs have already be copied to the new xh with the
64028c2ecf20Sopenharmony_ci		 * propriate OCFS2_EXT_REFCOUNTED flag we just need to
64038c2ecf20Sopenharmony_ci		 * increase the refount count int the refcount tree.
64048c2ecf20Sopenharmony_ci		 *
64058c2ecf20Sopenharmony_ci		 * For the xattr which has l_tree_depth > 0, we need
64068c2ecf20Sopenharmony_ci		 * to initialize it to the empty default value root,
64078c2ecf20Sopenharmony_ci		 * and then insert the extents one by one.
64088c2ecf20Sopenharmony_ci		 */
64098c2ecf20Sopenharmony_ci		if (xv->xr_list.l_tree_depth) {
64108c2ecf20Sopenharmony_ci			memcpy(new_xv, &def_xv, OCFS2_XATTR_ROOT_SIZE);
64118c2ecf20Sopenharmony_ci			vb->vb_xv = new_xv;
64128c2ecf20Sopenharmony_ci			vb->vb_bh = value_bh;
64138c2ecf20Sopenharmony_ci			ocfs2_init_xattr_value_extent_tree(&data_et,
64148c2ecf20Sopenharmony_ci					INODE_CACHE(args->new_inode), vb);
64158c2ecf20Sopenharmony_ci		}
64168c2ecf20Sopenharmony_ci
64178c2ecf20Sopenharmony_ci		clusters = le32_to_cpu(xv->xr_clusters);
64188c2ecf20Sopenharmony_ci		cpos = 0;
64198c2ecf20Sopenharmony_ci		while (cpos < clusters) {
64208c2ecf20Sopenharmony_ci			ret = ocfs2_xattr_get_clusters(args->old_inode,
64218c2ecf20Sopenharmony_ci						       cpos,
64228c2ecf20Sopenharmony_ci						       &p_cluster,
64238c2ecf20Sopenharmony_ci						       &num_clusters,
64248c2ecf20Sopenharmony_ci						       &xv->xr_list,
64258c2ecf20Sopenharmony_ci						       &ext_flags);
64268c2ecf20Sopenharmony_ci			if (ret) {
64278c2ecf20Sopenharmony_ci				mlog_errno(ret);
64288c2ecf20Sopenharmony_ci				goto out;
64298c2ecf20Sopenharmony_ci			}
64308c2ecf20Sopenharmony_ci
64318c2ecf20Sopenharmony_ci			BUG_ON(!p_cluster);
64328c2ecf20Sopenharmony_ci
64338c2ecf20Sopenharmony_ci			if (xv->xr_list.l_tree_depth) {
64348c2ecf20Sopenharmony_ci				ret = ocfs2_insert_extent(handle,
64358c2ecf20Sopenharmony_ci						&data_et, cpos,
64368c2ecf20Sopenharmony_ci						ocfs2_clusters_to_blocks(
64378c2ecf20Sopenharmony_ci							args->old_inode->i_sb,
64388c2ecf20Sopenharmony_ci							p_cluster),
64398c2ecf20Sopenharmony_ci						num_clusters, ext_flags,
64408c2ecf20Sopenharmony_ci						meta_ac);
64418c2ecf20Sopenharmony_ci				if (ret) {
64428c2ecf20Sopenharmony_ci					mlog_errno(ret);
64438c2ecf20Sopenharmony_ci					goto out;
64448c2ecf20Sopenharmony_ci				}
64458c2ecf20Sopenharmony_ci			}
64468c2ecf20Sopenharmony_ci
64478c2ecf20Sopenharmony_ci			ret = ocfs2_increase_refcount(handle, args->ref_ci,
64488c2ecf20Sopenharmony_ci						      args->ref_root_bh,
64498c2ecf20Sopenharmony_ci						      p_cluster, num_clusters,
64508c2ecf20Sopenharmony_ci						      meta_ac, args->dealloc);
64518c2ecf20Sopenharmony_ci			if (ret) {
64528c2ecf20Sopenharmony_ci				mlog_errno(ret);
64538c2ecf20Sopenharmony_ci				goto out;
64548c2ecf20Sopenharmony_ci			}
64558c2ecf20Sopenharmony_ci
64568c2ecf20Sopenharmony_ci			cpos += num_clusters;
64578c2ecf20Sopenharmony_ci		}
64588c2ecf20Sopenharmony_ci	}
64598c2ecf20Sopenharmony_ci
64608c2ecf20Sopenharmony_ciout:
64618c2ecf20Sopenharmony_ci	return ret;
64628c2ecf20Sopenharmony_ci}
64638c2ecf20Sopenharmony_ci
64648c2ecf20Sopenharmony_cistatic int ocfs2_reflink_xattr_inline(struct ocfs2_xattr_reflink *args)
64658c2ecf20Sopenharmony_ci{
64668c2ecf20Sopenharmony_ci	int ret = 0, credits = 0;
64678c2ecf20Sopenharmony_ci	handle_t *handle;
64688c2ecf20Sopenharmony_ci	struct ocfs2_super *osb = OCFS2_SB(args->old_inode->i_sb);
64698c2ecf20Sopenharmony_ci	struct ocfs2_dinode *di = (struct ocfs2_dinode *)args->old_bh->b_data;
64708c2ecf20Sopenharmony_ci	int inline_size = le16_to_cpu(di->i_xattr_inline_size);
64718c2ecf20Sopenharmony_ci	int header_off = osb->sb->s_blocksize - inline_size;
64728c2ecf20Sopenharmony_ci	struct ocfs2_xattr_header *xh = (struct ocfs2_xattr_header *)
64738c2ecf20Sopenharmony_ci					(args->old_bh->b_data + header_off);
64748c2ecf20Sopenharmony_ci	struct ocfs2_xattr_header *new_xh = (struct ocfs2_xattr_header *)
64758c2ecf20Sopenharmony_ci					(args->new_bh->b_data + header_off);
64768c2ecf20Sopenharmony_ci	struct ocfs2_alloc_context *meta_ac = NULL;
64778c2ecf20Sopenharmony_ci	struct ocfs2_inode_info *new_oi;
64788c2ecf20Sopenharmony_ci	struct ocfs2_dinode *new_di;
64798c2ecf20Sopenharmony_ci	struct ocfs2_xattr_value_buf vb = {
64808c2ecf20Sopenharmony_ci		.vb_bh = args->new_bh,
64818c2ecf20Sopenharmony_ci		.vb_access = ocfs2_journal_access_di,
64828c2ecf20Sopenharmony_ci	};
64838c2ecf20Sopenharmony_ci
64848c2ecf20Sopenharmony_ci	ret = ocfs2_reflink_lock_xattr_allocators(osb, xh, args->ref_root_bh,
64858c2ecf20Sopenharmony_ci						  &credits, &meta_ac);
64868c2ecf20Sopenharmony_ci	if (ret) {
64878c2ecf20Sopenharmony_ci		mlog_errno(ret);
64888c2ecf20Sopenharmony_ci		goto out;
64898c2ecf20Sopenharmony_ci	}
64908c2ecf20Sopenharmony_ci
64918c2ecf20Sopenharmony_ci	handle = ocfs2_start_trans(osb, credits);
64928c2ecf20Sopenharmony_ci	if (IS_ERR(handle)) {
64938c2ecf20Sopenharmony_ci		ret = PTR_ERR(handle);
64948c2ecf20Sopenharmony_ci		mlog_errno(ret);
64958c2ecf20Sopenharmony_ci		goto out;
64968c2ecf20Sopenharmony_ci	}
64978c2ecf20Sopenharmony_ci
64988c2ecf20Sopenharmony_ci	ret = ocfs2_journal_access_di(handle, INODE_CACHE(args->new_inode),
64998c2ecf20Sopenharmony_ci				      args->new_bh, OCFS2_JOURNAL_ACCESS_WRITE);
65008c2ecf20Sopenharmony_ci	if (ret) {
65018c2ecf20Sopenharmony_ci		mlog_errno(ret);
65028c2ecf20Sopenharmony_ci		goto out_commit;
65038c2ecf20Sopenharmony_ci	}
65048c2ecf20Sopenharmony_ci
65058c2ecf20Sopenharmony_ci	memcpy(args->new_bh->b_data + header_off,
65068c2ecf20Sopenharmony_ci	       args->old_bh->b_data + header_off, inline_size);
65078c2ecf20Sopenharmony_ci
65088c2ecf20Sopenharmony_ci	new_di = (struct ocfs2_dinode *)args->new_bh->b_data;
65098c2ecf20Sopenharmony_ci	new_di->i_xattr_inline_size = cpu_to_le16(inline_size);
65108c2ecf20Sopenharmony_ci
65118c2ecf20Sopenharmony_ci	ret = ocfs2_reflink_xattr_header(handle, args, args->old_bh, xh,
65128c2ecf20Sopenharmony_ci					 args->new_bh, new_xh, &vb, meta_ac,
65138c2ecf20Sopenharmony_ci					 ocfs2_get_xattr_value_root, NULL);
65148c2ecf20Sopenharmony_ci	if (ret) {
65158c2ecf20Sopenharmony_ci		mlog_errno(ret);
65168c2ecf20Sopenharmony_ci		goto out_commit;
65178c2ecf20Sopenharmony_ci	}
65188c2ecf20Sopenharmony_ci
65198c2ecf20Sopenharmony_ci	new_oi = OCFS2_I(args->new_inode);
65208c2ecf20Sopenharmony_ci	/*
65218c2ecf20Sopenharmony_ci	 * Adjust extent record count to reserve space for extended attribute.
65228c2ecf20Sopenharmony_ci	 * Inline data count had been adjusted in ocfs2_duplicate_inline_data().
65238c2ecf20Sopenharmony_ci	 */
65248c2ecf20Sopenharmony_ci	if (!(new_oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) &&
65258c2ecf20Sopenharmony_ci	    !(ocfs2_inode_is_fast_symlink(args->new_inode))) {
65268c2ecf20Sopenharmony_ci		struct ocfs2_extent_list *el = &new_di->id2.i_list;
65278c2ecf20Sopenharmony_ci		le16_add_cpu(&el->l_count, -(inline_size /
65288c2ecf20Sopenharmony_ci					sizeof(struct ocfs2_extent_rec)));
65298c2ecf20Sopenharmony_ci	}
65308c2ecf20Sopenharmony_ci	spin_lock(&new_oi->ip_lock);
65318c2ecf20Sopenharmony_ci	new_oi->ip_dyn_features |= OCFS2_HAS_XATTR_FL | OCFS2_INLINE_XATTR_FL;
65328c2ecf20Sopenharmony_ci	new_di->i_dyn_features = cpu_to_le16(new_oi->ip_dyn_features);
65338c2ecf20Sopenharmony_ci	spin_unlock(&new_oi->ip_lock);
65348c2ecf20Sopenharmony_ci
65358c2ecf20Sopenharmony_ci	ocfs2_journal_dirty(handle, args->new_bh);
65368c2ecf20Sopenharmony_ci
65378c2ecf20Sopenharmony_ciout_commit:
65388c2ecf20Sopenharmony_ci	ocfs2_commit_trans(osb, handle);
65398c2ecf20Sopenharmony_ci
65408c2ecf20Sopenharmony_ciout:
65418c2ecf20Sopenharmony_ci	if (meta_ac)
65428c2ecf20Sopenharmony_ci		ocfs2_free_alloc_context(meta_ac);
65438c2ecf20Sopenharmony_ci	return ret;
65448c2ecf20Sopenharmony_ci}
65458c2ecf20Sopenharmony_ci
65468c2ecf20Sopenharmony_cistatic int ocfs2_create_empty_xattr_block(struct inode *inode,
65478c2ecf20Sopenharmony_ci					  struct buffer_head *fe_bh,
65488c2ecf20Sopenharmony_ci					  struct buffer_head **ret_bh,
65498c2ecf20Sopenharmony_ci					  int indexed)
65508c2ecf20Sopenharmony_ci{
65518c2ecf20Sopenharmony_ci	int ret;
65528c2ecf20Sopenharmony_ci	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
65538c2ecf20Sopenharmony_ci	struct ocfs2_xattr_set_ctxt ctxt;
65548c2ecf20Sopenharmony_ci
65558c2ecf20Sopenharmony_ci	memset(&ctxt, 0, sizeof(ctxt));
65568c2ecf20Sopenharmony_ci	ret = ocfs2_reserve_new_metadata_blocks(osb, 1, &ctxt.meta_ac);
65578c2ecf20Sopenharmony_ci	if (ret < 0) {
65588c2ecf20Sopenharmony_ci		mlog_errno(ret);
65598c2ecf20Sopenharmony_ci		return ret;
65608c2ecf20Sopenharmony_ci	}
65618c2ecf20Sopenharmony_ci
65628c2ecf20Sopenharmony_ci	ctxt.handle = ocfs2_start_trans(osb, OCFS2_XATTR_BLOCK_CREATE_CREDITS);
65638c2ecf20Sopenharmony_ci	if (IS_ERR(ctxt.handle)) {
65648c2ecf20Sopenharmony_ci		ret = PTR_ERR(ctxt.handle);
65658c2ecf20Sopenharmony_ci		mlog_errno(ret);
65668c2ecf20Sopenharmony_ci		goto out;
65678c2ecf20Sopenharmony_ci	}
65688c2ecf20Sopenharmony_ci
65698c2ecf20Sopenharmony_ci	trace_ocfs2_create_empty_xattr_block(
65708c2ecf20Sopenharmony_ci				(unsigned long long)fe_bh->b_blocknr, indexed);
65718c2ecf20Sopenharmony_ci	ret = ocfs2_create_xattr_block(inode, fe_bh, &ctxt, indexed,
65728c2ecf20Sopenharmony_ci				       ret_bh);
65738c2ecf20Sopenharmony_ci	if (ret)
65748c2ecf20Sopenharmony_ci		mlog_errno(ret);
65758c2ecf20Sopenharmony_ci
65768c2ecf20Sopenharmony_ci	ocfs2_commit_trans(osb, ctxt.handle);
65778c2ecf20Sopenharmony_ciout:
65788c2ecf20Sopenharmony_ci	ocfs2_free_alloc_context(ctxt.meta_ac);
65798c2ecf20Sopenharmony_ci	return ret;
65808c2ecf20Sopenharmony_ci}
65818c2ecf20Sopenharmony_ci
65828c2ecf20Sopenharmony_cistatic int ocfs2_reflink_xattr_block(struct ocfs2_xattr_reflink *args,
65838c2ecf20Sopenharmony_ci				     struct buffer_head *blk_bh,
65848c2ecf20Sopenharmony_ci				     struct buffer_head *new_blk_bh)
65858c2ecf20Sopenharmony_ci{
65868c2ecf20Sopenharmony_ci	int ret = 0, credits = 0;
65878c2ecf20Sopenharmony_ci	handle_t *handle;
65888c2ecf20Sopenharmony_ci	struct ocfs2_inode_info *new_oi = OCFS2_I(args->new_inode);
65898c2ecf20Sopenharmony_ci	struct ocfs2_dinode *new_di;
65908c2ecf20Sopenharmony_ci	struct ocfs2_super *osb = OCFS2_SB(args->new_inode->i_sb);
65918c2ecf20Sopenharmony_ci	int header_off = offsetof(struct ocfs2_xattr_block, xb_attrs.xb_header);
65928c2ecf20Sopenharmony_ci	struct ocfs2_xattr_block *xb =
65938c2ecf20Sopenharmony_ci			(struct ocfs2_xattr_block *)blk_bh->b_data;
65948c2ecf20Sopenharmony_ci	struct ocfs2_xattr_header *xh = &xb->xb_attrs.xb_header;
65958c2ecf20Sopenharmony_ci	struct ocfs2_xattr_block *new_xb =
65968c2ecf20Sopenharmony_ci			(struct ocfs2_xattr_block *)new_blk_bh->b_data;
65978c2ecf20Sopenharmony_ci	struct ocfs2_xattr_header *new_xh = &new_xb->xb_attrs.xb_header;
65988c2ecf20Sopenharmony_ci	struct ocfs2_alloc_context *meta_ac;
65998c2ecf20Sopenharmony_ci	struct ocfs2_xattr_value_buf vb = {
66008c2ecf20Sopenharmony_ci		.vb_bh = new_blk_bh,
66018c2ecf20Sopenharmony_ci		.vb_access = ocfs2_journal_access_xb,
66028c2ecf20Sopenharmony_ci	};
66038c2ecf20Sopenharmony_ci
66048c2ecf20Sopenharmony_ci	ret = ocfs2_reflink_lock_xattr_allocators(osb, xh, args->ref_root_bh,
66058c2ecf20Sopenharmony_ci						  &credits, &meta_ac);
66068c2ecf20Sopenharmony_ci	if (ret) {
66078c2ecf20Sopenharmony_ci		mlog_errno(ret);
66088c2ecf20Sopenharmony_ci		return ret;
66098c2ecf20Sopenharmony_ci	}
66108c2ecf20Sopenharmony_ci
66118c2ecf20Sopenharmony_ci	/* One more credits in case we need to add xattr flags in new inode. */
66128c2ecf20Sopenharmony_ci	handle = ocfs2_start_trans(osb, credits + 1);
66138c2ecf20Sopenharmony_ci	if (IS_ERR(handle)) {
66148c2ecf20Sopenharmony_ci		ret = PTR_ERR(handle);
66158c2ecf20Sopenharmony_ci		mlog_errno(ret);
66168c2ecf20Sopenharmony_ci		goto out;
66178c2ecf20Sopenharmony_ci	}
66188c2ecf20Sopenharmony_ci
66198c2ecf20Sopenharmony_ci	if (!(new_oi->ip_dyn_features & OCFS2_HAS_XATTR_FL)) {
66208c2ecf20Sopenharmony_ci		ret = ocfs2_journal_access_di(handle,
66218c2ecf20Sopenharmony_ci					      INODE_CACHE(args->new_inode),
66228c2ecf20Sopenharmony_ci					      args->new_bh,
66238c2ecf20Sopenharmony_ci					      OCFS2_JOURNAL_ACCESS_WRITE);
66248c2ecf20Sopenharmony_ci		if (ret) {
66258c2ecf20Sopenharmony_ci			mlog_errno(ret);
66268c2ecf20Sopenharmony_ci			goto out_commit;
66278c2ecf20Sopenharmony_ci		}
66288c2ecf20Sopenharmony_ci	}
66298c2ecf20Sopenharmony_ci
66308c2ecf20Sopenharmony_ci	ret = ocfs2_journal_access_xb(handle, INODE_CACHE(args->new_inode),
66318c2ecf20Sopenharmony_ci				      new_blk_bh, OCFS2_JOURNAL_ACCESS_WRITE);
66328c2ecf20Sopenharmony_ci	if (ret) {
66338c2ecf20Sopenharmony_ci		mlog_errno(ret);
66348c2ecf20Sopenharmony_ci		goto out_commit;
66358c2ecf20Sopenharmony_ci	}
66368c2ecf20Sopenharmony_ci
66378c2ecf20Sopenharmony_ci	memcpy(new_blk_bh->b_data + header_off, blk_bh->b_data + header_off,
66388c2ecf20Sopenharmony_ci	       osb->sb->s_blocksize - header_off);
66398c2ecf20Sopenharmony_ci
66408c2ecf20Sopenharmony_ci	ret = ocfs2_reflink_xattr_header(handle, args, blk_bh, xh,
66418c2ecf20Sopenharmony_ci					 new_blk_bh, new_xh, &vb, meta_ac,
66428c2ecf20Sopenharmony_ci					 ocfs2_get_xattr_value_root, NULL);
66438c2ecf20Sopenharmony_ci	if (ret) {
66448c2ecf20Sopenharmony_ci		mlog_errno(ret);
66458c2ecf20Sopenharmony_ci		goto out_commit;
66468c2ecf20Sopenharmony_ci	}
66478c2ecf20Sopenharmony_ci
66488c2ecf20Sopenharmony_ci	ocfs2_journal_dirty(handle, new_blk_bh);
66498c2ecf20Sopenharmony_ci
66508c2ecf20Sopenharmony_ci	if (!(new_oi->ip_dyn_features & OCFS2_HAS_XATTR_FL)) {
66518c2ecf20Sopenharmony_ci		new_di = (struct ocfs2_dinode *)args->new_bh->b_data;
66528c2ecf20Sopenharmony_ci		spin_lock(&new_oi->ip_lock);
66538c2ecf20Sopenharmony_ci		new_oi->ip_dyn_features |= OCFS2_HAS_XATTR_FL;
66548c2ecf20Sopenharmony_ci		new_di->i_dyn_features = cpu_to_le16(new_oi->ip_dyn_features);
66558c2ecf20Sopenharmony_ci		spin_unlock(&new_oi->ip_lock);
66568c2ecf20Sopenharmony_ci
66578c2ecf20Sopenharmony_ci		ocfs2_journal_dirty(handle, args->new_bh);
66588c2ecf20Sopenharmony_ci	}
66598c2ecf20Sopenharmony_ci
66608c2ecf20Sopenharmony_ciout_commit:
66618c2ecf20Sopenharmony_ci	ocfs2_commit_trans(osb, handle);
66628c2ecf20Sopenharmony_ci
66638c2ecf20Sopenharmony_ciout:
66648c2ecf20Sopenharmony_ci	ocfs2_free_alloc_context(meta_ac);
66658c2ecf20Sopenharmony_ci	return ret;
66668c2ecf20Sopenharmony_ci}
66678c2ecf20Sopenharmony_ci
66688c2ecf20Sopenharmony_cistruct ocfs2_reflink_xattr_tree_args {
66698c2ecf20Sopenharmony_ci	struct ocfs2_xattr_reflink *reflink;
66708c2ecf20Sopenharmony_ci	struct buffer_head *old_blk_bh;
66718c2ecf20Sopenharmony_ci	struct buffer_head *new_blk_bh;
66728c2ecf20Sopenharmony_ci	struct ocfs2_xattr_bucket *old_bucket;
66738c2ecf20Sopenharmony_ci	struct ocfs2_xattr_bucket *new_bucket;
66748c2ecf20Sopenharmony_ci};
66758c2ecf20Sopenharmony_ci
66768c2ecf20Sopenharmony_ci/*
66778c2ecf20Sopenharmony_ci * NOTE:
66788c2ecf20Sopenharmony_ci * We have to handle the case that both old bucket and new bucket
66798c2ecf20Sopenharmony_ci * will call this function to get the right ret_bh.
66808c2ecf20Sopenharmony_ci * So The caller must give us the right bh.
66818c2ecf20Sopenharmony_ci */
66828c2ecf20Sopenharmony_cistatic int ocfs2_get_reflink_xattr_value_root(struct super_block *sb,
66838c2ecf20Sopenharmony_ci					struct buffer_head *bh,
66848c2ecf20Sopenharmony_ci					struct ocfs2_xattr_header *xh,
66858c2ecf20Sopenharmony_ci					int offset,
66868c2ecf20Sopenharmony_ci					struct ocfs2_xattr_value_root **xv,
66878c2ecf20Sopenharmony_ci					struct buffer_head **ret_bh,
66888c2ecf20Sopenharmony_ci					void *para)
66898c2ecf20Sopenharmony_ci{
66908c2ecf20Sopenharmony_ci	struct ocfs2_reflink_xattr_tree_args *args =
66918c2ecf20Sopenharmony_ci			(struct ocfs2_reflink_xattr_tree_args *)para;
66928c2ecf20Sopenharmony_ci	struct ocfs2_xattr_bucket *bucket;
66938c2ecf20Sopenharmony_ci
66948c2ecf20Sopenharmony_ci	if (bh == args->old_bucket->bu_bhs[0])
66958c2ecf20Sopenharmony_ci		bucket = args->old_bucket;
66968c2ecf20Sopenharmony_ci	else
66978c2ecf20Sopenharmony_ci		bucket = args->new_bucket;
66988c2ecf20Sopenharmony_ci
66998c2ecf20Sopenharmony_ci	return ocfs2_get_xattr_tree_value_root(sb, bucket, offset,
67008c2ecf20Sopenharmony_ci					       xv, ret_bh);
67018c2ecf20Sopenharmony_ci}
67028c2ecf20Sopenharmony_ci
67038c2ecf20Sopenharmony_cistruct ocfs2_value_tree_metas {
67048c2ecf20Sopenharmony_ci	int num_metas;
67058c2ecf20Sopenharmony_ci	int credits;
67068c2ecf20Sopenharmony_ci	int num_recs;
67078c2ecf20Sopenharmony_ci};
67088c2ecf20Sopenharmony_ci
67098c2ecf20Sopenharmony_cistatic int ocfs2_value_tree_metas_in_bucket(struct super_block *sb,
67108c2ecf20Sopenharmony_ci					struct buffer_head *bh,
67118c2ecf20Sopenharmony_ci					struct ocfs2_xattr_header *xh,
67128c2ecf20Sopenharmony_ci					int offset,
67138c2ecf20Sopenharmony_ci					struct ocfs2_xattr_value_root **xv,
67148c2ecf20Sopenharmony_ci					struct buffer_head **ret_bh,
67158c2ecf20Sopenharmony_ci					void *para)
67168c2ecf20Sopenharmony_ci{
67178c2ecf20Sopenharmony_ci	struct ocfs2_xattr_bucket *bucket =
67188c2ecf20Sopenharmony_ci				(struct ocfs2_xattr_bucket *)para;
67198c2ecf20Sopenharmony_ci
67208c2ecf20Sopenharmony_ci	return ocfs2_get_xattr_tree_value_root(sb, bucket, offset,
67218c2ecf20Sopenharmony_ci					       xv, ret_bh);
67228c2ecf20Sopenharmony_ci}
67238c2ecf20Sopenharmony_ci
67248c2ecf20Sopenharmony_cistatic int ocfs2_calc_value_tree_metas(struct inode *inode,
67258c2ecf20Sopenharmony_ci				      struct ocfs2_xattr_bucket *bucket,
67268c2ecf20Sopenharmony_ci				      void *para)
67278c2ecf20Sopenharmony_ci{
67288c2ecf20Sopenharmony_ci	struct ocfs2_value_tree_metas *metas =
67298c2ecf20Sopenharmony_ci			(struct ocfs2_value_tree_metas *)para;
67308c2ecf20Sopenharmony_ci	struct ocfs2_xattr_header *xh =
67318c2ecf20Sopenharmony_ci			(struct ocfs2_xattr_header *)bucket->bu_bhs[0]->b_data;
67328c2ecf20Sopenharmony_ci
67338c2ecf20Sopenharmony_ci	/* Add the credits for this bucket first. */
67348c2ecf20Sopenharmony_ci	metas->credits += bucket->bu_blocks;
67358c2ecf20Sopenharmony_ci	return ocfs2_value_metas_in_xattr_header(inode->i_sb, bucket->bu_bhs[0],
67368c2ecf20Sopenharmony_ci					xh, &metas->num_metas,
67378c2ecf20Sopenharmony_ci					&metas->credits, &metas->num_recs,
67388c2ecf20Sopenharmony_ci					ocfs2_value_tree_metas_in_bucket,
67398c2ecf20Sopenharmony_ci					bucket);
67408c2ecf20Sopenharmony_ci}
67418c2ecf20Sopenharmony_ci
67428c2ecf20Sopenharmony_ci/*
67438c2ecf20Sopenharmony_ci * Given a xattr extent rec starting from blkno and having len clusters,
67448c2ecf20Sopenharmony_ci * iterate all the buckets calculate how much metadata we need for reflinking
67458c2ecf20Sopenharmony_ci * all the ocfs2_xattr_value_root and lock the allocators accordingly.
67468c2ecf20Sopenharmony_ci */
67478c2ecf20Sopenharmony_cistatic int ocfs2_lock_reflink_xattr_rec_allocators(
67488c2ecf20Sopenharmony_ci				struct ocfs2_reflink_xattr_tree_args *args,
67498c2ecf20Sopenharmony_ci				struct ocfs2_extent_tree *xt_et,
67508c2ecf20Sopenharmony_ci				u64 blkno, u32 len, int *credits,
67518c2ecf20Sopenharmony_ci				struct ocfs2_alloc_context **meta_ac,
67528c2ecf20Sopenharmony_ci				struct ocfs2_alloc_context **data_ac)
67538c2ecf20Sopenharmony_ci{
67548c2ecf20Sopenharmony_ci	int ret, num_free_extents;
67558c2ecf20Sopenharmony_ci	struct ocfs2_value_tree_metas metas;
67568c2ecf20Sopenharmony_ci	struct ocfs2_super *osb = OCFS2_SB(args->reflink->old_inode->i_sb);
67578c2ecf20Sopenharmony_ci	struct ocfs2_refcount_block *rb;
67588c2ecf20Sopenharmony_ci
67598c2ecf20Sopenharmony_ci	memset(&metas, 0, sizeof(metas));
67608c2ecf20Sopenharmony_ci
67618c2ecf20Sopenharmony_ci	ret = ocfs2_iterate_xattr_buckets(args->reflink->old_inode, blkno, len,
67628c2ecf20Sopenharmony_ci					  ocfs2_calc_value_tree_metas, &metas);
67638c2ecf20Sopenharmony_ci	if (ret) {
67648c2ecf20Sopenharmony_ci		mlog_errno(ret);
67658c2ecf20Sopenharmony_ci		goto out;
67668c2ecf20Sopenharmony_ci	}
67678c2ecf20Sopenharmony_ci
67688c2ecf20Sopenharmony_ci	*credits = metas.credits;
67698c2ecf20Sopenharmony_ci
67708c2ecf20Sopenharmony_ci	/*
67718c2ecf20Sopenharmony_ci	 * Calculate we need for refcount tree change.
67728c2ecf20Sopenharmony_ci	 *
67738c2ecf20Sopenharmony_ci	 * We need to add/modify num_recs in refcount tree, so just calculate
67748c2ecf20Sopenharmony_ci	 * an approximate number we need for refcount tree change.
67758c2ecf20Sopenharmony_ci	 * Sometimes we need to split the tree, and after split,  half recs
67768c2ecf20Sopenharmony_ci	 * will be moved to the new block, and a new block can only provide
67778c2ecf20Sopenharmony_ci	 * half number of recs. So we multiple new blocks by 2.
67788c2ecf20Sopenharmony_ci	 * In the end, we have to add credits for modifying the already
67798c2ecf20Sopenharmony_ci	 * existed refcount block.
67808c2ecf20Sopenharmony_ci	 */
67818c2ecf20Sopenharmony_ci	rb = (struct ocfs2_refcount_block *)args->reflink->ref_root_bh->b_data;
67828c2ecf20Sopenharmony_ci	metas.num_recs =
67838c2ecf20Sopenharmony_ci		(metas.num_recs + ocfs2_refcount_recs_per_rb(osb->sb) - 1) /
67848c2ecf20Sopenharmony_ci		 ocfs2_refcount_recs_per_rb(osb->sb) * 2;
67858c2ecf20Sopenharmony_ci	metas.num_metas += metas.num_recs;
67868c2ecf20Sopenharmony_ci	*credits += metas.num_recs +
67878c2ecf20Sopenharmony_ci		    metas.num_recs * OCFS2_EXPAND_REFCOUNT_TREE_CREDITS;
67888c2ecf20Sopenharmony_ci	if (le32_to_cpu(rb->rf_flags) & OCFS2_REFCOUNT_TREE_FL)
67898c2ecf20Sopenharmony_ci		*credits += le16_to_cpu(rb->rf_list.l_tree_depth) *
67908c2ecf20Sopenharmony_ci			    le16_to_cpu(rb->rf_list.l_next_free_rec) + 1;
67918c2ecf20Sopenharmony_ci	else
67928c2ecf20Sopenharmony_ci		*credits += 1;
67938c2ecf20Sopenharmony_ci
67948c2ecf20Sopenharmony_ci	/* count in the xattr tree change. */
67958c2ecf20Sopenharmony_ci	num_free_extents = ocfs2_num_free_extents(xt_et);
67968c2ecf20Sopenharmony_ci	if (num_free_extents < 0) {
67978c2ecf20Sopenharmony_ci		ret = num_free_extents;
67988c2ecf20Sopenharmony_ci		mlog_errno(ret);
67998c2ecf20Sopenharmony_ci		goto out;
68008c2ecf20Sopenharmony_ci	}
68018c2ecf20Sopenharmony_ci
68028c2ecf20Sopenharmony_ci	if (num_free_extents < len)
68038c2ecf20Sopenharmony_ci		metas.num_metas += ocfs2_extend_meta_needed(xt_et->et_root_el);
68048c2ecf20Sopenharmony_ci
68058c2ecf20Sopenharmony_ci	*credits += ocfs2_calc_extend_credits(osb->sb,
68068c2ecf20Sopenharmony_ci					      xt_et->et_root_el);
68078c2ecf20Sopenharmony_ci
68088c2ecf20Sopenharmony_ci	if (metas.num_metas) {
68098c2ecf20Sopenharmony_ci		ret = ocfs2_reserve_new_metadata_blocks(osb, metas.num_metas,
68108c2ecf20Sopenharmony_ci							meta_ac);
68118c2ecf20Sopenharmony_ci		if (ret) {
68128c2ecf20Sopenharmony_ci			mlog_errno(ret);
68138c2ecf20Sopenharmony_ci			goto out;
68148c2ecf20Sopenharmony_ci		}
68158c2ecf20Sopenharmony_ci	}
68168c2ecf20Sopenharmony_ci
68178c2ecf20Sopenharmony_ci	if (len) {
68188c2ecf20Sopenharmony_ci		ret = ocfs2_reserve_clusters(osb, len, data_ac);
68198c2ecf20Sopenharmony_ci		if (ret)
68208c2ecf20Sopenharmony_ci			mlog_errno(ret);
68218c2ecf20Sopenharmony_ci	}
68228c2ecf20Sopenharmony_ciout:
68238c2ecf20Sopenharmony_ci	if (ret) {
68248c2ecf20Sopenharmony_ci		if (*meta_ac) {
68258c2ecf20Sopenharmony_ci			ocfs2_free_alloc_context(*meta_ac);
68268c2ecf20Sopenharmony_ci			*meta_ac = NULL;
68278c2ecf20Sopenharmony_ci		}
68288c2ecf20Sopenharmony_ci	}
68298c2ecf20Sopenharmony_ci
68308c2ecf20Sopenharmony_ci	return ret;
68318c2ecf20Sopenharmony_ci}
68328c2ecf20Sopenharmony_ci
68338c2ecf20Sopenharmony_cistatic int ocfs2_reflink_xattr_bucket(handle_t *handle,
68348c2ecf20Sopenharmony_ci				u64 blkno, u64 new_blkno, u32 clusters,
68358c2ecf20Sopenharmony_ci				u32 *cpos, int num_buckets,
68368c2ecf20Sopenharmony_ci				struct ocfs2_alloc_context *meta_ac,
68378c2ecf20Sopenharmony_ci				struct ocfs2_alloc_context *data_ac,
68388c2ecf20Sopenharmony_ci				struct ocfs2_reflink_xattr_tree_args *args)
68398c2ecf20Sopenharmony_ci{
68408c2ecf20Sopenharmony_ci	int i, j, ret = 0;
68418c2ecf20Sopenharmony_ci	struct super_block *sb = args->reflink->old_inode->i_sb;
68428c2ecf20Sopenharmony_ci	int bpb = args->old_bucket->bu_blocks;
68438c2ecf20Sopenharmony_ci	struct ocfs2_xattr_value_buf vb = {
68448c2ecf20Sopenharmony_ci		.vb_access = ocfs2_journal_access,
68458c2ecf20Sopenharmony_ci	};
68468c2ecf20Sopenharmony_ci
68478c2ecf20Sopenharmony_ci	for (i = 0; i < num_buckets; i++, blkno += bpb, new_blkno += bpb) {
68488c2ecf20Sopenharmony_ci		ret = ocfs2_read_xattr_bucket(args->old_bucket, blkno);
68498c2ecf20Sopenharmony_ci		if (ret) {
68508c2ecf20Sopenharmony_ci			mlog_errno(ret);
68518c2ecf20Sopenharmony_ci			break;
68528c2ecf20Sopenharmony_ci		}
68538c2ecf20Sopenharmony_ci
68548c2ecf20Sopenharmony_ci		ret = ocfs2_init_xattr_bucket(args->new_bucket, new_blkno, 1);
68558c2ecf20Sopenharmony_ci		if (ret) {
68568c2ecf20Sopenharmony_ci			mlog_errno(ret);
68578c2ecf20Sopenharmony_ci			break;
68588c2ecf20Sopenharmony_ci		}
68598c2ecf20Sopenharmony_ci
68608c2ecf20Sopenharmony_ci		ret = ocfs2_xattr_bucket_journal_access(handle,
68618c2ecf20Sopenharmony_ci						args->new_bucket,
68628c2ecf20Sopenharmony_ci						OCFS2_JOURNAL_ACCESS_CREATE);
68638c2ecf20Sopenharmony_ci		if (ret) {
68648c2ecf20Sopenharmony_ci			mlog_errno(ret);
68658c2ecf20Sopenharmony_ci			break;
68668c2ecf20Sopenharmony_ci		}
68678c2ecf20Sopenharmony_ci
68688c2ecf20Sopenharmony_ci		for (j = 0; j < bpb; j++)
68698c2ecf20Sopenharmony_ci			memcpy(bucket_block(args->new_bucket, j),
68708c2ecf20Sopenharmony_ci			       bucket_block(args->old_bucket, j),
68718c2ecf20Sopenharmony_ci			       sb->s_blocksize);
68728c2ecf20Sopenharmony_ci
68738c2ecf20Sopenharmony_ci		/*
68748c2ecf20Sopenharmony_ci		 * Record the start cpos so that we can use it to initialize
68758c2ecf20Sopenharmony_ci		 * our xattr tree we also set the xh_num_bucket for the new
68768c2ecf20Sopenharmony_ci		 * bucket.
68778c2ecf20Sopenharmony_ci		 */
68788c2ecf20Sopenharmony_ci		if (i == 0) {
68798c2ecf20Sopenharmony_ci			*cpos = le32_to_cpu(bucket_xh(args->new_bucket)->
68808c2ecf20Sopenharmony_ci					    xh_entries[0].xe_name_hash);
68818c2ecf20Sopenharmony_ci			bucket_xh(args->new_bucket)->xh_num_buckets =
68828c2ecf20Sopenharmony_ci				cpu_to_le16(num_buckets);
68838c2ecf20Sopenharmony_ci		}
68848c2ecf20Sopenharmony_ci
68858c2ecf20Sopenharmony_ci		ocfs2_xattr_bucket_journal_dirty(handle, args->new_bucket);
68868c2ecf20Sopenharmony_ci
68878c2ecf20Sopenharmony_ci		ret = ocfs2_reflink_xattr_header(handle, args->reflink,
68888c2ecf20Sopenharmony_ci					args->old_bucket->bu_bhs[0],
68898c2ecf20Sopenharmony_ci					bucket_xh(args->old_bucket),
68908c2ecf20Sopenharmony_ci					args->new_bucket->bu_bhs[0],
68918c2ecf20Sopenharmony_ci					bucket_xh(args->new_bucket),
68928c2ecf20Sopenharmony_ci					&vb, meta_ac,
68938c2ecf20Sopenharmony_ci					ocfs2_get_reflink_xattr_value_root,
68948c2ecf20Sopenharmony_ci					args);
68958c2ecf20Sopenharmony_ci		if (ret) {
68968c2ecf20Sopenharmony_ci			mlog_errno(ret);
68978c2ecf20Sopenharmony_ci			break;
68988c2ecf20Sopenharmony_ci		}
68998c2ecf20Sopenharmony_ci
69008c2ecf20Sopenharmony_ci		/*
69018c2ecf20Sopenharmony_ci		 * Re-access and dirty the bucket to calculate metaecc.
69028c2ecf20Sopenharmony_ci		 * Because we may extend the transaction in reflink_xattr_header
69038c2ecf20Sopenharmony_ci		 * which will let the already accessed block gone.
69048c2ecf20Sopenharmony_ci		 */
69058c2ecf20Sopenharmony_ci		ret = ocfs2_xattr_bucket_journal_access(handle,
69068c2ecf20Sopenharmony_ci						args->new_bucket,
69078c2ecf20Sopenharmony_ci						OCFS2_JOURNAL_ACCESS_WRITE);
69088c2ecf20Sopenharmony_ci		if (ret) {
69098c2ecf20Sopenharmony_ci			mlog_errno(ret);
69108c2ecf20Sopenharmony_ci			break;
69118c2ecf20Sopenharmony_ci		}
69128c2ecf20Sopenharmony_ci
69138c2ecf20Sopenharmony_ci		ocfs2_xattr_bucket_journal_dirty(handle, args->new_bucket);
69148c2ecf20Sopenharmony_ci
69158c2ecf20Sopenharmony_ci		ocfs2_xattr_bucket_relse(args->old_bucket);
69168c2ecf20Sopenharmony_ci		ocfs2_xattr_bucket_relse(args->new_bucket);
69178c2ecf20Sopenharmony_ci	}
69188c2ecf20Sopenharmony_ci
69198c2ecf20Sopenharmony_ci	ocfs2_xattr_bucket_relse(args->old_bucket);
69208c2ecf20Sopenharmony_ci	ocfs2_xattr_bucket_relse(args->new_bucket);
69218c2ecf20Sopenharmony_ci	return ret;
69228c2ecf20Sopenharmony_ci}
69238c2ecf20Sopenharmony_ci
69248c2ecf20Sopenharmony_cistatic int ocfs2_reflink_xattr_buckets(handle_t *handle,
69258c2ecf20Sopenharmony_ci				struct inode *inode,
69268c2ecf20Sopenharmony_ci				struct ocfs2_reflink_xattr_tree_args *args,
69278c2ecf20Sopenharmony_ci				struct ocfs2_extent_tree *et,
69288c2ecf20Sopenharmony_ci				struct ocfs2_alloc_context *meta_ac,
69298c2ecf20Sopenharmony_ci				struct ocfs2_alloc_context *data_ac,
69308c2ecf20Sopenharmony_ci				u64 blkno, u32 cpos, u32 len)
69318c2ecf20Sopenharmony_ci{
69328c2ecf20Sopenharmony_ci	int ret, first_inserted = 0;
69338c2ecf20Sopenharmony_ci	u32 p_cluster, num_clusters, reflink_cpos = 0;
69348c2ecf20Sopenharmony_ci	u64 new_blkno;
69358c2ecf20Sopenharmony_ci	unsigned int num_buckets, reflink_buckets;
69368c2ecf20Sopenharmony_ci	unsigned int bpc =
69378c2ecf20Sopenharmony_ci		ocfs2_xattr_buckets_per_cluster(OCFS2_SB(inode->i_sb));
69388c2ecf20Sopenharmony_ci
69398c2ecf20Sopenharmony_ci	ret = ocfs2_read_xattr_bucket(args->old_bucket, blkno);
69408c2ecf20Sopenharmony_ci	if (ret) {
69418c2ecf20Sopenharmony_ci		mlog_errno(ret);
69428c2ecf20Sopenharmony_ci		goto out;
69438c2ecf20Sopenharmony_ci	}
69448c2ecf20Sopenharmony_ci	num_buckets = le16_to_cpu(bucket_xh(args->old_bucket)->xh_num_buckets);
69458c2ecf20Sopenharmony_ci	ocfs2_xattr_bucket_relse(args->old_bucket);
69468c2ecf20Sopenharmony_ci
69478c2ecf20Sopenharmony_ci	while (len && num_buckets) {
69488c2ecf20Sopenharmony_ci		ret = ocfs2_claim_clusters(handle, data_ac,
69498c2ecf20Sopenharmony_ci					   1, &p_cluster, &num_clusters);
69508c2ecf20Sopenharmony_ci		if (ret) {
69518c2ecf20Sopenharmony_ci			mlog_errno(ret);
69528c2ecf20Sopenharmony_ci			goto out;
69538c2ecf20Sopenharmony_ci		}
69548c2ecf20Sopenharmony_ci
69558c2ecf20Sopenharmony_ci		new_blkno = ocfs2_clusters_to_blocks(inode->i_sb, p_cluster);
69568c2ecf20Sopenharmony_ci		reflink_buckets = min(num_buckets, bpc * num_clusters);
69578c2ecf20Sopenharmony_ci
69588c2ecf20Sopenharmony_ci		ret = ocfs2_reflink_xattr_bucket(handle, blkno,
69598c2ecf20Sopenharmony_ci						 new_blkno, num_clusters,
69608c2ecf20Sopenharmony_ci						 &reflink_cpos, reflink_buckets,
69618c2ecf20Sopenharmony_ci						 meta_ac, data_ac, args);
69628c2ecf20Sopenharmony_ci		if (ret) {
69638c2ecf20Sopenharmony_ci			mlog_errno(ret);
69648c2ecf20Sopenharmony_ci			goto out;
69658c2ecf20Sopenharmony_ci		}
69668c2ecf20Sopenharmony_ci
69678c2ecf20Sopenharmony_ci		/*
69688c2ecf20Sopenharmony_ci		 * For the 1st allocated cluster, we make it use the same cpos
69698c2ecf20Sopenharmony_ci		 * so that the xattr tree looks the same as the original one
69708c2ecf20Sopenharmony_ci		 * in the most case.
69718c2ecf20Sopenharmony_ci		 */
69728c2ecf20Sopenharmony_ci		if (!first_inserted) {
69738c2ecf20Sopenharmony_ci			reflink_cpos = cpos;
69748c2ecf20Sopenharmony_ci			first_inserted = 1;
69758c2ecf20Sopenharmony_ci		}
69768c2ecf20Sopenharmony_ci		ret = ocfs2_insert_extent(handle, et, reflink_cpos, new_blkno,
69778c2ecf20Sopenharmony_ci					  num_clusters, 0, meta_ac);
69788c2ecf20Sopenharmony_ci		if (ret)
69798c2ecf20Sopenharmony_ci			mlog_errno(ret);
69808c2ecf20Sopenharmony_ci
69818c2ecf20Sopenharmony_ci		trace_ocfs2_reflink_xattr_buckets((unsigned long long)new_blkno,
69828c2ecf20Sopenharmony_ci						  num_clusters, reflink_cpos);
69838c2ecf20Sopenharmony_ci
69848c2ecf20Sopenharmony_ci		len -= num_clusters;
69858c2ecf20Sopenharmony_ci		blkno += ocfs2_clusters_to_blocks(inode->i_sb, num_clusters);
69868c2ecf20Sopenharmony_ci		num_buckets -= reflink_buckets;
69878c2ecf20Sopenharmony_ci	}
69888c2ecf20Sopenharmony_ciout:
69898c2ecf20Sopenharmony_ci	return ret;
69908c2ecf20Sopenharmony_ci}
69918c2ecf20Sopenharmony_ci
69928c2ecf20Sopenharmony_ci/*
69938c2ecf20Sopenharmony_ci * Create the same xattr extent record in the new inode's xattr tree.
69948c2ecf20Sopenharmony_ci */
69958c2ecf20Sopenharmony_cistatic int ocfs2_reflink_xattr_rec(struct inode *inode,
69968c2ecf20Sopenharmony_ci				   struct buffer_head *root_bh,
69978c2ecf20Sopenharmony_ci				   u64 blkno,
69988c2ecf20Sopenharmony_ci				   u32 cpos,
69998c2ecf20Sopenharmony_ci				   u32 len,
70008c2ecf20Sopenharmony_ci				   void *para)
70018c2ecf20Sopenharmony_ci{
70028c2ecf20Sopenharmony_ci	int ret, credits = 0;
70038c2ecf20Sopenharmony_ci	handle_t *handle;
70048c2ecf20Sopenharmony_ci	struct ocfs2_reflink_xattr_tree_args *args =
70058c2ecf20Sopenharmony_ci			(struct ocfs2_reflink_xattr_tree_args *)para;
70068c2ecf20Sopenharmony_ci	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
70078c2ecf20Sopenharmony_ci	struct ocfs2_alloc_context *meta_ac = NULL;
70088c2ecf20Sopenharmony_ci	struct ocfs2_alloc_context *data_ac = NULL;
70098c2ecf20Sopenharmony_ci	struct ocfs2_extent_tree et;
70108c2ecf20Sopenharmony_ci
70118c2ecf20Sopenharmony_ci	trace_ocfs2_reflink_xattr_rec((unsigned long long)blkno, len);
70128c2ecf20Sopenharmony_ci
70138c2ecf20Sopenharmony_ci	ocfs2_init_xattr_tree_extent_tree(&et,
70148c2ecf20Sopenharmony_ci					  INODE_CACHE(args->reflink->new_inode),
70158c2ecf20Sopenharmony_ci					  args->new_blk_bh);
70168c2ecf20Sopenharmony_ci
70178c2ecf20Sopenharmony_ci	ret = ocfs2_lock_reflink_xattr_rec_allocators(args, &et, blkno,
70188c2ecf20Sopenharmony_ci						      len, &credits,
70198c2ecf20Sopenharmony_ci						      &meta_ac, &data_ac);
70208c2ecf20Sopenharmony_ci	if (ret) {
70218c2ecf20Sopenharmony_ci		mlog_errno(ret);
70228c2ecf20Sopenharmony_ci		goto out;
70238c2ecf20Sopenharmony_ci	}
70248c2ecf20Sopenharmony_ci
70258c2ecf20Sopenharmony_ci	handle = ocfs2_start_trans(osb, credits);
70268c2ecf20Sopenharmony_ci	if (IS_ERR(handle)) {
70278c2ecf20Sopenharmony_ci		ret = PTR_ERR(handle);
70288c2ecf20Sopenharmony_ci		mlog_errno(ret);
70298c2ecf20Sopenharmony_ci		goto out;
70308c2ecf20Sopenharmony_ci	}
70318c2ecf20Sopenharmony_ci
70328c2ecf20Sopenharmony_ci	ret = ocfs2_reflink_xattr_buckets(handle, inode, args, &et,
70338c2ecf20Sopenharmony_ci					  meta_ac, data_ac,
70348c2ecf20Sopenharmony_ci					  blkno, cpos, len);
70358c2ecf20Sopenharmony_ci	if (ret)
70368c2ecf20Sopenharmony_ci		mlog_errno(ret);
70378c2ecf20Sopenharmony_ci
70388c2ecf20Sopenharmony_ci	ocfs2_commit_trans(osb, handle);
70398c2ecf20Sopenharmony_ci
70408c2ecf20Sopenharmony_ciout:
70418c2ecf20Sopenharmony_ci	if (meta_ac)
70428c2ecf20Sopenharmony_ci		ocfs2_free_alloc_context(meta_ac);
70438c2ecf20Sopenharmony_ci	if (data_ac)
70448c2ecf20Sopenharmony_ci		ocfs2_free_alloc_context(data_ac);
70458c2ecf20Sopenharmony_ci	return ret;
70468c2ecf20Sopenharmony_ci}
70478c2ecf20Sopenharmony_ci
70488c2ecf20Sopenharmony_ci/*
70498c2ecf20Sopenharmony_ci * Create reflinked xattr buckets.
70508c2ecf20Sopenharmony_ci * We will add bucket one by one, and refcount all the xattrs in the bucket
70518c2ecf20Sopenharmony_ci * if they are stored outside.
70528c2ecf20Sopenharmony_ci */
70538c2ecf20Sopenharmony_cistatic int ocfs2_reflink_xattr_tree(struct ocfs2_xattr_reflink *args,
70548c2ecf20Sopenharmony_ci				    struct buffer_head *blk_bh,
70558c2ecf20Sopenharmony_ci				    struct buffer_head *new_blk_bh)
70568c2ecf20Sopenharmony_ci{
70578c2ecf20Sopenharmony_ci	int ret;
70588c2ecf20Sopenharmony_ci	struct ocfs2_reflink_xattr_tree_args para;
70598c2ecf20Sopenharmony_ci
70608c2ecf20Sopenharmony_ci	memset(&para, 0, sizeof(para));
70618c2ecf20Sopenharmony_ci	para.reflink = args;
70628c2ecf20Sopenharmony_ci	para.old_blk_bh = blk_bh;
70638c2ecf20Sopenharmony_ci	para.new_blk_bh = new_blk_bh;
70648c2ecf20Sopenharmony_ci
70658c2ecf20Sopenharmony_ci	para.old_bucket = ocfs2_xattr_bucket_new(args->old_inode);
70668c2ecf20Sopenharmony_ci	if (!para.old_bucket) {
70678c2ecf20Sopenharmony_ci		mlog_errno(-ENOMEM);
70688c2ecf20Sopenharmony_ci		return -ENOMEM;
70698c2ecf20Sopenharmony_ci	}
70708c2ecf20Sopenharmony_ci
70718c2ecf20Sopenharmony_ci	para.new_bucket = ocfs2_xattr_bucket_new(args->new_inode);
70728c2ecf20Sopenharmony_ci	if (!para.new_bucket) {
70738c2ecf20Sopenharmony_ci		ret = -ENOMEM;
70748c2ecf20Sopenharmony_ci		mlog_errno(ret);
70758c2ecf20Sopenharmony_ci		goto out;
70768c2ecf20Sopenharmony_ci	}
70778c2ecf20Sopenharmony_ci
70788c2ecf20Sopenharmony_ci	ret = ocfs2_iterate_xattr_index_block(args->old_inode, blk_bh,
70798c2ecf20Sopenharmony_ci					      ocfs2_reflink_xattr_rec,
70808c2ecf20Sopenharmony_ci					      &para);
70818c2ecf20Sopenharmony_ci	if (ret)
70828c2ecf20Sopenharmony_ci		mlog_errno(ret);
70838c2ecf20Sopenharmony_ci
70848c2ecf20Sopenharmony_ciout:
70858c2ecf20Sopenharmony_ci	ocfs2_xattr_bucket_free(para.old_bucket);
70868c2ecf20Sopenharmony_ci	ocfs2_xattr_bucket_free(para.new_bucket);
70878c2ecf20Sopenharmony_ci	return ret;
70888c2ecf20Sopenharmony_ci}
70898c2ecf20Sopenharmony_ci
70908c2ecf20Sopenharmony_cistatic int ocfs2_reflink_xattr_in_block(struct ocfs2_xattr_reflink *args,
70918c2ecf20Sopenharmony_ci					struct buffer_head *blk_bh)
70928c2ecf20Sopenharmony_ci{
70938c2ecf20Sopenharmony_ci	int ret, indexed = 0;
70948c2ecf20Sopenharmony_ci	struct buffer_head *new_blk_bh = NULL;
70958c2ecf20Sopenharmony_ci	struct ocfs2_xattr_block *xb =
70968c2ecf20Sopenharmony_ci			(struct ocfs2_xattr_block *)blk_bh->b_data;
70978c2ecf20Sopenharmony_ci
70988c2ecf20Sopenharmony_ci
70998c2ecf20Sopenharmony_ci	if (le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)
71008c2ecf20Sopenharmony_ci		indexed = 1;
71018c2ecf20Sopenharmony_ci
71028c2ecf20Sopenharmony_ci	ret = ocfs2_create_empty_xattr_block(args->new_inode, args->new_bh,
71038c2ecf20Sopenharmony_ci					     &new_blk_bh, indexed);
71048c2ecf20Sopenharmony_ci	if (ret) {
71058c2ecf20Sopenharmony_ci		mlog_errno(ret);
71068c2ecf20Sopenharmony_ci		goto out;
71078c2ecf20Sopenharmony_ci	}
71088c2ecf20Sopenharmony_ci
71098c2ecf20Sopenharmony_ci	if (!indexed)
71108c2ecf20Sopenharmony_ci		ret = ocfs2_reflink_xattr_block(args, blk_bh, new_blk_bh);
71118c2ecf20Sopenharmony_ci	else
71128c2ecf20Sopenharmony_ci		ret = ocfs2_reflink_xattr_tree(args, blk_bh, new_blk_bh);
71138c2ecf20Sopenharmony_ci	if (ret)
71148c2ecf20Sopenharmony_ci		mlog_errno(ret);
71158c2ecf20Sopenharmony_ci
71168c2ecf20Sopenharmony_ciout:
71178c2ecf20Sopenharmony_ci	brelse(new_blk_bh);
71188c2ecf20Sopenharmony_ci	return ret;
71198c2ecf20Sopenharmony_ci}
71208c2ecf20Sopenharmony_ci
71218c2ecf20Sopenharmony_cistatic int ocfs2_reflink_xattr_no_security(struct ocfs2_xattr_entry *xe)
71228c2ecf20Sopenharmony_ci{
71238c2ecf20Sopenharmony_ci	int type = ocfs2_xattr_get_type(xe);
71248c2ecf20Sopenharmony_ci
71258c2ecf20Sopenharmony_ci	return type != OCFS2_XATTR_INDEX_SECURITY &&
71268c2ecf20Sopenharmony_ci	       type != OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS &&
71278c2ecf20Sopenharmony_ci	       type != OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT;
71288c2ecf20Sopenharmony_ci}
71298c2ecf20Sopenharmony_ci
71308c2ecf20Sopenharmony_ciint ocfs2_reflink_xattrs(struct inode *old_inode,
71318c2ecf20Sopenharmony_ci			 struct buffer_head *old_bh,
71328c2ecf20Sopenharmony_ci			 struct inode *new_inode,
71338c2ecf20Sopenharmony_ci			 struct buffer_head *new_bh,
71348c2ecf20Sopenharmony_ci			 bool preserve_security)
71358c2ecf20Sopenharmony_ci{
71368c2ecf20Sopenharmony_ci	int ret;
71378c2ecf20Sopenharmony_ci	struct ocfs2_xattr_reflink args;
71388c2ecf20Sopenharmony_ci	struct ocfs2_inode_info *oi = OCFS2_I(old_inode);
71398c2ecf20Sopenharmony_ci	struct ocfs2_dinode *di = (struct ocfs2_dinode *)old_bh->b_data;
71408c2ecf20Sopenharmony_ci	struct buffer_head *blk_bh = NULL;
71418c2ecf20Sopenharmony_ci	struct ocfs2_cached_dealloc_ctxt dealloc;
71428c2ecf20Sopenharmony_ci	struct ocfs2_refcount_tree *ref_tree;
71438c2ecf20Sopenharmony_ci	struct buffer_head *ref_root_bh = NULL;
71448c2ecf20Sopenharmony_ci
71458c2ecf20Sopenharmony_ci	ret = ocfs2_lock_refcount_tree(OCFS2_SB(old_inode->i_sb),
71468c2ecf20Sopenharmony_ci				       le64_to_cpu(di->i_refcount_loc),
71478c2ecf20Sopenharmony_ci				       1, &ref_tree, &ref_root_bh);
71488c2ecf20Sopenharmony_ci	if (ret) {
71498c2ecf20Sopenharmony_ci		mlog_errno(ret);
71508c2ecf20Sopenharmony_ci		goto out;
71518c2ecf20Sopenharmony_ci	}
71528c2ecf20Sopenharmony_ci
71538c2ecf20Sopenharmony_ci	ocfs2_init_dealloc_ctxt(&dealloc);
71548c2ecf20Sopenharmony_ci
71558c2ecf20Sopenharmony_ci	args.old_inode = old_inode;
71568c2ecf20Sopenharmony_ci	args.new_inode = new_inode;
71578c2ecf20Sopenharmony_ci	args.old_bh = old_bh;
71588c2ecf20Sopenharmony_ci	args.new_bh = new_bh;
71598c2ecf20Sopenharmony_ci	args.ref_ci = &ref_tree->rf_ci;
71608c2ecf20Sopenharmony_ci	args.ref_root_bh = ref_root_bh;
71618c2ecf20Sopenharmony_ci	args.dealloc = &dealloc;
71628c2ecf20Sopenharmony_ci	if (preserve_security)
71638c2ecf20Sopenharmony_ci		args.xattr_reflinked = NULL;
71648c2ecf20Sopenharmony_ci	else
71658c2ecf20Sopenharmony_ci		args.xattr_reflinked = ocfs2_reflink_xattr_no_security;
71668c2ecf20Sopenharmony_ci
71678c2ecf20Sopenharmony_ci	if (oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL) {
71688c2ecf20Sopenharmony_ci		ret = ocfs2_reflink_xattr_inline(&args);
71698c2ecf20Sopenharmony_ci		if (ret) {
71708c2ecf20Sopenharmony_ci			mlog_errno(ret);
71718c2ecf20Sopenharmony_ci			goto out_unlock;
71728c2ecf20Sopenharmony_ci		}
71738c2ecf20Sopenharmony_ci	}
71748c2ecf20Sopenharmony_ci
71758c2ecf20Sopenharmony_ci	if (!di->i_xattr_loc)
71768c2ecf20Sopenharmony_ci		goto out_unlock;
71778c2ecf20Sopenharmony_ci
71788c2ecf20Sopenharmony_ci	ret = ocfs2_read_xattr_block(old_inode, le64_to_cpu(di->i_xattr_loc),
71798c2ecf20Sopenharmony_ci				     &blk_bh);
71808c2ecf20Sopenharmony_ci	if (ret < 0) {
71818c2ecf20Sopenharmony_ci		mlog_errno(ret);
71828c2ecf20Sopenharmony_ci		goto out_unlock;
71838c2ecf20Sopenharmony_ci	}
71848c2ecf20Sopenharmony_ci
71858c2ecf20Sopenharmony_ci	ret = ocfs2_reflink_xattr_in_block(&args, blk_bh);
71868c2ecf20Sopenharmony_ci	if (ret)
71878c2ecf20Sopenharmony_ci		mlog_errno(ret);
71888c2ecf20Sopenharmony_ci
71898c2ecf20Sopenharmony_ci	brelse(blk_bh);
71908c2ecf20Sopenharmony_ci
71918c2ecf20Sopenharmony_ciout_unlock:
71928c2ecf20Sopenharmony_ci	ocfs2_unlock_refcount_tree(OCFS2_SB(old_inode->i_sb),
71938c2ecf20Sopenharmony_ci				   ref_tree, 1);
71948c2ecf20Sopenharmony_ci	brelse(ref_root_bh);
71958c2ecf20Sopenharmony_ci
71968c2ecf20Sopenharmony_ci	if (ocfs2_dealloc_has_cluster(&dealloc)) {
71978c2ecf20Sopenharmony_ci		ocfs2_schedule_truncate_log_flush(OCFS2_SB(old_inode->i_sb), 1);
71988c2ecf20Sopenharmony_ci		ocfs2_run_deallocs(OCFS2_SB(old_inode->i_sb), &dealloc);
71998c2ecf20Sopenharmony_ci	}
72008c2ecf20Sopenharmony_ci
72018c2ecf20Sopenharmony_ciout:
72028c2ecf20Sopenharmony_ci	return ret;
72038c2ecf20Sopenharmony_ci}
72048c2ecf20Sopenharmony_ci
72058c2ecf20Sopenharmony_ci/*
72068c2ecf20Sopenharmony_ci * Initialize security and acl for a already created inode.
72078c2ecf20Sopenharmony_ci * Used for reflink a non-preserve-security file.
72088c2ecf20Sopenharmony_ci *
72098c2ecf20Sopenharmony_ci * It uses common api like ocfs2_xattr_set, so the caller
72108c2ecf20Sopenharmony_ci * must not hold any lock expect i_mutex.
72118c2ecf20Sopenharmony_ci */
72128c2ecf20Sopenharmony_ciint ocfs2_init_security_and_acl(struct inode *dir,
72138c2ecf20Sopenharmony_ci				struct inode *inode,
72148c2ecf20Sopenharmony_ci				const struct qstr *qstr)
72158c2ecf20Sopenharmony_ci{
72168c2ecf20Sopenharmony_ci	int ret = 0;
72178c2ecf20Sopenharmony_ci	struct buffer_head *dir_bh = NULL;
72188c2ecf20Sopenharmony_ci
72198c2ecf20Sopenharmony_ci	ret = ocfs2_init_security_get(inode, dir, qstr, NULL);
72208c2ecf20Sopenharmony_ci	if (ret) {
72218c2ecf20Sopenharmony_ci		mlog_errno(ret);
72228c2ecf20Sopenharmony_ci		goto leave;
72238c2ecf20Sopenharmony_ci	}
72248c2ecf20Sopenharmony_ci
72258c2ecf20Sopenharmony_ci	ret = ocfs2_inode_lock(dir, &dir_bh, 0);
72268c2ecf20Sopenharmony_ci	if (ret) {
72278c2ecf20Sopenharmony_ci		mlog_errno(ret);
72288c2ecf20Sopenharmony_ci		goto leave;
72298c2ecf20Sopenharmony_ci	}
72308c2ecf20Sopenharmony_ci	ret = ocfs2_init_acl(NULL, inode, dir, NULL, dir_bh, NULL, NULL);
72318c2ecf20Sopenharmony_ci	if (ret)
72328c2ecf20Sopenharmony_ci		mlog_errno(ret);
72338c2ecf20Sopenharmony_ci
72348c2ecf20Sopenharmony_ci	ocfs2_inode_unlock(dir, 0);
72358c2ecf20Sopenharmony_ci	brelse(dir_bh);
72368c2ecf20Sopenharmony_cileave:
72378c2ecf20Sopenharmony_ci	return ret;
72388c2ecf20Sopenharmony_ci}
72398c2ecf20Sopenharmony_ci
72408c2ecf20Sopenharmony_ci/*
72418c2ecf20Sopenharmony_ci * 'security' attributes support
72428c2ecf20Sopenharmony_ci */
72438c2ecf20Sopenharmony_cistatic int ocfs2_xattr_security_get(const struct xattr_handler *handler,
72448c2ecf20Sopenharmony_ci				    struct dentry *unused, struct inode *inode,
72458c2ecf20Sopenharmony_ci				    const char *name, void *buffer, size_t size)
72468c2ecf20Sopenharmony_ci{
72478c2ecf20Sopenharmony_ci	return ocfs2_xattr_get(inode, OCFS2_XATTR_INDEX_SECURITY,
72488c2ecf20Sopenharmony_ci			       name, buffer, size);
72498c2ecf20Sopenharmony_ci}
72508c2ecf20Sopenharmony_ci
72518c2ecf20Sopenharmony_cistatic int ocfs2_xattr_security_set(const struct xattr_handler *handler,
72528c2ecf20Sopenharmony_ci				    struct dentry *unused, struct inode *inode,
72538c2ecf20Sopenharmony_ci				    const char *name, const void *value,
72548c2ecf20Sopenharmony_ci				    size_t size, int flags)
72558c2ecf20Sopenharmony_ci{
72568c2ecf20Sopenharmony_ci	return ocfs2_xattr_set(inode, OCFS2_XATTR_INDEX_SECURITY,
72578c2ecf20Sopenharmony_ci			       name, value, size, flags);
72588c2ecf20Sopenharmony_ci}
72598c2ecf20Sopenharmony_ci
72608c2ecf20Sopenharmony_cistatic int ocfs2_initxattrs(struct inode *inode, const struct xattr *xattr_array,
72618c2ecf20Sopenharmony_ci		     void *fs_info)
72628c2ecf20Sopenharmony_ci{
72638c2ecf20Sopenharmony_ci	struct ocfs2_security_xattr_info *si = fs_info;
72648c2ecf20Sopenharmony_ci	const struct xattr *xattr;
72658c2ecf20Sopenharmony_ci	int err = 0;
72668c2ecf20Sopenharmony_ci
72678c2ecf20Sopenharmony_ci	if (si) {
72688c2ecf20Sopenharmony_ci		si->value = kmemdup(xattr_array->value, xattr_array->value_len,
72698c2ecf20Sopenharmony_ci				    GFP_KERNEL);
72708c2ecf20Sopenharmony_ci		if (!si->value)
72718c2ecf20Sopenharmony_ci			return -ENOMEM;
72728c2ecf20Sopenharmony_ci
72738c2ecf20Sopenharmony_ci		si->name = xattr_array->name;
72748c2ecf20Sopenharmony_ci		si->value_len = xattr_array->value_len;
72758c2ecf20Sopenharmony_ci		return 0;
72768c2ecf20Sopenharmony_ci	}
72778c2ecf20Sopenharmony_ci
72788c2ecf20Sopenharmony_ci	for (xattr = xattr_array; xattr->name != NULL; xattr++) {
72798c2ecf20Sopenharmony_ci		err = ocfs2_xattr_set(inode, OCFS2_XATTR_INDEX_SECURITY,
72808c2ecf20Sopenharmony_ci				      xattr->name, xattr->value,
72818c2ecf20Sopenharmony_ci				      xattr->value_len, XATTR_CREATE);
72828c2ecf20Sopenharmony_ci		if (err)
72838c2ecf20Sopenharmony_ci			break;
72848c2ecf20Sopenharmony_ci	}
72858c2ecf20Sopenharmony_ci	return err;
72868c2ecf20Sopenharmony_ci}
72878c2ecf20Sopenharmony_ci
72888c2ecf20Sopenharmony_ciint ocfs2_init_security_get(struct inode *inode,
72898c2ecf20Sopenharmony_ci			    struct inode *dir,
72908c2ecf20Sopenharmony_ci			    const struct qstr *qstr,
72918c2ecf20Sopenharmony_ci			    struct ocfs2_security_xattr_info *si)
72928c2ecf20Sopenharmony_ci{
72938c2ecf20Sopenharmony_ci	int ret;
72948c2ecf20Sopenharmony_ci
72958c2ecf20Sopenharmony_ci	/* check whether ocfs2 support feature xattr */
72968c2ecf20Sopenharmony_ci	if (!ocfs2_supports_xattr(OCFS2_SB(dir->i_sb)))
72978c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
72988c2ecf20Sopenharmony_ci	if (si) {
72998c2ecf20Sopenharmony_ci		ret = security_inode_init_security(inode, dir, qstr,
73008c2ecf20Sopenharmony_ci						   &ocfs2_initxattrs, si);
73018c2ecf20Sopenharmony_ci		/*
73028c2ecf20Sopenharmony_ci		 * security_inode_init_security() does not return -EOPNOTSUPP,
73038c2ecf20Sopenharmony_ci		 * we have to check the xattr ourselves.
73048c2ecf20Sopenharmony_ci		 */
73058c2ecf20Sopenharmony_ci		if (!ret && !si->name)
73068c2ecf20Sopenharmony_ci			si->enable = 0;
73078c2ecf20Sopenharmony_ci
73088c2ecf20Sopenharmony_ci		return ret;
73098c2ecf20Sopenharmony_ci	}
73108c2ecf20Sopenharmony_ci
73118c2ecf20Sopenharmony_ci	return security_inode_init_security(inode, dir, qstr,
73128c2ecf20Sopenharmony_ci					    &ocfs2_initxattrs, NULL);
73138c2ecf20Sopenharmony_ci}
73148c2ecf20Sopenharmony_ci
73158c2ecf20Sopenharmony_ciint ocfs2_init_security_set(handle_t *handle,
73168c2ecf20Sopenharmony_ci			    struct inode *inode,
73178c2ecf20Sopenharmony_ci			    struct buffer_head *di_bh,
73188c2ecf20Sopenharmony_ci			    struct ocfs2_security_xattr_info *si,
73198c2ecf20Sopenharmony_ci			    struct ocfs2_alloc_context *xattr_ac,
73208c2ecf20Sopenharmony_ci			    struct ocfs2_alloc_context *data_ac)
73218c2ecf20Sopenharmony_ci{
73228c2ecf20Sopenharmony_ci	return ocfs2_xattr_set_handle(handle, inode, di_bh,
73238c2ecf20Sopenharmony_ci				     OCFS2_XATTR_INDEX_SECURITY,
73248c2ecf20Sopenharmony_ci				     si->name, si->value, si->value_len, 0,
73258c2ecf20Sopenharmony_ci				     xattr_ac, data_ac);
73268c2ecf20Sopenharmony_ci}
73278c2ecf20Sopenharmony_ci
73288c2ecf20Sopenharmony_ciconst struct xattr_handler ocfs2_xattr_security_handler = {
73298c2ecf20Sopenharmony_ci	.prefix	= XATTR_SECURITY_PREFIX,
73308c2ecf20Sopenharmony_ci	.get	= ocfs2_xattr_security_get,
73318c2ecf20Sopenharmony_ci	.set	= ocfs2_xattr_security_set,
73328c2ecf20Sopenharmony_ci};
73338c2ecf20Sopenharmony_ci
73348c2ecf20Sopenharmony_ci/*
73358c2ecf20Sopenharmony_ci * 'trusted' attributes support
73368c2ecf20Sopenharmony_ci */
73378c2ecf20Sopenharmony_cistatic int ocfs2_xattr_trusted_get(const struct xattr_handler *handler,
73388c2ecf20Sopenharmony_ci				   struct dentry *unused, struct inode *inode,
73398c2ecf20Sopenharmony_ci				   const char *name, void *buffer, size_t size)
73408c2ecf20Sopenharmony_ci{
73418c2ecf20Sopenharmony_ci	return ocfs2_xattr_get(inode, OCFS2_XATTR_INDEX_TRUSTED,
73428c2ecf20Sopenharmony_ci			       name, buffer, size);
73438c2ecf20Sopenharmony_ci}
73448c2ecf20Sopenharmony_ci
73458c2ecf20Sopenharmony_cistatic int ocfs2_xattr_trusted_set(const struct xattr_handler *handler,
73468c2ecf20Sopenharmony_ci				   struct dentry *unused, struct inode *inode,
73478c2ecf20Sopenharmony_ci				   const char *name, const void *value,
73488c2ecf20Sopenharmony_ci				   size_t size, int flags)
73498c2ecf20Sopenharmony_ci{
73508c2ecf20Sopenharmony_ci	return ocfs2_xattr_set(inode, OCFS2_XATTR_INDEX_TRUSTED,
73518c2ecf20Sopenharmony_ci			       name, value, size, flags);
73528c2ecf20Sopenharmony_ci}
73538c2ecf20Sopenharmony_ci
73548c2ecf20Sopenharmony_ciconst struct xattr_handler ocfs2_xattr_trusted_handler = {
73558c2ecf20Sopenharmony_ci	.prefix	= XATTR_TRUSTED_PREFIX,
73568c2ecf20Sopenharmony_ci	.get	= ocfs2_xattr_trusted_get,
73578c2ecf20Sopenharmony_ci	.set	= ocfs2_xattr_trusted_set,
73588c2ecf20Sopenharmony_ci};
73598c2ecf20Sopenharmony_ci
73608c2ecf20Sopenharmony_ci/*
73618c2ecf20Sopenharmony_ci * 'user' attributes support
73628c2ecf20Sopenharmony_ci */
73638c2ecf20Sopenharmony_cistatic int ocfs2_xattr_user_get(const struct xattr_handler *handler,
73648c2ecf20Sopenharmony_ci				struct dentry *unused, struct inode *inode,
73658c2ecf20Sopenharmony_ci				const char *name, void *buffer, size_t size)
73668c2ecf20Sopenharmony_ci{
73678c2ecf20Sopenharmony_ci	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
73688c2ecf20Sopenharmony_ci
73698c2ecf20Sopenharmony_ci	if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR)
73708c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
73718c2ecf20Sopenharmony_ci	return ocfs2_xattr_get(inode, OCFS2_XATTR_INDEX_USER, name,
73728c2ecf20Sopenharmony_ci			       buffer, size);
73738c2ecf20Sopenharmony_ci}
73748c2ecf20Sopenharmony_ci
73758c2ecf20Sopenharmony_cistatic int ocfs2_xattr_user_set(const struct xattr_handler *handler,
73768c2ecf20Sopenharmony_ci				struct dentry *unused, struct inode *inode,
73778c2ecf20Sopenharmony_ci				const char *name, const void *value,
73788c2ecf20Sopenharmony_ci				size_t size, int flags)
73798c2ecf20Sopenharmony_ci{
73808c2ecf20Sopenharmony_ci	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
73818c2ecf20Sopenharmony_ci
73828c2ecf20Sopenharmony_ci	if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR)
73838c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
73848c2ecf20Sopenharmony_ci
73858c2ecf20Sopenharmony_ci	return ocfs2_xattr_set(inode, OCFS2_XATTR_INDEX_USER,
73868c2ecf20Sopenharmony_ci			       name, value, size, flags);
73878c2ecf20Sopenharmony_ci}
73888c2ecf20Sopenharmony_ci
73898c2ecf20Sopenharmony_ciconst struct xattr_handler ocfs2_xattr_user_handler = {
73908c2ecf20Sopenharmony_ci	.prefix	= XATTR_USER_PREFIX,
73918c2ecf20Sopenharmony_ci	.get	= ocfs2_xattr_user_get,
73928c2ecf20Sopenharmony_ci	.set	= ocfs2_xattr_user_set,
73938c2ecf20Sopenharmony_ci};
7394