Skip to content

Commit 00a45b9

Browse files
committed
Keep files open for non-zero-copy reads as well
Opening and closing files is bad for performance, so now that we accurately track the situation of hitting too many open files we can keep the band files open, even for the non-readbuf code path. This unifies the logic of opening (and caching file descriptors) between the readbuf and non-readbuf code paths.
1 parent b5398b1 commit 00a45b9

2 files changed

Lines changed: 61 additions & 61 deletions

File tree

src/sparsebundlefs.cpp

Lines changed: 60 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,7 @@ struct sparsebundle_t {
8787
uint64_t band_size;
8888
uint64_t size;
8989
uint64_t times_opened;
90-
#if FUSE_SUPPORTS_ZERO_COPY
9190
map<string, int> open_files;
92-
#endif
9391
struct {
9492
bool allow_other = false;
9593
bool allow_root = false;
@@ -180,6 +178,59 @@ static int sparsebundle_open(const char *path, struct fuse_file_info *fi)
180178
return 0;
181179
}
182180

181+
static void sparsebundle_close_files()
182+
{
183+
sparsebundle_t *sparsebundle = sparsebundle_current();
184+
185+
if (sparsebundle->open_files.empty())
186+
return;
187+
188+
syslog(LOG_DEBUG, "closing %zu open file descriptor(s)", sparsebundle->open_files.size());
189+
190+
map<string, int>::iterator iter;
191+
for(iter = sparsebundle->open_files.begin(); iter != sparsebundle->open_files.end(); ++iter) {
192+
close(iter->second);
193+
syslog(LOG_DEBUG, "closed %s", iter->first.c_str());
194+
}
195+
196+
sparsebundle->open_files.clear();
197+
}
198+
199+
static rlim_t sparsebundle_max_files()
200+
{
201+
struct rlimit fd_limit;
202+
getrlimit(RLIMIT_NOFILE, &fd_limit);
203+
return fd_limit.rlim_cur;
204+
}
205+
206+
static int sparsebundle_open_file(const char *path)
207+
{
208+
sparsebundle_t *sparsebundle = sparsebundle_current();
209+
210+
int fd = -1;
211+
map<string, int>::const_iterator iter = sparsebundle->open_files.find(path);
212+
if (iter != sparsebundle->open_files.end()) {
213+
fd = iter->second;
214+
} else {
215+
syslog(LOG_DEBUG, "file %s not opened yet, opening", path);
216+
if ((fd = open(path, O_RDONLY)) == -1) {
217+
if (errno == EMFILE) {
218+
syslog(LOG_DEBUG, "too many open file descriptors (max %ju)",
219+
uintmax_t(sparsebundle_max_files()));
220+
221+
sparsebundle_close_files();
222+
return sparsebundle_open_file(path);
223+
}
224+
syslog(LOG_ERR, "failed to open %s: %s", path, strerror(errno));
225+
return -errno;
226+
}
227+
228+
sparsebundle->open_files[path] = fd;
229+
}
230+
231+
return fd;
232+
}
233+
183234
struct sparsebundle_read_operations {
184235
int (*process_band) (const char *, size_t, off_t, void *);
185236
int (*pad_with_zeroes) (size_t, void *);
@@ -255,14 +306,9 @@ static int sparsebundle_read_process_band(const char *band_path, size_t length,
255306
syslog(LOG_DEBUG, "reading %zu bytes at offset %ju into %p",
256307
length, uintmax_t(offset), static_cast<void *>(*buffer));
257308

258-
syslog(LOG_DEBUG, "opening %s", band_path);
259-
int band_file = open(band_path, O_RDONLY);
309+
int band_file = sparsebundle_open_file(band_path);
260310
if (band_file != -1) {
261311
read = pread(band_file, *buffer, length, offset);
262-
263-
syslog(LOG_DEBUG, "closing %s", band_path);
264-
close(band_file);
265-
266312
if (read == -1) {
267313
syslog(LOG_ERR, "failed to read band: %s", strerror(errno));
268314
return -errno;
@@ -305,51 +351,6 @@ static int sparsebundle_read(const char *path, char *buffer, size_t length, off_
305351
}
306352

307353
#if FUSE_SUPPORTS_ZERO_COPY
308-
static void sparsebundle_read_buf_close_files()
309-
{
310-
sparsebundle_t *sparsebundle = sparsebundle_current();
311-
312-
syslog(LOG_DEBUG, "closing %zu open file descriptor(s)", sparsebundle->open_files.size());
313-
314-
map<string, int>::iterator iter;
315-
for(iter = sparsebundle->open_files.begin(); iter != sparsebundle->open_files.end(); ++iter) {
316-
close(iter->second);
317-
syslog(LOG_DEBUG, "closed %s", iter->first.c_str());
318-
}
319-
320-
sparsebundle->open_files.clear();
321-
}
322-
323-
static int sparsebundle_read_buf_prepare_file(const char *path)
324-
{
325-
sparsebundle_t *sparsebundle = sparsebundle_current();
326-
327-
int fd = -1;
328-
map<string, int>::const_iterator iter = sparsebundle->open_files.find(path);
329-
if (iter != sparsebundle->open_files.end()) {
330-
fd = iter->second;
331-
} else {
332-
syslog(LOG_DEBUG, "file %s not opened yet, opening", path);
333-
if ((fd = open(path, O_RDONLY)) == -1) {
334-
if (errno == EMFILE) {
335-
struct rlimit fd_limit;
336-
getrlimit(RLIMIT_NOFILE, &fd_limit);
337-
syslog(LOG_DEBUG, "too many open files (%ju)",
338-
uintmax_t(fd_limit.rlim_cur));
339-
340-
sparsebundle_read_buf_close_files();
341-
return sparsebundle_read_buf_prepare_file(path);
342-
}
343-
syslog(LOG_ERR, "failed to open band %s: %s", path, strerror(errno));
344-
return -errno;
345-
}
346-
347-
sparsebundle->open_files[path] = fd;
348-
}
349-
350-
return fd;
351-
}
352-
353354
static int sparsebundle_read_buf_process_band(const char *band_path, size_t length, off_t offset, void *read_data)
354355
{
355356
size_t read = 0;
@@ -359,7 +360,7 @@ static int sparsebundle_read_buf_process_band(const char *band_path, size_t leng
359360
syslog(LOG_DEBUG, "preparing %zu bytes at offset %ju", length,
360361
uintmax_t(offset));
361362

362-
int band_file_fd = sparsebundle_read_buf_prepare_file(band_path);
363+
int band_file_fd = sparsebundle_open_file(band_path);
363364
if (band_file_fd != -1) {
364365
struct stat band_stat;
365366
stat(band_path, &band_stat);
@@ -382,7 +383,7 @@ static const char zero_device[] = "/dev/zero";
382383
static int sparsebundle_read_buf_pad_with_zeroes(size_t length, void *read_data)
383384
{
384385
vector<fuse_buf> *buffers = static_cast<vector<fuse_buf> *>(read_data);
385-
int zero_device_fd = sparsebundle_read_buf_prepare_file(zero_device);
386+
int zero_device_fd = sparsebundle_open_file(zero_device);
386387
fuse_buf buffer = { length, fuse_buf_flags(FUSE_BUF_IS_FD), 0, zero_device_fd, 0 };
387388
buffers->push_back(buffer);
388389

@@ -440,11 +441,7 @@ static int sparsebundle_release(const char *path, struct fuse_file_info *)
440441

441442
if (sparsebundle->times_opened == 0) {
442443
syslog(LOG_DEBUG, "no more references, cleaning up");
443-
444-
#if FUSE_SUPPORTS_ZERO_COPY
445-
if (!sparsebundle->open_files.empty())
446-
sparsebundle_read_buf_close_files();
447-
#endif
444+
sparsebundle_close_files();
448445
}
449446

450447
return 0;
@@ -605,6 +602,9 @@ int main(int argc, char **argv)
605602
sparsebundle_filesystem_operations.read_buf = sparsebundle_read_buf;
606603
#endif
607604

605+
syslog(LOG_DEBUG, "max open file descriptors is %ju",
606+
uintmax_t(sparsebundle_max_files()));
607+
608608
int ret = fuse_main(args.argc, args.argv, &sparsebundle_filesystem_operations, &sparsebundle);
609609
syslog(LOG_DEBUG, "exiting with return code %d", ret);
610610
return ret;

tests/testhelpers.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ function _test_can_handle_ulimit() {
5353
cat $f > /dev/null
5454
done
5555

56-
cat $test_output_file | grep -q "too many open files"
56+
cat $test_output_file | grep -q "too many open file descriptors"
5757

5858
umount $hfs_dir && rm -Rf $hfs_dir
5959
umount $mount_dir && rm -Rf $mount_dir

0 commit comments

Comments
 (0)