 All right, let's get started. So today we will mostly talk about swapping. Before that, let's do a quick recap of what we talked about last time. We talked about the page table design alternatives. So one option is I see a lot of people using is the link list option where you have one link list and note per virtual to physical page mapping, right? So I see also different styles of link list. So somebody may have a global link list per address space. You have one link list for each address space. Some others may have a link list per region. So I saw people doing multiple link lists where he have one link list per region for code segment, for data segment. Both options are okay. As long as you are comfortable with those link list manipulation operations. And so this is the link list design option. We talked about the advantages and disadvantages of this approach. Basically it's a link list. Everybody is familiar with link list. So you do a lot of link list operations in the data structure course. The disadvantage of course is the query time where each time you want to get a virtual to physical mapping the worst case is you have to traverse all in the entire link list. And we also talked about the page table design. So this is the second option where you use multiple level page tables. So this is the most classical way of doing this. But so far I haven't seen people using this option yet. Perhaps the link list option is too simple to use. Again, the advantage of this approach is that no matter what virtual address you are querying you always have constant time, look up time of the page table. And of course the disadvantage will be that the two level page tables may sometimes be too complex to deal with. So we briefly talked about the address-based design. So this is a view of the user's virtual address from zero up to two gigabyte, the OX at a median value. So the user may have a code segment, data segment, and heap. So there are most programs who have these two segments. And some user program may use malloc. In that case, that user program has one more region called heap which has a variable size. And every program has a stack segment which starts from the top of the user address space and grows downwards. So those heap and stack are two special segments in the sense that the size can change. Other segments like code and data, the size are fixed. They are, you know the size by ASD5 regions, the function. Also for each segment, each segment may have different permissions. So for example, the code segment is read-only but also have a permission called executable. The data segment is usually read and writeable. So of course heap and stack are read and writeable. So you want to remember that permission information somewhere in your address space. So later on when you have a VM fault, you can query the permission information to know whether or not the user program has permission to write or read this segment. So finally, we talk about the TLB. So what's the TLB in this MIPS architecture looks like? So TLB is basically a hardware map where it translates the virtual page number which is up higher 20 bit of the virtual address to the physical page number which is a higher 20 bit of the physical address. It also have some other flags that determine what the user program can do about this page or can do about this TLB entry. So we have a valid bit flag which indicate whether or not this TLB entry contains a valid translation. We have a dirty bit. So as we said, the dirty bit is not actually a flag indicate whether this page is dirty or not. It's actually a flag that determine if the user program can write to the page. So whenever the CPU got instruction say write to this memory location, the CPU query the TLB entry and gets the physical address. The CPU will also look at this bit, say if this bit is zero, then the CPU will throw a VMFOT virtual memory exception saying that the TLB entry says that this page is not writable but now the user try to write to this page. So that hardware doesn't know what to do. What the hardware does is throw a virtual memory exception so that you can handle this. So this bit determines that whether or not user can write to that. You may wonder that why do we want to have this flag? Why do we want to protect the page so that the user cannot write to it? Any ideas on this? So why does the hardware provide such a functionality called dirty bit to determine whether or not the user program can write to this page? Nobody? What's that? Avoid checking the page. How? You mean clear the bit so that user cannot write to it? So my question is why don't just allow write operation by default? Yeah, that's one reason. We want to enforce the permission, right? So for some segment like the code segment, the permission is redolent. So we don't want the user to write to that segment. And if user does write to that, we want to know. That's why we tell the hardware that user cannot write to this. If it writes, raise the exception, let me know, I will handle it. Inside of VNFOT, that's one reason. And some other times you will see code that also set the data segment to be redolent in the TLB entry. So what's the reason for that? For the code segment, we want to enforce the correctness. We don't want the user to modify the code segment. For data segment, sometimes you may also want to set the dirty bit to be zero, meaning that you don't want the user program to write to that segment or write to the page. Yeah, yes, that's another reason actually. So sometimes you don't want the user write to it, but the user actually has permission to write to that page. You just want to know when you start writing so that you can duplicate the page. And the other reason I'm trying to get to is that when you do swapping, you may find it handy to differentiate the clean pages and the dirty pages. Clean means that this page, the content of this page, first of all, this page has a copy in disk. Second, the content of these two copies, when in memory and when in disk are the same, identical. That means that this page in memory has a backup copy in disk. In this case, the page's data is clean. Clean in the sense that, so later on, for example, if you wanted to swap out this page, it means you don't actually need to write the page content to disk because the page already has a copy in disk, right? But if this page is writable, then user may modify the content of the page in memory. Then the page content will be different, the copy in disk and the copy in memory. In that case, the page data we say is dirty. Dirty in the sense that the page content in memory is different with disk. So later on, if you choose to swap out that page, you actually need to write the content to disk. So that's dirty pages and that's clean pages. So in swapping, so first you scan the com app entry and finally you run out of physical pages. So you decide to pick a page and swap that page out. And what you prefer is a clean page because you can just discard the page content and you know that there is some copy in disk that has the content, right? So you save a disk IO. So you always prefer the clean pages first. Then if you have no clean pages, every page is dirty, then you really have to swap out some page. So how do you know a page is clean? Or so you know a page is clean when you just flush out that page. Just write that page to disk. But how do you know when the page becomes dirty? You cannot just read the content from disk and do the byte differentiation difference comparison. So the way you do it is that you set this page to be redolent. Even though it's a data segment page, it should be writeable, but you still set it to redolent. So once the user tries to write this page, you get an exception. And you carry the page table and figure out this is the data segment, the user has write permission, but the page state is clean. So what you do is that you mark that page as dirty because user is going to modify the content of the page. And then you set the TRB entry bit dirty to one to enable this write. So we basically leave the three usage of this dirty bit. One is to enforce the correctness. We don't want the user to write to code segment. And the second usage is the copy and write. So we want to know when user starts writing some page, if that page is copy and write, at that point, we want to make the duplication. And the third usage is that you want to protect the clean pages, right? So when the user tries to write to that page, at that point, you know that page is no longer clean. Its content is being modified and you need to mark it as dirty. So later on, you cannot just discard the content. You have to actually flush that page to disk. And finally, there is no catch bit which you don't need to care. I think the default one is one when you make up TRB entry. Is that correct? So this bit, you don't need to pay any attention with. I think the default value is one and that'll be fine. So any questions? Yeah. What's that? 64 pages. Yeah, I see. Yes. Well, any reasonable user program will use more than that. So you only have a limited number of TRB entries, but you have more pages than that, which means that sometimes you will always get TRB fault. So you need to kick out some TRB entry and plug in the correct value. Later on, when the user actually access the previous page where you kick out the TRB entry, there will be no translation for that. So you have a TRB fault again. That's why we say that there's a difference of TRB fault and page fault. A TRB fault is not necessarily a page fault. It may be that the page is already there. It's just that there is no TRB mappings for it. So in that case, you have a TRB fault, but you don't have page fault. Not any. Being true, being false clearly doesn't use that much. But parallel VM and some other huge, for example, may use up more than that. Yeah. So here there are two actually algorithms related policy here. One is a swapping policy, which page you choose to swap out. You can use some least recently used random first in first out algorithm. So another similar algorithm here is which TRB entry do you choose to use when you want to plug in some values? So ideally, you want to find that available TRB entries. So you don't need to kick out any TRB entries. That'd be perfect. But in some case, you will find all the TRB entries are being used. So in that case, which TRB entry do you choose to kick out or invalidate? You plug your values in there. There is also some, you can also do some algorithm on this. For example, do first in first out, do random, do have some kind of tracking information to know when is the last time this page is accessed. But for this assignment, I would suggest you for both policies, start with random first because it's simple and it works. Just whenever you want to kick out a page or you want to kick out a TRB entry, just randomly choose one. And if this works, then you can, and if you have time and you want to, you can implement some other algorithm, but use random as the best line and use that first. That's, yeah. Well, you first want to find the available TRB entry. If you have to kick out some TRB entry, then you use random. It doesn't make sense to use random at the very beginning because you know you will have entries to use. Yeah. Any other questions? So this is the address space related material. So today, we'll mostly talk about swiping, especially we want to have a very clear picture of what's the state of the virtual and physical page and what it means for a page to each state and how does the page transit from one state to another state. So then we'll talk about the process of swap out a page and also a process of swiping a page. So before you do anything swiping related stuff, you want to make sure that you pass all the tests that do not require swiping. So this is a list of the tests that the auto weather will run with this many RAM size. So you want to make sure that check your CIS 161 configuration and set the RAM size to be exactly that much and I don't remember exactly how many CPU cores are there. Four, two. For all the test cases, okay. For all the test cases, two cores, this many memory size and run this test. Make sure you can pass this before you move on to do swiping. Otherwise, if there is some bug, you want to find that early on instead of later on, when you involve swiping, you have so many variables, you don't know where the bug is probably from. So you want to do one step at a time. At the very least, you should pass the call map test, which is cam 1 and cam 2, to make sure that your call map is solid and you want to run that cam 1 and cam 2 multiple times within one kernel session. So you start up the kernel, you run cam 1, you run cam 1 again and again, then you run cam 2 and again and again and so on. So you shouldn't have any memory leaks and you should be able to run cam 1 and cam 2 multiple times without exiting the kernel. So that way you know the call map is solid. You can rely on that. Then you move on to the basic user programs like Bintro v4s, you run Shell, you run Bintro v4s multiple times to make sure it's okay. Remember, you only have 500 kilobytes there. So if you have some memory leak or you fail to clean up all those pages, you will have those problems. So doing that help you spot the problems early on instead of leaving it to the latest stages. Then you want to do meta test of which basically you need to implement as break syscall, right? Again, you only have 512 kilobytes of memory. Make sure you can run that multiple times and then the same applies to protocol, runnacle and crash. So you also have some assembly specific test cases. Excuse me. For example, metrics, modification, sort and hilt. These are meant to be memory intensive memory intensive and also CPU intensive. And some of them may use multiple threads like fork test and triple metrics multiplication. So that's the test case and make sure you can run this without any problem before you do swapping. Any questions on the test cases? Yeah, the parallel VM one may be tricky because you only have two megabytes of memory where you have to spawn like 20 or so thread. So if you don't make your thread structure efficiently, you may have some problem that you will not be able to run parallel VM with two megabytes of memory. And if you, so first try to strict down any unnecessary death structures like if your file table is too large and all that. If you don't, if you try it very hard and you cannot run parallel VM in two megabytes memory and try to enlarge the memory to like four megabytes, make sure you can run that multiple times, then you can move on to swapping because with swapping, this problem will go away. Whenever you run out of memory, you always have to swap some page and you don't have any memory issue, memory limit issue. Any questions on the test cases? So which test have you been able to run? Which one, who can run all of them? No one? Well, at least the CAM2, that's everybody, right? And what about bintro bintforce, the basic one? No? For that you need a pretty decent address space. So bintro bintforce is not that easy, actually. You need s create, s define region, s copy, s activate and all that function. And also you need a page table and also you need a region information and also you need a VM for handler to be able to run bintro bintforce. So these are the test cases. So in the very first recitations about the physical page management, we briefly mentioned the state. So now with everything, with user address space, with swapping, let's see what state can a physical page be. So when you initialize your com app in VmpleStrap, you know that there will be only two states. Whether either is fixed or be used by the earlier Camelogs or Kernels. So the very first few pages will be occupied. In this case, we call it fixed, right? And all pages beyond that will be free, right? So at this point in VmpleStrap, you only have two possible page states, used or not used. Used is fixed here because you cannot swap it. So we, or you can call it pinned, it's pinned to memory. So we, if we don't have any user program running, we only have kernel when you run cam one, cam two, that will be the case. So a free page can become a fixed page when you call allocated key pages and you return that pages. Our fixed pages can become free when you call free key page on it. It's very simple. It's only free and fixed. And the page that can move between these two, right? Once you have user program and user address space since becomes complicated. So inside Vmfold, you get a page fault. You realize that you need to allocate a map. You need to allocate a physical page. Once you allocate that, what's the state of the physical page? Here, we're talking about the physical page. So the state should go into your call map entry, physical page. So the page, the state of that page will be one of this. Well, at least if you, at this point, if you merge these two into one, you can call it used by user program, right? If you don't consider swapping yet. But at this point, we really want to consider swapping. So with swapping, what's the state of the first allocated page, physical page? Yeah, we talk about dirty and clean. Dirty means that this page, two cases. Either this page doesn't have a copy in disk, which is the case when we first allocate it. Or the page content, or this page has a copy in disk, but the content is different. Both cases means that this page is dirty, right? So when you first allocate the page, the page status is dirty. Then later on, when you try to swap out that page, you need to write the page content to disk, right? After you do that, the page will have a copy in disk and the copy's content is the same. At that point, the page's content is clean, right? Clean means that, yeah, so we already said what clean means. But so later on, when you swap out, either you swap out or you flush. So say you have a flush function which periodically flush the content to disk. So when you have VN4, you can save a few disk IOs. What if the user writes to that page again, right? When you swap out, you know that you have to set the TRB dirty bit of that TRB entry to be zero. So that when user writes to that page, you would know and you would mark the page content, page status to be dirty, right? So this is the translation between the dirty and clean. How does the dirty becomes clean? Either you flush or you swap out. How does the clean page become a dirty page? Well, that's because the user writes to that page and you want to remember that that somewhere in your com app. And finally, when you destroy a address space, either these dirty or clean pages can become free again. Nobody is using that. So free is simple to understand. Fixed meaning that it's used by the kernel. Dirty or clean mean that it's used by the user. And the state indicate whether this page has a copy of this and or not. And the difference of dirty and clean is that when you want to swap out the page, it determines whether or not you need to write that page content to disk. So these are the state of the physical pages. And let's take a look what's the state of the virtual pages. So of course, physical page state goes into com app entries and virtual page state goes into where? The page table entry, right? Page table is corresponding to virtual pages. So this is your address space. This is the regions you have. And initially, so when you call AS create and you call a lot of we call AS define region to define different regions. Right after AS define region, every virtual pages that is what? Is on mapped, right? At that point, the virtual pages are only virtual. There is no physical pages corresponding to that virtual page, right? So at that point, the page state is on mapped. Then user program starts running and we'll trigger page fault on those virtual addresses. You, in VM for the handler, you realize you need to allocate a page. So you allocate the physical page and set up the page table entry. So at that point, the virtual page becomes mapped. Meaning that this page corresponding to some page in the memory, right? And then later on, so when some other process have a page fault, you realize you don't have enough physical pages to use. You're determined to swap out that page. At that point, what's the state of that virtual page? Well, it's still corresponding to some page. Just that the page is no longer in memory. It's in disk now. So now the page, the virtual page state is swapped, right? And later on, when the original process access this page again, you will have another page fault or TRB fault and you will swap that page back in. At that point, the page, the virtual page again, corresponding to some physical pages. So it becomes mapped again. So this is the transition of the state of the virtual pages, right? This goes into your page table entry. Any questions on the physical and the virtual page state transition? It's very important to understand this so that you don't get lost in all those gory details. Yeah. So that's how you determine whether or not it's a page fault or not. So here's the thing. So you have a VM fault and inside VM fault, how do you know whether or not you need to allocate a page? Yeah, that's because you're using LakeList. That's right. In that case, mapped mean that you have a page type entry for that. All mapped mean that you don't have a page. Well, in that case, a page will still have two state. All mapped and mapped. Just that the format of the state is different. In my case, I may use some flag to indicate because I'm using two level page tables, I may use some flag to indicate whether or not this page is mapped or not. And if you're using LakeList, well, the existence of the LakeList node for this virtual page is indication of whether or not this virtual page is mapped. If you are using LakeList, you don't have to explicitly store the mapped information. That information is already stored by the existence of the page type of node for that virtual page. But you do need to store mapped and swapped information so that in both cases, you will have a LakeList node for that virtual page. Then you will need to figure out where do I actually find this page, whether in memory or in disk. In memory, you want to find the physical page address. And in disk, you need to find out which swap slot you do use. Any other questions? Okay, so yeah. So this is the state of the virtual and physical pages. So now let's talk about swapping. So the big two picture of swapping that there is two main interface, swap out and swap in. When do you need to swap out? So whenever you want to allocate a physical page, either for kernel or for user program, you scan your com app entry and find that you don't have any free physical pages. This is the point where you determine you need to swap out some page so that you can make space for the new allocation request. Later on, so swap may or may not involve a disk IO, depending on which page you choose to swap. If you choose to swap a clean page and like you, you don't have to do any disk IO. If you choose to swap a dirty page, then you will have to write the page into disk. Then later on, because you are actually kicking out of some page from memory to disk, later on if some user access that page, you will have a tier before. At that point, you will have to bring that page from disk to memory again. So you need to do swap in. And notice that in the process, in order to swap in a page, you need to first allocate a page first, so that you can read the content into the physical page. But to be able to allocate a page, you may trigger another swap out because you may already run out of physical pages. So swap in may contain a swap out. And keep this in mind when you deal with the synchronization issues of swapping. So this is a big picture of the swapping part. And so about swap out, the, well, of course, the most major part is actually write the page content to disk. Though the question here is first of all, where do you store all the swapped pages, right? Whether or not you want to store them in a file or in a dedicated swap disk, we will talk about different options in the next slide. And also when you choose a swap victim and you swap out that page, how do you notify the page owner, which is the process that this page is no longer in memory. It's already being swapped to disk. And also when you write, you cannot just write this page to some arbitrary disk placed on disk. You need to remember where to do right to it. So later on when you do swap in, you can find that page and bring back the content. So these are the questions of the swapping. So as I said in the previous slide, where can you store all those swapped pages? Well, I guess after assignment two, you are pretty familiar with the file stuff. So a more intuitive option would be to just open a file and write the page content to that file. Well, it will work. You can open some file and write to it, write the page content to it. But a more better option will be use a dedicated swap disk, meaning that you can open the disk as a raw file and there will be no file system on it. You can store your page content there. In both ways, the way to use it is quite similar. The only difference is the file name when you call VFS open. So if you open the configuration file of OS 161, you will find that there are two disk configurations, disk one and disk two. If you want to use a swap disk, actually for each option, you need to make one of these values large to be able to set the swap space. I think one sector is 512 bytes and you times that by this sector number, you will get a total swap disk size. So we will notice that there are two disks. One is used for the emulated file system called emuFS zero. Another is not used. So you can use that by calling VFS open with this file name. So if you want to use a normal file to store all the swap pages, you can just substitute this to anything, to like whatever file name you choose. Or if you use this particular file name, the VFS open will know that you want to open a disk instead of a normal file. So it's up to you to choose which one to use. And it doesn't actually matter much of which one to use. You have to, so one thing you want to do is that you want to set this sector number to be very large so that you have enough swap space. And that's it. So when you call VFS open to get a swap file, you can use either this file name or any arbitrary file name you like. So this is where to store all those files. And inside that file, we all know that a file is a one-dimensional byte storage. You can store 4K bytes here in various locations. And when you do UIO, you can specify the offset so you can virtually split the file into swap slot. One slot is 4K bytes. So you can number the slots as zero, one, two, three, four, five. And there is very easy translation between the slot and the offset, the slot ID and the offset. So the next step is how do you notify the owner so that the owner will know this page is no longer in our memory. Well, to be able to notify the owner, first you need to figure out what the owners are, right? Remember in the first recitation about physical pages that we said in the com app, you may want to store the owner information. Their owner means address page and virtual address. So which virtual address this page is being mapped to and where it is being mapped to. So this is the reason why you want to store that information at the first place. If you don't want to do swapping, you don't need to store the owner information at all. You don't need to know the reverse mapping or physical to virtual. This is the reason why you want that mapping. So when you scan your com app and you choose a victim, you want to find out where this physical page is being mapped to, right? You want to figure out, find out the address space and also find out the virtual address. So once you have that information, you can notify the owner by modifying the owner's page table, right? Given the address space and virtual address, you should be able to locate that page table entry for that virtual page. And then in that virtual page table entry, you can set some flags maybe to indicate this page is no longer in memory, right? But first, you want to prevent access to the page because it's possible that that process is running in another CPU core, right? You have multiple CPU cores. So to be able to do that, you want to first shoot down the TIB entries for that virtual address. Once you do that, you will be sure that nobody can access that virtual page unless it triggers a VM fault because there will be no TIB translation for that. Well, this may be a little bit trigger to understand at first, but when you do swapping, you will soon realize that, okay, I'm about to write out a page. And in the process, I might go to sleep because I'm doing this IO. In the process, how do I make sure that nobody else access this page? Because a page is 4K. For example, when you adjust in the middle of it, some other process may modify the content of the previous bytes, right? In that case, you have to redo the swapping again because you want to make sure the page content of the memory copy and this copy is identical. So you don't want anybody to write to that page while you do swapping. The way you do it is to shoot down the TIB entries for this virtual to physical mapping so that nobody will be able to access that page at all while you do swapping. And this involves some synchronization here to coordinate the process that actually swap out of the page under the owner process that maybe may access this page. Any questions on this? I see a lot of confused eyes. So in high level, do you understand what I'm saying here? When you do swapping, you choose a victim. You clearly don't want any other process access this page while you do swapping because swapping is not just happening instantaneously. It takes a while, right? It involves this IO here. In the process, in that time duration, you don't want anybody else access this page. At least you don't want anybody else write to this page. Otherwise, it will totally invalidate your purpose of swap out, right? To be able to do that, to be able to be sure that nobody will access this page while you do swapping, you have to do something before you swap, right? To set a lock or set a guard so that nobody else can access this page. This is conceptually what you need to do. And the imperfection, while you can figure out on your own, the basically the way to do it is that to shut down the TLB entries for this page. So after you swap out, actually before you swap out, another thing you want to determine is that where do I write the page to, right? It's a swap file, so you need to decide the offset in that file that you want to store the page, right? And in order to do that, you need another map which is quite similar to a call map which you can call it a swap map. It's basically a mapping between address space plus virtual address to a swap slot. So it's a mapping like this, it's a key value map. The key being the address space and the virtual address, the value being the swap slot, right? Imagine you already have such a map. Whenever you want to swap out the page, you know the address space, you know the virtual address from the call map. Then given this two information, this structure will give you a swap slot, an index or offset, right? So suppose this offset is two, then you know you should start from 8K because the zero one is being used and you should write it from two, right? So you need to devise such a data structure that first of all, given address space and virtual address, give me a swap slot I can use, right? And this structure should be smart enough to, for example, the structure may already have a mapping for that virtual address space plus virtual address to swap slot. It should be able to reuse that. So for example, the first time you swap out a page, it should allocate a slot for you, a new slot, right? The second time you swap that page, it should still return use that slot. It doesn't make sense to use another swap slot. You can reuse the storage space that you use for the page before. So you need to come up with some data structure plus function that help you do the mapping. The mapping from address space plus virtual address to the slot index. And finally, swap in. Swapping in, actually, if you have swapped out, swapping is kind of easier. So first of all, you need to do swapping only in VMFOT, right? You only need to swap in a page because somebody wants to access that page and you swap out that page before. So inside VMFOT, you figure out, okay, you need to swap in the page. How? Well, you already have a page type entry for that, which means this page is being accessed before and is being allocated before. And you query some flag in that page type entry that indicate this page is being swapped out. In that case, you know that some user process is trying to access a virtual page that is being previously swapped out. That's the time where you need to swap in that page. So first of all, you need to figure out, well, the very first thing is that you want to allocate a physical page to be able to hold the content of the swapped out page. So allocate a physical page, then get the content. Again, the question here is how do you know which swap slot that page is? You know that by the data structure we mentioned in the last slide. Given address space, which is a current address space, given a virtual address, give me the swap slot. Then I get the offset in that swap file. I read the content into the allocated physical page and I set up the page type entry, set up the TLB, and I'm done with this VMFort. So you only need to do swap in inside the VMFort. And another trick thing here is that swap in may trigger a swap out. So you should be careful when you do synchronizations. Any questions about swap out and swap in the process in general? Okay, so finally, let's look at what changes you need to make when you introduce swap in your address space. So first of all, in AS copy. So previously, in AS copy, you just traverse all those page type entries and copy every physical page, right? Once you have swap in, now you may encounter some cases where this page is not in memory, it's in disk. In that case, what do you do? Copy on disk, right? You allocate another swap slot for the new address spaces page, copy the content, we'll read the content from disk to memory and from memory to disk, copy that. So when you do AS copy, you need not only copy the in-memory pages, you also need to copy the in-disk pages, swapped pages. That's the change you need to do in AS copy. And again, in AS destroy, you not only need to destroy all the, free all the pages in memory, you also free up all the swapped pages in disk. So that's the changes to address space of swap in. So this is basically what I have today. Any questions before we wrap this up? Yeah. Oh, you mean two address space of VA can map to the same swap slot? Yeah. For that, so the thing is that you don't want to allocate any extra memories. The fact that you have some swap out page is indication is that you are quite tight on the memories. And when you do AS copy, you don't want to allocate. Of course, you can allocate all the pages in memory and copy it to memory. So later on, you may end up swap that page again in disk. So it's up to you. You want to copy at this point or you want to later on do the right disk part. Either way. Yeah, you're right. You don't have to actually copy from disk to another swap slot. All right then. This shall be the last visitations. I already covered pretty much everything about the address spaces and all that. So next week, I think I will do more office hours. Well, keep, stay tuned. I mean, I'm not sure yet. I have to discuss with Jeff, but I think that will be the case.