Commit 4f902c37727bbedbc0508a1477874c58ddcc9af8
1 parent
49cb8d2d49
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>
Showing 5 changed files with 109 additions and 12 deletions Side-by-side Diff
fs/ocfs2/aops.c
... | ... | @@ -439,8 +439,7 @@ |
439 | 439 | struct buffer_head *bh_result, int create) |
440 | 440 | { |
441 | 441 | int ret; |
442 | - u64 p_blkno, inode_blocks; | |
443 | - int contig_blocks; | |
442 | + u64 p_blkno, inode_blocks, contig_blocks; | |
444 | 443 | unsigned int ext_flags; |
445 | 444 | unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits; |
446 | 445 | unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits; |
fs/ocfs2/extent_map.c
... | ... | @@ -39,6 +39,97 @@ |
39 | 39 | #include "buffer_head_io.h" |
40 | 40 | |
41 | 41 | /* |
42 | + * Return the 1st index within el which contains an extent start | |
43 | + * larger than v_cluster. | |
44 | + */ | |
45 | +static int ocfs2_search_for_hole_index(struct ocfs2_extent_list *el, | |
46 | + u32 v_cluster) | |
47 | +{ | |
48 | + int i; | |
49 | + struct ocfs2_extent_rec *rec; | |
50 | + | |
51 | + for(i = 0; i < le16_to_cpu(el->l_next_free_rec); i++) { | |
52 | + rec = &el->l_recs[i]; | |
53 | + | |
54 | + if (v_cluster < le32_to_cpu(rec->e_cpos)) | |
55 | + break; | |
56 | + } | |
57 | + | |
58 | + return i; | |
59 | +} | |
60 | + | |
61 | +/* | |
62 | + * Figure out the size of a hole which starts at v_cluster within the given | |
63 | + * extent list. | |
64 | + * | |
65 | + * If there is no more allocation past v_cluster, we return the maximum | |
66 | + * cluster size minus v_cluster. | |
67 | + * | |
68 | + * If we have in-inode extents, then el points to the dinode list and | |
69 | + * eb_bh is NULL. Otherwise, eb_bh should point to the extent block | |
70 | + * containing el. | |
71 | + */ | |
72 | +static int ocfs2_figure_hole_clusters(struct inode *inode, | |
73 | + struct ocfs2_extent_list *el, | |
74 | + struct buffer_head *eb_bh, | |
75 | + u32 v_cluster, | |
76 | + u32 *num_clusters) | |
77 | +{ | |
78 | + int ret, i; | |
79 | + struct buffer_head *next_eb_bh = NULL; | |
80 | + struct ocfs2_extent_block *eb, *next_eb; | |
81 | + | |
82 | + i = ocfs2_search_for_hole_index(el, v_cluster); | |
83 | + | |
84 | + if (i == le16_to_cpu(el->l_next_free_rec) && eb_bh) { | |
85 | + eb = (struct ocfs2_extent_block *)eb_bh->b_data; | |
86 | + | |
87 | + /* | |
88 | + * Check the next leaf for any extents. | |
89 | + */ | |
90 | + | |
91 | + if (le64_to_cpu(eb->h_next_leaf_blk) == 0ULL) | |
92 | + goto no_more_extents; | |
93 | + | |
94 | + ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), | |
95 | + le64_to_cpu(eb->h_next_leaf_blk), | |
96 | + &next_eb_bh, OCFS2_BH_CACHED, inode); | |
97 | + if (ret) { | |
98 | + mlog_errno(ret); | |
99 | + goto out; | |
100 | + } | |
101 | + next_eb = (struct ocfs2_extent_block *)next_eb_bh->b_data; | |
102 | + | |
103 | + if (!OCFS2_IS_VALID_EXTENT_BLOCK(next_eb)) { | |
104 | + ret = -EROFS; | |
105 | + OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, next_eb); | |
106 | + goto out; | |
107 | + } | |
108 | + | |
109 | + el = &next_eb->h_list; | |
110 | + | |
111 | + i = ocfs2_search_for_hole_index(el, v_cluster); | |
112 | + } | |
113 | + | |
114 | +no_more_extents: | |
115 | + if (i == le16_to_cpu(el->l_next_free_rec)) { | |
116 | + /* | |
117 | + * We're at the end of our existing allocation. Just | |
118 | + * return the maximum number of clusters we could | |
119 | + * possibly allocate. | |
120 | + */ | |
121 | + *num_clusters = UINT_MAX - v_cluster; | |
122 | + } else { | |
123 | + *num_clusters = le32_to_cpu(el->l_recs[i].e_cpos) - v_cluster; | |
124 | + } | |
125 | + | |
126 | + ret = 0; | |
127 | +out: | |
128 | + brelse(next_eb_bh); | |
129 | + return ret; | |
130 | +} | |
131 | + | |
132 | +/* | |
42 | 133 | * Return the index of the extent record which contains cluster #v_cluster. |
43 | 134 | * -1 is returned if it was not found. |
44 | 135 | * |
45 | 136 | |
... | ... | @@ -117,11 +208,19 @@ |
117 | 208 | if (i == -1) { |
118 | 209 | /* |
119 | 210 | * A hole was found. Return some canned values that |
120 | - * callers can key on. | |
211 | + * callers can key on. If asked for, num_clusters will | |
212 | + * be populated with the size of the hole. | |
121 | 213 | */ |
122 | 214 | *p_cluster = 0; |
123 | - if (num_clusters) | |
124 | - *num_clusters = 1; | |
215 | + if (num_clusters) { | |
216 | + ret = ocfs2_figure_hole_clusters(inode, el, eb_bh, | |
217 | + v_cluster, | |
218 | + num_clusters); | |
219 | + if (ret) { | |
220 | + mlog_errno(ret); | |
221 | + goto out; | |
222 | + } | |
223 | + } | |
125 | 224 | } else { |
126 | 225 | rec = &el->l_recs[i]; |
127 | 226 | |
... | ... | @@ -162,7 +261,7 @@ |
162 | 261 | * all while the map is in the process of being updated. |
163 | 262 | */ |
164 | 263 | int ocfs2_extent_map_get_blocks(struct inode *inode, u64 v_blkno, u64 *p_blkno, |
165 | - int *ret_count, unsigned int *extent_flags) | |
264 | + u64 *ret_count, unsigned int *extent_flags) | |
166 | 265 | { |
167 | 266 | int ret; |
168 | 267 | int bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1); |
fs/ocfs2/extent_map.h
... | ... | @@ -28,7 +28,7 @@ |
28 | 28 | int ocfs2_get_clusters(struct inode *inode, u32 v_cluster, u32 *p_cluster, |
29 | 29 | u32 *num_clusters, unsigned int *extent_flags); |
30 | 30 | int ocfs2_extent_map_get_blocks(struct inode *inode, u64 v_blkno, u64 *p_blkno, |
31 | - int *ret_count, unsigned int *extent_flags); | |
31 | + u64 *ret_count, unsigned int *extent_flags); | |
32 | 32 | |
33 | 33 | #endif /* _EXTENT_MAP_H */ |
fs/ocfs2/journal.c
... | ... | @@ -649,9 +649,9 @@ |
649 | 649 | static int ocfs2_force_read_journal(struct inode *inode) |
650 | 650 | { |
651 | 651 | int status = 0; |
652 | - int i, p_blocks; | |
653 | - u64 v_blkno, p_blkno; | |
654 | -#define CONCURRENT_JOURNAL_FILL 32 | |
652 | + int i; | |
653 | + u64 v_blkno, p_blkno, p_blocks; | |
654 | +#define CONCURRENT_JOURNAL_FILL 32ULL | |
655 | 655 | struct buffer_head *bhs[CONCURRENT_JOURNAL_FILL]; |
656 | 656 | |
657 | 657 | mlog_entry_void(); |
fs/ocfs2/namei.c
... | ... | @@ -1483,8 +1483,7 @@ |
1483 | 1483 | struct buffer_head **bhs = NULL; |
1484 | 1484 | const char *c; |
1485 | 1485 | struct super_block *sb = osb->sb; |
1486 | - u64 p_blkno; | |
1487 | - int p_blocks; | |
1486 | + u64 p_blkno, p_blocks; | |
1488 | 1487 | int virtual, blocks, status, i, bytes_left; |
1489 | 1488 | |
1490 | 1489 | bytes_left = i_size_read(inode) + 1; |