CS560 NOTES on File I/O
1. Kernel Data Structures
|<---------------- Kernel ------------------------> |
(1). PROC |
pid |
cwd |
... |
fd[fd] (2) |
.-------> openInstance |
mode = R|W|RW|APP |
refCount (3) |
minodePtr --------> minode[ ] | BlockDevice
offset ============== | ==============
| INODE | (4).INODE--> blocks
| ---------- |
| fileSize |
| i_blok[0-11] |
| i_block[12] |
| i_block[13] |
| i_block[14] |
| ------------ |
| (dev, ino) |
| modified |
| lock |
| refCount |
| ============== |
(5). |
----------------------------------------------
LBK:| 0 | 1 | ..| lbk| ...... ........|xxxxxxxxxx.
----------------------------------------------
byte:012... | |fileSize
|
startByte
in lbk
|<--- bytesInfile ---->|
(1). fd is an opened file descriptor. PROC.fd[fd] points to an openInstance (2)
(2). openInstance is a struct of the opened file:
ASSUME opened for READ ==> mode=READ
minodePtr points to in-memory inode struct (3).
refCount = number of procs sharing this openInsatnce (via fork())
offset = CURRENT byte pointer into the file
0 when opened for READ; increment after each read()
(3). minode[ ] contains the file's INODE from disk <====================== (4)
fileSize = size in bytes
i_block[ ] are the disk blocks
(dev,ino) for writing INODE back
modified != 0 if INODE modified
refCount=proc# accessing this minode
lock=flag OR semaphore for locking minode
(4). INODE and its data blocks on a dev (disk)
(5). LOGICAL view of file:
A file is a sequence of bytes, counting from 0 to size-1.
The bytes form LOGICAL BLOCKs (LBKs) of BLKSIZE.
LBKs are contigious as shown in the above figure.
---------------------- READ/WRITE syscalls -----------------------------
(6). Umode : int fd = open("filename", O_RDONLY); returns fd > 0.
int n = read(fd, ubuf[ ], nbytes);
|
syscall to Kernel's kread():
========================================================
(7). int kread(fd, ubuf, nbytes){
1. validate fd;
2. openInstance.mode==READ_PIPE ===> read_pipe(pipePtr,ubuf,nbytes);
3. minode.INODE.i_mode == SPECIAL ===> devcie driver() via devsw[ ];
4. REGULAR file: read regular file algorithm (8):
------------------------------------------------------
bytesRead = 0;
(8). 1. Compute logical block lbk & bytesInFile for READ:
lbk = offset / BLKSIZE;
startByte = offset % BLKSIZE;
bytesInfile = fileSize - offset
2. Map Logical block lbk to Physical block blk:
0 <= lbk <12 ==> blk = INODE.i_block[blk]; (DIRECT)
12 <= lbk <12+256 ==> blk = INDIRECT;
etc.
3. Read blk into kbuf[BLKSIZE];
|<-- | : bytesInBlock
startByte
| COPY bytes from kbuf[ ] to ubuf[ ]
UPDATE: bytesRead, bytesInBlock
offset, bytesInFile
4. DO (1)-(3) WHILE : bytesRead < nbytes &&
bytesInBlock > 0 &&
bytesInfile > 0
5 return n = bytesRead;
=================================================================
(9). BUFFER CACHE:
Consider n = read(fd, ubuf, 20); many times.
At (8)-3: On each syscall, Kernel has to read in the SAME block from
disk to kbuf[ ] and copy 20 bytes to ubuf[ ].
Other OS solutions:, e.g. IBM OS reads directly to ubuf[ ]==> then
during actual I/O the Umode image must be locked
in memory.
Unix solution: Use a set of kbuf[BLKSIZE] to act as a cache between
Kernel memory and blocks of disks. ==>
In addition to data, each kbuf[ ] has:
ID : (dev, blk#)
dataStatus: valid or invalid
useage : free or busy (or locked)
etc.
---------------------------------------------------------------------
(10). Buffer Management Algorithm: