diff options
-rw-r--r-- | fs/gfs2/incore.h | 2 | ||||
-rw-r--r-- | fs/gfs2/mount.c | 10 | ||||
-rw-r--r-- | fs/gfs2/ops_super.c | 2 | ||||
-rw-r--r-- | fs/gfs2/rgrp.c | 55 |
4 files changed, 68 insertions, 1 deletions
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 8fe0675120ac..3f29bd224ba1 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h | |||
@@ -416,7 +416,7 @@ struct gfs2_args { | |||
416 | unsigned int ar_suiddir:1; /* suiddir support */ | 416 | unsigned int ar_suiddir:1; /* suiddir support */ |
417 | unsigned int ar_data:2; /* ordered/writeback */ | 417 | unsigned int ar_data:2; /* ordered/writeback */ |
418 | unsigned int ar_meta:1; /* mount metafs */ | 418 | unsigned int ar_meta:1; /* mount metafs */ |
419 | unsigned int ar_num_glockd; /* Number of glockd threads */ | 419 | unsigned int ar_discard:1; /* discard requests */ |
420 | }; | 420 | }; |
421 | 421 | ||
422 | struct gfs2_tune { | 422 | struct gfs2_tune { |
diff --git a/fs/gfs2/mount.c b/fs/gfs2/mount.c index fba502aa8b2d..ee69701a7777 100644 --- a/fs/gfs2/mount.c +++ b/fs/gfs2/mount.c | |||
@@ -41,6 +41,8 @@ enum { | |||
41 | Opt_data_writeback, | 41 | Opt_data_writeback, |
42 | Opt_data_ordered, | 42 | Opt_data_ordered, |
43 | Opt_meta, | 43 | Opt_meta, |
44 | Opt_discard, | ||
45 | Opt_nodiscard, | ||
44 | Opt_err, | 46 | Opt_err, |
45 | }; | 47 | }; |
46 | 48 | ||
@@ -65,6 +67,8 @@ static const match_table_t tokens = { | |||
65 | {Opt_data_writeback, "data=writeback"}, | 67 | {Opt_data_writeback, "data=writeback"}, |
66 | {Opt_data_ordered, "data=ordered"}, | 68 | {Opt_data_ordered, "data=ordered"}, |
67 | {Opt_meta, "meta"}, | 69 | {Opt_meta, "meta"}, |
70 | {Opt_discard, "discard"}, | ||
71 | {Opt_nodiscard, "nodiscard"}, | ||
68 | {Opt_err, NULL} | 72 | {Opt_err, NULL} |
69 | }; | 73 | }; |
70 | 74 | ||
@@ -157,6 +161,12 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options) | |||
157 | case Opt_meta: | 161 | case Opt_meta: |
158 | args->ar_meta = 1; | 162 | args->ar_meta = 1; |
159 | break; | 163 | break; |
164 | case Opt_discard: | ||
165 | args->ar_discard = 1; | ||
166 | break; | ||
167 | case Opt_nodiscard: | ||
168 | args->ar_discard = 0; | ||
169 | break; | ||
160 | case Opt_err: | 170 | case Opt_err: |
161 | default: | 171 | default: |
162 | fs_info(sdp, "invalid mount option: %s\n", o); | 172 | fs_info(sdp, "invalid mount option: %s\n", o); |
diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index 4ecdad026eaf..458019569dcb 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c | |||
@@ -608,6 +608,8 @@ static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt) | |||
608 | } | 608 | } |
609 | seq_printf(s, ",data=%s", state); | 609 | seq_printf(s, ",data=%s", state); |
610 | } | 610 | } |
611 | if (args->ar_discard) | ||
612 | seq_printf(s, ",discard"); | ||
611 | 613 | ||
612 | return 0; | 614 | return 0; |
613 | } | 615 | } |
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 | } |