posix_memalign() requires alignment argument to be a multiple of
sizeof(void *). Since it is an implementation detail of buffer,
it needs to be adjusted there -- buffer consumers have no way of
knowing that passing e.g. align == 4 is incorrect.
One place already does the adjustment, but only for align == 0.
The other just asserts. Fix both and remove the "power of two"
assertion. Let posix_memalign() return EINVAL and handle that
by throwing buffer::bad_alloc, as expected by the consumers.
Fixes: https://tracker.ceph.com/issues/50646
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
(cherry picked from commit
aa31ddf0e70b3b8ef8012e09cb3158f3db4dea1b)
Conflicts:
src/common/buffer.cc [ commit
ea32d802031d ("common: drop
sharing of buffer::raw outside bufferlist.") not in nautilus ]
static raw_combined *create(unsigned len,
unsigned align,
int mempool = mempool::mempool_buffer_anon) {
- if (!align)
- align = sizeof(size_t);
+ // posix_memalign() requires a multiple of sizeof(void *)
+ align = std::max<unsigned>(align, sizeof(void *));
size_t rawlen = round_up_to(sizeof(buffer::raw_combined),
alignof(buffer::raw_combined));
size_t datalen = round_up_to(len, alignof(buffer::raw_combined));
MEMPOOL_CLASS_HELPERS();
raw_posix_aligned(unsigned l, unsigned _align) : raw(l) {
- align = _align;
- ceph_assert((align >= sizeof(void *)) && (align & (align - 1)) == 0);
+ // posix_memalign() requires a multiple of sizeof(void *)
+ align = std::max<unsigned>(_align, sizeof(void *));
#ifdef DARWIN
data = (char *) valloc(len);
#else