mirror of
https://github.com/rdmsr/zag.git
synced 2026-11-01 23:58:21 +00:00
mm/zone: remove slab coloring
This simplifies the code and fixes a race condition where the color was read and updated without taking the zone lock in slab_create(). I don't think coloring is very useful these days anyway.
This commit is contained in:
+15
-41
@@ -191,10 +191,8 @@ const Slab = struct {
|
|||||||
/// Reference count indicating how many objects are in use.
|
/// Reference count indicating how many objects are in use.
|
||||||
refcount: u16,
|
refcount: u16,
|
||||||
capacity: u16,
|
capacity: u16,
|
||||||
/// Base address of the slab + its color.
|
/// Base address of the slab.
|
||||||
base: usize,
|
base: usize,
|
||||||
/// Color that was added to the base.
|
|
||||||
color: u16,
|
|
||||||
|
|
||||||
/// Round-robin cursor that is used to allocate objects from.
|
/// Round-robin cursor that is used to allocate objects from.
|
||||||
/// This is used to avoid predictable heap behavior; an attacker
|
/// This is used to avoid predictable heap behavior; an attacker
|
||||||
@@ -244,7 +242,11 @@ const Slab = struct {
|
|||||||
/// Free a bit to the bitmap.
|
/// Free a bit to the bitmap.
|
||||||
pub fn bitmap_free(self: *Slab, idx: usize) void {
|
pub fn bitmap_free(self: *Slab, idx: usize) void {
|
||||||
const bm = self.bitmap();
|
const bm = self.bitmap();
|
||||||
bm[idx / 64] |= @as(u64, 1) << @intCast(idx % 64);
|
|
||||||
|
const bit = @as(u64, 1) << @intCast(idx % 64);
|
||||||
|
std.debug.assert(bm[idx / 64] & (bit) == 0);
|
||||||
|
|
||||||
|
bm[idx / 64] |= bit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check whether or not the slab is completely empty.
|
/// Check whether or not the slab is completely empty.
|
||||||
@@ -284,7 +286,7 @@ const Slab = struct {
|
|||||||
/// fact that the bitmap size grows with capacity (making this circular).
|
/// fact that the bitmap size grows with capacity (making this circular).
|
||||||
/// We resolve the circular dependency by starting with an overestimate and
|
/// We resolve the circular dependency by starting with an overestimate and
|
||||||
/// shrinking until everything fits.
|
/// shrinking until everything fits.
|
||||||
pub fn calc_capacity(chunk_size: usize, alignment: usize, color: usize) usize {
|
pub fn calc_capacity(chunk_size: usize, alignment: usize) usize {
|
||||||
// Start with the largest possible capacity.
|
// Start with the largest possible capacity.
|
||||||
var capacity = (mm.page_size - @sizeOf(Slab)) / chunk_size;
|
var capacity = (mm.page_size - @sizeOf(Slab)) / chunk_size;
|
||||||
|
|
||||||
@@ -293,7 +295,7 @@ const Slab = struct {
|
|||||||
// since a smaller capacity means a smaller bitmap, which may then fit.
|
// since a smaller capacity means a smaller bitmap, which may then fit.
|
||||||
while (capacity > 0) : (capacity -= 1) {
|
while (capacity > 0) : (capacity -= 1) {
|
||||||
const objects_off =
|
const objects_off =
|
||||||
std.mem.alignForward(usize, @sizeOf(Slab) + Slab.bitmap_bytes(capacity), alignment) + color;
|
std.mem.alignForward(usize, @sizeOf(Slab) + Slab.bitmap_bytes(capacity), alignment);
|
||||||
|
|
||||||
if (objects_off + capacity * chunk_size <= mm.page_size) {
|
if (objects_off + capacity * chunk_size <= mm.page_size) {
|
||||||
break;
|
break;
|
||||||
@@ -463,10 +465,6 @@ pub const Zone = struct {
|
|||||||
slab_size: usize,
|
slab_size: usize,
|
||||||
/// Size of a chunk.
|
/// Size of a chunk.
|
||||||
chunk_size: usize,
|
chunk_size: usize,
|
||||||
/// Max color for slab coloring.
|
|
||||||
max_color: u16,
|
|
||||||
/// Current color for slab coloring.
|
|
||||||
color: u16,
|
|
||||||
/// Zone lock.
|
/// Zone lock.
|
||||||
lock: ke.Mutex,
|
lock: ke.Mutex,
|
||||||
/// List of full slabs in this zone.
|
/// List of full slabs in this zone.
|
||||||
@@ -514,13 +512,7 @@ pub const Zone = struct {
|
|||||||
const obj_align = if (options.alignment == 0) slab_align else options.alignment;
|
const obj_align = if (options.alignment == 0) slab_align else options.alignment;
|
||||||
const chunk_size = std.mem.alignForward(usize, size, obj_align);
|
const chunk_size = std.mem.alignForward(usize, size, obj_align);
|
||||||
|
|
||||||
const slab_size, const max_color = if (size <= small_slab_size) blk: {
|
const slab_size = if (size <= small_slab_size) mm.page_size else Slab.calc_slab_size(chunk_size);
|
||||||
const ss = mm.page_size;
|
|
||||||
break :blk .{ ss, @rem(ss - @sizeOf(Slab), chunk_size) };
|
|
||||||
} else blk: {
|
|
||||||
const ss = Slab.calc_slab_size(chunk_size);
|
|
||||||
break :blk .{ ss, @rem(ss, chunk_size) };
|
|
||||||
};
|
|
||||||
|
|
||||||
self.full_slabs.init();
|
self.full_slabs.init();
|
||||||
self.partial_slabs.init();
|
self.partial_slabs.init();
|
||||||
@@ -530,8 +522,6 @@ pub const Zone = struct {
|
|||||||
self.alignment = obj_align;
|
self.alignment = obj_align;
|
||||||
self.slab_size = slab_size;
|
self.slab_size = slab_size;
|
||||||
self.chunk_size = chunk_size;
|
self.chunk_size = chunk_size;
|
||||||
self.max_color = @intCast(max_color);
|
|
||||||
self.color = 0;
|
|
||||||
self.ctor = options.ctor;
|
self.ctor = options.ctor;
|
||||||
self.dtor = options.dtor;
|
self.dtor = options.dtor;
|
||||||
self.lock = .init();
|
self.lock = .init();
|
||||||
@@ -1118,17 +1108,7 @@ pub const Zone = struct {
|
|||||||
fn slab_create_small(self: *Self, policy: mm.WaitPolicy) mm.Error!*Slab {
|
fn slab_create_small(self: *Self, policy: mm.WaitPolicy) mm.Error!*Slab {
|
||||||
const buf = try alloc_page(policy);
|
const buf = try alloc_page(policy);
|
||||||
|
|
||||||
// We employ a simple coloring scheme; every time a slab is created,
|
const capacity = Slab.calc_capacity(self.chunk_size, self.alignment);
|
||||||
// the color is shifted by the alignment. This is done until we reach the
|
|
||||||
// max color (which is when there is no space left in the slab buffer).
|
|
||||||
// This ensures uniform buffer address distribution.
|
|
||||||
self.color += self.alignment;
|
|
||||||
|
|
||||||
if (self.color > self.max_color) {
|
|
||||||
self.color = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const capacity = Slab.calc_capacity(self.chunk_size, self.alignment, self.color);
|
|
||||||
|
|
||||||
// Slab info is located at the beginning of the page.
|
// Slab info is located at the beginning of the page.
|
||||||
var slab: *Slab = @ptrCast(@alignCast(buf));
|
var slab: *Slab = @ptrCast(@alignCast(buf));
|
||||||
@@ -1137,7 +1117,7 @@ pub const Zone = struct {
|
|||||||
slab.refcount = 0;
|
slab.refcount = 0;
|
||||||
slab.capacity = @intCast(capacity);
|
slab.capacity = @intCast(capacity);
|
||||||
const meta_end = @intFromPtr(slab) + @sizeOf(Slab) + Slab.bitmap_bytes(capacity);
|
const meta_end = @intFromPtr(slab) + @sizeOf(Slab) + Slab.bitmap_bytes(capacity);
|
||||||
slab.base = std.mem.alignForward(usize, meta_end, self.alignment) + self.color;
|
slab.base = std.mem.alignForward(usize, meta_end, self.alignment);
|
||||||
|
|
||||||
const bm = slab.bitmap();
|
const bm = slab.bitmap();
|
||||||
const full_words = capacity / 64;
|
const full_words = capacity / 64;
|
||||||
@@ -1158,13 +1138,7 @@ pub const Zone = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn slab_create_large(self: *Self, policy: mm.WaitPolicy) mm.Error!*Slab {
|
fn slab_create_large(self: *Self, policy: mm.WaitPolicy) mm.Error!*Slab {
|
||||||
self.color += self.alignment;
|
const capacity = (self.slab_size) / self.chunk_size;
|
||||||
|
|
||||||
if (self.color > self.max_color) {
|
|
||||||
self.color = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const capacity = (self.slab_size - self.color) / self.chunk_size;
|
|
||||||
const buf = try mi.heap.alloc(self.slab_size, policy);
|
const buf = try mi.heap.alloc(self.slab_size, policy);
|
||||||
|
|
||||||
var ret: *Slab = @ptrCast(@alignCast(try gpa.alloc(u8, @sizeOf(Slab) + Slab.bitmap_bytes(capacity))));
|
var ret: *Slab = @ptrCast(@alignCast(try gpa.alloc(u8, @sizeOf(Slab) + Slab.bitmap_bytes(capacity))));
|
||||||
@@ -1177,8 +1151,8 @@ pub const Zone = struct {
|
|||||||
const rem = capacity % 64;
|
const rem = capacity % 64;
|
||||||
if (rem > 0) bm[full_words] = (@as(u64, 1) << @intCast(rem)) - 1;
|
if (rem > 0) bm[full_words] = (@as(u64, 1) << @intCast(rem)) - 1;
|
||||||
|
|
||||||
ret.base = @intFromPtr(buf) + self.color;
|
ret.link = undefined;
|
||||||
ret.color = self.color;
|
ret.base = @intFromPtr(buf);
|
||||||
ret.capacity = @intCast(capacity);
|
ret.capacity = @intCast(capacity);
|
||||||
ret.refcount = 0;
|
ret.refcount = 0;
|
||||||
ret.alloc_rr = 0;
|
ret.alloc_rr = 0;
|
||||||
@@ -1213,7 +1187,7 @@ pub const Zone = struct {
|
|||||||
const alloc_size = @sizeOf(Slab) + Slab.bitmap_bytes(slab.capacity);
|
const alloc_size = @sizeOf(Slab) + Slab.bitmap_bytes(slab.capacity);
|
||||||
gpa.free(@as([*]u8, @ptrCast(slab))[0..alloc_size]);
|
gpa.free(@as([*]u8, @ptrCast(slab))[0..alloc_size]);
|
||||||
|
|
||||||
mm.heap.free(slab.base - slab.color, self.slab_size);
|
mm.heap.free(slab.base, self.slab_size);
|
||||||
} else {
|
} else {
|
||||||
free_page(@ptrFromInt(std.mem.alignBackward(usize, @intFromPtr(slab), mm.page_size)));
|
free_page(@ptrFromInt(std.mem.alignBackward(usize, @intFromPtr(slab), mm.page_size)));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user