diff options
Diffstat (limited to 'src/core/iobuf.c')
| -rw-r--r-- | src/core/iobuf.c | 53 |
1 files changed, 30 insertions, 23 deletions
diff --git a/src/core/iobuf.c b/src/core/iobuf.c index c9970bc76..7e9a4156d 100644 --- a/src/core/iobuf.c +++ b/src/core/iobuf.c @@ -22,6 +22,7 @@ */ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +FILE_SECBOOT ( PERMITTED ); #include <stdint.h> #include <strings.h> @@ -47,22 +48,26 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); */ struct io_buffer * alloc_iob_raw ( size_t len, size_t align, size_t offset ) { struct io_buffer *iobuf; + size_t headroom; + size_t tailroom; size_t padding; size_t threshold; unsigned int align_log2; void *data; - /* Calculate padding required below alignment boundary to - * ensure that a correctly aligned inline struct io_buffer - * could fit (regardless of the requested offset). + /* Round up requested alignment and calculate initial headroom + * and tailroom to ensure that no cachelines are shared + * between I/O buffer data and other data structures. */ - padding = ( sizeof ( *iobuf ) + __alignof__ ( *iobuf ) - 1 ); - - /* Round up requested alignment to at least the size of the - * padding, to simplify subsequent calculations. - */ - if ( align < padding ) - align = padding; + if ( align < IOB_ZLEN ) + align = IOB_ZLEN; + headroom = ( offset & ( IOB_ZLEN - 1 ) ); + tailroom = ( ( - len - offset ) & ( IOB_ZLEN - 1 ) ); + padding = ( headroom + tailroom ); + offset -= headroom; + len += padding; + if ( len < padding ) + return NULL; /* Round up alignment to the nearest power of two, avoiding * a potentially undefined shift operation. @@ -73,8 +78,8 @@ struct io_buffer * alloc_iob_raw ( size_t len, size_t align, size_t offset ) { align = ( 1UL << align_log2 ); /* Calculate length threshold */ - assert ( align >= padding ); - threshold = ( align - padding ); + assert ( align >= sizeof ( *iobuf ) ); + threshold = ( align - sizeof ( *iobuf ) ); /* Allocate buffer plus an inline descriptor as a single unit, * unless doing so would push the total size over the @@ -82,11 +87,6 @@ struct io_buffer * alloc_iob_raw ( size_t len, size_t align, size_t offset ) { */ if ( len <= threshold ) { - /* Round up buffer length to ensure that struct - * io_buffer is aligned. - */ - len += ( ( - len - offset ) & ( __alignof__ ( *iobuf ) - 1 ) ); - /* Allocate memory for buffer plus descriptor */ data = malloc_phys_offset ( len + sizeof ( *iobuf ), align, offset ); @@ -111,7 +111,8 @@ struct io_buffer * alloc_iob_raw ( size_t len, size_t align, size_t offset ) { /* Populate descriptor */ memset ( &iobuf->map, 0, sizeof ( iobuf->map ) ); - iobuf->head = iobuf->data = iobuf->tail = data; + iobuf->head = data; + iobuf->data = iobuf->tail = ( data + headroom ); iobuf->end = ( data + len ); return iobuf; @@ -124,18 +125,24 @@ struct io_buffer * alloc_iob_raw ( size_t len, size_t align, size_t offset ) { * @ret iobuf I/O buffer, or NULL if none available * * The I/O buffer will be physically aligned on its own size (rounded - * up to the nearest power of two). + * up to the nearest power of two), up to a maximum of page-size + * alignment. */ struct io_buffer * alloc_iob ( size_t len ) { + size_t align; /* Pad to minimum length */ if ( len < IOB_ZLEN ) len = IOB_ZLEN; - /* Align buffer on its own size to avoid potential problems - * with boundary-crossing DMA. + /* Align buffer on its own size (up to page size) to avoid + * potential problems with boundary-crossing DMA. */ - return alloc_iob_raw ( len, len, 0 ); + align = len; + if ( align > PAGE_SIZE ) + align = PAGE_SIZE; + + return alloc_iob_raw ( len, align, 0 ); } /** @@ -260,7 +267,7 @@ struct io_buffer * iob_concatenate ( struct list_head *list ) { len += iob_len ( iobuf ); /* Allocate new I/O buffer */ - concatenated = alloc_iob_raw ( len, __alignof__ ( *iobuf ), 0 ); + concatenated = alloc_iob_raw ( len, IOB_ZLEN, 0 ); if ( ! concatenated ) return NULL; |
