aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/gfs2/incore.h2
-rw-r--r--fs/gfs2/mount.c10
-rw-r--r--fs/gfs2/ops_super.c2
-rw-r--r--fs/gfs2/rgrp.c55
4 files changed, 68 insertions, 1 deletions
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index 8fe0675120a..3f29bd224ba 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
422struct gfs2_tune { 422struct gfs2_tune {
diff --git a/fs/gfs2/mount.c b/fs/gfs2/mount.c
index fba502aa8b2..ee69701a777 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 4ecdad026ea..458019569dc 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 ba5a021b1c5..789953a2b6a 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 }