Let's return to the code in our cp example. The open( ) system calls return two file descriptors, which are stored in the inf and outf variables. Then the program starts a loop: at each iteration, a portion of the /floppy/TEST file is copied into a local buffer (read( ) system call), and then the data in the local buffer is written into the /tmp/test file (write( ) system call).
The read( ) and write( ) system calls are quite similar. Both require three parameters: a file descriptor fd, the address buf of a memory area (the buffer containing the data to be transferred), and a number count that specifies how many bytes should be transferred. Of course, read( ) transfers the data from the file into the buffer, while write( ) does the opposite. Both system calls return either the number of bytes that were successfully transferred or -1 to signal an error condition.
A return value less than count does not mean that an error occurred. The kernel is always allowed to terminate the system call even if not all requested bytes were transferred, and the user application must accordingly check the return value and reissue, if necessary, the system call. Typically, a small value is returned when reading from a pipe or a terminal device, when reading past the end of the file, or when the system call is interrupted by a signal. The End-Of-File condition (EOF) can easily be recognized by a null return value from read( ). This condition will not be confused with an abnormal termination due to a signal, because if read( ) is interrupted by a signal before any data is read, an error occurs.
The read or write operation always takes place at the file offset specified by the current file pointer (field f_pos of the file object). Both system calls update the file pointer by adding the number of transferred bytes to it.
In short, both sys_read( ) (the read( )'s service routine) and sys_write( ) (the write( )'s service routine) perform almost the same steps:
1. Invoke fget( ) to derive from fd the address file of the corresponding file object and increment the usage counter file->f_count.
2. Check whether the flags in file->f_mode allow the requested access (read or write operation).
3. Invoke locks_verify_area( ) to check whether there are mandatory locks for
4. Invoke either file->f_op->read or file->f_op->write to transfer the data.
Both functions return the number of bytes that were actually transferred. As a side effect, the file pointer is properly updated.
5. Invoke fput( ) to decrement the usage counter file->f_count.
6. Return the number of bytes actually transferred. 12.6.3 The close( ) System Call
The loop in our example code terminates when the read( ) system call returns the value
0—that is, when all bytes of /floppy/TEST have been copied into /tmp/test. The program can then close the open files, since the copy operation has completed.
The close( ) system call receives as its parameter fd, which is the file descriptor of the file to be closed. The sys_close( ) service routine performs the following operations:
1. Gets the file object address stored in current->files->fd[fd]; if it is null, returns an error code.
2. Sets current->files->fd[fd] to null. Releases the file descriptor fd by clearing the corresponding bits in the open_fds and close_on_exec fields of current->files (see Chapter 20 for the Close on Execution flag).
3. Invokes filp_close( ), which performs the following operations:
a. Invokes the flush method of the file operations, if defined b. Releases any mandatory lock on the file c. Invokes fput( ) to release the file object
4. Returns the error code of the flush method (usually 0).
I [email protected] RuBoard
Was this article helpful?