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 ¶); 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(¶, 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 ¶); 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