diff options
| author | Mark Fasheh <mfasheh@suse.com> | 2008-10-03 17:32:11 -0400 |
|---|---|---|
| committer | Theodore Ts'o <tytso@mit.edu> | 2008-10-03 17:32:11 -0400 |
| commit | 00dc417fa3e763345b34ccb6034d72de76eea0a1 (patch) | |
| tree | c50da655dbd6747499f4516280f323b90214af62 | |
| parent | c4b929b85bdb64afacbbf6453b1f2bf7e14c9e89 (diff) | |
ocfs2: fiemap support
Plug ocfs2 into ->fiemap. Some portions of ocfs2_get_clusters() had to be
refactored so that the extent cache can be skipped in favor of going
directly to the on-disk records. This makes it easier for us to determine
which extent is the last one in the btree. Also, I'm not sure we want to be
caching fiemap lookups anyway as they're not directly related to data
read/write.
Signed-off-by: Mark Fasheh <mfasheh@suse.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Cc: ocfs2-devel@oss.oracle.com
Cc: linux-fsdevel@vger.kernel.org
| -rw-r--r-- | fs/ocfs2/alloc.c | 9 | ||||
| -rw-r--r-- | fs/ocfs2/alloc.h | 9 | ||||
| -rw-r--r-- | fs/ocfs2/extent_map.c | 346 | ||||
| -rw-r--r-- | fs/ocfs2/extent_map.h | 3 | ||||
| -rw-r--r-- | fs/ocfs2/file.c | 1 |
5 files changed, 306 insertions, 62 deletions
diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index 10bfb466e068..29ff57ec5d1f 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c | |||
| @@ -990,15 +990,6 @@ out: | |||
| 990 | } | 990 | } |
| 991 | 991 | ||
| 992 | /* | 992 | /* |
| 993 | * This is only valid for leaf nodes, which are the only ones that can | ||
| 994 | * have empty extents anyway. | ||
| 995 | */ | ||
| 996 | static inline int ocfs2_is_empty_extent(struct ocfs2_extent_rec *rec) | ||
| 997 | { | ||
| 998 | return !rec->e_leaf_clusters; | ||
| 999 | } | ||
| 1000 | |||
| 1001 | /* | ||
| 1002 | * This function will discard the rightmost extent record. | 993 | * This function will discard the rightmost extent record. |
| 1003 | */ | 994 | */ |
| 1004 | static void ocfs2_shift_records_right(struct ocfs2_extent_list *el) | 995 | static void ocfs2_shift_records_right(struct ocfs2_extent_list *el) |
diff --git a/fs/ocfs2/alloc.h b/fs/ocfs2/alloc.h index 42ff94bd8011..60cd3d59230c 100644 --- a/fs/ocfs2/alloc.h +++ b/fs/ocfs2/alloc.h | |||
| @@ -146,4 +146,13 @@ static inline unsigned int ocfs2_rec_clusters(struct ocfs2_extent_list *el, | |||
| 146 | return le16_to_cpu(rec->e_leaf_clusters); | 146 | return le16_to_cpu(rec->e_leaf_clusters); |
| 147 | } | 147 | } |
| 148 | 148 | ||
| 149 | /* | ||
| 150 | * This is only valid for leaf nodes, which are the only ones that can | ||
| 151 | * have empty extents anyway. | ||
| 152 | */ | ||
| 153 | static inline int ocfs2_is_empty_extent(struct ocfs2_extent_rec *rec) | ||
| 154 | { | ||
| 155 | return !rec->e_leaf_clusters; | ||
| 156 | } | ||
| 157 | |||
| 149 | #endif /* OCFS2_ALLOC_H */ | 158 | #endif /* OCFS2_ALLOC_H */ |
diff --git a/fs/ocfs2/extent_map.c b/fs/ocfs2/extent_map.c index c58668a326fe..aed268e80b49 100644 --- a/fs/ocfs2/extent_map.c +++ b/fs/ocfs2/extent_map.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include <linux/fs.h> | 25 | #include <linux/fs.h> |
| 26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
| 27 | #include <linux/types.h> | 27 | #include <linux/types.h> |
| 28 | #include <linux/fiemap.h> | ||
| 28 | 29 | ||
| 29 | #define MLOG_MASK_PREFIX ML_EXTENT_MAP | 30 | #define MLOG_MASK_PREFIX ML_EXTENT_MAP |
| 30 | #include <cluster/masklog.h> | 31 | #include <cluster/masklog.h> |
| @@ -32,6 +33,7 @@ | |||
| 32 | #include "ocfs2.h" | 33 | #include "ocfs2.h" |
| 33 | 34 | ||
| 34 | #include "alloc.h" | 35 | #include "alloc.h" |
| 36 | #include "dlmglue.h" | ||
| 35 | #include "extent_map.h" | 37 | #include "extent_map.h" |
| 36 | #include "inode.h" | 38 | #include "inode.h" |
| 37 | #include "super.h" | 39 | #include "super.h" |
| @@ -282,6 +284,51 @@ out: | |||
| 282 | kfree(new_emi); | 284 | kfree(new_emi); |
| 283 | } | 285 | } |
| 284 | 286 | ||
| 287 | static int ocfs2_last_eb_is_empty(struct inode *inode, | ||
| 288 | struct ocfs2_dinode *di) | ||
| 289 | { | ||
| 290 | int ret, next_free; | ||
| 291 | u64 last_eb_blk = le64_to_cpu(di->i_last_eb_blk); | ||
| 292 | struct buffer_head *eb_bh = NULL; | ||
| 293 | struct ocfs2_extent_block *eb; | ||
| 294 | struct ocfs2_extent_list *el; | ||
| 295 | |||
| 296 | ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), last_eb_blk, | ||
| 297 | &eb_bh, OCFS2_BH_CACHED, inode); | ||
| 298 | if (ret) { | ||
| 299 | mlog_errno(ret); | ||
| 300 | goto out; | ||
| 301 | } | ||
| 302 | |||
| 303 | eb = (struct ocfs2_extent_block *) eb_bh->b_data; | ||
| 304 | el = &eb->h_list; | ||
| 305 | |||
| 306 | if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) { | ||
| 307 | ret = -EROFS; | ||
| 308 | OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb); | ||
| 309 | goto out; | ||
| 310 | } | ||
| 311 | |||
| 312 | if (el->l_tree_depth) { | ||
| 313 | ocfs2_error(inode->i_sb, | ||
| 314 | "Inode %lu has non zero tree depth in " | ||
| 315 | "leaf block %llu\n", inode->i_ino, | ||
| 316 | (unsigned long long)eb_bh->b_blocknr); | ||
| 317 | ret = -EROFS; | ||
| 318 | goto out; | ||
| 319 | } | ||
| 320 | |||
| 321 | next_free = le16_to_cpu(el->l_next_free_rec); | ||
| 322 | |||
| 323 | if (next_free == 0 || | ||
| 324 | (next_free == 1 && ocfs2_is_empty_extent(&el->l_recs[0]))) | ||
| 325 | ret = 1; | ||
| 326 | |||
| 327 | out: | ||
| 328 | brelse(eb_bh); | ||
| 329 | return ret; | ||
| 330 | } | ||
| 331 | |||
| 285 | /* | 332 | /* |
| 286 | * Return the 1st index within el which contains an extent start | 333 | * Return the 1st index within el which contains an extent start |
| 287 | * larger than v_cluster. | 334 | * larger than v_cluster. |
| @@ -373,42 +420,28 @@ out: | |||
| 373 | return ret; | 420 | return ret; |
| 374 | } | 421 | } |
| 375 | 422 | ||
| 376 | int ocfs2_get_clusters(struct inode *inode, u32 v_cluster, | 423 | static int ocfs2_get_clusters_nocache(struct inode *inode, |
| 377 | u32 *p_cluster, u32 *num_clusters, | 424 | struct buffer_head *di_bh, |
| 378 | unsigned int *extent_flags) | 425 | u32 v_cluster, unsigned int *hole_len, |
| 426 | struct ocfs2_extent_rec *ret_rec, | ||
| 427 | unsigned int *is_last) | ||
| 379 | { | 428 | { |
| 380 | int ret, i; | 429 | int i, ret, tree_height, len; |
| 381 | unsigned int flags = 0; | ||
| 382 | struct buffer_head *di_bh = NULL; | ||
| 383 | struct buffer_head *eb_bh = NULL; | ||
| 384 | struct ocfs2_dinode *di; | 430 | struct ocfs2_dinode *di; |
| 385 | struct ocfs2_extent_block *eb; | 431 | struct ocfs2_extent_block *uninitialized_var(eb); |
| 386 | struct ocfs2_extent_list *el; | 432 | struct ocfs2_extent_list *el; |
| 387 | struct ocfs2_extent_rec *rec; | 433 | struct ocfs2_extent_rec *rec; |
| 388 | u32 coff; | 434 | struct buffer_head *eb_bh = NULL; |
| 389 | |||
| 390 | if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { | ||
| 391 | ret = -ERANGE; | ||
| 392 | mlog_errno(ret); | ||
| 393 | goto out; | ||
| 394 | } | ||
| 395 | |||
| 396 | ret = ocfs2_extent_map_lookup(inode, v_cluster, p_cluster, | ||
| 397 | num_clusters, extent_flags); | ||
| 398 | if (ret == 0) | ||
| 399 | goto out; | ||
| 400 | 435 | ||
| 401 | ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), OCFS2_I(inode)->ip_blkno, | 436 | memset(ret_rec, 0, sizeof(*ret_rec)); |
| 402 | &di_bh, OCFS2_BH_CACHED, inode); | 437 | if (is_last) |
| 403 | if (ret) { | 438 | *is_last = 0; |
| 404 | mlog_errno(ret); | ||
| 405 | goto out; | ||
| 406 | } | ||
| 407 | 439 | ||
| 408 | di = (struct ocfs2_dinode *) di_bh->b_data; | 440 | di = (struct ocfs2_dinode *) di_bh->b_data; |
| 409 | el = &di->id2.i_list; | 441 | el = &di->id2.i_list; |
| 442 | tree_height = le16_to_cpu(el->l_tree_depth); | ||
| 410 | 443 | ||
| 411 | if (el->l_tree_depth) { | 444 | if (tree_height > 0) { |
| 412 | ret = ocfs2_find_leaf(inode, el, v_cluster, &eb_bh); | 445 | ret = ocfs2_find_leaf(inode, el, v_cluster, &eb_bh); |
| 413 | if (ret) { | 446 | if (ret) { |
| 414 | mlog_errno(ret); | 447 | mlog_errno(ret); |
| @@ -431,46 +464,143 @@ int ocfs2_get_clusters(struct inode *inode, u32 v_cluster, | |||
| 431 | i = ocfs2_search_extent_list(el, v_cluster); | 464 | i = ocfs2_search_extent_list(el, v_cluster); |
| 432 | if (i == -1) { | 465 | if (i == -1) { |
| 433 | /* | 466 | /* |
| 434 | * A hole was found. Return some canned values that | 467 | * Holes can be larger than the maximum size of an |
| 435 | * callers can key on. If asked for, num_clusters will | 468 | * extent, so we return their lengths in a seperate |
| 436 | * be populated with the size of the hole. | 469 | * field. |
| 437 | */ | 470 | */ |
| 438 | *p_cluster = 0; | 471 | if (hole_len) { |
| 439 | if (num_clusters) { | ||
| 440 | ret = ocfs2_figure_hole_clusters(inode, el, eb_bh, | 472 | ret = ocfs2_figure_hole_clusters(inode, el, eb_bh, |
| 441 | v_cluster, | 473 | v_cluster, &len); |
| 442 | num_clusters); | ||
| 443 | if (ret) { | 474 | if (ret) { |
| 444 | mlog_errno(ret); | 475 | mlog_errno(ret); |
| 445 | goto out; | 476 | goto out; |
| 446 | } | 477 | } |
| 478 | |||
| 479 | *hole_len = len; | ||
| 447 | } | 480 | } |
| 448 | } else { | 481 | goto out_hole; |
| 449 | rec = &el->l_recs[i]; | 482 | |
