]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
osdc/Striper: fix handling for sparse reads in add_partial_sparse_result()
authorSage Weil <sage@inktank.com>
Wed, 21 Nov 2012 00:11:00 +0000 (16:11 -0800)
committerSage Weil <sage@inktank.com>
Wed, 21 Nov 2012 00:41:28 +0000 (16:41 -0800)
If bl_map begins *after* the first item in buffer_extents, we want to
skip only the first buffer extent before doing 'continue' to loop to the
next one.

This fixes a crash caused by underflow with a pattern like:

2012-11-20 13:54:30.347861 7f9404ed6700 10 striper add_partial_sparse_result(0x1efa088) 192 covering {12288=192} (offset 2906) to [0,5286,38054,4288]
2012-11-20 13:54:30.347863 7f9404ed6700 20 striper   t 0~5286 bl has 192 off 2906
2012-11-20 13:54:30.347866 7f9404ed6700 20 striper   s gap 9382, skipping
2012-11-20 13:54:30.347867 7f9404ed6700 20 striper   s has 192, copying
2012-11-20 13:54:30.347872 7f9404ed6700 20 striper   t 9574~18446744073709547328 bl has 0 off 12480
2012-11-20 13:54:30.347874 7f9404ed6700 20 striper   s at end
2012-11-20 13:54:30.347876 7f9404ed6700 20 striper   t 38054~4288 bl has 0 off 12480
2012-11-20 13:54:30.347877 7f9404ed6700 20 striper   s at end

Dan reproduced this with

 ./test_librbd_fsx -d -W -R -p 10 -t 1 -S 4 -N 300 rbd fsx

(although I was unable to do so).

Re-fixes #3428.

Reported-and-tested-by: Dan Mick <dan.mick@inktank.com>
Signed-off-by: Sage Weil <sage@inktank.com>
src/osdc/Striper.cc

index cdbfe61674d662eeb9fe993331f11fb3963f8ff2..26e2b917bb7be5bdf86c8f46c028f835ddd5f4e0 100644 (file)
@@ -231,12 +231,15 @@ void Striper::StripedReadResult::add_partial_sparse_result(CephContext *cct,
       if (s->first > bl_off) {
        // gap in sparse read result
        pair<bufferlist, uint64_t>& r = partial[tofs];
-       size_t gap = s->first - bl_off;
+       size_t gap = MIN(s->first - bl_off, tlen);
        ldout(cct, 20) << "  s gap " << gap << ", skipping" << dendl;
        r.second = gap;
        bl_off += gap;
        tofs += gap;
        tlen -= gap;
+       if (tlen == 0) {
+         continue;
+       }
       }
 
       assert(s->first <= bl_off);