summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorMark Fasheh <mark.fasheh@oracle.com>2007-03-10 01:26:50 +0100
committerMark Fasheh <mark.fasheh@oracle.com>2007-04-27 00:02:45 +0200
commit4f902c37727bbedbc0508a1477874c58ddcc9af8 (patch)
tree841b35387cfea5d2518c258c4de6ef868948369b /fs
parentocfs2: Read from an unwritten extent returns zeros (diff)
downloadlinux-4f902c37727bbedbc0508a1477874c58ddcc9af8.tar.xz
linux-4f902c37727bbedbc0508a1477874c58ddcc9af8.zip
ocfs2: Fix extent lookup to return true size of holes
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>
Diffstat (limited to 'fs')
-rw-r--r--fs/ocfs2/aops.c3
-rw-r--r--fs/ocfs2/extent_map.c107
-rw-r--r--fs/ocfs2/extent_map.h2
-rw-r--r--fs/ocfs2/journal.c6
-rw-r--r--fs/ocfs2/namei.c3
5 files changed, 109 insertions, 12 deletions
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
index eb67c902b002..ff71e0b430cd 100644
--- a/fs/ocfs2/aops.c
+++ b/fs/ocfs2/aops.c
@@ -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;
diff --git a/fs/ocfs2/extent_map.c b/fs/ocfs2/extent_map.c
index eef6c1887708..f35e04f27f32 100644
--- a/fs/ocfs2/extent_map.c
+++ b/fs/ocfs2/extent_map.c
@@ -39,6 +39,97 @@
#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);
diff --git a/fs/ocfs2/extent_map.h b/fs/ocfs2/extent_map.h
index 0031c59c347f..1d745e174afc 100644
--- a/fs/ocfs2/extent_map.h
+++ b/fs/ocfs2/extent_map.h
@@ -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 */
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c
index db77e0996bb7..12d2340eee29 100644
--- a/fs/ocfs2/journal.c
+++ b/fs/ocfs2/journal.c
@@ -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();
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
index 395859edb51f..9bdbe4ae92f8 100644
--- a/fs/ocfs2/namei.c
+++ b/fs/ocfs2/namei.c
@@ -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;