Assignment 7, Solutions

Part of the homework for 22C:112, Spring 2009
by Douglas W. Jones
THE UNIVERSITY OF IOWA Department of Computer Science

  1. Background: Consider a file system where an open file is made to appear, largely, as a virtual disk drive.

    a) There's one particular operation you want on an open file that is not possible on a disk drive. Identify it. (0.5 points)

    Append to the file, making it larger. Appending to a physical disk drive when it is full is not possible.

    b) Discuss the reasons you might want to open a raw disk as if it was an open file. (Note, in Unix, /dev/disk0/ is the raw boot disk and /dev/fd is the floppy disk, if you have just one.) (0.5 points)

    If the file system used on that disk is not the native file system of your machine, you might be able to get an application program that understands the file system. This is actually a common way to deal with non-native file systems.

    If you are dealing with very large files, it may be more efficient to store one file per disk drive, without a file system. Some database management systems operate this way.

  2. Background: Consider a disk scheduler running a naive implementation of the elevator algorithm, with one FIFO queue of disk I/O requests per cylinder of the disk. The interrupt handler operates as follows:
          if queue[current_cylinder].isempty() {
                current_cylinder = current_cylinder + 1 mod cylinders;
          } else {
                request = queue[current_cylinder].dequeue();
                start_IO_transfer( request );
                /* note:  disk ready bit is now zero until transfer done */
          }
          return_from_interrupt;
    

    a) There is a bug in this code. What happens if there are no disk I/O requests in any queues? (0.5 points)

    The interrupt request is never reset by starting an I/O transfer. As a result, each time the interrupt handler returns from interrupt, there is an immediate interrupt. Each interrupt increments current_cylinder which simply cycles over and over through the disk.

    b) Fix the above bug (or at least, discuss how it can be fixed). (0.5 points)

    Consider adding a count of the number of pending requests. This count is incremented whenever a request is enqueued in any queue. Also, after adding a request to any disk queue, the disk interrupt-enable bit is set. This works in conjunction with the following revised handler:

          if pending_requests == 0 {
                reset_disk_interrupt_enable();
          } else if queue[current_cylinder].isempty() {
                current_cylinder = current_cylinder + 1 mod cylinders;
          } else {
                pending_requests = pending_requests - 1;
                request = queue[current_cylinder].dequeue();
                start_IO_transfer( request );
                /* note:  disk ready bit is now zero until transfer done */
          }
          return_from_interrupt;
    

    c) There is a bug in the above code. What happens to I/O requests from other processes if one process is always scheduling I/O in cylinder X, so the queue for cylinder X is never empty. (0.5 points)

    The disk will be stuck on cylinder X and will never service requests for any other cylinder. This means that one user process can lock out all other processes indefinitely.

    d) Fix the above bug (or at least, discuss how it can be fixed). (0.5 points)

    Consider enforcing the rule that no new requests for queue X will be serviced once the disk begins servicing old requests for queue X until all other queues are serviced. This can be done by moving the entire queue to a current working queue, as the following handler does:

          if working_queue.isempty() {
                if pending_requests == 0 {
                      reset_disk_interrupt_enable();
                } else if queue[current_cylinder].isempty() {
                      current_cylinder = current_cylinder + 1 mod cylinders;
                      working_queue = queue[current_cylinder];
                      queue[current_cylinder] = new_empty_queue;
                }
          } else {
                pending_requests = pending_requests - 1;
                request = working_queue.dequeue();
                start_IO_transfer( request );
                /* note:  disk ready bit is now zero until transfer done */
          }
          return_from_interrupt;