-
Notifications
You must be signed in to change notification settings - Fork 3
/
listing2.html
executable file
·750 lines (628 loc) · 36.7 KB
/
listing2.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
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
<!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>MFSLives - /HashNode.h</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');">MFSLives</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">MFSLives</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>/HashNode.h</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">/HashNode.c</option>
<option value="listing2.html">/HashNode.h</option>
<option value="listing3.html">/MFSCore.c</option>
<option value="listing4.html">/MFSCore.h</option>
<option value="listing5.html">/MFSLives.c</option>
<option value="listing6.html">/MFSLivesMountArgs.h</option>
<option value="listing7.html">/MFSLivesPseudoMount.c</option>
<option value="listing8.html">/MFSLivesPseudoMount.h</option>
<option value="listing9.html">/MFSLivesUtil.c</option>
<option value="listing10.html">/MountMFSLives.c</option>
<option value="listing11.html">/Read Me About MFSLives.txt</option>
<option value="listing12.html">/TableGenerator.c</option>
<option value="listing13.html">/TestMFSLives.c</option>
<option value="listing14.html">/UserSpaceKernel.c</option>
<option value="listing15.html">/UserSpaceKernel.h</option>
<option value="listing16.html">/utf8_decodestr.c</option>
<option value="listing17.html">/utf8_decodestr.h</option>
<option value="listing18.html">/VNodeAttr.h</option></select>
</p>
</form>
<p><strong><a href="MFSLives.zip">Download Sample</a></strong> (“MFSLives.zip”, 2.12M)<BR>
<strong><a href="MFSLives.dmg">Download Sample</a></strong> (“MFSLives.dmg”, 2.52M)</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">/*
File: HashNode.h
Contains: Generic hash table module for VFS plug-in.
Written by: DTS
Copyright: Copyright (c) 2006 by Apple Computer, Inc., All Rights Reserved.
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
("Apple") in consideration of your agreement to the following terms, and your
use, installation, modification or redistribution of this Apple software
constitutes acceptance of these terms. If you do not agree with these terms,
please do not use, install, modify or redistribute this Apple software.
In consideration of your agreement to abide by the following terms, and subject
to these terms, Apple grants you a personal, non-exclusive license, under Apple's
copyrights in this original Apple software (the "Apple Software"), to use,
reproduce, modify and redistribute the Apple Software, with or without
modifications, in source and/or binary forms; provided that if you redistribute
the Apple Software in its entirety and without modifications, you must retain
this notice and the following text and disclaimers in all such redistributions of
the Apple Software. Neither the name, trademarks, service marks or logos of
Apple Computer, Inc. may be used to endorse or promote products derived from the
Apple Software without specific prior written permission from Apple. Except as
expressly stated in this notice, no other rights or licenses, express or implied,
are granted by Apple herein, including but not limited to any patent rights that
may be infringed by your derivative works or by other works in which the Apple
Software may be incorporated.
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
COMBINATION WITH YOUR PRODUCTS.
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Change History (most recent first):
$Log: HashNode.h,v $
Revision 1.1 2006/07/27 15:47:35
First checked in.
*/
#ifndef _HASHNODE_H
#define _HASHNODE_H
/////////////////////////////////////////////////////////////////////
#include <stdint.h>
// The following headers are only available to kernel code, which is the default
// disposition. To simplify testing, however, we compile this module for user
// space. In that case, we can't include these headers. Rather, the relevant
// declarations come from "UserSpaceKernel.h".
#if KERNEL
#include <sys/systm.h>
#include <libkern/OSMalloc.h>
#else
#include "UserSpaceKernel.h"
#endif
/////////////////////////////////////////////////////////////////////
/*
Theory of Operation
===================
VNodes and FSNodes
------------------
One of the hardest parts about writing a VFS plug-in is implementing the hash
layer. Both VFS and your plug-in have an idea of what file system objects (fsobjs)
are currently cached in memory. For VFS, fsobjs are cached as "vnodes".
A VFS plug-in is free to represent the cached fsobjs however it sees
fit. For the sake of this discussion, the file system-specific fsobj
cache items are called "FSNodes". To make it easier to map from a vnode
to an FSNode, VFS provides a per-file pointer for each vnode (accessed via
vnode_fsnode).
In a traditional UNIX system, there's a one-to-one correspondence between
vnodes and fsnodes (excluding transition situations, where vnodes are being
created or reclaimed). However, Mac OS X's support for multi-fork files means that
there can be more than one vnode for a given FSNode. As vnodes are the hook on
which file system operations like read and write are performed, each fork has
its own vnode. However, you don't want each of these vnodes to have its own FSNode,
because that makes directory operations (like renaming or deleting a file) much harder.
So, on Mac OS X there is a many-to-one relationship between vnodes and FSNodes.
Also, the existance of hard links means that there's a one-to-many relationship
between directory entries and fsobjs. It's important to remember that a vnode
represents an fsobj, not a directory entry. Likewise for an FSNode.
What makes this stuff tricky is that these two caches (vnodes and FSNodes) must
be kept in sync, and this must be done in a multi-threaded environment. Moreover,
it's not possible for an FSNode to keep a strong reference to the vnode, because
if it did it would be impossible to ever reclaim a vnode.
The solution to this problem (as implemented by this module, the architecture of
which was basically cribbed from the HFS Plus implementation) is for the VFS plug-in
to maintain a hash table of the FSNodes that currently exist. This is hashed by
the device number on which the FSNode's fsobj resides, and the inode number of
the fsobj. This hashing scheme allows the VFS plug-in's implementation
of VNOPLookup to quickly determine where an FSNode exists for the fsobj
referenced by a given directory entry.
The hash table in protected by a single (per VFS plug-in) lock. For good performance,
it's critical that the VFS plug-in not hold this lock for long. Furthermore, to
prevent deadlock the VFS plug-in should not call out to other parts of the system
while holding this lock. For example, a VFS plug-in /must/ drop its hash lock
before allocating memory.
This module implements the above recommendation exactly. The locking is entirely
internal to the module, and it will never return to you (or call out to the system)
with a lock held.
One key subtlety here is that, when VNOPLookup looks for an FSNode and fails to
find one, it creates a dummy one and puts it in the hash table. This dummy
entry is in a state (the attaching state) that causes other threads that might
also be looking up this FSNode to stall until the FSNode is fully constructed
(that is, the vnode has been attached to it) or the original thread has failed
to attach. This presence of this dummy allows the thread to drop the hash table
lock (in order to construct the vnode) without worrying about other threads stepping
on its toes.
As I mentioned previously, an entry in the FSNode hash table cannot keep
a strong reference on its associated vnodes because that would prevent the
vnodes from every being reclaimed. Thus, every time you pull a vnode out of the
FSNode hash table, you have to reconfirm that it's valid. This is done using
the vnode ID. While holding the hash table lock (which holds up any threads
reclaiming the vnode inside the VNOPReclaim) you get the vnode's ID. You
then drop the lock and get an I/O reference on the vnode using
vnode_getwithvid. This checks to see if the vnode ID has changed. If so,
the vnode has been recycled between you dropping your hash table lock and
you getting the vnode I/O reference. In that case, you can just retry
and expect that the next time you will get consistent results (it's likely
that, when you dropped the hash lock, the vnode was reclaimed and thus
the vnode reference in the FSNode has been set to NULL).
Note
This architecture works because the system's vnode table grows
(up to a limit), but it never shrinks. Thus, vnodes are never freed,
only recycled. Therefore, once you've been given a vnode_t, you can
rest assured that it will be valid for ever (well, until the system
restarts). It may, however, change what fsobj it refers to, but in
that case its vnode ID will change.
On the subject of vnode reclaiming, it's important to get three pieces of
terminology correct:
o When we say that a vnode has been recycled, it means that it has changed
identity. Remember, the system maintains a vnode table as a cache of
the fsobjs on disk. The system can pick and choose which fsobjs it
wants to cache. When it changes the identity of a vnode, the vnode
has been recycled.
A VFS plug-in can force a vnode to be recycled by calling vnode_recycle;
typically you do this when you want to force the system to forget about
some file (perhaps some internal B-tree file).
o A vnode is reclaimed as part of the process of recycling it. Once VFS
has decided to change the identity of a vnode, it must first disconnect it
from its previous identity. It needs to tell the VFS plug-in about this,
and this is the reclaim call (VNOPReclaim).
It's vital to realise that a VFS plug-in cannot say "no" to a reclaim call
(doing so will panic the system). This is not an appropriate place to,
for example, write the directory entry back to disk. The primary goal of
a reclaim call is to disconnect the vnode from the FSNode. Secondary to
that, if this is the last vnode associated with the FSNode, the reclaim
call should, at its disgression, dispose of of the FSNode.
o VFS makes a vnode inactive when the last significant reference to the
vnode goes away. For example, when the last file descriptor that uses
the vnode is closed, VFS makes the inactive call to the VFS plug-in
(VNOPInactive). This is the point where the plug-in should do any clean
up that might fail (for example, write to disk any changes made to the
fsobj).
It's important to realise that, just because a vnode has been made inactive,
doesn't mean that it will be recycled (and, prior to that, reclaimed) soon.
The vnodes act as a cache of directory entries, and if that cache is not
under pressure, vnodes aren't recycled. Also, if the vnode isn't recycled
immediately, it's possible that someone will take a significant reference
to the vnode (for example, open the file again) and that will make it
active again.
Module Usage
------------
To start, you need to get the following terminology straight.
o vnode -- This is VFS's handle to the cached file system object (fsobj). Your
VFS plug-in can create and manipulate vnodes using the VFS KPI.
o HNode -- This is the file system specific data for a cached fsobj that is
managed by this module. This is not truly file system specific, in that
the HNode data structure, like this module, is meant to be reusable, and would be
the same for virtually any file system.
Your VFS plug-in manipulates HNodes using the routines exported by this module.
o FSNode -- This is the file system specific data for a cached fsobj that is
not managed by this module. Your VFS plug-in is responsible for this data.
There is a one-to-many relationship between vnodes and HNodes. The HNode maintains an
array of vnodes for the file's forks. The index into this array can be simple (for
example, on a simple twin fork file system, like MFS, 0 is the data fork and 1 is the
resource fork), or it can be complex (you might dynamically allocate fork indexes based
on some criteria internal to your file system. However, I strongly recommend that you
follow these guidelines:
o You should use fork 0 as the data fork, which is the fork seen by non-fork aware
programs (<x-man-page://1/cat, for example).
o For directory vnodes, you should always specify a fork index of 0.
There is a strict one-to-one relationship between HNodes and FSNodes; in fact, they are
both embedded in the same memory block.
The routines exported by this module can be broken into 5 groups:
o initialisations and termination -- Your VFS plug-in must call HNodeInit before
calling any other routines in this module, and HNodeTerm before unloading.
It is safe to call HNodeTerm even if HNodeInit fails, and it's safe to call
HNodeTerm without ever calling HNodeInit.
When you initialise this module, you give it the following information:
o A lock group and lock attributes, so that the module can create locks.
o A OS malloc tag, so that the module can allocate memory.
o A magic number that the module uses to mark HNodes.
o The size of your FSNode.
The module will use this last piece of information to allocate your FSNode as part
of the same memory block as it uses for the HNode. It guarantees to clear the FSNode
before you see it, so you can use an "initialised" field to determine whether you've
constructed the FSNode yet.
o transfer functions -- These routines allow you to get the HNode for a vnode
(HNodeFromVNode), the FSNode for an HNode (FSNodeGenericFromHNode), and so on.
o accessors -- The simple accessors let you access certain important fields of an
including the device number (HNodeGetDevice) and inode number (HNodeGetInodeNumber).
The complex accessors let you map a vnode to a fork index (HNodeGetForkIndexForVNode),
and get the vnode for a given fork index (HNodeGetVNodeForForkAtIndex).
IMPORTANT
Because a vnode can be reclaimed at any time, and unless you know that the vnode
can't be reclaimed, you should confirm that the vnode hasn't been reclaimed
(using the vnode ID technique described above) before assuming that the vnode still
refers to this FSNode.
o vnode lifecycle -- These routines let you create and destroy FSNodes, and attach and
detach vnodes from them. Their usage is explained in more detail below.
o debugging -- HNodePrintState lets you print the state of this module.
The two most important places where your VFS plug-in interacts with this module are
VNOPLookup and VNOPReclaim. In VNOPLookup, you want to create a vnode for a given
directory entry. This module assumes that the file system object (fsobj) referenced
by the directory entry is uniquely identified by its device number (dev_t) and inode
number (ino_t). These, along with the fork index, are the keys that you pass to
HNodeLookupCreatingIfNecessary to see if the vnode already exists. Once you've called
HNodeLookupCreatingIfNecessary, you must interpret the results and then follow a strictly
defined protocol to ensure that everything works properly. The results of
HNodeLookupCreatingIfNecessary are as follows:
o failure -- If HNodeLookupCreatingIfNecessary returns an error, it has failed
and you don't have to do anything more (other than handle the error, but that
has no hash-layer implications).
o success, no vnode -- If there is no vnode matching your request,
HNodeLookupCreatingIfNecessary will return a valid HNode but a NULL vnode.
In this case, you must either:
o create a vnode and attach it to the HNode by calling HNodeAttachVNodeSucceeded
o abort the attach by calling HNodeDetachVNode
There are two substate here:
o If the HNode is entirely new, the FSNode will have just been allocated and
will be all zeros. You should check for this, and initialise the FSNode
(before creating the vnode).
o If the HNode already exists, the FSNode will not be all zeros, and you can
assume that you've initialised it already.
Thus, you can use a simple "initialised" field in your FSNode to tell whether
it's been initialised or not.
o success, vnode -- If there is a vnode matching your request,
HNodeLookupCreatingIfNecessary will return a valid HNode and a valid vnode.
The FSNode associated with the HNode will be initialised in this case. You have
an I/O reference on the vnode, so you can guarantee that it won't go away
until you call vnode_put (and neither will the HNode or FSNode, because the existance
of the vnode will keep them from going away). You /must/ call vnode_put on the vnode
at some point in the future (or pass it to someone who will call vnode_put for you).
So, here's a high-level outline of how to create a vnode using HNodeLookupCreatingIfNecessary.
HNodeLookupCreatingIfNecessary(dev, ino, forkIndex) -> err, hn, vn
if not err and vn is NULL then
assert(hn != NULL);
FSNodeGenericFromHNode(hn) -> fsn
if fsn is not initialised then
initialise fsn -> err
end if
if not err then
vnode_create(hn) -> err, vn
end if
if err then
HNodeAttachVNodeSucceeded(hn, forkIndex, vn)
else
HNodeAttachVNodeFailed(hn, forkIndex) -> see below
end if
end if
if no err then
-- vn is not NULL, and you have an I/O reference on it
-- you must release that reference at some point by calling vnode_put
else
-- handle the error; with no further hash-layer implications
end if
The second important interaction between your VFS plug-in and this module is in
VNOPReclaim. In this case, you must call HNodeDetachVNode to detach the vnode from
the HNode. This is pretty simple, and the only complication is in FSNode
scrubbing (described next).
In all cases where you detach a reference on an HNode (HNodeDetachVNode, obviously, but
also when you fail to create a vnode for an HNode and abort the operation by calling
HNodeAttachVNodeFailed), the function returns a Boolean indicating whether this is
the last vnode referencing the HNode. If it is, you must scrub the FSNode and, when
that's done, tell this module that you're done by calling HNodeScrubDone. At this point,
this module will free the memory used for the HNode and FSNode.
IMPORTANT
Your scrubbing code MUST NEVER FAIL. This is a direct consequence of it running on
the reclaim path.
When your scrubbing code runs, it is guaranteed that no other threads will be
scrubbing the FSNode, or attempting to resurrect the FSNode. The HNode has been
pulled out of the hash table. Thus, once HNodeDetachVNode or HNodeAttachVNodeFailed
returns true, any other threads that try to access this FSNode will end up creating a
new FSNode instead.
A typical scrubbing routine would just dispose of any data structures (like locks)
that are owned by the FSNode.
Here's a high-level outline of FSNode scrubbing.
HNodeDetachVNode(hn, vn) -> scrubIt
if scrubIt then
FSNodeGenericFromHNode(hn) -> fsnode
-- dispose of any data structures owned by fsnode
HNodeScrubDone(hn)
end if
IMPORTANT
Do not call HNodeFromVNode or FSNodeGenericFromVNode after HNodeDetachVNode has
returned true. By that point, the vnode no longer references the HNode/FSNode.
Don't forget that you have to use the same logic for HNodeAttachVNodeFailed as well as
HNodeDetachVNode.
*/
/////////////////////////////////////////////////////////////////////
typedef struct HNode * HNodeRef;
#pragma mark - Init/Term
extern errno_t HNodeInit(
lck_grp_t * lockGroup,
lck_attr_t * lockAttr,
OSMallocTag mallocTag,
uint32_t magic,
size_t fsNodeSize
);
// Initialises this module. You must call this routine before calling any other
// routines exported by this module (except HNodeTerm).
//
// lockGroup must be a valid lock group, and that lock group must persist until
// HNodeTerm is called. Any locks that this module creates will be in this group.
//
// lockAttr may be NULL, in which case locks with the default attributes are used.
// If lockAttr is not NULL, these attributes are used for all locks created by this
// module. lockAttr may be destroyed after this routine has returned.
//
// mallocTag must be a valid OS malloc tag, and this must persist until HNodeTerm is
// called.
//
// magic is a magic number used for the first four bytes of any HNode created by this
// module; it's purely a debugging aid. If you set it to something notable (like
// four ASCII characters), it's easy to see HNodes in the debugger.
//
// fsNodeSize is the amount of memory that this module should allocate for the FSNode
// when allocating an HNode. That is, when you call FSNodeGenericFromHNode, the returned
// value will point to a block of memory that's at least this big.
//
// Returns an errno-style error.
//
// On success, you must call HNodeTerm before unloading this code.
// On error, you may call HNodeTerm before unloading this code (it will be a NOP).
extern void HNodeTerm(void);
// Terminates this module. Before calling this routine, you must ensure that all
// HNodes have been destroyed (by ensuring that all vnodes that reference these
// HNodes have been reclaimed). Typically this happens automatically if you make
// sure that all of your VFS plug-in's volumes are unmounted before you call this
// routine.
//
// You must call this routine before unloading this code.
//
// You must not call any other routine in this module (except HNodeInit) after
// calling this routine.
//
// It is safe to call this routine even if you've never called HNodeInit, or if
// HNodeInit failed.
#pragma mark - Transfer
extern void * FSNodeGenericFromHNode(HNodeRef hnode);
// Returns the FSNode associated with an hnode. hnode must be a valid
// HNode. This routine can never fail because the HNode and FSNode are allocated
// within the same memory block.
//
// This routine has the word "Generic" in it because it is expected
// that you'll write your own HNodeGetFSNode routine whose return value is
// cast to the type you're using for your FSNode.
extern HNodeRef HNodeFromFSNodeGeneric(void *fsNode);
// Returns the HNode associated a given FSNode. fsnode must be a valid
// FSNode. This routine can never fail because the HNode and FSNode are allocated
// within the same memory block.
//
// This routine has the word "Generic" in it because it is expected
// that you'll write your own FSNodeGetHNode routine whose input is of the
// appropriate type.
extern HNodeRef HNodeFromVNode(vnode_t vn);
// Returns the HNode for a given vnode. This routine should never fail.
// The only circumstances in which it might fail are if vn is not valid,
// or its not a vnode for your file system, or it has somehow been created
// without an HNode. All of these are panicworthy.
extern void * FSNodeGenericFromVNode(vnode_t vn);
// Returns the FSNode for a given vnode. As this is a composition of
// HNodeFromVNode and FSNodeGenericFromHNode, it shouldn't fail and any
// failures are panicworthy.
#pragma mark - Accessors
extern dev_t HNodeGetDevice(HNodeRef hnode);
// Gets the device number associated with this HNode. This is exactly what you passed
// in when you created the HNode using HNodeLookupCreatingIfNecessary.
extern ino_t HNodeGetInodeNumber(HNodeRef hnode);
// Gets the inode number associated with this HNode. This is exactly what you passed
// in when you created the HNode using HNodeLookupCreatingIfNecessary.
extern vnode_t HNodeGetVNodeForForkAtIndex(HNodeRef hnode, size_t forkIndex);
// This returns the vnode for a given fork of the HNode, which may be NULL. As this
// doesn't take any references on the vnode, the results can be stale.
//
// hnode must be a valid HNodeRef.
//
// forkIndex must not be greater than the highest fork index that you've passed to
// HNodeLookupCreatingIfNecessary for this HNode.
//
// Note:
// This routine is more expensive than you might think because it has to take the
// global hash table lock; if possible, it's better to remember the result from
// another routine (like HNodeLookupCreatingIfNecessary) rather than call this routine
// to recover the same information.
extern size_t HNodeGetForkIndexForVNode(vnode_t vn);
// This returns the fork index of the given vnode within the HNode.
//
// vn must be a valid vnode for a vnode on this file system. To meet this precondition,
// the caller must hold a reference (typically an I/O reference) on the vnode when
// calling this routine.
//
// Note:
// This routine is more expensive than you might think because it has to take the
// global hash table lock; if possible, it's better to remember the result from
// another routine (like HNodeLookupCreatingIfNecessary) rather than call this routine
// to recover the same information.
#pragma mark - VNode/FSNode Lifecycle
extern errno_t HNodeLookupCreatingIfNecessary(dev_t dev, ino_t ino, size_t forkIndex, HNodeRef *hnodePtr, vnode_t *vnPtr);
// Looks up the HNode in the hash table, and returns a reference to it and to the vnode for
// the specified fork (if one exists).
//
// dev and ino form the hash table key.
//
// forkIndex may be greater than any previous fork index used for this HNode, in which case
// the routine will silently and automatically expand the array used to track the fork vnodes.
//
// hnodePtr must not be NULL; *hnodePtr must be NULL.
//
// vnPtr must not be NULL; *vnPtr must be NULL.
//
// On error, *hnodePtr and *vnPtr will be NULL
//
// On success, *vnPtr will either be NULL or it will be a reference to a vnode. In the first case,
// the caller must attach a vnode (by calling HNodeAttachVNodeSucceeded) or release the HNode
// (by calling HNodeAttachVNodeFailed). In the second case, the caller must release the reference
// to the vnode by calling vnode_put.
//
// On success, *hnodePtr will be a reference to an HNode. This reference will persist for one
// of two reasons:
//
// o If *vnPtr is NULL, the reference to the HNode will persist because we've set internal state
// that is cleared by this thread calling either HNodeAttachVNodeSucceeded or HNodeAttachVNodeFailed.
//
// o If *vnPtr is not NULL, the reference will persist because the HNode is 'owned' by the vnode,
// and the vnode will persist until the caller drops its reference by calling vnode_put.
//
// IMPORTANT
// The HNode returned by this routine might be newly allocated, in which case the associated
// FSNode will not be initialised. It is your responsibility for checking whether the FSNode
// has been initialised, and initialising it if it hasn't already been. This requirement is
// only relevant if the routine succeeds and *vnPtr is NULL.
//
// IMPORTANT
// In other hash layer implementations, the hash layer 'knows' whether an FSNode refers to a
// file system object that has been deleted. This is not the case here. If you have an
// FSNode "is deleted" flag, you are responsible for checking it upon return from this routine.
extern void HNodeAttachVNodeSucceeded(HNodeRef hnode, size_t forkIndex, vnode_t vn);
// Attaches a vnode to an HNode. You can only call this routine after calling
// HNodeLookupCreatingIfNecessary and having it succeed but not return a vnode.
// In that case, you must either call this routine or HNodeAttachVNodeFailed.
//
// hnode must be the HNodeRef returned by HNodeLookupCreatingIfNecessary.
//
// forkIndex must be the same as the forkIndex you passed to HNodeLookupCreatingIfNecessary.
//
// vn must be a valid vnode that you've created using vnode_create; the per-file system data
// for this vnode (that is, the value you passed in the vnfs_fsnode of the (struct vnode_fsparam)
// you passed to vnode_create) must be equal to hnode.
//
// Note
// This routine adds an FS reference to the vnode (it calls vnode_addfsref).
extern boolean_t HNodeAttachVNodeFailed(HNodeRef hnode, size_t forkIndex);
// Indicates that an attempt to create a vnode to attach to to an HNode has failed. You
// can only call this routine after calling HNodeLookupCreatingIfNecessary and having it
// succeed but not return a vnode. In that case, you must either call this routine or
// HNodeAttachVNodeSucceeded.
//
// hnode must be the HNodeRef returned by HNodeLookupCreatingIfNecessary.
//
// forkIndex must be the same as the forkIndex you passed to HNodeLookupCreatingIfNecessary.
//
// If this routine returns true, you must scrub the FSNode associated with the HNode
// and then call HNodeScrubDone on the HNode.
extern boolean_t HNodeDetachVNode(HNodeRef hnode, vnode_t vn);
// Detaches a vnode from an HNode. You must [should?] only call this from your
// VNOPReclaim routine.
//
// vn must be a valid vnode associated with this HNode
//
// If this routine returns true, you must scrub the FSNode associated with the HNode
// and then call HNodeScrubDone on the HNode.
//
// Note
// This routine removes the FS reference on the vnode (it calls vnode_removefsref).
extern void HNodeScrubDone(HNodeRef hnode);
// Deallocates an HNode. You must call this routine on an HNode if either
// HNodeAttachVNodeFailed or HNodeDetachVNode returns true.
#pragma mark - Debugging
extern void HNodePrintState(void);
// Prints the current state of this module using printf. This is a debugging aid
// only. It makes a best attempt to be thead safe, but there are still race conditions.
#endif
</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/MFSLives/listing2.html%3Fid%3DDTS10004026-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/MFSLives/listing2.html%3Fid%3DDTS10004026-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/MFSLives/listing2.html%3Fid%3DDTS10004026-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>