All quizzes (key)

All quizzes (key)

Quiz 01

Question 1: In xv6, which of the following information is part of the process control block, represented in xv6 as struct proc?
Select all that apply

  1. the value of the user registers, if the program is currently running in user mode on a processor

  2. (correct answer)

    the value of the user registers, if the program is currently not running in user mode on a processor

  3. the contents of the user stack

  4. (correct answer)

    the list of files the process has open

Question 2: On a typical implementation of POSIX, using read() to read one byte from a file descriptor with a call like:

    read(fd, buffer, 1);

where the file descriptor is opened to a file on a hard disk will:

  1. cause the OS to request exactly one byte from the disk, then store that byte in the application's buffer

  2. cause read to return an error because the hard disk can only read data in larger blocks

  3. (correct answer)

    cause the OS to request a block of data (larger than one byte) from disk and store it in the OS's memory, then copy one byte of that into the application's buffer

  4. cause the OS to request a block of data (larger than one byte) from disk, then copy the entire block into the application's buffer

Question 3: Consider the following POSIX C program:

#include <unistd.h>
int main(void) {
    int i = 0;
    for (i = 0; i < 2; ++i) {
        pid_t p = fork();
        printf("%d", i);
    }
    return 0; 
}

Which of the following is a possible output of this program?
Select all that apply

  1. (correct answer)

    001111

  2. 011101

  3. (correct answer)

    011011

  4. (correct answer)

    010111

Note: this was a poor question because realistic outputs are going to be more garbled from printf's buffers being copied on fork.

Question 4: After a successful call to execv
Select all that apply

  1. execv returns the new process ID

  2. file descriptors other than 0, 1, 2 (stdin, stdout, and stderr) are closed

  3. (correct answer)

    instructions are executed at the beginning of main()

  4. (correct answer)

    an executable specified as an argument to execv is loaded

Quiz 03

Question 1: Linux's Completely Fair Scheduler adjusts timeslices based on the number of processes that are running. When there are a large number of processes running, this adjustment is likely to improve
Select all that apply

  1. (correct answer)

    the mean wait time experienced by processes

  2. the compute throughput of the system

  3. the fairness of the amounts of processor time given to each process over a long period of time

  4. the amount of stack space required in the kernel

[note added 18 October] Re: "fairness over a long period time". The timeslice adjustment is not primarily how CFS does this. It is true that timeslice adjustment does help CFS ensure that processes wait for more similar amounts of time, but if one assumes a "long period of time" includes each thread getting to run for a bit many times, then the timeslice length won't matter much for this. (I could see that argument that "many processes" could have meant a sufficiently huge number of threads that it would take a "long period of time" to run all of them, but I don't think that's a likely interpretation of the scales of time and processes counts at play here. e.g. you need many tens of thousnads of processes for this effect to matter on the order of a minute of time.)

Question 2: On a system which implements threads in the kernel, creating a thread requires allocating
Select all that apply

  1. (correct answer)

    space for an additional user stack

  2. space for an additional heap

  3. (correct answer)

    more space to store user register values

  4. space for an additional array of open files

Question 3: Consider the following function:

node *head = NULL;
void prepend(int new_value) {
    node *new_head = new node;
    new_head->value = new_value;
    new_head->next = head;
    head = new_head;
}

When running prepend simulatenously from multiple threads we find that one of the prepended values is not on the linked list head. What most likely happened?

  1. each thread had its own version of the global variable head and so each created its own list

  2. (correct answer)

    two threads running prepend read the same value of head

  3. one thread running prepend overwrote the other thread's new_head->next value as it copied new_head over head

  4. one thread's call to prepend overwrote the other thread's copy of the variable new_value

Question 4: Consider the following pthreads code:

int global = 100;
void *print_id(void *argument) {
    int value = (int*) argument;
    printf("value=%d; global=%d\n", value, global);
    return NULL;
}

int main() {
    pthread_t threads[2];
    ++global;
    for (int i = 0; i < 2; ++i) {
        pthread_create(&threads[i], NULL, print_id, (void *) i);
    }
    for (int i = 0; i < 2; ++i) {
        pthread_join(threads[i], NULL);
    }
    return 0;
}

Assume that reading from and writing to an int or void * is atomic and that within each thread, operations (such as loads and stores) are executed in the order they are written in the C code (that is, not reordered by the processor or compiler). Which of the following would be possible outputs of this program?
Select all that apply

  1. (correct answer)
    value=0; global=101
    value=1; global=101
    
  2. (correct answer)
    value=1; global=101
    value=0; global=101
    
  3. value=0; global=100
    value=1; global=100
    
  4. value=2; global=101
    value=2; global=101
    

the cast for for assigning to value should have been to (int) not (int*)

Quiz 04

Question 1: In lecture we discussed a cache coherency mechanism where

  • each processor has its own cache
  • these caches and memory are all connected via a shared bus
  • each block in each cache is in either a Modified, Shared, or Invalid state.

Which of the following is true about such a system?
Select all that apply

  1. two processors can modify two memory locations that map to different parts of the same cache block at the same time (without waiting for each other)

  2. (correct answer)

    two processors can both hold the value of a single memory location in their caches at the same time

  3. (accepted any answer)

    after one processor finishes updating a value, another processor could still have an old version of the value cached

  4. when a value is written to the processors' caches, they must always write that value to memory immediately (by sending a message over the shared bus)

Since only one cache can have a cache block in the Modified state and they need to get the value in the Modified state to change it, they need to take turns when modifying a cache block, even if they are modifying different parts of it. To update a value, the processor needs to invalidate other cache's copy of the value, so this gaurentees that when the update is finished, no old versions of the value are still cached. An invalid value isn't still cached because one can never ever read out of the cache. When a processor has a cache block in the Modified state, it can modify it without sending it to memory immediately.
As long no processors are writing a value, two caches can have copies of the value from memory in the Shared state.

Question 2: We discussed a strategy to implement a "mutex" lock that puts waiting threads to sleep, allowing other threads to use the CPU, that internally used a spinlock (a lock that "spins" in an infinite loop checking the status of the lock). Which of the following was true about this spinlock?

  1. (correct answer)

    the spinlock is not locked the entire time the mutex lock is locked

  2. threads only acquire the spinlock after checking that acquiring the lock was likely to succeed without waiting

  3. the spinlock is released earlier than usual when another thread started waiting to lock the mutex lock

  4. this spinlock would be unlocked whenever the processor entered kernel mode

This question dropped due to ambiguity regarding "is not locked the entire time" meant "is unlocked whenever the mutex is locked" or "is unlocked at some point when the mutex is locked".

Suppose we are writing a multithreaded program which sometimes needs to retrieve data over the network from a single remote machine. To avoid overloading that machine, we want to make sure at most ten threads are retrieving data from the machine at a time.

Question 3: (see above) (see scenario above) To do this we can use a counting (that is, non-binary) semaphore, where we initialize the semaphore to _________, use the ____ operation before each thread starts retrieving data, and use the _____ operation after each thread finishes retrieving data.

  1. 10 / down / down

  2. 9 / down / down

  3. -10 / down / up

  4. (correct answer)

    10 / down / up

  5. 9 / down / up

  6. 0 / down / up

  7. -10 / up / down

  8. 10 / up / down

  9. 9 / up / down

  10. 0 / up / down

  11. 0 / up / up

  12. -10 / up / up

  13. none of the above

Question 4: (see above) (see scenario above) To do this we can use a mutex lock, condition variable, and a counter variable tracking the number of threads currently retreving data that is only accessed while holding the mutex. In this case, threads would call Wait on the condition variable ______.

  1. before retrieving data, as long as no other threads are retrieving data

  2. before retrieving data, as long as exactly 9 other threads are retrieving data

  3. (correct answer)

    before retrieving data, as long as exactly 10 other threads are retrieving data

  4. after retrieving data, as long as exactly 9 other threads are retrieving data

  5. after retrieving data, as long as no other threads are retrieving data

Quiz 05

Question 1: Suppose we have a system where one thread runs a function HandleChange(old_value, new_value) every time other threads use the SetValue function to change a shared value from old_value to new_value with the following code using a mutex and condition variable:

int value;
bool value_changed;
pthread_mutex_t lock;
pthread_cond_t change_happened;
void WaitForAndHandleChanges() {
    pthread_mutex_lock(&lock);
    while (true) {
        int old_value = value;
        while (!value_changed) {
            pthread_cond_wait(&change_happened, &lock);
        }
        HandleChange(old_value, value);
        value_changed = false;
    }
}
void SetValue(int new_value) {
    pthread_mutex_lock(&lock);
    value = new_value;
    value_changed = true;
    pthread_cond_signal(&change_happened);
    pthread_mutex_lock(&unlock);
}

After using this code, we find that sometimes HandleChange() is run too few times when SetValue() is called twice in a row from different threads.

How can we modify the above code to make sure HandleChange() is run once each time SetValue() is called?

  1. change SetValue to use pthread_cond_broadcast instead of pthread_cond_signal

  2. (correct answer)

    add an additional condition variable that SetValue waits for as long as value_changed is true and WaitForAndHandleChanges signals after setting value_changed to false

  3. change the while(!value_changed) loop in WaitForAndHandleChanges to checkvalue == old_valueinstead of!value_changed`

  4. use different mutexes for value_changed and for value

  5. have WaitForAndHandleChanges lock and unlock the mutex in the while(true) loop instead of locking it before the loop and never calling pthread_mutex_unlock

"SetValue" was meant to unlock the lock rather than locking a mysterious "unlock" mutex.

Question 2: In lecture, we discussed a version of reader/writer locks that favored readers. This had the disadvantage of starving writers. Suppose we wanted to implement a policy that favored readers until the waiting writers have been waiting for too much time. To implement this policy, what strategy could we use?

  1. (correct answer)

    track the amount of time writers have been waiting in shared variables, and use this information to decide whether to wait in the lock functions and to decide whether to signal/broadcast to readers to writers in the unlock functions.

  2. track the amount of time writers have been waiting in shared variables, and use this information to decide whether to signal/broadcast to readers to writers in the unlock functions

  3. track the amount of time writers have been waiting in shared variables, and use this information to decide whether to wait in the lock functions

  4. to replace the "write lock" cond_wait with a version of cond_wait that automatically wakes up after a certain amount of time (like POSIX's pthread_cond_timedwait)

  5. have each writer track the amount of time it's been waiting in a local variable in the "write lock" function, and if this time exceeds the maximum amount of time, to break out of the while loop that calls cond_wait

"to readers to writers" should have been "to readers or writers"

Suppose we have a multithreaded chat server which has a data structure to represent each user, which contains the list of messages they recently sent and the list of messages they recently received. Each user's data structure has its own lock. A naive attempt to implementing sending a message from one user to another first locks the sending user, then the receiving user, then updates the two message lists, then unlocks each of the locks. This naive strategy can cause deadlocks.

Question 3: (see above) When might a deadlock occur because of the locks described above?
Select all that apply

  1. when two threads at almost the same time try to send messages from a user A to a user B

  2. (correct answer)

    when one thread tries to send a message from user A to user B while another tries to send a message from user B to user A

  3. when one thread tries to send a message from user A to user B while another tries to send a message from user A to user C

  4. when too many threads all try to send messages to user A at the same time

Question 4: (see above) What alternatives would avoid these deadlocks?
Select all that apply

  1. add locks for the list of sent messages and the list of received messages in addition to the lock for each user. The send operation acquires the lock for the sending user, then for the list of sent messages, then for the receiving user, then the list of received messages, then adds the messages, then releases the locks

  2. (correct answer)

    replace the locks for the entire user data structure with seperate locks for the list of sent messages and the list of received messages. The send operation acquires the lock for the list of sent messages of the sending user and the list of received messages of the receiving user, then adds the messages, then releases the locks

  3. (correct answer)

    instead of acquiring the lock for the sending user first, acquire the lock for whichever of the sending and receiving users has the lowest address first

  4. instead of acquire the lock for the sending user, then the receiving user, acquire the locks in the other order: first acquire the lock for the receiving user, then the sending user.

Quiz 06

Question 1: Before it starts any programs, xv6 sets up its page table so that 224MB starting at virtual address 0x80000000 corresponds to physical byte addresses starting with 0. (MB = 1024 * 1024 bytes.) It does this using 4K pages. How much space is requires for page tables where only these pages are valid? (Assume it uses 4K pages and the page table format used by xv6.)

  1. 28 pages (112KB)

  2. 29 pages (116KB)

  3. 32 pages (128KB)

  4. 56 pages (224KB)

  5. (correct answer)

    57 pages (228KB)

  6. 224 pages (896KB)

  7. 225 pages (896KB)

  8. 256 pages (1024KB)

Question 2: The sbrk() system call has commonly been used to implement malloc(). On an OS like xv6 where this is true, for each program that is using malloc() the kernel must keep track of which of the following?
Select all that apply

  1. (correct answer)

    the address of the end of the heap

  2. the amount of space in the heap that is currently used

  3. (correct answer)

    the physical addresses that are assigned to each virtual page in the heap

  4. a linked list of free regions of the heap

Question 3: A page fault will occur when a process tries to access a virtual address whose page table entry is invalid (on x86, has the "present" flag set to 0). If the operating system determines that the memory access should be allowed to despite it not having a valid page table entry, it will most likely:

  1. perform a memory access to the same virtual address, but in kernel mode, then return from the page fault handler

  2. lookup the virtual address in the process's page table, convert it to a physical address, then use that physical addres to access the memory,t hen return from the page fault handler

  3. (correct answer)

    adjust the page table for the process so the memory access will work if attempted again, then return from the page fault handler

  4. reload the process from disk and restart it from the beginning of main()

Question 4: Suppose a Unix-like operating system uses 4K pages and the 32-bit x86 page table scheme we discussed in class. A process is running on this OS where in its page table: * virtual addresses 0x1000 through 0x9FFF (9 pages) are valid and writable and used to hold code and global variables * virtual addresses 0x10000 through 0x10FFF (1 page) are valid and writable and used for the heap, and * virtual addresses 0x7FFF0000 through 0x7FFFFFFF (16 pages) are valid and writable and used for the main thread's stack, and * every other virtual address is invalid (To simplify these questions, we will ignore any kernel-only page table entries.)

This process invokes the fork() system call, then the child process modifies addresses 0x7FFFEFF8 through 0x7FFFF016 on its stack.

If the system uses copy-on-write to implement fork(), excluding pages that hold page tables and kernel data structures, how many new physical pages will be allocated as a result of the call to fork() and subsequent modification of the child process's stack?

  1. 0 pages

  2. 1 page

  3. (correct answer)

    2 pages

  4. 3 pages

  5. 16 pages

  6. 17 pages

  7. 26 pages

  8. unknown; it depends on what instructions the child uses to modify the stack

  9. none of the above; the child process would crash (e.g. segfault)

Quiz 07

Question 1: Linux, and most operating systems which use memory to cache data on disk, maintains a mapping from physical pages to page table entries that reference this page. What is true about this mapping?
Select all that apply

  1. it is read by the processor when the program accesses a virtual address that corresponds to a valid page

  2. (correct answer)

    it is read by the operating system when it changes what file's data will be stored in that physical page

  3. each physical page has at most one corresponding page table entry, so the mapping is one to zero or one

Question 2: Suppose a process runs the following code on a Unix-like operating system:

    int fd = open("/tmp/file.dat", O_RDWR);
    char *data = mmap(NULL, 8 * 1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

The calls to open and mmap succeed and mmap returns 0x999000, which is the address of the first byte of virtual page 0x999. Pages on this system are 4096 bytes.

Which of the following is definitely true?
Select all that apply

  1. immediately after the mmap call, the page table entry for virtual page 0x999 is valid

  2. immediately after accessing address 0x99A000 after this mmap call, the page table entry for virtual page 0x999 would be valid

  3. (correct answer)

    after the mmap call, attempting to read from address 0x999000 will read the first byte of /tmp/file.dat

  4. (correct answer)

    after the mmap call, attempting to write to address 0x999000 will modify /tmp/file.dat

  5. (correct answer)

    after the mmap call, attempting to write to address 0x99A485 will modify /tmp/file.dat

Question 3: Suppose we are using a system which uses the "second chance" replacement policy which has the following list of physical pages with the following "referenced" (or "accessed") bit values, starting with the most recently added page:

  • physical page 4 (referenced)
  • physical page 3 (referenced)
  • physical page 1 (not referenced)
  • physical page 2 (referenced)

Suppose the program accesses an unloaded virtual page A. Immediately after this, it accesses another unloaded virtual page B. To load each of these virtual pages, the OS replaces the contents of one of the physical page on its list. Which pages will be chosen?

  1. 1 for A; 1 for B (overwriting A)

  2. (correct answer)

    1 for A; 2 for B

  3. 1 for A; 3 for B

  4. 1 for A; 4 for B

  5. 2 for A; 1 for B

  6. 2 for A; 2 for B (overwriting A)

  7. 2 for A; 3 for B

  8. 2 for A; 4 for B

  9. 4 for A; 3 for B

  10. 4 for A; 1 for B

  11. none of the above

Question 4: Suppose a program maps one page of a file from disk to its address space using mmap with MAP_SHARED and PROT_WRITE (so copy-on-write is not used and the mapping is writeable). The program first reads from the mapping, then writes to it repeatedly. What is true about writing to this mapping?
Select all that apply

  1. each write will trigger an exception or fault, so the OS can promptly handle the write

  2. (correct answer)

    the data written will be immediately available to another process that reads from the file

  3. the data written will be immediately written to the disk

Quiz 08

Question 1: When performing readahead, an operating system detects that a program accessed consecutive locations in a file. Based on this, it predicts that the program will read future locations in the file and reads this data into memory before the program is likely to access them.

Which of the following statements about readahead are true?
Select all that apply

  1. readahead is likely to be slower when the program only accesses the file data once

  2. (correct answer)

    if the operating predicts future accesses incorrectly, then it may evict more cached data that will be accessed than if it did not implement readahead

  3. to maximize performance, the OS should start reading more from the file only after the program has accessed all the pages of the file that were already read into memory

Suppose a very simple hard disk controller exposes a buffer and several control registers via fixed (physical) memory addresses:

The disk will trigger an interrupt whenever the value of the status register changes from "reading" or "writing" to "idle".

Question 2: (see above) A process running on a POSIX-like system makes read call on the device file for the hard disk controller. The hard disk's device driver's implementation of the read operation will, assuming the disk is currently idle, update the register indicating the sector number to read to, then write 1 to the control register to start a read. After this, what would make the most sense for the device driver's read implementation do next?

  1. (correct answer)

    put the current thread to sleep until it's woken up by the device driver's interrupt handler implementation

  2. update the process's page table entry for the virtual address of the user's buffer passed to the read system call to point at the device's buffer

  3. write the virtual address passed of the user's buffer passed to the read system call to the disk controller's buffer

  4. read the status register, and if it indicates the device is currently "reading", return successfully from the read system call

Question 3: (see above) If we modified this disk controller's interface to support direct memory access, the most likely change would be

  1. (correct answer)

    replacing the buffer with a register in which a device driver would place a physical memory address before doing a read or write

  2. modifying the status register's value to include the fixed memory address assigned to the buffer in addition to indicating whether the disk is reading, writing, or idle

  3. the operating system would make the processor access values in the controller's buffer with the processor cache enabled instead of disabled

Question 4: In the FAT filesystem, creating a new file A in a directory D potentially involves updating which the following?
Select all that apply

  1. the BIOS parameter block, also known as the filesystem header

  2. (correct answer)

    file allocation table entries corresponding to clusters for the file A's data

  3. (correct answer)

    file allocation table entries corresponding to clusters for the directory D's data

  4. (correct answer)

    the clusters for the file A's data

  5. (correct answer)

    the clusters for the directory D's data

Quiz 09

Question 1: Suppose a inode-based filesystem running requires 8B for each block number, uses 2048B blocks and stores 10 direct pointers in its inode, one indirect pointer, and one double-indirect pointer. How large a file can this filesystem support? (MB = 2 to the 20 bytes below)

  1. more than 4096MB

  2. between 1024MB and 4096MB

  3. between 256MB and 1024MB

  4. (correct answer)

    between 128MB and 256MB

  5. between 32MB and 128MB

  6. between 8MB and 32MB

  7. between 1MB and 8MB

  8. between 256KB and 1MB

  9. less than 256KB

Question 2: An inode-based filesystem with block groups (also known as cylinder groups) improves performance by
Select all that apply

  1. making it likely that all the inodes are stored together on disk

  2. making it likely that all the directories are stored together on disk, seperate from the regular files

  3. (correct answer)

    making it likely that an inode is stored near its directory entry on disk

  4. (correct answer)

    making it likely that the data for a file is allocated in only one region of disk

  5. allowing the number of inodes the filesystem supports to be dynamically changed

Question 3: In lecture, we discussed RAID 5, which divides data up among multiple disks, but allows failures to be tolerated by also storing "parity" information --- the result for XORing data from other disks together. Suppose we have a RAID 5 system which stores 8 sectors (A1, A2, B1, B2, C1, C2, D1, D2) where the parity information is scattered among multiple disks like as follows:

Disk 1A1B1Cp = C1 XOR C2D1
Disk 2A2Bp = B1 XOR B2C1D2
Disk 3Ap = A1 XOR A2B2C2Dp = D1 XOR D2

In this scheme with three disks as pictured, above, if all data from disk 3 is lost, recovering the value of the lost sectors B2 and C2 will reading how many sectors?

  1. 1

  2. 2

  3. 3

  4. (correct answer)

    4

  5. 5

  6. 6

  7. 7

Question 4: Suppose an inode-based filesystem moves a file from an old to a new directory by taking the following steps in the following order:

  • overwrite the old directory's entry for the file with an "unused" entry
  • if the new directory requires more space to store the directory entry, update its inode to point to an extra data block
  • write the new directory's entry for the file
  • write to the free block map for the extra directory data block, if any
  • update the new and old directory's inode to change modification times

What are possible outcomes if the system is interrupted and unexpectedly shuts down in the middle of this process? (You may assume that each step listed above completes entirely or not at all.)
Select all that apply

  1. (correct answer)

    the file being moved is not present in either directory

  2. (correct answer)

    a directory has a block pointer that points to disk space that is marked as free

  3. (correct answer)

    a directory has a block pointer that points to disk space whose value does not contain valid directory entries

  4. the file being moved is present in both directories

  5. the file being moved has its block pointer pointing to disk space that is marked as free

Quiz 10

Question 1: Consider an xv6-like inode-based filesystem that uses redo-logging. Suppose this filesystem does not want to report a file deletion operation as complete until the deletion will persist even if the machine loses power. To delete a file, the filesystem will overwrite the directory entry for the file with one labelled as "unused", update the free block list, and update the file inode (to mark it as free) and directory inode (to change its modification time). It should return from the file deletion system call after

  1. the value in directory entry is updated

  2. the log message containing the updated directory entry is written

  3. the log message containing the file's inode is written

  4. the log message containing the directory's inode is written

  5. the log message containing the update free block map is written

  6. (correct answer)

    the log message indicating that a transaction is committed is written

  7. the log message indicating that a transaction has been started is written

  8. the log is updated to remove the transaction that deletes the file and replace it with new transactions

In retrospect, the answers should have specified that 'a transaction' meant the transaction containing the deletion rather than unclearly not specifying what transaction was at issue.

Question 2: When overwriting 3 blocks of data in a 10 block file on a filesystem that does copy-on-write snapshots, the filesystem will
Select all that apply

  1. allocate 10 blocks of space for a new copy of the file's data

  2. (correct answer)

    allocate a new copy of the file's inode

  3. allocate a new copy of the entire inode array

  4. (correct answer)

    allocate space for pointers to inodes

Question 3: Port numbers
Select all that apply

  1. (correct answer)

    can be set by bind() in the POSIX socket APIs

  2. are assigned only to the end of a connection which calls accept()

  3. are typically used by routers to decide where to send messages

Question 4: In POSIX sockets, a server socket
Select all that apply

  1. is created whenever a successful call to bind() is made

  2. is used for read() calls, to receive the initial requests from clients

  3. (correct answer)

    is used to create other sockets

  4. (correct answer)

    can be assigned a file descriptor

Quiz 11

Question 1: Consider two phase commit with a coordinate machine C and two worker machines A and B. Suppose after both A and B send their 'agree-to-commit' messages to C, then after C tries to send its 'global-commit' message to A and B, it discovers that B has lost power and cannot receive the 'global-commit' message. What should C do while machine B remains down?

  1. Sending a 'global-abort' message to A.

  2. Restart the transaction from the beginning by sending a new 'prepare' message to A.

  3. (correct answer)

    Allow A to commit the transaction.

  4. Forwarding B's 'agree-to-commit' message to A since B won't be able to send it.

Question 2: We described two-phase commit in terms of the worker and coordinator nodes operating according to a state machine. In order to recover properly from failures, as it transitions from one state to another, each worker machine writes ___________ to its log __________ it sends the messages (such as votes on transactions) triggered by that transition.

  1. its new state / after

  2. (correct answer)

    its new state / before

  3. its prior state / after

  4. its prior state / before

  5. the coordinator's last known state / before

  6. the coordinator's last known state / after

Question 3: Suppose one wanted to:

  • allow processes running for a list of users to write data to a file, but only if they are writing ASCII data to the file, and
  • disallow any other users (except maybe the system administrator) from modifying the file

Which of the following access control mechanisms could enforce these restrictions?
Select all that apply

  1. POSIX's file permissions (without full access control lists)

  2. POSIX access control lists

  3. (correct answer)

    a setuid program that those processes would run, which would perform the write on their behalf

  4. providing those processes with a file descriptor for the file over a local socket

Question 4: In a capability-based system, to give a process access to files in a directory, but only to read it, one would most likely

  1. start the process with the appropriate user ID and changes the metadata on the directory and the files it contains

  2. start the process with the appropriate user ID and add the user ID and the directory name to an appropriate configuration file

  3. (correct answer)

    start the process with an appropriate file descriptor open to the directory in question

  4. change the set-group-ID bit on the executlabe the process runs