Skip to contentSkip to conversation

ocfs2: Add extended attributes for ocfs2. V1

PATCH New Tao Ma 3 participants 31 messages Jun 5, 2008 – Jun 30, 2008 OCFS2

lore
Share & tools
lore

Tao Ma

author
#0 lore raw

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

#1 lore raw

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
index af63980..21323da 100644
@@ -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
index e138fec..b2b96b3 100644
@@ -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
index 7e9e4c7..da4b013 100644
@@ -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
index d5d808f..b938b00 100644
@@ -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
index 3169237..f567215 100644
@@ -172,6 +172,7 @@ enum ocfs2_mount_options
 	OCFS2_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
index df63ba2..2628dbf 100644
@@ -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
index debde62..0732a00 100644
@@ -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 0x1
 
 struct 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
author
#11 lore raw

PATCH 1/8 Modify ocfs2_num_free_extents for future xattr usage.v1

In reply to Tao Ma

ocfs2_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
index 10bfb46..c74711f 100644
@@ -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
index 42ff94b..758dbda 100644
@@ -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
index 17964c0..6d933df 100644
@@ -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
index 8a18758..8a14fff 100644
@@ -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
index 57e0d30..3993312 100644
@@ -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
index 048ddca..e38ecb2 100644
@@ -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
author
#12 lore raw

PATCH 2/8 Use ocfs2_extent_list instead of ocfs2_dinode.v1

In reply to Tao Ma

ocfs2_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
index c74711f..dc844df 100644
@@ -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
index 758dbda..249e79e 100644
@@ -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
index 6d933df..f83a2a4 100644
@@ -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
index 8a14fff..5e8cd6d 100644
@@ -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
index 3993312..79d7da9 100644
@@ -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
index db82be2..f1479ab 100644
@@ -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
index d2d278f..af769a5 100644
@@ -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
index 544c600..d024c69 100644
@@ -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
author
#13 lore raw

PATCH 3/8 Make ocfs2_lock_allocators generic for extent allocation.v1

In reply to Tao Ma

Now 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
index dc844df..71a89b2 100644
@@ -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
index 249e79e..5a460a9 100644
@@ -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
index f83a2a4..009dcc4 100644
@@ -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
index 5e8cd6d..8c10158 100644
@@ -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
index e38ecb2..e090ff2 100644
@@ -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
index d024c69..df19591 100644
@@ -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
author
#17 lore raw

PATCH 4/8 Make extend allocation generic.v1

In reply to Tao Ma

The 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
index cc292ee..69ef6ba 100644
@@ -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
index e090ff2..1ef2ac3 100644
@@ -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
index df19591..fff02f9 100644
@@ -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
author
#20 lore raw

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
new file mode 100644
index 0000000..a5b93cf
@@ -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
author
#23 lore raw

PATCH 6/8 Add extent tree operation for xattr value.v1

In reply to Tao Ma

When 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
index f6956de..af63980 100644
@@ -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
index 5a460a9..b50ace5 100644
@@ -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
index 009dcc4..b1b7750 100644
@@ -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
index 8c10158..b3e5cc5 100644
@@ -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
index de91e3e..d98444e 100644
@@ -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
index 69ef6ba..e138fec 100644
@@ -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
index c953796..464870c 100644
@@ -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
index fff02f9..592fc83 100644
@@ -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
author
#29 lore raw

PATCH 8/8 Add large numbers of extended attributes support for ocfs2.v1

In reply to Tao Ma

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 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
index 9aba2c1..e0ceda6 100644
@@ -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
index b50ace5..7587f0e 100644
@@ -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

fs/ocfs2/xattr.h +4 -1
index 6e17242..84484ca 100644

Lines of this file are not shown. View the 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.

author
#30 lore raw

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
index 9aba2c1..e0ceda6 100644
@@ -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
index b50ace5..7587f0e 100644
@@ -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

fs/ocfs2/xattr.h +4 -1
index 6e17242..84484ca 100644

Lines of this file are not shown. View the 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.

#14 lore raw

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_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.

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
---
 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
index dc844df..71a89b2 100644

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

author
#15 lore raw

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.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.

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

#18 lore raw

PATCH 4/8 Make extend allocation generic.v1

In reply to Tao Ma
Quoted 18 lines · Tao Ma

The 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 +0 -0
index cc292ee..69ef6ba 100644

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
index 1992a6a..c953796 100644
@@ -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

#21 lore raw

PATCH 5/8 Add xattr header in ocfs2.v1

In reply to Tao Ma

fs/ocfs2/xattr.h

Quoted 9 lines · 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 +0 -0
new file mode 100644
index 0000000..a5b93cf

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

#24 lore raw

PATCH 6/8 Add extent tree operation for xattr value.v1

In reply to Tao Ma

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 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

#16 lore raw

PATCH 3/8 Make ocfs2_lock_allocators generic for extent allocation.v1

In reply to Tao Ma
Quoted 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.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.

Quoted 4 lines

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.

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

author
#25 lore raw

PATCH 6/8 Add extent tree operation for xattr value.v1

In reply to Mark Fasheh

Hi 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 anm ocfs2_extent_tree and then pass it down to the common ocfs2_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

author
#22 lore raw

PATCH 5/8 Add xattr header in ocfs2.v1

In reply to Mark Fasheh
Quoted 7 lines · Mark Fasheh
Quoted 6 lines · Tao Ma
---
 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 -0
new file mode 100644
index 0000000..a5b93cf

Can we put this in ocfs2_fs.h instead? 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	"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.

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 '__u64 xh_reserved2;'

Should be. Will modify it.

Regards,
Tao

author
#19 lore raw

PATCH 4/8 Make extend allocation generic.v1

In reply to Mark Fasheh
Quoted 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_allocation to something more direct since it's used only for traditional inode data btrees. Maybe ocfs2_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
index 1992a6a..c953796 100644
@@ -1973,3 +1973,106 @@ out:
 
Quoted 7 lines

fs/ocfs2/suballoc.c out: · line 1977

Quoted 4 lines
fs/ocfs2/suballoc.c +2 -0
 	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 ;)

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

#28 lore raw

PATCH 6/8 Add extent tree operation for xattr value.v1

In reply to Tao Ma
Quoted 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

#26 lore raw

PATCH 6/8 Add extent tree operation for xattr value.v1

In reply to Tao Ma
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 anm ocfs2_extent_tree and
then pass it down to the common ocfs2_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

#2 lore raw

PATCH 7/8 ocfs2: Add extended attributes support. v1

In reply to Tiger Yang

Ok, 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
index 52c4266..d0fbf38 100644
@@ -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
index c223ab0..ed07448 100644
@@ -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

author
#27 lore raw

PATCH 6/8 Add extent tree operation for xattr value.v1

In reply to Mark Fasheh
Quoted 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 anm ocfs2_extent_tree and
then pass it down to the common ocfs2_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.

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

author
#3 lore raw

PATCH 7/8 ocfs2: Add extended attributes support. v1

In reply to Mark Fasheh
Quoted 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	16

Some 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

#4 lore raw

PATCH 7/8 ocfs2: Add extended attributes support. v1

In reply to Mark Fasheh

Hi, 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 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.

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

#5 lore raw

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. So i_xattr_loc could 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 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 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

#7 lore raw

PATCH 7/8 ocfs2: Add extended attributes support. v1

In reply to Tiger Yang

Ok, 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
index debde62..0732a00 100644
@@ -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 0x1
 
 struct 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

#6 lore raw

PATCH 7/8 ocfs2: Add extended attributes support. v1

In reply to Mark Fasheh
Quoted 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 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:

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

#8 lore raw

PATCH 7/8 ocfs2: Add extended attributes support. v1

In reply to Mark Fasheh

Hi, 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

#9 lore raw

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

author
#10 lore raw

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