diff options
| -rw-r--r-- | fs/ocfs2/alloc.c | 159 | ||||
| -rw-r--r-- | fs/ocfs2/alloc.h | 1 |
2 files changed, 160 insertions, 0 deletions
diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index 48aa9c7401c..ae3ea783dad 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 | } | ||
diff --git a/fs/ocfs2/alloc.h b/fs/ocfs2/alloc.h index 3bd08a03251..ca381c58412 100644 --- a/fs/ocfs2/alloc.h +++ b/fs/ocfs2/alloc.h | |||
| @@ -239,6 +239,7 @@ int ocfs2_find_leaf(struct ocfs2_caching_info *ci, | |||
| 239 | struct buffer_head **leaf_bh); | 239 | struct buffer_head **leaf_bh); |
| 240 | int ocfs2_search_extent_list(struct ocfs2_extent_list *el, u32 v_cluster); | 240 | int ocfs2_search_extent_list(struct ocfs2_extent_list *el, u32 v_cluster); |
| 241 | 241 | ||
| 242 | int ocfs2_trim_fs(struct super_block *sb, struct fstrim_range *range); | ||
| 242 | /* | 243 | /* |
| 243 | * Helper function to look at the # of clusters in an extent record. | 244 | * Helper function to look at the # of clusters in an extent record. |
| 244 | */ | 245 | */ |
