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: