diff options
Diffstat (limited to 'fs/gfs2/rgrp.c')
-rw-r--r-- | fs/gfs2/rgrp.c | 55 |
1 files changed, 55 insertions, 0 deletions
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index ba5a021b1c57..789953a2b6a8 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/fs.h> | 14 | #include <linux/fs.h> |
15 | #include <linux/gfs2_ondisk.h> | 15 | #include <linux/gfs2_ondisk.h> |
16 | #include <linux/prefetch.h> | 16 | #include <linux/prefetch.h> |
17 | #include <linux/blkdev.h> | ||
17 | 18 | ||
18 | #include "gfs2.h" | 19 | #include "gfs2.h" |
19 | #include "incore.h" | 20 | #include "incore.h" |
@@ -830,6 +831,58 @@ void gfs2_rgrp_bh_put(struct gfs2_rgrpd *rgd) | |||
830 | spin_unlock(&sdp->sd_rindex_spin); | 831 | spin_unlock(&sdp->sd_rindex_spin); |
831 | } | 832 | } |
832 | 833 | ||
834 | static void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset, | ||
835 | const struct gfs2_bitmap *bi) | ||
836 | { | ||
837 | struct super_block *sb = sdp->sd_vfs; | ||
838 | struct block_device *bdev = sb->s_bdev; | ||
839 | const unsigned int sects_per_blk = sdp->sd_sb.sb_bsize / | ||
840 | bdev_hardsect_size(sb->s_bdev); | ||
841 | u64 blk; | ||
842 | sector_t start; | ||
843 | sector_t nr_sects = 0; | ||
844 | int rv; | ||
845 | unsigned int x; | ||
846 | |||
847 | for (x = 0; x < bi->bi_len; x++) { | ||
848 | const u8 *orig = bi->bi_bh->b_data + bi->bi_offset + x; | ||
849 | const u8 *clone = bi->bi_clone + bi->bi_offset + x; | ||
850 | u8 diff = ~(*orig | (*orig >> 1)) & (*clone | (*clone >> 1)); | ||
851 | diff &= 0x55; | ||
852 | if (diff == 0) | ||
853 | continue; | ||
854 | blk = offset + ((bi->bi_start + x) * GFS2_NBBY); | ||
855 | blk *= sects_per_blk; /* convert to sectors */ | ||
856 | while(diff) { | ||
857 | if (diff & 1) { | ||
858 | if (nr_sects == 0) | ||
859 | goto start_new_extent; | ||
860 | if ((start + nr_sects) != blk) { | ||
861 | rv = blkdev_issue_discard(bdev, start, | ||
862 | nr_sects, GFP_NOFS); | ||
863 | if (rv) | ||
864 | goto fail; | ||
865 | nr_sects = 0; | ||
866 | start_new_extent: | ||
867 | start = blk; | ||
868 | } | ||
869 | nr_sects += sects_per_blk; | ||
870 | } | ||
871 | diff >>= 2; | ||
872 | blk += sects_per_blk; | ||
873 | } | ||
874 | } | ||
875 | if (nr_sects) { | ||
876 | rv = blkdev_issue_discard(bdev, start, nr_sects, GFP_NOFS); | ||
877 | if (rv) | ||
878 | goto fail; | ||
879 | } | ||
880 | return; | ||
881 | fail: | ||
882 | fs_warn(sdp, "error %d on discard request, turning discards off for this filesystem", rv); | ||
883 | sdp->sd_args.ar_discard = 0; | ||
884 | } | ||
885 | |||
833 | void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd) | 886 | void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd) |
834 | { | 887 | { |
835 | struct gfs2_sbd *sdp = rgd->rd_sbd; | 888 | struct gfs2_sbd *sdp = rgd->rd_sbd; |
@@ -840,6 +893,8 @@ void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd) | |||
840 | struct gfs2_bitmap *bi = rgd->rd_bits + x; | 893 | struct gfs2_bitmap *bi = rgd->rd_bits + x; |
841 | if (!bi->bi_clone) | 894 | if (!bi->bi_clone) |
842 | continue; | 895 | continue; |
896 | if (sdp->sd_args.ar_discard) | ||
897 | gfs2_rgrp_send_discards(sdp, rgd->rd_data0, bi); | ||
843 | memcpy(bi->bi_clone + bi->bi_offset, | 898 | memcpy(bi->bi_clone + bi->bi_offset, |
844 | bi->bi_bh->b_data + bi->bi_offset, bi->bi_len); | 899 | bi->bi_bh->b_data + bi->bi_offset, bi->bi_len); |
845 | } | 900 | } |