aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ocfs2/alloc.c
diff options
context:
space:
mode:
authorTao Ma <boyu.mt@taobao.com>2011-05-22 22:36:43 -0400
committerJoel Becker <jlbec@evilplan.org>2011-05-24 02:37:18 -0400
commite80de36d8dbff216a384e9204e54d59deeadf344 (patch)
treeff1bde3fa17785519863f3880fecbb6b6fcd148a /fs/ocfs2/alloc.c
parent69a60c4d177632bd56ae567dc0a082f7119b71c2 (diff)
ocfs2: Add ocfs2_trim_fs for SSD trim support.
Add ocfs2_trim_fs to support trimming freed clusters in the volume. A range will be given and all the freed clusters greater than minlen will be discarded to the block layer. Signed-off-by: Tao Ma <boyu.mt@taobao.com> Signed-off-by: Joel Becker <jlbec@evilplan.org>
Diffstat (limited to 'fs/ocfs2/alloc.c')
-rw-r--r--fs/ocfs2/alloc.c159
1 files changed, 159 insertions, 0 deletions
diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c
index 48aa9c7401c7..ae3ea783dad7 100644
--- a/fs/ocfs2/alloc.c
+++ b/fs/ocfs2/alloc.c
@@ -29,6 +29,7 @@
29#include <linux/highmem.h> 29#include <linux/highmem.h>
30#include <linux/swap.h> 30#include <linux/swap.h>
31#include <linux/quotaops.h> 31#include <linux/quotaops.h>
32#include <linux/blkdev.h>
32 33
33#include <cluster/masklog.h> 34#include <cluster/masklog.h>
34 35
@@ -7184,3 +7185,161 @@ out_commit:
7184out: 7185out:
7185 return ret; 7186 return ret;
7186} 7187}
7188
7189static int ocfs2_trim_extent(struct super_block *sb,
7190 struct ocfs2_group_desc *gd,
7191 u32 start, u32 count)
7192{
7193 u64 discard, bcount;
7194
7195 bcount = ocfs2_clusters_to_blocks(sb, count);
7196 discard = le64_to_cpu(gd->bg_blkno) +
7197 ocfs2_clusters_to_blocks(sb, start);
7198
7199 return sb_issue_discard(sb, discard, bcount, GFP_NOFS, 0);
7200}
7201
7202static int ocfs2_trim_group(struct super_block *sb,
7203 struct ocfs2_group_desc *gd,
7204 u32 start, u32 max, u32 minbits)
7205{
7206 int ret = 0, count = 0, next;
7207 void *bitmap = gd->bg_bitmap;
7208
7209 if (le16_to_cpu(gd->bg_free_bits_count) < minbits)
7210 return 0;
7211
7212 while (start < max) {
7213 start = ocfs2_find_next_zero_bit(bitmap, max, start);
7214 if (start >= max)
7215 break;
7216 next = ocfs2_find_next_bit(bitmap, max, start);
7217
7218 if ((next - start) >= minbits) {
7219 ret = ocfs2_trim_extent(sb, gd,
7220 start, next - start);
7221 if (ret < 0) {
7222 mlog_errno(ret);
7223 break;
7224 }
7225 count += next - start;
7226 }
7227 start = next + 1;
7228
7229 if (fatal_signal_pending(current)) {
7230 count = -ERESTARTSYS;
7231 break;
7232 }
7233
7234 if ((le16_to_cpu(gd->bg_free_bits_count) - count) < minbits)
7235 break;
7236 }
7237
7238 if (ret < 0)
7239 count = ret;
7240
7241 return count;
7242}
7243
7244int ocfs2_trim_fs(struct super_block *sb, struct fstrim_range *range)
7245{
7246 struct ocfs2_super *osb = OCFS2_SB(sb);
7247 u64 start, len, trimmed, first_group, last_group, group;
7248 int ret, cnt;
7249 u32 first_bit, last_bit, minlen;
7250 struct buffer_head *main_bm_bh = NULL;
7251 struct inode *main_bm_inode = NULL;
7252 struct buffer_head *gd_bh = NULL;
7253 struct ocfs2_dinode *main_bm;
7254 struct ocfs2_group_desc *gd = NULL;
7255
7256 start = range->start >> osb->s_clustersize_bits;
7257 len = range->len >> osb->s_clustersize_bits;
7258 minlen = range->minlen >> osb->s_clustersize_bits;
7259 trimmed = 0;
7260
7261 if (!len) {
7262 range->len = 0;
7263 return 0;
7264 }
7265
7266 if (minlen >= osb->bitmap_cpg)
7267 return -EINVAL;
7268
7269 main_bm_inode = ocfs2_get_system_file_inode(osb,
7270 GLOBAL_BITMAP_SYSTEM_INODE,
7271 OCFS2_INVALID_SLOT);
7272 if (!main_bm_inode) {
7273 ret = -EIO;
7274 mlog_errno(ret);
7275 goto out;
7276 }
7277
7278 mutex_lock(&main_bm_inode->i_mutex);
7279
7280 ret = ocfs2_inode_lock(main_bm_inode, &main_bm_bh, 0);
7281 if (ret < 0) {
7282 mlog_errno(ret);
7283 goto out_mutex;
7284 }
7285 main_bm = (struct ocfs2_dinode *)main_bm_bh->b_data;
7286
7287 if (start >= le32_to_cpu(main_bm->i_clusters)) {
7288 ret = -EINVAL;
7289 goto out_unlock;
7290 }
7291
7292 if (start + len > le32_to_cpu(main_bm->i_clusters))
7293 len = le32_to_cpu(main_bm->i_clusters) - start;
7294
7295 /* Determine first and last group to examine based on start and len */
7296 first_group = ocfs2_which_cluster_group(main_bm_inode, start);
7297 if (first_group == osb->first_cluster_group_blkno)
7298 first_bit = start;
7299 else
7300 first_bit = start - ocfs2_blocks_to_clusters(sb, first_group);
7301 last_group = ocfs2_which_cluster_group(main_bm_inode, start + len - 1);
7302 last_bit = osb->bitmap_cpg;
7303
7304 for (group = first_group; group <= last_group;) {
7305 if (first_bit + len >= osb->bitmap_cpg)
7306 last_bit = osb->bitmap_cpg;
7307 else
7308 last_bit = first_bit + len;
7309
7310 ret = ocfs2_read_group_descriptor(main_bm_inode,
7311 main_bm, group,
7312 &gd_bh);
7313 if (ret < 0) {
7314 mlog_errno(ret);
7315 break;
7316 }
7317
7318 gd = (struct ocfs2_group_desc *)gd_bh->b_data;
7319 cnt = ocfs2_trim_group(sb, gd, first_bit, last_bit, minlen);
7320 brelse(gd_bh);
7321 gd_bh = NULL;
7322 if (cnt < 0) {
7323 ret = cnt;
7324 mlog_errno(ret);
7325 break;
7326 }
7327
7328 trimmed += cnt;
7329 len -= osb->bitmap_cpg - first_bit;
7330 first_bit = 0;
7331 if (group == osb->first_cluster_group_blkno)
7332 group = ocfs2_clusters_to_blocks(sb, osb->bitmap_cpg);
7333 else
7334 group += ocfs2_clusters_to_blocks(sb, osb->bitmap_cpg);
7335 }
7336 range->len = trimmed * sb->s_blocksize;
7337out_unlock:
7338 ocfs2_inode_unlock(main_bm_inode, 0);
7339 brelse(main_bm_bh);
7340out_mutex:
7341 mutex_unlock(&main_bm_inode->i_mutex);
7342 iput(main_bm_inode);
7343out:
7344 return ret;
7345}