Assume you've read my previous post on file operations in OS161, then everything is quite straightforward. One more thing, remember to protect every access to the file descriptor data structure using lock!
Let's get started.
sys_open and sys_close
We'll rely on vfs_open to do most of the work. But before that, we need to
check:
-
Is
filenamea valid pointer? (alignment, NULL, kernel pointer, etc.) -
Is flags valid? flags can only contain exactly one of
O_RDONLY,O_WRONLYandO_RDWR
After these, we need to allocate a fd to the opened file: just scan the
curthread->t_fdtable and find a available slot (NULL). Then we need to
actually open the file using vfs_open. Note that we need to copy filename
into kernel buffer using copyinstr, for both security reasons, and that
vfs_open may destroy the pathname passed in.
Once vfs_open successfully returns, we can initialize a struct fdesc. Pay
special attention to fdesc->offset. Without O_APPEND, it should be zero.
But with O_APPEND, it should be file size. So we need to check it and use
VOP_STAT to get file size if necessary.
sys_close is quite easy. We first decrease the file reference counter. And
close the file using vfs_close and free the struct fdesc if the counter
reaches 0.
sys_read and sys_write
As usual, before do anything, first check the parameters.
The main work here is using VOP_READ or VOP_WRITE together with struct
iovec and struct uio. kern/syscall/loadelf.c is a good start point.
However, we need to initialize the uio for read/write for user space
buffers. That means the uio->uio_segflg should be UIO_USERSPACE.
Note that uio->uio_resid is how many bytes left after the IO operation. So you
can calculate how many bytes are actually read/written by len - uio->uio_resid.
Since we've carefully handled std files when initialization. Here we just treat them as normal files and pay no special attention to them.
sys_dup2
The hardest thing here is not how to write sys_dup2, but instead how dup2
is supposed to be used. Here is a typical code snippet of how to use dup2
int logfd = open("logfile", O_WRONLY);
/* note the sequence of parameter */
dup2(logfd, STDOUT_FILENO);
close(logfd);
/* now all print content will go to log file */
printf("Hello, OS161.\n");
We can see that in dup2(oldfd, newfd):
-
After
dup2,oldfdandnewfdpoints to the same file. But we can callcloseon any of them and do not influence the other. -
After
dup2, all read/write tonewfdwill be actually performed onoldfd. (Of course, they points to the same file!!) -
If
newfdis previous opened, it should be closed indup2( according todup2man page).
Once we're clear about these. Coding sys_dup2 is a piece of cake. Just don't
forget to maintain the fdesc->ref_count accordingly.
sys_lseek, sys_chdir and sys__getcwd
Nothing to say. Use VOP_TRYSEEK, vfs_chidr and vfs_getcwd respectively.
Only one thing, if SEEK_END is used. use VOP_STAT to get the file size, as
we did in sys_open
64-bit parameter and return value in lseek
This is just a minor trick. Let's first see the definition of lseek
off_t lseek (int fd, off_t pos, int whence)
And from $OS161_SRC/kern/include/types.h, we can see that off_t is type-defined as
64-bit integer (i64). So the question here is: how to pass 64-bit parameter
to sys_lseek and how get the 64-bit return value of it.
Pass 64-bit argument to sys_lseek
From the comment in $OS161_SRC/kern/arch/mips/syscall/syscall.c, we can see that, fd
should be in $a0, pos should be in ($a2:$a3) ($a2 stores high 32-bit and
$a3 stores low 32-bit), and whence should be in sp+16. Here, $a1 is not
used due to alignment.
So in the switch branch of sys_lseek, we should first pack ($a2:$a3) into a 64-bit
variable, say sys_pos. Then we use copyin to copy whence from user stack (tf->tf_sp+16).
Get 64-bit return value of sys_lseek
Also from the comment, we know that a 64-bit return value is stored in
($v0:$v1) ($v0 stores high 32-bit and $v1 stores low 32-bit). And note that
after the switch statement, retval will be assigned to $v0, so here we just
need to copy the low 32-bit of sys_lseek's return value to $v1, and high
32-bit to retval.