|
@@ -752,53 +752,79 @@ static int gfs2_write_inode(struct inode *inode, struct writeback_control *wbc)
|
|
struct gfs2_sbd *sdp = GFS2_SB(inode);
|
|
struct gfs2_sbd *sdp = GFS2_SB(inode);
|
|
struct address_space *metamapping = gfs2_glock2aspace(ip->i_gl);
|
|
struct address_space *metamapping = gfs2_glock2aspace(ip->i_gl);
|
|
struct backing_dev_info *bdi = metamapping->backing_dev_info;
|
|
struct backing_dev_info *bdi = metamapping->backing_dev_info;
|
|
- struct gfs2_holder gh;
|
|
|
|
- struct buffer_head *bh;
|
|
|
|
- struct timespec atime;
|
|
|
|
- struct gfs2_dinode *di;
|
|
|
|
- int ret = -EAGAIN;
|
|
|
|
- int unlock_required = 0;
|
|
|
|
-
|
|
|
|
- /* Skip timestamp update, if this is from a memalloc */
|
|
|
|
- if (current->flags & PF_MEMALLOC)
|
|
|
|
- goto do_flush;
|
|
|
|
- if (!gfs2_glock_is_locked_by_me(ip->i_gl)) {
|
|
|
|
- ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
|
|
|
|
- if (ret)
|
|
|
|
- goto do_flush;
|
|
|
|
- unlock_required = 1;
|
|
|
|
- }
|
|
|
|
- ret = gfs2_meta_inode_buffer(ip, &bh);
|
|
|
|
- if (ret == 0) {
|
|
|
|
- di = (struct gfs2_dinode *)bh->b_data;
|
|
|
|
- atime.tv_sec = be64_to_cpu(di->di_atime);
|
|
|
|
- atime.tv_nsec = be32_to_cpu(di->di_atime_nsec);
|
|
|
|
- if (timespec_compare(&inode->i_atime, &atime) > 0) {
|
|
|
|
- ret = gfs2_trans_begin(sdp, RES_DINODE, 0);
|
|
|
|
- if (ret == 0) {
|
|
|
|
- gfs2_trans_add_bh(ip->i_gl, bh, 1);
|
|
|
|
- gfs2_dinode_out(ip, bh->b_data);
|
|
|
|
- gfs2_trans_end(sdp);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- brelse(bh);
|
|
|
|
- }
|
|
|
|
- if (unlock_required)
|
|
|
|
- gfs2_glock_dq_uninit(&gh);
|
|
|
|
-do_flush:
|
|
|
|
|
|
+ int ret = 0;
|
|
|
|
+
|
|
if (wbc->sync_mode == WB_SYNC_ALL)
|
|
if (wbc->sync_mode == WB_SYNC_ALL)
|
|
gfs2_log_flush(GFS2_SB(inode), ip->i_gl);
|
|
gfs2_log_flush(GFS2_SB(inode), ip->i_gl);
|
|
if (bdi->dirty_exceeded)
|
|
if (bdi->dirty_exceeded)
|
|
gfs2_ail1_flush(sdp, wbc);
|
|
gfs2_ail1_flush(sdp, wbc);
|
|
else
|
|
else
|
|
filemap_fdatawrite(metamapping);
|
|
filemap_fdatawrite(metamapping);
|
|
- if (!ret && (wbc->sync_mode == WB_SYNC_ALL))
|
|
|
|
|
|
+ if (wbc->sync_mode == WB_SYNC_ALL)
|
|
ret = filemap_fdatawait(metamapping);
|
|
ret = filemap_fdatawait(metamapping);
|
|
if (ret)
|
|
if (ret)
|
|
mark_inode_dirty_sync(inode);
|
|
mark_inode_dirty_sync(inode);
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * gfs2_dirty_inode - check for atime updates
|
|
|
|
+ * @inode: The inode in question
|
|
|
|
+ * @flags: The type of dirty
|
|
|
|
+ *
|
|
|
|
+ * Unfortunately it can be called under any combination of inode
|
|
|
|
+ * glock and transaction lock, so we have to check carefully.
|
|
|
|
+ *
|
|
|
|
+ * At the moment this deals only with atime - it should be possible
|
|
|
|
+ * to expand that role in future, once a review of the locking has
|
|
|
|
+ * been carried out.
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+static void gfs2_dirty_inode(struct inode *inode, int flags)
|
|
|
|
+{
|
|
|
|
+ struct gfs2_inode *ip = GFS2_I(inode);
|
|
|
|
+ struct gfs2_sbd *sdp = GFS2_SB(inode);
|
|
|
|
+ struct buffer_head *bh;
|
|
|
|
+ struct gfs2_holder gh;
|
|
|
|
+ int need_unlock = 0;
|
|
|
|
+ int need_endtrans = 0;
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ if (!(flags & (I_DIRTY_DATASYNC|I_DIRTY_SYNC)))
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ if (!gfs2_glock_is_locked_by_me(ip->i_gl)) {
|
|
|
|
+ ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
|
|
|
|
+ if (ret) {
|
|
|
|
+ fs_err(sdp, "dirty_inode: glock %d\n", ret);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ need_unlock = 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (current->journal_info == NULL) {
|
|
|
|
+ ret = gfs2_trans_begin(sdp, RES_DINODE, 0);
|
|
|
|
+ if (ret) {
|
|
|
|
+ fs_err(sdp, "dirty_inode: gfs2_trans_begin %d\n", ret);
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+ need_endtrans = 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ret = gfs2_meta_inode_buffer(ip, &bh);
|
|
|
|
+ if (ret == 0) {
|
|
|
|
+ gfs2_trans_add_bh(ip->i_gl, bh, 1);
|
|
|
|
+ gfs2_dinode_out(ip, bh->b_data);
|
|
|
|
+ brelse(bh);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (need_endtrans)
|
|
|
|
+ gfs2_trans_end(sdp);
|
|
|
|
+out:
|
|
|
|
+ if (need_unlock)
|
|
|
|
+ gfs2_glock_dq_uninit(&gh);
|
|
|
|
+}
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* gfs2_make_fs_ro - Turn a Read-Write FS into a Read-Only one
|
|
* gfs2_make_fs_ro - Turn a Read-Write FS into a Read-Only one
|
|
* @sdp: the filesystem
|
|
* @sdp: the filesystem
|
|
@@ -1578,6 +1604,7 @@ const struct super_operations gfs2_super_ops = {
|
|
.alloc_inode = gfs2_alloc_inode,
|
|
.alloc_inode = gfs2_alloc_inode,
|
|
.destroy_inode = gfs2_destroy_inode,
|
|
.destroy_inode = gfs2_destroy_inode,
|
|
.write_inode = gfs2_write_inode,
|
|
.write_inode = gfs2_write_inode,
|
|
|
|
+ .dirty_inode = gfs2_dirty_inode,
|
|
.evict_inode = gfs2_evict_inode,
|
|
.evict_inode = gfs2_evict_inode,
|
|
.put_super = gfs2_put_super,
|
|
.put_super = gfs2_put_super,
|
|
.sync_fs = gfs2_sync_fs,
|
|
.sync_fs = gfs2_sync_fs,
|