aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ocfs2
diff options
context:
space:
mode:
authorTao Ma <tao.ma@oracle.com>2010-11-04 03:14:11 -0400
committerJoel Becker <joel.becker@oracle.com>2010-12-16 03:46:02 -0500
commit50308d813bf26500fed671882469939fd19403a3 (patch)
tree4fab5caccf450f3528c1e88c7a0299680578c1ec /fs/ocfs2
parentb0c3844d8af6b9f3f18f31e1b0502fbefa2166be (diff)
ocfs2: Try to free truncate log when meeting ENOSPC in write.
Recently, one of our colleagues meet with a problem that if we write/delete a 32mb files repeatly, we will get an ENOSPC in the end. And the corresponding bug is 1288. http://oss.oracle.com/bugzilla/show_bug.cgi?id=1288 The real problem is that although we have freed the clusters, they are in truncate log and they will be summed up so that we can free them once in a whole. So this patch just try to resolve it. In case we see -ENOSPC in ocfs2_write_begin_no_lock, we will check whether the truncate log has enough clusters for our need, if yes, we will try to flush the truncate log at that point and try again. This method is inspired by Mark Fasheh <mfasheh@suse.com>. Thanks. Cc: Mark Fasheh <mfasheh@suse.com> Signed-off-by: Tao Ma <tao.ma@oracle.com> Signed-off-by: Joel Becker <joel.becker@oracle.com>
Diffstat (limited to 'fs/ocfs2')
-rw-r--r--fs/ocfs2/alloc.c3
-rw-r--r--fs/ocfs2/aops.c59
-rw-r--r--fs/ocfs2/ocfs2.h5
3 files changed, 66 insertions, 1 deletions
diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c
index 592fae5007d1..8ec418dd9e36 100644
--- a/fs/ocfs2/alloc.c
+++ b/fs/ocfs2/alloc.c
@@ -5858,6 +5858,7 @@ int ocfs2_truncate_log_append(struct ocfs2_super *osb,
5858 5858
5859 ocfs2_journal_dirty(handle, tl_bh); 5859 ocfs2_journal_dirty(handle, tl_bh);
5860 5860
5861 osb->truncated_clusters += num_clusters;
5861bail: 5862bail:
5862 mlog_exit(status); 5863 mlog_exit(status);
5863 return status; 5864 return status;
@@ -5929,6 +5930,8 @@ static int ocfs2_replay_truncate_records(struct ocfs2_super *osb,
5929 i--; 5930 i--;
5930 } 5931 }
5931 5932
5933 osb->truncated_clusters = 0;
5934
5932bail: 5935bail:
5933 mlog_exit(status); 5936 mlog_exit(status);
5934 return status; 5937 return status;
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
index f1e962cb3b73..d55a10e2f300 100644
--- a/fs/ocfs2/aops.c
+++ b/fs/ocfs2/aops.c
@@ -1627,6 +1627,43 @@ static int ocfs2_zero_tail(struct inode *inode, struct buffer_head *di_bh,
1627 return ret; 1627 return ret;
1628} 1628}
1629 1629
1630/*
1631 * Try to flush truncate logs if we can free enough clusters from it.
1632 * As for return value, "< 0" means error, "0" no space and "1" means
1633 * we have freed enough spaces and let the caller try to allocate again.
1634 */
1635static int ocfs2_try_to_free_truncate_log(struct ocfs2_super *osb,
1636 unsigned int needed)
1637{
1638 tid_t target;
1639 int ret = 0;
1640 unsigned int truncated_clusters;
1641
1642 mutex_lock(&osb->osb_tl_inode->i_mutex);
1643 truncated_clusters = osb->truncated_clusters;
1644 mutex_unlock(&osb->osb_tl_inode->i_mutex);
1645
1646 /*
1647 * Check whether we can succeed in allocating if we free
1648 * the truncate log.
1649 */
1650 if (truncated_clusters < needed)
1651 goto out;
1652
1653 ret = ocfs2_flush_truncate_log(osb);
1654 if (ret) {
1655 mlog_errno(ret);
1656 goto out;
1657 }
1658
1659 if (jbd2_journal_start_commit(osb->journal->j_journal, &target)) {
1660 jbd2_log_wait_commit(osb->journal->j_journal, target);
1661 ret = 1;
1662 }
1663out:
1664 return ret;
1665}
1666
1630int ocfs2_write_begin_nolock(struct file *filp, 1667int ocfs2_write_begin_nolock(struct file *filp,
1631 struct address_space *mapping, 1668 struct address_space *mapping,
1632 loff_t pos, unsigned len, unsigned flags, 1669 loff_t pos, unsigned len, unsigned flags,
@@ -1634,7 +1671,7 @@ int ocfs2_write_begin_nolock(struct file *filp,
1634 struct buffer_head *di_bh, struct page *mmap_page) 1671 struct buffer_head *di_bh, struct page *mmap_page)
1635{ 1672{
1636 int ret, cluster_of_pages, credits = OCFS2_INODE_UPDATE_CREDITS; 1673 int ret, cluster_of_pages, credits = OCFS2_INODE_UPDATE_CREDITS;
1637 unsigned int clusters_to_alloc, extents_to_split; 1674 unsigned int clusters_to_alloc, extents_to_split, clusters_need = 0;
1638 struct ocfs2_write_ctxt *wc; 1675 struct ocfs2_write_ctxt *wc;
1639 struct inode *inode = mapping->host; 1676 struct inode *inode = mapping->host;
1640 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 1677 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
@@ -1643,7 +1680,9 @@ int ocfs2_write_begin_nolock(struct file *filp,
1643 struct ocfs2_alloc_context *meta_ac = NULL; 1680 struct ocfs2_alloc_context *meta_ac = NULL;
1644 handle_t *handle; 1681 handle_t *handle;
1645 struct ocfs2_extent_tree et; 1682 struct ocfs2_extent_tree et;
1683 int try_free = 1, ret1;
1646 1684
1685try_again:
1647 ret = ocfs2_alloc_write_ctxt(&wc, osb, pos, len, di_bh); 1686 ret = ocfs2_alloc_write_ctxt(&wc, osb, pos, len, di_bh);
1648 if (ret) { 1687 if (ret) {
1649 mlog_errno(ret); 1688 mlog_errno(ret);
@@ -1678,6 +1717,7 @@ int ocfs2_write_begin_nolock(struct file *filp,
1678 mlog_errno(ret); 1717 mlog_errno(ret);
1679 goto out; 1718 goto out;
1680 } else if (ret == 1) { 1719 } else if (ret == 1) {
1720 clusters_need = wc->w_clen;
1681 ret = ocfs2_refcount_cow(inode, filp, di_bh, 1721 ret = ocfs2_refcount_cow(inode, filp, di_bh,
1682 wc->w_cpos, wc->w_clen, UINT_MAX); 1722 wc->w_cpos, wc->w_clen, UINT_MAX);
1683 if (ret) { 1723 if (ret) {
@@ -1692,6 +1732,7 @@ int ocfs2_write_begin_nolock(struct file *filp,
1692 mlog_errno(ret); 1732 mlog_errno(ret);
1693 goto out; 1733 goto out;
1694 } 1734 }
1735 clusters_need += clusters_to_alloc;
1695 1736
1696 di = (struct ocfs2_dinode *)wc->w_di_bh->b_data; 1737 di = (struct ocfs2_dinode *)wc->w_di_bh->b_data;
1697 1738
@@ -1814,6 +1855,22 @@ out:
1814 ocfs2_free_alloc_context(data_ac); 1855 ocfs2_free_alloc_context(data_ac);
1815 if (meta_ac) 1856 if (meta_ac)
1816 ocfs2_free_alloc_context(meta_ac); 1857 ocfs2_free_alloc_context(meta_ac);
1858
1859 if (ret == -ENOSPC && try_free) {
1860 /*
1861 * Try to free some truncate log so that we can have enough
1862 * clusters to allocate.
1863 */
1864 try_free = 0;
1865
1866 ret1 = ocfs2_try_to_free_truncate_log(osb, clusters_need);
1867 if (ret1 == 1)
1868 goto try_again;
1869
1870 if (ret1 < 0)
1871 mlog_errno(ret1);
1872 }
1873
1817 return ret; 1874 return ret;
1818} 1875}
1819 1876
diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h
index 70dd3b1798f1..51cd6898e7f1 100644
--- a/fs/ocfs2/ocfs2.h
+++ b/fs/ocfs2/ocfs2.h
@@ -420,6 +420,11 @@ struct ocfs2_super
420 struct inode *osb_tl_inode; 420 struct inode *osb_tl_inode;
421 struct buffer_head *osb_tl_bh; 421 struct buffer_head *osb_tl_bh;
422 struct delayed_work osb_truncate_log_wq; 422 struct delayed_work osb_truncate_log_wq;
423 /*
424 * How many clusters in our truncate log.
425 * It must be protected by osb_tl_inode->i_mutex.
426 */
427 unsigned int truncated_clusters;
423 428
424 struct ocfs2_node_map osb_recovering_orphan_dirs; 429 struct ocfs2_node_map osb_recovering_orphan_dirs;
425 unsigned int *osb_orphan_wipes; 430 unsigned int *osb_orphan_wipes;