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