1 /* 2 * Copyright (c) 2018 FUJITSU LIMITED. All rights reserved. 3 * Author: Xiao Yang <yangx.jy (at) cn.fujitsu.com> 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 /* 20 * Description: 21 * Check the basic functionality of the preadv(2) for the file 22 * opened with O_DIRECT in all filesystem. 23 * preadv(2) should succeed to read the expected content of data 24 * and after reading the file, the file offset is not changed. 25 */ 26 27 #define _GNU_SOURCE 28 #include <stdlib.h> 29 #include <string.h> 30 #include <sys/uio.h> 31 #include <sys/ioctl.h> 32 #include <sys/mount.h> 33 #include "tst_test.h" 34 #include "preadv.h" 35 36 #define MNTPOINT "mntpoint" 37 #define FNAME MNTPOINT"/file" 38 39 static int fd; 40 static off_t blk_off, zero_off; 41 static ssize_t blksz; 42 static char *pop_buf; 43 44 static struct iovec rd_iovec[] = { 45 {NULL, 0}, 46 {NULL, 0}, 47 }; 48 49 static struct tcase { 50 int count; 51 off_t *offset; 52 ssize_t *size; 53 char content; 54 } tcases[] = { 55 {1, &zero_off, &blksz, 0x61}, 56 {2, &zero_off, &blksz, 0x61}, 57 {1, &blk_off, &blksz, 0x62}, 58 }; 59 60 static void verify_direct_preadv(unsigned int n) 61 { 62 int i; 63 char *vec; 64 struct tcase *tc = &tcases[n]; 65 66 vec = rd_iovec[0].iov_base; 67 memset(vec, 0x00, blksz); 68 69 SAFE_LSEEK(fd, 0, SEEK_SET); 70 71 TEST(preadv(fd, rd_iovec, tc->count, *tc->offset)); 72 if (TST_RET < 0) { 73 tst_res(TFAIL | TTERRNO, "preadv(O_DIRECT) fails"); 74 return; 75 } 76 77 if (TST_RET != *tc->size) { 78 tst_res(TFAIL, "preadv(O_DIRECT) read %li bytes, expected %zi", 79 TST_RET, *tc->size); 80 return; 81 } 82 83 for (i = 0; i < *tc->size; i++) { 84 if (vec[i] != tc->content) 85 break; 86 } 87 88 if (i < *tc->size) { 89 tst_res(TFAIL, "Buffer wrong at %i have %02x expected %02x", 90 i, vec[i], tc->content); 91 return; 92 } 93 94 if (SAFE_LSEEK(fd, 0, SEEK_CUR) != 0) { 95 tst_res(TFAIL, "preadv(O_DIRECT) has changed file offset"); 96 return; 97 } 98 99 tst_res(TPASS, "preadv(O_DIRECT) read %zi bytes successfully " 100 "with content '%c' expectedly", *tc->size, tc->content); 101 } 102 103 static void setup(void) 104 { 105 int dev_fd, ret; 106 107 dev_fd = SAFE_OPEN(tst_device->dev, O_RDWR); 108 SAFE_IOCTL(dev_fd, BLKSSZGET, &ret); 109 SAFE_CLOSE(dev_fd); 110 111 if (ret <= 0) 112 tst_brk(TBROK, "BLKSSZGET returned invalid block size %i", ret); 113 114 tst_res(TINFO, "Using block size %i", ret); 115 116 blksz = ret; 117 blk_off = ret; 118 119 fd = SAFE_OPEN(FNAME, O_RDWR | O_CREAT | O_DIRECT, 0644); 120 121 pop_buf = SAFE_MEMALIGN(blksz, blksz); 122 memset(pop_buf, 0x61, blksz); 123 SAFE_WRITE(1, fd, pop_buf, blksz); 124 125 memset(pop_buf, 0x62, blksz); 126 SAFE_WRITE(1, fd, pop_buf, blksz); 127 128 rd_iovec[0].iov_base = SAFE_MEMALIGN(blksz, blksz); 129 rd_iovec[0].iov_len = blksz; 130 } 131 132 static void cleanup(void) 133 { 134 free(pop_buf); 135 free(rd_iovec[0].iov_base); 136 137 if (fd > 0) 138 SAFE_CLOSE(fd); 139 } 140 141 static struct tst_test test = { 142 .tcnt = ARRAY_SIZE(tcases), 143 .setup = setup, 144 .cleanup = cleanup, 145 .test = verify_direct_preadv, 146 .min_kver = "2.6.30", 147 .mntpoint = MNTPOINT, 148 .mount_device = 1, 149 .all_filesystems = 1, 150 }; 151