ocfs2: Add extended attributes for ocfs2. V1
cover ocfs2: Add extended attributes for ocfs2. V1
Hi all,
Extended attributes are used for storing POSIX ACLs, SELinux labels,
and user accessible metadata. They are essential for deploying file systems exported for workgroup use via samba. The following patches implement extended attributes on the OCFS2 file system.
Patch 1-4: The refactoring of extent tree operation. xattr will use ocfs2_extent_list for both the large EA and large numbers of EA. So we need some refactoring so that the old code can work with them.
Patch 5: Add ocfs2 xattr header.
Patch 6: Add operations for storing large EA in ocfs2. This is also refactor the old extent tree a little.
Patch 7: The extended attributes for ocfs2. It enables extended attributes storage for both in-inode and one meta block. The main design doc can be found at
http://oss.oracle.com/osswiki/OCFS2/DesignDocs/ExtendedAttributes.
Patch 8: Enables storing large numbers of EAs in ocfs2. The main design doc can be found at
http://oss.oracle.com/osswiki/OCFS2/DesignDocs/IndexedEATrees. The main process is almost the same, but some difference is described in detail in that patch.
Regards,
Tiger and Tao
PATCH 7/8 ocfs2: Add extended attributes support. v1
This patch implement storing extended attributes both in inode or metadata block. For EAs in inode, we reserve the last 256 bytes in inode block(blocksize >= 1024). When EAs value size large than 80 bytes, we will store the value via b-tree outside inode or block.
--- fs/ocfs2/Makefile | 2 + fs/ocfs2/file.c | 5 + fs/ocfs2/inode.c | 8 + fs/ocfs2/namei.c | 5 + fs/ocfs2/ocfs2.h | 1 + fs/ocfs2/ocfs2_fs.h | 43 ++- fs/ocfs2/super.c | 12 + fs/ocfs2/xattr.c | 1342 +++++++++++++++++++++++++++++++++++++++++++++- fs/ocfs2/xattr.h | 27 + fs/ocfs2/xattr_trusted.c | 79 +++ fs/ocfs2/xattr_user.c | 91 ++++ 11 files changed, 1600 insertions(+), 15 deletions(-) create mode 100644 fs/ocfs2/xattr_trusted.c create mode 100644 fs/ocfs2/xattr_user.c
fs/ocfs2/Makefile +2 -0
@@ -36,6 +36,8 @@ ocfs2-objs := \ uptodate.o \ ver.o \ xattr.o \ + xattr_user.o \ + xattr_trusted.o ocfs2_stackglue-objs := stackglue.o ocfs2_stack_o2cb-objs := stack_o2cb.o
fs/ocfs2/file.c +5 -0
@@ -55,6 +55,7 @@#include "mmap.h" #include "suballoc.h" #include "super.h" +#include "xattr.h" #include "buffer_head_io.h"
@@ -2070,6 +2071,10 @@ const struct inode_operations ocfs2_file_iops = { .setattr = ocfs2_setattr, .getattr = ocfs2_getattr, .permission = ocfs2_permission, + .setxattr = generic_setxattr, + .getxattr = generic_getxattr, + .listxattr = ocfs2_listxattr, + .removexattr = generic_removexattr, .fallocate = ocfs2_fallocate, };
fs/ocfs2/inode.c +8 -0
@@ -49,6 +49,7 @@#include "symlink.h" #include "sysfile.h" #include "uptodate.h" +#include "xattr.h" #include "buffer_head_io.h"
@@ -730,6 +731,13 @@ static int ocfs2_wipe_inode(struct inode *inode, goto bail_unlock_dir; } +/*Free extended attribute resources associated with this inode.*/ + status =ocfs2_xattr_remove (inode, di_bh); +if (status <0 ) { +mlog_errno (status); + goto bail_unlock_dir; + } + status =ocfs2_remove_inode (inode, di_bh, orphan_dir_inode, orphan_dir_bh);if (status <0 )
fs/ocfs2/namei.c +5 -0
@@ -60,6 +60,7 @@#include "symlink.h" #include "sysfile.h" #include "uptodate.h" +#include "xattr.h" #include "buffer_head_io.h"
@@ -1918,4 +1919,8 @@ const struct inode_operations ocfs2_dir_iops = { .setattr = ocfs2_setattr, .getattr = ocfs2_getattr, .permission = ocfs2_permission, + .setxattr = generic_setxattr, + .getxattr = generic_getxattr, + .listxattr = ocfs2_listxattr, + .removexattr = generic_removexattr, };
fs/ocfs2/ocfs2.h +1 -0
@@ -172,6 +172,7 @@ enum ocfs2_mount_optionsOCFS2_MOUNT_ERRORS_PANIC =1 <<3 ,/* Panic on errors */ OCFS2_MOUNT_DATA_WRITEBACK =1 <<4 ,/* No data ordering */ OCFS2_MOUNT_LOCALFLOCKS =1 <<5 ,/* No cluster aware user file locks */ + OCFS2_MOUNT_NOUSERXATTR = 1 << 6, /* No user xattr */ };#define OCFS2_OSB_SOFT_RO 0x0001
fs/ocfs2/ocfs2_fs.h +34 -9
82 lines not on this page · raw message
fs/ocfs2/super.c +12 -0
@@ -64,6 +64,7 @@#include "sysfile.h" #include "uptodate.h" #include "ver.h" +#include "xattr.h" #include "buffer_head_io.h"
@@ -154,6 +155,8 @@ enum { Opt_localalloc, Opt_localflocks, Opt_stack, + Opt_user_xattr, + Opt_nouser_xattr, Opt_err, };
@@ -173,6 +176,8 @@ static match_table_t tokens = { {Opt_localalloc, "localalloc=%d"}, {Opt_localflocks, "localflocks"}, {Opt_stack, "cluster_stack=%s"}, + {Opt_user_xattr, "user_xattr"}, + {Opt_nouser_xattr, "nouser_xattr"}, {Opt_err, NULL} };
@@ -847,6 +852,12 @@ static int ocfs2_parse_options(struct super_block *sb,case Opt_data_writeback: mopt->mount_opt |=OCFS2_MOUNT_DATA_WRITEBACK ;break ; +case Opt_user_xattr: + mopt->mount_opt &= ~OCFS2_MOUNT_NOUSERXATTR ; +break ; +case Opt_nouser_xattr: + mopt->mount_opt |=OCFS2_MOUNT_NOUSERXATTR ; +break ;case Opt_atime_quantum:if (match_int (&args[0 ], &option)) { status =0 ;
@@ -1375,6 +1386,7 @@ static int ocfs2_initialize_super(struct super_block *sb, sb->s_fs_info = osb; sb->s_op = &ocfs2_sops; sb->s_export_op = &ocfs2_export_ops; + sb->s_xattr = ocfs2_xattr_handlers; sb->s_time_gran =1 ; sb->s_flags |=MS_NOATIME ;/* this is needed to support O_LARGEFILE */
fs/ocfs2/xattr.c +1336 -6
1,387 lines not on this page · raw message
fs/ocfs2/xattr.h +27 -0
@@ -77,6 +77,11 @@ struct ocfs2_xattr_tree_root {/*10*/ struct ocfs2_extent_list xt_list; }; +struct ocfs2_xattr_def_value_root { +struct ocfs2_xattr_value_root xv; +struct ocfs2_extent_rec er; +}; +#define OCFS2_XATTR_INDEXED 0x1struct ocfs2_xattr_block {
@@ -95,4 +100,26 @@ struct ocfs2_xattr_block { } xb_attrs; }; +extern struct xattr_handler ocfs2_xattr_user_handler; +extern struct xattr_handler ocfs2_xattr_trusted_handler; +#ifdef CONFIG_OCFS2_FS_POSIX_ACL +extern struct xattr_handler ocfs2_xattr_acl_access_handler; +extern struct xattr_handler ocfs2_xattr_acl_default_handler; +#endif +#ifdef CONFIG_OCFS2_FS_LUSTRE +extern struct xattr_handler ocfs2_xattr_lustre_handler; +#endif +#ifdef CONFIG_OCFS2_FS_SECURITY +extern struct xattr_handler ocfs2_xattr_security_handler; +#endif + +extern ssize_t ocfs2_listxattr (struct dentry *,char *,size_t ); + +extern int ocfs2_xattr_get (struct inode *,int ,const char *,void *,size_t ); +extern int ocfs2_xattr_set (struct inode *,int ,const char *,const void *, +size_t ,int ); +extern int ocfs2_xattr_remove (struct inode *inode,struct buffer_head *di_bh); + +extern struct xattr_handler *ocfs2_xattr_handlers[]; +#endif /* OCFS2_XATTR_H */
fs/ocfs2/xattr_trusted.c new file +79 -0
79 lines not on this page · raw message
fs/ocfs2/xattr_user.c new file +91 -0
91 lines not on this page · raw message
Signature · 1 line
1.5.4.4
PATCH 1/8 Modify ocfs2_num_free_extents for future xattr usage.v1
In reply to Tao Maocfs2_num_free_extents is used to find the free extent record number. The old parameter is "ocfs2_dinode", and it isn't suitable for xattr_value. So change it to "buffer_head *". ocfs2_lock_allocator is also modified in this patch because we need "buffer_head *" to call ocfs2_num_free_extents.
--- fs/ocfs2/alloc.c | 3 ++- fs/ocfs2/alloc.h | 2 +- fs/ocfs2/aops.c | 5 +++-- fs/ocfs2/dir.c | 3 ++- fs/ocfs2/file.c | 11 ++++++----- fs/ocfs2/file.h | 2 +- 6 files changed, 15 insertions(+), 11 deletions(-)
fs/ocfs2/alloc.c +2 -1
@@ -368,12 +368,13 @@ struct ocfs2_merge_ctxt {*/ int ocfs2_num_free_extents (struct ocfs2_super *osb,struct inode *inode, -struct ocfs2_dinode *fe) +struct buffer_head *bh) {int retval;struct ocfs2_extent_list *el;struct ocfs2_extent_block *eb;struct buffer_head *eb_bh =NULL ; +struct ocfs2_dinode *fe = (struct ocfs2_dinode *)bh->b_data;mlog_entry_void ();
fs/ocfs2/alloc.h +1 -1
@@ -47,7 +47,7 @@ int ocfs2_remove_extent(struct inode *inode, struct buffer_head *di_bh, struct ocfs2_cached_dealloc_ctxt *dealloc);int ocfs2_num_free_extents (struct ocfs2_super *osb,struct inode *inode, -struct ocfs2_dinode *fe); +struct buffer_head *bh);/* how many new metadata chunks would an allocation need at maximum? */ static inline int ocfs2_extend_meta_needed (struct ocfs2_dinode *fe) {
fs/ocfs2/aops.c +3 -2
@@ -1702,8 +1702,9 @@ int ocfs2_write_begin_nolock(struct address_space *mapping,* ocfs2_lock_allocators(). It greatly over-estimates * the work to be done. */ - ret =ocfs2_lock_allocators (inode, di, clusters_to_alloc, - extents_to_split, &data_ac, &meta_ac); + ret =ocfs2_lock_allocators (inode, wc->w_di_bh, + clusters_to_alloc, extents_to_split, + &data_ac, &meta_ac);if (ret) {mlog_errno (ret); goto out;
fs/ocfs2/dir.c +2 -1
@@ -1474,7 +1474,8 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb,spin_lock (&OCFS2_I (dir)->ip_lock);if (dir_i_size ==ocfs2_clusters_to_bytes (sb,OCFS2_I (dir)->ip_clusters)) {spin_unlock (&OCFS2_I (dir)->ip_lock); - num_free_extents =ocfs2_num_free_extents (osb, dir, fe); + num_free_extents =ocfs2_num_free_extents (osb, dir, + parent_fe_bh);if (num_free_extents <0 ) { status = num_free_extents;mlog_errno (status);
fs/ocfs2/file.c +6 -5
@@ -521,7 +521,7 @@ int ocfs2_do_extend_allocation(struct ocfs2_super *osb,if (mark_unwritten) flags =OCFS2_EXT_UNWRITTEN ; - free_extents =ocfs2_num_free_extents (osb, inode, fe); + free_extents =ocfs2_num_free_extents (osb, inode, fe_bh);if (free_extents <0 ) { status = free_extents;mlog_errno (status);
@@ -609,7 +609,7 @@ leave:* File systems which don't support holes call this from * ocfs2_extend_allocation(). */ -int ocfs2_lock_allocators (struct inode *inode,struct ocfs2_dinode *di, +int ocfs2_lock_allocators (struct inode *inode,struct buffer_head *di_bh,u32 clusters_to_add,u32 extents_to_split,struct ocfs2_alloc_context **data_ac,struct ocfs2_alloc_context **meta_ac)
@@ -617,6 +617,7 @@ int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_dinode *di,int ret =0 , num_free_extents;unsigned int max_recs_needed = clusters_to_add +2 * extents_to_split;struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); +struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; *meta_ac =NULL ;if (data_ac)
@@ -629,7 +630,7 @@ int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_dinode *di, (unsigned long long )OCFS2_I (inode)->ip_blkno, (long long )i_size_read (inode), le32_to_cpu(di->i_clusters), clusters_to_add, extents_to_split); - num_free_extents =ocfs2_num_free_extents (osb, inode, di); + num_free_extents =ocfs2_num_free_extents (osb, inode, di_bh);if (num_free_extents <0 ) { ret = num_free_extents;mlog_errno (ret);
@@ -724,7 +725,7 @@ static int __ocfs2_extend_allocation(struct inode *inode, u32 logical_start, restart_all:BUG_ON (le32_to_cpu (fe->i_clusters) !=OCFS2_I (inode)->ip_clusters); - status =ocfs2_lock_allocators (inode, fe, clusters_to_add,0 , &data_ac, + status =ocfs2_lock_allocators (inode, bh, clusters_to_add,0 , &data_ac, &meta_ac);if (status) {mlog_errno (status);
@@ -1395,7 +1396,7 @@ static int __ocfs2_remove_inode_range(struct inode *inode,struct ocfs2_alloc_context *meta_ac =NULL ;struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; - ret =ocfs2_lock_allocators (inode, di,0 ,1 ,NULL , &meta_ac); + ret =ocfs2_lock_allocators (inode, di_bh,0 ,1 ,NULL , &meta_ac);if (ret) {mlog_errno (ret);return ret;
fs/ocfs2/file.h +1 -1
@@ -55,7 +55,7 @@ int ocfs2_do_extend_allocation(struct ocfs2_super *osb, enum ocfs2_alloc_restarted *reason_ret);int ocfs2_extend_no_holes (struct inode *inode,u64 new_i_size,u64 zero_to); -int ocfs2_lock_allocators (struct inode *inode,struct ocfs2_dinode *di, +int ocfs2_lock_allocators (struct inode *inode,struct buffer_head *fe,u32 clusters_to_add,u32 extents_to_split,struct ocfs2_alloc_context **data_ac,struct ocfs2_alloc_context **meta_ac);
Signature · 1 line
1.5.4.GIT
PATCH 2/8 Use ocfs2_extent_list instead of ocfs2_dinode.v1
In reply to Tao Maocfs2_extend_meta_needed, ocfs2_calc_extend_credits and ocfs2_reserve_new_metadata are all useful for extent tree operations. But they are all limited by using ocfs2_dinode as the parameter. Change their parameter to ocfs2_extent_list so that xattr extent list can use them.
--- fs/ocfs2/alloc.c | 3 ++- fs/ocfs2/alloc.h | 12 +++++++++--- fs/ocfs2/aops.c | 3 ++- fs/ocfs2/dir.c | 5 +++-- fs/ocfs2/file.c | 9 +++++---- fs/ocfs2/journal.h | 17 +++++++++++------ fs/ocfs2/suballoc.c | 4 ++-- fs/ocfs2/suballoc.h | 7 ++++++- 8 files changed, 40 insertions(+), 20 deletions(-)
fs/ocfs2/alloc.c +2 -1
@@ -4536,7 +4536,8 @@ static int ocfs2_split_tree(struct inode *inode, struct buffer_head *di_bh, }else rightmost_el =path_leaf_el (path); - credits += path->p_tree_depth +ocfs2_extend_meta_needed (di); + credits += path->p_tree_depth + +ocfs2_extend_meta_needed (&di->id2.i_list); ret =ocfs2_extend_trans (handle, credits);if (ret) {mlog_errno (ret);
fs/ocfs2/alloc.h +9 -3
@@ -48,8 +48,14 @@ int ocfs2_remove_extent(struct inode *inode, struct buffer_head *di_bh,int ocfs2_num_free_extents (struct ocfs2_super *osb,struct inode *inode,struct buffer_head *bh); -/* how many new metadata chunks would an allocation need at maximum? */ -static inline int ocfs2_extend_meta_needed (struct ocfs2_dinode *fe) +/* +* how many new metadata chunks would an allocation need at maximum? +* +* Please note that the caller must make sure that root_el is the root +* of extent tree. So for an inode, it should be &fe->id2.i_list. Otherwise +* the result may be wrong. +*/ +static inline int ocfs2_extend_meta_needed (struct ocfs2_extent_list *root_el) {/* * Rather than do all the work of determining how much we need
@@ -59,7 +65,7 @@ static inline int ocfs2_extend_meta_needed(struct ocfs2_dinode *fe)* new tree_depth==0 extent_block, and one block at the new * top-of-the tree. */ -return le16_to_cpu (fe->id2.i_list.l_tree_depth) +2 ; +return le16_to_cpu (root_el->l_tree_depth) +2 ; }void ocfs2_dinode_new_extent_list (struct inode *inode,struct ocfs2_dinode *di);
fs/ocfs2/aops.c +2 -1
@@ -1710,7 +1710,8 @@ int ocfs2_write_begin_nolock(struct address_space *mapping, goto out; } - credits =ocfs2_calc_extend_credits (inode->i_sb, di, + credits =ocfs2_calc_extend_credits (inode->i_sb, + &di->id2.i_list, clusters_to_alloc); }
fs/ocfs2/dir.c +3 -2
@@ -1425,6 +1425,7 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb,int credits, num_free_extents, drop_alloc_sem =0 ;loff_t dir_i_size;struct ocfs2_dinode *fe = (struct ocfs2_dinode *) parent_fe_bh->b_data; +struct ocfs2_extent_list *el = &fe->id2.i_list;struct ocfs2_alloc_context *data_ac =NULL ;struct ocfs2_alloc_context *meta_ac =NULL ;handle_t *handle =NULL ;
@@ -1483,7 +1484,7 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb, }if (!num_free_extents) { - status =ocfs2_reserve_new_metadata (osb, fe, &meta_ac); + status =ocfs2_reserve_new_metadata (osb, el, &meta_ac);if (status <0 ) {if (status != -ENOSPC )mlog_errno (status);
@@ -1498,7 +1499,7 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb, goto bail; } - credits =ocfs2_calc_extend_credits (sb, fe,1 ); + credits =ocfs2_calc_extend_credits (sb, el,1 ); }else {spin_unlock (&OCFS2_I (dir)->ip_lock); credits =OCFS2_SIMPLE_DIR_EXTEND_CREDITS ;
fs/ocfs2/file.c +5 -4
@@ -540,7 +540,7 @@ int ocfs2_do_extend_allocation(struct ocfs2_super *osb, goto leave; }else if ((!free_extents) && (ocfs2_alloc_context_bits_left (meta_ac) - <ocfs2_extend_meta_needed (fe))) { + <ocfs2_extend_meta_needed (&fe->id2.i_list))) {mlog (0 ,"filesystem is really fragmented...\n" ); status = -EAGAIN ; reason =RESTART_META ;
@@ -652,7 +652,7 @@ int ocfs2_lock_allocators(struct inode *inode, struct buffer_head *di_bh,*/ if (!num_free_extents || (ocfs2_sparse_alloc (osb) && num_free_extents < max_recs_needed)) { - ret =ocfs2_reserve_new_metadata (osb, di, meta_ac); + ret =ocfs2_reserve_new_metadata (osb, &di->id2.i_list, meta_ac);if (ret <0 ) {if (ret != -ENOSPC )mlog_errno (ret);
@@ -732,7 +732,8 @@ restart_all: goto leave; } - credits =ocfs2_calc_extend_credits (osb->sb, fe, clusters_to_add); + credits =ocfs2_calc_extend_credits (osb->sb, &fe->id2.i_list, + clusters_to_add); handle =ocfs2_start_trans (osb, credits);if (IS_ERR (handle)) { status =PTR_ERR (handle);
@@ -790,7 +791,7 @@ restarted_transaction:mlog (0 ,"restarting transaction.\n" );/* TODO: This can be more intelligent. */ credits =ocfs2_calc_extend_credits (osb->sb, - fe, + &fe->id2.i_list, clusters_to_add); status =ocfs2_extend_trans (handle, credits);if (status <0 ) {
fs/ocfs2/journal.h +11 -6
@@ -339,11 +339,16 @@ int ocfs2_journal_dirty_data(handle_t *handle,#define OCFS2_RENAME_CREDITS (3 * OCFS2_INODE_UPDATE_CREDITS + 3 \ + OCFS2_UNLINK_CREDITS) +/* +* Please note that the caller must make sure that root_el is the root +* of extent tree. So for an inode, it should be &fe->id2.i_list. Otherwise +* the result may be wrong. +*/ static inline int ocfs2_calc_extend_credits (struct super_block *sb, -struct ocfs2_dinode *fe, +struct ocfs2_extent_list *root_el,u32 bits_wanted) { -int bitmap_blocks, sysfile_bitmap_blocks, dinode_blocks; +int bitmap_blocks, sysfile_bitmap_blocks, extent_blocks;/* bitmap dinode, group desc. + relinked group. */ bitmap_blocks =OCFS2_SUBALLOC_ALLOC ;
@@ -354,16 +359,16 @@ static inline int ocfs2_calc_extend_credits(struct super_block *sb,* however many metadata chunks needed * a remaining suballoc * alloc. */ sysfile_bitmap_blocks =1 + - (OCFS2_SUBALLOC_ALLOC -1 ) *ocfs2_extend_meta_needed (fe); + (OCFS2_SUBALLOC_ALLOC -1 ) *ocfs2_extend_meta_needed (root_el);/* this does not include *new* metadata blocks, which are -* accounted for in sysfile_bitmap_blocks. fe + +* accounted for in sysfile_bitmap_blocks. root_el + * prev. last_eb_blk + blocks along edge of tree. * calc_symlink_credits passes because we just need 1 * credit for the dinode there. */ - dinode_blocks =1 +1 +le16_to_cpu (fe->id2.i_list.l_tree_depth); + extent_blocks =1 +1 +le16_to_cpu (root_el->l_tree_depth); -return bitmap_blocks + sysfile_bitmap_blocks + dinode_blocks; +return bitmap_blocks + sysfile_bitmap_blocks + extent_blocks; }static inline int ocfs2_calc_symlink_credits (struct super_block *sb)
fs/ocfs2/suballoc.c +2 -2
@@ -494,7 +494,7 @@ bail: }int ocfs2_reserve_new_metadata (struct ocfs2_super *osb, -struct ocfs2_dinode *fe, +struct ocfs2_extent_list *root_el,struct ocfs2_alloc_context **ac) {int status;
@@ -507,7 +507,7 @@ int ocfs2_reserve_new_metadata(struct ocfs2_super *osb, goto bail; } - (*ac)->ac_bits_wanted =ocfs2_extend_meta_needed (fe); + (*ac)->ac_bits_wanted =ocfs2_extend_meta_needed (root_el); (*ac)->ac_which =OCFS2_AC_USE_META ; slot = osb->slot_num; (*ac)->ac_group_search = ocfs2_block_group_search;
fs/ocfs2/suballoc.h +6 -1
@@ -59,8 +59,13 @@ static inline int ocfs2_alloc_context_bits_left(struct ocfs2_alloc_context *ac)return ac->ac_bits_wanted - ac->ac_bits_given; } +/* +* Please note that the caller must make sure that root_el is the root +* of extent tree. So for an inode, it should be &fe->id2.i_list. Otherwise +* the result may be wrong. +*/ int ocfs2_reserve_new_metadata (struct ocfs2_super *osb, -struct ocfs2_dinode *fe, +struct ocfs2_extent_list *root_el,struct ocfs2_alloc_context **ac);int ocfs2_reserve_new_inode (struct ocfs2_super *osb,struct ocfs2_alloc_context **ac);
Signature · 1 line
1.5.4.GIT
PATCH 3/8 Make ocfs2_lock_allocators generic for extent allocation.v1
In reply to Tao MaNow ocfs2_lock_allocators is localized to be only used in file extend allocation. But the whole function is useful when we want to store large EAs. So make it generic.
--- fs/ocfs2/alloc.c | 460 ++++++++++++++++++++++++++++++++------------------- fs/ocfs2/alloc.h | 23 ++- fs/ocfs2/aops.c | 11 +- fs/ocfs2/dir.c | 7 +- fs/ocfs2/file.c | 104 ++---------- fs/ocfs2/file.h | 4 - fs/ocfs2/suballoc.c | 82 +++++++++ fs/ocfs2/suballoc.h | 5 + 8 files changed, 418 insertions(+), 278 deletions(-)
fs/ocfs2/alloc.c +289 -171
@@ -49,6 +49,94 @@#include "buffer_head_io.h" +struct ocfs2_extent_tree_operations { +void (*set_last_eb_blk) (void *et,u64 blkno); +u64 (*get_last_eb_blk) (void *et); +int (*sanity_check) (struct inode *inode,void *et); +}; + +struct ocfs2_extent_tree { +enum ocfs2_extent_tree_type type; +struct ocfs2_extent_tree_operations *eops; +struct buffer_head *root_bh; +struct ocfs2_extent_list *root_el; +}; + +static void ocfs2_dinode_set_last_eb_blk (void *p,u64 blkno) +{ +struct ocfs2_extent_tree *et = (struct ocfs2_extent_tree *)p; +struct ocfs2_dinode *di = (struct ocfs2_dinode *)et->root_bh->b_data; + +BUG_ON (et->type !=OCFS2_DINODE_EXTENT ); + di->i_last_eb_blk =cpu_to_le64 (blkno); +} + +static u64 ocfs2_dinode_get_last_eb_blk (void *p) +{ +struct ocfs2_extent_tree *et = (struct ocfs2_extent_tree *)p; +struct ocfs2_dinode *di = (struct ocfs2_dinode *)et->root_bh->b_data; + +BUG_ON (et->type !=OCFS2_DINODE_EXTENT ); +return le64_to_cpu (di->i_last_eb_blk); +} + +static int ocfs2_dinode_sanity_check (struct inode *inode,void *p) +{ +int ret =0 ; +struct ocfs2_extent_tree *et = (struct ocfs2_extent_tree *)p; +struct ocfs2_dinode *di; + +BUG_ON (et->type !=OCFS2_DINODE_EXTENT ); + + di = (struct ocfs2_dinode *)et->root_bh->b_data; +if (!OCFS2_IS_VALID_DINODE (di)) { + ret = -EIO ; +ocfs2_error (inode->i_sb, +"Inode %llu has invalid path root" , + (unsigned long long )OCFS2_I (inode)->ip_blkno); + } + +return ret; +} + +static struct ocfs2_extent_tree_operations ocfs2_dinode_et_ops = { + .set_last_eb_blk = ocfs2_dinode_set_last_eb_blk, + .get_last_eb_blk = ocfs2_dinode_get_last_eb_blk, + .sanity_check = ocfs2_dinode_sanity_check, +}; + +static struct ocfs2_extent_tree * +ocfs2_new_extent_tree (struct buffer_head *bh, +enum ocfs2_extent_tree_type et_type) +{ +struct ocfs2_extent_tree *et; + + et =kzalloc (sizeof (*et),GFP_NOFS ); +if (!et) +return NULL ; + + et->type = et_type; +get_bh (bh); + et->root_bh = bh; + +/* current we only support dinode extent. */ +BUG_ON (et->type !=OCFS2_DINODE_EXTENT ); +if (et_type ==OCFS2_DINODE_EXTENT ) { + et->root_el = &((struct ocfs2_dinode *)bh->b_data)->id2.i_list; + et->eops = &ocfs2_dinode_et_ops; + } + +return et; +} + +static void ocfs2_free_extent_tree (struct ocfs2_extent_tree *et) +{ +if (et) { +brelse (et->root_bh); +kfree (et); + } +} +static void ocfs2_free_truncate_context (struct ocfs2_truncate_context *tc);static int ocfs2_cache_extent_block_free (struct ocfs2_cached_dealloc_ctxt *ctxt,struct ocfs2_extent_block *eb);
@@ -205,17 +293,6 @@ static struct ocfs2_path *ocfs2_new_path(struct buffer_head *root_bh, }/* -* Allocate and initialize a new path based on a disk inode tree. -*/ -static struct ocfs2_path *ocfs2_new_inode_path (struct buffer_head *di_bh) -{ -struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; -struct ocfs2_extent_list *el = &di->id2.i_list; - -return ocfs2_new_path (di_bh, el); -} - -/* * Convenience function to journal all components in a path. */ static int ocfs2_journal_access_path(struct inode *inode, handle_t *handle,
@@ -368,24 +445,33 @@ struct ocfs2_merge_ctxt {*/ int ocfs2_num_free_extents (struct ocfs2_super *osb,struct inode *inode, -struct buffer_head *bh) +struct buffer_head *root_bh, +enum ocfs2_extent_tree_type type) {int retval; -struct ocfs2_extent_list *el; +struct ocfs2_extent_list *el =NULL ;struct ocfs2_extent_block *eb;struct buffer_head *eb_bh =NULL ; -struct ocfs2_dinode *fe = (struct ocfs2_dinode *)bh->b_data; +u64 last_eb_blk =0 ;mlog_entry_void (); -if (!OCFS2_IS_VALID_DINODE (fe)) { -OCFS2_RO_ON_INVALID_DINODE (inode->i_sb, fe); - retval = -EIO ; - goto bail; +if (type ==OCFS2_DINODE_EXTENT ) { +struct ocfs2_dinode *fe = + (struct ocfs2_dinode *)root_bh->b_data; +if (!OCFS2_IS_VALID_DINODE (fe)) { +OCFS2_RO_ON_INVALID_DINODE (inode->i_sb, fe); + retval = -EIO ; + goto bail; + } + +if (fe->i_last_eb_blk) + last_eb_blk =le64_to_cpu (fe->i_last_eb_blk); + el = &fe->id2.i_list; } -if (fe->i_last_eb_blk) { - retval =ocfs2_read_block (osb,le64_to_cpu (fe->i_last_eb_blk), +if (last_eb_blk) { + retval =ocfs2_read_block (osb, last_eb_blk, &eb_bh,OCFS2_BH_CACHED , inode);if (retval <0 ) {mlog_errno (retval);
@@ -393,8 +479,7 @@ int ocfs2_num_free_extents(struct ocfs2_super *osb, } eb = (struct ocfs2_extent_block *) eb_bh->b_data; el = &eb->h_list; - }else - el = &fe->id2.i_list; + }BUG_ON (el->l_tree_depth !=0 );
@@ -532,7 +617,7 @@ static inline u32 ocfs2_sum_rightmost_rec(struct ocfs2_extent_list *el)static int ocfs2_add_branch (struct ocfs2_super *osb,handle_t *handle,struct inode *inode, -struct buffer_head *fe_bh, +struct ocfs2_extent_tree *et,struct buffer_head *eb_bh,struct buffer_head **last_eb_bh,struct ocfs2_alloc_context *meta_ac)
@@ -541,7 +626,6 @@ static int ocfs2_add_branch(struct ocfs2_super *osb,u64 next_blkno, new_last_eb_blk;struct buffer_head *bh;struct buffer_head **new_eb_bhs =NULL ; -struct ocfs2_dinode *fe;struct ocfs2_extent_block *eb;struct ocfs2_extent_list *eb_el;struct ocfs2_extent_list *el;
@@ -551,13 +635,11 @@ static int ocfs2_add_branch(struct ocfs2_super *osb,BUG_ON (!last_eb_bh || !*last_eb_bh); - fe = (struct ocfs2_dinode *) fe_bh->b_data; -if (eb_bh) { eb = (struct ocfs2_extent_block *) eb_bh->b_data; el = &eb->h_list; }else - el = &fe->id2.i_list; + el = et->root_el;/* we never add a branch to a leaf. */ BUG_ON (!el->l_tree_depth);
@@ -647,7 +729,7 @@ static int ocfs2_add_branch(struct ocfs2_super *osb,mlog_errno (status); goto bail; } - status =ocfs2_journal_access (handle, inode, fe_bh, + status =ocfs2_journal_access (handle, inode, et->root_bh,OCFS2_JOURNAL_ACCESS_WRITE );if (status <0 ) {mlog_errno (status);
@@ -663,7 +745,7 @@ static int ocfs2_add_branch(struct ocfs2_super *osb, }/* Link the new branch into the rest of the tree (el will -* either be on the fe, or the extent block passed in. */ +* either be on the root_bh, or the extent block passed in. */ i =le16_to_cpu (el->l_next_free_rec); el->l_recs[i].e_blkno =cpu_to_le64 (next_blkno); el->l_recs[i].e_cpos =cpu_to_le32 (new_cpos);
@@ -672,7 +754,7 @@ static int ocfs2_add_branch(struct ocfs2_super *osb,/* fe needs a new last extent block pointer, as does the * next_leaf on the previously last-extent-block. */ - fe->i_last_eb_blk =cpu_to_le64 (new_last_eb_blk); + et->eops->set_last_eb_blk (et, new_last_eb_blk); eb = (struct ocfs2_extent_block *) (*last_eb_bh)->b_data; eb->h_next_leaf_blk =cpu_to_le64 (new_last_eb_blk);
@@ -680,7 +762,7 @@ static int ocfs2_add_branch(struct ocfs2_super *osb, status =ocfs2_journal_dirty (handle, *last_eb_bh);if (status <0 )mlog_errno (status); - status =ocfs2_journal_dirty (handle, fe_bh); + status =ocfs2_journal_dirty (handle, et->root_bh);if (status <0 )mlog_errno (status);if (eb_bh) {
@@ -718,16 +800,15 @@ bail:static int ocfs2_shift_tree_depth (struct ocfs2_super *osb,handle_t *handle,struct inode *inode, -struct buffer_head *fe_bh, +struct ocfs2_extent_tree *et,struct ocfs2_alloc_context *meta_ac,struct buffer_head **ret_new_eb_bh) {int status, i;u32 new_clusters;struct buffer_head *new_eb_bh =NULL ; -struct ocfs2_dinode *fe;struct ocfs2_extent_block *eb; -struct ocfs2_extent_list *fe_el; +struct ocfs2_extent_list *root_el;struct ocfs2_extent_list *eb_el;mlog_entry_void ();
@@ -747,8 +828,7 @@ static int ocfs2_shift_tree_depth(struct ocfs2_super *osb, } eb_el = &eb->h_list; - fe = (struct ocfs2_dinode *) fe_bh->b_data; - fe_el = &fe->id2.i_list; + root_el = et->root_el; status =ocfs2_journal_access (handle, inode, new_eb_bh,OCFS2_JOURNAL_ACCESS_CREATE );
@@ -757,11 +837,11 @@ static int ocfs2_shift_tree_depth(struct ocfs2_super *osb, goto bail; } -/* copy the fe data into the new extent block */ - eb_el->l_tree_depth = fe_el->l_tree_depth; - eb_el->l_next_free_rec = fe_el->l_next_free_rec; -for (i =0 ; i <le16_to_cpu (fe_el->l_next_free_rec); i++) - eb_el->l_recs[i] = fe_el->l_recs[i]; +/* copy the root extent list data into the new extent block */ + eb_el->l_tree_depth = root_el->l_tree_depth; + eb_el->l_next_free_rec = root_el->l_next_free_rec; +for (i =0 ; i <le16_to_cpu (root_el->l_next_free_rec); i++) + eb_el->l_recs[i] = root_el->l_recs[i]; status =ocfs2_journal_dirty (handle, new_eb_bh);if (status <0 ) {
@@ -769,7 +849,7 @@ static int ocfs2_shift_tree_depth(struct ocfs2_super *osb, goto bail; } - status =ocfs2_journal_access (handle, inode, fe_bh, + status =ocfs2_journal_access (handle, inode, et->root_bh,OCFS2_JOURNAL_ACCESS_WRITE );if (status <0 ) {mlog_errno (status);
@@ -778,21 +858,21 @@ static int ocfs2_shift_tree_depth(struct ocfs2_super *osb, new_clusters =ocfs2_sum_rightmost_rec (eb_el); -/* update fe now */ -le16_add_cpu (&fe_el->l_tree_depth,1 ); - fe_el->l_recs[0 ].e_cpos =0 ; - fe_el->l_recs[0 ].e_blkno = eb->h_blkno; - fe_el->l_recs[0 ].e_int_clusters =cpu_to_le32 (new_clusters); -for (i =1 ; i <le16_to_cpu (fe_el->l_next_free_rec); i++) -memset (&fe_el->l_recs[i],0 ,sizeof (struct ocfs2_extent_rec )); - fe_el->l_next_free_rec =cpu_to_le16 (1 ); +/* update root_bh now */ +le16_add_cpu (&root_el->l_tree_depth,1 ); + root_el->l_recs[0 ].e_cpos =0 ; + root_el->l_recs[0 ].e_blkno = eb->h_blkno; + root_el->l_recs[0 ].e_int_clusters =cpu_to_le32 (new_clusters); +for (i =1 ; i <le16_to_cpu (root_el->l_next_free_rec); i++) +memset (&root_el->l_recs[i],0 ,sizeof (struct ocfs2_extent_rec )); + root_el->l_next_free_rec =cpu_to_le16 (1 );/* If this is our 1st tree depth shift, then last_eb_blk * becomes the allocated extent block */ -if (fe_el->l_tree_depth ==cpu_to_le16 (1 )) - fe->i_last_eb_blk = eb->h_blkno; +if (root_el->l_tree_depth ==cpu_to_le16 (1 )) + et->eops->set_last_eb_blk (et,le64_to_cpu (eb->h_blkno)); - status =ocfs2_journal_dirty (handle, fe_bh); + status =ocfs2_journal_dirty (handle, et->root_bh);if (status <0 ) {mlog_errno (status); goto bail;
@@ -818,22 +898,21 @@ bail:* 1) a lowest extent block is found, then we pass it back in * *lowest_eb_bh and return '0' * -* 2) the search fails to find anything, but the dinode has room. We +* 2) the search fails to find anything, but the root_el has room. We * pass NULL back in *lowest_eb_bh, but still return '0' * -* 3) the search fails to find anything AND the dinode is full, in +* 3) the search fails to find anything AND the root_el is full, in * which case we return > 0 * * return status < 0 indicates an error. */ static int ocfs2_find_branch_target (struct ocfs2_super *osb,struct inode *inode, -struct buffer_head *fe_bh, +struct ocfs2_extent_tree *et,struct buffer_head **target_bh) {int status =0 , i;u64 blkno; -struct ocfs2_dinode *fe;struct ocfs2_extent_block *eb;struct ocfs2_extent_list *el;struct buffer_head *bh =NULL ;
@@ -843,8 +922,7 @@ static int ocfs2_find_branch_target(struct ocfs2_super *osb, *target_bh =NULL ; - fe = (struct ocfs2_dinode *) fe_bh->b_data; - el = &fe->id2.i_list; + el = et->root_el;while (le16_to_cpu (el->l_tree_depth) >1 ) {if (le16_to_cpu (el->l_next_free_rec) ==0 ) {
@@ -896,8 +974,8 @@ static int ocfs2_find_branch_target(struct ocfs2_super *osb,/* If we didn't find one and the fe doesn't have any room, * then return '1' */ -if (!lowest_bh - && (fe->id2.i_list.l_next_free_rec == fe->id2.i_list.l_count)) + el = et->root_el; +if (!lowest_bh && (el->l_next_free_rec == el->l_count)) status =1 ; *target_bh = lowest_bh;
@@ -920,19 +998,19 @@ bail:* *last_eb_bh will be updated by ocfs2_add_branch(). */ static int ocfs2_grow_tree (struct inode *inode,handle_t *handle, -struct buffer_head *di_bh,int *final_depth, +struct ocfs2_extent_tree *et,int *final_depth,struct buffer_head **last_eb_bh,struct ocfs2_alloc_context *meta_ac) {int ret, shift; -struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; -int depth =le16_to_cpu (di->id2.i_list.l_tree_depth); +struct ocfs2_extent_list *el = et->root_el; +int depth =le16_to_cpu (el->l_tree_depth);struct ocfs2_super *osb =OCFS2_SB (inode->i_sb);struct buffer_head *bh =NULL ;BUG_ON (meta_ac ==NULL ); - shift =ocfs2_find_branch_target (osb, inode, di_bh, &bh); + shift =ocfs2_find_branch_target (osb, inode, et, &bh);if (shift <0 ) { ret = shift;mlog_errno (ret);
@@ -949,7 +1027,7 @@ static int ocfs2_grow_tree(struct inode *inode, handle_t *handle,/* ocfs2_shift_tree_depth will return us a buffer with * the new extent block (so we can pass that to * ocfs2_add_branch). */ - ret =ocfs2_shift_tree_depth (osb, handle, inode, di_bh, + ret =ocfs2_shift_tree_depth (osb, handle, inode, et, meta_ac, &bh);if (ret <0 ) {mlog_errno (ret);
@@ -976,7 +1054,7 @@ static int ocfs2_grow_tree(struct inode *inode, handle_t *handle,/* call ocfs2_add_branch to add the final part of the tree with * the new data. */ mlog (0 ,"add branch. bh = %p\n" , bh); - ret =ocfs2_add_branch (osb, handle, inode, di_bh, bh, last_eb_bh, + ret =ocfs2_add_branch (osb, handle, inode, et, bh, last_eb_bh, meta_ac);if (ret <0 ) {mlog_errno (ret);
@@ -2068,11 +2146,11 @@ static int ocfs2_rotate_subtree_left(struct inode *inode, handle_t *handle,struct ocfs2_path *right_path, int subtree_index, struct ocfs2_cached_dealloc_ctxt *dealloc, - int *deleted) + int *deleted, + struct ocfs2_extent_tree *et) { int ret, i, del_right_subtree = 0, right_has_empty = 0; -struct buffer_head *root_bh, *di_bh =path_root_bh (right_path); -struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; +struct buffer_head *root_bh, *et_root_bh =path_root_bh (right_path);struct ocfs2_extent_list *right_leaf_el, *left_leaf_el;struct ocfs2_extent_block *eb;
@@ -2124,7 +2202,7 @@ static int ocfs2_rotate_subtree_left(struct inode *inode, handle_t *handle,* We have to update i_last_eb_blk during the meta * data delete. */ - ret =ocfs2_journal_access (handle, inode, di_bh, + ret =ocfs2_journal_access (handle, inode, et_root_bh,OCFS2_JOURNAL_ACCESS_WRITE );if (ret) {mlog_errno (ret);
@@ -2199,7 +2277,7 @@ static int ocfs2_rotate_subtree_left(struct inode *inode, handle_t *handle,ocfs2_update_edge_lengths (inode, handle, left_path); eb = (struct ocfs2_extent_block *)path_leaf_bh (left_path)->b_data; - di->i_last_eb_blk = eb->h_blkno; + et->eops->set_last_eb_blk (et,le64_to_cpu (eb->h_blkno));/* * Removal of the extent in the left leaf was skipped
@@ -2209,7 +2287,7 @@ static int ocfs2_rotate_subtree_left(struct inode *inode, handle_t *handle,if (right_has_empty)ocfs2_remove_empty_extent (left_leaf_el); - ret =ocfs2_journal_dirty (handle, di_bh); + ret =ocfs2_journal_dirty (handle, et_root_bh);if (ret)mlog_errno (ret);
@@ -2332,7 +2410,8 @@ static int __ocfs2_rotate_tree_left(struct inode *inode, handle_t *handle, int orig_credits, struct ocfs2_path *path, struct ocfs2_cached_dealloc_ctxt *dealloc, - struct ocfs2_path **empty_extent_path) + struct ocfs2_path **empty_extent_path, + struct ocfs2_extent_tree *et) { int ret, subtree_root, deleted;u32 right_cpos;
@@ -2405,7 +2484,7 @@ static int __ocfs2_rotate_tree_left(struct inode *inode, ret =ocfs2_rotate_subtree_left (inode, handle, left_path, right_path, subtree_root, - dealloc, &deleted); + dealloc, &deleted, et);if (ret == -EAGAIN ) {/* * The rotation has to temporarily stop due to
@@ -2448,29 +2527,20 @@ out: }static int ocfs2_remove_rightmost_path (struct inode *inode,handle_t *handle, -struct ocfs2_path *path, -struct ocfs2_cached_dealloc_ctxt *dealloc) +struct ocfs2_path *path, +struct ocfs2_cached_dealloc_ctxt *dealloc, +struct ocfs2_extent_tree *et) {int ret, subtree_index;u32 cpos;struct ocfs2_path *left_path =NULL ; -struct ocfs2_dinode *di;struct ocfs2_extent_block *eb;struct ocfs2_extent_list *el; -/* -* XXX: This code assumes that the root is an inode, which is -* true for now but may change as tree code gets generic. -*/ - di = (struct ocfs2_dinode *)path_root_bh (path)->b_data; -if (!OCFS2_IS_VALID_DINODE (di)) { - ret = -EIO ; -ocfs2_error (inode->i_sb, -"Inode %llu has invalid path root" , - (unsigned long long )OCFS2_I (inode)->ip_blkno); - goto out; - } + ret = et->eops->sanity_check (inode, et); +if (ret) + goto out;/* * There's two ways we handle this depending on * whether path is the only existing one.
@@ -2527,7 +2597,7 @@ static int ocfs2_remove_rightmost_path(struct inode *inode, handle_t *handle,ocfs2_update_edge_lengths (inode, handle, left_path); eb = (struct ocfs2_extent_block *)path_leaf_bh (left_path)->b_data; - di->i_last_eb_blk = eb->h_blkno; + et->eops->set_last_eb_blk (et,le64_to_cpu (eb->h_blkno)); }else {/* * 'path' is also the leftmost path which
@@ -2538,12 +2608,12 @@ static int ocfs2_remove_rightmost_path(struct inode *inode, handle_t *handle,*/ ocfs2_unlink_path (inode, handle, dealloc, path,1 ); - el = &di->id2.i_list; + el = et->root_el; el->l_tree_depth =0 ; el->l_next_free_rec =0 ;memset (&el->l_recs[0 ],0 ,sizeof (struct ocfs2_extent_rec )); - di->i_last_eb_blk =0 ; + et->eops->set_last_eb_blk (et,0 ); }ocfs2_journal_dirty (handle,path_root_bh (path));
@@ -2571,7 +2641,8 @@ out:*/ static int ocfs2_rotate_tree_left (struct inode *inode,handle_t *handle,struct ocfs2_path *path, -struct ocfs2_cached_dealloc_ctxt *dealloc) +struct ocfs2_cached_dealloc_ctxt *dealloc, +struct ocfs2_extent_tree *et) {int ret, orig_credits = handle->h_buffer_credits;struct ocfs2_path *tmp_path =NULL , *restart_path =NULL ;
@@ -2585,7 +2656,7 @@ static int ocfs2_rotate_tree_left(struct inode *inode, handle_t *handle,if (path->p_tree_depth ==0 ) { rightmost_no_delete:/* -* In-inode extents. This is trivially handled, so do +* Inline extents. This is trivially handled, so do * it up front. */ ret = ocfs2_rotate_rightmost_leaf_left(inode, handle,
@@ -2639,7 +2710,7 @@ rightmost_no_delete:*/ ret =ocfs2_remove_rightmost_path (inode, handle, path, - dealloc); + dealloc, et);if (ret)mlog_errno (ret); goto out;
@@ -2651,7 +2722,7 @@ rightmost_no_delete:*/ try_rotate: ret =__ocfs2_rotate_tree_left (inode, handle, orig_credits, path, - dealloc, &restart_path); + dealloc, &restart_path, et);if (ret && ret != -EAGAIN ) {mlog_errno (ret); goto out;
@@ -2663,7 +2734,7 @@ try_rotate: ret =__ocfs2_rotate_tree_left (inode, handle, orig_credits, tmp_path, dealloc, - &restart_path); + &restart_path, et);if (ret && ret != -EAGAIN ) {mlog_errno (ret); goto out;
@@ -2949,6 +3020,7 @@ static int ocfs2_merge_rec_left(struct inode *inode,handle_t *handle, struct ocfs2_extent_rec *split_rec, struct ocfs2_cached_dealloc_ctxt *dealloc, + struct ocfs2_extent_tree *et, int index) { int ret, i, subtree_index = 0, has_empty_extent = 0;
@@ -3069,7 +3141,8 @@ static int ocfs2_merge_rec_left(struct inode *inode, le16_to_cpu(el->l_next_free_rec) == 1) { ret =ocfs2_remove_rightmost_path (inode, handle, - right_path, dealloc); + right_path, + dealloc, et);if (ret) {mlog_errno (ret); goto out;
@@ -3096,7 +3169,8 @@ static int ocfs2_try_to_merge_extent(struct inode *inode,int split_index, struct ocfs2_extent_rec *split_rec, struct ocfs2_cached_dealloc_ctxt *dealloc, - struct ocfs2_merge_ctxt *ctxt) + struct ocfs2_merge_ctxt *ctxt, + struct ocfs2_extent_tree *et) { int ret = 0;
@@ -3114,7 +3188,7 @@ static int ocfs2_try_to_merge_extent(struct inode *inode,* illegal. */ ret =ocfs2_rotate_tree_left (inode, handle, path, - dealloc); + dealloc, et);if (ret) {mlog_errno (ret); goto out;
@@ -3157,7 +3231,8 @@ static int ocfs2_try_to_merge_extent(struct inode *inode,BUG_ON (!ocfs2_is_empty_extent (&el->l_recs[0 ]));/* The merge left us with an empty extent, remove it. */ - ret =ocfs2_rotate_tree_left (inode, handle, path, dealloc); + ret =ocfs2_rotate_tree_left (inode, handle, path, + dealloc, et);if (ret) {mlog_errno (ret); goto out;
@@ -3171,7 +3246,7 @@ static int ocfs2_try_to_merge_extent(struct inode *inode,*/ ret =ocfs2_merge_rec_left (inode, path, handle, rec, - dealloc, + dealloc, et, split_index);if (ret) {
@@ -3180,7 +3255,7 @@ static int ocfs2_try_to_merge_extent(struct inode *inode, } ret =ocfs2_rotate_tree_left (inode, handle, path, - dealloc); + dealloc, et);/* * Error from this last rotate is not critical, so * print but don't bubble it up.
@@ -3200,7 +3275,7 @@ static int ocfs2_try_to_merge_extent(struct inode *inode, ret =ocfs2_merge_rec_left (inode, path, handle, split_rec, - dealloc, + dealloc, et, split_index);if (ret) {mlog_errno (ret);
@@ -3223,7 +3298,7 @@ static int ocfs2_try_to_merge_extent(struct inode *inode,* our leaf. Try to rotate it away. */ ret =ocfs2_rotate_tree_left (inode, handle, path, - dealloc); + dealloc, et);if (ret)mlog_errno (ret); ret =0 ;
@@ -3367,6 +3442,17 @@ static inline void ocfs2_update_dinode_clusters(struct inode *inode,spin_unlock (&OCFS2_I (inode)->ip_lock); } +static void ocfs2_update_clusters (struct inode *inode, +struct ocfs2_extent_tree *et, +u32 clusters) +{ +if (et->type ==OCFS2_DINODE_EXTENT ) { +struct ocfs2_dinode *di = + (struct ocfs2_dinode *)et->root_bh->b_data; +ocfs2_update_dinode_clusters (inode, di, clusters); + } +} + static void ocfs2_adjust_rightmost_records(struct inode *inode, handle_t *handle, struct ocfs2_path *path,
@@ -3568,8 +3654,8 @@ static void ocfs2_split_record(struct inode *inode, }/* -* This function only does inserts on an allocation b-tree. For dinode -* lists, ocfs2_insert_at_leaf() is called directly. +* This function only does inserts on an allocation b-tree. For tree +* depth = 0, ocfs2_insert_at_leaf() is called directly. * * right_path is the path we want to do the actual insert * in. left_path should only be passed in if we need to update that
@@ -3666,7 +3752,7 @@ out:static int ocfs2_do_insert_extent (struct inode *inode,handle_t *handle, -struct buffer_head *di_bh, +struct ocfs2_extent_tree *et,struct ocfs2_extent_rec *insert_rec,struct ocfs2_insert_type *type) {
@@ -3674,13 +3760,11 @@ static int ocfs2_do_insert_extent(struct inode *inode,u32 cpos;struct ocfs2_path *right_path =NULL ;struct ocfs2_path *left_path =NULL ; -struct ocfs2_dinode *di;struct ocfs2_extent_list *el; - di = (struct ocfs2_dinode *) di_bh->b_data; - el = &di->id2.i_list; + el = et->root_el; - ret =ocfs2_journal_access (handle, inode, di_bh, + ret =ocfs2_journal_access (handle, inode, et->root_bh,OCFS2_JOURNAL_ACCESS_WRITE );if (ret) {mlog_errno (ret);
@@ -3692,7 +3776,7 @@ static int ocfs2_do_insert_extent(struct inode *inode, goto out_update_clusters; } - right_path =ocfs2_new_inode_path (di_bh); + right_path =ocfs2_new_path (et->root_bh, et->root_el);if (!right_path) { ret = -ENOMEM ;mlog_errno (ret);
@@ -3742,7 +3826,7 @@ static int ocfs2_do_insert_extent(struct inode *inode,* ocfs2_rotate_tree_right() might have extended the * transaction without re-journaling our tree root. */ - ret =ocfs2_journal_access (handle, inode, di_bh, + ret =ocfs2_journal_access (handle, inode, et->root_bh,OCFS2_JOURNAL_ACCESS_WRITE );if (ret) {mlog_errno (ret);
@@ -3767,10 +3851,10 @@ static int ocfs2_do_insert_extent(struct inode *inode, out_update_clusters:if (type->ins_split ==SPLIT_NONE ) -ocfs2_update_dinode_clusters (inode, di, -le16_to_cpu (insert_rec->e_leaf_clusters)); +ocfs2_update_clusters (inode, et, +le16_to_cpu (insert_rec->e_leaf_clusters)); - ret =ocfs2_journal_dirty (handle, di_bh); + ret =ocfs2_journal_dirty (handle, et->root_bh);if (ret)mlog_errno (ret);
@@ -3924,8 +4008,8 @@ static void ocfs2_figure_contig_type(struct inode *inode,* ocfs2_figure_appending_type() will figure out whether we'll have to * insert at the tail of the rightmost leaf. * -* This should also work against the dinode list for tree's with 0 -* depth. If we consider the dinode list to be the rightmost leaf node +* This should also work against the root extent list for tree's with 0 +* depth. If we consider the root extent list to be the rightmost leaf node * then the logic here makes sense. */ static void ocfs2_figure_appending_type(struct ocfs2_insert_type *insert,
@@ -3976,14 +4060,13 @@ set_tail_append:* structure. */ static int ocfs2_figure_insert_type (struct inode *inode, -struct buffer_head *di_bh, +struct ocfs2_extent_tree *et,struct buffer_head **last_eb_bh,struct ocfs2_extent_rec *insert_rec,int *free_records,struct ocfs2_insert_type *insert) {int ret; -struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;struct ocfs2_extent_block *eb;struct ocfs2_extent_list *el;struct ocfs2_path *path =NULL ;
@@ -3991,7 +4074,7 @@ static int ocfs2_figure_insert_type(struct inode *inode, insert->ins_split =SPLIT_NONE ; - el = &di->id2.i_list; + el = et->root_el; insert->ins_tree_depth =le16_to_cpu (el->l_tree_depth);if (el->l_tree_depth) {
@@ -4002,7 +4085,7 @@ static int ocfs2_figure_insert_type(struct inode *inode,* may want it later. */ ret =ocfs2_read_block (OCFS2_SB (inode->i_sb), -le64_to_cpu (di->i_last_eb_blk), &bh, + et->eops->get_last_eb_blk (et), &bh,OCFS2_BH_CACHED , inode);if (ret) {mlog_exit (ret);
@@ -4029,7 +4112,7 @@ static int ocfs2_figure_insert_type(struct inode *inode,return 0 ; } - path =ocfs2_new_inode_path (di_bh); + path =ocfs2_new_path (et->root_bh, et->root_el);if (!path) { ret = -ENOMEM ;mlog_errno (ret);
@@ -4079,7 +4162,8 @@ static int ocfs2_figure_insert_type(struct inode *inode,* the case that we're doing a tail append, so maybe we can * take advantage of that information somehow. */ -if (le64_to_cpu (di->i_last_eb_blk) ==path_leaf_bh (path)->b_blocknr) { +if (et->eops->get_last_eb_blk (et) == +path_leaf_bh (path)->b_blocknr) {/* * Ok, ocfs2_find_path() returned us the rightmost * tree path. This might be an appending insert. There are
@@ -4109,21 +4193,30 @@ out:int ocfs2_insert_extent (struct ocfs2_super *osb,handle_t *handle,struct inode *inode, -struct buffer_head *fe_bh, +struct buffer_head *root_bh,u32 cpos,u64 start_blk,u32 new_clusters,u8 flags, -struct ocfs2_alloc_context *meta_ac) +struct ocfs2_alloc_context *meta_ac, +enum ocfs2_extent_tree_type et_type) {int status;int uninitialized_var (free_records );struct buffer_head *last_eb_bh =NULL ;struct ocfs2_insert_type insert = {0 , };struct ocfs2_extent_rec rec; +struct ocfs2_extent_tree *et =NULL ;BUG_ON (OCFS2_I (inode)->ip_dyn_features &OCFS2_INLINE_DATA_FL ); + et =ocfs2_new_extent_tree (root_bh, et_type); +if (!et) { + status = -ENOMEM ; +mlog_errno (status); + goto bail; + } +mlog (0 ,"add %u clusters at position %u to inode %llu\n" , new_clusters, cpos, (unsigned long long )OCFS2_I (inode)->ip_blkno);
@@ -4141,7 +4234,7 @@ int ocfs2_insert_extent(struct ocfs2_super *osb, rec.e_leaf_clusters =cpu_to_le16 (new_clusters); rec.e_flags = flags; - status =ocfs2_figure_insert_type (inode, fe_bh, &last_eb_bh, &rec, + status =ocfs2_figure_insert_type (inode, et, &last_eb_bh, &rec, &free_records, &insert);if (status <0 ) {mlog_errno (status);
@@ -4155,7 +4248,7 @@ int ocfs2_insert_extent(struct ocfs2_super *osb, free_records, insert.ins_tree_depth);if (insert.ins_contig ==CONTIG_NONE && free_records ==0 ) { - status =ocfs2_grow_tree (inode, handle, fe_bh, + status =ocfs2_grow_tree (inode, handle, et, &insert.ins_tree_depth, &last_eb_bh, meta_ac);if (status) {
@@ -4165,16 +4258,18 @@ int ocfs2_insert_extent(struct ocfs2_super *osb, }/* Finally, we can add clusters. This might rotate the tree for us. */ - status =ocfs2_do_insert_extent (inode, handle, fe_bh, &rec, &insert); + status =ocfs2_do_insert_extent (inode, handle, et, &rec, &insert);if (status <0 )mlog_errno (status); -else +else if (et->type ==OCFS2_DINODE_EXTENT )ocfs2_extent_map_insert_rec (inode, &rec); bail:if (last_eb_bh)brelse (last_eb_bh); +if (et) +ocfs2_free_extent_tree (et);mlog_exit (status);return status; }
@@ -4202,7 +4297,7 @@ static void ocfs2_make_right_split_rec(struct super_block *sb, static int ocfs2_split_and_insert(struct inode *inode, handle_t *handle, struct ocfs2_path *path, - struct buffer_head *di_bh, + struct ocfs2_extent_tree *et, struct buffer_head **last_eb_bh, int split_index, struct ocfs2_extent_rec *orig_split_rec,
@@ -4216,7 +4311,6 @@ static int ocfs2_split_and_insert(struct inode *inode,struct ocfs2_extent_rec split_rec = *orig_split_rec;struct ocfs2_insert_type insert;struct ocfs2_extent_block *eb; -struct ocfs2_dinode *di; leftright:/*
@@ -4225,8 +4319,7 @@ leftright:*/ rec =path_leaf_el (path)->l_recs[split_index]; - di = (struct ocfs2_dinode *)di_bh->b_data; - rightmost_el = &di->id2.i_list; + rightmost_el = et->root_el; depth =le16_to_cpu (rightmost_el->l_tree_depth);if (depth) {
@@ -4237,8 +4330,8 @@ leftright:if (le16_to_cpu (rightmost_el->l_next_free_rec) ==le16_to_cpu (rightmost_el->l_count)) { - ret =ocfs2_grow_tree (inode, handle, di_bh, &depth, last_eb_bh, - meta_ac); + ret =ocfs2_grow_tree (inode, handle, et, + &depth, last_eb_bh, meta_ac);if (ret) {mlog_errno (ret); goto out;
@@ -4275,8 +4368,7 @@ leftright: do_leftright =1 ; } - ret =ocfs2_do_insert_extent (inode, handle, di_bh, &split_rec, - &insert); + ret =ocfs2_do_insert_extent (inode, handle, et, &split_rec, &insert);if (ret) {mlog_errno (ret); goto out;
@@ -4318,8 +4410,9 @@ out:* of the tree is required. All other cases will degrade into a less * optimal tree layout. * -* last_eb_bh should be the rightmost leaf block for any inode with a -* btree. Since a split may grow the tree or a merge might shrink it, the caller cannot trust the contents of that buffer after this call. +* last_eb_bh should be the rightmost leaf block for any extent +* btree. Since a split may grow the tree or a merge might shrink it, +* the caller cannot trust the contents of that buffer after this call. * * This code is optimized for readability - several passes might be * made over certain portions of the tree. All of those blocks will
@@ -4327,7 +4420,7 @@ out:* extra overhead is not expressed in terms of disk reads. */ static int __ocfs2_mark_extent_written(struct inode *inode, - struct buffer_head *di_bh, + struct ocfs2_extent_tree *et, handle_t *handle, struct ocfs2_path *path, int split_index,
@@ -4367,10 +4460,9 @@ static int __ocfs2_mark_extent_written(struct inode *inode,*/ if (path->p_tree_depth) {struct ocfs2_extent_block *eb; -struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; ret =ocfs2_read_block (OCFS2_SB (inode->i_sb), -le64_to_cpu (di->i_last_eb_blk), + et->eops->get_last_eb_blk (et), &last_eb_bh,OCFS2_BH_CACHED , inode);if (ret) {mlog_exit (ret);
@@ -4404,7 +4496,7 @@ static int __ocfs2_mark_extent_written(struct inode *inode,if (ctxt.c_split_covers_rec) el->l_recs[split_index] = *split_rec;else - ret =ocfs2_split_and_insert (inode, handle, path, di_bh, + ret =ocfs2_split_and_insert (inode, handle, path, et, &last_eb_bh, split_index, split_rec, meta_ac);if (ret)
@@ -4412,7 +4504,7 @@ static int __ocfs2_mark_extent_written(struct inode *inode, }else { ret =ocfs2_try_to_merge_extent (inode, handle, path, split_index, split_rec, - dealloc, &ctxt); + dealloc, &ctxt, et);if (ret)mlog_errno (ret); }
@@ -4430,16 +4522,18 @@ out:* * The caller is responsible for passing down meta_ac if we'll need it. */ -int ocfs2_mark_extent_written (struct inode *inode,struct buffer_head *di_bh, +int ocfs2_mark_extent_written (struct inode *inode,struct buffer_head *root_bh,handle_t *handle,u32 cpos,u32 len,u32 phys,struct ocfs2_alloc_context *meta_ac, -struct ocfs2_cached_dealloc_ctxt *dealloc) +struct ocfs2_cached_dealloc_ctxt *dealloc, +enum ocfs2_extent_tree_type et_type) {int ret, index;u64 start_blkno =ocfs2_clusters_to_blocks (inode->i_sb, phys);struct ocfs2_extent_rec split_rec;struct ocfs2_path *left_path =NULL ;struct ocfs2_extent_list *el; +struct ocfs2_extent_tree *et =NULL ;mlog (0 ,"Inode %lu cpos %u, len %u, phys %u (%llu)\n" , inode->i_ino, cpos, len, phys, (unsigned long long )start_blkno);
@@ -4453,13 +4547,21 @@ int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *di_bh, goto out; } + et =ocfs2_new_extent_tree (root_bh, et_type); +if (!et) { + ret = -ENOMEM ; +mlog_errno (ret); + goto out; + } +/* * XXX: This should be fixed up so that we just re-insert the * next extent records. */ -ocfs2_extent_map_trunc (inode,0 ); +if (et_type ==OCFS2_DINODE_EXTENT ) +ocfs2_extent_map_trunc (inode,0 ); - left_path =ocfs2_new_inode_path (di_bh); + left_path =ocfs2_new_path (et->root_bh, et->root_el);if (!left_path) { ret = -ENOMEM ;mlog_errno (ret);
@@ -4490,23 +4592,25 @@ int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *di_bh, split_rec.e_flags =path_leaf_el (left_path)->l_recs[index].e_flags; split_rec.e_flags &= ~OCFS2_EXT_UNWRITTEN ; - ret =__ocfs2_mark_extent_written (inode, di_bh, handle, left_path, - index, &split_rec, meta_ac, dealloc); + ret =__ocfs2_mark_extent_written (inode, et, handle, left_path, + index, &split_rec, meta_ac, + dealloc);if (ret)mlog_errno (ret); out:ocfs2_free_path (left_path); +if (et) +ocfs2_free_extent_tree (et);return ret; } -static int ocfs2_split_tree (struct inode *inode,struct buffer_head *di_bh, +static int ocfs2_split_tree (struct inode *inode,struct ocfs2_extent_tree *et,handle_t *handle,struct ocfs2_path *path,int index,u32 new_range,struct ocfs2_alloc_context *meta_ac) {int ret, depth, credits = handle->h_buffer_credits; -struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;struct buffer_head *last_eb_bh =NULL ;struct ocfs2_extent_block *eb;struct ocfs2_extent_list *rightmost_el, *el;
@@ -4524,7 +4628,7 @@ static int ocfs2_split_tree(struct inode *inode, struct buffer_head *di_bh, depth = path->p_tree_depth;if (depth >0 ) { ret =ocfs2_read_block (OCFS2_SB (inode->i_sb), -le64_to_cpu (di->i_last_eb_blk), + et->eops->get_last_eb_blk (et), &last_eb_bh,OCFS2_BH_CACHED , inode);if (ret <0 ) {mlog_errno (ret);
@@ -4537,7 +4641,7 @@ static int ocfs2_split_tree(struct inode *inode, struct buffer_head *di_bh, rightmost_el =path_leaf_el (path); credits += path->p_tree_depth + -ocfs2_extend_meta_needed (&di->id2.i_list); +ocfs2_extend_meta_needed (et->root_el); ret =ocfs2_extend_trans (handle, credits);if (ret) {mlog_errno (ret);
@@ -4546,7 +4650,7 @@ static int ocfs2_split_tree(struct inode *inode, struct buffer_head *di_bh,if (le16_to_cpu (rightmost_el->l_next_free_rec) ==le16_to_cpu (rightmost_el->l_count)) { - ret =ocfs2_grow_tree (inode, handle, di_bh, &depth, &last_eb_bh, + ret =ocfs2_grow_tree (inode, handle, et, &depth, &last_eb_bh, meta_ac);if (ret) {mlog_errno (ret);
@@ -4560,7 +4664,7 @@ static int ocfs2_split_tree(struct inode *inode, struct buffer_head *di_bh, insert.ins_split =SPLIT_RIGHT ; insert.ins_tree_depth = depth; - ret =ocfs2_do_insert_extent (inode, handle, di_bh, &split_rec, &insert); + ret =ocfs2_do_insert_extent (inode, handle, et, &split_rec, &insert);if (ret)mlog_errno (ret);
@@ -4572,7 +4676,8 @@ out:static int ocfs2_truncate_rec (struct inode *inode,handle_t *handle,struct ocfs2_path *path,int index,struct ocfs2_cached_dealloc_ctxt *dealloc, -u32 cpos,u32 len) +u32 cpos,u32 len, +struct ocfs2_extent_tree *et) {int ret;u32 left_cpos, rec_range, trunc_range;
@@ -4584,7 +4689,7 @@ static int ocfs2_truncate_rec(struct inode *inode, handle_t *handle,struct ocfs2_extent_block *eb;if (ocfs2_is_empty_extent (&el->l_recs[0 ]) && index >0 ) { - ret =ocfs2_rotate_tree_left (inode, handle, path, dealloc); + ret =ocfs2_rotate_tree_left (inode, handle, path, dealloc, et);if (ret) {mlog_errno (ret); goto out;
@@ -4715,7 +4820,7 @@ static int ocfs2_truncate_rec(struct inode *inode, handle_t *handle,ocfs2_journal_dirty (handle,path_leaf_bh (path)); - ret =ocfs2_rotate_tree_left (inode, handle, path, dealloc); + ret =ocfs2_rotate_tree_left (inode, handle, path, dealloc, et);if (ret) {mlog_errno (ret); goto out;
@@ -4726,20 +4831,29 @@ out:return ret; } -int ocfs2_remove_extent (struct inode *inode,struct buffer_head *di_bh, +int ocfs2_remove_extent (struct inode *inode,struct buffer_head *root_bh,u32 cpos,u32 len,handle_t *handle,struct ocfs2_alloc_context *meta_ac, -struct ocfs2_cached_dealloc_ctxt *dealloc) +struct ocfs2_cached_dealloc_ctxt *dealloc, +enum ocfs2_extent_tree_type et_type) {int ret, index;u32 rec_range, trunc_range;struct ocfs2_extent_rec *rec;struct ocfs2_extent_list *el; -struct ocfs2_path *path; +struct ocfs2_path *path =NULL ; +struct ocfs2_extent_tree *et =NULL ; + + et =ocfs2_new_extent_tree (root_bh, et_type); +if (!et) { + ret = -ENOMEM ; +mlog_errno (ret); + goto out; + }ocfs2_extent_map_trunc (inode,0 ); - path =ocfs2_new_inode_path (di_bh); + path =ocfs2_new_path (et->root_bh, et->root_el);if (!path) { ret = -ENOMEM ;mlog_errno (ret);
@@ -4792,13 +4906,13 @@ int ocfs2_remove_extent(struct inode *inode, struct buffer_head *di_bh,if (le32_to_cpu (rec->e_cpos) == cpos || rec_range == trunc_range) { ret =ocfs2_truncate_rec (inode, handle, path, index, dealloc, - cpos, len); + cpos, len, et);if (ret) {mlog_errno (ret); goto out; } }else { - ret =ocfs2_split_tree (inode, di_bh, handle, path, index, + ret =ocfs2_split_tree (inode, et, handle, path, index, trunc_range, meta_ac);if (ret) {mlog_errno (ret);
@@ -4847,7 +4961,7 @@ int ocfs2_remove_extent(struct inode *inode, struct buffer_head *di_bh, } ret =ocfs2_truncate_rec (inode, handle, path, index, dealloc, - cpos, len); + cpos, len, et);if (ret) {mlog_errno (ret); goto out;
@@ -4856,6 +4970,8 @@ int ocfs2_remove_extent(struct inode *inode, struct buffer_head *di_bh, out:ocfs2_free_path (path); +if (et) +ocfs2_free_extent_tree (et);return ret; }
@@ -6364,7 +6480,8 @@ int ocfs2_convert_inline_data_to_extents(struct inode *inode,* the in-inode data from our pages. */ ret =ocfs2_insert_extent (osb, handle, inode, di_bh, -0 , block,1 ,0 ,NULL ); +0 , block,1 ,0 , +NULL ,OCFS2_DINODE_EXTENT );if (ret) {mlog_errno (ret); goto out_commit;
@@ -6406,13 +6523,14 @@ int ocfs2_commit_truncate(struct ocfs2_super *osb,handle_t *handle =NULL ;struct inode *tl_inode = osb->osb_tl_inode;struct ocfs2_path *path =NULL ; +struct ocfs2_dinode *di = (struct ocfs2_dinode *)fe_bh->b_data;mlog_entry_void (); new_highest_cpos =ocfs2_clusters_for_bytes (osb->sb,i_size_read (inode)); - path =ocfs2_new_inode_path (fe_bh); + path =ocfs2_new_path (fe_bh, &di->id2.i_list);if (!path) { status = -ENOMEM ;mlog_errno (status);
fs/ocfs2/alloc.h +16 -7
@@ -26,28 +26,37 @@#ifndef OCFS2_ALLOC_H #define OCFS2_ALLOC_H +enum ocfs2_extent_tree_type { +OCFS2_DINODE_EXTENT =0 , +}; +struct ocfs2_alloc_context ;int ocfs2_insert_extent (struct ocfs2_super *osb,handle_t *handle,struct inode *inode, -struct buffer_head *fe_bh, +struct buffer_head *root_bh,u32 cpos,u64 start_blk,u32 new_clusters,u8 flags, -struct ocfs2_alloc_context *meta_ac); +struct ocfs2_alloc_context *meta_ac, +enum ocfs2_extent_tree_type et_type);struct ocfs2_cached_dealloc_ctxt ; -int ocfs2_mark_extent_written (struct inode *inode,struct buffer_head *di_bh, +int ocfs2_mark_extent_written (struct inode *inode,struct buffer_head *root_bh,handle_t *handle,u32 cpos,u32 len,u32 phys,struct ocfs2_alloc_context *meta_ac, -struct ocfs2_cached_dealloc_ctxt *dealloc); -int ocfs2_remove_extent (struct inode *inode,struct buffer_head *di_bh, +struct ocfs2_cached_dealloc_ctxt *dealloc, +enum ocfs2_extent_tree_type et_type); +int ocfs2_remove_extent (struct inode *inode,struct buffer_head *root_bh,u32 cpos,u32 len,handle_t *handle,struct ocfs2_alloc_context *meta_ac, -struct ocfs2_cached_dealloc_ctxt *dealloc); +struct ocfs2_cached_dealloc_ctxt *dealloc, +enum ocfs2_extent_tree_type et_type);int ocfs2_num_free_extents (struct ocfs2_super *osb,struct inode *inode, -struct buffer_head *bh); +struct buffer_head *root_bh, +enum ocfs2_extent_tree_type et_type); +/* * how many new metadata chunks would an allocation need at maximum? *
fs/ocfs2/aops.c +9 -2
@@ -1268,7 +1268,8 @@ static int ocfs2_write_cluster(struct address_space *mapping, }else if (unwritten) { ret =ocfs2_mark_extent_written (inode, wc->w_di_bh, wc->w_handle, cpos,1 , phys, - meta_ac, &wc->w_dealloc); + meta_ac, &wc->w_dealloc, +OCFS2_DINODE_EXTENT );if (ret <0 ) {mlog_errno (ret); goto out;
@@ -1702,7 +1703,13 @@ int ocfs2_write_begin_nolock(struct address_space *mapping,* ocfs2_lock_allocators(). It greatly over-estimates * the work to be done. */ - ret =ocfs2_lock_allocators (inode, wc->w_di_bh, +mlog (0 ,"extend inode %llu, i_size = %lld, di->i_clusters = %u," +" clusters_to_add = %u, extents_to_split = %u\n" , + (unsigned long long )OCFS2_I (inode)->ip_blkno, + (long long )i_size_read (inode),le32_to_cpu (di->i_clusters), + clusters_to_alloc, extents_to_split); + + ret =ocfs2_lock_allocators (inode, wc->w_di_bh, &di->id2.i_list, clusters_to_alloc, extents_to_split, &data_ac, &meta_ac);if (ret) {
fs/ocfs2/dir.c +4 -3
@@ -1307,7 +1307,7 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,* related blocks have been journaled already. */ ret =ocfs2_insert_extent (osb, handle, dir, di_bh,0 , blkno, len,0 , -NULL ); +NULL ,OCFS2_DINODE_EXTENT );if (ret) {mlog_errno (ret); goto out;
@@ -1333,7 +1333,7 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, blkno =ocfs2_clusters_to_blocks (dir->i_sb, bit_off); ret =ocfs2_insert_extent (osb, handle, dir, di_bh,1 , blkno, - len,0 ,NULL ); + len,0 ,NULL ,OCFS2_DINODE_EXTENT );if (ret) {mlog_errno (ret); goto out;
@@ -1476,7 +1476,8 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb,if (dir_i_size ==ocfs2_clusters_to_bytes (sb,OCFS2_I (dir)->ip_clusters)) {spin_unlock (&OCFS2_I (dir)->ip_lock); num_free_extents =ocfs2_num_free_extents (osb, dir, - parent_fe_bh); + parent_fe_bh, +OCFS2_DINODE_EXTENT );if (num_free_extents <0 ) { status = num_free_extents;mlog_errno (status);
fs/ocfs2/file.c +13 -91
140 lines not on this page · raw message
fs/ocfs2/file.h +0 -4
@@ -55,10 +55,6 @@ int ocfs2_do_extend_allocation(struct ocfs2_super *osb, enum ocfs2_alloc_restarted *reason_ret);int ocfs2_extend_no_holes (struct inode *inode,u64 new_i_size,u64 zero_to); -int ocfs2_lock_allocators (struct inode *inode,struct buffer_head *fe, -u32 clusters_to_add,u32 extents_to_split, -struct ocfs2_alloc_context **data_ac, -struct ocfs2_alloc_context **meta_ac);int ocfs2_setattr (struct dentry *dentry,struct iattr *attr);int ocfs2_getattr (struct vfsmount *mnt,struct dentry *dentry,struct kstat *stat);
fs/ocfs2/suballoc.c +82 -0
85 lines not on this page · raw message
fs/ocfs2/suballoc.h +5 -0
@@ -161,4 +161,9 @@ u64 ocfs2_which_cluster_group(struct inode *inode, u32 cluster);int ocfs2_check_group_descriptor (struct super_block *sb,struct ocfs2_dinode *di,struct ocfs2_group_desc *gd); +int ocfs2_lock_allocators (struct inode *inode,struct buffer_head *root_bh, +struct ocfs2_extent_list *root_el, +u32 clusters_to_add,u32 extents_to_split, +struct ocfs2_alloc_context **data_ac, +struct ocfs2_alloc_context **meta_ac);#endif /* _CHAINALLOC_H_ */
Signature · 1 line
1.5.4.GIT
PATCH 4/8 Make extend allocation generic.v1
In reply to Tao MaThe old ocfs2_do_extend_allocation is restrictly to be used in file extension. Now a new function named ocfs2_do_cluster_allocation will handle the issue of generic extend allocation and it is created in suballoc.c.
--- fs/ocfs2/file.c | 94 +++------------------------------------------- fs/ocfs2/file.h | 6 +-- fs/ocfs2/suballoc.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++ fs/ocfs2/suballoc.h | 18 +++++++++ 4 files changed, 128 insertions(+), 93 deletions(-)
fs/ocfs2/file.c +6 -88
@@ -508,96 +508,14 @@ int ocfs2_do_extend_allocation(struct ocfs2_super *osb,struct ocfs2_alloc_context *meta_ac, enum ocfs2_alloc_restarted *reason_ret) { - int status = 0; -int free_extents; struct ocfs2_dinode *fe = (struct ocfs2_dinode *) fe_bh->b_data; -enum ocfs2_alloc_restarted reason =RESTART_NONE ; -u32 bit_off, num_bits; -u64 block; -u8 flags =0 ; - -BUG_ON (!clusters_to_add); - -if (mark_unwritten) - flags =OCFS2_EXT_UNWRITTEN ; - - free_extents =ocfs2_num_free_extents (osb, inode, fe_bh, -OCFS2_DINODE_EXTENT ); -if (free_extents <0 ) { - status = free_extents; -mlog_errno (status); - goto leave; - } - -/* there are two cases which could cause us to EAGAIN in the -* we-need-more-metadata case: -* 1) we haven't reserved *any* -* 2) we are so fragmented, we've needed to add metadata too -* many times. */ -if (!free_extents && !meta_ac) { -mlog (0 ,"we haven't reserved any metadata!\n" ); - status = -EAGAIN ; - reason =RESTART_META ; - goto leave; - }else if ((!free_extents) - && (ocfs2_alloc_context_bits_left (meta_ac) - <ocfs2_extend_meta_needed (&fe->id2.i_list))) { -mlog (0 ,"filesystem is really fragmented...\n" ); - status = -EAGAIN ; - reason =RESTART_META ; - goto leave; - } +struct ocfs2_extent_list *el = &fe->id2.i_list; - status =__ocfs2_claim_clusters (osb, handle, data_ac,1 , - clusters_to_add, &bit_off, &num_bits); -if (status <0 ) { -if (status != -ENOSPC ) -mlog_errno (status); - goto leave; - } - -BUG_ON (num_bits > clusters_to_add); - -/* reserve our write early -- insert_extent may update the inode */ - status =ocfs2_journal_access (handle, inode, fe_bh, -OCFS2_JOURNAL_ACCESS_WRITE ); -if (status <0 ) { -mlog_errno (status); - goto leave; - } - - block =ocfs2_clusters_to_blocks (osb->sb, bit_off); -mlog (0 ,"Allocating %u clusters at block %u for inode %llu\n" , - num_bits, bit_off, (unsigned long long )OCFS2_I (inode)->ip_blkno); - status =ocfs2_insert_extent (osb, handle, inode, fe_bh, - *logical_offset, block, num_bits, - flags, meta_ac,OCFS2_DINODE_EXTENT ); -if (status <0 ) { -mlog_errno (status); - goto leave; - } - - status =ocfs2_journal_dirty (handle, fe_bh); -if (status <0 ) { -mlog_errno (status); - goto leave; - } - - clusters_to_add -= num_bits; - *logical_offset += num_bits; - -if (clusters_to_add) { -mlog (0 ,"need to alloc once more, clusters = %u, wanted = " -"%u\n" , fe->i_clusters, clusters_to_add); - status = -EAGAIN ; - reason =RESTART_TRANS ; - } - -leave: -mlog_exit (status); -if (reason_ret) - *reason_ret = reason; -return status; +return ocfs2_do_cluster_allocation (osb, inode, logical_offset, + &clusters_to_add, mark_unwritten, + fe_bh, el, handle, + data_ac, meta_ac, reason_ret, +OCFS2_DINODE_EXTENT ); } static int __ocfs2_extend_allocation(struct inode *inode, u32 logical_start,
fs/ocfs2/file.h +1 -5
@@ -31,6 +31,7 @@ extern const struct file_operations ocfs2_dops;extern const struct inode_operations ocfs2_file_iops;extern const struct inode_operations ocfs2_special_file_iops;struct ocfs2_alloc_context ; +enum ocfs2_alloc_restarted ;struct ocfs2_file_private {struct file *fp_file;
@@ -38,11 +39,6 @@ struct ocfs2_file_private {struct ocfs2_lock_res fp_flock; }; -enum ocfs2_alloc_restarted { -RESTART_NONE =0 , -RESTART_TRANS , -RESTART_META -}; int ocfs2_do_extend_allocation(struct ocfs2_super *osb, struct inode *inode, u32 *logical_offset,
fs/ocfs2/suballoc.c +103 -0
106 lines not on this page · raw message
fs/ocfs2/suballoc.h +18 -0
@@ -166,4 +166,22 @@ int ocfs2_lock_allocators(struct inode *inode, struct buffer_head *root_bh, u32 clusters_to_add, u32 extents_to_split, struct ocfs2_alloc_context **data_ac, struct ocfs2_alloc_context **meta_ac); + +enum ocfs2_alloc_restarted { +RESTART_NONE =0 , +RESTART_TRANS , +RESTART_META +}; +int ocfs2_do_cluster_allocation (struct ocfs2_super *osb, +struct inode *inode, +u32 *logical_offset, +u32 *clusters_to_add, +int mark_unwritten, +struct buffer_head *root_bh, +struct ocfs2_extent_list *root_el, +handle_t *handle, +struct ocfs2_alloc_context *data_ac, +struct ocfs2_alloc_context *meta_ac, +enum ocfs2_alloc_restarted *reason_ret, +enum ocfs2_extent_tree_type type);#endif /* _CHAINALLOC_H_ */
Signature · 1 line
1.5.4.GIT
PATCH 5/8 Add xattr header in ocfs2.v1
In reply to Tao Ma--- fs/ocfs2/xattr.h | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 95 insertions(+), 0 deletions(-) create mode 100644 fs/ocfs2/xattr.h
fs/ocfs2/xattr.h new file +95 -0
@@ -0,0 +1,95 @@ +/* -*- mode: c; c-basic-offset: 8; -*- +* vim: noexpandtab sw=8 ts=8 sts=0: +* +* xattr.h +* +* Function prototypes +* +* Copyright (C) 2008 Oracle. All rights reserved. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public +* License as published by the Free Software Foundation; either +* version 2 of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., 59 Temple Place - Suite 330, +* Boston, MA 021110-1307, USA. +*/ + +#ifndef OCFS2_XATTR_H +#define OCFS2_XATTR_H + +#include <linux/init.h> +#include <linux/xattr.h> + +/* Magic value in attribute blocks */ +#define OCFS2_XATTR_BLOCK_SIGNATURE_1 "XATTR01" +#define OCFS2_XATTR_BLOCK_SIGNATURE_2 "XATTR02" + +enum ocfs2_xattr_type { +OCFS2_XATTR_INDEX_USER =1 , +OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS , +OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT , +OCFS2_XATTR_INDEX_TRUSTED , +OCFS2_XATTR_INDEX_LUSTRE , +OCFS2_XATTR_INDEX_SECURITY , +OCFS2_XATTR_MAX +}; + +struct ocfs2_xattr_entry { +__le32 xe_name_hash; +__le16 xe_name_offset; +__u8 xe_name_len; +__u8 xe_type :7 ; +__u8 xe_local :1 ; +__le64 xe_value_size; +}; + +struct ocfs2_xattr_header { +__le16 xh_count; +__le16 xh_reserved1; +__le32 xh_csum; +__le16 xh_reserved2[4 ]; +struct ocfs2_xattr_entry xh_entries[0 ]; +}; + +struct ocfs2_xattr_value_root { +/*00*/ __le32 xr_clusters; +__le32 xr_reserved0; +__le64 xr_last_eb_blk; +/*10*/ struct ocfs2_extent_list xr_list; +}; + +struct ocfs2_xattr_tree_root { +/*00*/ __le32 xt_clusters; +__le32 xt_reserved0; +__le64 xt_last_eb_blk; +/*10*/ struct ocfs2_extent_list xt_list; +}; + +#define OCFS2_XATTR_INDEXED 0x1 + +struct ocfs2_xattr_block { +/*00*/ __u8 xb_signature[8 ]; +__le16 xb_suballoc_slot; +__le16 xb_suballoc_bit; +__le32 xb_fs_generation; +/*10*/ __le32 xb_csum; +__le16 xb_flags; +__le16 xb_reserved0; +__le64 xb_blkno; +/*20*/ __le64 xb_reserved1[2 ]; +/*30*/ union { +struct ocfs2_xattr_header xb_header; +struct ocfs2_xattr_tree_root xb_root; + } xb_attrs; +}; + +#endif /* OCFS2_XATTR_H */
Signature · 1 line
1.5.4.GIT
PATCH 6/8 Add extent tree operation for xattr value.v1
In reply to Tao MaWhen storing xattr value which is too large, we will allocate some clusters for it and here ocfs2_extent_list and ocfs2_extent_rec will also be used. In order to re-use the b-tree operation code, a new parameter named "private" is added into ocfs2_extent_tree and it is used to indicate the root of ocfs2_exent_list. The reason is that we can't deduce the root from the buffer_head now. It may be in an inode, an ocfs2_xattr_block or even worse, in any place in an ocfs2_xattr_bucket.
--- fs/ocfs2/Makefile | 3 +- fs/ocfs2/alloc.c | 72 ++++++++++-- fs/ocfs2/alloc.h | 13 ++- fs/ocfs2/aops.c | 5 +- fs/ocfs2/dir.c | 8 +- fs/ocfs2/extent_map.c | 60 ++++++++++ fs/ocfs2/extent_map.h | 3 + fs/ocfs2/file.c | 9 +- fs/ocfs2/suballoc.c | 13 ++- fs/ocfs2/suballoc.h | 6 +- fs/ocfs2/xattr.c | 301 +++++++++++++++++++++++++++++++++++++++++++++++++ 11 files changed, 461 insertions(+), 32 deletions(-) create mode 100644 fs/ocfs2/xattr.c
fs/ocfs2/Makefile +2 -1
@@ -34,7 +34,8 @@ ocfs2-objs := \ symlink.o \ sysfile.o \ uptodate.o \ - ver.o + ver.o \ + xattr.o \ ocfs2_stackglue-objs := stackglue.o ocfs2_stack_o2cb-objs := stack_o2cb.o
fs/ocfs2/alloc.c +61 -11
162 lines not on this page · raw message
fs/ocfs2/alloc.h +9 -4
@@ -28,6 +28,7 @@enum ocfs2_extent_tree_type {OCFS2_DINODE_EXTENT =0 , +OCFS2_XATTR_VALUE_EXTENT , };struct ocfs2_alloc_context ;
@@ -40,22 +41,26 @@ int ocfs2_insert_extent(struct ocfs2_super *osb,u32 new_clusters, u8 flags, struct ocfs2_alloc_context *meta_ac, - enum ocfs2_extent_tree_type et_type); + enum ocfs2_extent_tree_type et_type, + void *private);struct ocfs2_cached_dealloc_ctxt ;int ocfs2_mark_extent_written (struct inode *inode,struct buffer_head *root_bh,handle_t *handle,u32 cpos,u32 len,u32 phys,struct ocfs2_alloc_context *meta_ac,struct ocfs2_cached_dealloc_ctxt *dealloc, -enum ocfs2_extent_tree_type et_type); +enum ocfs2_extent_tree_type et_type, +void *private);int ocfs2_remove_extent (struct inode *inode,struct buffer_head *root_bh,u32 cpos,u32 len,handle_t *handle,struct ocfs2_alloc_context *meta_ac,struct ocfs2_cached_dealloc_ctxt *dealloc, -enum ocfs2_extent_tree_type et_type); +enum ocfs2_extent_tree_type et_type, +void *private);int ocfs2_num_free_extents (struct ocfs2_super *osb,struct inode *inode,struct buffer_head *root_bh, -enum ocfs2_extent_tree_type et_type); +enum ocfs2_extent_tree_type et_type, +void *private);/* * how many new metadata chunks would an allocation need at maximum?
fs/ocfs2/aops.c +3 -2
@@ -1269,7 +1269,7 @@ static int ocfs2_write_cluster(struct address_space *mapping, ret =ocfs2_mark_extent_written (inode, wc->w_di_bh, wc->w_handle, cpos,1 , phys, meta_ac, &wc->w_dealloc, -OCFS2_DINODE_EXTENT ); +OCFS2_DINODE_EXTENT ,NULL );if (ret <0 ) {mlog_errno (ret); goto out;
@@ -1711,7 +1711,8 @@ int ocfs2_write_begin_nolock(struct address_space *mapping, ret =ocfs2_lock_allocators (inode, wc->w_di_bh, &di->id2.i_list, clusters_to_alloc, extents_to_split, - &data_ac, &meta_ac); + &data_ac, &meta_ac, +OCFS2_DINODE_EXTENT ,NULL );if (ret) {mlog_errno (ret); goto out;
fs/ocfs2/dir.c +5 -3
@@ -1307,7 +1307,7 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,* related blocks have been journaled already. */ ret =ocfs2_insert_extent (osb, handle, dir, di_bh,0 , blkno, len,0 , -NULL ,OCFS2_DINODE_EXTENT ); +NULL ,OCFS2_DINODE_EXTENT ,NULL );if (ret) {mlog_errno (ret); goto out;
@@ -1333,7 +1333,8 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, blkno =ocfs2_clusters_to_blocks (dir->i_sb, bit_off); ret =ocfs2_insert_extent (osb, handle, dir, di_bh,1 , blkno, - len,0 ,NULL ,OCFS2_DINODE_EXTENT ); + len,0 ,NULL ,OCFS2_DINODE_EXTENT , +NULL );if (ret) {mlog_errno (ret); goto out;
@@ -1477,7 +1478,8 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb,spin_unlock (&OCFS2_I (dir)->ip_lock); num_free_extents =ocfs2_num_free_extents (osb, dir, parent_fe_bh, -OCFS2_DINODE_EXTENT ); +OCFS2_DINODE_EXTENT , +NULL );if (num_free_extents <0 ) { status = num_free_extents;mlog_errno (status);
fs/ocfs2/extent_map.c +60 -0
66 lines not on this page · raw message
fs/ocfs2/extent_map.h +3 -0
@@ -50,4 +50,7 @@ int ocfs2_get_clusters(struct inode *inode, u32 v_cluster, u32 *p_cluster,int ocfs2_extent_map_get_blocks (struct inode *inode,u64 v_blkno,u64 *p_blkno,u64 *ret_count,unsigned int *extent_flags); +int ocfs2_xattr_get_clusters (struct inode *inode,u32 v_cluster, +u32 *p_cluster,u32 *num_clusters, +struct ocfs2_extent_list *el);#endif /* _EXTENT_MAP_H */
fs/ocfs2/file.c +5 -4
@@ -515,7 +515,7 @@ int ocfs2_do_extend_allocation(struct ocfs2_super *osb, &clusters_to_add, mark_unwritten, fe_bh, el, handle, data_ac, meta_ac, reason_ret, - OCFS2_DINODE_EXTENT); + OCFS2_DINODE_EXTENT, NULL); } static int __ocfs2_extend_allocation(struct inode *inode, u32 logical_start,
@@ -565,7 +565,7 @@ restart_all: clusters_to_add); status =ocfs2_lock_allocators (inode, bh, &fe->id2.i_list, clusters_to_add,0 , &data_ac, - &meta_ac); + &meta_ac,OCFS2_DINODE_EXTENT ,NULL );if (status) {mlog_errno (status); goto leave;
@@ -1237,7 +1237,8 @@ static int __ocfs2_remove_inode_range(struct inode *inode,struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; ret =ocfs2_lock_allocators (inode, di_bh, &di->id2.i_list, -0 ,1 ,NULL , &meta_ac); +0 ,1 ,NULL , &meta_ac, +OCFS2_DINODE_EXTENT ,NULL );if (ret) {mlog_errno (ret);return ret;
@@ -1268,7 +1269,7 @@ static int __ocfs2_remove_inode_range(struct inode *inode, } ret =ocfs2_remove_extent (inode, di_bh, cpos, len, handle, meta_ac, - dealloc,OCFS2_DINODE_EXTENT ); + dealloc,OCFS2_DINODE_EXTENT ,NULL );if (ret) {mlog_errno (ret); goto out_commit;
fs/ocfs2/suballoc.c +8 -5
@@ -1906,7 +1906,8 @@ int ocfs2_lock_allocators(struct inode *inode, struct buffer_head *root_bh,struct ocfs2_extent_list *root_el, u32 clusters_to_add, u32 extents_to_split, struct ocfs2_alloc_context **data_ac, - struct ocfs2_alloc_context **meta_ac) + struct ocfs2_alloc_context **meta_ac, + enum ocfs2_extent_tree_type type, void *private) { int ret = 0, num_free_extents;unsigned int max_recs_needed = clusters_to_add +2 * extents_to_split;
@@ -1919,7 +1920,7 @@ int ocfs2_lock_allocators(struct inode *inode, struct buffer_head *root_bh,BUG_ON (clusters_to_add !=0 && data_ac ==NULL ); num_free_extents =ocfs2_num_free_extents (osb, inode, root_bh, -OCFS2_DINODE_EXTENT ); + type, private);if (num_free_extents <0 ) { ret = num_free_extents;mlog_errno (ret);
@@ -1985,7 +1986,8 @@ int ocfs2_do_cluster_allocation(struct ocfs2_super *osb,struct ocfs2_alloc_context *data_ac, struct ocfs2_alloc_context *meta_ac, enum ocfs2_alloc_restarted *reason_ret, - enum ocfs2_extent_tree_type type) + enum ocfs2_extent_tree_type type, + void *private) { int status = 0;int free_extents;
@@ -1999,7 +2001,8 @@ int ocfs2_do_cluster_allocation(struct ocfs2_super *osb,if (mark_unwritten) flags =OCFS2_EXT_UNWRITTEN ; - free_extents =ocfs2_num_free_extents (osb, inode, root_bh, type); + free_extents =ocfs2_num_free_extents (osb, inode, root_bh, type, + private);if (free_extents <0 ) { status = free_extents;mlog_errno (status);
@@ -2048,7 +2051,7 @@ int ocfs2_do_cluster_allocation(struct ocfs2_super *osb, num_bits, bit_off, (unsigned long long)OCFS2_I(inode)->ip_blkno); status =ocfs2_insert_extent (osb, handle, inode, root_bh, *logical_offset, block, num_bits, - flags, meta_ac, type); + flags, meta_ac, type, private);if (status <0 ) {mlog_errno (status); goto leave;
fs/ocfs2/suballoc.h +4 -2
@@ -165,7 +165,8 @@ int ocfs2_lock_allocators(struct inode *inode, struct buffer_head *root_bh,struct ocfs2_extent_list *root_el, u32 clusters_to_add, u32 extents_to_split, struct ocfs2_alloc_context **data_ac, - struct ocfs2_alloc_context **meta_ac); + struct ocfs2_alloc_context **meta_ac, + enum ocfs2_extent_tree_type type, void *private);enum ocfs2_alloc_restarted {RESTART_NONE =0 ,
@@ -183,5 +184,6 @@ int ocfs2_do_cluster_allocation(struct ocfs2_super *osb,struct ocfs2_alloc_context *data_ac, struct ocfs2_alloc_context *meta_ac, enum ocfs2_alloc_restarted *reason_ret, - enum ocfs2_extent_tree_type type); + enum ocfs2_extent_tree_type type, + void *private);#endif /* _CHAINALLOC_H_ */
fs/ocfs2/xattr.c new file +301 -0
301 lines not on this page · raw message
Signature · 1 line
1.5.4.GIT
PATCH 8/8 Add large numbers of extended attributes support for ocfs2.v1
In reply to Tao MaExtended attributes is added into ocfs2, but it can be only stored in inode and one extra block, so the number is very limited. This patch enable ocfs2 to store large numbers of EAs.
The original design doc is written by Mark Fasheh, and it can be found in
http://oss.oracle.com/osswiki/OCFS2/DesignDocs/IndexedEATrees. Just some little modifications to it.
First, because the bucket size is 4K, a new field named as xh_offset is added in ocfs2_xattr_header to indicate the next valid name/value offset in abucket. It is used when we store new EA name/value. With this field, we can find the place more quickly and what's more, we dont' need to sort the name/value every time to let the last entry indicate the next unused space. Considering when the blocksize is 512, we may have to update 8 blocks for one insertion if we sort name/value like the original in-inode xattr. It is definitely inefficient.
Because of the new xh_offset, another field named as xh_name_value_len is also added in ocfs2_xattr_header. It records the total length of all the name/values in the bucket. We need this so that we can check it and defragment the bucket if the bucket is too much fragmented.
So now the insertion will be like this:
1. xattr_index_block_find: find the right bucket by the name_hash, say bucketA.
2. check whether there is enough space in bucketA. If yes, insert it directly and modify xh_offset and xh_name_value_len accordingly. If no, check xh_name_value_len to see whether we can store this by defragment the bucket. If yes, defragment it and go on insertion.
3. If defragement doesnt' work, check whether there is new empty bucket in the clusters within this extent record. If yes, init the new bucket and move all the buckets after bucketA one by one to the next bucket. Move half of the entries in bucketA to the next bucket and go on insertion.
4. If there is no new bucket, grow the extent tree.(This should be the same as Mark has described in the design doc).
As for xattr deletion, we will delete an xattr bucket when all the xattr in this bucket are removed and move all the buckets after it to the previous one. When all the xattr buckets in an extend record are freed, free this extend records from ocfs2_xattr_tree.
Two more things. This patch is a bit longer, so please be patient when reviewing it. ;) I will divide it inot several small ones next time. And some function names may not be good enough, I may modify them when I collect all of your advice. So hope you enjoy it.
--- fs/ocfs2/alloc.c | 46 + fs/ocfs2/alloc.h | 1 + fs/ocfs2/xattr.c | 3017 +++++++++++++++++++++++++++++++++++++++++++++++++++++- fs/ocfs2/xattr.h | 5 +- 4 files changed, 3028 insertions(+), 41 deletions(-)
fs/ocfs2/alloc.c +46 -0
@@ -136,6 +136,37 @@ static struct ocfs2_extent_tree_operations ocfs2_xattr_et_ops = { .sanity_check = ocfs2_xattr_value_sanity_check, }; +static void ocfs2_xattr_tree_set_last_eb_blk (void *p,u64 blkno) +{ +struct ocfs2_extent_tree *et = (struct ocfs2_extent_tree *)p; +struct ocfs2_xattr_block *xb = + (struct ocfs2_xattr_block *) et->root_bh->b_data; +struct ocfs2_xattr_tree_root *xt = &xb->xb_attrs.xb_root; + + xt->xt_last_eb_blk =cpu_to_le64 (blkno); +} + +static u64 ocfs2_xattr_tree_get_last_eb_blk (void *p) +{ +struct ocfs2_extent_tree *et = (struct ocfs2_extent_tree *)p; +struct ocfs2_xattr_block *xb = + (struct ocfs2_xattr_block *) et->root_bh->b_data; +struct ocfs2_xattr_tree_root *xt = &xb->xb_attrs.xb_root; + +return le64_to_cpu (xt->xt_last_eb_blk); +} + +static int ocfs2_xattr_tree_sanity_check (struct inode *inode,void *p) +{ +return 0 ; +} + +static struct ocfs2_extent_tree_operations ocfs2_xattr_tree_et_ops = { + .set_last_eb_blk = ocfs2_xattr_tree_set_last_eb_blk, + .get_last_eb_blk = ocfs2_xattr_tree_get_last_eb_blk, + .sanity_check = ocfs2_xattr_tree_sanity_check, +}; +static struct ocfs2_extent_tree * ocfs2_new_extent_tree(struct buffer_head *bh, enum ocfs2_extent_tree_type et_type,
@@ -160,6 +191,11 @@ static struct ocfs2_extent_tree* (struct ocfs2_xattr_value_root *) private; et->root_el = &xv->xr_list; et->eops = &ocfs2_xattr_et_ops; + }else if (et_type ==OCFS2_XATTR_TREE_EXTENT ) { +struct ocfs2_xattr_block *xb = + (struct ocfs2_xattr_block *)bh->b_data; + et->root_el = &xb->xb_attrs.xb_root.xt_list; + et->eops = &ocfs2_xattr_tree_et_ops; }return et;
@@ -511,6 +547,12 @@ int ocfs2_num_free_extents(struct ocfs2_super *osb, last_eb_blk =le64_to_cpu (xv->xr_last_eb_blk); el = &xv->xr_list; + }else if (type ==OCFS2_XATTR_TREE_EXTENT ) { +struct ocfs2_xattr_block *xb = + (struct ocfs2_xattr_block *)root_bh->b_data; + + last_eb_blk =le64_to_cpu (xb->xb_attrs.xb_root.xt_last_eb_blk); + el = &xb->xb_attrs.xb_root.xt_list; }if (last_eb_blk) {
@@ -3497,6 +3539,10 @@ static void ocfs2_update_clusters(struct inode *inode,struct ocfs2_xattr_value_root *xv = (struct ocfs2_xattr_value_root *)et->private;le32_add_cpu (&xv->xr_clusters, clusters); + }else if (et->type ==OCFS2_XATTR_TREE_EXTENT ) { +struct ocfs2_xattr_block *xb = + (struct ocfs2_xattr_block *)et->root_bh->b_data; +le32_add_cpu (&xb->xb_attrs.xb_root.xt_clusters, clusters); } }
fs/ocfs2/alloc.h +1 -0
@@ -29,6 +29,7 @@enum ocfs2_extent_tree_type {OCFS2_DINODE_EXTENT =0 ,OCFS2_XATTR_VALUE_EXTENT , +OCFS2_XATTR_TREE_EXTENT , };struct ocfs2_alloc_context ;
fs/ocfs2/xattr.c +2977 -40
2,923 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 1 line
1.5.4.GIT
Part of the diff is not shown here. View the raw message.
PATCH 8/8 (Imporved)Add large numbers of extended attributes support for ocfs2.v1
change-log:
Add some comments in the functions so that it may be easily for review.;)
Extended attributes is added into ocfs2, but it can be only stored in inode and one extra block, so the number is very limited. This patch enable ocfs2 to store large numbers of EAs.
The original design doc is written by Mark Fasheh, and it can be found in
http://oss.oracle.com/osswiki/OCFS2/DesignDocs/IndexedEATrees. Just some little modifications to it.
First, because the bucket size is 4K, a new field named as xh_offset is added in ocfs2_xattr_header to indicate the next valid name/value offset in abucket. It is used when we store new EA name/value. With this field, we can find the place more quickly and what's more, we don't need to sort the name/value every time to let the last entry indicate the next unused space. Considering when the blocksize is 512, we may have to update 8 blocks for one insertion if we sort name/value like the original in-inode xattr. It is definitely inefficient.
Because of the new xh_offset, another field named as xh_name_value_len is also added in ocfs2_xattr_header. It records the total length of all the name/values in the bucket. We need this so that we can check it and defragment the bucket if the bucket is too much fragmented.
So now the insertion will be like this:
1. xattr_index_block_find: find the right bucket by the name_hash, say bucketA.
2. check whether there is enough space in bucketA. If yes, insert it directly and modify xh_offset and xh_name_value_len accordingly. If no, check xh_name_value_len to see whether we can store this by defragment the bucket. If yes, defragment it and go on insertion.
3. If defragement doesnt' work, check whether there is new empty bucket in the clusters within this extent record. If yes, init the new bucket and move all the buckets after bucketA one by one to the next bucket. Move half of the entries in bucketA to the next bucket and go on insertion.
4. If there is no new bucket, grow the extent tree.(This should be the same as Mark has described in the design doc).
As for xattr deletion, we will delete an xattr bucket when all the xattr in this bucket are removed and move all the buckets after it to the previous one. When all the xattr buckets in an extend record are freed, free this extend records from ocfs2_xattr_tree.
Two more things. This patch is a bit longer, so please be patient when reviewing it. ;) I will divide it inot several small ones next time. And some function names may not be good enough, I may modify them when I collect all of your advice. So hope you enjoy it.
--- fs/ocfs2/alloc.c | 46 + fs/ocfs2/alloc.h | 1 + fs/ocfs2/xattr.c | 3075 +++++++++++++++++++++++++++++++++++++++++++++++++++++- fs/ocfs2/xattr.h | 5 +- 4 files changed, 3084 insertions(+), 43 deletions(-)
fs/ocfs2/alloc.c +46 -0
@@ -136,6 +136,37 @@ static struct ocfs2_extent_tree_operations ocfs2_xattr_et_ops = { .sanity_check = ocfs2_xattr_value_sanity_check, }; +static void ocfs2_xattr_tree_set_last_eb_blk (void *p,u64 blkno) +{ +struct ocfs2_extent_tree *et = (struct ocfs2_extent_tree *)p; +struct ocfs2_xattr_block *xb = + (struct ocfs2_xattr_block *) et->root_bh->b_data; +struct ocfs2_xattr_tree_root *xt = &xb->xb_attrs.xb_root; + + xt->xt_last_eb_blk =cpu_to_le64 (blkno); +} + +static u64 ocfs2_xattr_tree_get_last_eb_blk (void *p) +{ +struct ocfs2_extent_tree *et = (struct ocfs2_extent_tree *)p; +struct ocfs2_xattr_block *xb = + (struct ocfs2_xattr_block *) et->root_bh->b_data; +struct ocfs2_xattr_tree_root *xt = &xb->xb_attrs.xb_root; + +return le64_to_cpu (xt->xt_last_eb_blk); +} + +static int ocfs2_xattr_tree_sanity_check (struct inode *inode,void *p) +{ +return 0 ; +} + +static struct ocfs2_extent_tree_operations ocfs2_xattr_tree_et_ops = { + .set_last_eb_blk = ocfs2_xattr_tree_set_last_eb_blk, + .get_last_eb_blk = ocfs2_xattr_tree_get_last_eb_blk, + .sanity_check = ocfs2_xattr_tree_sanity_check, +}; +static struct ocfs2_extent_tree * ocfs2_new_extent_tree(struct buffer_head *bh, enum ocfs2_extent_tree_type et_type,
@@ -160,6 +191,11 @@ static struct ocfs2_extent_tree* (struct ocfs2_xattr_value_root *) private; et->root_el = &xv->xr_list; et->eops = &ocfs2_xattr_et_ops; + }else if (et_type ==OCFS2_XATTR_TREE_EXTENT ) { +struct ocfs2_xattr_block *xb = + (struct ocfs2_xattr_block *)bh->b_data; + et->root_el = &xb->xb_attrs.xb_root.xt_list; + et->eops = &ocfs2_xattr_tree_et_ops; }return et;
@@ -511,6 +547,12 @@ int ocfs2_num_free_extents(struct ocfs2_super *osb, last_eb_blk =le64_to_cpu (xv->xr_last_eb_blk); el = &xv->xr_list; + }else if (type ==OCFS2_XATTR_TREE_EXTENT ) { +struct ocfs2_xattr_block *xb = + (struct ocfs2_xattr_block *)root_bh->b_data; + + last_eb_blk =le64_to_cpu (xb->xb_attrs.xb_root.xt_last_eb_blk); + el = &xb->xb_attrs.xb_root.xt_list; }if (last_eb_blk) {
@@ -3497,6 +3539,10 @@ static void ocfs2_update_clusters(struct inode *inode,struct ocfs2_xattr_value_root *xv = (struct ocfs2_xattr_value_root *)et->private;le32_add_cpu (&xv->xr_clusters, clusters); + }else if (et->type ==OCFS2_XATTR_TREE_EXTENT ) { +struct ocfs2_xattr_block *xb = + (struct ocfs2_xattr_block *)et->root_bh->b_data; +le32_add_cpu (&xb->xb_attrs.xb_root.xt_clusters, clusters); } }
fs/ocfs2/alloc.h +1 -0
@@ -29,6 +29,7 @@enum ocfs2_extent_tree_type {OCFS2_DINODE_EXTENT =0 ,OCFS2_XATTR_VALUE_EXTENT , +OCFS2_XATTR_TREE_EXTENT , };struct ocfs2_alloc_context ;
fs/ocfs2/xattr.c +3033 -42
2,923 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 1 line
1.5.4.GIT
Part of the diff is not shown here. View the raw message.
PATCH 3/8 Make ocfs2_lock_allocators generic for extent allocation.v1
In reply to Tao Ma[ Btw, patches 1 and 2 looked fine to me ]
Quoted 3 lines · Tao Ma
Now
ocfs2_lock_allocatorsis localized to be only used in file extend allocation. But the whole function is useful when we want to store large EAs. So make it generic.
There's a lot more going on in this patch than your subject line and description let on about ;) Next time around, an explanation of the extent_tree_operations + interface would be nice.
Quoted 17 lines
Signed-off-by Tao Ma <[email protected]>--- fs/ocfs2/alloc.c | 460 ++++++++++++++++++++++++++++++++------------------- fs/ocfs2/alloc.h | 23 ++- fs/ocfs2/aops.c | 11 +- fs/ocfs2/dir.c | 7 +- fs/ocfs2/file.c | 104 ++---------- fs/ocfs2/file.h | 4 - fs/ocfs2/suballoc.c | 82 +++++++++ fs/ocfs2/suballoc.h | 5 + 8 files changed, 418 insertions(+), 278 deletions(-)fs/ocfs2/alloc.c +0
-0
fs/ocfs2/alloc.c line 56
Quoted 8 lines
fs/ocfs2/alloc.c +5
-0@@ -49,6 +49,94 @@#include "buffer_head_io.h" +struct ocfs2_extent_tree_operations { +void (*set_last_eb_blk) (void *et,u64 blkno); +u64 (*get_last_eb_blk) (void *et); +int (*sanity_check) (struct inode *inode,void *et); +};
Shouldn't the 'et' argument to these functions be properly typed?
Also, this entire interface should be very well commented.
Quoted 10 lines
fs/ocfs2/alloc.c +1
-1@@ -663,7 +745,7 @@ static int ocfs2_add_branch(struct ocfs2_super *osb, }/* Link the new branch into the rest of the tree (el will -* either be on the fe, or the extent block passed in. */ +* either be on the root_bh, or the extent block passed in. */ i =le16_to_cpu (el->l_next_free_rec); el->l_recs[i].e_blkno =cpu_to_le64 (next_blkno); el->l_recs[i].e_cpos =cpu_to_le32 (new_cpos);
fs/ocfs2/alloc.c static int ocfs2_add_branch(struct ocfs2_super *osb, · line 757
Quoted 5 lines
fs/ocfs2/alloc.c +1
-1@@ -672,7 +754,7 @@ static int ocfs2_add_branch(struct ocfs2_super *osb,/* fe needs a new last extent block pointer, as does the * next_leaf on the previously last-extent-block. */ - fe->i_last_eb_blk =cpu_to_le64 (new_last_eb_blk); + et->eops->set_last_eb_blk (et, new_last_eb_blk);
It might be less akward if we had some small wrappers around these calls:
static inline void ocfs2_set_last_eb_blk(struct ocfs2_extent_tree *et,
u64 new_last_eb_blk)
{
et->eops->set_last_eb_blk(et, new_last_eb_blk);
}and the same could be done for ->get_last_eb_blk.
fs/ocfs2/alloc.c static inline void ocfs2_update_dinode_clusters(struct inode *inode, · line 3454
Quoted 10 lines
fs/ocfs2/alloc.c +10
-0+static void ocfs2_update_clusters (struct inode *inode, +struct ocfs2_extent_tree *et, +u32 clusters) +{ +if (et->type ==OCFS2_DINODE_EXTENT ) { +struct ocfs2_dinode *di = + (struct ocfs2_dinode *)et->root_bh->b_data; +ocfs2_update_dinode_clusters (inode, di, clusters); + } +}
Shouldn't 'update clusters' be an ocfs2_extent_tree_operation?
The rest of this looks good. It's a big patch, but it looks good :) The only conern I have isn't really with your code per se, but with layout of our source files. Alloc.c keeps growing... and growing... and growing... At some point it might be worth our while to split things out at least so that we have a 'core btree operations' file.
--Mark
--
Mark Fasheh
PATCH 3/8 Make ocfs2_lock_allocators generic for extent allocation.v1
Hi Mark,
Thanks for the review.
I will modify it according to your suggestions.
Quoted 5 lines · Mark Fasheh
The rest of this looks good. It's a big patch, but it looks good :) The only conern I have isn't really with your code per se, but with layout of our source files.
Alloc.ckeeps growing... and growing... and growing... At some point it might be worth our while to split things out at least so that we have a 'core btree operations' file.
Yes, now alloc.c have more than 6000 lines. And maybe a new file name btree.c can be split out from this file that will do the real work of btree operation since with my patch, btree now isn't used by inode only. ;) I will handle this after the xattr patch is committed. Thanks.
Regards,
Tao
PATCH 4/8 Make extend allocation generic.v1
In reply to Tao MaQuoted 18 lines · Tao Ma
The old
ocfs2_do_extend_allocationis restrictly to be used in file extension. Now a new function namedocfs2_do_cluster_allocationwill handle the issue of generic extend allocation and it is created insuballoc.c.Signed-off-by Tao Ma <[email protected]>--- fs/ocfs2/file.c | 94 +++------------------------------------------- fs/ocfs2/file.h | 6 +-- fs/ocfs2/suballoc.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++ fs/ocfs2/suballoc.h | 18 +++++++++ 4 files changed, 128 insertions(+), 93 deletions(-)fs/ocfs2/file.c +0
-0
fs/ocfs2/file.c int ocfs2_do_extend_allocation(struct ocfs2_super *osb, · line 509
Quoted 2 lines
fs/ocfs2/file.c +0
-0@@ -508,96 +508,14 @@ int ocfs2_do_extend_allocation(struct ocfs2_super *osb,struct ocfs2_alloc_context *meta_ac, enum ocfs2_alloc_restarted *reason_ret)
I think you should rename ocfs2_do_extend_allocation to something more direct since it's used only for traditional inode data btrees. Maybe ocfs2_add_inode_data() ?
fs/ocfs2/suballoc.c out: · line 1977
Quoted 10 lines
fs/ocfs2/suballoc.c +2
-0@@ -1973,3 +1973,106 @@ out:return ret; } + +int ocfs2_do_cluster_allocation(struct ocfs2_super *osb,
Likewise, this name doesn't tell me much about the function. Also, a comment describing it's expected usage would be nice ;)
fs/ocfs2/suballoc.c out: · line 1980
Quoted 3 lines
fs/ocfs2/suballoc.c +3
-0+struct inode *inode, + u32 *logical_offset, + u32 *clusters_to_add,
This changed to a "u32 *" but you gave no explanation of why.
We have a ton of arguments to this function. I can not at the moment offer you a better way to structure it though.
--Mark
--
Mark Fasheh
PATCH 5/8 Add xattr header in ocfs2.v1
In reply to Tao Mafs/ocfs2/xattr.h
Quoted 9 lines · Tao Ma
Signed-off-by Tao Ma <[email protected]>--- fs/ocfs2/xattr.h | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 95 insertions(+), 0 deletions(-) create mode 100644 fs/ocfs2/xattr.hfs/ocfs2/xattr.h new file +0
-0
Can we put this in ocfs2_fs.h instead? That way we still have just one place to look for describing the disk format.
Quoted 27 lines
fs/ocfs2/xattr.h new file +24
-0@@ -0,0 +1,95 @@ +/* -*- mode: c; c-basic-offset: 8; -*- +* vim: noexpandtab sw=8 ts=8 sts=0: +* +* xattr.h +* +* Function prototypes +* +* Copyright (C) 2008 Oracle. All rights reserved. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public +* License as published by the Free Software Foundation; either +* version 2 of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., 59 Temple Place - Suite 330, +* Boston, MA 021110-1307, USA. +*/
fs/ocfs2/xattr.h line 34
Quoted 10 lines
fs/ocfs2/xattr.h new file +10
-0+ +#ifndef OCFS2_XATTR_H +#define OCFS2_XATTR_H + +#include <linux/init.h> +#include <linux/xattr.h> + +/* Magic value in attribute blocks */ +#define OCFS2_XATTR_BLOCK_SIGNATURE_1 "XATTR01" +#define OCFS2_XATTR_BLOCK_SIGNATURE_2 "XATTR02
Did we still need the "XATTR02" signature? I thought it was taken out of the design. Looking through the doc, it's only referenced in an out-dated diagram.
Quoted 15 lines
fs/ocfs2/xattr.h new file +15
-0+ +enum ocfs2_xattr_type { +OCFS2_XATTR_INDEX_USER =1 , +OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS , +OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT , +OCFS2_XATTR_INDEX_TRUSTED , +OCFS2_XATTR_INDEX_LUSTRE , +OCFS2_XATTR_INDEX_SECURITY , +OCFS2_XATTR_MAX +}; + +struct ocfs2_xattr_entry { +__le32 xe_name_hash; +__le16 xe_name_offset; +__u8 xe_name_len;
fs/ocfs2/xattr.h line 59
Quoted 10 lines
fs/ocfs2/xattr.h new file +10
-0+ __u8 xe_type : 7; + __u8 xe_local : 1; +__le64 xe_value_size; +}; + +struct ocfs2_xattr_header { +__le16 xh_count; +__le16 xh_reserved1; +__le32 xh_csum; +__le16 xh_reserved2[4 ];
Could just be '__u64 xh_reserved2;'
--Mark
--
Mark Fasheh
PATCH 6/8 Add extent tree operation for xattr value.v1
In reply to Tao Mafs/ocfs2/alloc.c int ocfs2_insert_extent(struct ocfs2_super *osb, · line 4250
Quoted 7 lines · Tao Ma
fs/ocfs2/alloc.c +2
-1@@ -4199,7 +4246,8 @@ int ocfs2_insert_extent(struct ocfs2_super *osb,u32 new_clusters, u8 flags, struct ocfs2_alloc_context *meta_ac, - enum ocfs2_extent_tree_type et_type) + enum ocfs2_extent_tree_type et_type, + void *private)
Hmm, at this point, wouldn't it make sense to have a couple high-level "ocfs2_foo_insert_extent" functions whcih build up anm ocfs2_extent_tree and then pass it down to the common ocfs2_insert_extent?
Quoted 10 lines
fs/ocfs2/xattr.c new file +10
-0+static int ocfs2_xattr_value_truncate (struct inode *inode, +struct buffer_head *root_bh, +struct ocfs2_xattr_value_root *xv, +int len) +{ +int ret; +u32 new_clusters =ocfs2_clusters_for_bytes (inode->i_sb, len); +u32 old_clusters =le32_to_cpu (xv->xr_clusters); + +if (new_clusters == old_clusters)
fs/ocfs2/xattr.c line 298
Quoted 10 lines
fs/ocfs2/xattr.c new file +10
-0+return 0 ; + +if (new_clusters > old_clusters) + ret =ocfs2_xattr_extend_allocation (inode, + new_clusters - old_clusters, + root_bh, xv); +else + ret =ocfs2_xattr_shrink_size (inode, + old_clusters, new_clusters, + root_bh, xv);
If we shrink the xattr value, do you need to zero the area between the new size and the end of the last cluster? We do it for inodes because a later extend might expose the data which was trucated. But I think EA's don't have that equivalent operation?
--Mark
--
Mark Fasheh
PATCH 3/8 Make ocfs2_lock_allocators generic for extent allocation.v1
In reply to Tao MaQuoted 12 lines · Tao Ma
Hi Mark,
Thanks for the review.
I will modify it according to your suggestions.Quoted 7 lines · Mark Fasheh
The rest of this looks good. It's a big patch, but it looks good :) The only
conern I have isn't really with your code per se, but with layout of our source files.Alloc.ckeeps growing... and growing... and growing... At some
point it might be worth our while to split things out at least so that we have a 'core btree operations' file.
Quoted 4 lines
Yes, now
alloc.chave more than 6000 lines. And maybe a new file namebtree.ccan be split out from this file that will do the real work of btree operation since with my patch, btree now isn't used by inode only. ;) I will handle this after the xattr patch is committed. Thanks.
Btree.c sounds good to me. I think maybe we can split out some parts of the indexed btree code into their own file as well - that last patch looks pretty big ;)
--Mark
Quoted 3 lines
Regards,
Tao
--
Mark Fasheh
PATCH 6/8 Add extent tree operation for xattr value.v1
In reply to Mark FashehHi Mark,
Quoted 12 lines · Mark Fasheh
fs/ocfs2/alloc.c int ocfs2_insert_extent(struct ocfs2_super *osb, · line 4250
Quoted 7 lines · Tao Ma
fs/ocfs2/alloc.c +2
-1@@ -4199,7 +4246,8 @@ int ocfs2_insert_extent(struct ocfs2_super *osb,u32 new_clusters, u8 flags, struct ocfs2_alloc_context *meta_ac, - enum ocfs2_extent_tree_type et_type) + enum ocfs2_extent_tree_type et_type, + void *private)Hmm, at this point, wouldn't it make sense to have a couple high-level "
ocfs2_foo_insert_extent" functions whcih build up anmocfs2_extent_treeand then pass it down to the commonocfs2_insert_extent?
Why do we need that? Just to reduce the parameter to one "ocfs2_extent_tree *"? ;) Any other benefit?
Quoted 19 lines
Quoted 19 lines
fs/ocfs2/xattr.c new file +17
-0+static int ocfs2_xattr_value_truncate (struct inode *inode, +struct buffer_head *root_bh, +struct ocfs2_xattr_value_root *xv, +int len) +{ +int ret; +u32 new_clusters =ocfs2_clusters_for_bytes (inode->i_sb, len); +u32 old_clusters =le32_to_cpu (xv->xr_clusters); + +if (new_clusters == old_clusters) +return 0 ; + +if (new_clusters > old_clusters) + ret =ocfs2_xattr_extend_allocation (inode, + new_clusters - old_clusters, + root_bh, xv); +else
Quoted 8 lines
fs/ocfs2/xattr.c line 298
Quoted 3 lines
fs/ocfs2/xattr.c new file +3
-0+ ret =ocfs2_xattr_shrink_size (inode, + old_clusters, new_clusters, + root_bh, xv);If we shrink the xattr value, do you need to zero the area between the new size and the end of the last cluster? We do it for inodes because a later extend might expose the data which was trucated. But I think EA's don't have that equivalent operation?
Yes, that is the reason I do this. In EA, I think normally when we extend it by setting larger values, we will definitely set the content. So we can't extend a EA without setting the value here like we do in inodes
Regards,
Tao
PATCH 5/8 Add xattr header in ocfs2.v1
In reply to Mark FashehQuoted 7 lines · Mark Fasheh
Quoted 6 lines · Tao Ma
Signed-off-by Tao Ma <[email protected]>--- fs/ocfs2/xattr.h | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 95 insertions(+), 0 deletions(-) create mode 100644 fs/ocfs2/xattr.h
Quoted 6 lines
fs/ocfs2/xattr.h
Quoted 3 lines
fs/ocfs2/xattr.h new file +0
-0Can we put this in
ocfs2_fs.hinstead? That way we still have just one place to look for describing the disk format.
ext3 separate its ext header in xattr.h, so we do like it does. But you may be right since we put all the stuffs concerning disk format in ocfs2_fs.h. I will modify it.
Quoted 35 lines
Quoted 35 lines
fs/ocfs2/xattr.h new file +30
-0@@ -0,0 +1,95 @@ +/* -*- mode: c; c-basic-offset: 8; -*- +* vim: noexpandtab sw=8 ts=8 sts=0: +* +* xattr.h +* +* Function prototypes +* +* Copyright (C) 2008 Oracle. All rights reserved. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public +* License as published by the Free Software Foundation; either +* version 2 of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public +* License along with this program; if not, write to the +* Free Software Foundation, Inc., 59 Temple Place - Suite 330, +* Boston, MA 021110-1307, USA. +*/ + +#ifndef OCFS2_XATTR_H +#define OCFS2_XATTR_H + +#include <linux/init.h> +#include <linux/xattr.h>
Quoted 8 lines
fs/ocfs2/xattr.h
Quoted 4 lines
fs/ocfs2/xattr.h new file +4
-0+ +/* Magic value in attribute blocks */ +#define OCFS2_XATTR_BLOCK_SIGNATURE_1 "XATTR01" +#define OCFS2_XATTR_BLOCK_SIGNATURE_2 "XATTR02Did we still need the "XATTR02" signature? I thought it was taken out of the design. Looking through the doc, it's only referenced in an out-dated diagram.
Yes, it is from Tiger's original implementation. I will remove it. Thanks.
Quoted 21 lines
Quoted 21 lines
fs/ocfs2/xattr.h new file +19
-0+ +enum ocfs2_xattr_type { +OCFS2_XATTR_INDEX_USER =1 , +OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS , +OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT , +OCFS2_XATTR_INDEX_TRUSTED , +OCFS2_XATTR_INDEX_LUSTRE , +OCFS2_XATTR_INDEX_SECURITY , +OCFS2_XATTR_MAX +}; + +struct ocfs2_xattr_entry { +__le32 xe_name_hash; +__le16 xe_name_offset; +__u8 xe_name_len; +__u8 xe_type :7 ; +__u8 xe_local :1 ; +__le64 xe_value_size; +};
Quoted 8 lines
fs/ocfs2/xattr.h line 59
Quoted 6 lines
fs/ocfs2/xattr.h new file +6
-0+ +struct ocfs2_xattr_header { +__le16 xh_count; +__le16 xh_reserved1; +__le32 xh_csum; +__le16 xh_reserved2[4 ];Could just be '
__u64xh_reserved2;'
Should be. Will modify it.
Regards,
Tao
PATCH 4/8 Make extend allocation generic.v1
In reply to Mark FashehQuoted 9 lines · Mark Fasheh
fs/ocfs2/file.c int ocfs2_do_extend_allocation(struct ocfs2_super *osb, · line 509
Quoted 3 lines · Tao Ma
fs/ocfs2/file.c +0
-0@@ -508,96 +508,14 @@ int ocfs2_do_extend_allocation(struct ocfs2_super *osb,struct ocfs2_alloc_context *meta_ac, enum ocfs2_alloc_restarted *reason_ret)I think you should rename
ocfs2_do_extend_allocationto something more direct since it's used only for traditional inode data btrees. Maybeocfs2_add_inode_data()?
How about ocfs2_add_inode_data_in_extent? So that it means we allocate extent rec to store it?
Quoted 8 lines
Quoted 8 lines
fs/ocfs2/suballoc.c +0
-0@@ -1973,3 +1973,106 @@ out:
Quoted 7 lines
fs/ocfs2/suballoc.c out: · line 1977
Quoted 4 lines
fs/ocfs2/suballoc.c +2
-0return ret; } + +int ocfs2_do_cluster_allocation(struct ocfs2_super *osb,Likewise, this name doesn't tell me much about the function. Also, a comment describing it's expected usage would be nice ;)
How about the name ocfs2_add_cluster_for_extent?
Quoted 7 lines
fs/ocfs2/suballoc.c out: · line 1980
Quoted 5 lines
fs/ocfs2/suballoc.c +3
-0+struct inode *inode, + u32 *logical_offset, + u32 *clusters_to_add,This changed to a "u32 *" but you gave no explanation of why.
Yes, this is used by the *old* xattr extend allocation, so that the user can detect how much the clusters have been added. Now I can do it in another way.So I will not change it in my revised patch. Thanks.
Regards,
Tao
PATCH 6/8 Add extent tree operation for xattr value.v1
In reply to Tao MaQuoted 38 lines
fs/ocfs2/xattr.c new file +38
-0+static int ocfs2_xattr_shrink_size (struct inode *inode, +u32 old_clusters, +u32 new_clusters, +struct buffer_head *root_bh, +struct ocfs2_xattr_value_root *xv) +{ +int ret =0 ; +u32 trunc_len, cpos, phys_cpos, alloc_size; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); +struct ocfs2_cached_dealloc_ctxt dealloc; + +ocfs2_init_dealloc_ctxt (&dealloc); + +if (old_clusters <= new_clusters) +return 0 ; + + cpos = new_clusters; + trunc_len = old_clusters - new_clusters; +while (trunc_len) { + ret =ocfs2_xattr_get_clusters (inode, cpos, &phys_cpos, + &alloc_size, &xv->xr_list); +if (ret) { +mlog_errno (ret); + goto out; + } + +if (alloc_size > trunc_len) + alloc_size = trunc_len; + + ret =__ocfs2_remove_xattr_range (inode, root_bh, xv, cpos, + phys_cpos, alloc_size, + &dealloc); +if (ret) { +mlog_errno (ret); + goto out; + } + + cpos += alloc_size;
fs/ocfs2/xattr.c line 277
Quoted 10 lines
fs/ocfs2/xattr.c new file +10
-0+ trunc_len -= alloc_size; + } + +out: +ocfs2_schedule_truncate_log_flush (osb,1 ); +ocfs2_run_deallocs (osb, &dealloc); + +return ret; +return 0 ; +}
You have two 'return' statements here.
--Mark
--
Mark Fasheh
PATCH 6/8 Add extent tree operation for xattr value.v1
In reply to Tao MaQuoted 6 lines · Tao Ma
Quoted 4 lines
Hmm, at this point, wouldn't it make sense to have a couple high-level "
ocfs2_foo_insert_extent" functions whcih build up anmocfs2_extent_treeand
then pass it down to the commonocfs2_insert_extent?Why do we need that? Just to reduce the parameter to one "
ocfs2_extent_tree*"? ;) Any other benefit?
No, that's mostly what I was concerned with. Well, that and type-checking - we don't have to have a void * in ocfs2_insert_extent any more.
--Mark
--
Mark Fasheh
PATCH 7/8 ocfs2: Add extended attributes support. v1
In reply to Tiger YangOk, so I only got halfway through this one today - I'll have to pick it up tommorrow. In the meantime, here are the comments I have so far. My hope is that you can at least start from what I've gathered here.
--Mark
Quoted 2 lines · Tiger Yang
This patch implement storing extended attributes both in inode or metadata block. For EAs in inode, we reserve the last 256 bytes in inode block(blocksize >= 1024).
Ok, so this comes out to the space occupied by 16 extent records. Imho, for block sizes 1k and over, this is a perfectly reasonable amount of space to devote to ea storage.
Quoted 80 lines
fs/ocfs2/ocfs2_fs.h +27
-9@@ -291,6 +291,9 @@ struct ocfs2_new_group_input {/* Journal limits (in bytes) */ #define OCFS2_MIN_JOURNAL_SIZE (4 * 1024 * 1024) +/* Inline extended attribute size (in bytes) */ +#define OCFS2_MAX_XATTR_INLINE_SIZE 256 +/* * Default local alloc size (in megabytes) * @@ -640,11 +643,12 @@ struct ocfs2_dinode {__le32 i_atime_nsec;__le32 i_ctime_nsec;__le32 i_mtime_nsec; -__le32 i_attr; +/*70*/ __le32 i_attr;__le16 i_orphaned_slot;/* Only valid when OCFS2_ORPHANED_FL was set in i_flags */ __le16 i_dyn_features; -/*70*/ __le64 i_reserved2[8 ]; +__le64 i_xattr_loc; +/*80*/ __le64 i_reserved2[7 ];/*B8*/ union {__le64 i_pad1;/* Generic way to refer to this 64bit union */ @@ -721,16 +725,26 @@ static inline int ocfs2_fast_symlink_chars(struct super_block *sb)static inline int ocfs2_max_inline_data (struct super_block *sb) { -return sb->s_blocksize - - offsetof(struct ocfs2_dinode, id2.i_data.id_data); +if (sb->s_blocksize !=OCFS2_MIN_BLOCKSIZE ) +return sb->s_blocksize - + offsetof(struct ocfs2_dinode, id2.i_data.id_data) - +OCFS2_MAX_XATTR_INLINE_SIZE ; +else +return sb->s_blocksize - + offsetof(struct ocfs2_dinode, id2.i_data.id_data); }static inline int ocfs2_extent_recs_per_inode (struct super_block *sb) {int size; - size = sb->s_blocksize - - offsetof(struct ocfs2_dinode, id2.i_list.l_recs); +if (sb->s_blocksize !=OCFS2_MIN_BLOCKSIZE ) + size = sb->s_blocksize - + offsetof(struct ocfs2_dinode, id2.i_list.l_recs) - +OCFS2_MAX_XATTR_INLINE_SIZE ; +else + size = sb->s_blocksize - + offsetof(struct ocfs2_dinode, id2.i_list.l_recs);return size /sizeof (struct ocfs2_extent_rec ); }@@ -806,15 +820,26 @@ static inline int ocfs2_fast_symlink_chars(int blocksize)static inline int ocfs2_max_inline_data (int blocksize) { - return blocksize - offsetof(struct ocfs2_dinode, id2.i_data.id_data); +if (blocksize !=OCFS2_MIN_BLOCKSIZE ) +return blocksize - + offsetof(struct ocfs2_dinode, id2.i_data.id_data) - +OCFS2_MAX_XATTR_INLINE_SIZE ; +else +return blocksize - + offsetof(struct ocfs2_dinode, id2.i_data.id_data); }static inline int ocfs2_extent_recs_per_inode (int blocksize) {int size; - size = blocksize - - offsetof(struct ocfs2_dinode, id2.i_list.l_recs);
fs/ocfs2/ocfs2_fs.h static inline int ocfs2_fast_symlink_chars(int blocksize) · line 845
Quoted 10 lines
fs/ocfs2/ocfs2_fs.h +7
-0+if (blocksize !=OCFS2_MIN_BLOCKSIZE ) + size = blocksize - + offsetof(struct ocfs2_dinode, id2.i_list.l_recs) - +OCFS2_MAX_XATTR_INLINE_SIZE ; +else + size = blocksize - + offsetof(struct ocfs2_dinode, id2.i_list.l_recs);return size /sizeof (struct ocfs2_extent_rec ); }
You can't just change these functions like that - by doing so, you are effectively changing the disk format. Say I have an existing file system and I run your code. Now the module is going to think some of my inline-data files are too large, and that some of my extent lists have overflowed. New inodes will have different values for no good reason (pretend that I don't have EA support turned on yet).
I think what we need to do is replace some occurences of these calls with an inode-block specific version of the function in question. The new functions will take things like whether an inode has inline EA's into account. For example:
static inline int ocfs2_max_inline_data(struct super_block *sb,
struct ocfs2_dinode *di)
{
if (le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_XATTR_FL)
return le64_to_cpu(di->i_xattr_loc) -
offsetof(struct ocfs2_dinode, id2.i_data.id_data);
else
return sb->s_blocksize -
offsetof(struct ocfs2_dinode, id2.i_data.id_data);
}You'll have to go through the code and determine where we need to use the new functions. Please do this as a seperate patch by the way - it's a tricky enough operation that I will refuse to read the change if it's intermingled with other stuff.
Quoted 36 lines
fs/ocfs2/xattr.c +14
-0@@ -21,6 +21,19 @@* Boston, MA 021110-1307, USA. */ +#include <linux/capability.h> +#include <linux/fs.h> +#include <linux/types.h> +#include <linux/slab.h> +#include <linux/highmem.h> +#include <linux/pagemap.h> +#include <linux/uio.h> +#include <linux/sched.h> +#include <linux/splice.h> +#include <linux/mount.h> +#include <linux/writeback.h> +#include <linux/falloc.h> +#define MLOG_MASK_PREFIX ML_INODE#include <cluster/masklog.h> @@ -28,6 +41,7 @@#include "alloc.h" #include "dlmglue.h" #include "file.h" +#include "sysfile.h" #include "inode.h" #include "journal.h" #include "ocfs2_fs.h" @@ -36,6 +50,129 @@#include "buffer_head_io.h" #include "xattr.h"
fs/ocfs2/xattr.c line 62
Quoted 10 lines
fs/ocfs2/xattr.c +10
-0+ +#define OCFS2_XATTR_PAD_BITS 2 +#define OCFS2_XATTR_PAD 4 +#define OCFS2_XATTR_ROUND (OCFS2_XATTR_PAD-1) +#define OCFS2_XATTR_SIZE (size) (((size) + OCFS2_XATTR_ROUND) & \ + ~OCFS2_XATTR_ROUND) +#define OCFS2_XATTR_ROOT_SIZE (sizeof(struct ocfs2_xattr_def_value_root)) +#define OCFS2_XATTR_INLINE_SIZE 80 +#define OCFS2_NAME_HASH_SHIFT 5 +#define OCFS2_VALUE_HASH_SHIFT 16
Some of these should be defined in the patch where they're actually used.
Quoted 48 lines
fs/ocfs2/xattr.c +48
-0+static struct ocfs2_xattr_def_value_root def_xv = { + .xv.xr_list.l_count =cpu_to_le16 (1 ), +}; + +struct xattr_handler *ocfs2_xattr_handlers[] = { + &ocfs2_xattr_user_handler, +#ifdef CONFIG_OCFS2_FS_POSIX_ACL + &ocfs2_xattr_acl_access_handler, + &ocfs2_xattr_acl_default_handler, +#endif + &ocfs2_xattr_trusted_handler, +#ifdef CONFIG_OCFS2_FS_LUSTRE + &ocfs2_xattr_lustre_handler, +#endif +#ifdef CONFIG_OCFS2_FS_SECURITY + &ocfs2_xattr_security_handler, +#endif +NULL +}; + +static struct xattr_handler *ocfs2_xattr_handler_map[] = { + [OCFS2_XATTR_INDEX_USER ] = &ocfs2_xattr_user_handler, +#ifdef CONFIG_OCFS2_FS_POSIX_ACL + [OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS ] + = &ocfs2_xattr_acl_access_handler, + [OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT ] + = &ocfs2_xattr_acl_default_handler, +#endif + [OCFS2_XATTR_INDEX_TRUSTED ] = &ocfs2_xattr_trusted_handler, +#ifdef CONFIG_OCFS2_FS_LUSTRE + [OCFS2_XATTR_INDEX_LUSTRE ] = &ocfs2_xattr_lustre_handler, +#endif +#ifdef CONFIG_OCFS2_FS_SECURITY + [OCFS2_XATTR_INDEX_SECURITY ] = &ocfs2_xattr_security_handler, +#endif +}; + +struct ocfs2_xattr_info { +int name_index; +const char *name; +const void *value; +size_t value_len; +}; + +struct ocfs2_xattr_search { +struct buffer_head *inode_bh; +struct buffer_head *xattr_bh; +struct ocfs2_xattr_header *header;
fs/ocfs2/xattr.c line 121
Quoted 10 lines
fs/ocfs2/xattr.c +10
-0+void *base; +void *end; +struct ocfs2_xattr_entry *here; +int not_found; +}; + +static inline u32 ocfs2_blocks_per_cluster (struct super_block *sb) +{ +return 1 << (OCFS2_SB (sb)->s_clustersize_bits - sb->s_blocksize_bits); +}
You could just:
#define ocfs2_blocks_per_cluster(_sb) ocfs2_blocks_to_clusters((_sb), 1)
At any rate, this belongs in ocfs2.h.
Quoted 21 lines
fs/ocfs2/xattr.c +21
-0+static inline struct xattr_handler *ocfs2_xattr_handler (int name_index) +{ +struct xattr_handler *handler =NULL ; + +if (name_index >0 && name_index <OCFS2_XATTR_MAX ) + handler = ocfs2_xattr_handler_map[name_index]; + +return handler; +} + +static inline __u32 ocfs2_xattr_name_hash (char *prefix, +int prefix_len, +char *name, +int name_len) +{ +__u32 hash =0 ; +int i; + +for (i =0 ; i < prefix_len; i++) { + hash = (hash <<OCFS2_NAME_HASH_SHIFT ) ^ + (hash >> (8*sizeof(hash) - OCFS2_NAME_HASH_SHIFT)) ^
fs/ocfs2/xattr.c line 153
Quoted 10 lines
fs/ocfs2/xattr.c +10
-0+ *prefix++; + } + +for (i =0 ; i < name_len; i++) { + hash = (hash <<OCFS2_NAME_HASH_SHIFT ) ^ + (hash >> (8 *sizeof (hash) -OCFS2_NAME_HASH_SHIFT )) ^ + *name++; + } +return hash; +}
What hash function is this? Where did you get it from? How good is it for use with EA names? How good is it for other uses? Answers to all those questions belong here in e-mail, as well as a nice big comment at the top of this function.
Also, there's this item in the design doc:
* need a random seed in super block which is never printed on console
We want to combine the random seed with the hashing process somehow so that the results for a given name are not globally predictable for all Ocfs2 file systems.
Quoted 25 lines
fs/ocfs2/xattr.c +21
-0+/* +* ocfs2_xattr_hash_entry() +* +* Compute the hash of an extended attribute. +*/ +static void ocfs2_xattr_hash_entry (struct ocfs2_xattr_header *header, +struct ocfs2_xattr_entry *entry) +{ +__u32 hash =0 ; +struct xattr_handler *handler =ocfs2_xattr_handler (entry->xe_type); +char *prefix = handler->prefix; +char *name = (char *)header +le16_to_cpu (entry->xe_name_offset); +int prefix_len =strlen (handler->prefix); + + hash =ocfs2_xattr_name_hash (prefix, prefix_len, name, + entry->xe_name_len); + entry->xe_name_hash =cpu_to_le32 (hash); + +return ; +} + static int ocfs2_xattr_extend_allocation(struct inode *inode, u32 clusters_to_add, struct buffer_head *xattr_bh,
fs/ocfs2/xattr.c static int ocfs2_xattr_extend_allocation(struct inode *inode, · line 190
Quoted 5 lines
fs/ocfs2/xattr.c +1
-1@@ -50,7 +187,7 @@ static int ocfs2_xattr_extend_allocation(struct inode *inode,enum ocfs2_alloc_restarted why;struct ocfs2_super *osb =OCFS2_SB (inode->i_sb);struct ocfs2_extent_list *root_el = &xv->xr_list; -u32 logical_start =le16_to_cpu (xv->xr_clusters); +u32 logical_start =le32_to_cpu (xv->xr_clusters);
Is this a bug fix? Next round, please just merge that into the patch which introduces the code.
Quoted 14 lines
fs/ocfs2/xattr.c +14
-0+int ocfs2_xattr_get (struct inode *inode, +int name_index, +const char *name, +void *buffer, +size_t buffer_size) +{ +int ret; +struct ocfs2_dinode *di =NULL ; +struct buffer_head *di_bh =NULL ; +struct ocfs2_xattr_search xis = { + .not_found = -ENODATA , + }; +struct ocfs2_xattr_search xbs = { + .not_found = -ENODATA ,
fs/ocfs2/xattr.c static int ocfs2_xattr_value_truncate(struct inode *inode, · line 762
Quoted 10 lines
fs/ocfs2/xattr.c +10
-0+ }; + + ret =ocfs2_inode_lock (inode, &di_bh,0 ); +if (ret <0 ) { +mlog_errno (ret); +return ret; + } + xis.inode_bh = xbs.inode_bh = di_bh; + di = (struct ocfs2_dinode *)di_bh->b_data; +if (!(le16_to_cpu (di->i_dyn_features) &OCFS2_HAS_XATTR_FL )) {
A lot of these checks are using the disk field, when it's faster and more readable to look at the ocfs2_inode_info->ip_dyn_features.
Quoted 63 lines
fs/ocfs2/xattr.c +62
-0+ ret = -ENODATA ; + goto cleanup; + } + + ret =ocfs2_xattr_ibody_get (inode, name_index, name, buffer, + buffer_size, &xis); +if (ret == -ENODATA ) + ret =ocfs2_xattr_block_get (inode, name_index, name, buffer, + buffer_size, &xbs); +cleanup: +ocfs2_inode_unlock (inode,0 ); + +if (di_bh) +brelse (di_bh); +return ret; +} + +/* +* ocfs2_xattr_remove() +* +* Free extended attribute resources associated with this inode. +*/ +int ocfs2_xattr_remove (struct inode *inode,struct buffer_head *di_bh) +{ +struct ocfs2_xattr_block *xb; +struct buffer_head *blk_bh =NULL ; +struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; +struct ocfs2_super *osb =OCFS2_SB (inode->i_sb); +handle_t *handle; +int ret; + +if (!(le16_to_cpu (di->i_dyn_features) &OCFS2_HAS_XATTR_FL )) +return 0 ; + +if (le16_to_cpu (di->i_dyn_features) &OCFS2_INLINE_XATTR_FL ) { + ret =ocfs2_xattr_ibody_remove (inode, di_bh); +if (ret <0 ) +mlog_errno (ret); + } +if (di->i_xattr_loc) { + ret =ocfs2_read_block (OCFS2_SB (inode->i_sb), +le64_to_cpu (di->i_xattr_loc), + &blk_bh,OCFS2_BH_CACHED , inode); +if (ret) +return ret; + ret =ocfs2_xattr_block_remove (inode, blk_bh); +if (ret <0 ) +mlog_errno (ret); + } + + handle =ocfs2_start_trans ((OCFS2_SB (inode->i_sb)), +OCFS2_INODE_UPDATE_CREDITS ); +if (IS_ERR (handle)) { + ret =PTR_ERR (handle); + goto out; + } + ret =ocfs2_journal_access (handle, inode, di_bh, +OCFS2_JOURNAL_ACCESS_WRITE ); +if (ret) { +mlog_errno (ret); + goto out_commit; + }
fs/ocfs2/xattr.c
Quoted 10 lines
fs/ocfs2/xattr.c +10
-0+ +if (di->i_xattr_loc) { + xb = (struct ocfs2_xattr_block *)blk_bh->b_data; +ocfs2_xattr_free_block (handle, osb, xb); + di->i_xattr_loc =cpu_to_le64 (0 ); + } + + di->i_dyn_features =cpu_to_le16 (le16_to_cpu (di->i_dyn_features) & + !OCFS2_INLINE_XATTR_FL & + !OCFS2_HAS_XATTR_FL );
You aren't updating OCFS2_I(inode)->ip_dyn_features, and boy is this code confusing to read. Also, I'm not sure '!' is the operator you want to use. This is so much better:
struct ocfs2_inode_info *oi = OCFS2_I(inode);
...
oi->ip_dyn_features &= ~(OCFS2_INLINE_XATTR_FL|OCFS2_HAS_XATTR_FL); di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features);
Quoted 22 lines
fs/ocfs2/xattr.c +22
-0+ ret =ocfs2_journal_dirty (handle, di_bh); +if (ret <0 ) +mlog_errno (ret); +out_commit: +ocfs2_commit_trans (OCFS2_SB (inode->i_sb), handle); +out: +if (blk_bh) +brelse (blk_bh); +return ret; +} + +static int ocfs2_xattr_update_flag (struct inode *inode, +struct buffer_head *di_bh, +int flag) +{ +struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; +handle_t *handle =NULL ; +int ret =0 ; + + handle =ocfs2_start_trans ((OCFS2_SB (inode->i_sb)), +OCFS2_INODE_UPDATE_CREDITS ); +if (IS_ERR (handle)) {
fs/ocfs2/xattr.c static int ocfs2_xattr_value_truncate(struct inode *inode, · line 1356
Quoted 10 lines
fs/ocfs2/xattr.c +10
-0+ ret =PTR_ERR (handle); + goto out; + } + ret =ocfs2_journal_access (handle, inode, di_bh, +OCFS2_JOURNAL_ACCESS_WRITE ); +if (ret) { +mlog_errno (ret); + goto out_commit; + } +
Again, you aren't updating OCFS2_I(inode)->ip_dyn_features.
fs/ocfs2/xattr.c static int ocfs2_xattr_value_truncate(struct inode *inode, · line 1367
Quoted 11 lines
fs/ocfs2/xattr.c +11
-0+ di->i_dyn_features =cpu_to_le16 (le16_to_cpu (di->i_dyn_features) | + flag); + ret =ocfs2_journal_dirty (handle, di_bh); +if (ret <0 ) +mlog_errno (ret); +out_commit: +ocfs2_commit_trans (OCFS2_SB (inode->i_sb), handle); +out: +return ret; +} +
--
Mark Fasheh
PATCH 6/8 Add extent tree operation for xattr value.v1
In reply to Mark FashehQuoted 10 lines · Mark Fasheh
Quoted 6 lines · Tao Ma
Quoted 4 lines
Hmm, at this point, wouldn't it make sense to have a couple high-level "
ocfs2_foo_insert_extent" functions whcih build up anmocfs2_extent_treeand
then pass it down to the commonocfs2_insert_extent?Why do we need that? Just to reduce the parameter to one "
ocfs2_extent_tree*"? ;) Any other benefit?No, that's mostly what I was concerned with. Well, that and type-checking - we don't have to have a void * in
ocfs2_insert_extentany more.
Then how about add 3 functions: ocfs2_inode_insert_extent, ocfs2_xattr_value_insert_extent and ocfs2_xattr_tree_insert_extent(for xattr index btree, and it will show up in the last patch). All the old callers in file.c etc will call ocfs2_dinode_insert_extent, while the other two handle the xattr issue. And the init of extent tree are handled by these functions?
Regards,
Tao
PATCH 7/8 ocfs2: Add extended attributes support. v1
In reply to Mark FashehQuoted 4 lines · Mark Fasheh
Quoted 4 lines
fs/ocfs2/xattr.c +4
-0+ +#define OCFS2_XATTR_PAD_BITS 2 +#define OCFS2_XATTR_PAD 4 +#define OCFS2_XATTR_ROUND (OCFS2_XATTR_PAD-1)
Quoted 8 lines
fs/ocfs2/xattr.c line 62
Quoted 6 lines
fs/ocfs2/xattr.c +6
-0+#define OCFS2_XATTR_SIZE (size) (((size) + OCFS2_XATTR_ROUND) & \ + ~OCFS2_XATTR_ROUND) +#define OCFS2_XATTR_ROOT_SIZE (sizeof(struct ocfs2_xattr_def_value_root)) +#define OCFS2_XATTR_INLINE_SIZE 80 +#define OCFS2_NAME_HASH_SHIFT 5 +#define OCFS2_VALUE_HASH_SHIFT 16Some of these should be defined in the patch where they're actually used.
I wonder whether we should put the below lines into ocfs2_fs.h(combined with my previous xattr header patch)?
#define OCFS2_XATTR_PAD_BITS 2
#define OCFS2_XATTR_PAD 4
#define OCFS2_XATTR_ROUND (OCFS2_XATTR_PAD-1)
#define OCFS2_XATTR_SIZE(size) (((size) + OCFS2_XATTR_ROUND) & \ ~OCFS2_XATTR_ROUND)
ocfs2-tools also need this when fsck try to find the large xattr value. So if we put them in ocfs2_fs.h, we can keep both tools and kernel src synchronized easily.
Regards,
Tao
PATCH 7/8 ocfs2: Add extended attributes support. v1
In reply to Mark FashehHi, Mark,
Thanks for review my patch and comments.
Quoted 5 lines · Mark Fasheh
You'll have to go through the code and determine where we need to use the new functions. Please do this as a seperate patch by the way - it's a tricky enough operation that I will refuse to read the change if it's intermingled with other stuff.
This is a serious problem. The patch attached fix this problem. My patch could handle EAs in inode block or in external block at the same times. That is little different between design doc.
If we find free space inline, we will set EAs in it firstly, otherwise we will set EAs in external block. This resolution just like ext3 does. So i_xattr_loc could only be used for contain the number of external block.
Quoted 7 lines
What hash function is this? Where did you get it from? How good is it for
use with EA names? How good is it for other uses? Answers to all those questions belong here in e-mail, as well as a nice big comment at the top of this function.
Quoted 7 lines
Also, there's this item in the design doc:
* need a random seed in super block which is never printed on consoleWe want to combine the random seed with the hashing process somehow so that the results for a given name are not globally predictable for all Ocfs2 file systems.
I got this hash function form ext3_xattr_hash_entry(). In design doc, "The hash value is calculated using the full (prefix.suffix) name of the xattr to avoid hash collisions when the same suffix is used in multiple attribute namespaces. It it used to identify when a name is not going to match before doing a string comparison to verify that the name is a match.", so I got the hash value form EA's prefix and EA's name. Actually I didn't compare hash value and sort EAs when EAs in inode for in external block, Because only few EAs could be stored in inode or external block. Tao use this hash value for large number EAs in bucket. Next I will use that random seed for hash value.
I will correct other problems you commented.
Best regards,
tiger
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Reserve-space-in-inode-block-for-extented-attribute.patch
Type: text/x-patch
Size: 5848 bytes
Desc: not available
Url : http://oss.oracle.com/pipermail/ocfs2-devel/attachments/20080616/14db24eb/attachment.bin
PATCH 7/8 ocfs2: Add extended attributes support. v1
Quoted 8 lines · Tiger Yang
Quoted 6 lines · Mark Fasheh
You'll have to go through the code and determine where we need to use the new functions. Please do this as a seperate patch by the way - it's a tricky
enough operation that I will refuse to read the change if it's intermingled with other stuff.This is a serious problem. The patch attached fix this problem.
Great! I have one more comment regarding all this, below.
Quoted 5 lines
My patch could handle EAs in inode block or in external block at the same times. That is little different between design doc.
If we find free space inline, we will set EAs in it firstly, otherwise we will set EAs in external block. This resolution just like ext3 does. Soi_xattr_loccould only be used for contain the number of external block.
Go ahead and add a field to record inline xattr size on the inode. For now, if we're going to take some space for inline EA, you will always just set it to osb->s_min_inline_xattr, which is always OCFS2_MIN_XATTR_INLINE_SIZE.
So, use osb->s_min_inline_xattr to figure out whether there's enough space in the inode for xattrs and set the initial inode field based on it. But after that, use i_inline_xattr_size (or whatever you call it) to figure out offset to start in the inode from the end of block, how many bytes to scan, etc.
The two reasons I think this is a good idea:
- The inline xattr data size is explicitely stored on disk, as opposed to being assumed from a constant stored in memory.
- We don't have to rely on the minimum size to stay the same for all inodes on a file system. If we need to tune defaults, this becomes much easier if new inodes can just inherit the new value without affecting existing ones.
Quoted 16 lines
Quoted 8 lines
What hash function is this? Where did you get it from? How good is it for
use with EA names? How good is it for other uses? Answers to all those questions belong here in e-mail, as well as a nice big comment at the top of
this function.Quoted 8 lines
Also, there's this item in the design doc:
* need a random seed in super block which is never printed on consoleWe want to combine the random seed with the hashing process somehow so that the results for a given name are not globally predictable for all Ocfs2 file
systems.
Quoted 10 lines
I got this hash function form
ext3_xattr_hash_entry(). In design doc, "The hash value is calculated using the full (prefix.suffix) name of the xattr to avoid hash collisions when the same suffix is used in multiple attribute namespaces. It it used to identify when a name is not going to match before doing a string comparison to verify that the name is a match.", so I got the hash value form EA's prefix and EA's name. Actually I didn't compare hash value and sort EAs when EAs in inode for in external block, Because only few EAs could be stored in inode or external block. Tao use this hash value for large number EAs in bucket. Next I will use that random seed for hash value.
Ok, thanks for the explanation. We should keep in mind that ext3 can't store as many xattrs as we can so a bit of investigation into the effectiveness of this hash function for our use might be a good idea.
Quoted 1 line
I will correct other problems you commented.
Thanks, Tiger.
--Mark
--
Mark Fasheh
PATCH 7/8 ocfs2: Add extended attributes support. v1
In reply to Tiger YangOk, this more or less completes my review of this patch for this version of the changes.
Quoted 11 lines · Tiger Yang
index c223ab0..ed07448 100644
fs/ocfs2/xattr.c +4
-0@@ -21,6 +21,19 @@* Boston, MA 021110-1307, USA. */ +#include <linux/capability.h> +#include <linux/fs.h> +#include <linux/types.h> +#include <linux/slab.h>
fs/ocfs2/xattr.c line 37
Quoted 10 lines
fs/ocfs2/xattr.c +9
-0+#include <linux/highmem.h> +#include <linux/pagemap.h> +#include <linux/uio.h> +#include <linux/sched.h> +#include <linux/splice.h> +#include <linux/mount.h> +#include <linux/writeback.h> +#include <linux/falloc.h> +#define MLOG_MASK_PREFIX ML_INODE
How about adding a new prefix, ML_XATTR? That would make debugging a bit easier.
Quoted 11 lines
fs/ocfs2/xattr.c +11
-0+static int ocfs2_xattr_block_list (struct inode *inode, +struct ocfs2_dinode *di, +char *buffer, +size_t buffer_size) +{ +struct buffer_head *blk_bh =NULL ; +struct ocfs2_xattr_header *header =NULL ; +int ret =0 ; + +if (!di->i_xattr_loc) +return ret;
fs/ocfs2/xattr.c static int ocfs2_xattr_value_truncate(struct inode *inode, · line 510
Quoted 10 lines
fs/ocfs2/xattr.c +10
-0+else { + ret =ocfs2_read_block (OCFS2_SB (inode->i_sb), +le64_to_cpu (di->i_xattr_loc), + &blk_bh,OCFS2_BH_CACHED , inode); +if (ret) +return ret; + } + + header = &((struct ocfs2_xattr_block *)blk_bh->b_data)-> + xb_attrs.xb_header;
Any reason why we don't do any signature checks of the newly read block before proceeding here?
fs/ocfs2/xattr.c static int ocfs2_xattr_value_truncate(struct inode *inode, · line 1040
Quoted 4 lines
fs/ocfs2/xattr.c +4
-0+static int ocfs2_xattr_set_entry (struct inode *inode, +struct ocfs2_xattr_info *xi, +struct ocfs2_xattr_search *xs) +{
Hmm, some comments describing this function would be helpfull. In particular, I'd like to know how failure in the middle of an operation is handled. Say you're expanding the ea because the user asked to store a larger size, but you hit a problem shortly after growing it. What happens?
Quoted 106 lines
fs/ocfs2/xattr.c +106
-0+struct ocfs2_xattr_entry *last; +size_t free, min_offs = xs->end - xs->base, name_len =strlen (xi->name); +size_t size_l =0 ; +handle_t *handle =NULL ; +int i, ret; +struct ocfs2_xattr_info xi_l = { + .name_index = xi->name_index, + .name = xi->name, + .value = xi->value, + .value_len = xi->value_len, + }; + +/* Compute min_offs and last. */ + last = xs->header->xh_entries; + +for (i =0 ; i <le16_to_cpu (xs->header->xh_count); i++) { +size_t offs =le16_to_cpu (last->xe_name_offset); +if (offs < min_offs) + min_offs = offs; + last +=1 ; + } + + free = min_offs - ((void *)last - xs->base) -sizeof (__u32); + +if (!xs->not_found) { +size_t size =0 ; +if (xs->here->xe_local) + size =OCFS2_XATTR_SIZE (name_len) + +OCFS2_XATTR_SIZE (le64_to_cpu (xs->here->xe_value_size)); +else + size =OCFS2_XATTR_SIZE (name_len) + +OCFS2_XATTR_ROOT_SIZE ; + free += (size +sizeof (struct ocfs2_xattr_entry )); + } +if (xi->value && xi->value_len >OCFS2_XATTR_INLINE_SIZE ) { +if (free <sizeof (struct ocfs2_xattr_entry ) + +OCFS2_XATTR_SIZE (name_len) + +OCFS2_XATTR_ROOT_SIZE ) { + ret = -ENOSPC ; + goto out; + } + size_l =OCFS2_XATTR_SIZE (name_len) +OCFS2_XATTR_ROOT_SIZE ; + xi_l.value = (void *)&def_xv; + xi_l.value_len =OCFS2_XATTR_ROOT_SIZE ; + }else if (xi->value) { +if (free <sizeof (struct ocfs2_xattr_entry ) + +OCFS2_XATTR_SIZE (name_len) + +OCFS2_XATTR_SIZE (xi->value_len)) { + ret = -ENOSPC ; + goto out; + } + } + +if (!xs->not_found) { +size_t size =OCFS2_XATTR_SIZE (name_len) + +OCFS2_XATTR_SIZE (le64_to_cpu (xs->here->xe_value_size)); +size_t offs =le16_to_cpu (xs->here->xe_name_offset); +void *val = xs->base + offs; + +if (xs->here->xe_local && size == size_l) { + ret =ocfs2_xattr_set_value_outside (inode, xi, xs, + offs); + goto out; + }else if (!xs->here->xe_local) { +struct ocfs2_xattr_value_root *xv =NULL ; + xv = (struct ocfs2_xattr_value_root *)(val + +OCFS2_XATTR_SIZE (name_len)); + +if (xi->value_len >OCFS2_XATTR_INLINE_SIZE ) { + ret =ocfs2_xattr_value_truncate (inode, + xs->xattr_bh, + xv, + xi->value_len); +if (ret <0 ) + goto out; + + ret =__ocfs2_xattr_set_value_outside (inode, + xv, + xi->value, + xi->value_len); +if (ret <0 ) + goto out; + + ret =ocfs2_xattr_update_entry (inode, + xi, + xs, + offs); + goto out; + }else + ret =ocfs2_xattr_value_truncate (inode, + xs->xattr_bh, + xv, +0 ); + } + } + + handle =ocfs2_start_trans ((OCFS2_SB (inode->i_sb)), +OCFS2_INODE_UPDATE_CREDITS ); +if (IS_ERR (handle)) { + ret =PTR_ERR (handle); + goto out; + } + + ret =ocfs2_journal_access (handle, inode, xs->xattr_bh, +OCFS2_JOURNAL_ACCESS_WRITE ); +if (ret) {
fs/ocfs2/xattr.c static int ocfs2_xattr_value_truncate(struct inode *inode, · line 1156
Quoted 10 lines
fs/ocfs2/xattr.c +10
-0+mlog_errno (ret); + goto out_commit; + } + +ocfs2_xattr_set_entry_local (inode, &xi_l, xs, last, min_offs); + + ret =ocfs2_journal_dirty (handle, xs->xattr_bh); +if (ret <0 ) +mlog_errno (ret); +
What are the atime/mtime/ctime semantics of xattr updates? I don't see any handling of that here. I think at the very least we want to update ctime on changes.
Quoted 19 lines
fs/ocfs2/xattr.h +5
-0@@ -77,6 +77,11 @@ struct ocfs2_xattr_tree_root {/*10*/ struct ocfs2_extent_list xt_list; }; +struct ocfs2_xattr_def_value_root { +struct ocfs2_xattr_value_root xv; +struct ocfs2_extent_rec er; +}; +#define OCFS2_XATTR_INDEXED 0x1struct ocfs2_xattr_block {@@ -95,4 +100,26 @@ struct ocfs2_xattr_block { } xb_attrs; };
fs/ocfs2/xattr.h struct ocfs2_xattr_block { · line 111
Quoted 10 lines
fs/ocfs2/xattr.h +9
-0+extern struct xattr_handler ocfs2_xattr_user_handler; +extern struct xattr_handler ocfs2_xattr_trusted_handler; +#ifdef CONFIG_OCFS2_FS_POSIX_ACL +extern struct xattr_handler ocfs2_xattr_acl_access_handler; +extern struct xattr_handler ocfs2_xattr_acl_default_handler; +#endif +#ifdef CONFIG_OCFS2_FS_LUSTRE +extern struct xattr_handler ocfs2_xattr_lustre_handler; +#endif
Drop the lustre prefix from these patches. It's just something that ext3/ext4 need to care about.
Speaking of ext3/ext4 - it's clear that some of this code was inspired or copied from them. That's a good thing as it's well tested code, but you need to make sure to give them proper credit at the top of the C files in question.
--Mark
--
Mark Fasheh
PATCH 7/8 ocfs2: Add extended attributes support. v1
In reply to Mark FashehQuoted 12 lines · Mark Fasheh
Quoted 12 lines
Go ahead and add a field to record inline xattr size on the inode. For now, if we're going to take some space for inline EA, you will always just set it to
osb->s_min_inline_xattr, which is alwaysOCFS2_MIN_XATTR_INLINE_SIZE.So, use
osb->s_min_inline_xattrto figure out whether there's enough space in the inode for xattrs and set the initial inode field based on it. But after that, usei_inline_xattr_size(or whatever you call it) to figure out offset to start in the inode from the end of block, how many bytes to scan, etc.The two reasons I think this is a good idea:
Quoted 7 lines
Quoted 7 lines
- The inline xattr data size is explicitely stored on disk, as opposed to being assumed from a constant stored in memory.
- We don't have to rely on the minimum size to stay the same for all inodes on a file system. If we need to tune defaults, this becomes much easier if new inodes can just inherit the new value without affecting existing ones.
Thanks your suggestion, Your idea make me thought more about this.
ocfs2-tools:
1. In mkfs.ocfs2, we set OCFS2_FEATURE_INCOMPAT_XATTR flag in ocfs2_super_block->s_feature_incompat.
This flag protect EAs value blocks (clusters) not released by old version fsck.ocfs2.
2. In mkfs.ocfs2, we set OCFS2_XATTR_INLINE_SIZE (current is 256) into a field in ocfs2_super_block, say s_xattr_inline_size.
3. Tunefs.ocfs2 could set those flag and value on formatted ocfs2 partition.
kernel modules:OCFS2_FEATURE_INCOMPAT_XATTR flag could prevent old kernel module mount ocfs2 file system which already has EAs in it. Because they don't know the xattr existed, they may destroy the inline xattr.
We will check OCFS2_FEATURE_INCOMPAT_XATTR flag when we try to set xattr. This means we can mount the ocfs2 filesystem which didn't support xattr, but can't set xattr in it. Because without OCFS2_FEATURE_INCOMPAT_XATTR, the EAs value blocks could be destroyed by fsck.ocfs2.
When we mount the ocfs2 filesystem which formated by new version mkfs.ocfs2, our kernel module will set osb->s_xattr_inline_size according to the on-disk super block. I am not sure whether all inode in this file system could only use this value for xattr inline? I think fixed xattr inline size in one file system can make things simple because its convenient for calculate extent record count or inline data size. So we can only change this value by tunefs.ocfs2 or mkfs.ocfs2.
Best regards,
tiger
PATCH 7/8 ocfs2: Add extended attributes support. v1
In reply to Mark FashehHi, Mark,
Quoted 4 lines · Mark Fasheh
Hmm, some comments describing this function would be helpfull. In particular, I'd like to know how failure in the middle of an operation is handled. Say you're expanding the ea because the user asked to store a larger size, but you hit a problem shortly after growing it. What happens?
I split setting long value operation into two parts. First insert tree root in local, if succeed then insert long value into B tree based on that tree root. If hit problem in second step, we could only get that junk tree root. This is harmless for system. but is it acceptable?
I have an idea to fix this problem by reduce the entry count when second step hit problem. Do we have to do this?
All other issues fixed in the second version patches.
thanks and regards,
tiger
PATCH 7/8 ocfs2: Add extended attributes support. v1
Quoted 4 lines · Tiger Yang
I split setting long value operation into two parts. First insert tree root in local, if succeed then insert long value into B tree based on that tree root. If hit problem in second step, we could only get that junk tree root. This is harmless for system. but is it acceptable?
If the junk root is ignored, and eventually overwritten as more ea's get inserted then I don't think you need to do any more.
If the junk root stays in the block and occupies space that would otherwise be used, then we probably need to handle this.. I imagine a clever user could DOS the xattr space by making large ones when the system is low on free space...
--Mark
--
Mark Fasheh
PATCH 7/8 ocfs2: Add extended attributes support. v1
Hi Mark,
Yes, this is also a problem in xattr bucket. Tiger and I both inserted
a zeroed tree root as xattr's value and then extend the root.
The [PATCH 13/15] also has the same problem. I will revise it in the next round.
Regards,
Tao
Quoted 22 lines · Mark Fasheh
Quoted 4 lines · Tiger Yang
I split setting long value operation into two parts. First insert tree root in local, if succeed then insert long value into B tree based on that tree root. If hit problem in second step, we could only get that junk tree root. This is harmless for system. but is it acceptable?
If the junk root is ignored, and eventually overwritten as more ea's get inserted then I don't think you need to do any more.
If the junk root stays in the block and occupies space that would otherwise be used, then we probably need to handle this.. I imagine a clever user could DOS the xattr space by making large ones when the system is low on free space...
--Mark--
Mark Fasheh_______________________________________________
Ocfs2-devel mailing list
Ocfs2-devel at oss.oracle.com
http://oss.oracle.com/mailman/listinfo/ocfs2-devel