aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2/rgrp.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/gfs2/rgrp.c')
-rw-r--r--fs/gfs2/rgrp.c55
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
834static 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;
866start_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;
881fail:
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
833void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd) 886void 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 }