diff options
author | Mark Fasheh <mark.fasheh@oracle.com> | 2007-02-14 18:30:30 -0500 |
---|---|---|
committer | Mark Fasheh <mark.fasheh@oracle.com> | 2007-04-26 18:02:16 -0400 |
commit | 25baf2da1473d9dcde1a4c7b0ab26e7d67d9bf62 (patch) | |
tree | 7e07eb6de18f07d4814ab75a02c1c6837fd3e3ea /fs/ocfs2/aops.c | |
parent | 5069120b7227fd323152a3755a0aa6bdeb361310 (diff) |
ocfs2: Teach ocfs2_get_block() about holes
ocfs2_get_block() didn't understand sparse files, fix that. Also remove some
code that isn't really useful anymore. We can fix up
ocfs2_direct_IO_get_blocks() at the same time.
Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>
Diffstat (limited to 'fs/ocfs2/aops.c')
-rw-r--r-- | fs/ocfs2/aops.c | 99 |
1 files changed, 61 insertions, 38 deletions
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index 8368036f434a..acf8f0006725 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c | |||
@@ -137,6 +137,7 @@ static int ocfs2_get_block(struct inode *inode, sector_t iblock, | |||
137 | { | 137 | { |
138 | int err = 0; | 138 | int err = 0; |
139 | u64 p_blkno, past_eof; | 139 | u64 p_blkno, past_eof; |
140 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
140 | 141 | ||
141 | mlog_entry("(0x%p, %llu, 0x%p, %d)\n", inode, | 142 | mlog_entry("(0x%p, %llu, 0x%p, %d)\n", inode, |
142 | (unsigned long long)iblock, bh_result, create); | 143 | (unsigned long long)iblock, bh_result, create); |
@@ -151,15 +152,6 @@ static int ocfs2_get_block(struct inode *inode, sector_t iblock, | |||
151 | goto bail; | 152 | goto bail; |
152 | } | 153 | } |
153 | 154 | ||
154 | /* this can happen if another node truncs after our extend! */ | ||
155 | spin_lock(&OCFS2_I(inode)->ip_lock); | ||
156 | if (iblock >= ocfs2_clusters_to_blocks(inode->i_sb, | ||
157 | OCFS2_I(inode)->ip_clusters)) | ||
158 | err = -EIO; | ||
159 | spin_unlock(&OCFS2_I(inode)->ip_lock); | ||
160 | if (err) | ||
161 | goto bail; | ||
162 | |||
163 | err = ocfs2_extent_map_get_blocks(inode, iblock, &p_blkno, NULL); | 155 | err = ocfs2_extent_map_get_blocks(inode, iblock, &p_blkno, NULL); |
164 | if (err) { | 156 | if (err) { |
165 | mlog(ML_ERROR, "Error %d from get_blocks(0x%p, %llu, 1, " | 157 | mlog(ML_ERROR, "Error %d from get_blocks(0x%p, %llu, 1, " |
@@ -168,22 +160,38 @@ static int ocfs2_get_block(struct inode *inode, sector_t iblock, | |||
168 | goto bail; | 160 | goto bail; |
169 | } | 161 | } |
170 | 162 | ||
171 | map_bh(bh_result, inode->i_sb, p_blkno); | 163 | /* |
172 | 164 | * ocfs2 never allocates in this function - the only time we | |
173 | if (bh_result->b_blocknr == 0) { | 165 | * need to use BH_New is when we're extending i_size on a file |
174 | err = -EIO; | 166 | * system which doesn't support holes, in which case BH_New |
175 | mlog(ML_ERROR, "iblock = %llu p_blkno = %llu blkno=(%llu)\n", | 167 | * allows block_prepare_write() to zero. |
176 | (unsigned long long)iblock, | 168 | */ |
177 | (unsigned long long)p_blkno, | 169 | mlog_bug_on_msg(create && p_blkno == 0 && ocfs2_sparse_alloc(osb), |
178 | (unsigned long long)OCFS2_I(inode)->ip_blkno); | 170 | "ino %lu, iblock %llu\n", inode->i_ino, |
179 | } | 171 | (unsigned long long)iblock); |
172 | |||
173 | if (p_blkno) | ||
174 | map_bh(bh_result, inode->i_sb, p_blkno); | ||
175 | |||
176 | if (!ocfs2_sparse_alloc(osb)) { | ||
177 | if (p_blkno == 0) { | ||
178 | err = -EIO; | ||
179 | mlog(ML_ERROR, | ||
180 | "iblock = %llu p_blkno = %llu blkno=(%llu)\n", | ||
181 | (unsigned long long)iblock, | ||
182 | (unsigned long long)p_blkno, | ||
183 | (unsigned long long)OCFS2_I(inode)->ip_blkno); | ||
184 | mlog(ML_ERROR, "Size %llu, clusters %u\n", (unsigned long long)i_size_read(inode), OCFS2_I(inode)->ip_clusters); | ||
185 | dump_stack(); | ||
186 | } | ||
180 | 187 | ||
181 | past_eof = ocfs2_blocks_for_bytes(inode->i_sb, i_size_read(inode)); | 188 | past_eof = ocfs2_blocks_for_bytes(inode->i_sb, i_size_read(inode)); |
182 | mlog(0, "Inode %lu, past_eof = %llu\n", inode->i_ino, | 189 | mlog(0, "Inode %lu, past_eof = %llu\n", inode->i_ino, |
183 | (unsigned long long)past_eof); | 190 | (unsigned long long)past_eof); |
184 | 191 | ||
185 | if (create && (iblock >= past_eof)) | 192 | if (create && (iblock >= past_eof)) |
186 | set_buffer_new(bh_result); | 193 | set_buffer_new(bh_result); |
194 | } | ||
187 | 195 | ||
188 | bail: | 196 | bail: |
189 | if (err < 0) | 197 | if (err < 0) |
@@ -436,28 +444,15 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock, | |||
436 | * nicely aligned and of the right size, so there's no need | 444 | * nicely aligned and of the right size, so there's no need |
437 | * for us to check any of that. */ | 445 | * for us to check any of that. */ |
438 | 446 | ||
439 | spin_lock(&OCFS2_I(inode)->ip_lock); | 447 | inode_blocks = ocfs2_blocks_for_bytes(inode->i_sb, i_size_read(inode)); |
440 | inode_blocks = ocfs2_clusters_to_blocks(inode->i_sb, | ||
441 | OCFS2_I(inode)->ip_clusters); | ||
442 | |||
443 | /* | ||
444 | * For a read which begins past the end of file, we return a hole. | ||
445 | */ | ||
446 | if (!create && (iblock >= inode_blocks)) { | ||
447 | spin_unlock(&OCFS2_I(inode)->ip_lock); | ||
448 | ret = 0; | ||
449 | goto bail; | ||
450 | } | ||
451 | 448 | ||
452 | /* | 449 | /* |
453 | * Any write past EOF is not allowed because we'd be extending. | 450 | * Any write past EOF is not allowed because we'd be extending. |
454 | */ | 451 | */ |
455 | if (create && (iblock + max_blocks) > inode_blocks) { | 452 | if (create && (iblock + max_blocks) > inode_blocks) { |
456 | spin_unlock(&OCFS2_I(inode)->ip_lock); | ||
457 | ret = -EIO; | 453 | ret = -EIO; |
458 | goto bail; | 454 | goto bail; |
459 | } | 455 | } |
460 | spin_unlock(&OCFS2_I(inode)->ip_lock); | ||
461 | 456 | ||
462 | /* This figures out the size of the next contiguous block, and | 457 | /* This figures out the size of the next contiguous block, and |
463 | * our logical offset */ | 458 | * our logical offset */ |
@@ -470,7 +465,35 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock, | |||
470 | goto bail; | 465 | goto bail; |
471 | } | 466 | } |
472 | 467 | ||
473 | map_bh(bh_result, inode->i_sb, p_blkno); | 468 | if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)) && !p_blkno) { |
469 | ocfs2_error(inode->i_sb, | ||
470 | "Inode %llu has a hole at block %llu\n", | ||
471 | (unsigned long long)OCFS2_I(inode)->ip_blkno, | ||
472 | (unsigned long long)iblock); | ||
473 | ret = -EROFS; | ||
474 | goto bail; | ||
475 | } | ||
476 | |||
477 | /* | ||
478 | * get_more_blocks() expects us to describe a hole by clearing | ||
479 | * the mapped bit on bh_result(). | ||
480 | */ | ||
481 | if (p_blkno) | ||
482 | map_bh(bh_result, inode->i_sb, p_blkno); | ||
483 | else { | ||
484 | /* | ||
485 | * ocfs2_prepare_inode_for_write() should have caught | ||
486 | * the case where we'd be filling a hole and triggered | ||
487 | * a buffered write instead. | ||
488 | */ | ||
489 | if (create) { | ||
490 | ret = -EIO; | ||
491 | mlog_errno(ret); | ||
492 | goto bail; | ||
493 | } | ||
494 | |||
495 | clear_buffer_mapped(bh_result); | ||
496 | } | ||
474 | 497 | ||
475 | /* make sure we don't map more than max_blocks blocks here as | 498 | /* make sure we don't map more than max_blocks blocks here as |
476 | that's all the kernel will handle at this point. */ | 499 | that's all the kernel will handle at this point. */ |