]> err.no Git - linux-2.6/commitdiff
ocfs2: Fix extent lookup to return true size of holes
authorMark Fasheh <mark.fasheh@oracle.com>
Sat, 10 Mar 2007 00:26:50 +0000 (16:26 -0800)
committerMark Fasheh <mark.fasheh@oracle.com>
Thu, 26 Apr 2007 22:02:45 +0000 (15:02 -0700)
Initially, we had wired things to return a size '1' of holes. Cook up a
small amount of code to find the next extent and calculate the number of
clusters between the virtual offset and the next allocated extent.

Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>
fs/ocfs2/aops.c
fs/ocfs2/extent_map.c
fs/ocfs2/extent_map.h
fs/ocfs2/journal.c
fs/ocfs2/namei.c

index eb67c902b002a2b3212f42cc0d9677fa47d614ad..ff71e0b430cdd53a8b8afdc0be99bed5c7288782 100644 (file)
@@ -439,8 +439,7 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock,
                                     struct buffer_head *bh_result, int create)
 {
        int ret;
-       u64 p_blkno, inode_blocks;
-       int contig_blocks;
+       u64 p_blkno, inode_blocks, contig_blocks;
        unsigned int ext_flags;
        unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits;
        unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits;
index eef6c1887708042586a04e8a1e7a6e87bc583f69..f35e04f27f3230149ca98e985f8ea541a2c81b7f 100644 (file)
 
 #include "buffer_head_io.h"
 
+/*
+ * Return the 1st index within el which contains an extent start
+ * larger than v_cluster.
+ */
+static int ocfs2_search_for_hole_index(struct ocfs2_extent_list *el,
+                                      u32 v_cluster)
+{
+       int i;
+       struct ocfs2_extent_rec *rec;
+
+       for(i = 0; i < le16_to_cpu(el->l_next_free_rec); i++) {
+               rec = &el->l_recs[i];
+
+               if (v_cluster < le32_to_cpu(rec->e_cpos))
+                       break;
+       }
+
+       return i;
+}
+
+/*
+ * Figure out the size of a hole which starts at v_cluster within the given
+ * extent list.
+ *
+ * If there is no more allocation past v_cluster, we return the maximum
+ * cluster size minus v_cluster.
+ *
+ * If we have in-inode extents, then el points to the dinode list and
+ * eb_bh is NULL. Otherwise, eb_bh should point to the extent block
+ * containing el.
+ */
+static int ocfs2_figure_hole_clusters(struct inode *inode,
+                                     struct ocfs2_extent_list *el,
+                                     struct buffer_head *eb_bh,
+                                     u32 v_cluster,
+                                     u32 *num_clusters)
+{
+       int ret, i;
+       struct buffer_head *next_eb_bh = NULL;
+       struct ocfs2_extent_block *eb, *next_eb;
+
+       i = ocfs2_search_for_hole_index(el, v_cluster);
+
+       if (i == le16_to_cpu(el->l_next_free_rec) && eb_bh) {
+               eb = (struct ocfs2_extent_block *)eb_bh->b_data;
+
+               /*
+                * Check the next leaf for any extents.
+                */
+
+               if (le64_to_cpu(eb->h_next_leaf_blk) == 0ULL)
+                       goto no_more_extents;
+
+               ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
+                                      le64_to_cpu(eb->h_next_leaf_blk),
+                                      &next_eb_bh, OCFS2_BH_CACHED, inode);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+               next_eb = (struct ocfs2_extent_block *)next_eb_bh->b_data;
+
+               if (!OCFS2_IS_VALID_EXTENT_BLOCK(next_eb)) {
+                       ret = -EROFS;
+                       OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, next_eb);
+                       goto out;
+               }
+
+               el = &next_eb->h_list;
+
+               i = ocfs2_search_for_hole_index(el, v_cluster);
+       }
+
+no_more_extents:
+       if (i == le16_to_cpu(el->l_next_free_rec)) {
+               /*
+                * We're at the end of our existing allocation. Just
+                * return the maximum number of clusters we could
+                * possibly allocate.
+                */
+               *num_clusters = UINT_MAX - v_cluster;
+       } else {
+               *num_clusters = le32_to_cpu(el->l_recs[i].e_cpos) - v_cluster;
+       }
+
+       ret = 0;
+out:
+       brelse(next_eb_bh);
+       return ret;
+}
+
 /*
  * Return the index of the extent record which contains cluster #v_cluster.
  * -1 is returned if it was not found.
@@ -117,11 +208,19 @@ int ocfs2_get_clusters(struct inode *inode, u32 v_cluster,
        if (i == -1) {
                /*
                 * A hole was found. Return some canned values that
-                * callers can key on.
+                * callers can key on. If asked for, num_clusters will
+                * be populated with the size of the hole.
                 */
                *p_cluster = 0;
-               if (num_clusters)
-                       *num_clusters = 1;
+               if (num_clusters) {
+                       ret = ocfs2_figure_hole_clusters(inode, el, eb_bh,
+                                                        v_cluster,
+                                                        num_clusters);
+                       if (ret) {
+                               mlog_errno(ret);
+                               goto out;
+                       }
+               }
        } else {
                rec = &el->l_recs[i];
 
@@ -162,7 +261,7 @@ out:
  * all while the map is in the process of being updated.
  */
 int ocfs2_extent_map_get_blocks(struct inode *inode, u64 v_blkno, u64 *p_blkno,
-                               int *ret_count, unsigned int *extent_flags)
+                               u64 *ret_count, unsigned int *extent_flags)
 {
        int ret;
        int bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1);
index 0031c59c347f3f33440211a983e8a81189b8de4a..1d745e174afc01862e33d2e2a40a1916b873c070 100644 (file)
@@ -28,6 +28,6 @@
 int ocfs2_get_clusters(struct inode *inode, u32 v_cluster, u32 *p_cluster,
                       u32 *num_clusters, unsigned int *extent_flags);
 int ocfs2_extent_map_get_blocks(struct inode *inode, u64 v_blkno, u64 *p_blkno,
-                               int *ret_count, unsigned int *extent_flags);
+                               u64 *ret_count, unsigned int *extent_flags);
 
 #endif  /* _EXTENT_MAP_H */
index db77e0996bb74b648b73907acc823de40a6869d9..12d2340eee29ebf1761c2ed93df6ebe3bebd435c 100644 (file)
@@ -649,9 +649,9 @@ bail:
 static int ocfs2_force_read_journal(struct inode *inode)
 {
        int status = 0;
-       int i, p_blocks;
-       u64 v_blkno, p_blkno;
-#define CONCURRENT_JOURNAL_FILL 32
+       int i;
+       u64 v_blkno, p_blkno, p_blocks;
+#define CONCURRENT_JOURNAL_FILL 32ULL
        struct buffer_head *bhs[CONCURRENT_JOURNAL_FILL];
 
        mlog_entry_void();
index 395859edb51f5d1769bd46c83562ff22024f409e..9bdbe4ae92f8ef24a87b09d1438eac223bd90ce4 100644 (file)
@@ -1483,8 +1483,7 @@ static int ocfs2_create_symlink_data(struct ocfs2_super *osb,
        struct buffer_head **bhs = NULL;
        const char *c;
        struct super_block *sb = osb->sb;
-       u64 p_blkno;
-       int p_blocks;
+       u64 p_blkno, p_blocks;
        int virtual, blocks, status, i, bytes_left;
 
        bytes_left = i_size_read(inode) + 1;