Enable writing after the 2G boundary

This patch fixes a bug in readwrite.c which truncated the 'from' field
in nbd requests.  It was casting them down from an off64_t to an int.
This commit is contained in:
Alex Young
2012-07-12 18:01:10 +01:00
parent cef2dcaad2
commit 2e4e592c08
6 changed files with 55 additions and 19 deletions

View File

@@ -136,7 +136,6 @@ void write_not_zeroes(struct client* client, uint64_t from, int len)
*/ */
if (zerobuffer[0] != 0 || if (zerobuffer[0] != 0 ||
memcmp(zerobuffer, zerobuffer + 1, blockrun - 1)) { memcmp(zerobuffer, zerobuffer + 1, blockrun - 1)) {
debug("non-zero, writing from=%ld, blockrun=%d", from, blockrun);
memcpy(client->mapped+from, zerobuffer, blockrun); memcpy(client->mapped+from, zerobuffer, blockrun);
bitset_set_range(map, from, blockrun); bitset_set_range(map, from, blockrun);
server_dirty(client->serve, from, blockrun); server_dirty(client->serve, from, blockrun);
@@ -147,9 +146,7 @@ void write_not_zeroes(struct client* client, uint64_t from, int len)
* sparseness as possible. * sparseness as possible.
*/ */
} }
else {
debug("all zero, skip write");
}
len -= blockrun; len -= blockrun;
run -= blockrun; run -= blockrun;
from += blockrun; from += blockrun;
@@ -164,6 +161,7 @@ int fd_read_request( int fd, struct nbd_request_raw *out_request)
return readloop(fd, out_request, sizeof(struct nbd_request_raw)); return readloop(fd, out_request, sizeof(struct nbd_request_raw));
} }
/* Returns 1 if *request was filled with a valid request which we should /* Returns 1 if *request was filled with a valid request which we should
* try to honour. 0 otherwise. */ * try to honour. 0 otherwise. */
int client_read_request( struct client * client , struct nbd_request *out_request, int * disconnected ) int client_read_request( struct client * client , struct nbd_request *out_request, int * disconnected )
@@ -318,7 +316,7 @@ int client_request_needs_reply( struct client * client,
"after an entrust message."); "after an entrust message.");
/* check it's not out of range */ /* check it's not out of range */
if ( request.from+request.len > client->serve->size) { if ( request.from+request.len > client->serve->size) {
debug("request read %ld+%d out of range", debug("request read %llx+%ld out of range",
request.from, request.from,
request.len request.len
); );
@@ -495,7 +493,7 @@ void* client_serve(void* client_uncast)
NULL, NULL,
(void**) &client->mapped (void**) &client->mapped
), ),
"Couldn't open/mmap file %s", client->serve->filename "Couldn't open/mmap file %s: %s", client->serve->filename, strerror( errno )
); );
debug("client: sending hello"); debug("client: sending hello");
client_send_hello(client); client_send_hello(client);

View File

@@ -55,6 +55,9 @@ struct bitset_mapping* build_allocation_map(int fd, uint64_t size, int resolutio
); );
} }
/* This is pointlessly verbose for real discs, it's here as a
* reference for pulling data out of the allocation map */
if ( 0 ) {
for (i=0; i<(size/resolution); i++) { for (i=0; i<(size/resolution); i++) {
debug("map[%d] = %d%d%d%d%d%d%d%d", debug("map[%d] = %d%d%d%d%d%d%d%d",
i, i,
@@ -68,6 +71,7 @@ struct bitset_mapping* build_allocation_map(int fd, uint64_t size, int resolutio
(allocation_map->bits[i] & 128) == 128 (allocation_map->bits[i] & 128) == 128
); );
} }
}
free(fiemap); free(fiemap);

View File

@@ -56,7 +56,7 @@ fail:
return 0; return 0;
} }
void fill_request(struct nbd_request *request, int type, int from, int len) void fill_request(struct nbd_request *request, int type, off64_t from, int len)
{ {
request->magic = htobe32(REQUEST_MAGIC); request->magic = htobe32(REQUEST_MAGIC);
request->type = htobe32(type); request->type = htobe32(type);

View File

@@ -79,6 +79,10 @@ class Environment
end end
def truncate1( size )
system "truncate -s #{size} #{@filename1}"
end
def listening_ports def listening_ports
`netstat -ltn`. `netstat -ltn`.

View File

@@ -81,4 +81,15 @@ class TestHappyPath < Test::Unit::TestCase
assert @env.status2['has_control'], "destination didn't take control" assert @env.status2['has_control'], "destination didn't take control"
end end
def test_write_to_high_block
# Create a large file, then try to write to somewhere after the 2G boundary
@env.truncate1 "4G"
@env.serve1
@env.nbd1.write( 2**31+2**29, "12345678" )
sleep(1)
assert_equal "12345678", @env.nbd1.read( 2**31+2**29, 8 )
end
end end

View File

@@ -182,6 +182,24 @@ START_TEST(test_reply_handle)
END_TEST END_TEST
START_TEST( test_convert_from )
{
/* Check that we can correctly pull numbers out of an
* nbd_request_raw */
struct nbd_request_raw request_raw;
struct nbd_request request;
char readbuf[] = {0x80, 0, 0, 0, 0, 0, 0, 0};
memcpy( &request_raw.from, readbuf, 8 );
nbd_r2h_request( &request_raw, &request );
uint64_t target = 1;
target <<= 63;
fail_unless( target == request.from, "from was wrong" );
}
END_TEST
Suite *nbdtypes_suite(void) Suite *nbdtypes_suite(void)
{ {
Suite *s = suite_create( "nbdtypes" ); Suite *s = suite_create( "nbdtypes" );
@@ -197,6 +215,7 @@ Suite *nbdtypes_suite(void)
tcase_add_test( tc_request, test_request_handle ); tcase_add_test( tc_request, test_request_handle );
tcase_add_test( tc_request, test_request_from ); tcase_add_test( tc_request, test_request_from );
tcase_add_test( tc_request, test_request_len ); tcase_add_test( tc_request, test_request_len );
tcase_add_test( tc_request, test_convert_from );
tcase_add_test( tc_reply, test_reply_magic ); tcase_add_test( tc_reply, test_reply_magic );
tcase_add_test( tc_reply, test_reply_error ); tcase_add_test( tc_reply, test_reply_error );
tcase_add_test( tc_reply, test_reply_handle ); tcase_add_test( tc_reply, test_reply_handle );