MmappedFile.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9/* DEBUG: section 47 Store Directory Routines */
10
11#include "squid.h"
12#include "debug/Stream.h"
13#include "DiskIO/IORequestor.h"
15#include "DiskIO/ReadRequest.h"
16#include "DiskIO/WriteRequest.h"
17#include "fs_io.h"
18#include "globals.h"
19
20#include <cerrno>
21#if HAVE_SYS_MMAN_H
22#include <sys/mman.h>
23#endif
24#if HAVE_SYS_STAT_H
25#include <sys/stat.h>
26#endif
27
28// Some systems such as Hurd provide mmap() API but do not support MAP_NORESERVE
29#ifndef MAP_NORESERVE
30#define MAP_NORESERVE 0
31#endif
32
34
35// helper class to deal with mmap(2) offset alignment and other low-level specs
37{
38public:
39 Mmapping(int fd, size_t length, int prot, int flags, off_t offset);
40 ~Mmapping();
41
42 void *map();
43 bool unmap();
44
45private:
46 const int fd;
47 const size_t length;
48 const int prot;
49 const int flags;
50 const off_t offset;
51
52 off_t delta;
53 void *buf;
54};
55
56MmappedFile::MmappedFile(char const *aPath): fd(-1),
57 minOffset(0), maxOffset(-1), error_(false)
58{
59 assert(aPath);
60 path_ = xstrdup(aPath);
61 debugs(79,5, this << ' ' << path_);
62}
63
65{
67 doClose();
68}
69
70// XXX: almost a copy of BlockingFile::open
71void
73{
74 assert(fd < 0);
75
76 /* Simulate async calls */
77 fd = file_open(path_, flags);
78 ioRequestor = callback;
79
80 if (fd < 0) {
81 int xerrno = errno;
82 debugs(79,3, "open error: " << xstrerr(xerrno));
83 error_ = true;
84 } else {
86 debugs(79,3, "FD " << fd);
87
88 // setup mapping boundaries
89 struct stat sb;
90 if (fstat(fd, &sb) == 0)
91 maxOffset = sb.st_size; // we do not expect it to change
92 }
93
94 callback->ioCompletedNotification();
95}
96
101void
103{
104 /* We use the same logic path for open */
105 open(flags, mode, callback);
106}
107
109{
110 if (fd >= 0) {
111 file_close(fd);
112 fd = -1;
114 }
115}
116
117void
119{
120 debugs(79, 3, this << " closing for " << ioRequestor);
121 doClose();
122 assert(ioRequestor != nullptr);
124}
125
126bool
128{
129 return fd >= 0;
130}
131
132bool
134{
135 return fd >= 0;
136}
137
138bool
140{
141 return error_;
142}
143
144void
146{
147 debugs(79,3, "(FD " << fd << ", " << aRequest->len << ", " <<
148 aRequest->offset << ")");
149
150 assert(fd >= 0);
151 assert(ioRequestor != nullptr);
152 assert(aRequest->len > 0); // TODO: work around mmap failures on zero-len?
153 assert(aRequest->offset >= 0);
154 assert(!error_); // TODO: propagate instead?
155
156 assert(minOffset < 0 || minOffset <= aRequest->offset);
157 assert(maxOffset < 0 || static_cast<uint64_t>(aRequest->offset + aRequest->len) <= static_cast<uint64_t>(maxOffset));
158
159 Mmapping mapping(fd, aRequest->len, PROT_READ, MAP_PRIVATE | MAP_NORESERVE,
160 aRequest->offset);
161
162 bool done = false;
163 if (void *buf = mapping.map()) {
164 memcpy(aRequest->buf, buf, aRequest->len);
165 done = mapping.unmap();
166 }
167 error_ = !done;
168
169 const ssize_t rlen = error_ ? -1 : (ssize_t)aRequest->len;
170 const int errflag = error_ ? DISK_ERROR :DISK_OK;
171 ioRequestor->readCompleted(aRequest->buf, rlen, errflag, aRequest);
172}
173
174void
176{
177 debugs(79,3, "(FD " << fd << ", " << aRequest->len << ", " <<
178 aRequest->offset << ")");
179
180 assert(fd >= 0);
181 assert(ioRequestor != nullptr);
182 assert(aRequest->len > 0); // TODO: work around mmap failures on zero-len?
183 assert(aRequest->offset >= 0);
184 assert(!error_); // TODO: propagate instead?
185
186 assert(minOffset < 0 || minOffset <= aRequest->offset);
187 assert(maxOffset < 0 || static_cast<uint64_t>(aRequest->offset + aRequest->len) <= static_cast<uint64_t>(maxOffset));
188
189 const ssize_t written =
190 pwrite(fd, aRequest->buf, aRequest->len, aRequest->offset);
191 if (written < 0) {
192 debugs(79, DBG_IMPORTANT, "ERROR: " << xstrerr(errno));
193 error_ = true;
194 } else if (static_cast<size_t>(written) != aRequest->len) {
195 debugs(79, DBG_IMPORTANT, "problem: " << written << " < " << aRequest->len);
196 error_ = true;
197 }
198
199 if (aRequest->free_func)
200 (aRequest->free_func)(const_cast<char*>(aRequest->buf)); // broken API?
201
202 if (!error_) {
203 debugs(79,5, "wrote " << aRequest->len << " to FD " << fd << " at " << aRequest->offset);
204 } else {
205 doClose();
206 }
207
208 const ssize_t rlen = error_ ? 0 : (ssize_t)aRequest->len;
209 const int errflag = error_ ? DISK_ERROR :DISK_OK;
210 ioRequestor->writeCompleted(errflag, rlen, aRequest);
211}
212
214bool
216{
217 return false;
218}
219
220Mmapping::Mmapping(int aFd, size_t aLength, int aProt, int aFlags, off_t anOffset):
221 fd(aFd), length(aLength), prot(aProt), flags(aFlags), offset(anOffset),
222 delta(-1), buf(nullptr)
223{
224}
225
227{
228 if (buf)
229 unmap();
230}
231
232void *
234{
235 // mmap(2) requires that offset is a multiple of the page size
236 static const int pageSize = getpagesize();
237 delta = offset % pageSize;
238
239 buf = mmap(nullptr, length + delta, prot, flags, fd, offset - delta);
240
241 if (buf == MAP_FAILED) {
242 const int errNo = errno;
243 debugs(79,3, "error FD " << fd << "mmap(" << length << '+' <<
244 delta << ", " << offset << '-' << delta << "): " << xstrerr(errNo));
245 buf = nullptr;
246 return nullptr;
247 }
248
249 return static_cast<char*>(buf) + delta;
250}
251
252bool
254{
255 debugs(79,9, "FD " << fd <<
256 " munmap(" << buf << ", " << length << '+' << delta << ')');
257
258 if (!buf) // forgot or failed to map
259 return false;
260
261 const bool error = munmap(buf, length + delta) != 0;
262 if (error) {
263 const int errNo = errno;
264 debugs(79,3, "error FD " << fd <<
265 " munmap(" << buf << ", " << length << '+' << delta << "): " <<
266 "): " << xstrerr(errNo));
267 }
268 buf = nullptr;
269 return !error;
270}
271
272// TODO: check MAP_NORESERVE, consider MAP_POPULATE and MAP_FIXED
273
CBDATA_CLASS_INIT(MmappedFile)
#define MAP_NORESERVE
Definition: MmappedFile.cc:30
void error(char *format,...)
#define assert(EX)
Definition: assert.h:17
virtual void closeCompleted()=0
virtual void readCompleted(const char *buf, int len, int errflag, RefCount< ReadRequest >)=0
virtual void ioCompletedNotification()=0
virtual void writeCompleted(int errflag, size_t len, RefCount< WriteRequest >)=0
~MmappedFile() override
Definition: MmappedFile.cc:64
bool ioInProgress() const override
we only support blocking I/O
Definition: MmappedFile.cc:215
int64_t maxOffset
enforced if not negative (to avoid crashes)
Definition: MmappedFile.h:44
RefCount< IORequestor > ioRequestor
Definition: MmappedFile.h:37
bool error() const override
Definition: MmappedFile.cc:139
char const * path_
Definition: MmappedFile.h:36
void write(WriteRequest *) override
Definition: MmappedFile.cc:175
bool canWrite() const override
Definition: MmappedFile.cc:133
void read(ReadRequest *) override
Definition: MmappedFile.cc:145
void open(int flags, mode_t mode, RefCount< IORequestor > callback) override
Definition: MmappedFile.cc:72
int64_t minOffset
enforced if not negative (to preserve file headers)
Definition: MmappedFile.h:43
MmappedFile(char const *path)
Definition: MmappedFile.cc:56
void create(int flags, mode_t mode, RefCount< IORequestor > callback) override
Definition: MmappedFile.cc:102
void doClose()
Definition: MmappedFile.cc:108
void close() override
Definition: MmappedFile.cc:118
bool canRead() const override
Definition: MmappedFile.cc:127
const size_t length
user-requested data length, needed for munmap
Definition: MmappedFile.cc:47
void * map()
calls mmap(2); returns usable buffer or nil on failure
Definition: MmappedFile.cc:233
const int prot
mmap(2) "protection" flags
Definition: MmappedFile.cc:48
off_t delta
mapped buffer increment to hit user offset
Definition: MmappedFile.cc:52
void * buf
buffer returned by mmap, needed for munmap
Definition: MmappedFile.cc:53
const int flags
other mmap(2) flags
Definition: MmappedFile.cc:49
Mmapping(int fd, size_t length, int prot, int flags, off_t offset)
Definition: MmappedFile.cc:220
const int fd
descriptor of the mmapped file
Definition: MmappedFile.cc:46
bool unmap()
unmaps previously mapped buffer, if any
Definition: MmappedFile.cc:253
const off_t offset
user-requested data offset
Definition: MmappedFile.cc:50
size_t len
Definition: ReadRequest.h:26
off_t offset
Definition: ReadRequest.h:25
char * buf
Definition: ReadRequest.h:24
FREE * free_func
Definition: WriteRequest.h:28
char const * buf
Definition: WriteRequest.h:25
#define DBG_IMPORTANT
Definition: Stream.h:38
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:194
#define DISK_ERROR
Definition: defines.h:28
#define DISK_OK
Definition: defines.h:27
int file_open(const char *path, int mode)
Definition: fs_io.cc:45
void file_close(int fd)
Definition: fs_io.cc:73
int store_open_disk_fd
#define xstrdup
static struct stat sb
Definition: squidclient.cc:71
unsigned short mode_t
Definition: types.h:129
#define safe_free(x)
Definition: xalloc.h:73
const char * xstrerr(int error)
Definition: xstrerror.cc:83

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors