|
@@ -757,13 +757,17 @@ static int gfs2_write_inode(struct inode *inode, struct writeback_control *wbc)
|
|
|
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;
|
|
|
- ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
|
|
|
- if (ret)
|
|
|
- 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_trans_begin(sdp, RES_DINODE, 0);
|
|
|
if (ret)
|
|
|
goto do_unlock;
|
|
@@ -780,7 +784,8 @@ static int gfs2_write_inode(struct inode *inode, struct writeback_control *wbc)
|
|
|
}
|
|
|
gfs2_trans_end(sdp);
|
|
|
do_unlock:
|
|
|
- gfs2_glock_dq_uninit(&gh);
|
|
|
+ if (unlock_required)
|
|
|
+ gfs2_glock_dq_uninit(&gh);
|
|
|
do_flush:
|
|
|
if (wbc->sync_mode == WB_SYNC_ALL)
|
|
|
gfs2_log_flush(GFS2_SB(inode), ip->i_gl);
|
|
@@ -1427,7 +1432,20 @@ out:
|
|
|
return error;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
+/**
|
|
|
+ * gfs2_evict_inode - Remove an inode from cache
|
|
|
+ * @inode: The inode to evict
|
|
|
+ *
|
|
|
+ * There are three cases to consider:
|
|
|
+ * 1. i_nlink == 0, we are final opener (and must deallocate)
|
|
|
+ * 2. i_nlink == 0, we are not the final opener (and cannot deallocate)
|
|
|
+ * 3. i_nlink > 0
|
|
|
+ *
|
|
|
+ * If the fs is read only, then we have to treat all cases as per #3
|
|
|
+ * since we are unable to do any deallocation. The inode will be
|
|
|
+ * deallocated by the next read/write node to attempt an allocation
|
|
|
+ * in the same resource group
|
|
|
+ *
|
|
|
* We have to (at the moment) hold the inodes main lock to cover
|
|
|
* the gap between unlocking the shared lock on the iopen lock and
|
|
|
* taking the exclusive lock. I'd rather do a shared -> exclusive
|
|
@@ -1470,6 +1488,8 @@ static void gfs2_evict_inode(struct inode *inode)
|
|
|
if (error)
|
|
|
goto out_truncate;
|
|
|
|
|
|
+ /* Case 1 starts here */
|
|
|
+
|
|
|
if (S_ISDIR(inode->i_mode) &&
|
|
|
(ip->i_diskflags & GFS2_DIF_EXHASH)) {
|
|
|
error = gfs2_dir_exhash_dealloc(ip);
|
|
@@ -1493,13 +1513,16 @@ static void gfs2_evict_inode(struct inode *inode)
|
|
|
goto out_unlock;
|
|
|
|
|
|
out_truncate:
|
|
|
+ /* Case 2 starts here */
|
|
|
error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks);
|
|
|
if (error)
|
|
|
goto out_unlock;
|
|
|
- gfs2_final_release_pages(ip);
|
|
|
+ /* Needs to be done before glock release & also in a transaction */
|
|
|
+ truncate_inode_pages(&inode->i_data, 0);
|
|
|
gfs2_trans_end(sdp);
|
|
|
|
|
|
out_unlock:
|
|
|
+ /* Error path for case 1 */
|
|
|
if (test_bit(HIF_HOLDER, &ip->i_iopen_gh.gh_iflags))
|
|
|
gfs2_glock_dq(&ip->i_iopen_gh);
|
|
|
gfs2_holder_uninit(&ip->i_iopen_gh);
|
|
@@ -1507,6 +1530,7 @@ out_unlock:
|
|
|
if (error && error != GLR_TRYFAILED && error != -EROFS)
|
|
|
fs_warn(sdp, "gfs2_evict_inode: %d\n", error);
|
|
|
out:
|
|
|
+ /* Case 3 starts here */
|
|
|
truncate_inode_pages(&inode->i_data, 0);
|
|
|
end_writeback(inode);
|
|
|
|