Supporting user-defined transformations provides substantial flexibility. However, arbitrary user code cannot be used in kernel transformations for two reasons. First, the kernel operates in privileged mode. Second, a kernel thread is not preempted; therefore, a kernel transformation cannot execute for long periods of time. As a result, arbitrary user code cannot be downloaded into the kernel.
Therefore, Mona supports user-level transformations, which, although higher in overhead, have several advantages over kernel transformations. First, a user-level transformation does not execute in supervisor mode, which preserves the integrity of the system. Second, a user-level transformation has access to all the standard programming libraries. Lastly, a user-level transformation can use an arbitrarily large amount of resources, including CPU time and memory space. These advantages combine to make a user-level transformation much simpler and more powerful than a kernel transformations.
In addition, supporting both kernel and user-level transformations makes developing kernel transformations easier. Transformation code can be developed and debugged in user space first and then inserted into the kernel.1 This saves time because the compile/test/debug cycle is greatly reduced. First, there is no need to insert and remove a kernel module (and mount and unmount file systems) because a user transformation is an ordinary relocatable object file. Second, a symbolic debugger and print statements can be used to debug a user-level transformation. Third, a user-level bug causes a core dump, whereas a kernel bug causes a kernel panic. Developing in user space does not obviate the need for testing a transformation in the kernel, but it does reduce the time spent debugging.
The Mona file system provides the export transformation
to safely execute untrusted or computationally expensive transformations
outside of the kernel in user space. Figure 1
illustrates a transformation network generated by connecting a combination of kernel
and user-level transformations. A and B are kernel transformations, but
is a user-level transformation. Therefore, the
file system inserts the export transformation
between A and B. This transformation passes its input data across
the kernel-user boundary to a
user-level transformation network that runs in user space.
When transformation
completes, the output data returns to the
export transformation which then passes it on to transformation B.
Section 3.2 describes the mechanics of this process
in detail.