aboutsummaryrefslogtreecommitdiffstats
path: root/fs/logfs/readwrite.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/logfs/readwrite.c')
-rw-r--r--fs/logfs/readwrite.c34
1 files changed, 26 insertions, 8 deletions
diff --git a/fs/logfs/readwrite.c b/fs/logfs/readwrite.c
index aca6c56a107a..7e3a1e5fd76d 100644
--- a/fs/logfs/readwrite.c
+++ b/fs/logfs/readwrite.c
@@ -1837,19 +1837,37 @@ static int __logfs_truncate(struct inode *inode, u64 size)
1837 return logfs_truncate_direct(inode, size); 1837 return logfs_truncate_direct(inode, size);
1838} 1838}
1839 1839
1840int logfs_truncate(struct inode *inode, u64 size) 1840/*
1841 * Truncate, by changing the segment file, can consume a fair amount
1842 * of resources. So back off from time to time and do some GC.
1843 * 8 or 2048 blocks should be well within safety limits even if
1844 * every single block resided in a different segment.
1845 */
1846#define TRUNCATE_STEP (8 * 1024 * 1024)
1847int logfs_truncate(struct inode *inode, u64 target)
1841{ 1848{
1842 struct super_block *sb = inode->i_sb; 1849 struct super_block *sb = inode->i_sb;
1843 int err; 1850 u64 size = i_size_read(inode);
1851 int err = 0;
1844 1852
1845 logfs_get_wblocks(sb, NULL, 1); 1853 size = ALIGN(size, TRUNCATE_STEP);
1846 err = __logfs_truncate(inode, size); 1854 while (size > target) {
1847 if (!err) 1855 if (size > TRUNCATE_STEP)
1848 err = __logfs_write_inode(inode, 0); 1856 size -= TRUNCATE_STEP;
1849 logfs_put_wblocks(sb, NULL, 1); 1857 else
1858 size = 0;
1859 if (size < target)
1860 size = target;
1861
1862 logfs_get_wblocks(sb, NULL, 1);
1863 err = __logfs_truncate(inode, target);
1864 if (!err)
1865 err = __logfs_write_inode(inode, 0);
1866 logfs_put_wblocks(sb, NULL, 1);
1867 }
1850 1868
1851 if (!err) 1869 if (!err)
1852 err = vmtruncate(inode, size); 1870 err = vmtruncate(inode, target);
1853 1871
1854 /* I don't trust error recovery yet. */ 1872 /* I don't trust error recovery yet. */
1855 WARN_ON(err); 1873 WARN_ON(err);