2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
22 /* @(#)hfs_readwrite.c 1.0
24 * (c) 1990, 1992 NeXT Computer, Inc. All Rights Reserved
25 * (c) 1998 Apple Computer, Inc. All Rights Reserved
28 * hfs_readwrite.c -- vnode operations to deal with reading and writing files.
30 * MODIFICATION HISTORY:
31 * 9-Nov-1999 Scott Roberts hfs_allocate now returns sizes based on allocation block boundaries (#2398794)
32 * 3-Feb-1999 Pat Dirks Merged in Joe's change to hfs_truncate to skip vinvalbuf if LEOF isn't changing (#2302796)
33 * Removed superfluous (and potentially dangerous) second call to vinvalbuf() in hfs_truncate.
34 * 2-Dec-1998 Pat Dirks Added support for read/write bootstrap ioctls.
35 * 10-Nov-1998 Pat Dirks Changed read/write/truncate logic to optimize block sizes for first extents of a file.
36 * Changed hfs_strategy to correct I/O sizes from cluser code I/O requests in light of
37 * different block sizing. Changed bexpand to handle RELEASE_BUFFER flag.
38 * 22-Sep-1998 Don Brady Changed truncate zero-fill to use bwrite after several bawrites have been queued.
39 * 11-Sep-1998 Pat Dirks Fixed buffering logic to not rely on B_CACHE, which is set for empty buffers that
40 * have been pre-read by cluster_read (use b_validend > 0 instead).
41 * 27-Aug-1998 Pat Dirks Changed hfs_truncate to use cluster_write in place of bawrite where possible.
42 * 25-Aug-1998 Pat Dirks Changed hfs_write to do small device-block aligned writes into buffers without doing
43 * read-ahead of the buffer. Added bexpand to deal with incomplete [dirty] buffers.
44 * Fixed can_cluster macro to use MAXPHYSIO instead of MAXBSIZE.
45 * 19-Aug-1998 Don Brady Remove optimization in hfs_truncate that prevented extra physical blocks from
46 * being truncated (radar #2265750). Also set fcb->fcbEOF before calling vinvalbuf.
47 * 7-Jul-1998 Pat Dirks Added code to honor IO_NOZEROFILL in hfs_truncate.
48 * 16-Jul-1998 Don Brady In hfs_bmap use MAXPHYSIO instead of MAXBSIZE when calling MapFileBlockC (radar #2263753).
49 * 16-Jul-1998 Don Brady Fix error handling in hfs_allocate (radar #2252265).
50 * 04-Jul-1998 chw Synchronized options in hfs_allocate with flags in call to ExtendFileC
51 * 25-Jun-1998 Don Brady Add missing blockNo incrementing to zero fill loop in hfs_truncate.
52 * 22-Jun-1998 Don Brady Add bp = NULL assignment after brelse in hfs_read.
53 * 4-Jun-1998 Pat Dirks Split off from hfs_vnodeops.c
56 #include <sys/param.h>
57 #include <sys/systm.h>
58 #include <sys/resourcevar.h>
59 #include <sys/kernel.h>
60 #include <sys/fcntl.h>
64 //#include <mach/machine/vm_types.h>
65 #include <sys/vnode.h>
68 #include <miscfs/specfs/specdev.h>
71 #include <vm/vm_pageout.h>
73 #include <sys/kdebug.h>
77 #include "hfs_endian.h"
78 #include "hfscommon/headers/FileMgrInternal.h"
79 #include "hfscommon/headers/BTreesInternal.h"
82 #define can_cluster(size) ((((size & (4096-1))) == 0) && (size <= (MAXPHYSIO/2)))
85 MAXHFSFILESIZE
= 0x7FFFFFFF /* this needs to go in the mount structure */
88 extern u_int32_t
GetLogicalBlockSize(struct vnode
*vp
);
90 #if DBG_VOP_TEST_LOCKS
91 extern void DbgVopTest(int maxSlots
, int retval
, VopDbgStoreRec
*VopDbgStore
, char *funcname
);
95 void debug_check_blocksizes(struct vnode
*vp
);
98 /*****************************************************************************
100 * Operations on vnodes
102 *****************************************************************************/
109 INOUT struct uio *uio;
111 IN struct ucred *cred;
117 struct vop_read_args
/* {
121 struct ucred *a_cred;
124 register struct vnode
*vp
;
126 register struct uio
*uio
;
129 u_long fragSize
, moveSize
, startOffset
, ioxfersize
;
130 int devBlockSize
= 0;
131 off_t bytesRemaining
;
136 DBG_FUNC_NAME("hfs_read");
137 DBG_VOP_LOCKS_DECL(1);
138 DBG_VOP_PRINT_FUNCNAME();
139 DBG_VOP_PRINT_VNODE_INFO(ap
->a_vp
);DBG_VOP_CONT(("\n"));
140 DBG_VOP_LOCKS_INIT(0,ap
->a_vp
, VOPDBG_LOCKED
, VOPDBG_LOCKED
, VOPDBG_LOCKED
, VOPDBG_POS
);
145 mode
= hp
->h_meta
->h_mode
;
149 if (uio
->uio_rw
!= UIO_READ
)
150 panic("%s: mode", funcname
);
153 /* Can only read files */
154 if (ap
->a_vp
->v_type
!= VREG
&& ap
->a_vp
->v_type
!= VLNK
) {
155 DBG_VOP_LOCKS_TEST(EISDIR
);
158 DBG_RW(("\tfile size Ox%X\n", (u_int
)fcb
->fcbEOF
));
159 DBG_RW(("\tstarting at offset Ox%X of file, length Ox%X\n", (u_int
)uio
->uio_offset
, (u_int
)uio
->uio_resid
));
162 debug_check_blocksizes(vp
);
166 * If they didn't ask for any data, then we are done.
168 if (uio
->uio_resid
== 0) {
169 DBG_VOP_LOCKS_TEST(E_NONE
);
173 /* cant read from a negative offset */
174 if (uio
->uio_offset
< 0) {
175 DBG_VOP_LOCKS_TEST(EINVAL
);
179 if (uio
->uio_offset
> fcb
->fcbEOF
) {
180 if ( (!ISHFSPLUS(VTOVCB(vp
))) && (uio
->uio_offset
> (off_t
)MAXHFSFILESIZE
))
185 DBG_VOP_LOCKS_TEST(retval
);
189 VOP_DEVBLOCKSIZE(hp
->h_meta
->h_devvp
, &devBlockSize
);
191 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 12)) | DBG_FUNC_START
,
192 (int)uio
->uio_offset
, uio
->uio_resid
, (int)fcb
->fcbEOF
, (int)fcb
->fcbPLen
, 0);
195 retval
= cluster_read(vp
, uio
, (off_t
)fcb
->fcbEOF
, devBlockSize
, 0);
198 for (retval
= 0, bp
= NULL
; uio
->uio_resid
> 0; bp
= NULL
) {
200 if ((bytesRemaining
= (fcb
->fcbEOF
- uio
->uio_offset
)) <= 0)
203 logBlockNo
= (daddr_t
)(uio
->uio_offset
/ PAGE_SIZE_64
);
204 startOffset
= (u_long
) (uio
->uio_offset
& PAGE_MASK_64
);
205 fragSize
= PAGE_SIZE
;
207 if (((logBlockNo
* PAGE_SIZE
) + fragSize
) < fcb
->fcbEOF
)
208 ioxfersize
= fragSize
;
210 ioxfersize
= fcb
->fcbEOF
- (logBlockNo
* PAGE_SIZE
);
211 ioxfersize
= (ioxfersize
+ (devBlockSize
- 1)) & ~(devBlockSize
- 1);
213 DBG_RW(("\tat logBlockNo Ox%X, with Ox%lX left to read\n", logBlockNo
, (UInt32
)uio
->uio_resid
));
214 moveSize
= ioxfersize
;
215 DBG_RW(("\tmoveSize = Ox%lX; ioxfersize = Ox%lX; startOffset = Ox%lX.\n",
216 moveSize
, ioxfersize
, startOffset
));
217 DBG_ASSERT(moveSize
>= startOffset
);
218 moveSize
-= startOffset
;
220 if (bytesRemaining
< moveSize
)
221 moveSize
= bytesRemaining
;
223 if (uio
->uio_resid
< moveSize
) {
224 moveSize
= uio
->uio_resid
;
225 DBG_RW(("\treducing moveSize to Ox%lX (uio->uio_resid).\n", moveSize
));
231 DBG_RW(("\tat logBlockNo Ox%X, extent of Ox%lX, xfer of Ox%lX; moveSize = Ox%lX\n", logBlockNo
, fragSize
, ioxfersize
, moveSize
));
233 if (( uio
->uio_offset
+ fragSize
) >= fcb
->fcbEOF
) {
234 retval
= bread(vp
, logBlockNo
, ioxfersize
, NOCRED
, &bp
);
236 } else if (logBlockNo
- 1 == vp
->v_lastr
&& !(vp
->v_flag
& VRAOFF
)) {
237 daddr_t nextLogBlockNo
= logBlockNo
+ 1;
240 if (((nextLogBlockNo
* PAGE_SIZE
) +
241 (daddr_t
)fragSize
) < fcb
->fcbEOF
)
244 nextsize
= fcb
->fcbEOF
- (nextLogBlockNo
* PAGE_SIZE
);
245 nextsize
= (nextsize
+ (devBlockSize
- 1)) & ~(devBlockSize
- 1);
247 retval
= breadn(vp
, logBlockNo
, ioxfersize
, &nextLogBlockNo
, &nextsize
, 1, NOCRED
, &bp
);
249 retval
= bread(vp
, logBlockNo
, ioxfersize
, NOCRED
, &bp
);
252 if (retval
!= E_NONE
) {
259 vp
->v_lastr
= logBlockNo
;
262 * We should only get non-zero b_resid when an I/O retval
263 * has occurred, which should cause us to break above.
264 * However, if the short read did not cause an retval,
265 * then we want to ensure that we do not uiomove bad
266 * or uninitialized data.
268 ioxfersize
-= bp
->b_resid
;
270 if (ioxfersize
< moveSize
) { /* XXX PPD This should take the offset into account, too! */
273 moveSize
= ioxfersize
;
275 if ((startOffset
+ moveSize
) > bp
->b_bcount
)
276 panic("hfs_read: bad startOffset or moveSize\n");
278 DBG_RW(("\tcopying Ox%lX bytes from %lX; resid = Ox%lX...\n", moveSize
, (char *)bp
->b_data
+ startOffset
, bp
->b_resid
));
280 if ((retval
= uiomove((caddr_t
)bp
->b_data
+ startOffset
, (int)moveSize
, uio
)))
284 (((startOffset
+ moveSize
) == fragSize
) || (uio
->uio_offset
== fcb
->fcbEOF
))) {
285 bp
->b_flags
|= B_AGE
;
288 DBG_ASSERT(bp
->b_bcount
== bp
->b_validend
);
291 /* Start of loop resets bp to NULL before reaching outside this block... */
295 DBG_ASSERT(bp
->b_bcount
== bp
->b_validend
);
300 if (HTOVCB(hp
)->vcbSigWord
== kHFSPlusSigWord
)
301 hp
->h_nodeflags
|= IN_ACCESS
;
303 DBG_VOP_LOCKS_TEST(retval
);
306 debug_check_blocksizes(vp
);
309 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 12)) | DBG_FUNC_END
,
310 (int)uio
->uio_offset
, uio
->uio_resid
, (int)fcb
->fcbEOF
, (int)fcb
->fcbPLen
, 0);
316 * Write data to a file or directory.
321 INOUT struct uio *uio;
323 IN struct ucred *cred;
328 struct vop_write_args
/* {
332 struct ucred *a_cred;
335 struct hfsnode
*hp
= VTOH(ap
->a_vp
);
336 struct uio
*uio
= ap
->a_uio
;
337 struct vnode
*vp
= ap
->a_vp
;
342 FCB
*fcb
= HTOFCB(hp
);
343 ExtendedVCB
*vcb
= HTOVCB(hp
);
344 int devBlockSize
= 0;
347 off_t origFileSize
, currOffset
, writelimit
, bytesToAdd
;
348 off_t actualBytesAdded
;
349 u_long blkoffset
, resid
, xfersize
, clearSize
;
352 DBG_FUNC_NAME("hfs_write");
353 DBG_VOP_LOCKS_DECL(1);
354 DBG_VOP_PRINT_FUNCNAME();
355 DBG_VOP_PRINT_VNODE_INFO(ap
->a_vp
);DBG_VOP_CONT(("\n"));
356 DBG_RW(("\thfsnode 0x%x (%s)\n", (u_int
)hp
, H_NAME(hp
)));
357 DBG_RW(("\tstarting at offset Ox%lX of file, length Ox%lX\n", (UInt32
)uio
->uio_offset
, (UInt32
)uio
->uio_resid
));
359 DBG_VOP_LOCKS_INIT(0,ap
->a_vp
, VOPDBG_LOCKED
, VOPDBG_LOCKED
, VOPDBG_LOCKED
, VOPDBG_POS
);
361 dev
= hp
->h_meta
->h_devvp
;
364 debug_check_blocksizes(vp
);
367 if (uio
->uio_offset
< 0) {
368 DBG_VOP_LOCKS_TEST(EINVAL
);
372 if (uio
->uio_resid
== 0) {
373 DBG_VOP_LOCKS_TEST(E_NONE
);
377 if (ap
->a_vp
->v_type
!= VREG
&& ap
->a_vp
->v_type
!= VLNK
) { /* Can only write files */
378 DBG_VOP_LOCKS_TEST(EISDIR
);
383 if (uio
->uio_rw
!= UIO_WRITE
)
384 panic("%s: mode", funcname
);
387 ioflag
= ap
->a_ioflag
;
391 if (ioflag
& IO_APPEND
) uio
->uio_offset
= fcb
->fcbEOF
;
392 if ((hp
->h_meta
->h_pflags
& APPEND
) && uio
->uio_offset
!= fcb
->fcbEOF
)
395 writelimit
= uio
->uio_offset
+ uio
->uio_resid
;
398 * Maybe this should be above the vnode op call, but so long as
399 * file servers have no limits, I don't think it matters.
402 if (vp
->v_type
== VREG
&& p
&&
403 writelimit
> p
->p_rlimit
[RLIMIT_FSIZE
].rlim_cur
) {
407 VOP_DEVBLOCKSIZE(hp
->h_meta
->h_devvp
, &devBlockSize
);
409 resid
= uio
->uio_resid
;
410 origFileSize
= fcb
->fcbEOF
;
411 flags
= ioflag
& IO_SYNC
? B_SYNC
: 0;
413 DBG_RW(("\tLEOF is 0x%lX, PEOF is 0x%lX.\n", fcb
->fcbEOF
, fcb
->fcbPLen
));
416 NOTE: In the following loop there are two positions tracked:
417 currOffset is the current I/O starting offset. currOffset is never >LEOF; the
418 LEOF is nudged along with currOffset as data is zeroed or written.
419 uio->uio_offset is the start of the current I/O operation. It may be arbitrarily
422 The following is true at all times:
424 currOffset <= LEOF <= uio->uio_offset <= writelimit
426 currOffset
= MIN(uio
->uio_offset
, fcb
->fcbEOF
);
428 DBG_RW(("\tstarting I/O loop at 0x%lX.\n", (u_long
)currOffset
));
432 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 0)) | DBG_FUNC_START
,
433 (int)uio
->uio_offset
, uio
->uio_resid
, (int)fcb
->fcbEOF
, (int)fcb
->fcbPLen
, 0);
436 /* Now test if we need to extend the file */
437 /* Doing so will adjust the fcbPLen for us */
439 while (writelimit
> (off_t
)fcb
->fcbPLen
) {
441 bytesToAdd
= writelimit
- fcb
->fcbPLen
;
442 DBG_RW(("\textending file by 0x%lX bytes; 0x%lX blocks free",
443 (unsigned long)bytesToAdd
, (unsigned long)vcb
->freeBlocks
));
445 /* lock extents b-tree (also protects volume bitmap) */
446 retval
= hfs_metafilelocking(HTOHFS(hp
), kHFSExtentsFileID
, LK_EXCLUSIVE
, cp
);
447 if (retval
!= E_NONE
)
450 retval
= MacToVFSError(
458 (void) hfs_metafilelocking(HTOHFS(hp
), kHFSExtentsFileID
, LK_RELEASE
, cp
);
459 DBG_VOP_CONT(("\tactual bytes added = 0x%lX bytes, retval = %d...\n", actualBytesAdded
, retval
));
460 if ((actualBytesAdded
== 0) && (retval
== E_NONE
)) retval
= ENOSPC
;
461 if (retval
!= E_NONE
) break;
463 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 0)) | DBG_FUNC_NONE
,
464 (int)uio
->uio_offset
, uio
->uio_resid
, (int)fcb
->fcbEOF
, (int)fcb
->fcbPLen
, 0);
467 if (UBCISVALID(vp
) && retval
== E_NONE
) {
473 off_t io_start
, io_end
;
475 struct rl_entry
*invalid_range
;
477 if (writelimit
> fcb
->fcbEOF
)
478 filesize
= writelimit
;
480 filesize
= fcb
->fcbEOF
;
482 lflag
= (ioflag
& IO_SYNC
);
484 if (uio
->uio_offset
<= fcb
->fcbEOF
) {
485 zero_off
= uio
->uio_offset
& ~PAGE_MASK_64
;
487 /* Check to see whether the area between the zero_offset and the start
488 of the transfer to see whether is invalid and should be zero-filled
489 as part of the transfer:
491 if (rl_scan(&hp
->h_invalidranges
, zero_off
, uio
->uio_offset
- 1, &invalid_range
) != RL_NOOVERLAP
) {
492 lflag
|= IO_HEADZEROFILL
;
495 off_t eof_page_base
= fcb
->fcbEOF
& ~PAGE_MASK_64
;
497 /* The bytes between fcb->fcbEOF and uio->uio_offset must never be
498 read without being zeroed. The current last block is filled with zeroes
499 if it holds valid data but in all cases merely do a little bookkeeping
500 to track the area from the end of the current last page to the start of
501 the area actually written. For the same reason only the bytes up to the
502 start of the page where this write will start is invalidated; any remainder
503 before uio->uio_offset is explicitly zeroed as part of the cluster_write.
505 Note that inval_start, the start of the page after the current EOF,
506 may be past the start of the write, in which case the zeroing
507 will be handled by the cluser_write of the actual data.
509 inval_start
= (fcb
->fcbEOF
+ (PAGE_SIZE_64
- 1)) & ~PAGE_MASK_64
;
510 inval_end
= uio
->uio_offset
& ~PAGE_MASK_64
;
511 zero_off
= fcb
->fcbEOF
;
513 if ((fcb
->fcbEOF
& PAGE_MASK_64
) &&
514 (rl_scan(&hp
->h_invalidranges
,
517 &invalid_range
) != RL_NOOVERLAP
)) {
518 /* The page containing the EOF is not valid, so the
519 entire page must be made inaccessible now. If the write
520 starts on a page beyond the page containing the eof
521 (inval_end > eof_page_base), add the
522 whole page to the range to be invalidated. Otherwise
523 (i.e. if the write starts on the same page), zero-fill
524 the entire page explicitly now:
526 if (inval_end
> eof_page_base
) {
527 inval_start
= eof_page_base
;
529 zero_off
= eof_page_base
;
533 if (inval_start
< inval_end
) {
534 /* There's some range of data that's going to be marked invalid */
536 if (zero_off
< inval_start
) {
537 /* The pages between inval_start and inval_end are going to be invalidated,
538 and the actual write will start on a page past inval_end. Now's the last
539 chance to zero-fill the page containing the EOF:
541 retval
= cluster_write(vp
, (struct uio
*) 0, fcb
->fcbEOF
, inval_start
,
542 zero_off
, (off_t
)0, devBlockSize
, lflag
| IO_HEADZEROFILL
);
543 if (retval
) goto ioerr_exit
;
546 /* Mark the remaining area of the newly allocated space as invalid: */
547 rl_add(inval_start
, inval_end
- 1 , &hp
->h_invalidranges
);
548 zero_off
= fcb
->fcbEOF
= inval_end
;
551 if (uio
->uio_offset
> zero_off
) lflag
|= IO_HEADZEROFILL
;
554 /* Check to see whether the area between the end of the write and the end of
555 the page it falls in is invalid and should be zero-filled as part of the transfer:
557 tail_off
= (writelimit
+ (PAGE_SIZE_64
- 1)) & ~PAGE_MASK_64
;
558 if (tail_off
> filesize
) tail_off
= filesize
;
559 if (tail_off
> writelimit
) {
560 if (rl_scan(&hp
->h_invalidranges
, writelimit
, tail_off
- 1, &invalid_range
) != RL_NOOVERLAP
) {
561 lflag
|= IO_TAILZEROFILL
;
566 * if the write starts beyond the current EOF (possibly advanced in the
567 * zeroing of the last block, above), then we'll zero fill from the current EOF
568 * to where the write begins:
570 * NOTE: If (and ONLY if) the portion of the file about to be written is
571 * before the current EOF it might be marked as invalid now and must be
572 * made readable (removed from the invalid ranges) before cluster_write
575 io_start
= (lflag
& IO_HEADZEROFILL
) ? zero_off
: uio
->uio_offset
;
576 io_end
= (lflag
& IO_TAILZEROFILL
) ? tail_off
: writelimit
;
577 if (io_start
< fcb
->fcbEOF
) {
578 rl_remove(io_start
, io_end
- 1, &hp
->h_invalidranges
);
580 retval
= cluster_write(vp
, uio
, fcb
->fcbEOF
, filesize
, zero_off
, tail_off
, devBlockSize
, lflag
);
582 if (uio
->uio_offset
> fcb
->fcbEOF
) {
583 fcb
->fcbEOF
= uio
->uio_offset
;
585 ubc_setsize(vp
, (off_t
)fcb
->fcbEOF
); /* XXX check errors */
587 if (resid
> uio
->uio_resid
) hp
->h_nodeflags
|= IN_CHANGE
| IN_UPDATE
;
591 while (retval
== E_NONE
&& uio
->uio_resid
> 0) {
592 logBlockNo
= currOffset
/ PAGE_SIZE
;
593 blkoffset
= currOffset
& PAGE_MASK
;
595 if (((off_t
)(fcb
->fcbPLen
) - currOffset
) < PAGE_SIZE_64
)
596 fragSize
= (off_t
)(fcb
->fcbPLen
) - ((off_t
)logBlockNo
* PAGE_SIZE_64
);
598 fragSize
= PAGE_SIZE
;
599 xfersize
= fragSize
- blkoffset
;
601 DBG_RW(("\tcurrOffset = Ox%lX, logBlockNo = Ox%X, blkoffset = Ox%lX, xfersize = Ox%lX, fragSize = Ox%lX.\n",
602 (unsigned long)currOffset
, logBlockNo
, blkoffset
, xfersize
, fragSize
));
604 /* Make any adjustments for boundary conditions */
605 if (currOffset
+ (off_t
)xfersize
> writelimit
) {
606 xfersize
= writelimit
- currOffset
;
607 DBG_RW(("\ttrimming xfersize to 0x%lX to match writelimit (uio_resid)...\n", xfersize
));
611 * There is no need to read into bp if:
612 * We start on a block boundary and will overwrite the whole block
616 if ((blkoffset
== 0) && (xfersize
>= fragSize
)) {
617 DBG_RW(("\tRequesting %ld-byte block Ox%lX w/o read...\n", fragSize
, (long)logBlockNo
));
619 bp
= getblk(vp
, logBlockNo
, fragSize
, 0, 0, BLK_READ
);
622 if (bp
->b_blkno
== -1) {
624 retval
= EIO
; /* XXX */
629 if (currOffset
== fcb
->fcbEOF
&& blkoffset
== 0) {
630 bp
= getblk(vp
, logBlockNo
, fragSize
, 0, 0, BLK_READ
);
633 if (bp
->b_blkno
== -1) {
635 retval
= EIO
; /* XXX */
641 * This I/O transfer is not sufficiently aligned, so read the affected block into a buffer:
643 DBG_VOP(("\tRequesting block Ox%X, size = 0x%08lX...\n", logBlockNo
, fragSize
));
644 retval
= bread(vp
, logBlockNo
, fragSize
, ap
->a_cred
, &bp
);
646 if (retval
!= E_NONE
) {
654 /* See if we are starting to write within file boundaries:
655 If not, then we need to present a "hole" for the area between
656 the current EOF and the start of the current I/O operation:
658 Note that currOffset is only less than uio_offset if uio_offset > LEOF...
660 if (uio
->uio_offset
> currOffset
) {
661 clearSize
= MIN(uio
->uio_offset
- currOffset
, xfersize
);
662 DBG_RW(("\tzeroing Ox%lX bytes Ox%lX bytes into block Ox%X...\n", clearSize
, blkoffset
, logBlockNo
));
663 bzero(bp
->b_data
+ blkoffset
, clearSize
);
664 currOffset
+= clearSize
;
665 blkoffset
+= clearSize
;
666 xfersize
-= clearSize
;
670 DBG_RW(("\tCopying Ox%lX bytes Ox%lX bytes into block Ox%X... ioflag == 0x%X\n",
671 xfersize
, blkoffset
, logBlockNo
, ioflag
));
672 retval
= uiomove((caddr_t
)bp
->b_data
+ blkoffset
, (int)xfersize
, uio
);
673 currOffset
+= xfersize
;
675 DBG_ASSERT((bp
->b_bcount
% devBlockSize
) == 0);
677 if (ioflag
& IO_SYNC
) {
678 (void)VOP_BWRITE(bp
);
679 //DBG_RW(("\tissuing bwrite\n"));
680 } else if ((xfersize
+ blkoffset
) == fragSize
) {
681 //DBG_RW(("\tissuing bawrite\n"));
682 bp
->b_flags
|= B_AGE
;
685 //DBG_RW(("\tissuing bdwrite\n"));
689 /* Update the EOF if we just extended the file
690 (the PEOF has already been moved out and the block mapping table has been updated): */
691 if (currOffset
> fcb
->fcbEOF
) {
692 DBG_VOP(("\textending EOF to 0x%lX...\n", (UInt32
)fcb
->fcbEOF
));
693 fcb
->fcbEOF
= currOffset
;
696 ubc_setsize(vp
, (off_t
)fcb
->fcbEOF
); /* XXX check errors */
699 if (retval
|| (resid
== 0))
701 hp
->h_nodeflags
|= IN_CHANGE
| IN_UPDATE
;
707 * If we successfully wrote any data, and we are not the superuser
708 * we clear the setuid and setgid bits as a precaution against
711 if (resid
> uio
->uio_resid
&& ap
->a_cred
&& ap
->a_cred
->cr_uid
!= 0)
712 hp
->h_meta
->h_mode
&= ~(ISUID
| ISGID
);
715 if (ioflag
& IO_UNIT
) {
716 (void)VOP_TRUNCATE(vp
, origFileSize
,
717 ioflag
& IO_SYNC
, ap
->a_cred
, uio
->uio_procp
);
718 uio
->uio_offset
-= resid
- uio
->uio_resid
;
719 uio
->uio_resid
= resid
;
721 } else if (resid
> uio
->uio_resid
&& (ioflag
& IO_SYNC
)) {
723 retval
= VOP_UPDATE(vp
, &tv
, &tv
, 1);
727 debug_check_blocksizes(vp
);
730 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 0)) | DBG_FUNC_END
,
731 (int)uio
->uio_offset
, uio
->uio_resid
, (int)fcb
->fcbEOF
, (int)fcb
->fcbPLen
, 0);
733 DBG_VOP_LOCKS_TEST(retval
);
747 IN struct ucred *cred;
756 struct vop_ioctl_args
/* {
761 struct ucred *a_cred;
765 DBG_FUNC_NAME("hfs_ioctl");
766 DBG_VOP_LOCKS_DECL(1);
767 DBG_VOP_PRINT_FUNCNAME();
768 DBG_VOP_PRINT_VNODE_INFO(ap
->a_vp
);DBG_VOP_CONT(("\n"));
770 DBG_VOP_LOCKS_INIT(0,ap
->a_vp
, VOPDBG_UNLOCKED
, VOPDBG_UNLOCKED
, VOPDBG_UNLOCKED
, VOPDBG_POS
);
772 switch (ap
->a_command
) {
775 { register struct hfsnode
*hp
;
776 register struct vnode
*vp
;
777 register struct radvisory
*ra
;
779 int devBlockSize
= 0;
784 VOP_LEASE(vp
, ap
->a_p
, ap
->a_cred
, LEASE_READ
);
785 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, ap
->a_p
);
787 ra
= (struct radvisory
*)(ap
->a_data
);
792 if (ra
->ra_offset
>= fcb
->fcbEOF
) {
793 VOP_UNLOCK(vp
, 0, ap
->a_p
);
794 DBG_VOP_LOCKS_TEST(EFBIG
);
797 VOP_DEVBLOCKSIZE(hp
->h_meta
->h_devvp
, &devBlockSize
);
799 error
= advisory_read(vp
, fcb
->fcbEOF
, ra
->ra_offset
, ra
->ra_count
, devBlockSize
);
800 VOP_UNLOCK(vp
, 0, ap
->a_p
);
802 DBG_VOP_LOCKS_TEST(error
);
806 case 2: /* F_READBOOTBLOCKS */
807 case 3: /* F_WRITEBOOTBLOCKS */
809 struct vnode
*vp
= ap
->a_vp
;
810 struct hfsnode
*hp
= VTOH(vp
);
811 struct fbootstraptransfer
*btd
= (struct fbootstraptransfer
*)ap
->a_data
;
821 if ((vp
->v_flag
& VROOT
) == 0) return EINVAL
;
822 if (btd
->fbt_offset
+ btd
->fbt_length
> 1024) return EINVAL
;
824 aiov
.iov_base
= btd
->fbt_buffer
;
825 aiov
.iov_len
= btd
->fbt_length
;
827 auio
.uio_iov
= &aiov
;
829 auio
.uio_offset
= btd
->fbt_offset
;
830 auio
.uio_resid
= btd
->fbt_length
;
831 auio
.uio_segflg
= UIO_USERSPACE
;
832 auio
.uio_rw
= (ap
->a_command
== 3) ? UIO_WRITE
: UIO_READ
; /* F_WRITEBOOTSTRAP / F_READBOOTSTRAP */
833 auio
.uio_procp
= ap
->a_p
;
835 VOP_DEVBLOCKSIZE(hp
->h_meta
->h_devvp
, &devBlockSize
);
837 while (auio
.uio_resid
> 0) {
838 blockNumber
= auio
.uio_offset
/ devBlockSize
;
839 error
= bread(hp
->h_meta
->h_devvp
, blockNumber
, devBlockSize
, ap
->a_cred
, &bp
);
845 blockOffset
= auio
.uio_offset
% devBlockSize
;
846 xfersize
= devBlockSize
- blockOffset
;
847 error
= uiomove((caddr_t
)bp
->b_data
+ blockOffset
, (int)xfersize
, &auio
);
852 if (auio
.uio_rw
== UIO_WRITE
) {
853 error
= VOP_BWRITE(bp
);
854 if (error
) return error
;
862 case _IOC(IOC_OUT
,'h', 4, 0): /* Create date in local time */
864 *(time_t *)(ap
->a_data
) = to_bsd_time(VTOVCB(ap
->a_vp
)->localCreateDate
);
869 DBG_VOP_LOCKS_TEST(ENOTTY
);
873 /* Should never get here */
880 struct vop_select_args
/* {
884 struct ucred *a_cred;
889 DBG_FUNC_NAME("hfs_select");
890 DBG_VOP_LOCKS_DECL(1);
891 DBG_VOP_PRINT_FUNCNAME();
892 DBG_VOP_PRINT_VNODE_INFO(ap
->a_vp
);DBG_VOP_CONT(("\n"));
894 DBG_VOP_LOCKS_INIT(0,ap
->a_vp
, VOPDBG_LOCKED
, VOPDBG_IGNORE
, VOPDBG_IGNORE
, VOPDBG_POS
);
897 * We should really check to see if I/O is possible.
899 DBG_VOP_LOCKS_TEST(1);
908 * NB Currently unsupported.
914 IN struct ucred *cred;
923 struct vop_mmap_args
/* {
926 struct ucred *a_cred;
930 DBG_FUNC_NAME("hfs_mmap");
931 DBG_VOP_LOCKS_DECL(1);
932 DBG_VOP_PRINT_FUNCNAME();
933 DBG_VOP_PRINT_VNODE_INFO(ap
->a_vp
);DBG_VOP_CONT(("\n"));
935 DBG_VOP_LOCKS_INIT(0,ap
->a_vp
, VOPDBG_IGNORE
, VOPDBG_IGNORE
, VOPDBG_IGNORE
, VOPDBG_POS
);
937 DBG_VOP_LOCKS_TEST(EINVAL
);
946 * Nothing to do, so just return.
948 # Needs work: Is newoff right? What's it mean?
954 IN struct ucred *cred;
959 struct vop_seek_args
/* {
963 struct ucred *a_cred;
966 DBG_FUNC_NAME("hfs_seek");
967 DBG_VOP_LOCKS_DECL(1);
968 DBG_VOP_PRINT_FUNCNAME();
969 DBG_VOP_PRINT_VNODE_INFO(ap
->a_vp
);DBG_VOP_CONT(("\n"));
971 DBG_VOP_LOCKS_INIT(0,ap
->a_vp
, VOPDBG_IGNORE
, VOPDBG_IGNORE
, VOPDBG_IGNORE
, VOPDBG_POS
);
973 DBG_VOP_LOCKS_TEST(E_NONE
);
979 * Bmap converts a the logical block number of a file to its physical block
980 * number on the disk.
984 * vp - address of vnode file the file
985 * bn - which logical block to convert to a physical block number.
986 * vpp - returns the vnode for the block special file holding the filesystem
987 * containing the file of interest
988 * bnp - address of where to return the filesystem physical block number
995 OUT struct vnode **vpp;
1000 * Converts a logical block number to a physical block, and optionally returns
1001 * the amount of remaining blocks in a run. The logical block is based on hfsNode.logBlockSize.
1002 * The physical block number is based on the device block size, currently its 512.
1003 * The block run is returned in logical blocks, and is the REMAINING amount of blocks
1008 struct vop_bmap_args
/* {
1011 struct vnode **a_vpp;
1016 struct hfsnode
*hp
= VTOH(ap
->a_vp
);
1017 struct hfsmount
*hfsmp
= VTOHFS(ap
->a_vp
);
1018 int retval
= E_NONE
;
1019 daddr_t logBlockSize
;
1020 size_t bytesContAvail
= 0;
1021 off_t blockposition
;
1022 struct proc
*p
= NULL
;
1024 struct rl_entry
*invalid_range
;
1025 enum rl_overlaptype overlaptype
;
1027 #define DEBUG_BMAP 0
1029 DBG_FUNC_NAME("hfs_bmap");
1030 DBG_VOP_LOCKS_DECL(2);
1031 DBG_VOP_PRINT_FUNCNAME();
1032 DBG_VOP_PRINT_VNODE_INFO(ap
->a_vp
);
1034 DBG_VOP_LOCKS_INIT(0,ap
->a_vp
, VOPDBG_LOCKED
, VOPDBG_LOCKED
, VOPDBG_LOCKED
, VOPDBG_POS
);
1035 if (ap
->a_vpp
!= NULL
) {
1036 DBG_VOP_LOCKS_INIT(1,*ap
->a_vpp
, VOPDBG_IGNORE
, VOPDBG_UNLOCKED
, VOPDBG_IGNORE
, VOPDBG_POS
);
1038 DBG_VOP_LOCKS_INIT(1,NULL
, VOPDBG_IGNORE
, VOPDBG_IGNORE
, VOPDBG_IGNORE
, VOPDBG_POS
);
1042 DBG_IO(("\tMapped blk %d --> ", ap
->a_bn
));
1044 * Check for underlying vnode requests and ensure that logical
1045 * to physical mapping is requested.
1047 if (ap
->a_vpp
!= NULL
)
1048 *ap
->a_vpp
= VTOH(ap
->a_vp
)->h_meta
->h_devvp
;
1049 if (ap
->a_bnp
== NULL
)
1052 logBlockSize
= GetLogicalBlockSize(ap
->a_vp
);
1053 blockposition
= (off_t
)(ap
->a_bn
* logBlockSize
);
1055 lockExtBtree
= hasOverflowExtents(hp
);
1059 retval
= hfs_metafilelocking(hfsmp
, kHFSExtentsFileID
, LK_EXCLUSIVE
| LK_CANRECURSE
, p
);
1064 retval
= MacToVFSError(
1065 MapFileBlockC (HFSTOVCB(hfsmp
),
1072 if (lockExtBtree
) (void) hfs_metafilelocking(hfsmp
, kHFSExtentsFileID
, LK_RELEASE
, p
);
1074 if (retval
== E_NONE
) {
1075 /* Adjust the mapping information for invalid file ranges: */
1076 overlaptype
= rl_scan(&hp
->h_invalidranges
,
1078 blockposition
+ MAXPHYSIO
- 1,
1080 if (overlaptype
!= RL_NOOVERLAP
) {
1081 switch(overlaptype
) {
1082 case RL_MATCHINGOVERLAP
:
1083 case RL_OVERLAPCONTAINSRANGE
:
1084 case RL_OVERLAPSTARTSBEFORE
:
1085 /* There's no valid block for this byte offset: */
1086 *ap
->a_bnp
= (daddr_t
)-1;
1087 bytesContAvail
= invalid_range
->rl_end
+ 1 - blockposition
;
1090 case RL_OVERLAPISCONTAINED
:
1091 case RL_OVERLAPENDSAFTER
:
1092 /* The range of interest hits an invalid block before the end: */
1093 if (invalid_range
->rl_start
== blockposition
) {
1094 /* There's actually no valid information to be had starting here: */
1095 *ap
->a_bnp
= (daddr_t
)-1;
1096 if ((HTOFCB(hp
)->fcbEOF
> (invalid_range
->rl_end
+ 1)) &&
1097 (invalid_range
->rl_end
+ 1 - blockposition
< bytesContAvail
)) {
1098 bytesContAvail
= invalid_range
->rl_end
+ 1 - blockposition
;
1101 bytesContAvail
= invalid_range
->rl_start
- blockposition
;
1105 if (bytesContAvail
> MAXPHYSIO
) bytesContAvail
= MAXPHYSIO
;
1108 /* Figure out how many read ahead blocks there are */
1109 if (ap
->a_runp
!= NULL
) {
1110 if (can_cluster(logBlockSize
)) {
1111 /* Make sure this result never goes negative: */
1112 *ap
->a_runp
= (bytesContAvail
< logBlockSize
) ? 0 : (bytesContAvail
/ logBlockSize
) - 1;
1119 DBG_IO(("%d:%d.\n", *ap
->a_bnp
, (bytesContAvail
< logBlockSize
) ? 0 : (bytesContAvail
/ logBlockSize
) - 1));
1123 DBG_VOP_LOCKS_TEST(retval
);
1127 DBG_ASSERT((*ap
->a_runp
* logBlockSize
) < bytesContAvail
); /* At least *ap->a_runp blocks left and ... */
1128 if (can_cluster(logBlockSize
)) {
1129 DBG_ASSERT(bytesContAvail
- (*ap
->a_runp
* logBlockSize
) < (2*logBlockSize
)); /* ... at most 1 logical block accounted for by current block */
1130 /* ... plus some sub-logical block sized piece */
1137 /* blktooff converts logical block number to file offset */
1141 struct vop_blktooff_args
/* {
1147 if (ap
->a_vp
== NULL
)
1149 *ap
->a_offset
= (off_t
)ap
->a_lblkno
* PAGE_SIZE_64
;
1156 struct vop_offtoblk_args
/* {
1164 if (ap
->a_vp
== NULL
)
1166 *ap
->a_lblkno
= ap
->a_offset
/ PAGE_SIZE_64
;
1173 struct vop_cmap_args
/* {
1182 struct hfsnode
*hp
= VTOH(ap
->a_vp
);
1183 struct hfsmount
*hfsmp
= VTOHFS(ap
->a_vp
);
1184 FCB
*fcb
= HTOFCB(hp
);
1185 size_t bytesContAvail
= 0;
1186 int retval
= E_NONE
;
1188 struct proc
*p
= NULL
;
1189 struct rl_entry
*invalid_range
;
1190 enum rl_overlaptype overlaptype
;
1193 #define DEBUG_CMAP 0
1195 DBG_FUNC_NAME("hfs_cmap");
1196 DBG_VOP_LOCKS_DECL(2);
1197 DBG_VOP_PRINT_FUNCNAME();
1198 DBG_VOP_PRINT_VNODE_INFO(ap
->a_vp
);
1200 DBG_VOP_LOCKS_INIT(0, ap
->a_vp
, VOPDBG_LOCKED
, VOPDBG_LOCKED
, VOPDBG_LOCKED
, VOPDBG_POS
);
1203 DBG_IO(("\tMapped offset %qx --> ", ap
->a_foffset
));
1205 * Check for underlying vnode requests and ensure that logical
1206 * to physical mapping is requested.
1208 if (ap
->a_bpn
== NULL
) {
1212 if (lockExtBtree
= hasOverflowExtents(hp
))
1215 if (retval
= hfs_metafilelocking(hfsmp
, kHFSExtentsFileID
, LK_EXCLUSIVE
| LK_CANRECURSE
, p
)) {
1219 retval
= MacToVFSError(
1220 MapFileBlockC (HFSTOVCB(hfsmp
),
1227 if (lockExtBtree
) (void) hfs_metafilelocking(hfsmp
, kHFSExtentsFileID
, LK_RELEASE
, p
);
1229 if (retval
== E_NONE
) {
1230 /* Adjust the mapping information for invalid file ranges: */
1231 overlaptype
= rl_scan(&hp
->h_invalidranges
,
1233 ap
->a_foffset
+ (off_t
)bytesContAvail
- 1,
1235 if (overlaptype
!= RL_NOOVERLAP
) {
1236 switch(overlaptype
) {
1237 case RL_MATCHINGOVERLAP
:
1238 case RL_OVERLAPCONTAINSRANGE
:
1239 case RL_OVERLAPSTARTSBEFORE
:
1240 /* There's no valid block for this byte offset: */
1241 *ap
->a_bpn
= (daddr_t
)-1;
1243 /* There's no point limiting the amount to be returned if the
1244 invalid range that was hit extends all the way to the EOF
1245 (i.e. there's no valid bytes between the end of this range
1246 and the file's EOF):
1248 if ((fcb
->fcbEOF
> (invalid_range
->rl_end
+ 1)) &&
1249 (invalid_range
->rl_end
+ 1 - ap
->a_foffset
< bytesContAvail
)) {
1250 bytesContAvail
= invalid_range
->rl_end
+ 1 - ap
->a_foffset
;
1254 case RL_OVERLAPISCONTAINED
:
1255 case RL_OVERLAPENDSAFTER
:
1256 /* The range of interest hits an invalid block before the end: */
1257 if (invalid_range
->rl_start
== ap
->a_foffset
) {
1258 /* There's actually no valid information to be had starting here: */
1259 *ap
->a_bpn
= (daddr_t
)-1;
1260 if ((fcb
->fcbEOF
> (invalid_range
->rl_end
+ 1)) &&
1261 (invalid_range
->rl_end
+ 1 - ap
->a_foffset
< bytesContAvail
)) {
1262 bytesContAvail
= invalid_range
->rl_end
+ 1 - ap
->a_foffset
;
1265 bytesContAvail
= invalid_range
->rl_start
- ap
->a_foffset
;
1269 if (bytesContAvail
> ap
->a_size
) bytesContAvail
= ap
->a_size
;
1272 if (ap
->a_run
) *ap
->a_run
= bytesContAvail
;
1275 if (ap
->a_poff
) *(int *)ap
->a_poff
= 0;
1277 DBG_IO(("%d:%d.\n", *ap
->a_bpn
, bytesContAvail
));
1281 DBG_VOP_LOCKS_TEST(retval
);
1289 * Calculate the logical to physical mapping if not done already,
1290 * then call the device strategy routine.
1293 # IN struct buf *bp;
1297 struct vop_strategy_args
/* {
1301 register struct buf
*bp
= ap
->a_bp
;
1302 register struct vnode
*vp
= bp
->b_vp
;
1303 register struct hfsnode
*hp
;
1306 DBG_FUNC_NAME("hfs_strategy");
1308 // DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT(("\n"));
1312 if ( !(bp
->b_flags
& B_VECTORLIST
)) {
1314 if (vp
->v_type
== VBLK
|| vp
->v_type
== VCHR
)
1315 panic("hfs_strategy: device vnode passed!");
1317 if (bp
->b_flags
& B_PAGELIST
) {
1319 * if we have a page list associated with this bp,
1320 * then go through cluster_bp since it knows how to
1321 * deal with a page request that might span non-contiguous
1322 * physical blocks on the disk...
1324 retval
= cluster_bp(bp
);
1325 vp
= hp
->h_meta
->h_devvp
;
1326 bp
->b_dev
= vp
->v_rdev
;
1331 * If we don't already know the filesystem relative block number
1332 * then get it using VOP_BMAP(). If VOP_BMAP() returns the block
1333 * number as -1 then we've got a hole in the file. Although HFS
1334 * filesystems don't create files with holes, invalidating of
1335 * subranges of the file (lazy zero filling) may create such a
1338 if (bp
->b_blkno
== bp
->b_lblkno
) {
1339 if ((retval
= VOP_BMAP(vp
, bp
->b_lblkno
, NULL
, &bp
->b_blkno
, NULL
))) {
1340 bp
->b_error
= retval
;
1341 bp
->b_flags
|= B_ERROR
;
1345 if ((long)bp
->b_blkno
== -1)
1348 if ((long)bp
->b_blkno
== -1) {
1352 if (bp
->b_validend
== 0) {
1353 /* Record the exact size of the I/O transfer about to be made: */
1354 DBG_ASSERT(bp
->b_validoff
== 0);
1355 bp
->b_validend
= bp
->b_bcount
;
1356 DBG_ASSERT(bp
->b_dirtyoff
== 0);
1359 vp
= hp
->h_meta
->h_devvp
;
1360 bp
->b_dev
= vp
->v_rdev
;
1361 DBG_IO(("\t\t>>>%s: continuing w/ vp: 0x%x with logBlk Ox%X and phyBlk Ox%X\n", funcname
, (u_int
)vp
, bp
->b_lblkno
, bp
->b_blkno
));
1363 return VOCALL (vp
->v_op
, VOFFSET(vop_strategy
), ap
);
1368 #% reallocblks vp L L L
1371 IN struct vnode *vp;
1372 IN struct cluster_save *buflist;
1378 struct vop_reallocblks_args
/* {
1380 struct cluster_save *a_buflist;
1383 DBG_FUNC_NAME("hfs_reallocblks");
1384 DBG_VOP_LOCKS_DECL(1);
1385 DBG_VOP_PRINT_FUNCNAME();
1386 DBG_VOP_PRINT_VNODE_INFO(ap
->a_vp
);DBG_VOP_CONT(("\n"));
1388 DBG_VOP_LOCKS_INIT(0,ap
->a_vp
, VOPDBG_LOCKED
, VOPDBG_LOCKED
, VOPDBG_LOCKED
, VOPDBG_POS
);
1390 /* Currently no support for clustering */ /* XXX */
1391 DBG_VOP_LOCKS_TEST(ENOSPC
);
1399 #% truncate vp L L L
1402 IN struct vnode *vp;
1404 IN int flags; (IO_SYNC)
1405 IN struct ucred *cred;
1408 * Truncate the hfsnode hp to at most length size, freeing (or adding) the
1411 int hfs_truncate(ap
)
1412 struct vop_truncate_args
/* {
1416 struct ucred *a_cred;
1420 register struct vnode
*vp
= ap
->a_vp
;
1421 register struct hfsnode
*hp
= VTOH(vp
);
1422 off_t length
= ap
->a_length
;
1428 off_t actualBytesAdded
;
1429 DBG_FUNC_NAME("hfs_truncate");
1430 DBG_VOP_LOCKS_DECL(1);
1431 DBG_VOP_PRINT_FUNCNAME();
1432 DBG_VOP_PRINT_VNODE_INFO(ap
->a_vp
);DBG_VOP_CONT(("\n"));
1433 DBG_VOP_LOCKS_INIT(0,ap
->a_vp
, VOPDBG_LOCKED
, VOPDBG_LOCKED
, VOPDBG_LOCKED
, VOPDBG_POS
);
1436 debug_check_blocksizes(ap
->a_vp
);
1441 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 7)) | DBG_FUNC_START
,
1442 (int)length
, fcb
->fcbEOF
, fcb
->fcbPLen
, 0, 0);
1445 DBG_VOP_LOCKS_TEST(EINVAL
);
1449 if ((!ISHFSPLUS(VTOVCB(vp
))) && (length
> (off_t
)MAXHFSFILESIZE
)) {
1450 DBG_VOP_LOCKS_TEST(EFBIG
);
1454 if (vp
->v_type
!= VREG
&& vp
->v_type
!= VLNK
) {
1455 DBG_VOP_LOCKS_TEST(EISDIR
);
1456 return (EISDIR
); /* hfs doesn't support truncating of directories */
1462 DBG_RW(("%s: truncate from Ox%lX to Ox%X bytes\n", funcname
, fcb
->fcbPLen
, length
));
1465 * we cannot just check if fcb->fcbEOF == length (as an optimization)
1466 * since there may be extra physical blocks that also need truncation
1470 * Lengthen the size of the file. We must ensure that the
1471 * last byte of the file is allocated. Since the smallest
1472 * value of fcbEOF is 0, length will be at least 1.
1474 if (length
> fcb
->fcbEOF
) {
1481 struct buf
*bp
=NULL
;
1484 * If we don't have enough physical space then
1485 * we need to extend the physical size.
1487 if (length
> fcb
->fcbPLen
) {
1488 /* lock extents b-tree (also protects volume bitmap) */
1489 retval
= hfs_metafilelocking(HTOHFS(hp
), kHFSExtentsFileID
, LK_EXCLUSIVE
, ap
->a_p
);
1493 while ((length
> fcb
->fcbPLen
) && (retval
== E_NONE
)) {
1494 bytesToAdd
= length
- fcb
->fcbPLen
;
1495 retval
= MacToVFSError(
1496 ExtendFileC (HTOVCB(hp
),
1500 kEFAllMask
, /* allocate all requested bytes or none */
1501 &actualBytesAdded
));
1503 if (actualBytesAdded
== 0 && retval
== E_NONE
) {
1504 if (length
> fcb
->fcbPLen
)
1505 length
= fcb
->fcbPLen
;
1509 (void) hfs_metafilelocking(HTOHFS(hp
), kHFSExtentsFileID
, LK_RELEASE
, ap
->a_p
);
1513 DBG_ASSERT(length
<= fcb
->fcbPLen
);
1514 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 7)) | DBG_FUNC_NONE
,
1515 (int)length
, fcb
->fcbEOF
, fcb
->fcbPLen
, 0, 0);
1518 if (! (ap
->a_flags
& IO_NOZEROFILL
)) {
1520 if (UBCISVALID(vp
) && retval
== E_NONE
) {
1521 struct rl_entry
*invalid_range
;
1525 zero_limit
= (fcb
->fcbEOF
+ (PAGE_SIZE_64
- 1)) & ~PAGE_MASK_64
;
1526 if (length
< zero_limit
) zero_limit
= length
;
1528 if (length
> fcb
->fcbEOF
) {
1529 /* Extending the file: time to fill out the current last page w. zeroes? */
1530 if ((fcb
->fcbEOF
& PAGE_MASK_64
) &&
1531 (rl_scan(&hp
->h_invalidranges
,
1532 fcb
->fcbEOF
& ~PAGE_MASK_64
,
1534 &invalid_range
) == RL_NOOVERLAP
)) {
1536 /* There's some valid data at the start of the (current) last page
1537 of the file, so zero out the remainder of that page to ensure the
1538 entire page contains valid data. Since there is no invalid range
1539 possible past the (current) eof, there's no need to remove anything
1540 from the invalid range list before calling cluster_write(): */
1541 VOP_DEVBLOCKSIZE(hp
->h_meta
->h_devvp
, &devBlockSize
);
1542 retval
= cluster_write(vp
, (struct uio
*) 0, fcb
->fcbEOF
, zero_limit
,
1543 fcb
->fcbEOF
, (off_t
)0, devBlockSize
, (ap
->a_flags
& IO_SYNC
) | IO_HEADZEROFILL
);
1544 if (retval
) goto Err_Exit
;
1546 /* Merely invalidate the remaining area, if necessary: */
1547 if (length
> zero_limit
) rl_add(zero_limit
, length
- 1, &hp
->h_invalidranges
);
1549 /* The page containing the (current) eof is invalid: just add the
1550 remainder of the page to the invalid list, along with the area
1551 being newly allocated:
1553 rl_add(fcb
->fcbEOF
, length
- 1, &hp
->h_invalidranges
);
1560 * zero out any new logical space...
1562 bytestoclear
= length
- fcb
->fcbEOF
;
1563 filePosition
= fcb
->fcbEOF
;
1565 while (bytestoclear
> 0) {
1566 logBlockNo
= (daddr_t
)(filePosition
/ PAGE_SIZE_64
);
1567 blkOffset
= (long)(filePosition
& PAGE_MASK_64
);
1569 if (((off_t
)(fcb
->fcbPLen
) - ((off_t
)logBlockNo
* (off_t
)PAGE_SIZE
)) < PAGE_SIZE_64
)
1570 logBlockSize
= (off_t
)(fcb
->fcbPLen
) - ((off_t
)logBlockNo
* PAGE_SIZE_64
);
1572 logBlockSize
= PAGE_SIZE
;
1574 if (logBlockSize
< blkOffset
)
1575 panic("hfs_truncate: bad logBlockSize computed\n");
1577 blockZeroCount
= MIN(bytestoclear
, logBlockSize
- blkOffset
);
1579 if (blkOffset
== 0 && ((bytestoclear
>= logBlockSize
) || filePosition
>= fcb
->fcbEOF
)) {
1580 bp
= getblk(vp
, logBlockNo
, logBlockSize
, 0, 0, BLK_WRITE
);
1584 retval
= bread(vp
, logBlockNo
, logBlockSize
, ap
->a_cred
, &bp
);
1590 bzero((char *)bp
->b_data
+ blkOffset
, blockZeroCount
);
1592 bp
->b_flags
|= B_DIRTY
| B_AGE
;
1594 if (ap
->a_flags
& IO_SYNC
)
1596 else if (logBlockNo
% 32)
1599 VOP_BWRITE(bp
); /* wait after we issue 32 requests */
1601 bytestoclear
-= blockZeroCount
;
1602 filePosition
+= blockZeroCount
;
1605 panic("hfs_truncate: invoked on non-UBC object?!");
1609 fcb
->fcbEOF
= length
;
1612 ubc_setsize(vp
, (off_t
)fcb
->fcbEOF
); /* XXX check errors */
1614 } else { /* Shorten the size of the file */
1616 if (fcb
->fcbEOF
> length
) {
1618 * Any buffers that are past the truncation point need to be
1619 * invalidated (to maintain buffer cache consistency). For
1620 * simplicity, we invalidate all the buffers by calling vinvalbuf.
1623 ubc_setsize(vp
, (off_t
)length
); /* XXX check errors */
1625 vflags
= ((length
> 0) ? V_SAVE
: 0) | V_SAVEMETA
;
1626 retval
= vinvalbuf(vp
, vflags
, ap
->a_cred
, ap
->a_p
, 0, 0);
1628 /* Any space previously marked as invalid is now irrelevant: */
1629 rl_remove(length
, fcb
->fcbEOF
- 1, &hp
->h_invalidranges
);
1633 * For a TBE process the deallocation of the file blocks is
1634 * delayed until the file is closed. And hfs_close calls
1635 * truncate with the IO_NDELAY flag set. So when IO_NDELAY
1636 * isn't set, we make sure this isn't a TBE process.
1638 if ((ap
->a_flags
& IO_NDELAY
) || (!ISSET(ap
->a_p
->p_flag
, P_TBE
))) {
1640 /* lock extents b-tree (also protects volume bitmap) */
1641 retval
= hfs_metafilelocking(HTOHFS(hp
), kHFSExtentsFileID
, LK_EXCLUSIVE
, ap
->a_p
);
1644 retval
= MacToVFSError(
1650 (void) hfs_metafilelocking(HTOHFS(hp
), kHFSExtentsFileID
, LK_RELEASE
, ap
->a_p
);
1654 fcb
->fcbEOF
= length
;
1656 if (fcb
->fcbFlags
& fcbModifiedMask
)
1657 hp
->h_nodeflags
|= IN_MODIFIED
;
1659 hp
->h_nodeflags
|= IN_CHANGE
| IN_UPDATE
;
1660 retval
= VOP_UPDATE(vp
, &tv
, &tv
, MNT_WAIT
);
1662 DBG_ERR(("Could not update truncate"));
1663 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 7)) | DBG_FUNC_NONE
,
1664 -1, -1, -1, retval
, 0);
1669 debug_check_blocksizes(ap
->a_vp
);
1672 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 7)) | DBG_FUNC_END
,
1673 (int)length
, fcb
->fcbEOF
, fcb
->fcbPLen
, retval
, 0);
1675 DBG_VOP_LOCKS_TEST(retval
);
1683 #% allocate vp L L L
1686 IN struct vnode *vp;
1689 OUT off_t *bytesallocated;
1691 IN struct ucred *cred;
1694 * allocate the hfsnode hp to at most length size
1696 int hfs_allocate(ap
)
1697 struct vop_allocate_args
/* {
1701 off_t *a_bytesallocated;
1703 struct ucred *a_cred;
1707 register struct vnode
*vp
= ap
->a_vp
;
1708 register struct hfsnode
*hp
= VTOH(vp
);
1709 off_t length
= ap
->a_length
;
1711 off_t moreBytesRequested
;
1712 off_t actualBytesAdded
;
1715 int retval
, retval2
;
1718 UInt32 extendFlags
=0; /* For call to ExtendFileC */
1719 DBG_FUNC_NAME("hfs_allocate");
1720 DBG_VOP_LOCKS_DECL(1);
1721 DBG_VOP_PRINT_FUNCNAME();
1722 DBG_VOP_PRINT_VNODE_INFO(ap
->a_vp
);DBG_VOP_CONT(("\n"));
1723 DBG_VOP_LOCKS_INIT(0,ap
->a_vp
, VOPDBG_LOCKED
, VOPDBG_LOCKED
, VOPDBG_LOCKED
, VOPDBG_POS
);
1725 /* Set the number of bytes allocated to 0 so that the caller will know that we
1726 did nothing. ExtendFileC will fill this in for us if we actually allocate space */
1728 *(ap
->a_bytesallocated
) = 0;
1731 /* Now for some error checking */
1733 if (length
< (off_t
)0) {
1734 DBG_VOP_LOCKS_TEST(EINVAL
);
1738 if (vp
->v_type
!= VREG
&& vp
->v_type
!= VLNK
) {
1739 DBG_VOP_LOCKS_TEST(EISDIR
);
1740 return (EISDIR
); /* hfs doesn't support truncating of directories */
1743 if ((ap
->a_flags
& ALLOCATEFROMVOL
) && (length
<= fcb
->fcbPLen
))
1746 /* Fill in the flags word for the call to Extend the file */
1748 if (ap
->a_flags
& ALLOCATECONTIG
) {
1749 extendFlags
|= kEFContigMask
;
1752 if (ap
->a_flags
& ALLOCATEALL
) {
1753 extendFlags
|= kEFAllMask
;
1759 startingPEOF
= fcb
->fcbPLen
;
1761 if (ap
->a_flags
& ALLOCATEFROMPEOF
) {
1762 length
+= fcb
->fcbPLen
;
1765 if (ap
->a_flags
& ALLOCATEFROMVOL
)
1766 blockHint
= ap
->a_offset
/ HTOVCB(hp
)->blockSize
;
1768 /* If no changes are necesary, then we're done */
1769 if (fcb
->fcbPLen
== length
)
1773 * Lengthen the size of the file. We must ensure that the
1774 * last byte of the file is allocated. Since the smallest
1775 * value of fcbPLen is 0, length will be at least 1.
1777 if (length
> fcb
->fcbPLen
) {
1778 moreBytesRequested
= length
- fcb
->fcbPLen
;
1780 /* lock extents b-tree (also protects volume bitmap) */
1781 retval
= hfs_metafilelocking(HTOHFS(hp
), kHFSExtentsFileID
, LK_EXCLUSIVE
, ap
->a_p
);
1782 if (retval
) goto Err_Exit
;
1784 retval
= MacToVFSError(
1785 ExtendFileC(HTOVCB(hp
),
1790 &actualBytesAdded
));
1792 *(ap
->a_bytesallocated
) = actualBytesAdded
;
1794 (void) hfs_metafilelocking(HTOHFS(hp
), kHFSExtentsFileID
, LK_RELEASE
, ap
->a_p
);
1796 DBG_ASSERT(length
<= fcb
->fcbPLen
);
1799 * if we get an error and no changes were made then exit
1800 * otherwise we must do the VOP_UPDATE to reflect the changes
1802 if (retval
&& (startingPEOF
== fcb
->fcbPLen
)) goto Err_Exit
;
1805 * Adjust actualBytesAdded to be allocation block aligned, not
1806 * clump size aligned.
1807 * NOTE: So what we are reporting does not affect reality
1808 * until the file is closed, when we truncate the file to allocation
1812 if ((actualBytesAdded
!= 0) && (moreBytesRequested
< actualBytesAdded
))
1813 *(ap
->a_bytesallocated
) =
1814 roundup(moreBytesRequested
, (off_t
)VTOVCB(vp
)->blockSize
);
1816 } else { /* Shorten the size of the file */
1818 if (fcb
->fcbEOF
> length
) {
1820 * Any buffers that are past the truncation point need to be
1821 * invalidated (to maintain buffer cache consistency). For
1822 * simplicity, we invalidate all the buffers by calling vinvalbuf.
1824 vflags
= ((length
> 0) ? V_SAVE
: 0) | V_SAVEMETA
;
1825 (void) vinvalbuf(vp
, vflags
, ap
->a_cred
, ap
->a_p
, 0, 0);
1828 /* lock extents b-tree (also protects volume bitmap) */
1829 retval
= hfs_metafilelocking(HTOHFS(hp
), kHFSExtentsFileID
, LK_EXCLUSIVE
, ap
->a_p
);
1830 if (retval
) goto Err_Exit
;
1832 retval
= MacToVFSError(
1838 (void) hfs_metafilelocking(HTOHFS(hp
), kHFSExtentsFileID
, LK_RELEASE
, ap
->a_p
);
1841 * if we get an error and no changes were made then exit
1842 * otherwise we must do the VOP_UPDATE to reflect the changes
1844 if (retval
&& (startingPEOF
== fcb
->fcbPLen
)) goto Err_Exit
;
1845 if (fcb
->fcbFlags
& fcbModifiedMask
)
1846 hp
->h_nodeflags
|= IN_MODIFIED
;
1848 DBG_ASSERT(length
<= fcb
->fcbPLen
) // DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG
1850 if (fcb
->fcbEOF
> fcb
->fcbPLen
) {
1851 fcb
->fcbEOF
= fcb
->fcbPLen
;
1854 ubc_setsize(vp
, (off_t
)fcb
->fcbEOF
); /* XXX check errors */
1859 hp
->h_nodeflags
|= IN_CHANGE
| IN_UPDATE
;
1860 retval2
= VOP_UPDATE(vp
, &tv
, &tv
, MNT_WAIT
);
1862 if (retval
== 0) retval
= retval2
;
1865 DBG_VOP_LOCKS_TEST(retval
);
1872 /* pagein for HFS filesystem, similar to hfs_read(), but without cluster_read() */
1875 struct vop_pagein_args
/* {
1878 vm_offset_t a_pl_offset,
1881 struct ucred *a_cred,
1885 register struct vnode
*vp
;
1888 int devBlockSize
= 0;
1891 DBG_FUNC_NAME("hfs_pagein");
1892 DBG_VOP_LOCKS_DECL(1);
1893 DBG_VOP_PRINT_FUNCNAME();
1894 DBG_VOP_PRINT_VNODE_INFO(vp
);DBG_VOP_CONT(("\n"));
1895 DBG_VOP_LOCKS_INIT(0,vp
, VOPDBG_LOCKED
, VOPDBG_LOCKED
, VOPDBG_LOCKED
, VOPDBG_POS
);
1901 if (vp
->v_type
!= VREG
&& vp
->v_type
!= VLNK
)
1902 panic("hfs_pagein: vp not UBC type\n");
1904 DBG_VOP(("\tfile size Ox%X\n", (u_int
)fcb
->fcbEOF
));
1905 DBG_VOP(("\tstarting at offset Ox%X of file, length Ox%X\n", (u_int
)ap
->a_f_offset
, (u_int
)ap
->a_size
));
1908 debug_check_blocksizes(vp
);
1911 VOP_DEVBLOCKSIZE(hp
->h_meta
->h_devvp
, &devBlockSize
);
1913 retval
= cluster_pagein(vp
, ap
->a_pl
, ap
->a_pl_offset
, ap
->a_f_offset
,
1914 ap
->a_size
, (off_t
)fcb
->fcbEOF
, devBlockSize
,
1918 debug_check_blocksizes(vp
);
1920 DBG_VOP_LOCKS_TEST(retval
);
1926 * pageout for HFS filesystem.
1930 struct vop_pageout_args
/* {
1933 vm_offset_t a_pl_offset,
1936 struct ucred *a_cred,
1940 struct vnode
*vp
= ap
->a_vp
;
1941 struct hfsnode
*hp
= VTOH(vp
);
1942 FCB
*fcb
= HTOFCB(hp
);
1944 int devBlockSize
= 0;
1947 DBG_FUNC_NAME("hfs_pageout");
1948 DBG_VOP_LOCKS_DECL(1);
1949 DBG_VOP_PRINT_FUNCNAME();
1950 DBG_VOP_PRINT_VNODE_INFO(vp
);DBG_VOP_CONT(("\n"));
1951 DBG_VOP(("\thfsnode 0x%x (%s)\n", (u_int
)hp
, H_NAME(hp
)));
1952 DBG_VOP(("\tstarting at offset Ox%lX of file, length Ox%lX\n",
1953 (UInt32
)ap
->a_f_offset
, (UInt32
)ap
->a_size
));
1955 DBG_VOP_LOCKS_INIT(0, vp
, VOPDBG_LOCKED
,
1956 VOPDBG_LOCKED
, VOPDBG_LOCKED
, VOPDBG_POS
);
1959 debug_check_blocksizes(vp
);
1963 panic("hfs_pageout: Not a VREG: vp=%x", vp
);
1965 VOP_DEVBLOCKSIZE(hp
->h_meta
->h_devvp
, &devBlockSize
);
1967 end_of_range
= ap
->a_f_offset
+ ap
->a_size
- 1;
1969 if (end_of_range
>= (off_t
)fcb
->fcbEOF
)
1970 end_of_range
= (off_t
)(fcb
->fcbEOF
- 1);
1972 if (ap
->a_f_offset
< (off_t
)fcb
->fcbEOF
)
1973 rl_remove(ap
->a_f_offset
, end_of_range
, &hp
->h_invalidranges
);
1975 retval
= cluster_pageout(vp
, ap
->a_pl
, ap
->a_pl_offset
, ap
->a_f_offset
, ap
->a_size
,
1976 (off_t
)fcb
->fcbEOF
, devBlockSize
, ap
->a_flags
);
1979 * If we successfully wrote any data, and we are not the superuser
1980 * we clear the setuid and setgid bits as a precaution against
1983 if (retval
== 0 && ap
->a_cred
&& ap
->a_cred
->cr_uid
!= 0)
1984 hp
->h_meta
->h_mode
&= ~(ISUID
| ISGID
);
1987 debug_check_blocksizes(vp
);
1990 DBG_VOP_LOCKS_TEST(retval
);
1995 * Intercept B-Tree node writes to unswap them if necessary.
1998 # IN struct buf *bp;
2002 struct vop_bwrite_args
/* {
2006 register struct buf
*bp
= ap
->a_bp
;
2007 register struct vnode
*vp
= bp
->b_vp
;
2008 BlockDescriptor block
;
2011 DBG_FUNC_NAME("hfs_bwrite");
2013 #if BYTE_ORDER == LITTLE_ENDIAN
2014 /* Trap B-Tree writes */
2015 if ((H_FILEID(VTOH(vp
)) == kHFSExtentsFileID
) ||
2016 (H_FILEID(VTOH(vp
)) == kHFSCatalogFileID
)) {
2018 /* Swap if the B-Tree node is in native byte order */
2019 if (((UInt16
*)((char *)bp
->b_data
+ bp
->b_bcount
- 2))[0] == 0x000e) {
2020 /* Prepare the block pointer */
2021 block
.blockHeader
= bp
;
2022 block
.buffer
= bp
->b_data
+ IOBYTEOFFSETFORBLK(bp
->b_blkno
, VTOHFS(vp
)->hfs_phys_block_size
);
2023 block
.blockReadFromDisk
= (bp
->b_flags
& B_CACHE
) == 0; /* not found in cache ==> came from disk */
2024 block
.blockSize
= bp
->b_bcount
;
2026 /* Endian un-swap B-Tree node */
2027 SWAP_BT_NODE (&block
, ISHFSPLUS (VTOVCB(vp
)), H_FILEID(VTOH(vp
)), 1);
2030 /* We don't check to make sure that it's 0x0e00 because it could be all zeros */
2034 retval
= vn_bwrite (ap
);