Commit 4f902c37 authored by Mark Fasheh's avatar Mark Fasheh

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: default avatarMark Fasheh <mark.fasheh@oracle.com>
parent 49cb8d2d
...@@ -439,8 +439,7 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock, ...@@ -439,8 +439,7 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create) struct buffer_head *bh_result, int create)
{ {
int ret; int ret;
u64 p_blkno, inode_blocks; u64 p_blkno, inode_blocks, contig_blocks;
int contig_blocks;
unsigned int ext_flags; unsigned int ext_flags;
unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits; unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits;
unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits; unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits;
......
...@@ -38,6 +38,97 @@ ...@@ -38,6 +38,97 @@
#include "buffer_head_io.h" #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. * Return the index of the extent record which contains cluster #v_cluster.
* -1 is returned if it was not found. * -1 is returned if it was not found.
...@@ -117,11 +208,19 @@ int ocfs2_get_clusters(struct inode *inode, u32 v_cluster, ...@@ -117,11 +208,19 @@ int ocfs2_get_clusters(struct inode *inode, u32 v_cluster,
if (i == -1) { if (i == -1) {
/* /*
* A hole was found. Return some canned values that * 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; *p_cluster = 0;
if (num_clusters) if (num_clusters) {
*num_clusters = 1; ret = ocfs2_figure_hole_clusters(inode, el, eb_bh,
v_cluster,
num_clusters);
if (ret) {
mlog_errno(ret);
goto out;
}
}
} else { } else {
rec = &el->l_recs[i]; rec = &el->l_recs[i];
...@@ -162,7 +261,7 @@ int ocfs2_get_clusters(struct inode *inode, u32 v_cluster, ...@@ -162,7 +261,7 @@ int ocfs2_get_clusters(struct inode *inode, u32 v_cluster,
* all while the map is in the process of being updated. * 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 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 ret;
int bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1); int bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1);
......
...@@ -28,6 +28,6 @@ ...@@ -28,6 +28,6 @@
int ocfs2_get_clusters(struct inode *inode, u32 v_cluster, u32 *p_cluster, int ocfs2_get_clusters(struct inode *inode, u32 v_cluster, u32 *p_cluster,
u32 *num_clusters, unsigned int *extent_flags); u32 *num_clusters, unsigned int *extent_flags);
int ocfs2_extent_map_get_blocks(struct inode *inode, u64 v_blkno, u64 *p_blkno, 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 */ #endif /* _EXTENT_MAP_H */
...@@ -649,9 +649,9 @@ int ocfs2_journal_wipe(struct ocfs2_journal *journal, int full) ...@@ -649,9 +649,9 @@ int ocfs2_journal_wipe(struct ocfs2_journal *journal, int full)
static int ocfs2_force_read_journal(struct inode *inode) static int ocfs2_force_read_journal(struct inode *inode)
{ {
int status = 0; int status = 0;
int i, p_blocks; int i;
u64 v_blkno, p_blkno; u64 v_blkno, p_blkno, p_blocks;
#define CONCURRENT_JOURNAL_FILL 32 #define CONCURRENT_JOURNAL_FILL 32ULL
struct buffer_head *bhs[CONCURRENT_JOURNAL_FILL]; struct buffer_head *bhs[CONCURRENT_JOURNAL_FILL];
mlog_entry_void(); mlog_entry_void();
......
...@@ -1483,8 +1483,7 @@ static int ocfs2_create_symlink_data(struct ocfs2_super *osb, ...@@ -1483,8 +1483,7 @@ static int ocfs2_create_symlink_data(struct ocfs2_super *osb,
struct buffer_head **bhs = NULL; struct buffer_head **bhs = NULL;
const char *c; const char *c;
struct super_block *sb = osb->sb; struct super_block *sb = osb->sb;
u64 p_blkno; u64 p_blkno, p_blocks;
int p_blocks;
int virtual, blocks, status, i, bytes_left; int virtual, blocks, status, i, bytes_left;
bytes_left = i_size_read(inode) + 1; bytes_left = i_size_read(inode) + 1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment