Homework 11 Solutions

22C:116, Spring 1999

Douglas W. Jones
  1. ssize_t thread_read( nt fildes, void *buf, size_t nbyte )
    {
        int ret_val;   /* the value to return */
        int nb_rem;    /* the number of bytes remaining to read */
        char* buf_rem; /* the remainder of the buffer */
        long int flags;/* saved flags */
    
        if (nbyte <= 0) return 0; /* special case */
    
        /* save flags */
        flags = fcntl( fildes, F_GETFL );
        fcntl( fildes, F_SETFL, flags | O_NONBLOCK );
    
        /* accumulate the buffer */
        ret_val = 0;
        nb_rem = nbyte;
        buf_rem = buf;
        do {
    	int ret = read( fildes, buf_rem, nb_rem );
            if (ret < 0) { /* error return from read */
    	    if (errno == EAGAIN) {
    		thread_relinquish();
    	    } else {
                    nb_rem = 0;
    	    }
            } else if (ret = 0) { /* eof return from read */
    	    nb_rem = 0;
    	} else { /* ret > 0  normal return from read */
    	    ret_val = ret_val + ret;
    	    nb_rem = nb_rem - ret;
    	    buf_rem = &buf_rem[ret];
    	}
        } while (nb_rem > 0);
    
        /* restore flags */
        fcntl( fildes, F_SETFL, flags );
    
        return ret_val;
    }
    
    The above code is probably not formally correct. The problem is that read() has very complex semantics, and the assignment demands that the normal semantics be modelled exactly except for the blocking behavior of the result.

  2. The University of Iowa Division of Mathematical Sciences maintain a network file system. The departmental server uses NFS protocols; this becomes obvious if you look at the file /etc/rc.config.d/nfsconf, the startup script controlling the NFS configuration of the system. This, in turn, refers to many local man pages. The textbook explicitly classifies NFS as a network system and not a distributed system.

  3. Background: Consider a distributed file system based on a 2-level structure -- low-level files are accessed by file-number, and a directory is merely a file used by a directory server to relate textual file names to low-level file numbers. When a user sends an open() message to the directory server, it replies by giving the user a file number. The read() and write() services, provided by low-level file servers, operate on files by their numbers and have no knowledge of file names.

    Part A: The responsibility for security in a 2-level file system, where users deal directly with the low level after opening a file, must lie with the low level file system! This is because the directory manager cannot enforce anything once it gives an open file description to the user; if a user synthesizes an open file description without using the directory manager, or a user saves an open file description for later use, the directory manager would be unable to enforce any access restrictions, so there must be an enforcement mechanism at the low level.

    Part B: If we demand that our system use garbage collection to reclaim disk space filled by files that are no-longer usable, the users, directory manager and low-level file manager must cooperate!

    Each open file description held by a user represents a root, from the point of view of the marking phase of a mark-sweep garbage collector. Therefore, it must be possible to ask users to mark each file they have open.

    This, in turn, requires that the file server offer, for each file, a mark operation, in addition to the usual read and write operations, although, perhaps, read and write operations could also be interpreted as mark operations, and a read of length zero could be interpreted as a simple mark.

    It must also be possible to ask each directory manager to traverse the directories it holds, marking each file contained in or used to contain directories. If all directories are in a single tree, this is simple. If users may hold capabilities for directories, or if directory managers allow inclusion of directory capabilities in directories, then the directory manager must offer users the ability to mark directories, and this operation must initiate a recursive traversal of the marked directory, marking everything it contains.

    Finally, after all marking operations have completed, the initiator of the garbage collection cycle must inform each file server that all of the reachable files have been marked, and therfore, that all unmarked files can be swept into the free list.