diff --git a/src/client.c b/src/client.c index 5653a9b..2597ca6 100644 --- a/src/client.c +++ b/src/client.c @@ -132,6 +132,12 @@ void write_not_zeroes(struct client* client, uint64_t from, uint64_t len) debug("writing the lot: from=%ld, run=%d", from, run); /* already allocated, just write it all */ DO_READ(client->mapped + from, run); + /* We know from our earlier call to bitset_run_count that the + * bitset is all-1s at this point, but we need to dirty it for the + * sake of the event stream - the actual bytes have changed, and we + * are interested in that fact. + */ + bitset_set_range( map, from, run ); server_dirty(client->serve, from, run); len -= run; from += run; @@ -167,6 +173,10 @@ void write_not_zeroes(struct client* client, uint64_t from, uint64_t len) * sparseness as possible. */ } + /* When the block is all_zeroes, no bytes have changed, so we + * don't need to put an event into the bitset stream. This may + * be surprising in the future. + */ len -= blockrun; run -= blockrun; diff --git a/src/serve.c b/src/serve.c index a6e29b1..e03812d 100644 --- a/src/serve.c +++ b/src/serve.c @@ -705,6 +705,8 @@ void* build_allocation_map_thread(void* serve_uncast) * All that happens if we leave it is that it gradually builds up an * *incomplete* record of writes. Nobody will use it, as * allocation_map_built == 0 for the lifetime of the process. + * + * The stream functionality can still be relied on. */ warn( "Didn't build allocation map for %s", serve->filename ); } diff --git a/tests/acceptance/test_serve_mode.rb b/tests/acceptance/test_serve_mode.rb index 1278e68..b0eca04 100644 --- a/tests/acceptance/test_serve_mode.rb +++ b/tests/acceptance/test_serve_mode.rb @@ -44,6 +44,29 @@ class TestServeMode < Test::Unit::TestCase end end + def test_long_write_on_top_of_short_write_is_respected + + connect_to_server do |client| + # Start with a file of all-zeroes. + client.write( 0, "\x00" * @env.file1.size ) + rsp = client.read_response + assert_equal FlexNBD::REPLY_MAGIC, rsp[:magic] + assert_equal 0, rsp[:error] + + client.write( 0, "\xFF" ) + rsp = client.read_response + assert_equal FlexNBD::REPLY_MAGIC, rsp[:magic] + assert_equal 0, rsp[:error] + + client.write( 0, "\xFF\xFF" ) + rsp = client.read_response + assert_equal FlexNBD::REPLY_MAGIC, rsp[:magic] + assert_equal 0, rsp[:error] + end + + assert_equal "\xFF\xFF", @env.file1.read (0, 2 ) + end + def test_read_request_out_of_bounds_receives_error_response connect_to_server do |client|