Question 5 -- 23 points

Suppose you are on a system where multiple machines share disks. Moreover, suppose your disks export the following interfaces to the operating systems of the various machines: In order to perform any operation on a disk, the disk must be allocated to the calling machine. To call disk_to_disk_copy(), both disks must be allocated to the calling machine. Assume that sector numbers are ordered in a logical manner (i.e. contiguous sectors have adjacent sector numbers), as in JOS.

Assume your operating system is threaded (so that these blocking calls don't kill CPU utilization). Moreover, assume that a file is an ordered collection of sectors on one disk.

You have hired a summer student, whose first task is to write the procedure:

Dlist copy_file(int diskid1, Dlist sectors1, int diskid2)
This procedure copies a file from disk one to disk two. Sectors1 is a dlist of the sectors of file 1. Copy_file() returns a dlist of the copied file's sectors on disk 2. You may assume that diskid1 is not equal to diskid2. You want copy_file() to be correct and efficient as possible.

After two days of trying, here is what the student gives you.

Dlist copy_file(int diskid1, Dlist sectors1, int diskid2)
{
  Dlist d, tmp1, tmp2, sectors2;
  int sector1, sector2;

  d = make_dl();
  allocate_disk(diskid2);
  sectors2 = get_free_sectors(diskid2);
  tmp2 = sectors2->flink;

  allocate_disk(diskid1);
  dl_traverse(tmp1, sectors1) {
    sector1 = (int) tmp1->val;
    sector2 = (int) tmp2->val;
    disk_to_disk_copy(diskid1, sector1, diskid2, sector2);
    dl_insert_b(d, sector2);
  }
  deallocate_disk(diskid1);
  deallocate_disk(diskid2);
  return d;
}
There are a few things that are bad about this implementation, but they are not totally obvious, so you decide not to fire the student. However, you need to show him who's the boss. Do that in the following way:

Stuff from dlist.h

typedef struct dlist {
  struct dlist *flink;
  struct dlist *blink;
  void *val;
} *Dlist;

extern Dlist make_dl();
extern dl_insert_b(/* node, val */);
extern dl_delete_node(/* node */);    /* Deletes and frees a node */
extern dl_delete_list(/* head_node */);  /* Deletes the entire list */

#define dl_traverse(ptr, list) \
  for (ptr = first(list); ptr != nil(list); ptr = next(ptr))
#define dl_empty(list) (list->flink == list)


Stuff from rb.h

/* The relevant fields of an Rb_node are the k.ikey fields (for integer keys, the v.val field, and the c.list.flink and c.list.blink fields */ extern Rb_node make_rb(); extern Rb_node rb_find_ikey(/* tree, int ikey */); extern Rb_node rb_find_ikey_n(/* tree, int ikey, int *found */); extern rb_delete_node(/* node */); extern rb_free_tree(/* node */); /* Deletes and frees an entire tree */ #define rb_inserti(t, k, v) rb_insert_b(rb_find_ikey(t, k), (char *) k, v) #define rb_first(n) (n->c.list.flink) #define rb_last(n) (n->c.list.blink) #define rb_next(n) (n->c.list.flink) #define rb_prev(n) (n->c.list.blink) #define rb_empty(t) (t->c.list.flink == t) #define rb_traverse(ptr, lst) \ for(ptr = rb_first(lst); ptr != nil(lst); ptr = rb_next(ptr))