@@ -145,19 +145,6 @@ async fn in_memory_backend_smoke_test(ctx: &Framework) {
145
145
146
146
#[ phd_testcase]
147
147
async fn in_memory_backend_migration_test ( ctx : & Framework ) {
148
- // This test verifies that live-migrating a disk with an in-memory backend
149
- // copies the backend's data from the source to the target. To do that, it
150
- // uses `dd` flags to (try to) force writes to be synchronized to disk
151
- // immediately and to force reads to bypass the guest OS's caches.
152
- //
153
- // Dynamic tracing of block backend activity shows that Alpine guests don't
154
- // reliably read from underlying storage even when `iflag=direct` is used.
155
- // This can cause this test to pass incorrectly. Unless and until a more
156
- // reliable way to bypass caches is found, skip this test on Alpine.
157
- if let GuestOsKind :: Alpine = ctx. default_guest_os_kind ( ) . await ? {
158
- phd_skip ! ( "iflag=direct doesn't work as required on Alpine" ) ;
159
- }
160
-
161
148
// A blank disk is fine for this test: the rest of the test will address the
162
149
// disk device directly instead of assuming it has a file system. This works
163
150
// around #824 for Windows guests (which may not recognize the FAT
@@ -170,11 +157,17 @@ async fn in_memory_backend_migration_test(ctx: &Framework) {
170
157
)
171
158
. await ?;
172
159
173
- // Scribble random data into the first kilobyte of the data disk. Use
174
- // `oflag=sync` to force the guest OS to ensure this data is actually
175
- // persisted to the device (and not just held in an in-memory cache).
160
+ // Scribble random data into the first kilobyte of the data disk, passing
161
+ // the appropriate flags to ensure that the guest actually writes the data
162
+ // to the disk (instead of just holding it in memory).
163
+ let force_sync = if let GuestOsKind :: Alpine = vm. guest_os_kind ( ) {
164
+ "conv=sync"
165
+ } else {
166
+ "oflag=sync"
167
+ } ;
168
+
176
169
vm. run_shell_command ( & format ! (
177
- "dd if=/dev/random of={device_path} oflag=sync bs=1K count=1"
170
+ "dd if=/dev/random of={device_path} {force_sync} bs=1K count=1"
178
171
) )
179
172
. await ?;
180
173
@@ -197,15 +190,24 @@ async fn in_memory_backend_migration_test(ctx: &Framework) {
197
190
. migrate_from ( & vm, Uuid :: new_v4 ( ) , MigrationTimeout :: default ( ) )
198
191
. await ?;
199
192
200
- // Read the scribbled data again. Use `iflag=direct` to try to get the guest
201
- // to read this data back from the physical device instead of its disk
202
- // cache.
193
+ // Read the scribbled data back from the disk. On most guests, adding
194
+ // `iflag=direct` to the `dd` invocation is sufficient to bypass the guest's
195
+ // caches and read from the underlying disk. Alpine guests appear also to
196
+ // need a procfs poke to drop page caches before they'll read from the disk.
197
+ if let GuestOsKind :: Alpine = vm. guest_os_kind ( ) {
198
+ target. run_shell_command ( "sync" ) . await ?;
199
+ target. run_shell_command ( "echo 3 > /proc/sys/vm/drop_caches" ) . await ?;
200
+ }
201
+
203
202
target
204
203
. run_shell_command ( & format ! (
205
204
"dd if={device_path} of=/tmp/after iflag=direct bs=1K"
206
205
) )
207
206
. await ?;
208
207
208
+ // The data that was scribbled before migrating should match what was read
209
+ // back from the disk. If it doesn't, migration restored the original
210
+ // (blank) disk contents, which is incorrect.
209
211
let out = target
210
212
. run_shell_command ( "diff --report-identical /tmp/before /tmp/after" )
211
213
. await ?;
0 commit comments