diff options
Diffstat (limited to 'fs/ocfs2/file.c')
-rw-r--r-- | fs/ocfs2/file.c | 104 |
1 files changed, 77 insertions, 27 deletions
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index edc0b617f409..3bcf3629265e 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c | |||
@@ -480,13 +480,86 @@ leave: | |||
480 | return status; | 480 | return status; |
481 | } | 481 | } |
482 | 482 | ||
483 | /* | ||
484 | * For a given allocation, determine which allocators will need to be | ||
485 | * accessed, and lock them, reserving the appropriate number of bits. | ||
486 | * | ||
487 | * Called from ocfs2_extend_allocation() for file systems which don't | ||
488 | * support holes, and from ocfs2_prepare_write() for file systems | ||
489 | * which understand sparse inodes. | ||
490 | */ | ||
491 | static int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_dinode *di, | ||
492 | u32 clusters_to_add, | ||
493 | struct ocfs2_alloc_context **data_ac, | ||
494 | struct ocfs2_alloc_context **meta_ac) | ||
495 | { | ||
496 | int ret, num_free_extents; | ||
497 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
498 | |||
499 | *meta_ac = NULL; | ||
500 | *data_ac = NULL; | ||
501 | |||
502 | mlog(0, "extend inode %llu, i_size = %lld, di->i_clusters = %u, " | ||
503 | "clusters_to_add = %u\n", | ||
504 | (unsigned long long)OCFS2_I(inode)->ip_blkno, i_size_read(inode), | ||
505 | le32_to_cpu(di->i_clusters), clusters_to_add); | ||
506 | |||
507 | num_free_extents = ocfs2_num_free_extents(osb, inode, di); | ||
508 | if (num_free_extents < 0) { | ||
509 | ret = num_free_extents; | ||
510 | mlog_errno(ret); | ||
511 | goto out; | ||
512 | } | ||
513 | |||
514 | /* | ||
515 | * Sparse allocation file systems need to be more conservative | ||
516 | * with reserving room for expansion - the actual allocation | ||
517 | * happens while we've got a journal handle open so re-taking | ||
518 | * a cluster lock (because we ran out of room for another | ||
519 | * extent) will violate ordering rules. | ||
520 | * | ||
521 | * Most of the time we'll only be seeing this 1 page at a time | ||
522 | * anyway. | ||
523 | */ | ||
524 | if (!num_free_extents || | ||
525 | (ocfs2_sparse_alloc(osb) && num_free_extents < clusters_to_add)) { | ||
526 | ret = ocfs2_reserve_new_metadata(osb, di, meta_ac); | ||
527 | if (ret < 0) { | ||
528 | if (ret != -ENOSPC) | ||
529 | mlog_errno(ret); | ||
530 | goto out; | ||
531 | } | ||
532 | } | ||
533 | |||
534 | ret = ocfs2_reserve_clusters(osb, clusters_to_add, data_ac); | ||
535 | if (ret < 0) { | ||
536 | if (ret != -ENOSPC) | ||
537 | mlog_errno(ret); | ||
538 | goto out; | ||
539 | } | ||
540 | |||
541 | out: | ||
542 | if (ret) { | ||
543 | if (*meta_ac) { | ||
544 | ocfs2_free_alloc_context(*meta_ac); | ||
545 | *meta_ac = NULL; | ||
546 | } | ||
547 | |||
548 | /* | ||
549 | * We cannot have an error and a non null *data_ac. | ||
550 | */ | ||
551 | } | ||
552 | |||
553 | return ret; | ||
554 | } | ||
555 | |||
483 | static int ocfs2_extend_allocation(struct inode *inode, | 556 | static int ocfs2_extend_allocation(struct inode *inode, |
484 | u32 clusters_to_add) | 557 | u32 clusters_to_add) |
485 | { | 558 | { |
486 | int status = 0; | 559 | int status = 0; |
487 | int restart_func = 0; | 560 | int restart_func = 0; |
488 | int drop_alloc_sem = 0; | 561 | int drop_alloc_sem = 0; |
489 | int credits, num_free_extents; | 562 | int credits; |
490 | u32 prev_clusters, logical_start; | 563 | u32 prev_clusters, logical_start; |
491 | struct buffer_head *bh = NULL; | 564 | struct buffer_head *bh = NULL; |
492 | struct ocfs2_dinode *fe = NULL; | 565 | struct ocfs2_dinode *fe = NULL; |
@@ -523,36 +596,13 @@ static int ocfs2_extend_allocation(struct inode *inode, | |||
523 | restart_all: | 596 | restart_all: |
524 | BUG_ON(le32_to_cpu(fe->i_clusters) != OCFS2_I(inode)->ip_clusters); | 597 | BUG_ON(le32_to_cpu(fe->i_clusters) != OCFS2_I(inode)->ip_clusters); |
525 | 598 | ||
526 | mlog(0, "extend inode %llu, i_size = %lld, fe->i_clusters = %u, " | 599 | status = ocfs2_lock_allocators(inode, fe, clusters_to_add, &data_ac, |
527 | "clusters_to_add = %u\n", | 600 | &meta_ac); |
528 | (unsigned long long)OCFS2_I(inode)->ip_blkno, i_size_read(inode), | 601 | if (status) { |
529 | fe->i_clusters, clusters_to_add); | ||
530 | |||
531 | num_free_extents = ocfs2_num_free_extents(osb, | ||
532 | inode, | ||
533 | fe); | ||
534 | if (num_free_extents < 0) { | ||
535 | status = num_free_extents; | ||
536 | mlog_errno(status); | 602 | mlog_errno(status); |
537 | goto leave; | 603 | goto leave; |
538 | } | 604 | } |
539 | 605 | ||
540 | if (!num_free_extents) { | ||
541 | status = ocfs2_reserve_new_metadata(osb, fe, &meta_ac); | ||
542 | if (status < 0) { | ||
543 | if (status != -ENOSPC) | ||
544 | mlog_errno(status); | ||
545 | goto leave; | ||
546 | } | ||
547 | } | ||
548 | |||
549 | status = ocfs2_reserve_clusters(osb, clusters_to_add, &data_ac); | ||
550 | if (status < 0) { | ||
551 | if (status != -ENOSPC) | ||
552 | mlog_errno(status); | ||
553 | goto leave; | ||
554 | } | ||
555 | |||
556 | /* blocks peope in read/write from reading our allocation | 606 | /* blocks peope in read/write from reading our allocation |
557 | * until we're done changing it. We depend on i_mutex to block | 607 | * until we're done changing it. We depend on i_mutex to block |
558 | * other extend/truncate calls while we're here. Ordering wrt | 608 | * other extend/truncate calls while we're here. Ordering wrt |