没有合适的资源?快使用搜索试试~ 我知道了~
首页2016年USENIX OSDI会议论文集:操作系统设计与实现前沿
2016年USENIX OSDI会议论文集:操作系统设计与实现前沿
需积分: 33 43 下载量 128 浏览量
更新于2024-07-20
1
收藏 27.44MB PDF 举报
"USENIX OSDI 2016年论文集(Proceedings of USENIX OSDI 2016,OSDI '16)是一部汇集了操作系统领域顶尖研究的珍贵文献。作为由USENIX,一个成立于1975年的先进计算机系统协会主办的会议,OSDI(Operating Systems Design and Implementation)起源于1994年,每两年举办一次,旨在推动操作系统设计与实现技术的发展。OSDI会议通常为期三天,自2002年起,每届论文数量保持在27篇左右,体现出极高的学术质量和深度。
会议在2016年11月2日至4日于美国佐治亚州萨凡纳召开,吸引了来自全球的学者和业界专家共同探讨最前沿的操作系统设计理念和技术成果。论文集赞助商阵容强大,包括Facebook、Google、微软研究、NetApp和VMware等知名企业,以及FreeBSD基金会等产业合作伙伴和Platinum赞助商,展现了OSDI会议在业界的影响力。
该论文集不仅记录了会议上的精彩演讲和研究成果,而且对每篇论文的作者权益给予充分尊重,允许非商业性质的教育或研究目的下复制整部作品,但个人使用需限于单份打印副本。版权方面,所有权利归USENIX协会所有,强调了对知识产权的保护和尊重。
OSDI '16的论文涵盖了广泛的主题,如操作系统内核优化、虚拟化技术、分布式系统架构、安全机制、内存管理、并行计算、以及新兴技术的探索等。每一项研究都代表了当时操作系统领域的创新和挑战,对于理解操作系统的设计原则、实施策略以及未来发展趋势具有重要意义。通过阅读这些论文,研究人员、工程师和学生能够深入理解并应用最新的操作系统理论和实践,推动行业的进步和发展。"
that M maps each inode number in range (0, i) to a block
number in range (0, b). Finally, the root directory con-
straint requires D to map file names to inode numbers
in range (0, i). These three constraints are all Yggdrasil
needs to verify YminLFS (see §2.3).
2.3 Verification
To verify that the YminLFS implementation (§2.2) sat-
isfies the FSSpec specification (§2.1), Yggdrasil uses the
Z3 solver [15] to prove a two-part crash refinement theo-
rem (§3). The first part of the theorem deals with crash-
free executions. It requires the implementation and spec-
ification to behave alike in the absence of crashes: if both
YminLFS and FSSpec start in equivalent and consistent
states, they end up in equivalent and consistent states.
The verifier defines equivalence using the specification’s
equivalent predicate (§2.1), and consistency using the
implementation’s consistency invariants (§2.2).
The second part of the theorem deals with crashing
executions. It requires the implementation to exhibit no
more crash states (disk states after a crash) than the spec-
ification: each possible state of the YminLFS implemen-
tation (including states caused by crashes and reordered
writes) must be equivalent to some crash state of FSSpec.
Counterexamples. If there is any bug in the imple-
mentation or consistency invariants, the verifier will gen-
erate a counterexample to help programmers understand
the bug. A counterexample consists of a concrete trace
of the implementation that violates the crash refinement
theorem. As an example, consider the potential missing
flush bug described in §2.2. If we remove the flush
between the last two writes in the implementation of
mknod, Yggdrasil outputs the following counterexample:
# Pending writes
lfs.py:167 mknod write(new_imap_blkno, imap)
# Synchronized writes
lfs.py:148 mknod write(new_blkno, new_ino)
lfs.py:154 mknod write(new_parentdata, parentdata)
lfs.py:160 mknod write(new_parentblkno, parentinode)
lfs.py:170 mknod write(SUPERBLOCK, sb)
# Crash point
[..]
lfs.py:171 mknod flush()
The output describes the bug by showing the point at
which the system crashes and the list of writes pending
in the cache (along with their source code locations). In
this example, the write of the new inode mapping block
(step 4 above) is still pending, but the write to update the
superblock to point to that block (step 5) has reached the
disk, corrupting YminLFS’s state.
The visualization of “pending” and “synchronized”
writes in the counterexample is specific to the asyn-
chronous disk model; one can extend Yggdrasil with new
disk models and customized visualizations.
Our initial YminLFS implementation contained two
other bugs: one in the lookup logic and one in the data
layout. Neither of the bugs appeared during testing runs.
Both bugs were found by the verifier in a matter of sec-
onds, and we quickly localized and fixed them by exam-
ining the resulting counterexamples.
Proofs. If the Yggdrasil verifier finds no counterexam-
ples to the crash refinement theorem, then none exist, and
we have obtained a proof of correctness. In particular,
the crash refinement theorem holds for all disks with up
to 2
64
blocks, and for every trace of file system opera-
tions, regardless of its length. After we fixed the bugs in
our initial YminLFS implementation, the verifier proved
its correctness in under 30 seconds.
It is worth noting that the theorem holds if the file sys-
tem is the only user of the disk. For instance, it does not
hold if an adversary corrupted the file system image by
directly modifying the disk. To address this issue, one
can run fsck generated by Yggdrasil, which guarantees
to detect any such inconsistencies.
2.4 Optimizations and compilation
As described in §2.2, YminLFS’s mknod implementation
uses five disk flushes. Yggdrasil provides a greedy opti-
mizer that tries to remove every disk flush and re-verify
the code. Running the optimizer on the mknod code re-
moves three out of the five flushes within three minutes,
while still guaranteeing correctness.
The optimized and verified YminLFS implementation,
which is in Python, is executable but slow. Yggdrasil
invokes the Cython compiler [3] to generate C code from
Python for better performance. It also provides a small
bridge to connect the generated C code to FUSE [17].
The result is a single-threaded user-space file system.
2.5 Summary
We have demonstrated how to specify, implement, de-
bug, verify, optimize, and execute the YminLFS file sys-
tem using Yggdrasil. Compared to previous file sys-
tem verification work, push-button verification eases the
proof burden and enables automated features such as vi-
sualizing bugs and optimizing code.
Since there is no need to manually prove or annotate
implementation code when using Yggdrasil, the verifi-
cation effort is spent mainly on writing the specification
and coming up with consistency invariants about the on-
disk data format. We find the counterexample visualizer
useful for finding bugs in these two parts.
The trusted computing base (TCB) includes the file
system specification, Yggdrasil’s verifier, visualizer, and
compiler (but not the optimizer), their dependencies (i.e.,
the Z3 solver, Python, and gcc), as well as FUSE and the
Linux kernel. See §6 for discussion on limitations.
USENIX Association 12th USENIX Symposium on Operating Systems Design and Implementation 5
3 The Yggdrasil architecture
In Yggdrasil, the core notion of correctness is crash re-
finement. This section gives a formal definition of crash
refinement, and describes how Yggdrasil’s components
use this definition to support verification, counterexam-
ple visualization, and optimization.
3.1 Reasoning about systems with crashes
In Yggdrasil, programmers write both specifications and
implementations (referred to as “systems” in this section)
as state machines: each system comprises a state and a
set of operations that transition the state. A transition
can occur only if the system is in a consistent state, as
determined by its consistency invariant I. This invariant
is a predicate over the system’s state, indicating whether
it is consistent or corrupted; see §2.2 for an example.
Consider a specification F
0
and an implementation
F
1
. Our goal is to show that F
1
is correct with respect
to F
0
. Since both systems are state machines, a straw-
man definition of correctness is that they transition in
lock step (i.e., bisimulation): starting from equivalent
consistent states, if the same operation is invoked on
both systems, they will transition to equivalent consistent
states (where equivalence between states is defined by a
system-specific predicate). However, this bisimulation-
based definition is too strong for systems that interact
with external storage, as it does not account for non-
determinism from disk reorderings, crashes, or recovery.
To address this shortcoming, we introduce crash re-
finement as a new definition of correctness. At a high
level, crash refinement says that F
1
is correct with re-
spect to F
0
if, starting from equivalent consistent states
and invoking the same operation on both systems, any
state produced by F
1
is equivalent to some state produced
by F
0
. To formalize this intuition, we define the behav-
ior of a system in the presence of crashes, formalize crash
refinement for individual operations, and extend the re-
sulting definition to entire systems.
System operations. We model the behavior of a sys-
tem operation with a function f that takes three inputs:
• its current state s;
• an external input x, such as data to write; and
• a crash schedule b, which is a set of boolean values
denoting the occurrence of crash events.
Applying f to these inputs, written as f(s, x, b), pro-
duces the next state of the system.
As a concrete example, consider a single disk write
operation that writes value v to disk address a. The ex-
ternal input to the write operation’s function f
w
is the
pair (a, v). The state s is the disk content before the
write; s(a) gives the old value at the address a. The
asynchronous disk model in Yggdrasil generates a pair of
boolean values (on , sync ) as the crash schedule. The on
value indicates whether the write operation completed
successfully by storing its data into the volatile cache.
The sync value indicates whether the write’s effect has
been synchronized from the volatile cache to stable stor-
age. After executing the write operation, the disk is up-
dated to contain v at the address a only if both on and
sync are true, and left unchanged otherwise (e.g., the
system crashed before completing the write, or before
synchronizing it to stable storage):
f
w
(s, x, b) = s[a 7→ if on ∧ sync then v else s(a)],
where x = (a, v) and b = (on, sync).
Crash refinement. To define crash refinement for a
given schedule, we start from a special case where write
operations always complete and their effects are synchro-
nized to disk. That is, the crash schedule is the constant
vector true. Let s
0
∼ s
1
denote that s
0
and s
1
are equiv-
alent states according to a user-defined equivalence rela-
tion (as in §2.1). We write s
0
∼
I
0
,I
1
s
1
to say that s
0
and s
1
are equivalent and consistent according to their
respective system invariants I
0
and I
1
:
s
0
∼
I
0
,I
1
s
1
, I
0
(s
0
) ∧ I
1
(s
1
) ∧ s
0
∼ s
1
.
With a crash-free schedule true , two functions f
0
and f
1
are equivalent if they produce equivalent and consistent
output states when given the same external input x, as
well as equivalent and consistent starting states:
Definition 1 (Crash-free equivalence). Given two func-
tions f
0
and f
1
with their system consistency invariants
I
0
and I
1
, respectively, we say f
0
and f
1
are crash-free
equivalent if the following holds:
∀s
0
, s
1
, x. (s
0
∼
I
0
,I
1
s
1
) ⇒ (s
0
0
∼
I
0
,I
1
s
0
1
)
where s
0
0
= f
0
(s
0
, x, true ) and s
0
1
= f
1
(s
1
, x, true ).
Next, we allow for the possibility of crashes. We say
that f
1
is correct with respect to f
0
if, for any crash
schedule, the state produced by f
1
with that schedule is
equivalent to a state produced by f
0
with some schedule:
Definition 2 (Crash refinement without recovery). Func-
tion f
1
is a crash refinement (without recovery) of f
0
if
(1) f
0
and f
1
are crash-free equivalent and (2) the fol-
lowing holds:
∀s
0
, s
1
, x, b
1
. ∃b
0
. (s
0
∼
I
0
,I
1
s
1
) ⇒ (s
0
0
∼
I
0
,I
1
s
0
1
)
where s
0
0
= f
0
(s
0
, x, b
0
) and s
0
1
= f
1
(s
1
, x, b
1
).
Finally, we consider the possibility that the system
may run a recovery function upon reboot. A recovery
function r is a system operation (as defined above) that
takes no external input (as it is executed when the system
starts). It should also be idempotent: even if the system
crashes during recovery and re-runs the recovery func-
tion many times, the resulting state should be the same
once the recovery is complete.
6 12th USENIX Symposium on Operating Systems Design and Implementation USENIX Association
Definition 3 (Recovery idempotence). A recovery func-
tion r is idempotent if the following holds:
∀s, b. r(s, true ) = r(r(s, b), true).
Note that this definition accounts for multiple crash-
reboot cycles during recovery, by repeated application
of the idempotence definition on each intermediate crash
state r(s, b), r(r(s, b), b
0
), . . . , where b, b
0
, . . . are the
schedules for each crash during recovery.
Definition 4 (Crash refinement with recovery). Given
two functions f
0
and f
1
, their system consistency invari-
ants I
0
and I
1
, respectively, and a recovery function r,
f
1
with r is a crash refinement of f
0
if (1) f
0
and f
1
are crash-free equivalent; (2) r is idempotent; and (3) the
following holds:
∀s
0
, s
1
, x, b
1
. ∃b
0
. (s
0
∼
I
0
,I
1
s
1
) ⇒ (s
0
0
∼
I
0
,I
1
s
0
1
)
where s
0
0
= f
0
(s
0
, x, b
0
) and s
0
1
= r(f
1
(s
1
, x, b
1
), true ).
Furthermore, systems may run background operations
that do not change the externally visible state of a sys-
tem (i.e., no-ops), such as garbage collection.
Definition 5 (No-op). Function f with a recovery func-
tion r is a no-op if (1) r is idempotent, and (2) the fol-
lowing holds:
∀s
0
, s
1
, x, b
1
. (s
0
∼
I
0
,I
1
s
1
) ⇒ (s
0
∼
I
0
,I
1
s
0
1
)
where s
0
1
= r(f (s
1
, x, b
1
), true ).
With per-function crash refinement and no-ops, we can
now define crash refinement for entire systems.
Definition 6 (System crash refinement). Given two sys-
tems F
0
and F
1
, and a recovery function r , F
1
is a crash
refinement of F
0
if every function in F
1
with r is either a
crash refinement of the corresponding function in F
0
or
a no-op.
The rest of this section will describe Yggdrasil’s compo-
nents based on the definition of crash refinement.
3.2 The verifier
Given two file systems, F
0
and F
1
, Yggdrasil’s verifier
checks that F
1
is a crash refinement of F
0
according to
Definition 6. To do so, the verifier performs symbolic
execution [6, 24] for each operation f
i
∈ F
i
to obtain
an SMT encoding of the operation’s output, f
i
(s
i
, x, b
i
),
when applied to a symbolic input x (represented as a
bitvector), symbolic disk state s
i
(represented as an un-
interpreted function over bitvectors), and symbolic crash
schedule b
i
(represented as booleans). It then invokes
the Z3 solver to check the validity of either the no-op
identity (Definition 5) if f
1
is a no-op, or else the per-
function crash refinement formula (Definition 4) for the
corresponding functions f
0
∈ F
0
and f
1
∈ F
1
.
To capture all execution paths in the SMT encoding of
f
i
(s
i
, x, b
i
), the verifier adopts a “self-finitizing” sym-
bolic execution scheme [49], which simply unrolls loops
and recursion without bounding the depth. Since this
scheme will fail to terminate on non-finite code, the ver-
ifier requires file systems to be implemented in a finite
way: for instance, loops must be bounded [50]. In our
experience (further discussed in §4), the finiteness re-
quirement does not add much programming burden.
To prove the validity of the per-function crash refine-
ment formula, the verifier uses Z3 to check if the for-
mula’s negation is unsatisfiable. If so, the result is a
proof that f
1
is a crash refinement of f
0
. Otherwise, Z3
produces a model of the formula’s negation, which rep-
resents a concrete counterexample to crash refinement:
disk states s
0
and s
1
, an input x, and a crash schedule
b
1
, such that s
0
∼
I
0
,I
1
s
1
but there is no crash schedule
b
0
that satisfies f
0
(s
0
, x, b
0
) ∼
I
0
,I
1
f
1
(s
1
, x, b
1
).
Checking the satisfiability of the negated crash refine-
ment formula in Definition 4 requires reasoning about
quantifiers. In general, such queries are undecidable. In
our case, the problem is decidable because the quantifiers
range over finite domains, and the formula is expressed
in a decidable combination of decidable theories (i.e.,
equality with uninterpreted functions and fixed-width
bitvectors) [51]. Moreover, Z3 can solve this problem in
practice because the crash schedule b
0
, which is a set of
boolean variables, is the only universally quantified vari-
able in the negated formula. As many file system specifi-
cations have simple semantics, the crash schedule b
0
has
few boolean variables—often only one (e.g., the transac-
tion in §2.1)—which makes the reasoning efficient.
The verifier’s symbolic execution engine supports all
regular Python code with concrete (i.e., non-symbolic)
values. For symbolic values, it supports booleans, fixed-
width integers, maps, and lists of concrete length, as well
as regular control flow including conditionals and loops,
but no exceptions or coroutines. It does not support sym-
bolic execution into C library code.
3.3 The counterexample visualizer
To make counterexamples to validity easier to under-
stand, Yggdrasil provides a visualizer for the asyn-
chronous disk model. Given a counterexample model of
the formula in Definition 4, the visualizer produces con-
crete disk event traces (e.g., see §2.3) as follows. First,
it uses the crash schedule b
1
to identify the boolean vari-
able on that indicates where the system crashed, and
relates that location to the implementation source code
with a stack trace. Second, it evaluates the boolean sync
variables that indicate whether a write is synchronized
to disk, and prints out the pending writes with their cor-
responding source locations to help identify unintended
reorderings. Yggdrasil also allows programmers to sup-
USENIX Association 12th USENIX Symposium on Operating Systems Design and Implementation 7
ply their own plugin visualizer for data structures specific
to their file system images. We found this facility useful
when developing YminLFS and Yxv6.
3.4 The optimizer
The Yggdrasil optimizer improves the run-time perfor-
mance of implementation code. Yggdrasil treats the op-
timizer as untrusted and re-verifies the optimized code it
generates. This simple design, made possible by push-
button verification, allows programmers to plug in cus-
tom optimizations without the burden of supplying a cor-
rectness proof. We provide one built-in optimization that
greedily removes disk flush operations (see §2.4), imple-
mented by rewriting the Python abstract syntax tree.
4 The Yxv6 file system
The section describes the design, implementation, and
verification of the Yxv6 journaling file system. At a
high level, verifying the correctness of Yxv6 requires
Yggdrasil to obtain an SMT encoding of both the specifi-
cation and implementation through symbolic execution,
and to invoke an SMT solver to prove the crash refine-
ment theorem. A simple approach, used by YminLFS in
§2, is to directly prove crash refinement between the en-
tire file system specification and implementation. How-
ever, the complexity of Yxv6 makes such a proof in-
tractable for state-of-the-art SMT solvers. To address this
issue, Yxv6 employs a modular design enabled by crash
refinement to scale up SMT reasoning.
4.1 Design overview
Yxv6 uses crash refinement to achieve scalable SMT rea-
soning in three steps. First, to reduce the size of SMT
encodings, Yxv6 stacks five layers of abstraction, each
consisting of a specification and implementation, starting
with an asynchronous disk specification (§4.2). We use
Yggdrasil to prove crash refinement theorems for each
layer, showing that each correctly implements its specifi-
cation. Upper layers then use the specifications of lower
layers, rather than their implementations, in order to ac-
celerate verification. This layered approach effectively
bounds the reasoning to a single layer at a time.
Second, many file system operations touch only a
small part of the disk. To allow the SMT solver to ex-
ploit this locality, Yxv6 explicitly uses multiple separate
disks rather than one. For example, by storing the free
bitmap on a separate disk, the SMT solver can easily
infer that updating it does not affect the rest of the file
system. We then prove crash refinement from this multi-
disk system to a more space-efficient file system that uses
only a single disk (§4.3). The result of these first two
steps is Yxv6+sync, a synchronous file system that com-
mits a transaction for each system call (by forcing the log
to disk), similar to xv6 [14] and FSCQ [7].
re
gular files, symbolic
links, and directories
Yxv6
files
inodes
Yxv6
inodes
virtual
trans-
actional disk
block
pointer
transactional
disk
write-ahead
logging
asynchronous
disk
block
device
Axiom
1
Theorem
2
Theorem
3
Theorem
4
Theorem
5
Layer
1
Layer 2
Layer 3
Layer 4
Layer 5
Figure 3: The stack of layers of Yxv6. Within each layer, a
shaded box represents the specification; a (white) box repre-
sents the implementation; and the implementation is a crash
refinement of its specification, denoted using an arrow. Each
implementation (except for the lowest layer) builds on top of a
specification from the layer below, denoted using a circle.
Finally, for better run-time performance, we imple-
ment an optimized variant of Yxv6+sync that groups
multiple system calls into one transaction [19] and com-
mits only when the log is full or upon fsync. We prove
the resulting file system, called Yxv6+group_commit, is
a crash refinement of Yxv6+sync with a more relaxed
crash consistency model (§4.4).
4.2 Stacking layers of abstraction
Figure 3 shows the five abstraction layers of Yxv6. Each
layer consists of a specification and an implementation
that is written using a lower-level specification. We de-
scribe each of these layers in turn.
Layer 1: Asynchronous disk. The lowest layer of the
stack is a specification of an asynchronous disk. This
specification comprises the asynchronous disk model we
used in §2.2 to implement YminLFS. Since the imple-
mentation of a physical block device is opaque, we as-
sume the specification correctly models the block de-
vice (i.e., the specification is more conservative and al-
lows more behavior than real hardware), as follows:
Axiom 1. A block device is a crash refinement of the
asynchronous disk specification.
Layer 2: Transactional disk. The next layer intro-
duces the abstraction of a transactional disk, which man-
8 12th USENIX Symposium on Operating Systems Design and Implementation USENIX Association
ages multiple separate data disks, and offers the follow-
ing operations:
• d.begin_tx() starts a transaction;
• d.commit_tx() commits a transaction;
• d.write_tx(j, a, v) adds to the current transaction a
write of value v to address a on disk j; and
• d.read(j, a) returns the value at address a on disk j.
The specification says that operations executed within
the same transaction are atomic (i.e., all-or-nothing) and
sequential (i.e., transactions cannot be reordered).
The implementation uses the standard write-ahead
logging technique [19, 31]. It uses one asynchronous
disk (from layer 1) for the log, and a set of asynchronous
disks for data. Using a single transactional disk to man-
age multiple data disks allows higher layers to separate
writes within a transaction (e.g., updates to data and
inode blocks will not interfere), which helps scale SMT
reasoning; §4.3 refines the multiple disks to one.
The implementation is parameterized by the transac-
tion size limit k (i.e., the maximum number of writes in
one transaction). The log disk uses a fixed number of
blocks, determined by k, as a header to store log entry
addresses, and the remaining blocks to store log entry
data. The first entry in the first header block is a counter
of log entries; the consistency invariant for the transac-
tional disk layer says that this counter is always zero after
recovery. The Yxv6+sync file system sets k = 10, while
Yxv6+group_commit sets k = 511. For each of these
settings, we prove the following theorem:
Theorem 2. The write-ahead logging implementation is
a crash refinement of the transactional disk specification.
Layer 3: Virtual transactional disk. The specifica-
tion of the virtual transactional disk is similar to that
of the transactional disk, but instead uses 64-bit virtual
disk addresses [22]. Each virtual address can be mapped
to a physical disk address or unmapped later; reads and
writes are valid for mapped addresses only. We will use
this abstraction to implement inodes in the upper layer.
The virtual transactional disk implementation uses the
standard block pointers approach. It uses one transac-
tional disk managing at least three data disks: one to
store the free block bitmap, another to store direct block
pointers, and the third to store both data and singly in-
direct block pointers (higher layers will add additional
disks). The free block bitmap disk stores only one bit in
each of its blocks, which simplifies SMT reasoning but
wastes disk space; §4.3 will refine it to a more space-
efficient version.
The implementation relies on two consistency invari-
ants: (1) the mapping from virtual disk addresses to
physical disk addresses is injective (i.e., each physical
address is mapped at most once), and (2) if a virtual disk
address is mapped to physical address a, the a
th
bit in
the block bitmap must be marked as used. We use these
invariants to prove the following theorem:
Theorem 3. The block pointer implementation is a crash
refinement of the virtual transactional disk specification.
Layer 4: Inodes. The fourth layer introduces the ab-
straction of inodes. Each inode is uniquely identified us-
ing a 32-bit inode number. The specification maps an
inode number to 2
32
blocks, and to a set of metadata such
as size, mtime, and mode.
The implementation is straightforward thanks to the
virtual transactional disk specification. It simply splits
the 64-bit virtual disk address space into 2
32
ranges,
and each inode takes one range, which has 2
32
“virtual”
blocks, similar to NVMFS/DFS [22]. Inode metadata re-
sides on a separate disk managed by the virtual transac-
tional disk (which now has four data disks). There are no
consistency invariants in this layer. We prove the follow-
ing theorem:
Theorem 4. The Yxv6 inode implementation is a crash
refinement of the inode specification.
Layer 5: File system. The top layer of the file system
is an extended version of FSSpec given in §2, with regular
files, directories, and symbolic links.
The implementation builds on top of the inode speci-
fication, using a separate inode bitmap disk and another
for orphan inodes. Both are managed by the virtual trans-
actional disk (which now has six data disks plus the log
disk, giving a total of seven disks). There are two consis-
tency invariants: (1) if an inode is not marked as used in
the inode bitmap disk, its size must be zero in the meta-
data; and (2) if an inode has n blocks, no “virtual” block
larger than n is mapped. Using these invariants, we prove
the final crash refinement theorem:
Theorem 5. The Yxv6 implementation of files is a crash
refinement of the specification of regular files, symbolic
links, and directories.
Finitization. The Yggdrasil verifier requires Yxv6 op-
erations to be finite, as mentioned in §3.2. Most file sys-
tem operations satisfy this requirement, as they use only
a small number of disk reads and writes. For example,
moving a file involves updating only the source and des-
tination directories. However, there are two exceptions.
First, search-related procedures, such as finding a free
bit in a bitmap, may need to read many blocks. We
choose not to verify the bit-finding algorithm, but in-
stead adopt the idea of validation [38, 46, 48] to imple-
ment such search algorithms. The validator, which we
do verify, simply checks that an index returned by the
search is indeed marked free in the bitmap and if not,
fails the operation with an error code. We use similar
USENIX Association 12th USENIX Symposium on Operating Systems Design and Implementation 9
剩余796页未读,继续阅读
2019-04-05 上传
2023-05-14 上传
2023-04-03 上传
2023-05-14 上传
2024-08-08 上传
2024-09-03 上传
2024-09-02 上传
asdfdypro
- 粉丝: 0
- 资源: 3
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- 天池大数据比赛:伪造人脸图像检测技术
- ADS1118数据手册中英文版合集
- Laravel 4/5包增强Eloquent模型本地化功能
- UCOSII 2.91版成功移植至STM8L平台
- 蓝色细线风格的PPT鱼骨图设计
- 基于Python的抖音舆情数据可视化分析系统
- C语言双人版游戏设计:别踩白块儿
- 创新色彩搭配的PPT鱼骨图设计展示
- SPICE公共代码库:综合资源管理
- 大气蓝灰配色PPT鱼骨图设计技巧
- 绿色风格四原因分析PPT鱼骨图设计
- 恺撒密码:古老而经典的替换加密技术解析
- C语言超市管理系统课程设计详细解析
- 深入分析:黑色因素的PPT鱼骨图应用
- 创新彩色圆点PPT鱼骨图制作与分析
- C语言课程设计:吃逗游戏源码分享
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功