• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2018 FUJITSU LIMITED. All rights reserved.
3  * Author: Xiao Yang <yangx.jy@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 
verify_direct_preadv(unsigned int n)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 
setup(void)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 
cleanup(void)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