I think this is best explained with this code upfront:
struct Borrowed<'a>(&'a Buf);
struct Buf;
impl Buf {
    fn adapt(&mut self) {}
}
fn borrow(buf: &mut Buf) -> Option<Borrowed> {
    buf.adapt(); // think Vec::resize(), so we do need a mutable borrow initially
    // When done, we keep a shared borrow, but borrowchk doesn't know about that apparently
    Some(Borrowed(buf))
}
fn locate<'a>(buf: &'a mut Buf) -> Option<Borrowed<'a>> {
    for _c in 1..3 {
        // This works!
        // if _c % 2 == 0 {
        //   return borrow(buf); 
        // }
        // This also works but is wasteful
        // if borrow(buf).is_some() {
        //     return borrow(buf);
        // }
        if let Some(b) = borrow(buf) {
            return Some(b)
        }
    }
    None
}
fn main() {
    locate(&mut Buf);
}
Here is the playground link for the code above, which doesn't borrowcheck:
error[E0499]: cannot borrow `*buf` as mutable more than once at a time
  --> src/main.rs:24:33
   |
14 | fn locate<'a>(buf: &'a mut Buf) -> Option<Borrowed<'a>> {
   |           -- lifetime `'a` defined here
...
24 |         if let Some(b) = borrow(buf) {
   |                                 ^^^ mutable borrow starts here in previous iteration of loop
25 |             return Some(b)
   |                    ------- returning this value requires that `*buf` is borrowed for `'a`
I have found a similar problem referenced in a GitHub issue (but can't find it now) which indicates this is a known limitation of NLL for performance reasons.
What is a workaround for this that isn't wasteful and maintains a buffer that is passed in?
Due to this, right now I have to make an expensive pack lookup twice as a workaround.