aboutsummaryrefslogtreecommitdiffstats
path: root/module/zfs/metaslab.c
diff options
context:
space:
mode:
authorSerapheim Dimitropoulos <[email protected]>2019-07-19 11:19:50 -0700
committerBrian Behlendorf <[email protected]>2019-07-19 11:19:50 -0700
commit7f31908913592b3075306daf403f2a334602493e (patch)
treef344e3d64241744587a44197f5b5720f5f759a21 /module/zfs/metaslab.c
parent43a8536260e76dab4a615164f9e6d6397c6b7778 (diff)
Tricky semantics of ms_max_size in metaslab_should_allocate()
metaslab_should_allocate() is used in two places: [1] When trying to select a metaslab to allocate from [2] When trying to allocate from a metaslab In [2] we always expect the metaslab to be loaded, and after the refactoring of the log spacemap changes, whenever we load a metaslab we set ms_max_size to the biggest range in the ms_allocatable tree. Thus, when it is used in [2], if that field is 0, it means that the metaslab doesn't have any segments that can be used for allocations now (though it may have some free space but that space can be in the freeing, freed, or deferred trees). In [1] a metaslab can be loaded or unloaded at which point 0 can either mean the metaslab doesn't have any space or the metaslab is just not loaded thus we go ahead and try to make an estimation based on its weight. The issue here is when we call the above function for [2] and the metaslab doesn't have any allocatable space, we still go ahead and check its ms_weight which may be out of date because we haven't ran metaslab_sync_done() yet. At that point we are allowing an allocation to be attempted even though we know there is no range that is allocatable. This patch fixes this issue by explicitly checking if the metaslab is loaded and if it is, the ms_max_size is used. Reviewed-by: Matt Ahrens <[email protected]> Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Serapheim Dimitropoulos <[email protected]> Closes #9045
Diffstat (limited to 'module/zfs/metaslab.c')
-rw-r--r--module/zfs/metaslab.c17
1 files changed, 10 insertions, 7 deletions
diff --git a/module/zfs/metaslab.c b/module/zfs/metaslab.c
index 0b22aa875..20884d02c 100644
--- a/module/zfs/metaslab.c
+++ b/module/zfs/metaslab.c
@@ -2511,18 +2511,21 @@ metaslab_segment_weight(metaslab_t *msp)
/*
* Determine if we should attempt to allocate from this metaslab. If the
- * metaslab has a maximum size then we can quickly determine if the desired
- * allocation size can be satisfied. Otherwise, if we're using segment-based
- * weighting then we can determine the maximum allocation that this metaslab
- * can accommodate based on the index encoded in the weight. If we're using
- * space-based weights then rely on the entire weight (excluding the weight
- * type bit).
+ * metaslab is loaded, then we can determine if the desired allocation
+ * can be satisfied by looking at the size of the maximum free segment
+ * on that metaslab. Otherwise, we make our decision based on the metaslab's
+ * weight. For segment-based weighting we can determine the maximum
+ * allocation based on the index encoded in its value. For space-based
+ * weights we rely on the entire weight (excluding the weight-type bit).
*/
boolean_t
metaslab_should_allocate(metaslab_t *msp, uint64_t asize)
{
- if (msp->ms_max_size != 0)
+ if (msp->ms_loaded) {
return (msp->ms_max_size >= asize);
+ } else {
+ ASSERT0(msp->ms_max_size);
+ }
boolean_t should_allocate;
if (!WEIGHT_IS_SPACEBASED(msp->ms_weight)) {