aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2/super.c
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2011-08-15 09:20:36 -0400
committerSteven Whitehouse <swhiteho@redhat.com>2011-10-21 07:39:26 -0400
commitab9bbda0204dfd0e5342562d9979d1241b14ea5f (patch)
tree621e623d99fbef1432da17b6390c92d7f13224a4 /fs/gfs2/super.c
parentf18185291d605ea9e442e00e2cf6c917a84d9837 (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.c97
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);
788do_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
783static 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);
823out:
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,