overlay: getdents: support lseek

Refs: #1421
Change-Id: Ife7ab1b50159a5897552ff695bb001ada27ec934
This commit is contained in:
Masamichi Takagi
2019-11-13 15:51:20 +09:00
parent 7fc4272b89
commit 3c256e1a6c
5 changed files with 667 additions and 75 deletions

129
test/issues/1421/1421.c Normal file
View File

@@ -0,0 +1,129 @@
// test getdents d_off and lseek are coherent
#define _GNU_SOURCE
#include <dirent.h> /* Defines DT_* constants */
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
struct linux_dirent {
long d_ino;
off_t d_off;
unsigned short d_reclen;
char d_name[];
};
#define OFF_TABLE_SIZE (1UL << 20)
#define RECLEN_TABLE_SIZE (1UL << 20)
void print_dirent(char *buf, int bpos)
{
struct linux_dirent *d;
char d_type;
d = (struct linux_dirent *) (buf + bpos);
printf("%8ld ", d->d_ino);
d_type = *(buf + bpos + d->d_reclen - 1);
printf("%-10s ", (d_type == DT_REG) ? "regular" :
(d_type == DT_DIR) ? "directory" :
(d_type == DT_FIFO) ? "FIFO" :
(d_type == DT_SOCK) ? "socket" :
(d_type == DT_LNK) ? "symlink" :
(d_type == DT_BLK) ? "block dev" :
(d_type == DT_CHR) ? "char dev" : "???");
printf("%4d %10lld %s\n", d->d_reclen,
(long long) d->d_off, (char *) d->d_name);
}
int
main(int argc, char *argv[])
{
int fd, nread;
int buf_size = argc > 2 ? atoi(argv[2]) : 40;
char *buf;
struct linux_dirent *d;
int bpos;
off_t *off_table;
int off_table_size = 0;
unsigned short *reclen_table;
int reclen_table_size = 0;
int i;
buf = malloc(buf_size);
if (!buf)
handle_error("allocating buf");
off_table = malloc(OFF_TABLE_SIZE * sizeof(off_t));
if (!off_table)
handle_error("allocating off_table");
off_table[off_table_size++] = 0;
reclen_table = malloc(RECLEN_TABLE_SIZE * sizeof(unsigned short));
if (!reclen_table)
handle_error("allocating reclen_table");
fd = open(argc > 1 ? argv[1] : ".", O_RDONLY | O_DIRECTORY);
if (fd == -1)
handle_error("open");
for ( ; ; ) {
nread = syscall(SYS_getdents, fd, buf, buf_size);
if (nread == -1)
handle_error("getdents");
if (nread == 0)
break;
printf("--------------- nread=%d ---------------\n", nread);
printf("i-node# file type d_reclen d_off d_name\n");
for (bpos = 0; bpos < nread;) {
d = (struct linux_dirent *) (buf + bpos);
print_dirent(buf, bpos);
off_table[off_table_size++] = d->d_off;
reclen_table[reclen_table_size++] = d->d_reclen;
bpos += d->d_reclen;
}
printf("at end of getdents: lseek %10lld\n",
lseek(fd, 0, SEEK_CUR));
}
for (i = 0; i < off_table_size; i++) {
lseek(fd, off_table[i], SEEK_SET);
printf("lseek to %ld: lseek %10lld\n",
off_table[i], lseek(fd, 0, SEEK_CUR));
nread = syscall(SYS_getdents, fd, buf, reclen_table[i] - 1);
if (i != off_table_size - 1) {
if (nread == -1 && errno == EINVAL) {
printf("[ OK ] EINVAL for too small count\n");
} else {
printf("[ NG ] EINVAL for too small count\n");
handle_error("Test failed");
}
}
nread = syscall(SYS_getdents, fd, buf, buf_size);
if (nread == -1)
handle_error("getdents");
if (nread == 0) {
printf("--------------- nread=%d (EOF) ---------\n",
nread);
if (i != off_table_size - 1)
handle_error("unexpected EOF");
} else {
printf("--------------- nread=%d ---------------\n",
nread);
printf("i-node# file type d_reclen d_off d_name\n");
for (bpos = 0; bpos < nread;) {
d = (struct linux_dirent *) (buf + bpos);
print_dirent(buf, bpos);
bpos += d->d_reclen;
}
}
printf("at end of getdents: lseek %10lld\n",
lseek(fd, 0, SEEK_CUR));
}
exit(EXIT_SUCCESS);
}

11
test/issues/1421/Makefile Normal file
View File

@@ -0,0 +1,11 @@
include $(HOME)/.mck_test_config.mk
TARGET=1421
all: $(TARGET)
test: $(TARGET)
@echo "===== getdents count: 40"
$(MCK_DIR)/bin/mcexec ./$(TARGET) /sys/devices/system/node 40
@printf "\n===== getdents count: 200\n"
$(MCK_DIR)/bin/mcexec ./$(TARGET) /sys/devices/system/node 200

13
test/issues/1421/README Normal file
View File

@@ -0,0 +1,13 @@
============
What to test
============
(1) lseek value after a getdents matches the d_off of the last entry
received.
(2) lseek using d_off and then getdents gets the proper entry.
(3) lseek using d_off and then getdents with (d_reclen -1) returns EINVAL.
===========
How to test
===========
(1) make test
(2) Check the result manually.

View File

@@ -0,0 +1,179 @@
cc 1421.c -o 1421
===== getdents count: 40
/work/gg10/e29005/project/os/install/bin/mcexec ./1421 /sys/devices/system/node 40
--------------- nread=24 ---------------
i-node# file type d_reclen d_off d_name
61145 directory 24 24 .
at end of getdents: lseek 24
--------------- nread=24 ---------------
i-node# file type d_reclen d_off d_name
46533 directory 24 48 ..
at end of getdents: lseek 48
--------------- nread=32 ---------------
i-node# file type d_reclen d_off d_name
61156 directory 32 80 node0
at end of getdents: lseek 80
--------------- nread=32 ---------------
i-node# file type d_reclen d_off d_name
61148 directory 32 112 node1
at end of getdents: lseek 112
--------------- nread=32 ---------------
i-node# file type d_reclen d_off d_name
61147 regular 32 144 possible
at end of getdents: lseek 144
--------------- nread=32 ---------------
i-node# file type d_reclen d_off d_name
61146 regular 32 176 online
at end of getdents: lseek 176
--------------- nread=32 ---------------
i-node# file type d_reclen d_off d_name
18112 directory 32 208 power
at end of getdents: lseek 208
--------------- nread=32 ---------------
i-node# file type d_reclen d_off d_name
18106 regular 32 240 uevent
at end of getdents: lseek 240
lseek to 0: lseek 0
[ OK ] EINVAL for too small count
--------------- nread=24 ---------------
i-node# file type d_reclen d_off d_name
61145 directory 24 24 .
at end of getdents: lseek 24
lseek to 24: lseek 24
[ OK ] EINVAL for too small count
--------------- nread=24 ---------------
i-node# file type d_reclen d_off d_name
46533 directory 24 48 ..
at end of getdents: lseek 48
lseek to 48: lseek 48
[ OK ] EINVAL for too small count
--------------- nread=32 ---------------
i-node# file type d_reclen d_off d_name
61156 directory 32 80 node0
at end of getdents: lseek 80
lseek to 80: lseek 80
[ OK ] EINVAL for too small count
--------------- nread=32 ---------------
i-node# file type d_reclen d_off d_name
61148 directory 32 112 node1
at end of getdents: lseek 112
lseek to 112: lseek 112
[ OK ] EINVAL for too small count
--------------- nread=32 ---------------
i-node# file type d_reclen d_off d_name
61147 regular 32 144 possible
at end of getdents: lseek 144
lseek to 144: lseek 144
[ OK ] EINVAL for too small count
--------------- nread=32 ---------------
i-node# file type d_reclen d_off d_name
61146 regular 32 176 online
at end of getdents: lseek 176
lseek to 176: lseek 176
[ OK ] EINVAL for too small count
--------------- nread=32 ---------------
i-node# file type d_reclen d_off d_name
18112 directory 32 208 power
at end of getdents: lseek 208
lseek to 208: lseek 208
[ OK ] EINVAL for too small count
--------------- nread=32 ---------------
i-node# file type d_reclen d_off d_name
18106 regular 32 240 uevent
at end of getdents: lseek 240
lseek to 240: lseek 240
--------------- nread=0 (EOF) ---------
at end of getdents: lseek 240
===== getdents count: 200
/work/gg10/e29005/project/os/install/bin/mcexec ./1421 /sys/devices/system/node 200
--------------- nread=176 ---------------
i-node# file type d_reclen d_off d_name
61145 directory 24 24 .
46533 directory 24 48 ..
61156 directory 32 80 node0
61148 directory 32 112 node1
61147 regular 32 144 possible
61146 regular 32 176 online
at end of getdents: lseek 176
--------------- nread=64 ---------------
i-node# file type d_reclen d_off d_name
18112 directory 32 208 power
18106 regular 32 240 uevent
at end of getdents: lseek 240
lseek to 0: lseek 0
[ OK ] EINVAL for too small count
--------------- nread=176 ---------------
i-node# file type d_reclen d_off d_name
61145 directory 24 24 .
46533 directory 24 48 ..
61156 directory 32 80 node0
61148 directory 32 112 node1
61147 regular 32 144 possible
61146 regular 32 176 online
at end of getdents: lseek 176
lseek to 24: lseek 24
[ OK ] EINVAL for too small count
--------------- nread=184 ---------------
i-node# file type d_reclen d_off d_name
46533 directory 24 48 ..
61156 directory 32 80 node0
61148 directory 32 112 node1
61147 regular 32 144 possible
61146 regular 32 176 online
18112 directory 32 208 power
at end of getdents: lseek 208
lseek to 48: lseek 48
[ OK ] EINVAL for too small count
--------------- nread=192 ---------------
i-node# file type d_reclen d_off d_name
61156 directory 32 80 node0
61148 directory 32 112 node1
61147 regular 32 144 possible
61146 regular 32 176 online
18112 directory 32 208 power
18106 regular 32 240 uevent
at end of getdents: lseek 240
lseek to 80: lseek 80
[ OK ] EINVAL for too small count
--------------- nread=160 ---------------
i-node# file type d_reclen d_off d_name
61148 directory 32 112 node1
61147 regular 32 144 possible
61146 regular 32 176 online
18112 directory 32 208 power
18106 regular 32 240 uevent
at end of getdents: lseek 240
lseek to 112: lseek 112
[ OK ] EINVAL for too small count
--------------- nread=128 ---------------
i-node# file type d_reclen d_off d_name
61147 regular 32 144 possible
61146 regular 32 176 online
18112 directory 32 208 power
18106 regular 32 240 uevent
at end of getdents: lseek 240
lseek to 144: lseek 144
[ OK ] EINVAL for too small count
--------------- nread=96 ---------------
i-node# file type d_reclen d_off d_name
61146 regular 32 176 online
18112 directory 32 208 power
18106 regular 32 240 uevent
at end of getdents: lseek 240
lseek to 176: lseek 176
[ OK ] EINVAL for too small count
--------------- nread=64 ---------------
i-node# file type d_reclen d_off d_name
18112 directory 32 208 power
18106 regular 32 240 uevent
at end of getdents: lseek 240
lseek to 208: lseek 208
[ OK ] EINVAL for too small count
--------------- nread=32 ---------------
i-node# file type d_reclen d_off d_name
18106 regular 32 240 uevent
at end of getdents: lseek 240
lseek to 240: lseek 240
--------------- nread=0 (EOF) ---------
at end of getdents: lseek 240