-
-
Notifications
You must be signed in to change notification settings - Fork 66
Resource Magement #127
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Resource Magement #127
Conversation
|
|
||
| ## Resource Abstractation | ||
| When talking about _resources_, we need a way to distinguish between the different types that the kernel may expect to provide to userspace. Each resource behaves differently internally, but from the view of the userspace process everyting should be acessable from the same set of syscalls. In order to achive this, we define an enum of resource types to allow the kernel to tag each resource with it's category. This way when a system call is made, the kernel knows how to dispatch the request. | ||
| ``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pandoc (used for generating the pdf) doesnt like changing between text and code blocks within an empty line in between. Same goes for headings (# Per Process Resource Table and friends), can you update all of these?
|
|
||
| ## Resource Abstractation | ||
|
|
||
| When talking about _resources_, we need a way to distinguish between the different types that the kernel may expect to provide to userspace. Each resource behaves differently internally, but from the view of the userspace process, everything should be accessible from the same set of syscalls. In order to achieve this, we define an enum of resource types to allow the kernel to tag each resource with its category. This way, when a system call is made, the kernel knows how to dispatch the request. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even if in the example is an enum, I don't think that it has to be strictly it.
The sentence is kind of assuming and telling it, I think that it can be made more generic.
Something like: In order to achieve this we need to define a set of resource types to allow the kernel to tag each resources, for example we can use an enum... etc.
|
|
||
| When talking about _resources_, we need a way to distinguish between the different types that the kernel may expect to provide to userspace. Each resource behaves differently internally, but from the view of the userspace process, everything should be accessible from the same set of syscalls. In order to achieve this, we define an enum of resource types to allow the kernel to tag each resource with its category. This way, when a system call is made, the kernel knows how to dispatch the request. | ||
|
|
||
| ``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, please add the programming language, to have it rendered correctly by pandoc, and markdown.
So it will be something like:
```c
(do it everywhere in the code on your pr pls! :D)
| } process_t; | ||
| ``` | ||
|
|
||
| Now each process has a resource table that is a map of integers, called _handles_, to the kernel resource objects. A handle is simply an identifier returned by the kernel when opening a resource that is later used by the user to inform what resource the operation should be performed upon. This indirection is important because we do not want to expose any kernel pointers directly to a userspace process. Even if they cannot be used there, passing them could still create security or stability risks. This way, the resource structure is not exposed to userspace. Because of this, the same handle number in different processes can refer to different resources. For example, in Unix, handles `0`, `1`, and `2` refer to stdio for each process and are called "file descriptors". |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
stdio and stderr? :D
| 2. While the handle is valid, the process can perform operations such as `read_resource` or `write_resource`. | ||
| 3. Finally, when the process has finished using the resource, it calls `close_resource`, allowing the kernel to free any associated state. | ||
|
|
||
| Typically, a process should `close()` a resource once it is done using it. However, that is not always the case, as processes may exit without cleaning up properly, and thus it is up to the kernel to ensure resources aren't leaked. This could look like a loop through the process's resource table, calling `close_resource(process, handle);` for each open resource and letting the resource-specific `close()` function handle the work. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would say the first close() in this sentence, should be just italic, without parenthesis, since it refers to the one above that is close_resource, it could be confusing,.
|
|
||
| Here, `funcs` is the dispatch table that tells the kernel how to perform each operation for each resource. With this, each function pointer can be set differently depending on whether the resource is a file, IPC endpoint, or something else. Operations are defined to be blocking by default, meaning that if a resource is not ready (for example, no data to read), the process is suspended until the operation can complete. Each resource type can override these generic operations to provide behavior specific to that resource. | ||
|
|
||
| It has been left as an exercise to the reader to decide on how they want to handle extending this design for extra resource-specific functionality (ie, renaming a file). A simpler design may be to just add more syscalls to handle this; however, this means the ABI grows as your kernel manages more resources. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
functionality of functionalities?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
comma just after ie? Is that correct (I ask because I don´t know if in English is correct)
| Another thing left as an exercise to the user is to decide their method of copying data between userspace and the kernel. | ||
| One option is to use the userspace provided buffers, which is efficient due to a single copy but does require sanitization of pointers and lengths to ensure safety. Some things to consider are other threads in the same address space modifying memory at the same address. Another option is to copy into a kernel buffer first, which simplifies the sanitization but has the added overhead and loss of performance. | ||
|
|
||
| With using the user buffers, it's not necessarily a single copy, and you may be able to operate directly on the buffer (in which case it's zero-copy). Although, this can be dangerous as another user thread can write to, unmap, or remap the buffer while the kernel is operating on it. Holding a lock over the address space for that process throughout the entire duration of the resource operation is impractical, so the kernel must instead rely on fault handling. By faulting when the process tries to access the memory that the kernel is working with, it allows this behaviour to e caught and the kernel can try to abort or retry the operation safely. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At end of sentence: to e caught (missing b)
| * No extra features like permissions, uid and gid (although we are going to add those fields, they will not be used). | ||
| * The path length will be limited. | ||
|
|
||
| This VFS is built on top of the previously defined resource API (see Resource Management). The VFS creates a file-specific `resource_t` for each open file and returns a handle that is then used with the resource manager's generic `read`, `write`, and `close` functions that will perform the proper handle-to-resource lookup and call our VFS functions. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a Link to the resource management chapter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe handle-to-resource make it italic?
| ``` | ||
|
|
||
| The fildes argument is the VFS file descriptor id, it will be searched in the opened files list (using an array it will be found at `vfs_opened_files[fildes]`) and if found it should first call the fs driver function to close a file (if present), emptying all data structures associated to that file descriptor (i.e. if there are data on pipes or FIFO they should be discarded) and then doing the same with all the vfs resources, finally it will mark this position as available again. We have only one problem how to mark a file descriptor available using an array? One idea can be to use -1 as `fs_file_id` to identify a position that is marked as available (so we will need to set them to -1 when the vfs is initialized). | ||
| The `res` argument is the file resource to be closed, it will be called from the `close_resource(...)` of the kernel's resource manager. It should first call the fs driver function to close a file (if present), emptying all data structures associated to that file descriptor (i.e. if there are data on pipes or FIFO they should be discarded) and then doing the same with all the vfs resources, finally it will mark this handle as available again. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we specify somewhere that these are not the standard functions ? (since the parameters are different?)
| Where the parameters are the opened file resource (`res`) the buffer we want to read into (`buf`), and the number of bytes (`nbytes`) we want to read. | ||
| The read function will return the number of bytes read, and in case of failure -1. Like all other vfs functions, what the read will do is search for the file descriptor with id `fildes`, and if it exists call the fs driver function to read data from an opened file and fill the `buf` buffer. | ||
| The read function will return the number of bytes read, and in case of failure -1. Like all other vfs functions, what the read will acutally do is verify the resource and then call the fs driver function to read data from an opened file and fill the `buf` buffer. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
acutally?
| return bytes_read; | ||
| } | ||
| return -1; | ||
| ssize_t read(resource_t* res, void *buf, size_t nbytes) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok so this is read, and above we are using read_resource? And before we use again read. Let's decide on a name :D
dreamos82
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see previous comments
Here's the base write-up. Once settled on the design, I will go through and mix this in with the files and IPC.
closes #113