>From 1983b2aae17e5dd52e4effe3c61fd67cdb6ca114 Mon Sep 17 00:00:00 2001
From: Tiger Yang <tiger.yang@oracle.com>
Date: Mon, 14 Dec 2009 18:33:52 +0800
Subject: [PATCH 1/1] ocfs2: add extent block stealing for ocfs2

This patch add extent(metadata) block stealing mechanism for
extent allocation. This mechanism is same as the inode stealing.
ocfs2_reserve_new_resource was introducted to merge the resources
reserve, such as extent block and inode.

Signed-off-by: Tiger Yang <tiger.yang@oracle.com>
---
 fs/ocfs2/alloc.c        |    5 +-
 fs/ocfs2/dir.c          |    2 +-
 fs/ocfs2/localalloc.c   |    2 +-
 fs/ocfs2/ocfs2.h        |   38 +++++++++--
 fs/ocfs2/refcounttree.c |    6 +-
 fs/ocfs2/suballoc.c     |  155 +++++++++++++++++++++++++----------------------
 fs/ocfs2/super.c        |    2 +-
 fs/ocfs2/xattr.c        |    2 +-
 8 files changed, 124 insertions(+), 88 deletions(-)

diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c
index 7c7198a..268ddd4 100644
--- a/fs/ocfs2/alloc.c
+++ b/fs/ocfs2/alloc.c
@@ -1050,7 +1050,8 @@ static int ocfs2_create_new_meta_bhs(handle_t *handle,
 			strcpy(eb->h_signature, OCFS2_EXTENT_BLOCK_SIGNATURE);
 			eb->h_blkno = cpu_to_le64(first_blkno);
 			eb->h_fs_generation = cpu_to_le32(osb->fs_generation);
-			eb->h_suballoc_slot = cpu_to_le16(osb->slot_num);
+			eb->h_suballoc_slot =
+				cpu_to_le16(meta_ac->ac_alloc_slot);
 			eb->h_suballoc_bit = cpu_to_le16(suballoc_bit_start);
 			eb->h_list.l_count =
 				cpu_to_le16(ocfs2_extent_recs_per_eb(osb->sb));
@@ -6037,7 +6038,7 @@ static void ocfs2_truncate_log_worker(struct work_struct *work)
 	if (status < 0)
 		mlog_errno(status);
 	else
-		ocfs2_init_inode_steal_slot(osb);
+		ocfs2_init_all_steal_slot(osb);
 
 	mlog_exit(status);
 }
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c
index 28c3ec2..765d66c 100644
--- a/fs/ocfs2/dir.c
+++ b/fs/ocfs2/dir.c
@@ -2439,7 +2439,7 @@ static int ocfs2_dx_dir_attach_index(struct ocfs2_super *osb,
 	dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data;
 	memset(dx_root, 0, osb->sb->s_blocksize);
 	strcpy(dx_root->dr_signature, OCFS2_DX_ROOT_SIGNATURE);
-	dx_root->dr_suballoc_slot = cpu_to_le16(osb->slot_num);
+	dx_root->dr_suballoc_slot = cpu_to_le16(meta_ac->ac_alloc_slot);
 	dx_root->dr_suballoc_bit = cpu_to_le16(dr_suballoc_bit);
 	dx_root->dr_fs_generation = cpu_to_le32(osb->fs_generation);
 	dx_root->dr_blkno = cpu_to_le64(dr_blkno);
diff --git a/fs/ocfs2/localalloc.c b/fs/ocfs2/localalloc.c
index ac10f83..70480ce 100644
--- a/fs/ocfs2/localalloc.c
+++ b/fs/ocfs2/localalloc.c
@@ -476,7 +476,7 @@ out_mutex:
 
 out:
 	if (!status)
-		ocfs2_init_inode_steal_slot(osb);
+		ocfs2_init_all_steal_slot(osb);
 	mlog_exit(status);
 	return status;
 }
diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h
index d963d86..68ac7fb 100644
--- a/fs/ocfs2/ocfs2.h
+++ b/fs/ocfs2/ocfs2.h
@@ -299,7 +299,9 @@ struct ocfs2_super
 	u32 s_next_generation;
 	unsigned long osb_flags;
 	s16 s_inode_steal_slot;
+	s16 s_extent_steal_slot;
 	atomic_t s_num_inodes_stolen;
+	atomic_t s_num_extents_stolen;
 
 	unsigned long s_mount_opt;
 	unsigned int s_atime_quantum;
@@ -754,28 +756,50 @@ static inline unsigned int ocfs2_megabytes_to_clusters(struct super_block *sb,
 	return megs << (20 - OCFS2_SB(sb)->s_clustersize_bits);
 }
 
-static inline void ocfs2_init_inode_steal_slot(struct ocfs2_super *osb)
+static inline void ocfs2_init_all_steal_slot(struct ocfs2_super *osb)
 {
 	spin_lock(&osb->osb_lock);
 	osb->s_inode_steal_slot = OCFS2_INVALID_SLOT;
+	osb->s_extent_steal_slot = OCFS2_INVALID_SLOT;
 	spin_unlock(&osb->osb_lock);
 	atomic_set(&osb->s_num_inodes_stolen, 0);
+	atomic_set(&osb->s_num_extents_stolen, 0);
 }
 
-static inline void ocfs2_set_inode_steal_slot(struct ocfs2_super *osb,
-					      s16 slot)
+static inline void ocfs2_init_steal_slot(struct ocfs2_super *osb, int type)
 {
 	spin_lock(&osb->osb_lock);
-	osb->s_inode_steal_slot = slot;
+	if (type == INODE_ALLOC_SYSTEM_INODE)
+		osb->s_inode_steal_slot = OCFS2_INVALID_SLOT;
+	else if (type == EXTENT_ALLOC_SYSTEM_INODE)
+		osb->s_extent_steal_slot = OCFS2_INVALID_SLOT;
 	spin_unlock(&osb->osb_lock);
+	if (type == INODE_ALLOC_SYSTEM_INODE)
+		atomic_set(&osb->s_num_inodes_stolen, 0);
+	else if (type == EXTENT_ALLOC_SYSTEM_INODE)
+		atomic_set(&osb->s_num_extents_stolen, 0);
 }
 
-static inline s16 ocfs2_get_inode_steal_slot(struct ocfs2_super *osb)
+static inline void ocfs2_set_steal_slot(struct ocfs2_super *osb,
+					s16 slot, int type)
 {
-	s16 slot;
+	spin_lock(&osb->osb_lock);
+	if (type == INODE_ALLOC_SYSTEM_INODE)
+		osb->s_inode_steal_slot = slot;
+	else if (type == EXTENT_ALLOC_SYSTEM_INODE)
+		osb->s_extent_steal_slot = slot;
+	spin_unlock(&osb->osb_lock);
+}
+
+static inline s16 ocfs2_get_steal_slot(struct ocfs2_super *osb, int type)
+{
+	s16 slot = OCFS2_INVALID_SLOT;
 
 	spin_lock(&osb->osb_lock);
-	slot = osb->s_inode_steal_slot;
+	if (type == INODE_ALLOC_SYSTEM_INODE)
+		slot = osb->s_inode_steal_slot;
+	else if (type == EXTENT_ALLOC_SYSTEM_INODE)
+		slot = osb->s_extent_steal_slot;
 	spin_unlock(&osb->osb_lock);
 
 	return slot;
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c
index 30967e3..731e5d7 100644
--- a/fs/ocfs2/refcounttree.c
+++ b/fs/ocfs2/refcounttree.c
@@ -643,7 +643,7 @@ static int ocfs2_create_refcount_tree(struct inode *inode,
 	rb = (struct ocfs2_refcount_block *)new_bh->b_data;
 	memset(rb, 0, inode->i_sb->s_blocksize);
 	strcpy((void *)rb, OCFS2_REFCOUNT_BLOCK_SIGNATURE);
-	rb->rf_suballoc_slot = cpu_to_le16(osb->slot_num);
+	rb->rf_suballoc_slot = cpu_to_le16(meta_ac->ac_alloc_slot);
 	rb->rf_suballoc_bit = cpu_to_le16(suballoc_bit_start);
 	rb->rf_fs_generation = cpu_to_le32(osb->fs_generation);
 	rb->rf_blkno = cpu_to_le64(first_blkno);
@@ -1246,7 +1246,7 @@ static int ocfs2_expand_inline_ref_root(handle_t *handle,
 	memcpy(new_bh->b_data, ref_root_bh->b_data, sb->s_blocksize);
 
 	new_rb = (struct ocfs2_refcount_block *)new_bh->b_data;
-	new_rb->rf_suballoc_slot = cpu_to_le16(OCFS2_SB(sb)->slot_num);
+	new_rb->rf_suballoc_slot = cpu_to_le16(meta_ac->ac_alloc_slot);
 	new_rb->rf_suballoc_bit = cpu_to_le16(suballoc_bit_start);
 	new_rb->rf_blkno = cpu_to_le64(blkno);
 	new_rb->rf_cpos = cpu_to_le32(0);
@@ -1492,7 +1492,7 @@ static int ocfs2_new_leaf_refcount_block(handle_t *handle,
 	new_rb = (struct ocfs2_refcount_block *)new_bh->b_data;
 	memset(new_rb, 0, sb->s_blocksize);
 	strcpy((void *)new_rb, OCFS2_REFCOUNT_BLOCK_SIGNATURE);
-	new_rb->rf_suballoc_slot = cpu_to_le16(OCFS2_SB(sb)->slot_num);
+	new_rb->rf_suballoc_slot = cpu_to_le16(meta_ac->ac_alloc_slot);
 	new_rb->rf_suballoc_bit = cpu_to_le16(suballoc_bit_start);
 	new_rb->rf_fs_generation = cpu_to_le32(OCFS2_SB(sb)->fs_generation);
 	new_rb->rf_blkno = cpu_to_le64(blkno);
diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c
index c30b644..8cb8d44 100644
--- a/fs/ocfs2/suballoc.c
+++ b/fs/ocfs2/suballoc.c
@@ -52,6 +52,7 @@
 #define ALLOC_GROUPS_FROM_GLOBAL	0x2
 
 #define OCFS2_MAX_INODES_TO_STEAL	1024
+#define OCFS2_MAX_EXTENTS_TO_STEAL	1024
 
 static inline void ocfs2_debug_bg(struct ocfs2_group_desc *bg);
 static inline void ocfs2_debug_suballoc_inode(struct ocfs2_dinode *fe);
@@ -637,61 +638,14 @@ bail:
 	return status;
 }
 
-int ocfs2_reserve_new_metadata_blocks(struct ocfs2_super *osb,
-				      int blocks,
-				      struct ocfs2_alloc_context **ac)
-{
-	int status;
-	u32 slot;
-
-	*ac = kzalloc(sizeof(struct ocfs2_alloc_context), GFP_KERNEL);
-	if (!(*ac)) {
-		status = -ENOMEM;
-		mlog_errno(status);
-		goto bail;
-	}
-
-	(*ac)->ac_bits_wanted = blocks;
-	(*ac)->ac_which = OCFS2_AC_USE_META;
-	slot = osb->slot_num;
-	(*ac)->ac_group_search = ocfs2_block_group_search;
-
-	status = ocfs2_reserve_suballoc_bits(osb, (*ac),
-					     EXTENT_ALLOC_SYSTEM_INODE,
-					     slot, NULL, ALLOC_NEW_GROUP);
-	if (status < 0) {
-		if (status != -ENOSPC)
-			mlog_errno(status);
-		goto bail;
-	}
-
-	status = 0;
-bail:
-	if ((status < 0) && *ac) {
-		ocfs2_free_alloc_context(*ac);
-		*ac = NULL;
-	}
-
-	mlog_exit(status);
-	return status;
-}
-
-int ocfs2_reserve_new_metadata(struct ocfs2_super *osb,
-			       struct ocfs2_extent_list *root_el,
-			       struct ocfs2_alloc_context **ac)
-{
-	return ocfs2_reserve_new_metadata_blocks(osb,
-					ocfs2_extend_meta_needed(root_el),
-					ac);
-}
-
-static int ocfs2_steal_inode_from_other_nodes(struct ocfs2_super *osb,
-					      struct ocfs2_alloc_context *ac)
+static int ocfs2_steal_from_other_nodes(struct ocfs2_super *osb,
+					struct ocfs2_alloc_context *ac,
+					int type)
 {
 	int i, status = -ENOSPC;
-	s16 slot = ocfs2_get_inode_steal_slot(osb);
+	s16 slot = ocfs2_get_steal_slot(osb, type);
 
-	/* Start to steal inodes from the first slot after ours. */
+	/* Start to steal resource from the first slot after ours. */
 	if (slot == OCFS2_INVALID_SLOT)
 		slot = osb->slot_num + 1;
 
@@ -703,11 +657,11 @@ static int ocfs2_steal_inode_from_other_nodes(struct ocfs2_super *osb,
 			continue;
 
 		status = ocfs2_reserve_suballoc_bits(osb, ac,
-						     INODE_ALLOC_SYSTEM_INODE,
+						     type,
 						     slot, NULL,
 						     NOT_ALLOC_NEW_GROUP);
 		if (status >= 0) {
-			ocfs2_set_inode_steal_slot(osb, slot);
+			ocfs2_set_steal_slot(osb, slot, type);
 			break;
 		}
 
@@ -717,11 +671,41 @@ static int ocfs2_steal_inode_from_other_nodes(struct ocfs2_super *osb,
 	return status;
 }
 
-int ocfs2_reserve_new_inode(struct ocfs2_super *osb,
-			    struct ocfs2_alloc_context **ac)
+static inline int ocfs2_could_steal_resource(struct ocfs2_super *osb,
+					     int type)
+{
+	if (type == INODE_ALLOC_SYSTEM_INODE)
+		return (atomic_read(&osb->s_num_inodes_stolen)
+			 < OCFS2_MAX_INODES_TO_STEAL);
+	else if (type == EXTENT_ALLOC_SYSTEM_INODE)
+		return (atomic_read(&osb->s_num_extents_stolen)
+			 < OCFS2_MAX_EXTENTS_TO_STEAL);
+	else
+		return 0;
+}
+
+#define ATOMIC_INC_RESOURCE_NUMBER(type)			\
+do {								\
+	if (type == INODE_ALLOC_SYSTEM_INODE)			\
+		atomic_inc(&osb->s_num_inodes_stolen);		\
+	else if (type == EXTENT_ALLOC_SYSTEM_INODE)		\
+		atomic_inc(&osb->s_num_extents_stolen);		\
+} while (0)
+
+#define ATOMIC_ZERO_RESOURCE_NUMBER(type)			\
+do {								\
+	if (type == INODE_ALLOC_SYSTEM_INODE)			\
+		atomic_set(&osb->s_num_inodes_stolen, 0);	\
+	else if (type == EXTENT_ALLOC_SYSTEM_INODE)		\
+		atomic_set(&osb->s_num_extents_stolen, 0);	\
+} while (0)
+
+static int ocfs2_reserve_new_resource(struct ocfs2_super *osb,
+				      struct ocfs2_alloc_context **ac,
+				      int blocks, int type)
 {
 	int status;
-	s16 slot = ocfs2_get_inode_steal_slot(osb);
+	s16 slot = ocfs2_get_steal_slot(osb, type);
 	u64 alloc_group;
 
 	*ac = kzalloc(sizeof(struct ocfs2_alloc_context), GFP_KERNEL);
@@ -731,36 +715,39 @@ int ocfs2_reserve_new_inode(struct ocfs2_super *osb,
 		goto bail;
 	}
 
-	(*ac)->ac_bits_wanted = 1;
-	(*ac)->ac_which = OCFS2_AC_USE_INODE;
-
+	(*ac)->ac_bits_wanted = blocks;
 	(*ac)->ac_group_search = ocfs2_block_group_search;
+	if (type == INODE_ALLOC_SYSTEM_INODE)
+		(*ac)->ac_which = OCFS2_AC_USE_INODE;
+	else if (type == EXTENT_ALLOC_SYSTEM_INODE)
+		(*ac)->ac_which = OCFS2_AC_USE_META;
 
 	/*
 	 * stat(2) can't handle i_ino > 32bits, so we tell the
 	 * lower levels not to allocate us a block group past that
 	 * limit.  The 'inode64' mount option avoids this behavior.
 	 */
-	if (!(osb->s_mount_opt & OCFS2_MOUNT_INODE64))
+	if (type == INODE_ALLOC_SYSTEM_INODE &&
+	    !(osb->s_mount_opt & OCFS2_MOUNT_INODE64))
 		(*ac)->ac_max_block = (u32)~0U;
 
 	/*
-	 * slot is set when we successfully steal inode from other nodes.
-	 * It is reset in 3 places:
+	 * slot is set when we successfully steal inode/extent
+	 * from other nodes. It is reset in 3 places:
 	 * 1. when we flush the truncate log
 	 * 2. when we complete local alloc recovery.
 	 * 3. when we successfully allocate from our own slot.
-	 * After it is set, we will go on stealing inodes until we find the
+	 * After it is set, we will go on stealing resource until we find the
 	 * need to check our slots to see whether there is some space for us.
 	 */
 	if (slot != OCFS2_INVALID_SLOT &&
-	    atomic_read(&osb->s_num_inodes_stolen) < OCFS2_MAX_INODES_TO_STEAL)
-		goto inode_steal;
+	    ocfs2_could_steal_resource(osb, type))
+		goto resource_steal;
 
-	atomic_set(&osb->s_num_inodes_stolen, 0);
+	ATOMIC_ZERO_RESOURCE_NUMBER(type);
 	alloc_group = osb->osb_inode_alloc_group;
 	status = ocfs2_reserve_suballoc_bits(osb, *ac,
-					     INODE_ALLOC_SYSTEM_INODE,
+					     type,
 					     osb->slot_num,
 					     &alloc_group,
 					     ALLOC_NEW_GROUP |
@@ -779,7 +766,7 @@ int ocfs2_reserve_new_inode(struct ocfs2_super *osb,
 		 * from our own next time.
 		 */
 		if (slot != OCFS2_INVALID_SLOT)
-			ocfs2_init_inode_steal_slot(osb);
+			ocfs2_init_steal_slot(osb, type);
 		goto bail;
 	} else if (status < 0 && status != -ENOSPC) {
 		mlog_errno(status);
@@ -788,9 +775,9 @@ int ocfs2_reserve_new_inode(struct ocfs2_super *osb,
 
 	ocfs2_free_ac_resource(*ac);
 
-inode_steal:
-	status = ocfs2_steal_inode_from_other_nodes(osb, *ac);
-	atomic_inc(&osb->s_num_inodes_stolen);
+resource_steal:
+	status = ocfs2_steal_from_other_nodes(osb, *ac, type);
+	ATOMIC_INC_RESOURCE_NUMBER(type);
 	if (status < 0) {
 		if (status != -ENOSPC)
 			mlog_errno(status);
@@ -808,6 +795,30 @@ bail:
 	return status;
 }
 
+int ocfs2_reserve_new_metadata_blocks(struct ocfs2_super *osb,
+				      int blocks,
+				      struct ocfs2_alloc_context **ac)
+{
+	return ocfs2_reserve_new_resource(osb, ac, blocks,
+					  EXTENT_ALLOC_SYSTEM_INODE);
+}
+
+int ocfs2_reserve_new_metadata(struct ocfs2_super *osb,
+			       struct ocfs2_extent_list *root_el,
+			       struct ocfs2_alloc_context **ac)
+{
+	return ocfs2_reserve_new_metadata_blocks(osb,
+					ocfs2_extend_meta_needed(root_el),
+					ac);
+}
+
+int ocfs2_reserve_new_inode(struct ocfs2_super *osb,
+			    struct ocfs2_alloc_context **ac)
+{
+	return ocfs2_reserve_new_resource(osb, ac, 1,
+					  INODE_ALLOC_SYSTEM_INODE);
+}
+
 /* local alloc code has to do the same thing, so rather than do this
  * twice.. */
 int ocfs2_reserve_cluster_bitmap_bits(struct ocfs2_super *osb,
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index 14f47d2..8ca7ba7 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -1996,7 +1996,7 @@ static int ocfs2_initialize_super(struct super_block *sb,
 	osb->blocked_lock_count = 0;
 	spin_lock_init(&osb->osb_lock);
 	spin_lock_init(&osb->osb_xattr_lock);
-	ocfs2_init_inode_steal_slot(osb);
+	ocfs2_init_all_steal_slot(osb);
 
 	atomic_set(&osb->alloc_stats.moves, 0);
 	atomic_set(&osb->alloc_stats.local_data, 0);
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c
index fe34190..0bf9a37 100644
--- a/fs/ocfs2/xattr.c
+++ b/fs/ocfs2/xattr.c
@@ -2288,7 +2288,7 @@ static int ocfs2_create_xattr_block(handle_t *handle,
 	xblk = (struct ocfs2_xattr_block *)new_bh->b_data;
 	memset(xblk, 0, inode->i_sb->s_blocksize);
 	strcpy((void *)xblk, OCFS2_XATTR_BLOCK_SIGNATURE);
-	xblk->xb_suballoc_slot = cpu_to_le16(osb->slot_num);
+	xblk->xb_suballoc_slot = cpu_to_le16(meta_ac->ac_alloc_slot);
 	xblk->xb_suballoc_bit = cpu_to_le16(suballoc_bit_start);
 	xblk->xb_fs_generation = cpu_to_le32(osb->fs_generation);
 	xblk->xb_blkno = cpu_to_le64(first_blkno);
-- 
1.6.5.2

