1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) 2020 FUJITSU LIMITED. All rights reserved. 4f08c3bdfSopenharmony_ci * Copyright (c) Linux Test Project, 2022 5f08c3bdfSopenharmony_ci * Author: Yang Xu <xuyang2018.jy@cn.jujitsu.com> 6f08c3bdfSopenharmony_ci */ 7f08c3bdfSopenharmony_ci 8f08c3bdfSopenharmony_ci/*\ 9f08c3bdfSopenharmony_ci * [Description] 10f08c3bdfSopenharmony_ci * 11f08c3bdfSopenharmony_ci * Tests ioctl() on loopdevice with LO_FLAGS_READ_ONLY (similar as losetup -r) and 12f08c3bdfSopenharmony_ci * LOOP_CHANGE_FD flags. 13f08c3bdfSopenharmony_ci * 14f08c3bdfSopenharmony_ci * For LOOP_CHANGE_FD, this operation is possible only if the loop device 15f08c3bdfSopenharmony_ci * is read-only and the new backing store is the same size and type as the 16f08c3bdfSopenharmony_ci * old backing store. 17f08c3bdfSopenharmony_ci * 18f08c3bdfSopenharmony_ci * When using LOOP_CONFIGURE ioctl(), it can set LO_FLAGS_READ_ONLY 19f08c3bdfSopenharmony_ci * flag even though backing file with write mode. 20f08c3bdfSopenharmony_ci */ 21f08c3bdfSopenharmony_ci 22f08c3bdfSopenharmony_ci#include <stdio.h> 23f08c3bdfSopenharmony_ci#include <unistd.h> 24f08c3bdfSopenharmony_ci#include <string.h> 25f08c3bdfSopenharmony_ci#include <stdlib.h> 26f08c3bdfSopenharmony_ci#include "lapi/loop.h" 27f08c3bdfSopenharmony_ci#include "tst_test.h" 28f08c3bdfSopenharmony_ci 29f08c3bdfSopenharmony_cistatic int file_fd, file_change_fd, file_fd_invalid; 30f08c3bdfSopenharmony_cistatic char backing_path[1024], backing_file_path[1024], backing_file_change_path[1024]; 31f08c3bdfSopenharmony_cistatic int attach_flag, dev_fd, loop_configure_sup = 1; 32f08c3bdfSopenharmony_cistatic char loop_ro_path[1024], dev_path[1024]; 33f08c3bdfSopenharmony_cistatic struct loop_config loopconfig; 34f08c3bdfSopenharmony_ci 35f08c3bdfSopenharmony_cistatic struct tcase { 36f08c3bdfSopenharmony_ci int mode; 37f08c3bdfSopenharmony_ci int ioctl; 38f08c3bdfSopenharmony_ci char *message; 39f08c3bdfSopenharmony_ci} tcases[] = { 40f08c3bdfSopenharmony_ci {O_RDONLY, LOOP_SET_FD, "Using LOOP_SET_FD to setup loopdevice"}, 41f08c3bdfSopenharmony_ci {O_RDWR, LOOP_CONFIGURE, "Using LOOP_CONFIGURE with read_only flag"}, 42f08c3bdfSopenharmony_ci}; 43f08c3bdfSopenharmony_ci 44f08c3bdfSopenharmony_cistatic void verify_ioctl_loop(unsigned int n) 45f08c3bdfSopenharmony_ci{ 46f08c3bdfSopenharmony_ci struct tcase *tc = &tcases[n]; 47f08c3bdfSopenharmony_ci struct loop_info loopinfoget; 48f08c3bdfSopenharmony_ci 49f08c3bdfSopenharmony_ci if (tc->ioctl == LOOP_CONFIGURE && !loop_configure_sup) { 50f08c3bdfSopenharmony_ci tst_res(TCONF, "LOOP_CONFIGURE ioctl not supported"); 51f08c3bdfSopenharmony_ci return; 52f08c3bdfSopenharmony_ci } 53f08c3bdfSopenharmony_ci 54f08c3bdfSopenharmony_ci tst_res(TINFO, "%s", tc->message); 55f08c3bdfSopenharmony_ci file_fd = SAFE_OPEN("test.img", tc->mode); 56f08c3bdfSopenharmony_ci 57f08c3bdfSopenharmony_ci if (tc->ioctl == LOOP_SET_FD) { 58f08c3bdfSopenharmony_ci SAFE_IOCTL(dev_fd, LOOP_SET_FD, file_fd); 59f08c3bdfSopenharmony_ci } else { 60f08c3bdfSopenharmony_ci loopconfig.fd = file_fd; 61f08c3bdfSopenharmony_ci SAFE_IOCTL(dev_fd, LOOP_CONFIGURE, &loopconfig); 62f08c3bdfSopenharmony_ci } 63f08c3bdfSopenharmony_ci attach_flag = 1; 64f08c3bdfSopenharmony_ci 65f08c3bdfSopenharmony_ci TST_ASSERT_INT(loop_ro_path, 1); 66f08c3bdfSopenharmony_ci TST_ASSERT_STR(backing_path, backing_file_path); 67f08c3bdfSopenharmony_ci 68f08c3bdfSopenharmony_ci memset(&loopinfoget, 0, sizeof(loopinfoget)); 69f08c3bdfSopenharmony_ci 70f08c3bdfSopenharmony_ci SAFE_IOCTL(dev_fd, LOOP_GET_STATUS, &loopinfoget); 71f08c3bdfSopenharmony_ci 72f08c3bdfSopenharmony_ci if (loopinfoget.lo_flags & ~LO_FLAGS_READ_ONLY) 73f08c3bdfSopenharmony_ci tst_res(TFAIL, "lo_flags has unexpected %d flag", loopinfoget.lo_flags); 74f08c3bdfSopenharmony_ci else 75f08c3bdfSopenharmony_ci tst_res(TPASS, "lo_flags only has default LO_FLAGS_READ_ONLY flag"); 76f08c3bdfSopenharmony_ci 77f08c3bdfSopenharmony_ci TEST(write(dev_fd, "xx", 2)); 78f08c3bdfSopenharmony_ci if (TST_RET != -1) 79f08c3bdfSopenharmony_ci tst_res(TFAIL, "write succeed unexpectedly"); 80f08c3bdfSopenharmony_ci else 81f08c3bdfSopenharmony_ci tst_res(TPASS | TTERRNO, "Can not write data in RO mode"); 82f08c3bdfSopenharmony_ci 83f08c3bdfSopenharmony_ci TEST(ioctl(dev_fd, LOOP_CHANGE_FD, file_change_fd)); 84f08c3bdfSopenharmony_ci if (TST_RET) { 85f08c3bdfSopenharmony_ci tst_res(TFAIL | TTERRNO, "LOOP_CHANGE_FD failed"); 86f08c3bdfSopenharmony_ci } else { 87f08c3bdfSopenharmony_ci tst_res(TPASS, "LOOP_CHANGE_FD succeeded"); 88f08c3bdfSopenharmony_ci TST_ASSERT_INT(loop_ro_path, 1); 89f08c3bdfSopenharmony_ci TST_ASSERT_STR(backing_path, backing_file_change_path); 90f08c3bdfSopenharmony_ci } 91f08c3bdfSopenharmony_ci 92f08c3bdfSopenharmony_ci TEST(ioctl(dev_fd, LOOP_CHANGE_FD, file_fd_invalid)); 93f08c3bdfSopenharmony_ci if (TST_RET) { 94f08c3bdfSopenharmony_ci if (TST_ERR == EINVAL) 95f08c3bdfSopenharmony_ci tst_res(TPASS | TTERRNO, "LOOP_CHANGE_FD failed as expected"); 96f08c3bdfSopenharmony_ci else 97f08c3bdfSopenharmony_ci tst_res(TFAIL | TTERRNO, "LOOP_CHANGE_FD failed expected EINVAL got"); 98f08c3bdfSopenharmony_ci } else { 99f08c3bdfSopenharmony_ci tst_res(TFAIL, "LOOP_CHANGE_FD succeeded"); 100f08c3bdfSopenharmony_ci } 101f08c3bdfSopenharmony_ci 102f08c3bdfSopenharmony_ci SAFE_CLOSE(file_fd); 103f08c3bdfSopenharmony_ci tst_detach_device_by_fd(dev_path, dev_fd); 104f08c3bdfSopenharmony_ci attach_flag = 0; 105f08c3bdfSopenharmony_ci} 106f08c3bdfSopenharmony_ci 107f08c3bdfSopenharmony_cistatic void setup(void) 108f08c3bdfSopenharmony_ci{ 109f08c3bdfSopenharmony_ci int dev_num; 110f08c3bdfSopenharmony_ci int ret; 111f08c3bdfSopenharmony_ci 112f08c3bdfSopenharmony_ci char *tmpdir = tst_get_tmpdir(); 113f08c3bdfSopenharmony_ci dev_num = tst_find_free_loopdev(dev_path, sizeof(dev_path)); 114f08c3bdfSopenharmony_ci if (dev_num < 0) 115f08c3bdfSopenharmony_ci tst_brk(TBROK, "Failed to find free loop device"); 116f08c3bdfSopenharmony_ci 117f08c3bdfSopenharmony_ci tst_fill_file("test.img", 0, 1024, 10); 118f08c3bdfSopenharmony_ci tst_fill_file("test1.img", 0, 1024, 10); 119f08c3bdfSopenharmony_ci tst_fill_file("test2.img", 0, 2048, 20); 120f08c3bdfSopenharmony_ci 121f08c3bdfSopenharmony_ci sprintf(backing_path, "/sys/block/loop%d/loop/backing_file", dev_num); 122f08c3bdfSopenharmony_ci sprintf(backing_file_path, "%s/test.img", tmpdir); 123f08c3bdfSopenharmony_ci sprintf(backing_file_change_path, "%s/test1.img", tmpdir); 124f08c3bdfSopenharmony_ci sprintf(loop_ro_path, "/sys/block/loop%d/ro", dev_num); 125f08c3bdfSopenharmony_ci 126f08c3bdfSopenharmony_ci free(tmpdir); 127f08c3bdfSopenharmony_ci 128f08c3bdfSopenharmony_ci file_change_fd = SAFE_OPEN("test1.img", O_RDWR); 129f08c3bdfSopenharmony_ci file_fd_invalid = SAFE_OPEN("test2.img", O_RDWR); 130f08c3bdfSopenharmony_ci 131f08c3bdfSopenharmony_ci dev_fd = SAFE_OPEN(dev_path, O_RDWR); 132f08c3bdfSopenharmony_ci loopconfig.fd = -1; 133f08c3bdfSopenharmony_ci ret = ioctl(dev_fd, LOOP_CONFIGURE, &loopconfig); 134f08c3bdfSopenharmony_ci 135f08c3bdfSopenharmony_ci if (ret && errno != EBADF) { 136f08c3bdfSopenharmony_ci tst_res(TINFO | TERRNO, "LOOP_CONFIGURE is not supported"); 137f08c3bdfSopenharmony_ci loop_configure_sup = 0; 138f08c3bdfSopenharmony_ci } 139f08c3bdfSopenharmony_ci loopconfig.info.lo_flags = LO_FLAGS_READ_ONLY; 140f08c3bdfSopenharmony_ci} 141f08c3bdfSopenharmony_ci 142f08c3bdfSopenharmony_cistatic void cleanup(void) 143f08c3bdfSopenharmony_ci{ 144f08c3bdfSopenharmony_ci if (dev_fd > 0) 145f08c3bdfSopenharmony_ci SAFE_CLOSE(dev_fd); 146f08c3bdfSopenharmony_ci if (file_fd > 0) 147f08c3bdfSopenharmony_ci SAFE_CLOSE(file_fd); 148f08c3bdfSopenharmony_ci if (file_change_fd > 0) 149f08c3bdfSopenharmony_ci SAFE_CLOSE(file_change_fd); 150f08c3bdfSopenharmony_ci if (file_fd_invalid > 0) 151f08c3bdfSopenharmony_ci SAFE_CLOSE(file_fd_invalid); 152f08c3bdfSopenharmony_ci if (attach_flag) 153f08c3bdfSopenharmony_ci tst_detach_device(dev_path); 154f08c3bdfSopenharmony_ci} 155f08c3bdfSopenharmony_ci 156f08c3bdfSopenharmony_cistatic struct tst_test test = { 157f08c3bdfSopenharmony_ci .setup = setup, 158f08c3bdfSopenharmony_ci .cleanup = cleanup, 159f08c3bdfSopenharmony_ci .tcnt = ARRAY_SIZE(tcases), 160f08c3bdfSopenharmony_ci .test = verify_ioctl_loop, 161f08c3bdfSopenharmony_ci .needs_root = 1, 162f08c3bdfSopenharmony_ci .needs_tmpdir = 1, 163f08c3bdfSopenharmony_ci .needs_drivers = (const char *const []) { 164f08c3bdfSopenharmony_ci "loop", 165f08c3bdfSopenharmony_ci NULL 166f08c3bdfSopenharmony_ci } 167f08c3bdfSopenharmony_ci}; 168