diff options
author | Joel Becker <joel.becker@oracle.com> | 2008-11-13 17:49:17 -0500 |
---|---|---|
committer | Mark Fasheh <mfasheh@suse.com> | 2009-01-05 11:36:53 -0500 |
commit | a22305cc693254a2aa651e797875669112ef8635 (patch) | |
tree | 6beabdffc91bec297824f2049293c14bb05daadb | |
parent | 5e96581a377fc6bd76e9b112da9aeb8a7ae8bf22 (diff) |
ocfs2: Wrap dirblock reads in a dedicated function.
We have ocfs2_bread() as a vestige of the original ext-based dir code.
It's only used by directories, though. Turn it into
ocfs2_read_dir_block(), with a prototype matching the other metadata
read functions. It's set up to validate dirblocks when the time comes.
Signed-off-by: Joel Becker <joel.becker@oracle.com>
Signed-off-by: Mark Fasheh <mfasheh@suse.com>
-rw-r--r-- | fs/ocfs2/dir.c | 150 |
1 files changed, 88 insertions, 62 deletions
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index 5777045f1a67..c2f3fd93be5c 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c | |||
@@ -82,49 +82,6 @@ static int ocfs2_do_extend_dir(struct super_block *sb, | |||
82 | struct ocfs2_alloc_context *meta_ac, | 82 | struct ocfs2_alloc_context *meta_ac, |
83 | struct buffer_head **new_bh); | 83 | struct buffer_head **new_bh); |
84 | 84 | ||
85 | static struct buffer_head *ocfs2_bread(struct inode *inode, | ||
86 | int block, int *err, int reada) | ||
87 | { | ||
88 | struct buffer_head *bh = NULL; | ||
89 | int tmperr; | ||
90 | u64 p_blkno; | ||
91 | int readflags = 0; | ||
92 | |||
93 | if (reada) | ||
94 | readflags |= OCFS2_BH_READAHEAD; | ||
95 | |||
96 | if (((u64)block << inode->i_sb->s_blocksize_bits) >= | ||
97 | i_size_read(inode)) { | ||
98 | BUG_ON(!reada); | ||
99 | return NULL; | ||
100 | } | ||
101 | |||
102 | down_read(&OCFS2_I(inode)->ip_alloc_sem); | ||
103 | tmperr = ocfs2_extent_map_get_blocks(inode, block, &p_blkno, NULL, | ||
104 | NULL); | ||
105 | up_read(&OCFS2_I(inode)->ip_alloc_sem); | ||
106 | if (tmperr < 0) { | ||
107 | mlog_errno(tmperr); | ||
108 | goto fail; | ||
109 | } | ||
110 | |||
111 | tmperr = ocfs2_read_blocks(inode, p_blkno, 1, &bh, readflags); | ||
112 | if (tmperr < 0) | ||
113 | goto fail; | ||
114 | |||
115 | tmperr = 0; | ||
116 | |||
117 | *err = 0; | ||
118 | return bh; | ||
119 | |||
120 | fail: | ||
121 | brelse(bh); | ||
122 | bh = NULL; | ||
123 | |||
124 | *err = -EIO; | ||
125 | return NULL; | ||
126 | } | ||
127 | |||
128 | /* | 85 | /* |
129 | * bh passed here can be an inode block or a dir data block, depending | 86 | * bh passed here can be an inode block or a dir data block, depending |
130 | * on the inode inline data flag. | 87 | * on the inode inline data flag. |
@@ -250,6 +207,76 @@ out: | |||
250 | return NULL; | 207 | return NULL; |
251 | } | 208 | } |
252 | 209 | ||
210 | static int ocfs2_validate_dir_block(struct super_block *sb, | ||
211 | struct buffer_head *bh) | ||
212 | { | ||
213 | /* | ||
214 | * Nothing yet. We don't validate dirents here, that's handled | ||
215 | * in-place when the code walks them. | ||
216 | */ | ||
217 | |||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | /* | ||
222 | * This function forces all errors to -EIO for consistency with its | ||
223 | * predecessor, ocfs2_bread(). We haven't audited what returning the | ||
224 | * real error codes would do to callers. We log the real codes with | ||
225 | * mlog_errno() before we squash them. | ||
226 | */ | ||
227 | static int ocfs2_read_dir_block(struct inode *inode, u64 v_block, | ||
228 | struct buffer_head **bh, int flags) | ||
229 | { | ||
230 | int rc = 0; | ||
231 | struct buffer_head *tmp = *bh; | ||
232 | u64 p_blkno; | ||
233 | |||
234 | if (((u64)v_block << inode->i_sb->s_blocksize_bits) >= | ||
235 | i_size_read(inode)) { | ||
236 | BUG_ON(!(flags & OCFS2_BH_READAHEAD)); | ||
237 | goto out; | ||
238 | } | ||
239 | |||
240 | down_read(&OCFS2_I(inode)->ip_alloc_sem); | ||
241 | rc = ocfs2_extent_map_get_blocks(inode, v_block, &p_blkno, NULL, | ||
242 | NULL); | ||
243 | up_read(&OCFS2_I(inode)->ip_alloc_sem); | ||
244 | if (rc) { | ||
245 | mlog_errno(rc); | ||
246 | goto out; | ||
247 | } | ||
248 | |||
249 | if (!p_blkno) { | ||
250 | rc = -EIO; | ||
251 | mlog(ML_ERROR, | ||
252 | "Directory #%llu contains a hole at offset %llu\n", | ||
253 | (unsigned long long)OCFS2_I(inode)->ip_blkno, | ||
254 | (unsigned long long)v_block << inode->i_sb->s_blocksize_bits); | ||
255 | goto out; | ||
256 | } | ||
257 | |||
258 | rc = ocfs2_read_blocks(inode, p_blkno, 1, &tmp, flags); | ||
259 | if (rc) { | ||
260 | mlog_errno(rc); | ||
261 | goto out; | ||
262 | } | ||
263 | |||
264 | if (!(flags & OCFS2_BH_READAHEAD)) { | ||
265 | rc = ocfs2_validate_dir_block(inode->i_sb, tmp); | ||
266 | if (rc) { | ||
267 | brelse(tmp); | ||
268 | goto out; | ||
269 | } | ||
270 | } | ||
271 | |||
272 | /* If ocfs2_read_blocks() got us a new bh, pass it up. */ | ||
273 | if (!*bh) | ||
274 | *bh = tmp; | ||
275 | |||
276 | out: | ||
277 | return rc ? -EIO : 0; | ||
278 | } | ||
279 | |||
253 | static struct buffer_head *ocfs2_find_entry_el(const char *name, int namelen, | 280 | static struct buffer_head *ocfs2_find_entry_el(const char *name, int namelen, |
254 | struct inode *dir, | 281 | struct inode *dir, |
255 | struct ocfs2_dir_entry **res_dir) | 282 | struct ocfs2_dir_entry **res_dir) |
@@ -296,15 +323,17 @@ restart: | |||
296 | } | 323 | } |
297 | num++; | 324 | num++; |
298 | 325 | ||
299 | bh = ocfs2_bread(dir, b++, &err, 1); | 326 | bh = NULL; |
327 | err = ocfs2_read_dir_block(dir, b++, &bh, | ||
328 | OCFS2_BH_READAHEAD); | ||
300 | bh_use[ra_max] = bh; | 329 | bh_use[ra_max] = bh; |
301 | } | 330 | } |
302 | } | 331 | } |
303 | if ((bh = bh_use[ra_ptr++]) == NULL) | 332 | if ((bh = bh_use[ra_ptr++]) == NULL) |
304 | goto next; | 333 | goto next; |
305 | if (ocfs2_read_block(dir, block, &bh)) { | 334 | if (ocfs2_read_dir_block(dir, block, &bh, 0)) { |
306 | /* read error, skip block & hope for the best. | 335 | /* read error, skip block & hope for the best. |
307 | * ocfs2_read_block() has released the bh. */ | 336 | * ocfs2_read_dir_block() has released the bh. */ |
308 | ocfs2_error(dir->i_sb, "reading directory %llu, " | 337 | ocfs2_error(dir->i_sb, "reading directory %llu, " |
309 | "offset %lu\n", | 338 | "offset %lu\n", |
310 | (unsigned long long)OCFS2_I(dir)->ip_blkno, | 339 | (unsigned long long)OCFS2_I(dir)->ip_blkno, |
@@ -724,7 +753,6 @@ static int ocfs2_dir_foreach_blk_el(struct inode *inode, | |||
724 | int i, stored; | 753 | int i, stored; |
725 | struct buffer_head * bh, * tmp; | 754 | struct buffer_head * bh, * tmp; |
726 | struct ocfs2_dir_entry * de; | 755 | struct ocfs2_dir_entry * de; |
727 | int err; | ||
728 | struct super_block * sb = inode->i_sb; | 756 | struct super_block * sb = inode->i_sb; |
729 | unsigned int ra_sectors = 16; | 757 | unsigned int ra_sectors = 16; |
730 | 758 | ||
@@ -735,12 +763,8 @@ static int ocfs2_dir_foreach_blk_el(struct inode *inode, | |||
735 | 763 | ||
736 | while (!error && !stored && *f_pos < i_size_read(inode)) { | 764 | while (!error && !stored && *f_pos < i_size_read(inode)) { |
737 | blk = (*f_pos) >> sb->s_blocksize_bits; | 765 | blk = (*f_pos) >> sb->s_blocksize_bits; |
738 | bh = ocfs2_bread(inode, blk, &err, 0); | 766 | if (ocfs2_read_dir_block(inode, blk, &bh, 0)) { |
739 | if (!bh) { | 767 | /* Skip the corrupt dirblock and keep trying */ |
740 | mlog(ML_ERROR, | ||
741 | "directory #%llu contains a hole at offset %lld\n", | ||
742 | (unsigned long long)OCFS2_I(inode)->ip_blkno, | ||
743 | *f_pos); | ||
744 | *f_pos += sb->s_blocksize - offset; | 768 | *f_pos += sb->s_blocksize - offset; |
745 | continue; | 769 | continue; |
746 | } | 770 | } |
@@ -754,8 +778,10 @@ static int ocfs2_dir_foreach_blk_el(struct inode *inode, | |||
754 | || (((last_ra_blk - blk) << 9) <= (ra_sectors / 2))) { | 778 | || (((last_ra_blk - blk) << 9) <= (ra_sectors / 2))) { |
755 | for (i = ra_sectors >> (sb->s_blocksize_bits - 9); | 779 | for (i = ra_sectors >> (sb->s_blocksize_bits - 9); |
756 | i > 0; i--) { | 780 | i > 0; i--) { |
757 | tmp = ocfs2_bread(inode, ++blk, &err, 1); | 781 | tmp = NULL; |
758 | brelse(tmp); | 782 | if (!ocfs2_read_dir_block(inode, ++blk, &tmp, |
783 | OCFS2_BH_READAHEAD)) | ||
784 | brelse(tmp); | ||
759 | } | 785 | } |
760 | last_ra_blk = blk; | 786 | last_ra_blk = blk; |
761 | ra_sectors = 8; | 787 | ra_sectors = 8; |
@@ -828,6 +854,7 @@ revalidate: | |||
828 | } | 854 | } |
829 | offset = 0; | 855 | offset = 0; |
830 | brelse(bh); | 856 | brelse(bh); |
857 | bh = NULL; | ||
831 | } | 858 | } |
832 | 859 | ||
833 | stored = 0; | 860 | stored = 0; |
@@ -1680,8 +1707,8 @@ static int ocfs2_find_dir_space_el(struct inode *dir, const char *name, | |||
1680 | struct super_block *sb = dir->i_sb; | 1707 | struct super_block *sb = dir->i_sb; |
1681 | int status; | 1708 | int status; |
1682 | 1709 | ||
1683 | bh = ocfs2_bread(dir, 0, &status, 0); | 1710 | status = ocfs2_read_dir_block(dir, 0, &bh, 0); |
1684 | if (!bh) { | 1711 | if (status) { |
1685 | mlog_errno(status); | 1712 | mlog_errno(status); |
1686 | goto bail; | 1713 | goto bail; |
1687 | } | 1714 | } |
@@ -1702,11 +1729,10 @@ static int ocfs2_find_dir_space_el(struct inode *dir, const char *name, | |||
1702 | status = -ENOSPC; | 1729 | status = -ENOSPC; |
1703 | goto bail; | 1730 | goto bail; |
1704 | } | 1731 | } |
1705 | bh = ocfs2_bread(dir, | 1732 | status = ocfs2_read_dir_block(dir, |
1706 | offset >> sb->s_blocksize_bits, | 1733 | offset >> sb->s_blocksize_bits, |
1707 | &status, | 1734 | &bh, 0); |
1708 | 0); | 1735 | if (status) { |
1709 | if (!bh) { | ||
1710 | mlog_errno(status); | 1736 | mlog_errno(status); |
1711 | goto bail; | 1737 | goto bail; |
1712 | } | 1738 | } |