Skip to content

Commit

Permalink
Merge pull request pi-hole#519 from pi-hole/hotfix/v4.2.3
Browse files Browse the repository at this point in the history
Pi-hole FTL v4.2.3
  • Loading branch information
dschaper authored Feb 26, 2019
2 parents 4a8003c + a11d3dd commit aae487e
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 43 deletions.
8 changes: 7 additions & 1 deletion FTL.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ typedef struct {
int forwarded_MAX;
int clients_MAX;
int domains_MAX;
int overTime_MAX;
int strings_MAX;
int gravity;
int gravity_conf;
int querytype[TYPE_MAX-1];
Expand Down Expand Up @@ -221,6 +221,12 @@ typedef struct {
char **domains;
} whitelistStruct;

typedef struct {
int version;
unsigned int global_shm_counter;
unsigned int next_str_pos;
} ShmSettings;

// Prepare timers, used mainly for debugging purposes
#define NUMTIMERS 5

Expand Down
143 changes: 102 additions & 41 deletions shmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
#include "FTL.h"
#include "shmem.h"

/// The version of shared memory used
#define SHARED_MEMORY_VERSION 4

/// The name of the shared memory. Use this when connecting to the shared memory.
#define SHARED_LOCK_NAME "/FTL-lock"
#define SHARED_STRINGS_NAME "/FTL-strings"
Expand All @@ -20,6 +23,7 @@
#define SHARED_QUERIES_NAME "/FTL-queries"
#define SHARED_FORWARDED_NAME "/FTL-forwarded"
#define SHARED_OVERTIME_NAME "/FTL-overTime"
#define SHARED_SETTINGS_NAME "/FTL-settings"

/// The pointer in shared memory to the shared string buffer
static SharedMemory shm_lock = { 0 };
Expand All @@ -30,15 +34,17 @@ static SharedMemory shm_clients = { 0 };
static SharedMemory shm_queries = { 0 };
static SharedMemory shm_forwarded = { 0 };
static SharedMemory shm_overTime = { 0 };
static SharedMemory shm_settings = { 0 };

typedef struct {
pthread_mutex_t lock;
bool waitingForLock;
} ShmLock;
static ShmLock *shmLock = NULL;
static ShmSettings *shmSettings = NULL;

static int pagesize;
static unsigned int next_pos = 0;
static unsigned int local_shm_counter = 0;

unsigned long long addstr(const char *str)
{
Expand All @@ -51,24 +57,28 @@ unsigned long long addstr(const char *str)
// Get string length
size_t len = strlen(str);

if(debug) logg("Adding \"%s\" (len %i) to buffer. next_pos is %i", str, len, next_pos);
if(debug) logg("Adding \"%s\" (len %i) to buffer. next_str_pos is %i", str, len, shmSettings->next_str_pos);

// Reserve additional memory if necessary
size_t required_size = next_pos + len + 1;
size_t required_size = shmSettings->next_str_pos + len + 1;
// Need to cast to long long because size_t calculations cannot be negative
if((long long)required_size-(long long)shm_strings.size > 0 &&
!realloc_shm(&shm_strings, shm_strings.size + pagesize))
!realloc_shm(&shm_strings, shm_strings.size + pagesize, true))
return 0;

// Store new string buffer size in corresponding counters entry
// for re-using when we need to re-map shared memory objects
counters->strings_MAX = shm_strings.size;

// Copy the C string pointed by str into the shared string buffer
strncpy(&((char*)shm_strings.ptr)[next_pos], str, len);
((char*)shm_strings.ptr)[next_pos + len] = '\0';
strncpy(&((char*)shm_strings.ptr)[shmSettings->next_str_pos], str, len);
((char*)shm_strings.ptr)[shmSettings->next_str_pos + len] = '\0';

// Increment string length counter
next_pos += len+1;
shmSettings->next_str_pos += len+1;

// Return start of stored string
return (next_pos - (len + 1));
return (shmSettings->next_str_pos - (len + 1));
}

char *getstr(unsigned long long pos)
Expand Down Expand Up @@ -99,6 +109,24 @@ pthread_mutex_t create_mutex() {
return lock;
}

void remap_shm(void)
{
// Remap shared object pointers which might have changed
realloc_shm(&shm_queries, counters->queries_MAX*sizeof(queriesDataStruct), false);
queries = (queriesDataStruct*)shm_queries.ptr;
realloc_shm(&shm_domains, counters->domains_MAX*sizeof(domainsDataStruct), false);
domains = (domainsDataStruct*)shm_domains.ptr;
realloc_shm(&shm_clients, counters->clients_MAX*sizeof(clientsDataStruct), false);
clients = (clientsDataStruct*)shm_clients.ptr;
realloc_shm(&shm_forwarded, counters->forwarded_MAX*sizeof(forwardedDataStruct), false);
forwarded = (forwardedDataStruct*)shm_forwarded.ptr;
realloc_shm(&shm_strings, counters->strings_MAX, false);
// strings are not exposed by a global pointer

// Update local counter to reflect that we absorbed this change
local_shm_counter = shmSettings->global_shm_counter;
}

void _lock_shm(const char* function, const int line, const char * file) {
// Signal that FTL is waiting for a lock
shmLock->waitingForLock = true;
Expand All @@ -109,6 +137,15 @@ void _lock_shm(const char* function, const int line, const char * file) {

if(debug) logg("Obtained lock for %s() (%s:%i)", function, file, line);

// Check if this process needs to remap the shared memory objects
if(shmSettings != NULL &&
local_shm_counter != shmSettings->global_shm_counter)
{
if(debug) logg("Remapping shared memory for current process %u %u",
local_shm_counter, shmSettings->global_shm_counter);
remap_shm();
}

// Turn off the waiting for lock signal to notify everyone who was
// deferring to FTL that they can jump in the lock queue.
shmLock->waitingForLock = false;
Expand Down Expand Up @@ -144,18 +181,26 @@ bool init_shmem(void)
shmLock->lock = create_mutex();
shmLock->waitingForLock = false;

/****************************** shared counters struct ******************************/
// Try to create shared memory object
shm_counters = create_shm(SHARED_COUNTERS_NAME, sizeof(countersStruct));
counters = (countersStruct*)shm_counters.ptr;

/****************************** shared settings struct ******************************/
// Try to create shared memory object
shm_settings = create_shm(SHARED_SETTINGS_NAME, sizeof(ShmSettings));
shmSettings = (ShmSettings*)shm_settings.ptr;
shmSettings->version = SHARED_MEMORY_VERSION;
shmSettings->global_shm_counter = 0;

/****************************** shared strings buffer ******************************/
// Try to create shared memory object
shm_strings = create_shm(SHARED_STRINGS_NAME, pagesize);
counters->strings_MAX = pagesize;

// Initialize shared string object with an empty string at position zero
((char*)shm_strings.ptr)[0] = '\0';
next_pos = 1;

/****************************** shared counters struct ******************************/
// Try to create shared memory object
shm_counters = create_shm(SHARED_COUNTERS_NAME, sizeof(countersStruct));
counters = (countersStruct*)shm_counters.ptr;
shmSettings->next_str_pos = 1;

/****************************** shared domains struct ******************************/
// Try to create shared memory object
Expand Down Expand Up @@ -186,7 +231,6 @@ bool init_shmem(void)
// Try to create shared memory object
shm_overTime = create_shm(SHARED_OVERTIME_NAME, size);
overTime = (overTimeDataStruct*)shm_overTime.ptr;
counters->overTime_MAX = (int) size;
initOverTime();

return true;
Expand All @@ -205,6 +249,7 @@ void destroy_shmem(void)
delete_shm(&shm_queries);
delete_shm(&shm_forwarded);
delete_shm(&shm_overTime);
delete_shm(&shm_settings);
}

SharedMemory create_shm(char *name, size_t size)
Expand Down Expand Up @@ -303,40 +348,55 @@ void *enlarge_shmem_struct(char type)
}

// Reallocate enough space for 4096 instances of requested object
realloc_shm(sharedMemory, sharedMemory->size + pagesize*sizeofobj);
realloc_shm(sharedMemory, sharedMemory->size + pagesize*sizeofobj, true);

// Add allocated memory to corresponding counter
*counter += pagesize;

return sharedMemory->ptr;
}

bool realloc_shm(SharedMemory *sharedMemory, size_t size) {
logg("Resizing \"%s\" from %zu to %zu", sharedMemory->name, sharedMemory->size, size);

int result = munmap(sharedMemory->ptr, sharedMemory->size);
if(result != 0)
logg("realloc_shm(): munmap(%p, %zu) failed: %s", sharedMemory->ptr, sharedMemory->size, strerror(errno));

// Open shared memory object
int fd = shm_open(sharedMemory->name, O_RDWR, S_IRUSR | S_IWUSR);
if(fd == -1)
bool realloc_shm(SharedMemory *sharedMemory, size_t size, bool resize)
{
// Check if we can skip this routine as nothing is to be done
// when an object is not to be resized and its size didn't
// change elsewhere
if(!resize && size == sharedMemory->size)
return true;

// Log that we are doing something here
logg("%s \"%s\" from %zu to %zu", resize ? "Resizing" : "Remapping", sharedMemory->name, sharedMemory->size, size);

// Resize shard memory object if requested
// If not, we only remap a shared memory object which might have changed
// in another process. This happens when pihole-FTL forks due to incoming
// TCP requests.
int fd = -1;
if(resize)
{
logg("FATAL: realloc_shm(): Failed to open shared memory object \"%s\": %s",
sharedMemory->name, strerror(errno));
exit(EXIT_FAILURE);
// Open shared memory object
fd = shm_open(sharedMemory->name, O_RDWR, S_IRUSR | S_IWUSR);
if(fd == -1)
{
logg("FATAL: realloc_shm(): Failed to open shared memory object \"%s\": %s",
sharedMemory->name, strerror(errno));
exit(EXIT_FAILURE);
}

// Truncate shared memory object to specified size
int result = ftruncate(fd, size);
if(result == -1) {
logg("FATAL: realloc_shm(): ftruncate(%i, %zu): Failed to resize \"%s\": %s",
fd, size, sharedMemory->name, strerror(errno));
exit(EXIT_FAILURE);
}

// Update shm counters to indicate that at least one shared memory object changed
shmSettings->global_shm_counter++;
local_shm_counter++;
}

// Resize shard memory object to requested size
result = ftruncate(fd, size);
if(result == -1) {
logg("FATAL: realloc_shm(): ftruncate(%i, %zu): Failed to resize \"%s\": %s",
fd, size, sharedMemory->name, strerror(errno));
exit(EXIT_FAILURE);
}

// void *new_ptr = mremap(sharedMemory->ptr, sharedMemory->size, size, MREMAP_MAYMOVE);
void *new_ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
void *new_ptr = mremap(sharedMemory->ptr, sharedMemory->size, size, MREMAP_MAYMOVE);
if(new_ptr == MAP_FAILED)
{
logg("FATAL: realloc_shm(): mremap(%p, %zu, %zu, MREMAP_MAYMOVE): Failed to reallocate \"%s\" (%i): %s",
Expand All @@ -346,8 +406,9 @@ bool realloc_shm(SharedMemory *sharedMemory, size_t size) {
}

// Close shared memory object file descriptor as it is no longer
// needed after having called mmap()
close(fd);
// needed after having called ftruncate()
if(resize)
close(fd);

sharedMemory->ptr = new_ptr;
sharedMemory->size = size;
Expand Down
3 changes: 2 additions & 1 deletion shmem.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ SharedMemory create_shm(char *name, size_t size);
///
/// \param sharedMemory the shared memory struct
/// \param size the new size
/// \param resize whether the object should be resized or only remapped
/// \return if reallocation was successful
bool realloc_shm(SharedMemory *sharedMemory, size_t size);
bool realloc_shm(SharedMemory *sharedMemory, size_t size, bool resize);

/// Disconnect from shared memory. If there are no other connections to shared memory, it will be deleted.
///
Expand Down

0 comments on commit aae487e

Please sign in to comment.