Hallo,
Damit bist du doch einmal das Problem der Löcher los (die sind nie frei) und kannst gleichzeitig immer den ersten freien Descriptor (das erste Baumblatt) zurückgeben.
Es geht mir nicht darum das man diese "Löcher" allokieren könnte, sondern das man sie freigeben kann und dann könnten sie allokiert werden!
Freigeben kann man Ressourcen aber nur dann, wenn man sie besitzt oder liege ich da falsch? Wenn dein Kernel sich die Löcher selbst greift, kann nur er sie wieder freigeben und genau das tut er ja nie...
Ein Programm darf nur Ressourcen in Anspruch nehmen, die es vom System angefordert und zugewiesen bekommen hat - und auch nur diese Ressourcen darf es wieder freigeben. Löcher werden aber niemals zugewiesen, können also auch nicht freigegeben werden. Und die Verwaltung der zugewiesenen Ressourcen obliegt dem Programm selbst, also hat sich der Kernel nicht drum zu kümmern.
Du vertraust einem Programm aber ganz schön. Denn dann würde es auch keine Buffer-Overflows geben, wenn die Programme nur soviele Daten "schicken" wie sie dürfen!
Darum gibt es Zugriffsrechte. Prozesse werden gekillt, wenn sie auf ihnen nicht gehörende Ressourcen zugreifen wollen. Wenn ein Programm Ressourcen freigeben möchte, die ihm nicht gehören, wird es gekillt. Wenn ein Programm Ressourcen anfordern möchte, die bereits ein anderes Programm hat, wird die Anforderung abgelehnt. Will ein Programm Daten ausführen, wird es gekillt. Will ein Programm auf nur lesbare Pages schreiben, wird es gekillt. Und so weiter.
In seinen eigenen Ressourcen darf sich ein jeder Prozess frei austoben, der Kernel hat nur die Aufgabe, die Prozesse voreinander zu schützen, gegenseitig voneinander abzusichern und Dienste anzubieten, die Interprozesskommunikation ermöglichen. Buffer-Overflows sind Programmfehler, keine Betriebssystemfehler. Du solltest deinen Kernel also gegen Buffer-Overflows absichern, wie es jedes Programm auch tun muss.
Es geht um das freigeben von Speicher/virtuellem Speicher und da gibt es Sachen im UserSpace die ich gerne davor schützen würde.
Wenn dein Programm Speicher freigeben möchte, dann wird es damit schon Recht haben. Greift es danach nochmal auf diesen Speicher zu, wird es gekillt - das darf man nämlich nicht.
Zumal sich mein Kernel wahrscheinlich mehr um den UserSpace kümmert als das normalerweise der Fall ist.
Ich denke da wohl anders drüber.
Dann wäre meine Frage wie du das Problem lösen willst, das der VMM Datenstrukturen dynamisch allokiert und damit er das machen kann muss er ja wieder (irgendwann) auf den VMM zugreifen.
Du brauchst also ne Möglichkeit im VMM Speicher zu allokieren ohne das du den VMM dazu brauchst.
Es geht also darum, dass der VMM Speicher für sich selbst unter Verwendung des VMM reservieren muss. Genau das darf er aber nicht tun. Da fallen mir spontan nur zwei Möglichkeiten ein, die ich (mangels eigenem OS) nicht ausführlich erklären kann. Also keine Garantie auf Funktion [oder das ich überhaupt etwas verstehe].
(a) Der VMM reserviert sich selbst keinen Speicher dynamisch.
Das setzt voraus, dass die benötigten Datenstrukturen für den VMM in ihrer Größe zur Laufzeit statisch sind. Keine Ahnung, ob das funktioniert. Immerhin kann man die Größe der Datenstrukturen ermitteln und festlegen, bevor der VMM funktionsbereit sein muss.
Führt zwangsweise zu einem sehr sparsamen VMM mit vielen Einstellmöglichkeiten, für Mikrocontroller oder sowas sicherlich gut machbar. Ansonsten unelegant.
(b) Der VMM reserviert sich Speicher nicht über den VMM.
Da der VMM selbst die Hoheit über den virtuellen Adressraum hat, muss er seine eigenen Datenstrukturen ja nicht in den gleichen Büchern führen, wie die restlichen Datenstrukturen. Er darf - im Gegensatz zu allen anderen - die Ressourcen auch erst verwenden und danach die Buchführung betreiben, schließlich verwaltet er ja die Ressourcen und was nicht durch seine Finger gegangen ist, darf auch niemand anders nutzen.
Konkret darf der VMM einfach einen Block virtuellen, bisher ungenutzten Adressraum für sich selbst nehmen, ihn benutzen und erst im Anschluss daran die Bäume pflegen.
Soweit ich dich und das Slab Allocator-Prinzip verstehe, fragt die Anwendung beim Slab Allocator nach Objekten, die der Slab Allocator aus einem Cache zurückgibt. Ist im Cache nichts mehr frei, muss ein neues Stück Speicher zu einem neuen Cache für Objekte umfunktioniert werden und dazu fragt der Slab Allocator beim VMM an. In diesem Augenblick darf der VMM niemals beim Slab Allocator nach Objekten für sich selbst fragen, denn das wäre unzulässiges Layering und eine zirkuläre Abhängigkeit. Dafür gibt es wieder zwei Auswege, die mir einfallen:
(a) Der VMM benutzt keinen Slab Allocator.
Der VMM kümmert sich vollautonom um den virtuellen Speicher und benutzt selbst den PMM für den Zugriff auf den physischen Speicher. Mehr nicht. Der Slab Allocator nutzt dann den VMM, um seine Caches zu bauen, für alles, was so von den oberen Schichten (Kernel, Treiber, Anwendungen) anfällt. Da er den VMM benötigt, darf er diesen nicht verwalten. Du hast also mehrere getrennte Schichten.
(b) Der VMM ist gleichzeitig der Slab Allocator.
Damit verwischst du die Schichten, indem du grundsätzlich VMM und Slab Allocator gemeinsam implementierst. Du verwaltest somit keinen virtuellen Speicher mehr, sondern direkt Slab-Caches im physischen Speicher. Dein Slab Allocator redet also nach unten nicht mit einem VMM, sondern direkt mit dem PMM und verwaltet den virtuellen Speicher für sich selbst (und niemand anders hat darauf Zugriff).
Das geht natürlich nicht, wenn du Objekte irgendwo außerhalb des physischen Speichers alloziieren möchtest. Moderne nVidia-/ATI-Grafikkarten haben eine eigene MMU und die Speicherverwaltung im Grafikspeicher unterliegt gewissen Grenzen, wenn man so Sachen wie CUDA haben will; das lässt sich nicht ausschließlich über Slabs lösen. (Allerdings kann man das natürlich im Grafiktreiber implementieren, statt im System. Und für dich sollte das ohnehin irrelevant sein.)
Hoffe, das hilft. Im VMM-Thread kann ich nicht wirklich etwas beitragen, da ich das Problem an anderer Stelle sehe. Du verwischst die Grenzen nicht vollständig, sondern implementierst schnittstellenfremde Durchgriffe durch die Ebenen, sodaß dein VMM den Slab Allocator kennt und dein Slab Allocator den VMM mit dem Ziel, dass dein VMM selbst Slabs zu seiner eigenen Verwaltung verwenden kann. Das ist nicht einfach, nicht sauber und führt zu Problemen, wenn du Teile davon austauschen möchtest.
Theoretische Zwischenfrage: Ist es möglich, in den Adressraum jeden Prozesses nur eine einzelne Page einzublenden, die nur eine IPC-Funktion enthält und auf diese Weise Kernelfunktionen bereitzustellen?
Das musst du genauer erklären!
Ich mache mal einen eigenen Thread auf, denn das ist hier OT. (Gehört nicht dieser Thread nach OS-Design? Hier geht es doch um Ideen, nicht um die konkrete Implementierung - oder hab ich deinen Thread versehentlich theoretisiert?)
Gruß,
Svenska