*/
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.
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
*/
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 );
/* 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;
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;
"offset %#zx\n", iobuf, virt_to_phys ( iobuf->data ),
iob_tailroom ( iobuf ), len, align, offset );
- /* Validate requested length and alignment */
+ /* Validate requested length and data alignment */
okx ( ( ( ( intptr_t ) iobuf ) & ( __alignof__ ( *iobuf ) - 1 ) ) == 0,
file, line );
okx ( iob_tailroom ( iobuf ) >= len, file, line );
( ( virt_to_phys ( iobuf->data ) & ( align - 1 ) ) ==
( offset & ( align - 1 ) ) ) ), file, line );
+ /* Validate overall buffer alignment */
+ okx ( ( ( ( intptr_t ) iobuf->head ) & ( IOB_ZLEN - 1 ) ) == 0,
+ file, line );
+ okx ( ( ( ( intptr_t ) iobuf->end ) & ( IOB_ZLEN - 1 ) ) == 0,
+ file, line );
+
/* Overwrite entire content of I/O buffer (for Valgrind) */
memset ( iob_put ( iobuf, len ), 0x55, len );