1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (c) 2020 FUJITSU LIMITED. All rights reserved. 4 * Copyright (c) Linux Test Project, 2022 5 * Author: Yang Xu <xuyang2018.jy@cn.jujitsu.com> 6 */ 7 8/*\ 9 * [Description] 10 * 11 * Tests ioctl() on loopdevice with LOOP_SET_STATUS64 and LOOP_GET_STATUS64 flags. 12 * 13 * Tests lo_sizelimit field. If lo_sizelimit is 0, it means max 14 * available. If sizelimit is less than loop_size, loopsize will 15 * be truncated. 16 * 17 * Also uses LOOP_CONFIGURE ioctl to test lo_sizelimit field. 18 */ 19 20#include <stdio.h> 21#include <unistd.h> 22#include <sys/types.h> 23#include <stdlib.h> 24#include "lapi/loop.h" 25#include "tst_test.h" 26 27static char dev_path[1024], sys_loop_sizepath[1024], sys_loop_sizelimitpath[1024]; 28static int dev_num, dev_fd, file_fd, attach_flag, loop_configure_sup = 1; 29static struct loop_config loopconfig; 30 31static struct tcase { 32 unsigned int set_sizelimit; 33 unsigned int exp_loopsize; 34 int ioctl_flag; 35 char *message; 36} tcases[] = { 37 {1024 * 4096, 2048, LOOP_SET_STATUS64, 38 "When sizelimit is greater than loopsize by using LOOP_SET_STATUS64"}, 39 40 {1024 * 512, 1024, LOOP_SET_STATUS64, 41 "When sizelimit is less than loopsize by using LOOP_SET_STATUS64"}, 42 43 {1024 * 4096, 2048, LOOP_CONFIGURE, 44 "When sizelimit is greater than loopsize by using LOOP_CONFIGURE"}, 45 46 {1024 * 512, 1024, LOOP_CONFIGURE, 47 "When sizelimit is less than loopsize by using LOOP_CONFIGURE"}, 48}; 49 50static void verify_ioctl_loop(unsigned int n) 51{ 52 struct tcase *tc = &tcases[n]; 53 struct loop_info64 loopinfo, loopinfoget; 54 55 memset(&loopinfo, 0, sizeof(loopinfo)); 56 memset(&loopinfoget, 0, sizeof(loopinfoget)); 57 58 if (tc->ioctl_flag == LOOP_CONFIGURE) { 59 SAFE_IOCTL(dev_fd, LOOP_CONFIGURE, &loopconfig); 60 } else { 61 loopinfo.lo_sizelimit = tc->set_sizelimit; 62 TST_RETRY_FUNC(ioctl(dev_fd, LOOP_SET_STATUS64, &loopinfo), TST_RETVAL_EQ0); 63 } 64 65 TST_ASSERT_INT(sys_loop_sizepath, tc->exp_loopsize); 66 TST_ASSERT_INT(sys_loop_sizelimitpath, tc->set_sizelimit); 67 SAFE_IOCTL(dev_fd, LOOP_GET_STATUS64, &loopinfoget); 68 if (loopinfoget.lo_sizelimit == tc->set_sizelimit) 69 tst_res(TPASS, "LOOP_GET_STATUS64 gets correct lo_sizelimit(%d)", tc->set_sizelimit); 70 else 71 tst_res(TFAIL, "LOOP_GET_STATUS64 gets wrong lo_sizelimit(%llu), expect %d", 72 loopinfoget.lo_sizelimit, tc->set_sizelimit); 73 /*Reset*/ 74 if (tc->ioctl_flag == LOOP_CONFIGURE) { 75 tst_detach_device_by_fd(dev_path, dev_fd); 76 } else { 77 loopinfo.lo_sizelimit = 0; 78 TST_RETRY_FUNC(ioctl(dev_fd, LOOP_SET_STATUS, &loopinfo), TST_RETVAL_EQ0); 79 } 80} 81 82static void run(unsigned int n) 83{ 84 struct tcase *tc = &tcases[n]; 85 86 tst_res(TINFO, "%s", tc->message); 87 88 if (tc->ioctl_flag == LOOP_SET_STATUS64) { 89 if (!attach_flag) { 90 tst_attach_device(dev_path, "test.img"); 91 attach_flag = 1; 92 } 93 94 verify_ioctl_loop(n); 95 return; 96 } 97 98 if (tc->ioctl_flag == LOOP_CONFIGURE && !loop_configure_sup) { 99 tst_res(TCONF, "LOOP_CONFIGURE ioctl not supported"); 100 return; 101 } 102 if (attach_flag) { 103 tst_detach_device_by_fd(dev_path, dev_fd); 104 attach_flag = 0; 105 } 106 loopconfig.info.lo_sizelimit = tc->set_sizelimit; 107 verify_ioctl_loop(n); 108} 109 110static void setup(void) 111{ 112 int ret; 113 114 dev_num = tst_find_free_loopdev(dev_path, sizeof(dev_path)); 115 if (dev_num < 0) 116 tst_brk(TBROK, "Failed to find free loop device"); 117 118 tst_fill_file("test.img", 0, 1024 * 1024, 1); 119 tst_attach_device(dev_path, "test.img"); 120 attach_flag = 1; 121 122 sprintf(sys_loop_sizepath, "/sys/block/loop%d/size", dev_num); 123 sprintf(sys_loop_sizelimitpath, "/sys/block/loop%d/loop/sizelimit", dev_num); 124 125 tst_detach_device(dev_path); 126 attach_flag = 0; 127 128 tst_res(TINFO, "original loop size 2048 sectors"); 129 file_fd = SAFE_OPEN("test.img", O_RDWR); 130 dev_fd = SAFE_OPEN(dev_path, O_RDWR); 131 132 loopconfig.fd = -1; 133 ret = ioctl(dev_fd, LOOP_CONFIGURE, &loopconfig); 134 if (ret && errno != EBADF) { 135 tst_res(TINFO | TERRNO, "LOOP_CONFIGURE is not supported"); 136 loop_configure_sup = 0; 137 return; 138 } 139 140 loopconfig.fd = file_fd; 141} 142 143static void cleanup(void) 144{ 145 if (dev_fd > 0) 146 SAFE_CLOSE(dev_fd); 147 if (file_fd > 0) 148 SAFE_CLOSE(file_fd); 149 if (attach_flag) 150 tst_detach_device(dev_path); 151} 152 153static struct tst_test test = { 154 .setup = setup, 155 .cleanup = cleanup, 156 .test = run, 157 .tcnt = ARRAY_SIZE(tcases), 158 .needs_root = 1, 159 .needs_tmpdir = 1, 160 .tags = (const struct tst_tag[]) { 161 {"linux-git", "79e5dc59e297"}, 162 {} 163 }, 164 .needs_drivers = (const char *const []) { 165 "loop", 166 NULL 167 } 168}; 169