aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2/rgrp.c
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2009-02-09 04:25:01 -0500
committerSteven Whitehouse <steve@dolmen.chygwyn.com>2009-03-24 07:21:20 -0400
commitf15ab5619d8068a321094f4705147764d689e88e (patch)
treec08044e928dff4628b0aa6ea17d6bc5fb922d5dc /fs/gfs2/rgrp.c
parentd8348de06f704fc34d24ec068546ecb1045fc11a (diff)
GFS2: Support generation of discard requests
This patch allows GFS2 to generate discard requests for blocks which are no longer useful to the filesystem (i.e. those which have been freed as the result of an unlink operation). The requests are generated at the time which those blocks become available for reuse in the filesystem. In order to use this new feature, you have to specify the "discard" mount option. The code coalesces adjacent blocks into a single extent when generating the discard requests, thus generating the minimum number. If an error occurs when the request has been sent to the block device, then it will print a message and turn off the requests for that filesystem. If the problem is temporary, then you can use remount to turn the option back on again. There is also a nodiscard mount option so that you can use remount to turn discard requests off, if required. Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
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 }