-
Notifications
You must be signed in to change notification settings - Fork 3
/
listing4.html
executable file
·426 lines (346 loc) · 17.8 KB
/
listing4.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
<html>
<head>
<!-- BEGIN META TAG INFO -->
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<link rel="home" href="http://developer.apple.com/">
<link rel="find" href="http://developer.apple.com/search/">
<link rel="stylesheet" type="text/css" href="../../documentation/css/adcstyle.css" title="fonts">
<script language="JavaScript" src="../../documentation/js/adc.js" type="text/javascript"></script>
<!-- END META TAG INFO -->
<!-- BEGIN TITLE -->
<title>EmptyFS - /Read Me About EmptyFS.txt</title>
<!-- END TITLE -->
<script language="JavaScript">
function JumpToNewPage() {
window.location=document.scpopupmenu.gotop.value;
return true;
}
</script>
</head>
<!-- BEGIN BODY OPEN -->
<body>
<!--END BODY OPEN -->
<!-- START CENTER OPEN -->
<center>
<!-- END CENTER OPEN -->
<!-- BEGIN LOGO AND SEARCH -->
<!--#include virtual="/includes/adcnavbar"-->
<!-- END LOGO AND SEARCH -->
<!-- START BREADCRUMB -->
<div id="breadcrumb">
<table width="680" border="0" cellpadding="0" cellspacing="0">
<tr>
<td scope="row"><img width="340" height="10" src="images/1dot.gif" alt=""></td>
<td><img width="340" height="10" src="images/1dot.gif" alt=""></td>
</tr>
<tr valign="middle">
<td align="left" colspan="2">
<a href="http://developer.apple.com/">ADC Home</a> > <a href="../../referencelibrary/index.html">Reference Library</a> > <a href="../../samplecode/index.html">Sample Code</a> > <a href="../../samplecode/Darwin/index.html">Darwin</a> > <a href="../../samplecode/Darwin/idxFileManagement-date.html">File Management</a> > <A HREF="javascript:location.replace('index.html');">EmptyFS</A> >
</td>
</tr>
<tr>
<td colspan="2" scope="row"><img width="680" height="35" src="images/1dot.gif" alt=""></td>
</tr>
</table>
</div>
<!-- END BREADCRUMB -->
<!-- START MAIN CONTENT -->
<!-- START TITLE GRAPHIC AND INTRO-->
<table width="680" border="0" cellpadding="0" cellspacing="0">
<tr align="left" valign="top">
<td><h1><div id="pagehead">EmptyFS</div></h1></td>
</tr>
</table>
<!-- END TITLE GRAPHIC AND INTRO -->
<!-- START WIDE COLUMN -->
<table width="680" border="0" cellpadding="0" cellspacing="0">
<tr align="left" valign="top">
<td id="scdetails">
<h2>/Read Me About EmptyFS.txt</h2>
<form name="scpopupmenu" onSubmit="return false;" method=post>
<p><strong>View Source Code:</strong>
<select name="gotop" onChange="JumpToNewPage();" style="width:340px"><option selected value="ingnore">Select File</option>
<option value="listing1.html">/EmptyFS.c</option>
<option value="listing2.html">/EmptyFSMountArgs.h</option>
<option value="listing3.html">/MountEmptyFS.c</option>
<option value="listing4.html">/Read Me About EmptyFS.txt</option></select>
</p>
</form>
<p><strong><a href="EmptyFS.zip">Download Sample</a></strong> (“EmptyFS.zip”, 79.2K)<BR>
<strong><a href="EmptyFS.dmg">Download Sample</a></strong> (“EmptyFS.dmg”, 144.2K)</p>
<!--
<p><strong><a href="#">Download Sample</a></strong> (“filename.sit”, 500K)</p>
-->
</td>
</tr>
<tr>
<td scope="row"><img width="680" height="10" src="images/1dot.gif" alt=""><br>
<img height="1" width="680" src="images/1dot_919699.gif" alt=""><br>
<img width="680" height="20" src="images/1dot.gif" alt=""></td>
</tr>
<tr>
<td scope="row">
<!--googleon: index -->
<pre class="sourcecodebox">Read Me About EmptyFS
=====================
1.0
EmptyFS is a very simple VFS plug-in. EmptyFS volumes are completely empty
(except for the root directory). The purpose of this sample is to create the
minimal VFS plug-in that builds and runs. You can use EmptyFS to explore VFS
behaviour, or as a template for your own VFS plug-in.
EmptyFS requires Mac OS X 10.4 or later. Mac OS X 10.4 introduced a new
programming model for VFS plug-ins, and EmptyFS is tied to this model. It
would be tricky to port this code to earlier versions of Mac OS X.
Packing List
------------
The sample contains the following items:
o Read Me About EmptyFS.txt -- This file.
o EmptyFS.xcodeproj -- An Xcode 2.4 project for the sample.
o EmptyFS.c -- Source code for the kernel extension.
o Info.plist -- A property list file for the kernel extension.
o MountEmptyFS.c -- Source code for the mount tool.
o EmptyFSMountArgs.h -- Definitions shared between the kernel extension and the
mount tool.
o build -- A directory contain pre-built binaries.
Using the Sample
----------------
To use the sample, you must first decide what device node to mount on. The
simplest approach is to create a disk image.
$ hdiutil create -size 1MB -partitionType Apple_DTS_EmptyFS test
[...]
created: /Users/quinn/test.dmg
You then attach the disk image with the "-nomount" flag (so that the system
doesn't automatically mount the volumes on the image).
$ hdiutil attach -nomount test.dmg
/dev/disk1 Apple_partition_scheme
/dev/disk1s1 Apple_partition_map
/dev/disk1s2 Apple_DTS_EmptyFS
The last line that this prints (in this example it's "/dev/disk1s2", but it may
be different on your system) is a suitable device node for this test.
Now install the EmptyFS KEXT. The following assumes that you downloaded the
sample code archive to your desktop.
$ sudo cp -R ~/Desktop/EmptyFS/build/Debug/EmptyFS.kext /
$ sudo chown -R root:wheel /EmptyFS.kext
$ sudo kextload -t /EmptyFS.kext
kextload: extension /EmptyFS.kext appears to be valid
kextload: /EmptyFS.kext loaded successfully
At this point you can create a mount point and mount the file system.
$ mkdir MountPoint
$ ~/Desktop/EmptyFS/build/Debug/mount_EmptyFS /dev/disk1s2 MountPoint
You must change "/dev/disk1s2" to match the string printed by "hdiutil"
earlier.
The "mount" command will now show the file system as mounted.
$ mount | grep MountPoint
/dev/disk1s2 on /Users/quinn/MountPoint (local, nodev, noexec, nosuid,
read-only, mounted by quinn)
You can list its root directory.
$ ls -alh MountPoint
total 8
dr-xr-xr-x 2 quinn quinn 528B Jan 1 1970 .
drwxr-xr-x 30 quinn quinn 1020B Jul 4 14:13 ..
You can also use the "stat" command to get detailed information about the
EmptyFS root directory.
$ stat MountPoint
234881032 2 dr-xr-xr-x 2 quinn quinn 0 528 "Jan 1 01:00:00 1970" "Jan 1
01:00:00 1970" "Jan 1 01:00:00 1970" 4096 8 0 MountPoint
Finally, you can unmount the file system and then unload the KEXT.
$ umount MountPoint
$ sudo kextunload /EmptyFS.kext
kextunload: unload kext /EmptyFS.kext succeeded
Building the Sample
-------------------
The sample was built using Xcode 2.4 on Mac OS X 10.4.7. You should be able to
just open the project, select the "All" target, and choose Build from the Build
menu. This will build the "EmptyFS.kext" kernel extension and the
"mount_EmptyFS" command line tool, both in the "Build" directory.
Notes
-----
The source code has extensive comments that I won't repeat here. If you want
information about how the code works, you should start by reading those
comments.
To keep things as simple as possible, this file system has been designed and
tested at the BSD level only. This has a couple of consequences:
o I've made no attempt to support File Manager in this project.
o Similarly, I have not wrapped the KEXT in a bundle that's suitable for
installation in "/System/Library/Filesystems".
Thus, you should not expect EmptyFS volumes to automatically show up on the
desktop.
Build settings are tricky for any KEXT. I have used a number of interesting
tricks that you might find interesting.
o As with all my projects, I put the bulk of my build settings in the project
build settings panel, from where they are inherited by all targets.
o I preprocess the KEXT's "Info.plist" file by enabling the
INFOPLIST_PREPROCESS setting in the "KEXT" target. I do this for two reasons:
- It allows the Info.plist file to pick up compile-time variables
(KEXT_BUNDLE_ID and KEXT_VERSION) from the INFOPLIST_PREPROCESSOR_DEFINITIONS
build setting, which in turn picks them up from MODULE_NAME and MODULE_VERSION
build settings. Thus, you can change these settings in one place (the target
build settings panel) and they propagate to all of the relevant places.
- It allows me to conditionally express a dependency on the
"com.apple.kpi.unsupported" KPI. I need this KPI in my debug build (for
lck_mtx_assert), but I don't want my release build to depend on it.
o In the release build, I strip all non-exported symbols using the STRIP_STYLE
build setting. This is very important for KEXTs because the kernel is a single
flat namespace.
Vnode Locking and Reference Counts
----------------------------------
VFS handles the locking and reference counting needed for the structures it
manages (mount points, vnodes, and so on). Your VFS plug-in can decide how to
lock the structures it manages; VFS does not impose locking requirements on
your plug-in. You can use mutexes or read/write locks explicitly, so you can
get the maximum concurrency, or let VFS do most of your locking for you, which
makes your code easier.
If you let VFS do locking for you, VFS will acquire a "funnel" (a type of
mutex) before calling your VFS plug-in's entry points, and release it after
your code returns. The funnel is released and reacquired when your VFS plug-in
blocks, such as when allocating memory. The funnel is not released due to
preemption. The funnel is sufficient to protect your global variables as long
as your code does not block (for example, insertions and removals from linked
lists or hashes don't block, and are thus protected by the funnel).
Note
The funnel is the same mechanism that was used in older versions of
Mac OS X, but in Mac OS X 10.4 and later is used only for VFS plug-ins
that request it.
IMPORTANT
Use of the VFS funnel will be deprecated in the next major release of
Mac OS X. If you're creating a new VFS plug-in, we recommend that
you design your plug-in to not need funnel support.
If you let VFS do the locking for you, it will also acquire a per-vnode mutex
for every vnode passed in to your VFS plug-in, and release the mutex when your
code returns to VFS. You can use this to protect your per-vnode data
structures (what we call an FSNode).
Even if you use VFS's funnel and per-vnode locks, your VFS plug-in will still
need to provide explicit protection for shared structures that are accessed
across calls that may block. In some cases (such as your FSNode hash table),
you can rely on the funnel to set and clear flags, and use msleep and wakeup to
manage synchronization. In other cases, you may want to use your own mutex or
read/write lock. For example, if you maintain a per-volume data structure to
record which blocks are allocated on disk, you could protect that data
structure with a mutex. Alternatively, you could manipulate the data structure
within a buffer cache entry, and exploit the synchronization guarantees provided
by the buffer cache.
Whether or not you use VFS-provided locking, VFS makes some guarantees which
will simplify your VFS plug-in. For example, when a volume is being unmounted,
VFS waits for previous operations on the volume (and its vnodes) to complete
before starting the unmount, and will not let any other new operations on that
volume to begin until the unmount completes or returns an error. Also, vnodes
are not reused by other VFS plug-ins until all references to the vnode are
released.
VFS keeps track of three kinds of references to vnodes, each with different
meanings. VFS uses these references to determine whether a vnode is "busy" or
"in use".
The first type of reference is an "I/O reference", also known as an "io_count
reference". An I/O reference indicates that the vnode is actively involved in
handling some file system operation. You acquire an I/O reference by calling
vnode_get or vnode_getwithvid, and release the reference using vnode_put. The
vnode_create routine creates a vnode with a single I/O reference.
VFS uses I/O references to determine when a vnode is "busy". A volume cannot
be unmounted while any of its vnodes has an I/O reference. An I/O reference
should never be held beyond the duration of a single file system operation.
All the vnode ops already come from the VFS layer with an I/O reference. The
cache lookup routine returns the vnode with I/O reference. A vnode retrieved
from the file system hash needs to be returned with an I/O reference.
The second type of reference is a "use count reference". A use count reference
represents a long-term interest in a vnode. You acquire a use count reference
by calling vnode_ref, and release the reference using vnode_rele. You should
have an I/O reference on the vnode to acquire or release the use count
reference. VFS uses use count references to determine when a vnode is "in
use". A use count reference may (and often is) held beyond the duration of a
single file system operation. For example, if your private mount point
structure contains a pointer to a device vnode, you should acquire a use count
reference on that vnode when you store it in the mount point, and release the
reference when you change that mount point field or deallocate the mount point
structure.
Both I/O and use count references are counted. That is, the number of releases
must match the number of acquisitions. If the reference has been acquired more
times than it has been released, then the vnode is considered "busy" or "in
use". The counts are not allowed to be negative; that is you cannot release
first in order to balance a future acquisition.
Both I/O and use count references prevent a vnode from being reused by another
file or file system. That is, you will not receive a VNOPInactive or
VNOPReclaim call for a vnode until it has no I/O or use count references. A
volume cannot be unmounted if any of its vnodes have I/O or use count
references.
The third type of reference is an FS reference (not to be confused with File
Manager's FSRef). An FS reference is weak in that it does not prevent a vnode
from being reused. It indicates that the file system has stored a pointer to
the vnode, but can handle the vnode being reused. An FS reference is acquired
with vnode_addfsref, and released with vnode_removefsref. An FS reference is
typically acquired when a vnode (actually, its corresponding FSNode) is
inserted into a hash table, and released when the vnode removed from the table
(typically as the result of a VNOPReclaim operation). FS references are
Boolean, not counted, so a single release balances any number of acquisitions.
Important
Don't forget to call vnode_removefsref from your VNOPReclaim routine.
If you forget, the system will panic later, when that vnode is reused for
some other file. When testing, you can use "find -x / >& /dev/null" as a
handy way to cycle through lots of vnodes, forcing any inactive (not busy,
not used) vnode to be reused.
Credits and Version History
---------------------------
If you find any problems with this sample, mail <[email protected]> and I'll try to
fix them up.
1.0 (Oct 2006) was the first shipping version.
Share and Enjoy.
Apple Developer Technical Support
Core OS/Hardware
31 Oct 2006
$Log: Read\040Me\040About\040EmptyFS.txt,v $
Revision 1.9 2006/10/31 16:28:47
Updated the "Vnode Locking and Reference Counts" section based on review
feedback.
Revision 1.8 2006/10/20 23:08:08
Corrected partition type in hdiutil attach command results.
Revision 1.7 2006/10/17 13:57:08
Set the partition type when creating the disk image.
Revision 1.6 2006/10/10 21:13:51
Change group name.
Revision 1.5 2006/10/09 14:08:21
Noted the deprecation of VFS funnels, plus some copy edit changes.
Revision 1.4 2006/08/01 00:14:06
Corrected the disk device path in one of the example command lines.
Revision 1.3 2006/07/25 16:27:10
Rolled in changes based on experience from MFSLives. Almost all of these were
updated comments.
Revision 1.2 2006/07/04 14:10:54
Correct the paths in the example.
Revision 1.1 2006/07/04 14:04:06
First checked in.
</pre>
<!--googleoff: index -->
</td>
</tr>
</table>
<!-- END WIDE COLUMN -->
<!-- END MAIN CONTENT -->
<table width="680" border="0" cellpadding="0" cellspacing="0">
<tr>
<td><div style="width: 100%; height: 1px; background-color: #919699; margin-top: 5px; margin-bottom: 15px"></div></td>
</tr>
<tr>
<td align="center"><br/>
<table border="0" cellpadding="0" cellspacing="0" class="graybox">
<tr>
<th>Did this document help you?</th>
</tr>
<tr>
<td>
<div style="margin-bottom: 8px"><a href="http://developer.apple.com/feedback/?v=1&url=/samplecode/EmptyFS/listing4.html%3Fid%3DDTS10003966-1.0&media=dvd" target=_new>Yes</a>: Tell us what works for you.</div>
<div style="margin-bottom: 8px"><a href="http://developer.apple.com/feedback/?v=2&url=/samplecode/EmptyFS/listing4.html%3Fid%3DDTS10003966-1.0&media=dvd" target=_new>It’s good, but:</a> Report typos, inaccuracies, and so forth.</div>
<div><a href="http://developer.apple.com/feedback/?v=3&url=/samplecode/EmptyFS/listing4.html%3Fid%3DDTS10003966-1.0&media=dvd" target=_new>It wasn’t helpful</a>: Tell us what would have helped.</div>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!-- START BOTTOM APPLE NAVIGATION -->
<!--#include virtual="/includes/footer"-->
<!-- END BOTTOM APPLE NAVIGATION -->
<!-- START CENTER CLOSE -->
</center>
<!-- END CENTER CLOSE -->
</body>
</html>