diff --git a/include/iscsi-private.h b/include/iscsi-private.h index e9b9e7e..df20702 100644 --- a/include/iscsi-private.h +++ b/include/iscsi-private.h @@ -39,6 +39,7 @@ extern "C" { #define ISCSI_HEADER_SIZE (ISCSI_RAW_HEADER_SIZE \ + (iscsi->header_digest == ISCSI_HEADER_DIGEST_NONE?0:ISCSI_DIGEST_SIZE)) +#define SMALL_ALLOC_MAX_FREE (128) /* must be power of 2 */ struct iscsi_in_pdu { struct iscsi_in_pdu *next; @@ -131,6 +132,10 @@ struct iscsi_context { int mallocs; int reallocs; int frees; + int smallocs; + void* smalloc_ptrs[SMALL_ALLOC_MAX_FREE]; + int smalloc_free; + size_t smalloc_size; time_t last_reconnect; int scsi_timeout; @@ -301,6 +306,8 @@ inline void* iscsi_zmalloc(struct iscsi_context *iscsi, size_t size); inline void* iscsi_realloc(struct iscsi_context *iscsi, void* ptr, size_t size); inline void iscsi_free(struct iscsi_context *iscsi, void* ptr); inline char* iscsi_strdup(struct iscsi_context *iscsi, const char* str); +inline void* iscsi_szmalloc(struct iscsi_context *iscsi, size_t size); +inline void iscsi_sfree(struct iscsi_context *iscsi, void* ptr); unsigned long crc32c(char *buf, int len); diff --git a/lib/init.c b/lib/init.c index 60a1b6d..14a865f 100644 --- a/lib/init.c +++ b/lib/init.c @@ -33,7 +33,6 @@ #include "iscsi-private.h" #include "slist.h" - inline void* iscsi_malloc(struct iscsi_context *iscsi, size_t size) { void * ptr = malloc(size); if (ptr != NULL) iscsi->mallocs++; @@ -69,6 +68,36 @@ inline char* iscsi_strdup(struct iscsi_context *iscsi, const char* str) { return str2; } +inline void* iscsi_szmalloc(struct iscsi_context *iscsi, size_t size) { + void *ptr; + if (size > iscsi->smalloc_size) return NULL; + if (iscsi->smalloc_free > 0) { + ptr = iscsi->smalloc_ptrs[--iscsi->smalloc_free]; + memset(ptr, 0, iscsi->smalloc_size); + iscsi->smallocs++; + } else { + ptr = iscsi_zmalloc(iscsi, iscsi->smalloc_size); + } + return ptr; +} + +inline void iscsi_sfree(struct iscsi_context *iscsi, void* ptr) { + if (ptr == NULL) return; + if (iscsi->smalloc_free == SMALL_ALLOC_MAX_FREE) { + /* SMALL_ALLOC_MAX_FREE should be adjusted that this happens rarely */ + ISCSI_LOG(iscsi,6,"smalloc free == SMALLOC_MAX_FREE"); + int i; + /* remove oldest half of free pointers and copy + * upper half to lower half */ + iscsi->smalloc_free>>=1; + for (i=0; ismalloc_free; i++) { + iscsi_free(iscsi, iscsi->smalloc_ptrs[i]); + iscsi->smalloc_ptrs[i] = iscsi->smalloc_ptrs[i+iscsi->smalloc_free]; + } + } + iscsi->smalloc_ptrs[iscsi->smalloc_free++] = ptr; +} + struct iscsi_context * iscsi_create_context(const char *initiator_name) { @@ -144,6 +173,16 @@ iscsi_create_context(const char *initiator_name) iscsi_set_bind_interfaces(iscsi,getenv("LIBISCSI_BIND_INTERFACES")); } + /* iscsi->smalloc_size is the size for small allocations. this should be + max(ISCSI_HEADER_SIZE, sizeof(struct iscsi_pdu), sizeof(struct iscsi_in_pdu)) + rounded up to the next power of 2. */ + iscsi->smalloc_size = 1; + size_t required = ISCSI_RAW_HEADER_SIZE + ISCSI_DIGEST_SIZE; + if (sizeof(struct iscsi_pdu) > required) required = sizeof(struct iscsi_pdu); + if (sizeof(struct iscsi_in_pdu) > required) required = sizeof(struct iscsi_in_pdu); + while (iscsi->smalloc_size < required) iscsi->smalloc_size <<= 1; + ISCSI_LOG(iscsi,5,"small allocation size is %d byte", iscsi->smalloc_size); + return iscsi; } @@ -236,6 +275,7 @@ int iscsi_destroy_context(struct iscsi_context *iscsi) { struct iscsi_pdu *pdu; + int i; if (iscsi == NULL) { return 0; @@ -283,10 +323,14 @@ iscsi_destroy_context(struct iscsi_context *iscsi) iscsi->connect_data = NULL; + for (i=0;ismalloc_free;i++) { + iscsi_free(iscsi, iscsi->smalloc_ptrs[i]); + } + if (iscsi->mallocs != iscsi->frees) { - ISCSI_LOG(iscsi,1,"%d memory blocks lost at iscsi_destroy_context() after %d malloc(s), %d realloc(s) and %d free(s)",iscsi->mallocs-iscsi->frees,iscsi->mallocs,iscsi->reallocs,iscsi->frees); + ISCSI_LOG(iscsi,1,"%d memory blocks lost at iscsi_destroy_context() after %d malloc(s), %d realloc(s), %d free(s) and %d reused small allocations",iscsi->mallocs-iscsi->frees,iscsi->mallocs,iscsi->reallocs,iscsi->frees,iscsi->smallocs); } else { - ISCSI_LOG(iscsi,5,"memory is clean at iscsi_destroy_context() after %d mallocs, %d realloc(s) and %d frees",iscsi->mallocs,iscsi->reallocs,iscsi->frees); + ISCSI_LOG(iscsi,5,"memory is clean at iscsi_destroy_context() after %d mallocs, %d realloc(s), %d free(s) and %d reused small allocations",iscsi->mallocs,iscsi->reallocs,iscsi->frees,iscsi->smallocs); } memset(iscsi, 0, sizeof(struct iscsi_context)); diff --git a/lib/pdu.c b/lib/pdu.c index f53490a..e682abd 100644 --- a/lib/pdu.c +++ b/lib/pdu.c @@ -84,15 +84,14 @@ iscsi_allocate_pdu_with_itt_flags(struct iscsi_context *iscsi, enum iscsi_opcode { struct iscsi_pdu *pdu; - pdu = iscsi_zmalloc(iscsi, sizeof(struct iscsi_pdu)); + pdu = iscsi_szmalloc(iscsi, sizeof(struct iscsi_pdu)); if (pdu == NULL) { iscsi_set_error(iscsi, "failed to allocate pdu"); return NULL; } pdu->outdata.size = ISCSI_HEADER_SIZE; - pdu->outdata.data = iscsi_malloc(iscsi, pdu->outdata.size); - memset(pdu->outdata.data, 0, ISCSI_HEADER_SIZE); + pdu->outdata.data = iscsi_szmalloc(iscsi, pdu->outdata.size); if (pdu->outdata.data == NULL) { iscsi_set_error(iscsi, "failed to allocate pdu header"); @@ -134,13 +133,21 @@ iscsi_free_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) return; } - iscsi_free(iscsi, pdu->outdata.data); + if (pdu->outdata.size <= iscsi->smalloc_size) { + iscsi_sfree(iscsi, pdu->outdata.data); + } else { + iscsi_free(iscsi, pdu->outdata.data); + } pdu->outdata.data = NULL; - iscsi_free(iscsi, pdu->indata.data); + if (pdu->indata.size <= iscsi->smalloc_size) { + iscsi_sfree(iscsi, pdu->indata.data); + } else { + iscsi_free(iscsi, pdu->indata.data); + } pdu->indata.data = NULL; - iscsi_free(iscsi, pdu); + iscsi_sfree(iscsi, pdu); } @@ -164,9 +171,15 @@ iscsi_add_data(struct iscsi_context *iscsi, struct iscsi_data *data, } if (data->size == 0) { - data->data = iscsi_malloc(iscsi, aligned); + if (aligned <= iscsi->smalloc_size) { + data->data = iscsi_szmalloc(iscsi, aligned); + } else { + data->data = iscsi_malloc(iscsi, aligned); + } } else { - data->data = iscsi_realloc(iscsi, data->data, aligned); + if (aligned > iscsi->smalloc_size) { + data->data = iscsi_realloc(iscsi, data->data, aligned); + } } if (data->data == NULL) { iscsi_set_error(iscsi, "failed to allocate buffer for %d " diff --git a/lib/socket.c b/lib/socket.c index 1605065..8944623 100644 --- a/lib/socket.c +++ b/lib/socket.c @@ -492,7 +492,7 @@ iscsi_read_from_socket(struct iscsi_context *iscsi) ssize_t data_size, count; if (iscsi->incoming == NULL) { - iscsi->incoming = iscsi_zmalloc(iscsi, sizeof(struct iscsi_in_pdu)); + iscsi->incoming = iscsi_szmalloc(iscsi, sizeof(struct iscsi_in_pdu)); if (iscsi->incoming == NULL) { iscsi_set_error(iscsi, "Out-of-memory: failed to malloc iscsi_in_pdu"); return -1; @@ -820,7 +820,7 @@ iscsi_free_iscsi_in_pdu(struct iscsi_context *iscsi, struct iscsi_in_pdu *in) { iscsi_free(iscsi, in->data); in->data=NULL; - iscsi_free(iscsi, in); + iscsi_sfree(iscsi, in); in=NULL; }