xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/preadv/preadv03.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2018 FUJITSU LIMITED. All rights reserved.
4  * Author: Xiao Yang <[email protected]>
5  * Copyright (c) Linux Test Project, 2019-2023
6  */
7 
8 /*\
9  * [Description]
10  *
11  * Check the basic functionality of the preadv(2) for the file
12  * opened with O_DIRECT in all filesystem.
13  *
14  * preadv(2) should succeed to read the expected content of data
15  * and after reading the file, the file offset is not changed.
16  */
17 
18 #define _GNU_SOURCE
19 #include <stdlib.h>
20 #include <string.h>
21 #include <sys/uio.h>
22 #include <sys/ioctl.h>
23 #include <sys/mount.h>
24 #include "tst_test.h"
25 #include "preadv.h"
26 
27 #define MNTPOINT	"mntpoint"
28 #define FNAME	MNTPOINT"/file"
29 
30 static int fd;
31 static off_t blk_off, zero_off;
32 static ssize_t blksz;
33 static char *pop_buf;
34 
35 static struct iovec rd_iovec[] = {
36 	{NULL, 0},
37 	{NULL, 0},
38 };
39 
40 static struct tcase {
41 	int count;
42 	off_t *offset;
43 	ssize_t *size;
44 	char content;
45 } tcases[] = {
46 	{1, &zero_off, &blksz, 0x61},
47 	{2, &zero_off, &blksz, 0x61},
48 	{1, &blk_off, &blksz, 0x62},
49 };
50 
verify_direct_preadv(unsigned int n)51 static void verify_direct_preadv(unsigned int n)
52 {
53 	int i;
54 	char *vec;
55 	struct tcase *tc = &tcases[n];
56 
57 	vec = rd_iovec[0].iov_base;
58 	memset(vec, 0x00, blksz);
59 
60 	SAFE_LSEEK(fd, 0, SEEK_SET);
61 
62 	TEST(preadv(fd, rd_iovec, tc->count, *tc->offset));
63 	if (TST_RET < 0) {
64 		tst_res(TFAIL | TTERRNO, "preadv(O_DIRECT) fails");
65 		return;
66 	}
67 
68 	if (TST_RET != *tc->size) {
69 		tst_res(TFAIL, "preadv(O_DIRECT) read %li bytes, expected %zi",
70 			 TST_RET, *tc->size);
71 		return;
72 	}
73 
74 	for (i = 0; i < *tc->size; i++) {
75 		if (vec[i] != tc->content)
76 			break;
77 	}
78 
79 	if (i < *tc->size) {
80 		tst_res(TFAIL, "Buffer wrong at %i have %02x expected %02x",
81 			 i, vec[i], tc->content);
82 		return;
83 	}
84 
85 	if (SAFE_LSEEK(fd, 0, SEEK_CUR) != 0) {
86 		tst_res(TFAIL, "preadv(O_DIRECT) has changed file offset");
87 		return;
88 	}
89 
90 	tst_res(TPASS, "preadv(O_DIRECT) read %zi bytes successfully "
91 		 "with content '%c' expectedly", *tc->size, tc->content);
92 }
93 
setup(void)94 static void setup(void)
95 {
96 	int dev_fd, ret;
97 
98 	dev_fd = SAFE_OPEN(tst_device->dev, O_RDWR);
99 	SAFE_IOCTL(dev_fd, BLKSSZGET, &ret);
100 	SAFE_CLOSE(dev_fd);
101 
102 	if (ret <= 0)
103 		tst_brk(TBROK, "BLKSSZGET returned invalid block size %i", ret);
104 
105 	tst_res(TINFO, "Using block size %i", ret);
106 
107 	blksz = ret;
108 	blk_off = ret;
109 
110 	fd = SAFE_OPEN(FNAME, O_RDWR | O_CREAT | O_DIRECT, 0644);
111 
112 	pop_buf = SAFE_MEMALIGN(blksz, blksz);
113 	memset(pop_buf, 0x61, blksz);
114 	SAFE_WRITE(SAFE_WRITE_ALL, fd, pop_buf, blksz);
115 
116 	memset(pop_buf, 0x62, blksz);
117 	SAFE_WRITE(SAFE_WRITE_ALL, fd, pop_buf, blksz);
118 
119 	rd_iovec[0].iov_base = SAFE_MEMALIGN(blksz, blksz);
120 	rd_iovec[0].iov_len = blksz;
121 }
122 
cleanup(void)123 static void cleanup(void)
124 {
125 	free(pop_buf);
126 	free(rd_iovec[0].iov_base);
127 
128 	if (fd > 0)
129 		SAFE_CLOSE(fd);
130 }
131 
132 static struct tst_test test = {
133 	.tcnt = ARRAY_SIZE(tcases),
134 	.setup = setup,
135 	.cleanup = cleanup,
136 	.test = verify_direct_preadv,
137 	.mntpoint = MNTPOINT,
138 	.mount_device = 1,
139 	.all_filesystems = 1,
140 	.skip_filesystems = (const char *[]) {
141 		"tmpfs",
142 		NULL
143 	}
144 };
145