diff --git a/src/sparsebundlefs.cpp b/src/sparsebundlefs.cpp index fec0986..df5d4e1 100644 --- a/src/sparsebundlefs.cpp +++ b/src/sparsebundlefs.cpp @@ -87,9 +87,7 @@ struct sparsebundle_t { uint64_t band_size; uint64_t size; uint64_t times_opened; -#if FUSE_SUPPORTS_ZERO_COPY map open_files; -#endif struct { bool allow_other = false; bool allow_root = false; @@ -180,6 +178,59 @@ static int sparsebundle_open(const char *path, struct fuse_file_info *fi) return 0; } +static void sparsebundle_close_files() +{ + sparsebundle_t *sparsebundle = sparsebundle_current(); + + if (sparsebundle->open_files.empty()) + return; + + syslog(LOG_DEBUG, "closing %zu open file descriptor(s)", sparsebundle->open_files.size()); + + map::iterator iter; + for(iter = sparsebundle->open_files.begin(); iter != sparsebundle->open_files.end(); ++iter) { + close(iter->second); + syslog(LOG_DEBUG, "closed %s", iter->first.c_str()); + } + + sparsebundle->open_files.clear(); +} + +static rlim_t sparsebundle_max_files() +{ + struct rlimit fd_limit; + getrlimit(RLIMIT_NOFILE, &fd_limit); + return fd_limit.rlim_cur; +} + +static int sparsebundle_open_file(const char *path) +{ + sparsebundle_t *sparsebundle = sparsebundle_current(); + + int fd = -1; + map::const_iterator iter = sparsebundle->open_files.find(path); + if (iter != sparsebundle->open_files.end()) { + fd = iter->second; + } else { + syslog(LOG_DEBUG, "file %s not opened yet, opening", path); + if ((fd = open(path, O_RDONLY)) == -1) { + if (errno == EMFILE) { + syslog(LOG_DEBUG, "too many open file descriptors (max %ju)", + uintmax_t(sparsebundle_max_files())); + + sparsebundle_close_files(); + return sparsebundle_open_file(path); + } + syslog(LOG_ERR, "failed to open %s: %s", path, strerror(errno)); + return -errno; + } + + sparsebundle->open_files[path] = fd; + } + + return fd; +} + struct sparsebundle_read_operations { int (*process_band) (const char *, size_t, off_t, void *); int (*pad_with_zeroes) (size_t, void *); @@ -255,14 +306,9 @@ static int sparsebundle_read_process_band(const char *band_path, size_t length, syslog(LOG_DEBUG, "reading %zu bytes at offset %ju into %p", length, uintmax_t(offset), static_cast(*buffer)); - syslog(LOG_DEBUG, "opening %s", band_path); - int band_file = open(band_path, O_RDONLY); + int band_file = sparsebundle_open_file(band_path); if (band_file != -1) { read = pread(band_file, *buffer, length, offset); - - syslog(LOG_DEBUG, "closing %s", band_path); - close(band_file); - if (read == -1) { syslog(LOG_ERR, "failed to read band: %s", strerror(errno)); return -errno; @@ -305,51 +351,6 @@ static int sparsebundle_read(const char *path, char *buffer, size_t length, off_ } #if FUSE_SUPPORTS_ZERO_COPY -static void sparsebundle_read_buf_close_files() -{ - sparsebundle_t *sparsebundle = sparsebundle_current(); - - syslog(LOG_DEBUG, "closing %zu open file descriptor(s)", sparsebundle->open_files.size()); - - map::iterator iter; - for(iter = sparsebundle->open_files.begin(); iter != sparsebundle->open_files.end(); ++iter) { - close(iter->second); - syslog(LOG_DEBUG, "closed %s", iter->first.c_str()); - } - - sparsebundle->open_files.clear(); -} - -static int sparsebundle_read_buf_prepare_file(const char *path) -{ - sparsebundle_t *sparsebundle = sparsebundle_current(); - - int fd = -1; - map::const_iterator iter = sparsebundle->open_files.find(path); - if (iter != sparsebundle->open_files.end()) { - fd = iter->second; - } else { - syslog(LOG_DEBUG, "file %s not opened yet, opening", path); - if ((fd = open(path, O_RDONLY)) == -1) { - if (errno == EMFILE) { - struct rlimit fd_limit; - getrlimit(RLIMIT_NOFILE, &fd_limit); - syslog(LOG_DEBUG, "too many open files (%ju)", - uintmax_t(fd_limit.rlim_cur)); - - sparsebundle_read_buf_close_files(); - return sparsebundle_read_buf_prepare_file(path); - } - syslog(LOG_ERR, "failed to open band %s: %s", path, strerror(errno)); - return -errno; - } - - sparsebundle->open_files[path] = fd; - } - - return fd; -} - static int sparsebundle_read_buf_process_band(const char *band_path, size_t length, off_t offset, void *read_data) { size_t read = 0; @@ -359,7 +360,7 @@ static int sparsebundle_read_buf_process_band(const char *band_path, size_t leng syslog(LOG_DEBUG, "preparing %zu bytes at offset %ju", length, uintmax_t(offset)); - int band_file_fd = sparsebundle_read_buf_prepare_file(band_path); + int band_file_fd = sparsebundle_open_file(band_path); if (band_file_fd != -1) { struct stat band_stat; stat(band_path, &band_stat); @@ -382,7 +383,7 @@ static const char zero_device[] = "/dev/zero"; static int sparsebundle_read_buf_pad_with_zeroes(size_t length, void *read_data) { vector *buffers = static_cast *>(read_data); - int zero_device_fd = sparsebundle_read_buf_prepare_file(zero_device); + int zero_device_fd = sparsebundle_open_file(zero_device); fuse_buf buffer = { length, fuse_buf_flags(FUSE_BUF_IS_FD), 0, zero_device_fd, 0 }; buffers->push_back(buffer); @@ -440,11 +441,7 @@ static int sparsebundle_release(const char *path, struct fuse_file_info *) if (sparsebundle->times_opened == 0) { syslog(LOG_DEBUG, "no more references, cleaning up"); - -#if FUSE_SUPPORTS_ZERO_COPY - if (!sparsebundle->open_files.empty()) - sparsebundle_read_buf_close_files(); -#endif + sparsebundle_close_files(); } return 0; @@ -605,6 +602,9 @@ int main(int argc, char **argv) sparsebundle_filesystem_operations.read_buf = sparsebundle_read_buf; #endif + syslog(LOG_DEBUG, "max open file descriptors is %ju", + uintmax_t(sparsebundle_max_files())); + int ret = fuse_main(args.argc, args.argv, &sparsebundle_filesystem_operations, &sparsebundle); syslog(LOG_DEBUG, "exiting with return code %d", ret); return ret; diff --git a/tests/testhelpers.sh b/tests/testhelpers.sh index 93ddf28..1a635eb 100644 --- a/tests/testhelpers.sh +++ b/tests/testhelpers.sh @@ -53,7 +53,7 @@ function _test_can_handle_ulimit() { cat $f > /dev/null done - cat $test_output_file | grep -q "too many open files" + cat $test_output_file | grep -q "too many open file descriptors" umount $hfs_dir && rm -Rf $hfs_dir umount $mount_dir && rm -Rf $mount_dir