You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: 08_VirtualFileSystem/02_VirtualFileSystem.md
+30-26Lines changed: 30 additions & 26 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -61,7 +61,7 @@ As we anticipated earlier in this chapter we are going to use a linked list to k
61
61
So we assume that functions to handle list of mountpoints are present (their implementation is left as exercise), from now on we assume the following functions are present:
@@ -77,16 +77,15 @@ Let's call this new structure `mountpoint_t` and start to fill in some fields:
77
77
```c
78
78
#define VFS_TYPE_LENGTH 32
79
79
#define VFS_PATH_LENGTH 64
80
-
struct {
80
+
typedef struct {
81
81
82
82
char type[VFS_TYPE_LENGTH];
83
-
char mountpoint[VFS_TYPE_LENGTH];
83
+
char device[VFS_PATH_LENGTH];
84
+
char mountpoint[VFS_PATH_LENGTH];
84
85
85
86
fs_operations_t operations;
86
87
87
88
} mountpoint_t;
88
-
89
-
typedef struct mountpoint_t mountpoint_t;
90
89
```
91
90
92
91
The next thing is to have a variable to store those mountpoints, since we are using a linked list it is going to be just a pointer to its root, this will be the first place where we will look whenever we want to access a folder or a file:
@@ -114,7 +113,7 @@ There can be others of course configuration parameters like access permission, d
Once called it will simply create and add a new item to the mountpoints list, and will populate the data structure with the information provided, for example inside the function to create a mountpoint (in our example `create_mountpoint`) we are going to have something like the following code:
130
129
```c
131
130
mountpoint_t *new_mountpoint = malloc(sizeof(mountpoint_t)); // We assume a kind of malloc is present
132
-
new_mountpoint.device = device;
133
-
new_mountpoint.type = type;
134
-
new_mountpoint.mountpoint = target;
135
-
new_mountpoint.operations = NULL
131
+
if(new_mountpoint == NULL)
132
+
return -1;
133
+
strcpy(new_mountpoint->device, device);
134
+
strcpy(new_mountpoint->type, type);
135
+
strcpy(new_mountpoint->mountpoint, target);
136
+
new_mountpoint->operations = NULL;
136
137
```
137
138
138
139
the last line will be populated soon, for now let's leave it to `NULL`.
@@ -219,13 +220,16 @@ After having implemented all the functions to load file systems and identify giv
219
220
Let's quickly recap on how we usually read a file in C:
220
221
221
222
```C
222
-
int fd;
223
-
char *buffer = (char *) calloc(11, sizeof(char));
223
+
int file_descriptor;
224
+
char *buffer = calloc(11, sizeof(char));
225
+
if (buffer == NULL) {
226
+
return -1;
227
+
}
224
228
int file_descriptor = open("/path/to/file/to_open", O_RDONLY);
225
-
int sz = read(file_descriptor, buffer, 10)
229
+
int sz = read(file_descriptor, buffer, 10);
226
230
buffer[sz] = '\0';
227
231
printf("%s", buffer);
228
-
close(file_pointer);
232
+
close(file_descriptor);
229
233
```
230
234
231
235
The code snippet above is using the C stdlib file handling libraries, what the it does is:
@@ -234,7 +238,7 @@ The code snippet above is using the C stdlib file handling libraries, what the i
234
238
* If the file is found and the fd value is not -1, than we can read it
235
239
* It now reads 10 bytes from the opened file (the `read` function will access it via the fd field), and store the output in the buffer. The read function returns the number of bytes read.
236
240
* If we want to print the string read we need to append the EndOfLine symbol after the last byte read.
237
-
* Now we can close the file_pointer (destroying the file descriptor associated with the id if it is possible, otherwise -1 will be returned).
241
+
* Now we can close the file_descriptor (destroying the file descriptor associated with the id if it is possible, otherwise -1 will be returned).
238
242
239
243
As we can see there are no instructions where we specify the file system type, or the driver to use this is all managed by the vfs layer. The above functions will avail of kernel system calls open/read/close, they usually sits somewhere above the kernel VFS layer, in our _naive_ implementation they we are not going to create new system calls, and let them to be our VFS layer, and where needed make a simpler version of them.
240
244
@@ -265,21 +269,21 @@ The flags value is a bitwise operator, and there are other possible values to be
265
269
The return value of the function is the file descriptor id. We have already seen how to parse a path and get the mountpoint id if it is available. But what about the file descriptor and its id? What is it? File descriptors represents a file that has been opened by the VFS, and contain information on how to access it (i.e. mountpoint_id), the filename, the various pointers to keep track of current read/write positions, eventual locks, etc. So before proceed let's outline a very simple file descriptor struct:
266
270
267
271
```c
268
-
struct {
272
+
typedefstruct {
269
273
uint64_t fs_file_id;
270
274
int mountpoint_id;
271
275
char *filename;
272
276
int buf_read_pos;
273
277
int buf_write_pos;
274
278
int file_size;
275
279
char *file_buffer;
276
-
} file_descriptor_t
280
+
} file_descriptor_t;
277
281
```
278
282
279
283
We need to declare a variable that contains the opened file descriptors, as usual we are using a naive approach, and just use an array for simplicity, this means that we will have a limited number of files that can be opened:
Where the `mountpoint_id` fields is the id of the mounted file system that is containing the requested file. The `fs_file_id` is the fs specific id of the fs opened by the file descriptor, `buf_read_pos` and `buf_write_pos` are the current positions of the buffer pointer for the read and write operations and `file_size` is the size of the opened file.
@@ -308,16 +312,16 @@ The basic idea is that once mountpoint_id has been found, the vfs will use the m
The `buffer` content of the first read will be: `Text `, and the second one `examp`. This is the purpose `buf_read_pos` variable in the file descriptor, so it basically needs to be incremented of nbytes, of course only if `buf_read_pos + nbytes < file_size` .
@@ -393,7 +397,7 @@ The pseudocode for this function is going to be similar to the open/close:
0 commit comments