… | |
… | |
12 | use Linux::NBD::Server; |
12 | use Linux::NBD::Server; |
13 | |
13 | |
14 | use POSIX (); |
14 | use POSIX (); |
15 | |
15 | |
16 | use IO::Socket::UNIX; |
16 | use IO::Socket::UNIX; |
|
|
17 | |
|
|
18 | our $SYNC = 1; |
|
|
19 | our $NTFS_COMPRESSION = 1; |
17 | |
20 | |
18 | sub BLKSIZE() { 512 } |
21 | sub BLKSIZE() { 512 } |
19 | |
22 | |
20 | my $blocks = qx<blockdev --getsz \Q$orig> * 512 / BLKSIZE; |
23 | my $blocks = qx<blockdev --getsz \Q$orig> * 512 / BLKSIZE; |
21 | |
24 | |
… | |
… | |
42 | |
45 | |
43 | # IO::AIO::madvise $meta_data, 0, undef, IO::AIO::MADV_RANDOM; |
46 | # IO::AIO::madvise $meta_data, 0, undef, IO::AIO::MADV_RANDOM; |
44 | # IO::AIO::madvise $data_data, 0, undef, IO::AIO::MADV_RANDOM; |
47 | # IO::AIO::madvise $data_data, 0, undef, IO::AIO::MADV_RANDOM; |
45 | } |
48 | } |
46 | |
49 | |
47 | system "chattr", "+C", $cachemeta; |
50 | system "chattr +C \Q$cachemeta\E >/dev/null 2>&1"; |
48 | system "chattr", "+C", $cachedata; |
51 | system "chattr +C \Q$cachedata\E >/dev/null 2>&1"; |
|
|
52 | |
|
|
53 | system "btrfs property set \Q$cachemeta\E compression '' >/dev/null 2>&1"; |
|
|
54 | system "btrfs property set \Q$cachedata\E compression '' >/dev/null 2>&1"; |
49 | |
55 | |
50 | mapin; |
56 | mapin; |
51 | |
57 | |
52 | IO::AIO::mmap my $orig_data, $blocks * BLKSIZE, IO::AIO::PROT_READ | IO::AIO::PROT_WRITE, IO::AIO::MAP_SHARED, $orig_fh, 0; |
58 | IO::AIO::mmap my $orig_data, $blocks * BLKSIZE, IO::AIO::PROT_READ | IO::AIO::PROT_WRITE, IO::AIO::MAP_SHARED, $orig_fh, 0; |
53 | |
59 | |
… | |
… | |
63 | #my $need_sync = 0; |
69 | #my $need_sync = 0; |
64 | |
70 | |
65 | sub apply { |
71 | sub apply { |
66 | my ($reset) = @_; |
72 | my ($reset) = @_; |
67 | |
73 | |
|
|
74 | Coro::AIO::aio_msync $cachedata, 0, undef, IO::AIO::MS_SYNC |
|
|
75 | and die "cachedata msync: $!\n"; |
|
|
76 | Coro::AIO::aio_msync $cachemeta, 0, undef, IO::AIO::MS_SYNC |
|
|
77 | and die "cachemeta msync: $!\n"; |
|
|
78 | |
68 | my ($blk, $idx); |
79 | my ($blk, $idx); |
69 | |
80 | |
70 | my ($blk_nxt, $blk_buf, $blk_total); |
81 | my ($blk_nxt, $blk_buf, $blk_total); |
71 | |
82 | |
72 | my $blk_flush = sub { |
83 | my $blk_flush = sub { |
73 | return unless length $blk_buf; |
84 | return unless length $blk_buf; |
74 | |
85 | |
75 | $blk_nxt -= (length $blk_buf) / BLKSIZE; |
86 | $blk_nxt -= (length $blk_buf) / BLKSIZE; |
76 | $blk_total += length $blk_buf; |
87 | $blk_total += length $blk_buf; |
77 | |
88 | |
|
|
89 | if ($NTFS_COMPRESSION and 0x10000 > length $blk_buf) { |
|
|
90 | printf "patch back blk %d len %d (total: %.3fGB)\n", $blk_nxt, length $blk_buf, $blk_total / 1e9; |
|
|
91 | my $end = $blk_nxt * BLKSIZE + length $blk_buf; |
|
|
92 | my $len = 0x10000 - length $blk_buf; |
|
|
93 | |
|
|
94 | $blk_buf .= substr $orig_data, $end, $len; |
|
|
95 | |
|
|
96 | die unless $end + $len == ($blk_nxt + 128) * BLKSIZE; |
|
|
97 | # die unless 65536 == length $blk_buf; |
|
|
98 | } else { |
78 | printf "write back blk %d len %d (total: %.3fGiB)\n", $blk_nxt, length $blk_buf, $blk_total / (1 << 30); |
99 | printf "write back blk %d len %d (total: %.3fGB)\n", $blk_nxt, length $blk_buf, $blk_total / 1e9; |
|
|
100 | } |
|
|
101 | |
79 | Coro::AIO::aio_write $orig_fh, $blk_nxt * BLKSIZE, undef, $blk_buf, 0; |
102 | Coro::AIO::aio_write $orig_fh, $blk_nxt * BLKSIZE, undef, $blk_buf, 0;#d# |
80 | #substr $orig_data, $blk_nxt * BLKSIZE, length $blk_buf, $blk_buf; |
103 | #substr $orig_data, $blk_nxt * BLKSIZE, length $blk_buf, $blk_buf; |
81 | |
104 | |
82 | $blk_buf = ""; |
105 | $blk_buf = ""; |
83 | }; |
106 | }; |
84 | |
107 | |
85 | my $nul = (pack "L", 0) x 65536; |
108 | my $nul = (pack "L", 0) x 65536; |
86 | for (my $base = 0; $base * 4 < length $meta_data; $base += 65536) { |
109 | for (my $base = 0; $base * 4 < length $meta_data; $base += 65536) { |
87 | if ($nul ne substr $meta_data, $base * 4, 65536 * 4) { |
110 | if ($nul ne substr $meta_data, $base * 4, 65536 * 4) { |
|
|
111 | # next unless $base >= 3585490256; |
|
|
112 | # next unless $base >= 3643254984 - 65536; |
|
|
113 | # next unless $base >= 3644405080; |
88 | for $blk ($base .. $base + 65535) { |
114 | for $blk ($base .. $base + 65535) { |
89 | $idx = unpack "L", substr $meta_data, $blk * 4, 4; |
115 | $idx = unpack "L", substr $meta_data, $blk * 4, 4; |
90 | |
116 | |
91 | if ($idx) { |
117 | if ($idx) { |
92 | if ($blk_nxt != $blk or (64 * 1024 * 1024) <= length $blk_buf) { |
118 | if ($blk_nxt != $blk or (64 * 1024 * 1024) <= length $blk_buf) { |
… | |
… | |
104 | } |
130 | } |
105 | } |
131 | } |
106 | |
132 | |
107 | $blk_flush->(); |
133 | $blk_flush->(); |
108 | print "done, syncing...\n"; |
134 | print "done, syncing...\n"; |
109 | Coro::AIO::aio_fsync $orig_fh; |
135 | Coro::AIO::aio_fsync $orig_fh if $SYNC; |
110 | |
136 | |
111 | if ($reset) { |
137 | if ($reset) { |
112 | print "resetting\n"; |
138 | print "resetting\n"; |
113 | |
139 | |
114 | undef $meta_data; |
140 | undef $meta_data; |
… | |
… | |
117 | Coro::AIO::aio_truncate $meta_fh, 0; |
143 | Coro::AIO::aio_truncate $meta_fh, 0; |
118 | Coro::AIO::aio_truncate $data_fh, 0; |
144 | Coro::AIO::aio_truncate $data_fh, 0; |
119 | |
145 | |
120 | ::mapin; |
146 | ::mapin; |
121 | |
147 | |
122 | Coro::AIO::aio_fsync $meta_fh; |
148 | Coro::AIO::aio_fsync $meta_fh if $SYNC; |
123 | Coro::AIO::aio_fsync $data_fh; |
149 | Coro::AIO::aio_fsync $data_fh if $SYNC; |
124 | } |
150 | } |
125 | |
151 | |
126 | $alloc = 0; |
152 | $alloc = 0; |
127 | } |
153 | } |
128 | |
154 | |
|
|
155 | if ($apply) { |
129 | apply $apply eq "r" if $apply; |
156 | apply $apply eq "r"; |
|
|
157 | #exit 0; # maybe unsafe? |
|
|
158 | } |
130 | |
159 | |
131 | { |
160 | { |
132 | my $nul = "\x00" x 65536; |
161 | my $nul = "\x00" x 65536; |
133 | for (my $ofs = 0; $ofs < length $meta_data; $ofs += 65536) { |
162 | for (my $ofs = 0; $ofs < length $meta_data; $ofs += 65536) { |
134 | if ($nul ne substr $meta_data, $ofs, 65536) { |
163 | if ($nul ne substr $meta_data, $ofs, 65536) { |
… | |
… | |
140 | } |
169 | } |
141 | |
170 | |
142 | print "ALLOC is $alloc\n"; |
171 | print "ALLOC is $alloc\n"; |
143 | |
172 | |
144 | sub sync { |
173 | sub sync { |
145 | Coro::AIO::aio_fsync $data_fh; |
174 | Coro::AIO::aio_fsync $data_fh if $SYNC; |
146 | Coro::AIO::aio_fsync $meta_fh; |
175 | Coro::AIO::aio_fsync $meta_fh if $SYNC; |
147 | } |
176 | } |
148 | |
177 | |
149 | sub req_read { |
178 | sub req_read { |
150 | my ($self, $handle, $ofs, $len) = @_; |
179 | my ($self, $handle, $ofs, $len) = @_; |
151 | |
180 | |
… | |
… | |
229 | #my $listen = new IO::Socket::INET LocalPort => 10809, Listen => 1; |
258 | #my $listen = new IO::Socket::INET LocalPort => 10809, Listen => 1; |
230 | unlink "/tmp/nbdsock"; |
259 | unlink "/tmp/nbdsock"; |
231 | my $listen = new IO::Socket::UNIX Local => "/tmp/nbdsock", Listen => 1; |
260 | my $listen = new IO::Socket::UNIX Local => "/tmp/nbdsock", Listen => 1; |
232 | |
261 | |
233 | while () { |
262 | while () { |
234 | print "waiting for connections...\n"; |
263 | print "waiting for connections on nbd:unix:/tmp/nbdsock ...\n"; |
235 | my $fh = $listen->accept; |
264 | my $fh = $listen->accept; |
236 | print "accepted.\n"; |
265 | print "accepted.\n"; |
237 | |
266 | |
238 | syswrite $fh, |
267 | syswrite $fh, |
239 | ("NBDMAGIC\x00\x00\x42\x02\x81\x86\x12\x53") |
268 | ("NBDMAGIC\x00\x00\x42\x02\x81\x86\x12\x53") |