diff options
author | Tao Ma <boyu.mt@taobao.com> | 2011-05-22 22:36:43 -0400 |
---|---|---|
committer | Joel Becker <jlbec@evilplan.org> | 2011-05-24 02:37:18 -0400 |
commit | e80de36d8dbff216a384e9204e54d59deeadf344 (patch) | |
tree | ff1bde3fa17785519863f3880fecbb6b6fcd148a /fs/ocfs2/alloc.c | |
parent | 69a60c4d177632bd56ae567dc0a082f7119b71c2 (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.c | 159 |
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: | |||
7184 | out: | 7185 | out: |
7185 | return ret; | 7186 | return ret; |
7186 | } | 7187 | } |
7188 | |||
7189 | static 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 | |||
7202 | static 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 | |||
7244 | int 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; | ||
7337 | out_unlock: | ||
7338 | ocfs2_inode_unlock(main_bm_inode, 0); | ||
7339 | brelse(main_bm_bh); | ||
7340 | out_mutex: | ||
7341 | mutex_unlock(&main_bm_inode->i_mutex); | ||
7342 | iput(main_bm_inode); | ||
7343 | out: | ||
7344 | return ret; | ||
7345 | } | ||