|
@@ -49,6 +49,8 @@
|
|
|
#define NOT_ALLOC_NEW_GROUP 0
|
|
|
#define ALLOC_NEW_GROUP 1
|
|
|
|
|
|
+#define OCFS2_MAX_INODES_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);
|
|
|
static inline u16 ocfs2_find_victim_chain(struct ocfs2_chain_list *cl);
|
|
@@ -109,7 +111,7 @@ static inline void ocfs2_block_to_cluster_group(struct inode *inode,
|
|
|
u64 *bg_blkno,
|
|
|
u16 *bg_bit_off);
|
|
|
|
|
|
-void ocfs2_free_alloc_context(struct ocfs2_alloc_context *ac)
|
|
|
+static void ocfs2_free_ac_resource(struct ocfs2_alloc_context *ac)
|
|
|
{
|
|
|
struct inode *inode = ac->ac_inode;
|
|
|
|
|
@@ -120,9 +122,17 @@ void ocfs2_free_alloc_context(struct ocfs2_alloc_context *ac)
|
|
|
mutex_unlock(&inode->i_mutex);
|
|
|
|
|
|
iput(inode);
|
|
|
+ ac->ac_inode = NULL;
|
|
|
}
|
|
|
- if (ac->ac_bh)
|
|
|
+ if (ac->ac_bh) {
|
|
|
brelse(ac->ac_bh);
|
|
|
+ ac->ac_bh = NULL;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void ocfs2_free_alloc_context(struct ocfs2_alloc_context *ac)
|
|
|
+{
|
|
|
+ ocfs2_free_ac_resource(ac);
|
|
|
kfree(ac);
|
|
|
}
|
|
|
|
|
@@ -522,10 +532,42 @@ bail:
|
|
|
return status;
|
|
|
}
|
|
|
|
|
|
+static int ocfs2_steal_inode_from_other_nodes(struct ocfs2_super *osb,
|
|
|
+ struct ocfs2_alloc_context *ac)
|
|
|
+{
|
|
|
+ int i, status = -ENOSPC;
|
|
|
+ s16 slot = ocfs2_get_inode_steal_slot(osb);
|
|
|
+
|
|
|
+ /* Start to steal inodes from the first slot after ours. */
|
|
|
+ if (slot == OCFS2_INVALID_SLOT)
|
|
|
+ slot = osb->slot_num + 1;
|
|
|
+
|
|
|
+ for (i = 0; i < osb->max_slots; i++, slot++) {
|
|
|
+ if (slot == osb->max_slots)
|
|
|
+ slot = 0;
|
|
|
+
|
|
|
+ if (slot == osb->slot_num)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ status = ocfs2_reserve_suballoc_bits(osb, ac,
|
|
|
+ INODE_ALLOC_SYSTEM_INODE,
|
|
|
+ slot, NOT_ALLOC_NEW_GROUP);
|
|
|
+ if (status >= 0) {
|
|
|
+ ocfs2_set_inode_steal_slot(osb, slot);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ ocfs2_free_ac_resource(ac);
|
|
|
+ }
|
|
|
+
|
|
|
+ return status;
|
|
|
+}
|
|
|
+
|
|
|
int ocfs2_reserve_new_inode(struct ocfs2_super *osb,
|
|
|
struct ocfs2_alloc_context **ac)
|
|
|
{
|
|
|
int status;
|
|
|
+ s16 slot = ocfs2_get_inode_steal_slot(osb);
|
|
|
|
|
|
*ac = kzalloc(sizeof(struct ocfs2_alloc_context), GFP_KERNEL);
|
|
|
if (!(*ac)) {
|
|
@@ -539,9 +581,43 @@ int ocfs2_reserve_new_inode(struct ocfs2_super *osb,
|
|
|
|
|
|
(*ac)->ac_group_search = ocfs2_block_group_search;
|
|
|
|
|
|
+ /*
|
|
|
+ * slot is set when we successfully steal inode 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
|
|
|
+ * 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;
|
|
|
+
|
|
|
+ atomic_set(&osb->s_num_inodes_stolen, 0);
|
|
|
status = ocfs2_reserve_suballoc_bits(osb, *ac,
|
|
|
INODE_ALLOC_SYSTEM_INODE,
|
|
|
osb->slot_num, ALLOC_NEW_GROUP);
|
|
|
+ if (status >= 0) {
|
|
|
+ status = 0;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Some inodes must be freed by us, so try to allocate
|
|
|
+ * from our own next time.
|
|
|
+ */
|
|
|
+ if (slot != OCFS2_INVALID_SLOT)
|
|
|
+ ocfs2_init_inode_steal_slot(osb);
|
|
|
+ goto bail;
|
|
|
+ } else if (status < 0 && status != -ENOSPC) {
|
|
|
+ mlog_errno(status);
|
|
|
+ goto bail;
|
|
|
+ }
|
|
|
+
|
|
|
+ ocfs2_free_ac_resource(*ac);
|
|
|
+
|
|
|
+inode_steal:
|
|
|
+ status = ocfs2_steal_inode_from_other_nodes(osb, *ac);
|
|
|
+ atomic_inc(&osb->s_num_inodes_stolen);
|
|
|
if (status < 0) {
|
|
|
if (status != -ENOSPC)
|
|
|
mlog_errno(status);
|