]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/ocfs2/suballoc.c
ocfs2: Prefix the extent tree operations structure.
[karo-tx-linux.git] / fs / ocfs2 / suballoc.c
index d2d278fb9819ee3da92577a367b79f0bdc18681f..f1871ca8381522a9760c24bab752b3114a293127 100644 (file)
@@ -111,7 +111,7 @@ static inline void ocfs2_block_to_cluster_group(struct inode *inode,
                                                u64 *bg_blkno,
                                                u16 *bg_bit_off);
 
-static void ocfs2_free_ac_resource(struct ocfs2_alloc_context *ac)
+void ocfs2_free_ac_resource(struct ocfs2_alloc_context *ac)
 {
        struct inode *inode = ac->ac_inode;
 
@@ -493,9 +493,9 @@ bail:
        return status;
 }
 
-int ocfs2_reserve_new_metadata(struct ocfs2_super *osb,
-                              struct ocfs2_dinode *fe,
-                              struct ocfs2_alloc_context **ac)
+int ocfs2_reserve_new_metadata_blocks(struct ocfs2_super *osb,
+                                     int blocks,
+                                     struct ocfs2_alloc_context **ac)
 {
        int status;
        u32 slot;
@@ -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 = blocks;
        (*ac)->ac_which = OCFS2_AC_USE_META;
        slot = osb->slot_num;
        (*ac)->ac_group_search = ocfs2_block_group_search;
@@ -532,6 +532,15 @@ bail:
        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)
 {
@@ -686,15 +695,6 @@ int ocfs2_reserve_clusters(struct ocfs2_super *osb,
                if ((status < 0) && (status != -ENOSPC)) {
                        mlog_errno(status);
                        goto bail;
-               } else if (status == -ENOSPC) {
-                       /* reserve_local_bits will return enospc with
-                        * the local alloc inode still locked, so we
-                        * can change this safely here. */
-                       mlog(0, "Disabling local alloc\n");
-                       /* We set to OCFS2_LA_DISABLED so that umount
-                        * can clean up what's left of the local
-                        * allocation */
-                       osb->local_alloc_state = OCFS2_LA_DISABLED;
                }
        }
 
@@ -1005,6 +1005,7 @@ static int ocfs2_cluster_group_search(struct inode *inode,
        int search = -ENOSPC;
        int ret;
        struct ocfs2_group_desc *gd = (struct ocfs2_group_desc *) group_bh->b_data;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
        u16 tmp_off, tmp_found;
        unsigned int max_bits, gd_cluster_off;
 
@@ -1045,6 +1046,12 @@ static int ocfs2_cluster_group_search(struct inode *inode,
                        *bit_off = tmp_off;
                        *bits_found = tmp_found;
                        search = 0; /* success */
+               } else if (tmp_found) {
+                       /*
+                        * Don't show bits which we'll be returning
+                        * for allocation to the local alloc bitmap.
+                        */
+                       ocfs2_local_alloc_seen_free_bits(osb, tmp_found);
                }
        }
 
@@ -1203,9 +1210,8 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac,
        status = -ENOSPC;
        /* for now, the chain search is a bit simplistic. We just use
         * the 1st group with any empty bits. */
-       while ((status = ac->ac_group_search(alloc_inode, group_bh,
-                                            bits_wanted, min_bits, bit_off,
-                                            &tmp_bits)) == -ENOSPC) {
+       while ((status = ac->ac_group_search(alloc_inode, group_bh, bits_wanted,
+                                            min_bits, bit_off, &tmp_bits)) == -ENOSPC) {
                if (!bg->bg_next_group)
                        break;
 
@@ -1838,9 +1844,15 @@ int ocfs2_free_clusters(handle_t *handle,
        status = ocfs2_free_suballoc_bits(handle, bitmap_inode, bitmap_bh,
                                          bg_start_bit, bg_blkno,
                                          num_clusters);
-       if (status < 0)
+       if (status < 0) {
                mlog_errno(status);
+               goto out;
+       }
+
+       ocfs2_local_alloc_seen_free_bits(OCFS2_SB(bitmap_inode->i_sb),
+                                        num_clusters);
 
+out:
        mlog_exit(status);
        return status;
 }
@@ -1891,3 +1903,86 @@ static inline void ocfs2_debug_suballoc_inode(struct ocfs2_dinode *fe)
                       (unsigned long long)fe->id2.i_chain.cl_recs[i].c_blkno);
        }
 }
+
+/*
+ * For a given allocation, determine which allocators will need to be
+ * accessed, and lock them, reserving the appropriate number of bits.
+ *
+ * Sparse file systems call this from ocfs2_write_begin_nolock()
+ * and ocfs2_allocate_unwritten_extents().
+ *
+ * File systems which don't support holes call this from
+ * ocfs2_extend_allocation().
+ */
+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,
+                         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;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+       *meta_ac = NULL;
+       if (data_ac)
+               *data_ac = NULL;
+
+       BUG_ON(clusters_to_add != 0 && data_ac == NULL);
+
+       num_free_extents = ocfs2_num_free_extents(osb, inode, root_bh,
+                                                 type, private);
+       if (num_free_extents < 0) {
+               ret = num_free_extents;
+               mlog_errno(ret);
+               goto out;
+       }
+
+       /*
+        * Sparse allocation file systems need to be more conservative
+        * with reserving room for expansion - the actual allocation
+        * happens while we've got a journal handle open so re-taking
+        * a cluster lock (because we ran out of room for another
+        * extent) will violate ordering rules.
+        *
+        * Most of the time we'll only be seeing this 1 cluster at a time
+        * anyway.
+        *
+        * Always lock for any unwritten extents - we might want to
+        * add blocks during a split.
+        */
+       if (!num_free_extents ||
+           (ocfs2_sparse_alloc(osb) && num_free_extents < max_recs_needed)) {
+               ret = ocfs2_reserve_new_metadata(osb, root_el, meta_ac);
+               if (ret < 0) {
+                       if (ret != -ENOSPC)
+                               mlog_errno(ret);
+                       goto out;
+               }
+       }
+
+       if (clusters_to_add == 0)
+               goto out;
+
+       ret = ocfs2_reserve_clusters(osb, clusters_to_add, data_ac);
+       if (ret < 0) {
+               if (ret != -ENOSPC)
+                       mlog_errno(ret);
+               goto out;
+       }
+
+out:
+       if (ret) {
+               if (*meta_ac) {
+                       ocfs2_free_alloc_context(*meta_ac);
+                       *meta_ac = NULL;
+               }
+
+               /*
+                * We cannot have an error and a non null *data_ac.
+                */
+       }
+
+       return ret;
+}