| 2239 | } |
| 2240 | |
| 2241 | static void |
| 2242 | vdev_draid_xlate(vdev_t *cvd, const range_seg64_t *logical_rs, |
| 2243 | range_seg64_t *physical_rs, range_seg64_t *remain_rs) |
| 2244 | { |
| 2245 | vdev_t *raidvd = cvd->vdev_parent; |
| 2246 | ASSERT(raidvd->vdev_ops == &vdev_draid_ops); |
| 2247 | |
| 2248 | vdev_draid_config_t *vdc = raidvd->vdev_tsd; |
| 2249 | uint64_t ashift = raidvd->vdev_top->vdev_ashift; |
| 2250 | |
| 2251 | /* Make sure the offsets are block-aligned */ |
| 2252 | ASSERT0(logical_rs->rs_start % (1 << ashift)); |
| 2253 | ASSERT0(logical_rs->rs_end % (1 << ashift)); |
| 2254 | |
| 2255 | uint64_t logical_start = logical_rs->rs_start; |
| 2256 | uint64_t logical_end = logical_rs->rs_end; |
| 2257 | |
| 2258 | /* |
| 2259 | * Unaligned ranges must be skipped. All metaslabs are correctly |
| 2260 | * aligned so this should not happen, but this case is handled in |
| 2261 | * case it's needed by future callers. |
| 2262 | */ |
| 2263 | uint64_t astart = vdev_draid_get_astart(raidvd, logical_start); |
| 2264 | if (astart != logical_start) { |
| 2265 | physical_rs->rs_start = logical_start; |
| 2266 | physical_rs->rs_end = logical_start; |
| 2267 | remain_rs->rs_start = MIN(astart, logical_end); |
| 2268 | remain_rs->rs_end = logical_end; |
| 2269 | return; |
| 2270 | } |
| 2271 | |
| 2272 | /* |
| 2273 | * Unlike with mirrors and raidz a dRAID logical range can map |
| 2274 | * to multiple non-contiguous physical ranges. This is handled by |
| 2275 | * limiting the size of the logical range to a single group and |
| 2276 | * setting the remain argument such that it describes the remaining |
| 2277 | * unmapped logical range. This is stricter than absolutely |
| 2278 | * necessary but helps simplify the logic below. |
| 2279 | */ |
| 2280 | uint64_t group = vdev_draid_offset_to_group(raidvd, logical_start); |
| 2281 | uint64_t nextstart = vdev_draid_group_to_offset(raidvd, group + 1); |
| 2282 | if (logical_end > nextstart) |
| 2283 | logical_end = nextstart; |
| 2284 | |
| 2285 | /* Find the starting offset for each vdev in the group */ |
| 2286 | uint64_t perm, groupstart; |
| 2287 | uint64_t start = vdev_draid_logical_to_physical(raidvd, |
| 2288 | logical_start, &perm, &groupstart); |
| 2289 | uint64_t end = start; |
| 2290 | |
| 2291 | uint8_t *base; |
| 2292 | uint64_t iter, id; |
| 2293 | vdev_draid_get_perm(vdc, perm, &base, &iter); |
| 2294 | |
| 2295 | /* |
| 2296 | * Check if the passed child falls within the group. If it does |
| 2297 | * update the start and end to reflect the physical range. |
| 2298 | * Otherwise, leave them unmodified which will result in an empty |
nothing calls this directly
no test coverage detected