Skip to content

Commit

Permalink
linux file backing store probing
Browse files Browse the repository at this point in the history
Signed-off-by: Pantelis Antoniou <[email protected]>
  • Loading branch information
pantoniou committed Sep 22, 2023
1 parent 960bf43 commit 196e18d
Showing 1 changed file with 118 additions and 4 deletions.
122 changes: 118 additions & 4 deletions src/blake3/blake3_host_state.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/sysmacros.h>

#include "blake3.h"
#include "blake3_impl.h"
Expand Down Expand Up @@ -222,6 +223,109 @@ void blake3_hasher_destroy(blake3_hasher *self)
free(self);
}

#if defined(__linux__)

static int linux_block_dev_is_rotational(dev_t dev)
{
char *path = NULL;
int rc, fd;
uint8_t c[2];
int rotational;

/* by default it's the filesize */
rotational = -1; /* not found */

/* read the rotational attribute of the root */
rc = asprintf(&path, "/sys/dev/block/%u:%u/queue/rotational", major(dev), 0);
if (rc != -1) {
fd = open(path, O_RDONLY);
if (fd != -1) {
if (read(fd, c, 2) == 2)
rotational = c[0] == '1' && c[1] == '\n';
close(fd);
}
free(path);
}

return rotational;
}

static ssize_t linux_file_cached_size(int fd, void *mem, size_t filesize)
{
long pagesize = sysconf(_SC_PAGESIZE);
size_t vec_size, resident_size, i;
unsigned char *vec;
int rc;

(void)rc;
vec_size = (filesize + pagesize - 1) / pagesize;
vec = malloc(vec_size + 1);
if (!vec)
return -1;

rc = mincore(mem, filesize, vec);
assert(!rc);

/* this could be parallelized */
resident_size = 0;
for (i = 0; i < vec_size; i++) {
if (vec[i] & 1)
resident_size += pagesize;
}

free(vec);

if (resident_size > filesize)
resident_size = filesize;

return (ssize_t)resident_size;
}

#define BLAKE3_MMAP_MIN_CHUNKSIZE (1U << 20) // minimum chunksize is 1MB

static size_t blake3_mmap_file_chunksize(int fd, dev_t dev, void *mem, size_t filesize)
{
size_t chunksize;
ssize_t cached_size;
int rotational;

/* if the file is small enough don't bother with the rest */
if (filesize <= BLAKE3_MMAP_MIN_CHUNKSIZE)
return BLAKE3_MMAP_MIN_CHUNKSIZE;

/* by default it's the filesize */
chunksize = filesize;

/* starting, check if the rotational attribute exists in this dev */
rotational = linux_block_dev_is_rotational(dev);
if (rotational == -1) {
/* attribute not found? check the non-partition */
rotational = linux_block_dev_is_rotational(makedev(major(dev), 0));
}

if (rotational == 1) {
/* OK, it's rotational, but is it in cache?
* to avoid checking for the cached status of the whole file
* we just probe the MIN_CHUNKSIZE
* We will thrash in the case where the file is only cached
* for the first few bytes, but this is generally unusual.
*/
cached_size = linux_file_cached_size(fd, mem, BLAKE3_MMAP_MIN_CHUNKSIZE);

if (cached_size <= 0)
chunksize = BLAKE3_MMAP_MIN_CHUNKSIZE;
}

return chunksize;
}
#else
static size_t blake3_mmap_file_chunksize(int fd, dev_t dev, void *mem, size_t filesize)
{
/* for all others, just use mmap at max */
return filesize;
}
#endif

/* 256K threshold for using alloca */
#define BLAKE3_ALLOCA_BUFFER_SIZE (256U << 10)

Expand All @@ -230,11 +334,11 @@ int blake3_hash_file(blake3_hasher *hasher, const char *filename,
{
blake3_host_state *hs;
FILE *fp = NULL;
void *mem = NULL;
void *buf = NULL;
void *mem = NULL, *buf = NULL, *p;
int fd = -1, ret = -1;
size_t rdn, filesize, bufsz = 0;
size_t rdn, filesize, bufsz = 0, max_chunk, left, chunk;
struct stat sb;
dev_t dev = 0;
int rc;

if (!hasher || !filename || !output)
Expand Down Expand Up @@ -278,6 +382,7 @@ int blake3_hash_file(blake3_hasher *hasher, const char *filename,
if (mem != MAP_FAILED) {
close(fd);
fd = -1;
dev = sb.st_dev;
} else
mem = NULL;
}
Expand All @@ -296,7 +401,16 @@ int blake3_hash_file(blake3_hasher *hasher, const char *filename,

/* mmap case, very simple */
if (mem) {
blake3_hasher_update(hasher, mem, filesize);
max_chunk = blake3_mmap_file_chunksize(fd, dev, mem, filesize);

p = mem;
left = filesize;
while (left > 0) {
chunk = left > max_chunk ? max_chunk : left;
blake3_hasher_update(hasher, p, chunk);
p += chunk;
left -= chunk;
}
} else {
/* slow path using file reads */

Expand Down

0 comments on commit 196e18d

Please sign in to comment.