@@ -379,6 +379,78 @@ async def _test_005_size_after_clone(self):
379379 await qubes .utils .coro_maybe (testvol2 .import_volume (testvol ))
380380 self .assertEqual (testvol2 .size , size )
381381
382+ def test_006_no_revisions (self ):
383+ """Test if no-revisions volume persists data, and blocks parallel
384+ access"""
385+ return self .loop .run_until_complete (self ._test_006_no_revisions ())
386+
387+ async def _test_006_no_revisions (self ):
388+ self .vm1 .storage .set_revisions_to_keep ("private" , - 1 )
389+
390+ size = 32 * 1024 * 1024
391+ volume_config = {
392+ "pool" : self .pool .name ,
393+ "size" : size ,
394+ "save_on_stop" : True ,
395+ "rw" : True ,
396+ "revisions_to_keep" : - 1 ,
397+ }
398+ testvol = self .vm1 .storage .init_volume ("testvol" , volume_config )
399+ await qubes .utils .coro_maybe (testvol .create ())
400+ volume2_config = {
401+ "pool" : self .pool .name ,
402+ "size" : size ,
403+ "snap_on_start" : True ,
404+ "source" : testvol .vid ,
405+ "rw" : True ,
406+ }
407+ testvol2 = self .vm2 .storage .init_volume ("testvol2" , volume2_config )
408+ await qubes .utils .coro_maybe (testvol2 .create ())
409+ del testvol
410+ del testvol2
411+ self .app .save ()
412+ await self .vm1 .start ()
413+ await self .wait_for_session (self .vm1 )
414+ # non-volatile image not clean
415+ await self .vm1 .run_for_stdio (
416+ "head -c {} /dev/zero 2>&1 | diff -q /dev/xvde - 2>&1" .format (size ),
417+ user = "root" ,
418+ )
419+
420+ await self .vm1 .run_for_stdio ("echo test123 > /dev/xvde" , user = "root" )
421+ await self .vm1 .shutdown (wait = True )
422+ await self .vm1 .start ()
423+ # non-volatile image volatile
424+ with self .assertRaises (subprocess .CalledProcessError ):
425+ await self .vm1 .run_for_stdio (
426+ "head -c {} /dev/zero 2>&1 | diff -q /dev/xvde - 2>&1" .format (
427+ size
428+ ),
429+ user = "root" ,
430+ )
431+
432+ # should not work
433+ with self .assertRaises (qubes .exc .QubesException ):
434+ await self .vm2 .start ()
435+ with self .assertRaises (qubes .exc .QubesException ):
436+ await self .vm2 .storage .clone_volume (self .vm1 , "private" )
437+ with self .assertRaises (qubes .exc .QubesException ):
438+ path = await self .vm1 .storage .export ("testvol" )
439+ # just in case it was allowed...
440+ await self .vm1 .storage .export_end ("testvol" , path )
441+
442+ # now shutdown vm1 and the above operations should work
443+ await self .vm1 .shutdown (wait = True )
444+ await self .vm2 .storage .clone_volume (self .vm1 , "private" )
445+ path = await self .vm1 .storage .export ("testvol" )
446+ await self .vm1 .storage .export_end ("testvol" , path )
447+
448+ await self .vm2 .start ()
449+ stdout , stderr = await self .vm2 .run_for_stdio (
450+ "head -c 7 /dev/xvde" , user = "root"
451+ )
452+ self .assertEqual (stdout , b"test123" )
453+
382454
383455class StorageFile (StorageTestMixin , qubes .tests .SystemTestCase ):
384456 def init_pool (self ):
0 commit comments