+static ssize_t recovery_read_multiple(struct recoverybuf *r,
+ secaddr pos, secaddr want)
+{
+ ssize_t n;
+ secaddr skip, want0 = want;
+
+ while (want > r->sz) {
+ skip = want - r->sz;
+ n = recovery_read_buffer(r, pos + skip, r->sz);
+ if (n < r->sz) return (skip + (n >= 0 ? n : 0));
+ want -= r->sz;
+ }
+ n = recovery_read_buffer(r, pos, want);
+ if (n < 0 || n < want) return (n);
+ return (want0);
+}
+
+static ssize_t recovery_read(struct recoverybuf *r,
+ secaddr pos, secaddr want)
+{
+ secaddr lo = pos, hi = pos + want, span;
+ ssize_t n;
+
+ if (hi < r->good_lo || lo > r->good_hi) {
+ n = recovery_read_multiple(r, lo, hi - lo);
+ if (n > 0) { r->good_lo = lo; r->good_hi = lo + n; }
+ return (n);
+ }
+
+ if (hi > r->good_hi) {
+ span = hi - r->good_hi;
+ n = recovery_read_multiple(r, r->good_hi, span);
+ if (n > 0) r->good_hi += n;
+ if (n < 0 || n < span) return (r->good_hi - lo);
+ }
+
+ if (lo < r->good_lo) {
+ span = r->good_lo - lo;
+ n = recovery_read_multiple(r, lo, span);
+ if (n == span) r->good_lo = lo;
+ else return (n);
+ }
+
+ n = r->good_hi - pos; if (n > want) n = want;
+ if (!n) { errno = EIO; n = -1; }
+ return (n);
+}
+
+static double clear_factor = 1.5;
+static secaddr clear_min = 1, clear_max = SECLIMIT;
+static double step_factor = 2.0;
+static secaddr step_min = 1, step_max = 0;
+
+static secaddr run_length_wanted(secaddr pos, secaddr badlen, secaddr end)