diff options
author | Bob Peterson <rpeterso@redhat.com> | 2012-07-19 08:12:40 -0400 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2012-07-19 09:51:08 -0400 |
commit | 8e2e00473598dd5379d8408cb974dade000acafc (patch) | |
tree | 1f7bfdf0d07b6c0315bbd11ffee174742d66a459 /fs/gfs2/inode.c | |
parent | 294f2ad5a545eb71d397623743ddd8201131bdad (diff) |
GFS2: Reduce file fragmentation
This patch reduces GFS2 file fragmentation by pre-reserving blocks. The
resulting improved on disk layout greatly speeds up operations in cases
which would have resulted in interlaced allocation of blocks previously.
A typical example of this is 10 parallel dd processes, each writing to a
file in a common dirctory.
The implementation uses an rbtree of reservations attached to each
resource group (and each inode).
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2/inode.c')
-rw-r--r-- | fs/gfs2/inode.c | 37 |
1 files changed, 28 insertions, 9 deletions
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 2b035e0959b2..c53c67e30bd4 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c | |||
@@ -521,6 +521,9 @@ static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl, | |||
521 | int error; | 521 | int error; |
522 | 522 | ||
523 | munge_mode_uid_gid(dip, &mode, &uid, &gid); | 523 | munge_mode_uid_gid(dip, &mode, &uid, &gid); |
524 | error = gfs2_rindex_update(sdp); | ||
525 | if (error) | ||
526 | return error; | ||
524 | 527 | ||
525 | error = gfs2_quota_lock(dip, uid, gid); | 528 | error = gfs2_quota_lock(dip, uid, gid); |
526 | if (error) | 529 | if (error) |
@@ -551,6 +554,10 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name, | |||
551 | struct buffer_head *dibh; | 554 | struct buffer_head *dibh; |
552 | int error; | 555 | int error; |
553 | 556 | ||
557 | error = gfs2_rindex_update(sdp); | ||
558 | if (error) | ||
559 | return error; | ||
560 | |||
554 | error = gfs2_quota_lock(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); | 561 | error = gfs2_quota_lock(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); |
555 | if (error) | 562 | if (error) |
556 | goto fail; | 563 | goto fail; |
@@ -596,7 +603,8 @@ fail_end_trans: | |||
596 | gfs2_trans_end(sdp); | 603 | gfs2_trans_end(sdp); |
597 | 604 | ||
598 | fail_ipreserv: | 605 | fail_ipreserv: |
599 | gfs2_inplace_release(dip); | 606 | if (alloc_required) |
607 | gfs2_inplace_release(dip); | ||
600 | 608 | ||
601 | fail_quota_locks: | 609 | fail_quota_locks: |
602 | gfs2_quota_unlock(dip); | 610 | gfs2_quota_unlock(dip); |
@@ -647,7 +655,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, | |||
647 | const struct qstr *name = &dentry->d_name; | 655 | const struct qstr *name = &dentry->d_name; |
648 | struct gfs2_holder ghs[2]; | 656 | struct gfs2_holder ghs[2]; |
649 | struct inode *inode = NULL; | 657 | struct inode *inode = NULL; |
650 | struct gfs2_inode *dip = GFS2_I(dir); | 658 | struct gfs2_inode *dip = GFS2_I(dir), *ip; |
651 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); | 659 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); |
652 | struct gfs2_inum_host inum = { .no_addr = 0, .no_formal_ino = 0 }; | 660 | struct gfs2_inum_host inum = { .no_addr = 0, .no_formal_ino = 0 }; |
653 | int error; | 661 | int error; |
@@ -657,6 +665,11 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, | |||
657 | if (!name->len || name->len > GFS2_FNAMESIZE) | 665 | if (!name->len || name->len > GFS2_FNAMESIZE) |
658 | return -ENAMETOOLONG; | 666 | return -ENAMETOOLONG; |
659 | 667 | ||
668 | /* We need a reservation to allocate the new dinode block. The | ||
669 | directory ip temporarily points to the reservation, but this is | ||
670 | being done to get a set of contiguous blocks for the new dinode. | ||
671 | Since this is a create, we don't have a sizehint yet, so it will | ||
672 | have to use the minimum reservation size. */ | ||
660 | error = gfs2_rs_alloc(dip); | 673 | error = gfs2_rs_alloc(dip); |
661 | if (error) | 674 | if (error) |
662 | return error; | 675 | return error; |
@@ -694,24 +707,29 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, | |||
694 | if (IS_ERR(inode)) | 707 | if (IS_ERR(inode)) |
695 | goto fail_gunlock2; | 708 | goto fail_gunlock2; |
696 | 709 | ||
697 | error = gfs2_inode_refresh(GFS2_I(inode)); | 710 | ip = GFS2_I(inode); |
711 | error = gfs2_inode_refresh(ip); | ||
698 | if (error) | 712 | if (error) |
699 | goto fail_gunlock2; | 713 | goto fail_gunlock2; |
700 | 714 | ||
701 | /* the new inode needs a reservation so it can allocate xattrs. */ | 715 | /* The newly created inode needs a reservation so it can allocate |
702 | error = gfs2_rs_alloc(GFS2_I(inode)); | 716 | xattrs. At the same time, we want new blocks allocated to the new |
703 | if (error) | 717 | dinode to be as contiguous as possible. Since we allocated the |
704 | goto fail_gunlock2; | 718 | dinode block under the directory's reservation, we transfer |
719 | ownership of that reservation to the new inode. The directory | ||
720 | doesn't need a reservation unless it needs a new allocation. */ | ||
721 | ip->i_res = dip->i_res; | ||
722 | dip->i_res = NULL; | ||
705 | 723 | ||
706 | error = gfs2_acl_create(dip, inode); | 724 | error = gfs2_acl_create(dip, inode); |
707 | if (error) | 725 | if (error) |
708 | goto fail_gunlock2; | 726 | goto fail_gunlock2; |
709 | 727 | ||
710 | error = gfs2_security_init(dip, GFS2_I(inode), name); | 728 | error = gfs2_security_init(dip, ip, name); |
711 | if (error) | 729 | if (error) |
712 | goto fail_gunlock2; | 730 | goto fail_gunlock2; |
713 | 731 | ||
714 | error = link_dinode(dip, name, GFS2_I(inode)); | 732 | error = link_dinode(dip, name, ip); |
715 | if (error) | 733 | if (error) |
716 | goto fail_gunlock2; | 734 | goto fail_gunlock2; |
717 | 735 | ||
@@ -738,6 +756,7 @@ fail_gunlock: | |||
738 | iput(inode); | 756 | iput(inode); |
739 | } | 757 | } |
740 | fail: | 758 | fail: |
759 | gfs2_rs_delete(dip); | ||
741 | if (bh) | 760 | if (bh) |
742 | brelse(bh); | 761 | brelse(bh); |
743 | return error; | 762 | return error; |