]> err.no Git - linux-2.6/blobdiff - fs/ocfs2/suballoc.c
[PATCH 1/2] ocfs2: Add counter in struct ocfs2_dinode to track journal replays
[linux-2.6] / fs / ocfs2 / suballoc.c
index 3be4e73e8b135ca55e277ba76279393fa36ecf5c..d2d278fb9819ee3da92577a367b79f0bdc18681f 100644 (file)
@@ -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);
 }
 
@@ -424,6 +434,7 @@ static int ocfs2_reserve_suballoc_bits(struct ocfs2_super *osb,
        }
 
        ac->ac_inode = alloc_inode;
+       ac->ac_alloc_slot = slot;
 
        fe = (struct ocfs2_dinode *) bh->b_data;
        if (!OCFS2_IS_VALID_DINODE(fe)) {
@@ -521,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)) {
@@ -538,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);