fuck mmap_sem!

0.96
acab 16 years ago
parent ee1b2a6c81
commit 5a078ca98c
  1. 123
      libclamav/fmap.c

@ -37,6 +37,9 @@
#endif
#endif
#include <pthread.h>
#include "others.h"
#include "cltypes.h"
@ -54,9 +57,14 @@
/* FIXME: tune this stuff */
#define UNPAGE_THRSHLD_LO 4*1024*1024
#define UNPAGE_THRSHLD_HI 8*1024*1024
#define DUMB_SIZE 1*1024*1024
#define READAHEAD_PAGES 8
/* FIXME: remove the malloc fallback, it only makes thing slower */
#define DUMB_SIZE 0
/* DON'T ASK ME */
pthread_mutex_t fmap_mutex = PTHREAD_MUTEX_INITIALIZER;
#define READAHEAD_PAGES 4
static unsigned int fmap_align_items(unsigned int sz, unsigned int al) {
return sz / al + (sz % al != 0);
@ -99,10 +107,15 @@ struct F_MAP *fmap(int fd, off_t offset, size_t len) {
mapsz = pages * pgsz + hdrsz;
#if HAVE_MMAP
if(mapsz >= DUMB_SIZE) {
if ((m = (struct F_MAP *)mmap(NULL, mapsz, PROT_READ | PROT_WRITE, MAP_PRIVATE|ANONYMOUS_MAP, -1, 0)) == MAP_FAILED)
pthread_mutex_lock(&fmap_mutex);
if ((m = (struct F_MAP *)mmap(NULL, mapsz, PROT_READ | PROT_WRITE, MAP_PRIVATE|/*FIXME: MAP_POPULATE is ~8% faster but more memory intensive */ANONYMOUS_MAP, -1, 0)) == MAP_FAILED)
m = NULL;
else
else {
dumb = 0;
madvise(m, mapsz, MADV_RANDOM|MADV_DONTFORK);
madvise(m, hdrsz, MADV_WILLNEED);
}
pthread_mutex_unlock(&fmap_mutex);
} else
#endif
m = (struct F_MAP *)cli_malloc(mapsz);
@ -120,7 +133,13 @@ struct F_MAP *fmap(int fd, off_t offset, size_t len) {
m->pgsz = pgsz;
m->paged = 0;
memset(m->bitmap, 0, sizeof(uint32_t) * pages);
// cli_errmsg("FMAPDBG: created %p - len %u pages %u hdrsz %u\n", m, len, pages, hdrsz);
#ifdef FMAPDEBUG
m->page_needs = 0;
m->page_reads = 0;
m->page_locks = 0;
m->page_unlocks = 0;
m->page_unmaps = 0;
#endif
return m;
}
@ -179,8 +198,13 @@ static void fmap_aging(struct F_MAP *m) {
m->bitmap[freeme[i]] = FM_MASK_SEEN;
m->paged--;
/* and we mmap the page over so the kernel knows there's nothing good in there */
pthread_mutex_lock(&fmap_mutex);
if(mmap(pptr, m->pgsz, PROT_READ | PROT_WRITE, MAP_FIXED|MAP_PRIVATE|ANONYMOUS_MAP, -1, 0) == MAP_FAILED)
cli_warnmsg("fmap_aging: kernel hates you\n");
pthread_mutex_unlock(&fmap_mutex);
#ifdef FMAPDEBUG
m->page_unmaps++;
#endif
}
}
free(freeme);
@ -192,9 +216,16 @@ static void fmap_aging(struct F_MAP *m) {
static int fmap_readpage(struct F_MAP *m, unsigned int first_page, unsigned int count, unsigned int lock_count) {
size_t readsz = 0, got;
char *pptr = NULL;
uint32_t s;
volatile uint32_t s;
unsigned int i, page = first_page, force_read = 0;
for(i=0; i<count; i++) { /* REAL MEN DON'T MADVISE: seriously, it sucks! */
volatile char faultme = ((char *)m)[(first_page+i) * m->pgsz + m->hdrsz];
}
#ifdef FMAPDEBUG
m->page_needs += count;
m->page_locks += lock_count;
#endif
for(i=0; i<=count; i++, page++) {
int lock;
if(lock_count) {
@ -254,6 +285,9 @@ static int fmap_readpage(struct F_MAP *m, unsigned int first_page, unsigned int
cli_warnmsg("pread fail: page %u pages %u map-offset %lu - asked for %lu bytes, got %lu\n", first_page, m->pages, (long unsigned int)m->offset, (long unsigned int)readsz, (long unsigned int)got);
return 1;
}
#ifdef FMAPDEBUG
m->page_reads += count;
#endif
pptr = NULL;
force_read = 0;
readsz = 0;
@ -285,12 +319,12 @@ static void *fmap_need(struct F_MAP *m, size_t at, size_t len, int lock) {
char *ret;
if(!len) {
cli_warnmsg("fmap: attempted void need\n");
// cli_warnmsg("fmap: attempted void need\n");
return NULL;
}
if(!CLI_ISCONTAINED(0, m->len, at, len)) {
cli_warnmsg("fmap: attempted oof need\n");
// cli_warnmsg("fmap: attempted oof need\n");
return NULL;
}
@ -304,8 +338,6 @@ static void *fmap_need(struct F_MAP *m, size_t at, size_t len, int lock) {
if(last_page >= m->pages) last_page = m->pages - 1;
#endif
// cli_errmsg("FMAPDBG: +++ map %p - len %u lock: %d (page %u to %u)\n", m, len, lock, first_page, last_page);
if(fmap_readpage(m, first_page, last_page-first_page+1, lock_count))
return NULL;
@ -315,19 +347,15 @@ static void *fmap_need(struct F_MAP *m, size_t at, size_t len, int lock) {
}
void *fmap_need_off(struct F_MAP *m, size_t at, size_t len) {
// cli_errmsg("FMAPDBG: need_off map %p at %u len %u\n", m, at, len);
return fmap_need(m, at, len, 1);
}
void *fmap_need_off_once(struct F_MAP *m, size_t at, size_t len) {
// cli_errmsg("FMAPDBG: need_off_once map %p at %u len %u\n", m, at, len);
return fmap_need(m, at, len, 0);
}
void *fmap_need_ptr(struct F_MAP *m, void *ptr, size_t len) {
// cli_errmsg("FMAPDBG: need_ptr map %p at %p len %u\n", m, ptr, len);
return fmap_need_off(m, (char *)ptr - (char *)m - m->hdrsz, len);
}
void *fmap_need_ptr_once(struct F_MAP *m, void *ptr, size_t len) {
// cli_errmsg("FMAPDBG: need_ptr_once map %p at %p len %u\n", m, ptr, len);
return fmap_need_off_once(m, (char *)ptr - (char *)m - m->hdrsz, len);
}
@ -339,11 +367,12 @@ void *fmap_need_str(struct F_MAP *m, void *ptr, size_t len_hint) {
static void fmap_unneed_page(struct F_MAP *m, unsigned int page) {
uint32_t s = m->bitmap[page];
// cli_errmsg("FMAPDBG: --- map %p - page %u status %u count %u\n", m, page, s>>30, s & FM_MASK_COUNT);
if((s & (FM_MASK_PAGED | FM_MASK_LOCKED)) == (FM_MASK_PAGED | FM_MASK_LOCKED)) {
/* page is paged and locked: check lock count */
s &= FM_MASK_COUNT;
#ifdef FMAPDEBUG
m->page_unlocks ++;
#endif
if(s > 1) /* locked more than once: dec lock count */
m->bitmap[page]--;
else if (s == 1) /* only one lock left: unlock and begin aging */
@ -399,10 +428,16 @@ int fmap_readn(struct F_MAP *m, void *dst, size_t at, size_t len) {
}
void fmunmap(struct F_MAP *m) {
#ifdef FMAPDEBUG
cli_errmsg("FMAPDEBUG: Needs:%u reads:%u locks:%u unlocks:%u unmaps:%u\n", m->page_needs, m->page_reads, m->page_locks, m->page_unlocks, m->page_unmaps);
#endif
#if HAVE_MMAP
if(!m->dumb) {
size_t len = m->pages * m->pgsz + m->hdrsz;
pthread_mutex_lock(&fmap_mutex);
munmap((void *)m, len);
pthread_mutex_unlock(&fmap_mutex);
} else
#endif
free((void *)m);
@ -416,7 +451,7 @@ void *fmap_need_offstr(struct F_MAP *m, size_t at, size_t len_hint) {
len_hint = m->len - at;
if(!CLI_ISCONTAINED(0, m->len, at, len_hint)) {
cli_warnmsg("fmap: attempted oof need_str\n");
// cli_warnmsg("fmap: attempted oof need_str\n");
return NULL;
}
@ -435,11 +470,12 @@ void *fmap_need_offstr(struct F_MAP *m, size_t at, size_t len_hint) {
}
if(i == first_page) {
scanat = at % m->pgsz;
scansz = m->pgsz - scanat;
scansz = MIN(len_hint, m->pgsz - scanat);
} else {
scanat = 0;
scansz = m->pgsz;
scansz = MIN(len_hint, m->pgsz);
}
len_hint -= scansz;
if(memchr(&thispage[scanat], 0, scansz))
return ptr;
}
@ -447,3 +483,52 @@ void *fmap_need_offstr(struct F_MAP *m, size_t at, size_t len_hint) {
fmap_unneed_page(m, i);
return NULL;
}
void *fmap_gets(struct F_MAP *m, char *dst, size_t *at, size_t max_len) {
unsigned int i, first_page, last_page;
char *src = (void *)((char *)m + m->hdrsz + *at), *endptr = NULL;
size_t len = MIN(max_len-1, m->len - *at), fullen = len;
if(!len || !CLI_ISCONTAINED(0, m->len, *at, len)) {
//cli_warnmsg("fmap: attempted oof need_str\n");
return NULL;
}
fmap_aging(m);
first_page = fmap_which_page(m, *at);
last_page = fmap_which_page(m, *at + len - 1);
for(i=first_page; i<=last_page; i++) {
char *thispage = (char *)m + m->hdrsz + i * m->pgsz;
unsigned int scanat, scansz;
if(fmap_readpage(m, i, 1, 0))
return NULL;
if(i == first_page) {
scanat = *at % m->pgsz;
scansz = MIN(len, m->pgsz - scanat);
} else {
scanat = 0;
scansz = MIN(len, m->pgsz);
}
len -= scansz;
if((endptr = memchr(&thispage[scanat], '\n', scansz))) {
endptr++;
break;
}
}
if(endptr) {
memcpy(dst, src, endptr - src);
dst[endptr - src] = '\0';
*at += endptr - src;
} else {
memcpy(dst, src, fullen);
dst[fullen] = '\0';
*at += fullen;
}
return dst;
}

Loading…
Cancel
Save