|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /* @(#)hfs_btreeio.c
23: *
24: * (c) 1998, 2000 Apple Computer, Inc. All Rights Reserved
25: *
26: * hfs_btreeio.c -- I/O Routines for the HFS B-tree files.
27: *
28: * HISTORY
29: * 15-Feb-2000 Don Brady Added ClearBTNodes.
30: * 16-Jul-1998 Don Brady In ExtendBtreeFile force all b-tree nodes to be contiguous on disk.
31: * 4-Jun-1998 Pat Dirks Changed to do all B*-Tree writes synchronously (FORCESYNCBTREEWRITES = 1)
32: * 18-apr-1998 Don Brady Call brelse on bread failure.
33: * 17-Apr-1998 Pat Dirks Fixed ReleaseBTreeBlock to not call brelse when bwrite or bdwrite is called.
34: * 13-apr-1998 Don Brady Add ExtendBTreeFile routine (from BTreeWrapper.c).
35: * 26-mar-1998 Don Brady SetBTreeBlockSize was incorrectly excluding 512 byte blockSize.
36: * 18-feb-1998 Don Brady Initially created file.
37: *
38: */
39:
40: #include <sys/param.h>
41: #include <sys/systm.h>
42: #include <sys/buf.h>
43: #include <sys/mount.h>
44: #include <sys/vnode.h>
45:
46:
47: #include "hfs.h"
48: #include "hfs_dbg.h"
49:
50: #include "hfscommon/headers/FileMgrInternal.h"
51: #include "hfscommon/headers/BTreesPrivate.h"
52:
53: #define FORCESYNCBTREEWRITES 0
54:
55: static OSStatus FlushAlternate( ExtendedVCB *vcb );
56:
57: static int ClearBTNodes(struct vnode *vp, long blksize, off_t offset, off_t amount);
58:
59:
60: OSStatus SetBTreeBlockSize(FileReference vp, ByteCount blockSize, ItemCount minBlockCount)
61: {
62: BTreeControlBlockPtr bTreePtr;
63:
64: DBG_ASSERT(vp != NULL);
65: DBG_ASSERT(VTOFCB(vp) != NULL);
66: DBG_ASSERT(VTOFCB(vp)->fcbBTCBPtr != NULL);
67: DBG_ASSERT(blockSize >= kMinNodeSize);
68: if (blockSize > MAXBSIZE )
69: return (fsBTBadNodeSize);
70:
71: DBG_TREE(("SetBlockSizeProc: blockSize=%ld for file %ld\n", blockSize, H_FILEID(VTOH(vp))));
72:
73: bTreePtr = (BTreeControlBlockPtr)(VTOH(vp)->fcbBTCBPtr);
74: bTreePtr->nodeSize = blockSize;
75:
76: return (E_NONE);
77: }
78:
79:
80: OSStatus GetBTreeBlock(FileReference vp, UInt32 blockNum, GetBlockOptions options, BlockDescriptor *block)
81: {
82: OSStatus retval = E_NONE;
83: struct buf *bp = NULL;
84:
85: if (options & kGetEmptyBlock)
86: bp = getblk (vp,
87: IOBLKNOFORBLK(blockNum, VTOHFS(vp)->hfs_phys_block_size),
88: IOBYTECCNTFORBLK(blockNum, block->blockSize, VTOHFS(vp)->hfs_phys_block_size),
89: 0,
90: 0);
91: else
92: retval = bread (vp,
93: IOBLKNOFORBLK(blockNum, VTOHFS(vp)->hfs_phys_block_size),
94: IOBYTECCNTFORBLK(blockNum, block->blockSize, VTOHFS(vp)->hfs_phys_block_size),
95: NOCRED,
96: &bp);
97:
98: DBG_ASSERT(bp != NULL);
99: DBG_ASSERT(bp->b_data != NULL);
100: DBG_ASSERT(bp->b_bcount == block->blockSize);
101: DBG_ASSERT(bp->b_lblkno == blockNum);
102:
103: if (bp == NULL)
104: retval = -1; //XXX need better error
105:
106: if (retval == E_NONE) {
107: block->blockHeader = bp;
108: block->buffer = bp->b_data + IOBYTEOFFSETFORBLK(bp->b_blkno, VTOHFS(vp)->hfs_phys_block_size);
109: block->blockReadFromDisk = (bp->b_flags & B_CACHE) == 0; /* not found in cache ==> came from disk */
110: } else {
111: if (bp)
112: brelse(bp);
113: block->blockHeader = NULL;
114: block->buffer = NULL;
115: }
116:
117: return (retval);
118: }
119:
120:
121: OSStatus ReleaseBTreeBlock(FileReference vp, BlockDescPtr blockPtr, ReleaseBlockOptions options)
122: {
123: OSStatus retval = E_NONE;
124: struct buf *bp = NULL;
125:
126: bp = (struct buf *) blockPtr->blockHeader;
127:
128: if (bp == NULL) {
129: DBG_TREE(("ReleaseBlockProc: blockHeader is zero!\n"));
130: retval = -1;
131: goto exit;
132: }
133:
134: if (options & kTrashBlock) {
135: bp->b_flags |= B_INVAL;
136: brelse(bp); /* note: B-tree code will clear blockPtr->blockHeader and blockPtr->buffer */
137: } else {
138: if (options & kForceWriteBlock) {
139: bp->b_flags |= B_DIRTY;
140: retval = bwrite(bp);
141: } else if (options & kMarkBlockDirty) {
142: bp->b_flags |= B_DIRTY;
143: #if FORCESYNCBTREEWRITES
144: bwrite(bp);
145: #else
146: if (options & kLockTransaction) {
147:
148: /*
149: *
150: * Set the B_LOCKED flag and unlock the buffer, causing brelse to move
151: * the buffer onto the LOCKED free list. This is necessary, otherwise
152: * getnewbuf() would try to reclaim the buffers using bawrite, which
153: * isn't going to work.
154: *
155: */
156: bp->b_flags |= B_LOCKED;
157: };
158: bdwrite(bp);
159:
160: #endif
161: } else {
162: brelse(bp); /* note: B-tree code will clear blockPtr->blockHeader and blockPtr->buffer */
163: };
164: };
165:
166: exit:
167: return (retval);
168: }
169:
170:
171: OSStatus ExtendBTreeFile(FileReference vp, FSSize minEOF, FSSize maxEOF)
172: {
173: #pragma unused (maxEOF)
174:
175: OSStatus retval;
176: UInt64 actualBytesAdded;
177: UInt64 bytesToAdd;
178: UInt32 extendFlags;
179: BTreeInfoRec btInfo;
180: ExtendedVCB *vcb;
181: FCB *filePtr;
182: struct proc *p = NULL;
183:
184:
185: filePtr = GetFileControlBlock(vp);
186:
187: if ( minEOF > filePtr->fcbEOF )
188: {
189: bytesToAdd = minEOF - filePtr->fcbEOF;
190:
191: if (bytesToAdd < filePtr->fcbClmpSize)
192: bytesToAdd = filePtr->fcbClmpSize; //XXX why not always be a mutiple of clump size?
193: }
194: else
195: {
196: DBG_TREE((" ExtendBTreeFile: minEOF is smaller than current size!"));
197: return -1;
198: }
199:
200: vcb = FCBTOVCB(filePtr);
201:
202: /*
203: * The Extents B-tree can't have overflow extents. ExtendFileC will
204: * return an error if an attempt is made to extend the Extents B-tree
205: * when the resident extents are exhausted.
206: */
207: /* XXX warning - this can leave the volume bitmap unprotected during ExtendFileC call */
208: if(H_FILEID(filePtr) != kHFSExtentsFileID)
209: {
210: p = current_proc();
211: /* lock extents b-tree (also protects volume bitmap) */
212: retval = hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_EXCLUSIVE, p);
213: if (retval)
214: return (retval);
215: }
216:
217: (void) BTGetInformation(filePtr, 0, &btInfo);
218:
219: /*
220: * The b-tree code expects nodes to be contiguous. So when
221: * the allocation block size is less than the b-tree node
222: * size, we need to force disk allocations to be contiguous.
223: */
224: if (vcb->blockSize >= btInfo.nodeSize) {
225: extendFlags = 0;
226: } else {
227: /* Ensure that all b-tree nodes are contiguous on disk */
228: extendFlags = kEFAllMask | kEFContigMask;
229: }
230:
231: retval = ExtendFileC(vcb, filePtr, bytesToAdd, extendFlags, &actualBytesAdded );
232:
233: if(H_FILEID(filePtr) != kHFSExtentsFileID)
234: (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_RELEASE, p);
235:
236: if (retval)
237: return (retval);
238:
239: if (actualBytesAdded < bytesToAdd)
240: DBG_TREE((" ExtendBTreeFile: actualBytesAdded < bytesToAdd!"));
241:
242: filePtr->fcbEOF = filePtr->fcbPLen;
243:
244: retval = ClearBTNodes(vp, btInfo.nodeSize, filePtr->fcbEOF - actualBytesAdded, actualBytesAdded);
245: if (retval)
246: return (retval);
247:
248: /*
249: * Update the Alternate MDB or Alternate VolumeHeader
250: */
251: if ((H_FILEID(filePtr) == kHFSExtentsFileID) ||
252: (H_FILEID(filePtr) == kHFSCatalogFileID) ||
253: (H_FILEID(filePtr) == kHFSAttributesFileID)
254: ) {
255: MarkVCBDirty( vcb );
256: if (vcb->vcbSigWord == kHFSPlusSigWord) {
257: retval = hfs_flushvolumeheader(VCBTOHFS(vcb), 0);
258: } else {
259: retval = hfs_flushMDB(VCBTOHFS(vcb), 0);
260: }
261: if (retval == 0) {
262: retval = FlushAlternate(vcb);
263: }
264: }
265:
266: return retval;
267: }
268:
269:
270: static OSStatus
271: FlushAlternate( ExtendedVCB *vcb )
272: {
273: void *maindata;
274: void *altdata;
275: int result;
276:
277: /* Get the main MDB/VolumeHeader block */
278: result = GetBlock_glue(gbDefault,
279: (vcb->hfsPlusIOPosOffset / kHFSBlockSize) + kMasterDirectoryBlock,
280: (Ptr *)&maindata, kNoFileReference, vcb);
281: if (result) return (result);
282:
283: /* Get the alternate MDB/VolumeHeader block */
284: result = GetBlock_glue( gbDefault, vcb->altIDSector,
285: (Ptr *)&altdata, kNoFileReference, vcb );
286:
287: if (result == 0) {
288: bcopy(maindata, altdata, kMDBSize);
289:
290: result = RelBlock_glue( (Ptr)altdata, rbWriteMask );
291: }
292:
293: (void) RelBlock_glue( (Ptr)maindata, rbFreeMask );
294:
295: return (result);
296: }
297:
298:
299: /*
300: * Clear out (zero) new b-tree nodes on disk.
301: */
302: static int
303: ClearBTNodes(struct vnode *vp, long blksize, off_t offset, off_t amount)
304: {
305: struct buf *bp = NULL;
306: daddr_t blk;
307: daddr_t blkcnt;
308:
309: blk = offset / blksize;
310: blkcnt = amount / blksize;
311:
312: while (blkcnt > 0) {
313: bp = getblk(vp, blk, blksize, 0, 0); /* ubc: BLK_META */
314: if (bp == NULL)
315: continue;
316: bzero((char *)bp->b_data, blksize);
317: bp->b_flags |= (B_DIRTY | B_AGE);
318:
319: /* wait/yield every 32 blocks so we don't hog all the buffers */
320: if ((blk % 32) == 0)
321: bwrite(bp);
322: else
323: bawrite(bp);
324: --blkcnt;
325: ++blk;
326: }
327:
328: return (0);
329: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.