Browse Source

Remove linux only getdents in favor of readdir for FreeBSD sake (#1485)

pull/1486/head
trapexit 3 months ago
committed by GitHub
parent
commit
be49dbe1bd
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 78
      src/fuse_readdir_cor.cpp

78
src/fuse_readdir_cor.cpp

@ -20,9 +20,10 @@
#include "dirinfo.hpp"
#include "errno.hpp"
#include "fs_close.hpp"
#include "fs_closedir.hpp"
#include "fs_getdents64.hpp"
#include "fs_inode.hpp"
#include "fs_open.hpp"
#include "fs_opendir.hpp"
#include "fs_path.hpp"
#include "fs_readdir.hpp"
#include "hashset.hpp"
@ -32,6 +33,10 @@
#include "fuse_dirents.h"
#include "linux_dirent64.h"
#include "int_types.h"
#define MAX_ENTRIES_PER_LOOP 64
FUSE::ReadDirCOR::ReadDirCOR(unsigned concurrency_,
unsigned max_queue_depth_)
@ -45,6 +50,19 @@ FUSE::ReadDirCOR::~ReadDirCOR()
}
static
u64
_dirent_exact_namelen(const struct dirent *d_)
{
#ifdef _D_EXACT_NAMLEN
return _D_EXACT_NAMLEN(d_);
#elif defined _DIRENT_HAVE_D_NAMLEN
return d_->d_namlen;
#else
return strlen(d_->d_name);
#endif
}
namespace l
{
struct Error
@ -83,51 +101,53 @@ namespace l
std::mutex &mutex_)
{
int rv;
int dfd;
DIR *dir;
std::string rel_filepath;
std::string abs_dirpath;
abs_dirpath = fs::path::make(branch_path_,rel_dirpath_);
dfd = fs::open_dir_ro(abs_dirpath);
if(dfd == -1)
errno = 0;
dir = fs::opendir(abs_dirpath);
if(dir == NULL)
return errno;
DEFER{ fs::close(dfd); };
rv = 0;
for(;;)
DEFER{ fs::closedir(dir); };
// The default buffer size in glibc is 32KB. 64 is based on a
// guess of an average size of 512B per entry. This is to limit
// contention on the lock when needing to request more data from
// the kernel. This could be handled better by using getdents but
// due to the differences between Linux and FreeBSD a more
// complicated abstraction needs to be created to handle them to
// make it easier to use across the codebase.
// * https://man7.org/linux/man-pages/man2/getdents.2.html
// * https://man.freebsd.org/cgi/man.cgi?query=getdents
while(true)
{
long nread;
char buf[32 * 1024];
nread = fs::getdents_64(dfd,buf,sizeof(buf));
if(nread == -1)
return errno;
if(nread == 0)
break;
linux_dirent64_t *d;
std::lock_guard<std::mutex> lk(mutex_);
for(long pos = 0; pos < nread; pos += d->reclen)
for(int i = 0; i < MAX_ENTRIES_PER_LOOP; i++)
{
std::uint64_t namelen;
dirent *de;
u64 namelen;
d = (linux_dirent64_t*)&buf[pos];
de = fs::readdir(dir);
if(de == NULL)
return 0;
namelen = DIRENT_NAMELEN(d);
namelen = ::_dirent_exact_namelen(de);
rv = names_.put(d->name,namelen);
rv = names_.put(de->d_name,namelen);
if(rv == 0)
continue;
rel_filepath = fs::path::make(rel_dirpath_,d->name);
d->ino = fs::inode::calc(branch_path_,
rel_filepath,
DTTOIF(d->type),
d->ino);
rel_filepath = fs::path::make(rel_dirpath_,de->d_name);
de->d_ino = fs::inode::calc(branch_path_,
rel_filepath,
DTTOIF(de->d_type),
de->d_ino);
rv = fuse_dirents_add_linux(buf_,d,namelen);
rv = fuse_dirents_add(buf_,de,namelen);
if(rv >= 0)
continue;

Loading…
Cancel
Save