diff --git a/Rakefile b/Rakefile index 359ebad..1ec8292 100644 --- a/Rakefile +++ b/Rakefile @@ -1,5 +1,3 @@ -require 'rake_utils/debian' -include RakeUtils::DSL DEBUG = ENV.has_key?('DEBUG') && %w|yes y ok 1 true t|.include?(ENV['DEBUG']) @@ -85,8 +83,10 @@ task :clean do sh "rm -rf *~ build" end -namespace :pkg do - deb do |t| +namespace :pkg do + task :deb do |t| + require 'rake_utils/debian' + t.code_files = ALL_SOURCES + ["Rakefile"] t.pkg_name = "flexnbd" t.generate_changelog! diff --git a/src/serve.c b/src/serve.c index 4c6dd64..f2bc2dd 100644 --- a/src/serve.c +++ b/src/serve.c @@ -283,6 +283,21 @@ void client_reply_to_write( struct client_params* client, struct nbd_request req request.len ); dirty(client->serve, request.from, request.len); } + + if (1) /* not sure whether this is necessary... */ + { + /* multiple of 4K page size */ + uint64_t from_rounded = request.from & (!0xfff); + uint64_t len_rounded = request.len + (request.from - from_rounded); + + CLIENT_ERROR_ON_FAILURE( + msync( + client->mapped + from_rounded, + len_rounded, + MS_SYNC), + "msync failed %ld %ld", request.from, request.len + ); + } client_write_reply( client, &request, 0); } diff --git a/tests/flexnbd.rb b/tests/flexnbd.rb index 8ffb4b7..3864c60 100644 --- a/tests/flexnbd.rb +++ b/tests/flexnbd.rb @@ -16,19 +16,24 @@ class FlexNBD @port = port end - def serve(ip, port, file, *acl) + def serve(file, *acl) File.unlink(ctrl) if File.exists?(ctrl) + cmd ="#{@bin} serve "\ + "--addr #{ip} "\ + "--port #{port} "\ + "--file #{file} "\ + "--sock #{ctrl} "\ + "#{@debug} "\ + "#{acl.join(' ')}" @pid = fork do - cmd ="#{@bin} serve "\ - "--addr #{ip} "\ - "--port #{port} "\ - "--file #{file} "\ - "--sock #{ctrl} "\ - "#{@debug} "\ - "#{acl.join(' ')}" exec(cmd) end - sleep 0.1 until File.socket?(ctrl) + while !File.socket?(ctrl) + pid, status = Process.wait2(@pid, Process::WNOHANG) + raise "server did not start (#{cmd})" if pid + sleep 0.1 + end + at_exit { kill } end def kill diff --git a/tests/fuzz b/tests/fuzz new file mode 100644 index 0000000..e3e3558 --- /dev/null +++ b/tests/fuzz @@ -0,0 +1,80 @@ +#!/usr/bin/ruby + +require 'flexnbd' + +binary = ARGV.shift +test_size = ARGV.shift.to_i +repetitions = ARGV.shift.to_i +repetitions = 50 if repetitions == 0 +seed = ARGV.shift.to_i + +max_length = test_size > 10000000 ? 10000000 : test_size +CHEAT_AND_ROUND_DOWN = false # set to 'false' to expose bugs + +srand(seed) + +if test_size < 32768 || repetitions < 1 || !File.executable?(binary) + STDERR.print "Syntax: #{$0} [repetitions] [seed]\n" + STDERR.print "test_size must be >= 32768 and repeitions must be >= 1" + exit 1 +end + +testname_local = "#{$0}.test.#{$$}.local" +testname_serve = "#{$0}.test.#{$$}.serve" +[testname_local, testname_serve].each do |name| + File.open(name, "w+") { |fh| fh.seek(test_size-1, IO::SEEK_SET); fh.write("0") } +end + +@local = File.open(testname_local, "r+") + +@serve = FlexNBD.new(binary, "127.0.0.1", 41234) +@serve.serve(testname_serve) + +repetitions.times do |n| + + begin + + if File.size(testname_local) != File.size(testname_serve) + STDERR.print "Before pass #{n}: File sizes are different: local=#{File.size(testname_local)} serve=#{File.size(testname_serve)}\n" + exit 1; + end + + md5_local = `md5sum < #{testname_local}`.split(" ").first + md5_serve = `md5sum < #{testname_serve}`.split(" ").first + + if md5_local != md5_serve + STDERR.print "Before pass #{n}: MD5 error: local=#{md5_local} serve=#{md5_serve}\n" + STDERR.print "**** Local contents:\n" + system("hexdump #{testname_local}") + STDERR.print "**** Serve contents:\n" + system("hexdump #{testname_serve}") + exit 1 + end + + length = rand(max_length) + length &= 0xfffff000 if CHEAT_AND_ROUND_DOWN + offset = rand(test_size - length) + offset &= 0xfffff000 if CHEAT_AND_ROUND_DOWN + content = (n%2 == 1) ? ("x" * length) : ("\0" * length) + + @local.seek(offset, IO::SEEK_SET) + @local.write(content) + + @serve.write(offset, content) + + if @serve.read(offset, length) != content + STDERR.print "After pass #{n}: Didn't read back what we wrote!" + exit 1 + end + + rescue StandardError => ex + STDERR.print "During pass #{n}: Exception: #{ex}" + STDERR.print ex.backtrace.join("\n") + "\n" + exit 2 + end + +end + +File.unlink(testname_local) +File.unlink(testname_serve) + diff --git a/tests/nbd_scenarios b/tests/nbd_scenarios index 7392112..be58cfe 100644 --- a/tests/nbd_scenarios +++ b/tests/nbd_scenarios @@ -17,7 +17,6 @@ class NBDScenarios < Test::Unit::TestCase end def teardown - @nbd1.kill rescue nil [@filename1, @filename2].each do |f| File.unlink(f) if File.exists?(f) end @@ -73,7 +72,7 @@ class NBDScenarios < Test::Unit::TestCase protected def serve1(*acl) - @nbd1.serve(@ip, @port1, @filename1, *acl) + @nbd1.serve(@filename1, *acl) end def writefile1(data)