Skip to content

Commit 797c1a1

Browse files
author
Uwe Kleine-König
committed
Introduce abstraction layer for file access
This prepares to support further backends to access other memory-like devices. There are only little changes in the intended behaviour for some corner cases: - md -w x+y now rounds y down to a multiple of 2 instead of up. Same for -l with multiples of 4 and -q with multiples of 8. - The size of a memory map is limited to 4096, which for big requests increases the count of map + unmap operations. This is expected to not make a difference in the effects though. Signed-off-by: Uwe Kleine-König <[email protected]>
1 parent 312bcb7 commit 797c1a1

7 files changed

+402
-103
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/acc_mmap.o
12
/aclocal.m4
23
/autom4te.cache
34
/compile
@@ -6,6 +7,7 @@
67
/configure
78
/depcomp
89
/.deps
10+
/fileaccess.o
911
/install-sh
1012
/Makefile
1113
/Makefile.in

Makefile.am

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ EXTRA_DIST = README.devel
22

33
bin_PROGRAMS = memtool
44

5-
memtool_SOURCES = memtool.c
5+
noinst_HEADERS = fileaccess.h fileaccpriv.h
6+
memtool_SOURCES = memtool.c fileaccess.c acc_mmap.c
67

78
dist_man_MANS = memtool.1
89

acc_mmap.c

+213
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
/*
2+
* Copyright (C) 2018 Pengutronix, Uwe Kleine-König <[email protected]>
3+
*
4+
* This program is free software; you can redistribute it and/or
5+
* modify it under the terms of the GNU General Public License
6+
* version 2, as published by the Free Software Foundation.
7+
*
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
* GNU General Public License for more details.
12+
*/
13+
14+
#include <assert.h>
15+
#include <errno.h>
16+
#include <fcntl.h>
17+
#include <stdint.h>
18+
#include <stdio.h>
19+
#include <stdlib.h>
20+
#include <string.h>
21+
#include <sys/stat.h>
22+
#include <sys/mman.h>
23+
#include <sys/types.h>
24+
#include <unistd.h>
25+
26+
#include "fileaccpriv.h"
27+
28+
#define container_of(ptr, type, member) \
29+
(type *)((char *)(ptr) - (char *) &((type *)0)->member)
30+
31+
static off_t mmap_pagesize(void) __attribute__((const));
32+
static off_t mmap_pagesize(void)
33+
{
34+
static off_t pagesize;
35+
36+
if (pagesize == 0)
37+
pagesize = sysconf(_SC_PAGE_SIZE);
38+
39+
if (pagesize == 0)
40+
pagesize = 4096;
41+
42+
return pagesize;
43+
}
44+
45+
struct memtool_mmap_fd {
46+
struct memtool_fd mfd;
47+
struct stat s;
48+
int fd;
49+
};
50+
51+
static ssize_t mmap_read(struct memtool_fd *handle, off_t offset,
52+
void *buf, size_t nbytes, int width)
53+
{
54+
struct memtool_mmap_fd *mmap_fd =
55+
container_of(handle, struct memtool_mmap_fd, mfd);
56+
struct stat *s = &mmap_fd->s;
57+
off_t map_start, map_off;
58+
void *map;
59+
size_t i = 0;
60+
int ret;
61+
62+
if (S_ISREG(s->st_mode)) {
63+
if (s->st_size <= offset) {
64+
errno = EINVAL;
65+
perror("File to small");
66+
return -1;
67+
}
68+
69+
if (s->st_size < offset + nbytes)
70+
/* truncating */
71+
nbytes = s->st_size - offset;
72+
}
73+
74+
map_start = offset & ~(mmap_pagesize() - 1);
75+
map_off = offset - map_start;
76+
77+
map = mmap(NULL, nbytes + map_off, PROT_READ,
78+
MAP_SHARED, mmap_fd->fd, map_start);
79+
if (map == MAP_FAILED) {
80+
perror("mmap");
81+
return -1;
82+
}
83+
84+
while (i * width + width <= nbytes) {
85+
switch (width) {
86+
case 1:
87+
((uint8_t *)buf)[i] = ((uint8_t *)(map + map_off))[i];
88+
break;
89+
case 2:
90+
((uint16_t *)buf)[i] = ((uint16_t *)(map + map_off))[i];
91+
break;
92+
case 4:
93+
((uint32_t *)buf)[i] = ((uint32_t *)(map + map_off))[i];
94+
break;
95+
case 8:
96+
((uint64_t *)buf)[i] = ((uint64_t *)(map + map_off))[i];
97+
break;
98+
}
99+
++i;
100+
}
101+
102+
ret = munmap(map, nbytes + map_off);
103+
if (ret < 0) {
104+
perror("munmap");
105+
return -1;
106+
}
107+
108+
return i * width;
109+
}
110+
111+
static ssize_t mmap_write(struct memtool_fd *handle, off_t offset,
112+
const void *buf, size_t nbytes, int width)
113+
{
114+
struct memtool_mmap_fd *mmap_fd =
115+
container_of(handle, struct memtool_mmap_fd, mfd);
116+
struct stat *s = &mmap_fd->s;
117+
off_t map_start, map_off;
118+
void *map;
119+
size_t i = 0;
120+
int ret;
121+
122+
if (S_ISREG(s->st_mode) && s->st_size < offset + nbytes) {
123+
ret = posix_fallocate(mmap_fd->fd, offset, nbytes);
124+
if (ret) {
125+
errno = ret;
126+
perror("fallocate");
127+
return -1;
128+
}
129+
s->st_size = offset + nbytes;
130+
}
131+
132+
map_start = offset & ~(mmap_pagesize() - 1);
133+
map_off = offset - map_start;
134+
135+
map = mmap(NULL, nbytes + map_off, PROT_WRITE,
136+
MAP_SHARED, mmap_fd->fd, map_start);
137+
if (map == MAP_FAILED) {
138+
perror("mmap");
139+
return -1;
140+
}
141+
142+
while (i * width + width <= nbytes) {
143+
switch (width) {
144+
case 1:
145+
((uint8_t *)(map + map_off))[i] = ((uint8_t *)buf)[i];
146+
break;
147+
case 2:
148+
((uint16_t *)(map + map_off))[i] = ((uint16_t *)buf)[i];
149+
break;
150+
case 4:
151+
((uint32_t *)(map + map_off))[i] = ((uint32_t *)buf)[i];
152+
break;
153+
case 8:
154+
((uint64_t *)(map + map_off))[i] = ((uint64_t *)buf)[i];
155+
break;
156+
}
157+
++i;
158+
}
159+
160+
ret = munmap(map, nbytes + map_off);
161+
if (ret < 0) {
162+
perror("munmap");
163+
return -1;
164+
}
165+
166+
return i * width;
167+
}
168+
169+
static int mmap_close(struct memtool_fd *handle)
170+
{
171+
struct memtool_mmap_fd *mmap_fd =
172+
container_of(handle, struct memtool_mmap_fd, mfd);
173+
int ret;
174+
175+
ret = close(mmap_fd->fd);
176+
177+
free(mmap_fd);
178+
179+
return ret;
180+
}
181+
182+
struct memtool_fd *mmap_open(const char *spec, int flags)
183+
{
184+
struct memtool_mmap_fd *mmap_fd;
185+
int ret;
186+
187+
mmap_fd = malloc(sizeof(*mmap_fd));
188+
if (!mmap_fd) {
189+
fprintf(stderr, "Failure to allocate mmap_fd\n");
190+
return NULL;
191+
}
192+
193+
mmap_fd->mfd.read = mmap_read;
194+
mmap_fd->mfd.write = mmap_write;
195+
mmap_fd->mfd.close = mmap_close;
196+
197+
mmap_fd->fd = open(spec, flags, S_IRUSR | S_IWUSR);
198+
if (mmap_fd->fd < 0) {
199+
perror("open");
200+
free(mmap_fd);
201+
return NULL;
202+
}
203+
204+
ret = fstat(mmap_fd->fd, &mmap_fd->s);
205+
if (ret) {
206+
perror("fstat");
207+
close(mmap_fd->fd);
208+
free(mmap_fd);
209+
return NULL;
210+
}
211+
212+
return &mmap_fd->mfd;
213+
}

fileaccess.c

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright (C) 2018 Pengutronix, Uwe Kleine-König <[email protected]>
3+
*
4+
* This program is free software; you can redistribute it and/or
5+
* modify it under the terms of the GNU General Public License
6+
* version 2, as published by the Free Software Foundation.
7+
*
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
* GNU General Public License for more details.
12+
*/
13+
14+
#include "fileaccess.h"
15+
#include "fileaccpriv.h"
16+
17+
void *memtool_open(const char *spec, int flags)
18+
{
19+
return mmap_open(spec, flags);
20+
}
21+
22+
ssize_t memtool_read(void *handle,
23+
off_t offset, void *buf, size_t nbytes, int width)
24+
{
25+
struct memtool_fd *mfd = handle;
26+
27+
return mfd->read(mfd, offset, buf, nbytes, width);
28+
}
29+
30+
ssize_t memtool_write(void *handle,
31+
off_t offset, const void *buf, size_t nbytes, int width)
32+
{
33+
struct memtool_fd *mfd = handle;
34+
35+
return mfd->write(mfd, offset, buf, nbytes, width);
36+
}
37+
38+
int memtool_close(void *handle)
39+
{
40+
struct memtool_fd *mfd = handle;
41+
42+
return mfd->close(mfd);
43+
}

fileaccess.h

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright (C) 2018 Pengutronix, Uwe Kleine-König <[email protected]>
3+
*
4+
* This program is free software; you can redistribute it and/or
5+
* modify it under the terms of the GNU General Public License
6+
* version 2, as published by the Free Software Foundation.
7+
*
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
* GNU General Public License for more details.
12+
*/
13+
14+
#include <sys/types.h>
15+
16+
void *memtool_open(const char *spec, int flags);
17+
ssize_t memtool_read(void *handle, off_t offset,
18+
void *buf, size_t nbytes, int width);
19+
ssize_t memtool_write(void *handle, off_t offset,
20+
const void *buf, size_t nbytes, int width);
21+
int memtool_close(void *handle);

fileaccpriv.h

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright (C) 2018 Pengutronix, Uwe Kleine-König <[email protected]>
3+
*
4+
* This program is free software; you can redistribute it and/or
5+
* modify it under the terms of the GNU General Public License
6+
* version 2, as published by the Free Software Foundation.
7+
*
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
* GNU General Public License for more details.
12+
*/
13+
#include <sys/types.h>
14+
15+
struct memtool_fd {
16+
ssize_t (*read)(struct memtool_fd *handle, off_t offset,
17+
void *buf, size_t nbytes, int width);
18+
ssize_t (*write)(struct memtool_fd *handle, off_t offset,
19+
const void *buf, size_t nbytes, int width);
20+
int (*close)(struct memtool_fd *handle);
21+
};
22+
23+
struct memtool_fd *mmap_open(const char *spec, int flags);

0 commit comments

Comments
 (0)