diff options
author | Steven Whitehouse <swhiteho@redhat.com> | 2011-08-15 09:20:36 -0400 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2011-10-21 07:39:26 -0400 |
commit | ab9bbda0204dfd0e5342562d9979d1241b14ea5f (patch) | |
tree | 621e623d99fbef1432da17b6390c92d7f13224a4 /fs/gfs2/super.c | |
parent | f18185291d605ea9e442e00e2cf6c917a84d9837 (diff) |
GFS2: Use ->dirty_inode()
The aim of this patch is to use the newly enhanced ->dirty_inode()
super block operation to deal with atime updates, rather than
piggy backing that code into ->write_inode() as is currently
done.
The net result is a simplification of the code in various places
and a reduction of the number of gfs2_dinode_out() calls since
this is now implied by ->dirty_inode().
Some of the mark_inode_dirty() calls have been moved under glocks
in order to take advantage of then being able to avoid locking in
->dirty_inode() when we already have suitable locks.
One consequence is that generic_write_end() now correctly deals
with file size updates, so that we do not need a separate check
for that afterwards. This also, indirectly, means that fdatasync
should work correctly on GFS2 - the current code always syncs the
metadata whether it needs to or not.
Has survived testing with postmark (with and without atime) and
also fsx.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2/super.c')
-rw-r--r-- | fs/gfs2/super.c | 97 |
1 files changed, 62 insertions, 35 deletions
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 9961de702d1b..b05fa5954550 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c | |||
@@ -752,47 +752,15 @@ static int gfs2_write_inode(struct inode *inode, struct writeback_control *wbc) | |||
752 | struct gfs2_sbd *sdp = GFS2_SB(inode); | 752 | struct gfs2_sbd *sdp = GFS2_SB(inode); |
753 | struct address_space *metamapping = gfs2_glock2aspace(ip->i_gl); | 753 | struct address_space *metamapping = gfs2_glock2aspace(ip->i_gl); |
754 | struct backing_dev_info *bdi = metamapping->backing_dev_info; | 754 | struct backing_dev_info *bdi = metamapping->backing_dev_info; |
755 | struct gfs2_holder gh; | 755 | int ret = 0; |
756 | struct buffer_head *bh; | 756 | |
757 | struct timespec atime; | ||
758 | struct gfs2_dinode *di; | ||
759 | int ret = -EAGAIN; | ||
760 | int unlock_required = 0; | ||
761 | |||
762 | /* Skip timestamp update, if this is from a memalloc */ | ||
763 | if (current->flags & PF_MEMALLOC) | ||
764 | goto do_flush; | ||
765 | if (!gfs2_glock_is_locked_by_me(ip->i_gl)) { | ||
766 | ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); | ||
767 | if (ret) | ||
768 | goto do_flush; | ||
769 | unlock_required = 1; | ||
770 | } | ||
771 | ret = gfs2_meta_inode_buffer(ip, &bh); | ||
772 | if (ret == 0) { | ||
773 | di = (struct gfs2_dinode *)bh->b_data; | ||
774 | atime.tv_sec = be64_to_cpu(di->di_atime); | ||
775 | atime.tv_nsec = be32_to_cpu(di->di_atime_nsec); | ||
776 | if (timespec_compare(&inode->i_atime, &atime) > 0) { | ||
777 | ret = gfs2_trans_begin(sdp, RES_DINODE, 0); | ||
778 | if (ret == 0) { | ||
779 | gfs2_trans_add_bh(ip->i_gl, bh, 1); | ||
780 | gfs2_dinode_out(ip, bh->b_data); | ||
781 | gfs2_trans_end(sdp); | ||
782 | } | ||
783 | } | ||
784 | brelse(bh); | ||
785 | } | ||
786 | if (unlock_required) | ||
787 | gfs2_glock_dq_uninit(&gh); | ||
788 | do_flush: | ||
789 | if (wbc->sync_mode == WB_SYNC_ALL) | 757 | if (wbc->sync_mode == WB_SYNC_ALL) |
790 | gfs2_log_flush(GFS2_SB(inode), ip->i_gl); | 758 | gfs2_log_flush(GFS2_SB(inode), ip->i_gl); |
791 | if (bdi->dirty_exceeded) | 759 | if (bdi->dirty_exceeded) |
792 | gfs2_ail1_flush(sdp, wbc); | 760 | gfs2_ail1_flush(sdp, wbc); |
793 | else | 761 | else |
794 | filemap_fdatawrite(metamapping); | 762 | filemap_fdatawrite(metamapping); |
795 | if (!ret && (wbc->sync_mode == WB_SYNC_ALL)) | 763 | if (wbc->sync_mode == WB_SYNC_ALL) |
796 | ret = filemap_fdatawait(metamapping); | 764 | ret = filemap_fdatawait(metamapping); |
797 | if (ret) | 765 | if (ret) |
798 | mark_inode_dirty_sync(inode); | 766 | mark_inode_dirty_sync(inode); |
@@ -800,6 +768,64 @@ do_flush: | |||
800 | } | 768 | } |
801 | 769 | ||
802 | /** | 770 | /** |
771 | * gfs2_dirty_inode - check for atime updates | ||
772 | * @inode: The inode in question | ||
773 | * @flags: The type of dirty | ||
774 | * | ||
775 | * Unfortunately it can be called under any combination of inode | ||
776 | * glock and transaction lock, so we have to check carefully. | ||
777 | * | ||
778 | * At the moment this deals only with atime - it should be possible | ||
779 | * to expand that role in future, once a review of the locking has | ||
780 | * been carried out. | ||
781 | */ | ||
782 | |||
783 | static void gfs2_dirty_inode(struct inode *inode, int flags) | ||
784 | { | ||
785 | struct gfs2_inode *ip = GFS2_I(inode); | ||
786 | struct gfs2_sbd *sdp = GFS2_SB(inode); | ||
787 | struct buffer_head *bh; | ||
788 | struct gfs2_holder gh; | ||
789 | int need_unlock = 0; | ||
790 | int need_endtrans = 0; | ||
791 | int ret; | ||
792 | |||
793 | if (!(flags & (I_DIRTY_DATASYNC|I_DIRTY_SYNC))) | ||
794 | return; | ||
795 | |||
796 | if (!gfs2_glock_is_locked_by_me(ip->i_gl)) { | ||
797 | ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); | ||
798 | if (ret) { | ||
799 | fs_err(sdp, "dirty_inode: glock %d\n", ret); | ||
800 | return; | ||
801 | } | ||
802 | need_unlock = 1; | ||
803 | } | ||
804 | |||
805 | if (current->journal_info == NULL) { | ||
806 | ret = gfs2_trans_begin(sdp, RES_DINODE, 0); | ||
807 | if (ret) { | ||
808 | fs_err(sdp, "dirty_inode: gfs2_trans_begin %d\n", ret); | ||
809 | goto out; | ||
810 | } | ||
811 | need_endtrans = 1; | ||
812 | } | ||
813 | |||
814 | ret = gfs2_meta_inode_buffer(ip, &bh); | ||
815 | if (ret == 0) { | ||
816 | gfs2_trans_add_bh(ip->i_gl, bh, 1); | ||
817 | gfs2_dinode_out(ip, bh->b_data); | ||
818 | brelse(bh); | ||
819 | } | ||
820 | |||
821 | if (need_endtrans) | ||
822 | gfs2_trans_end(sdp); | ||
823 | out: | ||
824 | if (need_unlock) | ||
825 | gfs2_glock_dq_uninit(&gh); | ||
826 | } | ||
827 | |||
828 | /** | ||
803 | * gfs2_make_fs_ro - Turn a Read-Write FS into a Read-Only one | 829 | * gfs2_make_fs_ro - Turn a Read-Write FS into a Read-Only one |
804 | * @sdp: the filesystem | 830 | * @sdp: the filesystem |
805 | * | 831 | * |
@@ -1578,6 +1604,7 @@ const struct super_operations gfs2_super_ops = { | |||
1578 | .alloc_inode = gfs2_alloc_inode, | 1604 | .alloc_inode = gfs2_alloc_inode, |
1579 | .destroy_inode = gfs2_destroy_inode, | 1605 | .destroy_inode = gfs2_destroy_inode, |
1580 | .write_inode = gfs2_write_inode, | 1606 | .write_inode = gfs2_write_inode, |
1607 | .dirty_inode = gfs2_dirty_inode, | ||
1581 | .evict_inode = gfs2_evict_inode, | 1608 | .evict_inode = gfs2_evict_inode, |
1582 | .put_super = gfs2_put_super, | 1609 | .put_super = gfs2_put_super, |
1583 | .sync_fs = gfs2_sync_fs, | 1610 | .sync_fs = gfs2_sync_fs, |