diff options
author | Bob Peterson <rpeterso@redhat.com> | 2018-08-07 11:07:00 -0400 |
---|---|---|
committer | Bob Peterson <rpeterso@redhat.com> | 2018-08-07 11:07:00 -0400 |
commit | dffe12a82826082d2129ef91b17b257254cb60fc (patch) | |
tree | 8fea704759c5760f46a27468f6d8ec4dbbcc5c15 | |
parent | 21e2156f3c4b2ad8b780a6d02342ca0e028a8acd (diff) |
gfs2: Fix gfs2_testbit to use clone bitmaps
Function gfs2_testbit is called in three places. Two of those places,
gfs2_alloc_extent and gfs2_unaligned_extlen, should be using the clone
bitmaps, not the "real" bitmaps. Function gfs2_unaligned_extlen is used
by the block reservations scheme to determine the length of an extent of
free blocks. Before this patch, it wasn't using the clone bitmap, which
means recently-freed blocks were treated as free blocks for the purposes
of an allocation.
This patch adds a new parameter to gfs2_testbit to indicate whether or
not the clone bitmaps should be used (if available).
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Reviewed-by: Andreas Gruenbacher <agruenba@redhat.com>
-rw-r--r-- | fs/gfs2/incore.h | 21 | ||||
-rw-r--r-- | fs/gfs2/rgrp.c | 44 |
2 files changed, 40 insertions, 25 deletions
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index b50908211b69..b96d39c28e17 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h | |||
@@ -65,6 +65,27 @@ struct gfs2_log_operations { | |||
65 | 65 | ||
66 | #define GBF_FULL 1 | 66 | #define GBF_FULL 1 |
67 | 67 | ||
68 | /** | ||
69 | * Clone bitmaps (bi_clone): | ||
70 | * | ||
71 | * - When a block is freed, we remember the previous state of the block in the | ||
72 | * clone bitmap, and only mark the block as free in the real bitmap. | ||
73 | * | ||
74 | * - When looking for a block to allocate, we check for a free block in the | ||
75 | * clone bitmap, and if no clone bitmap exists, in the real bitmap. | ||
76 | * | ||
77 | * - For allocating a block, we mark it as allocated in the real bitmap, and if | ||
78 | * a clone bitmap exists, also in the clone bitmap. | ||
79 | * | ||
80 | * - At the end of a log_flush, we copy the real bitmap into the clone bitmap | ||
81 | * to make the clone bitmap reflect the current allocation state. | ||
82 | * (Alternatively, we could remove the clone bitmap.) | ||
83 | * | ||
84 | * The clone bitmaps are in-core only, and is never written to disk. | ||
85 | * | ||
86 | * These steps ensure that blocks which have been freed in a transaction cannot | ||
87 | * be reallocated in that same transaction. | ||
88 | */ | ||
68 | struct gfs2_bitmap { | 89 | struct gfs2_bitmap { |
69 | struct buffer_head *bi_bh; | 90 | struct buffer_head *bi_bh; |
70 | char *bi_clone; | 91 | char *bi_clone; |
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 7c5afeba8888..ef50fe9b880a 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c | |||
@@ -123,17 +123,26 @@ static inline void gfs2_setbit(const struct gfs2_rbm *rbm, bool do_clone, | |||
123 | /** | 123 | /** |
124 | * gfs2_testbit - test a bit in the bitmaps | 124 | * gfs2_testbit - test a bit in the bitmaps |
125 | * @rbm: The bit to test | 125 | * @rbm: The bit to test |
126 | * @use_clone: If true, test the clone bitmap, not the official bitmap. | ||
127 | * | ||
128 | * Some callers like gfs2_unaligned_extlen need to test the clone bitmaps, | ||
129 | * not the "real" bitmaps, to avoid allocating recently freed blocks. | ||
126 | * | 130 | * |
127 | * Returns: The two bit block state of the requested bit | 131 | * Returns: The two bit block state of the requested bit |
128 | */ | 132 | */ |
129 | 133 | ||
130 | static inline u8 gfs2_testbit(const struct gfs2_rbm *rbm) | 134 | static inline u8 gfs2_testbit(const struct gfs2_rbm *rbm, bool use_clone) |
131 | { | 135 | { |
132 | struct gfs2_bitmap *bi = rbm_bi(rbm); | 136 | struct gfs2_bitmap *bi = rbm_bi(rbm); |
133 | const u8 *buffer = bi->bi_bh->b_data + bi->bi_offset; | 137 | const u8 *buffer; |
134 | const u8 *byte; | 138 | const u8 *byte; |
135 | unsigned int bit; | 139 | unsigned int bit; |
136 | 140 | ||
141 | if (use_clone && bi->bi_clone) | ||
142 | buffer = bi->bi_clone; | ||
143 | else | ||
144 | buffer = bi->bi_bh->b_data; | ||
145 | buffer += bi->bi_offset; | ||
137 | byte = buffer + (rbm->offset / GFS2_NBBY); | 146 | byte = buffer + (rbm->offset / GFS2_NBBY); |
138 | bit = (rbm->offset % GFS2_NBBY) * GFS2_BIT_SIZE; | 147 | bit = (rbm->offset % GFS2_NBBY) * GFS2_BIT_SIZE; |
139 | 148 | ||
@@ -322,7 +331,7 @@ static bool gfs2_unaligned_extlen(struct gfs2_rbm *rbm, u32 n_unaligned, u32 *le | |||
322 | u8 res; | 331 | u8 res; |
323 | 332 | ||
324 | for (n = 0; n < n_unaligned; n++) { | 333 | for (n = 0; n < n_unaligned; n++) { |
325 | res = gfs2_testbit(rbm); | 334 | res = gfs2_testbit(rbm, true); |
326 | if (res != GFS2_BLKST_FREE) | 335 | if (res != GFS2_BLKST_FREE) |
327 | return true; | 336 | return true; |
328 | (*len)--; | 337 | (*len)--; |
@@ -2147,26 +2156,6 @@ void gfs2_inplace_release(struct gfs2_inode *ip) | |||
2147 | } | 2156 | } |
2148 | 2157 | ||
2149 | /** | 2158 | /** |
2150 | * gfs2_get_block_type - Check a block in a RG is of given type | ||
2151 | * @rgd: the resource group holding the block | ||
2152 | * @block: the block number | ||
2153 | * | ||
2154 | * Returns: The block type (GFS2_BLKST_*) | ||
2155 | */ | ||
2156 | |||
2157 | static unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block) | ||
2158 | { | ||
2159 | struct gfs2_rbm rbm = { .rgd = rgd, }; | ||
2160 | int ret; | ||
2161 | |||
2162 | ret = gfs2_rbm_from_block(&rbm, block); | ||
2163 | WARN_ON_ONCE(ret != 0); | ||
2164 | |||
2165 | return gfs2_testbit(&rbm); | ||
2166 | } | ||
2167 | |||
2168 | |||
2169 | /** | ||
2170 | * gfs2_alloc_extent - allocate an extent from a given bitmap | 2159 | * gfs2_alloc_extent - allocate an extent from a given bitmap |
2171 | * @rbm: the resource group information | 2160 | * @rbm: the resource group information |
2172 | * @dinode: TRUE if the first block we allocate is for a dinode | 2161 | * @dinode: TRUE if the first block we allocate is for a dinode |
@@ -2190,7 +2179,7 @@ static void gfs2_alloc_extent(const struct gfs2_rbm *rbm, bool dinode, | |||
2190 | block++; | 2179 | block++; |
2191 | while (*n < elen) { | 2180 | while (*n < elen) { |
2192 | ret = gfs2_rbm_from_block(&pos, block); | 2181 | ret = gfs2_rbm_from_block(&pos, block); |
2193 | if (ret || gfs2_testbit(&pos) != GFS2_BLKST_FREE) | 2182 | if (ret || gfs2_testbit(&pos, true) != GFS2_BLKST_FREE) |
2194 | break; | 2183 | break; |
2195 | gfs2_trans_add_meta(pos.rgd->rd_gl, rbm_bi(&pos)->bi_bh); | 2184 | gfs2_trans_add_meta(pos.rgd->rd_gl, rbm_bi(&pos)->bi_bh); |
2196 | gfs2_setbit(&pos, true, GFS2_BLKST_USED); | 2185 | gfs2_setbit(&pos, true, GFS2_BLKST_USED); |
@@ -2543,6 +2532,7 @@ int gfs2_check_blk_type(struct gfs2_sbd *sdp, u64 no_addr, unsigned int type) | |||
2543 | { | 2532 | { |
2544 | struct gfs2_rgrpd *rgd; | 2533 | struct gfs2_rgrpd *rgd; |
2545 | struct gfs2_holder rgd_gh; | 2534 | struct gfs2_holder rgd_gh; |
2535 | struct gfs2_rbm rbm; | ||
2546 | int error = -EINVAL; | 2536 | int error = -EINVAL; |
2547 | 2537 | ||
2548 | rgd = gfs2_blk2rgrpd(sdp, no_addr, 1); | 2538 | rgd = gfs2_blk2rgrpd(sdp, no_addr, 1); |
@@ -2553,7 +2543,11 @@ int gfs2_check_blk_type(struct gfs2_sbd *sdp, u64 no_addr, unsigned int type) | |||
2553 | if (error) | 2543 | if (error) |
2554 | goto fail; | 2544 | goto fail; |
2555 | 2545 | ||
2556 | if (gfs2_get_block_type(rgd, no_addr) != type) | 2546 | rbm.rgd = rgd; |
2547 | error = gfs2_rbm_from_block(&rbm, no_addr); | ||
2548 | WARN_ON_ONCE(error != 0); | ||
2549 | |||
2550 | if (gfs2_testbit(&rbm, false) != type) | ||
2557 | error = -ESTALE; | 2551 | error = -ESTALE; |
2558 | 2552 | ||
2559 | gfs2_glock_dq_uninit(&rgd_gh); | 2553 | gfs2_glock_dq_uninit(&rgd_gh); |