1*aef96d7dSFam Zheng /* 2*aef96d7dSFam Zheng * Image locking tests 3*aef96d7dSFam Zheng * 4*aef96d7dSFam Zheng * Copyright (c) 2018 Red Hat Inc. 5*aef96d7dSFam Zheng * 6*aef96d7dSFam Zheng * Author: Fam Zheng <famz@redhat.com> 7*aef96d7dSFam Zheng * 8*aef96d7dSFam Zheng * Permission is hereby granted, free of charge, to any person obtaining a copy 9*aef96d7dSFam Zheng * of this software and associated documentation files (the "Software"), to deal 10*aef96d7dSFam Zheng * in the Software without restriction, including without limitation the rights 11*aef96d7dSFam Zheng * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12*aef96d7dSFam Zheng * copies of the Software, and to permit persons to whom the Software is 13*aef96d7dSFam Zheng * furnished to do so, subject to the following conditions: 14*aef96d7dSFam Zheng * 15*aef96d7dSFam Zheng * The above copyright notice and this permission notice shall be included in 16*aef96d7dSFam Zheng * all copies or substantial portions of the Software. 17*aef96d7dSFam Zheng * 18*aef96d7dSFam Zheng * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19*aef96d7dSFam Zheng * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20*aef96d7dSFam Zheng * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21*aef96d7dSFam Zheng * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22*aef96d7dSFam Zheng * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23*aef96d7dSFam Zheng * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24*aef96d7dSFam Zheng * THE SOFTWARE. 25*aef96d7dSFam Zheng */ 26*aef96d7dSFam Zheng 27*aef96d7dSFam Zheng #include "qemu/osdep.h" 28*aef96d7dSFam Zheng #include "block/block.h" 29*aef96d7dSFam Zheng #include "sysemu/block-backend.h" 30*aef96d7dSFam Zheng #include "qapi/error.h" 31*aef96d7dSFam Zheng #include "qapi/qmp/qdict.h" 32*aef96d7dSFam Zheng 33*aef96d7dSFam Zheng static BlockBackend *open_image(const char *path, 34*aef96d7dSFam Zheng uint64_t perm, uint64_t shared_perm, 35*aef96d7dSFam Zheng Error **errp) 36*aef96d7dSFam Zheng { 37*aef96d7dSFam Zheng Error *local_err = NULL; 38*aef96d7dSFam Zheng BlockBackend *blk; 39*aef96d7dSFam Zheng QDict *options = qdict_new(); 40*aef96d7dSFam Zheng 41*aef96d7dSFam Zheng qdict_put_str(options, "driver", "raw"); 42*aef96d7dSFam Zheng blk = blk_new_open(path, NULL, options, BDRV_O_RDWR, &local_err); 43*aef96d7dSFam Zheng if (blk) { 44*aef96d7dSFam Zheng g_assert_null(local_err); 45*aef96d7dSFam Zheng if (blk_set_perm(blk, perm, shared_perm, errp)) { 46*aef96d7dSFam Zheng blk_unref(blk); 47*aef96d7dSFam Zheng blk = NULL; 48*aef96d7dSFam Zheng } 49*aef96d7dSFam Zheng } else { 50*aef96d7dSFam Zheng error_propagate(errp, local_err); 51*aef96d7dSFam Zheng } 52*aef96d7dSFam Zheng return blk; 53*aef96d7dSFam Zheng } 54*aef96d7dSFam Zheng 55*aef96d7dSFam Zheng static void check_locked_bytes(int fd, uint64_t perm_locks, 56*aef96d7dSFam Zheng uint64_t shared_perm_locks) 57*aef96d7dSFam Zheng { 58*aef96d7dSFam Zheng int i; 59*aef96d7dSFam Zheng 60*aef96d7dSFam Zheng if (!perm_locks && !shared_perm_locks) { 61*aef96d7dSFam Zheng g_assert(!qemu_lock_fd_test(fd, 0, 0, true)); 62*aef96d7dSFam Zheng return; 63*aef96d7dSFam Zheng } 64*aef96d7dSFam Zheng for (i = 0; (1ULL << i) <= BLK_PERM_ALL; i++) { 65*aef96d7dSFam Zheng uint64_t bit = (1ULL << i); 66*aef96d7dSFam Zheng bool perm_expected = !!(bit & perm_locks); 67*aef96d7dSFam Zheng bool shared_perm_expected = !!(bit & shared_perm_locks); 68*aef96d7dSFam Zheng g_assert_cmpint(perm_expected, ==, 69*aef96d7dSFam Zheng !!qemu_lock_fd_test(fd, 100 + i, 1, true)); 70*aef96d7dSFam Zheng g_assert_cmpint(shared_perm_expected, ==, 71*aef96d7dSFam Zheng !!qemu_lock_fd_test(fd, 200 + i, 1, true)); 72*aef96d7dSFam Zheng } 73*aef96d7dSFam Zheng } 74*aef96d7dSFam Zheng 75*aef96d7dSFam Zheng static void test_image_locking_basic(void) 76*aef96d7dSFam Zheng { 77*aef96d7dSFam Zheng BlockBackend *blk1, *blk2, *blk3; 78*aef96d7dSFam Zheng char img_path[] = "/tmp/qtest.XXXXXX"; 79*aef96d7dSFam Zheng uint64_t perm, shared_perm; 80*aef96d7dSFam Zheng 81*aef96d7dSFam Zheng int fd = mkstemp(img_path); 82*aef96d7dSFam Zheng assert(fd >= 0); 83*aef96d7dSFam Zheng 84*aef96d7dSFam Zheng perm = BLK_PERM_WRITE | BLK_PERM_CONSISTENT_READ; 85*aef96d7dSFam Zheng shared_perm = BLK_PERM_ALL; 86*aef96d7dSFam Zheng blk1 = open_image(img_path, perm, shared_perm, &error_abort); 87*aef96d7dSFam Zheng g_assert(blk1); 88*aef96d7dSFam Zheng 89*aef96d7dSFam Zheng check_locked_bytes(fd, perm, ~shared_perm); 90*aef96d7dSFam Zheng 91*aef96d7dSFam Zheng /* compatible perm between blk1 and blk2 */ 92*aef96d7dSFam Zheng blk2 = open_image(img_path, perm | BLK_PERM_RESIZE, shared_perm, NULL); 93*aef96d7dSFam Zheng g_assert(blk2); 94*aef96d7dSFam Zheng check_locked_bytes(fd, perm | BLK_PERM_RESIZE, ~shared_perm); 95*aef96d7dSFam Zheng 96*aef96d7dSFam Zheng /* incompatible perm with already open blk1 and blk2 */ 97*aef96d7dSFam Zheng blk3 = open_image(img_path, perm, BLK_PERM_WRITE_UNCHANGED, NULL); 98*aef96d7dSFam Zheng g_assert_null(blk3); 99*aef96d7dSFam Zheng 100*aef96d7dSFam Zheng blk_unref(blk2); 101*aef96d7dSFam Zheng 102*aef96d7dSFam Zheng /* Check that extra bytes in blk2 are correctly unlocked */ 103*aef96d7dSFam Zheng check_locked_bytes(fd, perm, ~shared_perm); 104*aef96d7dSFam Zheng 105*aef96d7dSFam Zheng blk_unref(blk1); 106*aef96d7dSFam Zheng 107*aef96d7dSFam Zheng /* Image is unused, no lock there */ 108*aef96d7dSFam Zheng check_locked_bytes(fd, 0, 0); 109*aef96d7dSFam Zheng blk3 = open_image(img_path, perm, BLK_PERM_WRITE_UNCHANGED, &error_abort); 110*aef96d7dSFam Zheng g_assert(blk3); 111*aef96d7dSFam Zheng blk_unref(blk3); 112*aef96d7dSFam Zheng close(fd); 113*aef96d7dSFam Zheng unlink(img_path); 114*aef96d7dSFam Zheng } 115*aef96d7dSFam Zheng 116*aef96d7dSFam Zheng static void test_set_perm_abort(void) 117*aef96d7dSFam Zheng { 118*aef96d7dSFam Zheng BlockBackend *blk1, *blk2; 119*aef96d7dSFam Zheng char img_path[] = "/tmp/qtest.XXXXXX"; 120*aef96d7dSFam Zheng uint64_t perm, shared_perm; 121*aef96d7dSFam Zheng int r; 122*aef96d7dSFam Zheng int fd = mkstemp(img_path); 123*aef96d7dSFam Zheng assert(fd >= 0); 124*aef96d7dSFam Zheng 125*aef96d7dSFam Zheng perm = BLK_PERM_WRITE | BLK_PERM_CONSISTENT_READ; 126*aef96d7dSFam Zheng shared_perm = BLK_PERM_ALL; 127*aef96d7dSFam Zheng blk1 = open_image(img_path, perm, shared_perm, &error_abort); 128*aef96d7dSFam Zheng g_assert(blk1); 129*aef96d7dSFam Zheng 130*aef96d7dSFam Zheng blk2 = open_image(img_path, perm, shared_perm, &error_abort); 131*aef96d7dSFam Zheng g_assert(blk2); 132*aef96d7dSFam Zheng 133*aef96d7dSFam Zheng check_locked_bytes(fd, perm, ~shared_perm); 134*aef96d7dSFam Zheng 135*aef96d7dSFam Zheng /* A failed blk_set_perm mustn't change perm status (locked bytes) */ 136*aef96d7dSFam Zheng r = blk_set_perm(blk2, perm | BLK_PERM_RESIZE, BLK_PERM_WRITE_UNCHANGED, 137*aef96d7dSFam Zheng NULL); 138*aef96d7dSFam Zheng g_assert_cmpint(r, !=, 0); 139*aef96d7dSFam Zheng check_locked_bytes(fd, perm, ~shared_perm); 140*aef96d7dSFam Zheng blk_unref(blk1); 141*aef96d7dSFam Zheng blk_unref(blk2); 142*aef96d7dSFam Zheng } 143*aef96d7dSFam Zheng 144*aef96d7dSFam Zheng int main(int argc, char **argv) 145*aef96d7dSFam Zheng { 146*aef96d7dSFam Zheng bdrv_init(); 147*aef96d7dSFam Zheng qemu_init_main_loop(&error_abort); 148*aef96d7dSFam Zheng 149*aef96d7dSFam Zheng g_test_init(&argc, &argv, NULL); 150*aef96d7dSFam Zheng 151*aef96d7dSFam Zheng if (qemu_has_ofd_lock()) { 152*aef96d7dSFam Zheng g_test_add_func("/image-locking/basic", test_image_locking_basic); 153*aef96d7dSFam Zheng g_test_add_func("/image-locking/set-perm-abort", test_set_perm_abort); 154*aef96d7dSFam Zheng } 155*aef96d7dSFam Zheng 156*aef96d7dSFam Zheng return g_test_run(); 157*aef96d7dSFam Zheng } 158