2 * Copyright (c) 2000-2002 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) 1998-2001 Apple Computer, Inc. All Rights Reserved
26 * hfs_readwrite.c -- vnode operations to deal with reading and writing files.
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/resourcevar.h>
33 #include <sys/kernel.h>
34 #include <sys/fcntl.h>
38 #include <sys/vnode.h>
41 #include <miscfs/specfs/specdev.h>
44 #include <vm/vm_pageout.h>
46 #include <sys/kdebug.h>
49 #include "hfs_endian.h"
50 #include "hfs_quota.h"
51 #include "hfscommon/headers/FileMgrInternal.h"
52 #include "hfscommon/headers/BTreesInternal.h"
53 #include "hfs_cnode.h"
56 extern int overflow_extents(struct filefork
*fp
);
58 #define can_cluster(size) ((((size & (4096-1))) == 0) && (size <= (MAXPHYSIO/2)))
61 MAXHFSFILESIZE
= 0x7FFFFFFF /* this needs to go in the mount structure */
64 extern u_int32_t
GetLogicalBlockSize(struct vnode
*vp
);
67 /*****************************************************************************
69 * Operations on vnodes
71 *****************************************************************************/
78 INOUT struct uio *uio;
80 IN struct ucred *cred;
86 struct vop_read_args
/* {
93 register struct uio
*uio
= ap
->a_uio
;
94 register struct vnode
*vp
= ap
->a_vp
;
99 u_long fragSize
, moveSize
, startOffset
, ioxfersize
;
100 int devBlockSize
= 0;
101 off_t bytesRemaining
;
106 /* Preflight checks */
107 if (vp
->v_type
!= VREG
&& vp
->v_type
!= VLNK
)
108 return (EISDIR
); /* HFS can only read files */
109 if (uio
->uio_resid
== 0)
110 return (0); /* Nothing left to do */
111 if (uio
->uio_offset
< 0)
112 return (EINVAL
); /* cant read from a negative offset */
116 filesize
= fp
->ff_size
;
117 filebytes
= (off_t
)fp
->ff_blocks
* (off_t
)VTOVCB(vp
)->blockSize
;
118 if (uio
->uio_offset
> filesize
) {
119 if ((!ISHFSPLUS(VTOVCB(vp
))) && (uio
->uio_offset
> (off_t
)MAXHFSFILESIZE
))
125 VOP_DEVBLOCKSIZE(cp
->c_devvp
, &devBlockSize
);
127 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 12)) | DBG_FUNC_START
,
128 (int)uio
->uio_offset
, uio
->uio_resid
, (int)filesize
, (int)filebytes
, 0);
130 if (UBCISVALID(vp
)) {
131 retval
= cluster_read(vp
, uio
, filesize
, devBlockSize
, 0);
134 for (retval
= 0, bp
= NULL
; uio
->uio_resid
> 0; bp
= NULL
) {
136 if ((bytesRemaining
= (filesize
- uio
->uio_offset
)) <= 0)
139 logBlockNo
= (daddr_t
)(uio
->uio_offset
/ PAGE_SIZE_64
);
140 startOffset
= (u_long
) (uio
->uio_offset
& PAGE_MASK_64
);
141 fragSize
= PAGE_SIZE
;
143 if (((logBlockNo
* PAGE_SIZE
) + fragSize
) < filesize
)
144 ioxfersize
= fragSize
;
146 ioxfersize
= filesize
- (logBlockNo
* PAGE_SIZE
);
147 ioxfersize
= (ioxfersize
+ (devBlockSize
- 1)) & ~(devBlockSize
- 1);
149 moveSize
= ioxfersize
;
150 moveSize
-= startOffset
;
152 if (bytesRemaining
< moveSize
)
153 moveSize
= bytesRemaining
;
155 if (uio
->uio_resid
< moveSize
) {
156 moveSize
= uio
->uio_resid
;
162 if (( uio
->uio_offset
+ fragSize
) >= filesize
) {
163 retval
= bread(vp
, logBlockNo
, ioxfersize
, NOCRED
, &bp
);
165 } else if (logBlockNo
- 1 == vp
->v_lastr
&& !(vp
->v_flag
& VRAOFF
)) {
166 daddr_t nextLogBlockNo
= logBlockNo
+ 1;
169 if (((nextLogBlockNo
* PAGE_SIZE
) +
170 (daddr_t
)fragSize
) < filesize
)
173 nextsize
= filesize
- (nextLogBlockNo
* PAGE_SIZE
);
174 nextsize
= (nextsize
+ (devBlockSize
- 1)) & ~(devBlockSize
- 1);
176 retval
= breadn(vp
, logBlockNo
, ioxfersize
, &nextLogBlockNo
, &nextsize
, 1, NOCRED
, &bp
);
178 retval
= bread(vp
, logBlockNo
, ioxfersize
, NOCRED
, &bp
);
181 if (retval
!= E_NONE
) {
188 vp
->v_lastr
= logBlockNo
;
191 * We should only get non-zero b_resid when an I/O retval
192 * has occurred, which should cause us to break above.
193 * However, if the short read did not cause an retval,
194 * then we want to ensure that we do not uiomove bad
195 * or uninitialized data.
197 ioxfersize
-= bp
->b_resid
;
199 if (ioxfersize
< moveSize
) { /* XXX PPD This should take the offset into account, too! */
202 moveSize
= ioxfersize
;
204 if ((startOffset
+ moveSize
) > bp
->b_bcount
)
205 panic("hfs_read: bad startOffset or moveSize\n");
207 if ((retval
= uiomove((caddr_t
)bp
->b_data
+ startOffset
, (int)moveSize
, uio
)))
210 if (S_ISREG(cp
->c_mode
) &&
211 (((startOffset
+ moveSize
) == fragSize
) || (uio
->uio_offset
== filesize
))) {
212 bp
->b_flags
|= B_AGE
;
216 /* Start of loop resets bp to NULL before reaching outside this block... */
224 cp
->c_flag
|= C_ACCESS
;
226 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 12)) | DBG_FUNC_END
,
227 (int)uio
->uio_offset
, uio
->uio_resid
, (int)filesize
, (int)filebytes
, 0);
233 * Write data to a file or directory.
238 INOUT struct uio *uio;
240 IN struct ucred *cred;
245 struct vop_write_args
/* {
249 struct ucred *a_cred;
252 struct vnode
*vp
= ap
->a_vp
;
253 struct uio
*uio
= ap
->a_uio
;
260 int devBlockSize
= 0;
263 off_t origFileSize
, currOffset
, writelimit
, bytesToAdd
;
264 off_t actualBytesAdded
;
265 u_long blkoffset
, resid
, xfersize
, clearSize
;
271 ioflag
= ap
->a_ioflag
;
273 if (uio
->uio_offset
< 0)
275 if (uio
->uio_resid
== 0)
277 if (vp
->v_type
!= VREG
&& vp
->v_type
!= VLNK
)
278 return (EISDIR
); /* Can only write files */
283 fileblocks
= fp
->ff_blocks
;
284 filebytes
= (off_t
)fileblocks
* (off_t
)vcb
->blockSize
;
286 if (ioflag
& IO_APPEND
)
287 uio
->uio_offset
= fp
->ff_size
;
288 if ((cp
->c_flags
& APPEND
) && uio
->uio_offset
!= fp
->ff_size
)
291 writelimit
= uio
->uio_offset
+ uio
->uio_resid
;
294 * Maybe this should be above the vnode op call, but so long as
295 * file servers have no limits, I don't think it matters.
298 if (vp
->v_type
== VREG
&& p
&&
299 writelimit
> p
->p_rlimit
[RLIMIT_FSIZE
].rlim_cur
) {
305 VOP_DEVBLOCKSIZE(cp
->c_devvp
, &devBlockSize
);
307 resid
= uio
->uio_resid
;
308 origFileSize
= fp
->ff_size
;
309 eflags
= kEFDeferMask
; /* defer file block allocations */
310 filebytes
= (off_t
)fp
->ff_blocks
* (off_t
)vcb
->blockSize
;
313 * NOTE: In the following loop there are two positions tracked:
314 * currOffset is the current I/O starting offset. currOffset
315 * is never >LEOF; the LEOF is nudged along with currOffset as
316 * data is zeroed or written. uio->uio_offset is the start of
317 * the current I/O operation. It may be arbitrarily beyond
320 * The following is true at all times:
321 * currOffset <= LEOF <= uio->uio_offset <= writelimit
323 currOffset
= MIN(uio
->uio_offset
, fp
->ff_size
);
325 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 0)) | DBG_FUNC_START
,
326 (int)uio
->uio_offset
, uio
->uio_resid
, (int)fp
->ff_size
, (int)filebytes
, 0);
329 /* Now test if we need to extend the file */
330 /* Doing so will adjust the filebytes for us */
333 if(writelimit
> filebytes
) {
334 bytesToAdd
= writelimit
- filebytes
;
336 retval
= hfs_chkdq(cp
, (int64_t)(roundup(bytesToAdd
, fp
->ff_clumpsize
)),
343 while (writelimit
> filebytes
) {
345 bytesToAdd
= writelimit
- filebytes
;
346 if (suser(ap
->a_cred
, NULL
) != 0)
347 eflags
|= kEFReserveMask
;
349 /* lock extents b-tree (also protects volume bitmap) */
350 retval
= hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_EXCLUSIVE
, current_proc());
351 if (retval
!= E_NONE
)
354 retval
= MacToVFSError(ExtendFileC (vcb
, (FCB
*)fp
, bytesToAdd
,
355 0, eflags
, &actualBytesAdded
));
357 (void) hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_RELEASE
, p
);
358 if ((actualBytesAdded
== 0) && (retval
== E_NONE
))
360 if (retval
!= E_NONE
)
362 filebytes
= (off_t
)fp
->ff_blocks
* (off_t
)vcb
->blockSize
;
363 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 0)) | DBG_FUNC_NONE
,
364 (int)uio
->uio_offset
, uio
->uio_resid
, (int)fp
->ff_size
, (int)filebytes
, 0);
367 if (UBCISVALID(vp
) && retval
== E_NONE
) {
373 off_t io_start
, io_end
;
375 struct rl_entry
*invalid_range
;
377 if (writelimit
> fp
->ff_size
)
378 filesize
= writelimit
;
380 filesize
= fp
->ff_size
;
382 lflag
= (ioflag
& IO_SYNC
);
384 if (uio
->uio_offset
<= fp
->ff_size
) {
385 zero_off
= uio
->uio_offset
& ~PAGE_MASK_64
;
387 /* Check to see whether the area between the zero_offset and the start
388 of the transfer to see whether is invalid and should be zero-filled
389 as part of the transfer:
391 if (rl_scan(&fp
->ff_invalidranges
, zero_off
, uio
->uio_offset
- 1, &invalid_range
) != RL_NOOVERLAP
)
392 lflag
|= IO_HEADZEROFILL
;
394 off_t eof_page_base
= fp
->ff_size
& ~PAGE_MASK_64
;
396 /* The bytes between fp->ff_size and uio->uio_offset must never be
397 read without being zeroed. The current last block is filled with zeroes
398 if it holds valid data but in all cases merely do a little bookkeeping
399 to track the area from the end of the current last page to the start of
400 the area actually written. For the same reason only the bytes up to the
401 start of the page where this write will start is invalidated; any remainder
402 before uio->uio_offset is explicitly zeroed as part of the cluster_write.
404 Note that inval_start, the start of the page after the current EOF,
405 may be past the start of the write, in which case the zeroing
406 will be handled by the cluser_write of the actual data.
408 inval_start
= (fp
->ff_size
+ (PAGE_SIZE_64
- 1)) & ~PAGE_MASK_64
;
409 inval_end
= uio
->uio_offset
& ~PAGE_MASK_64
;
410 zero_off
= fp
->ff_size
;
412 if ((fp
->ff_size
& PAGE_MASK_64
) &&
413 (rl_scan(&fp
->ff_invalidranges
,
416 &invalid_range
) != RL_NOOVERLAP
)) {
417 /* The page containing the EOF is not valid, so the
418 entire page must be made inaccessible now. If the write
419 starts on a page beyond the page containing the eof
420 (inval_end > eof_page_base), add the
421 whole page to the range to be invalidated. Otherwise
422 (i.e. if the write starts on the same page), zero-fill
423 the entire page explicitly now:
425 if (inval_end
> eof_page_base
) {
426 inval_start
= eof_page_base
;
428 zero_off
= eof_page_base
;
432 if (inval_start
< inval_end
) {
433 /* There's some range of data that's going to be marked invalid */
435 if (zero_off
< inval_start
) {
436 /* The pages between inval_start and inval_end are going to be invalidated,
437 and the actual write will start on a page past inval_end. Now's the last
438 chance to zero-fill the page containing the EOF:
440 retval
= cluster_write(vp
, (struct uio
*) 0,
441 fp
->ff_size
, inval_start
,
442 zero_off
, (off_t
)0, devBlockSize
,
443 lflag
| IO_HEADZEROFILL
| IO_NOZERODIRTY
);
444 if (retval
) goto ioerr_exit
;
447 /* Mark the remaining area of the newly allocated space as invalid: */
448 rl_add(inval_start
, inval_end
- 1 , &fp
->ff_invalidranges
);
449 cp
->c_zftimeout
= time
.tv_sec
+ ZFTIMELIMIT
;
450 zero_off
= fp
->ff_size
= inval_end
;
453 if (uio
->uio_offset
> zero_off
) lflag
|= IO_HEADZEROFILL
;
456 /* Check to see whether the area between the end of the write and the end of
457 the page it falls in is invalid and should be zero-filled as part of the transfer:
459 tail_off
= (writelimit
+ (PAGE_SIZE_64
- 1)) & ~PAGE_MASK_64
;
460 if (tail_off
> filesize
) tail_off
= filesize
;
461 if (tail_off
> writelimit
) {
462 if (rl_scan(&fp
->ff_invalidranges
, writelimit
, tail_off
- 1, &invalid_range
) != RL_NOOVERLAP
) {
463 lflag
|= IO_TAILZEROFILL
;
468 * if the write starts beyond the current EOF (possibly advanced in the
469 * zeroing of the last block, above), then we'll zero fill from the current EOF
470 * to where the write begins:
472 * NOTE: If (and ONLY if) the portion of the file about to be written is
473 * before the current EOF it might be marked as invalid now and must be
474 * made readable (removed from the invalid ranges) before cluster_write
477 io_start
= (lflag
& IO_HEADZEROFILL
) ? zero_off
: uio
->uio_offset
;
478 io_end
= (lflag
& IO_TAILZEROFILL
) ? tail_off
: writelimit
;
479 if (io_start
< fp
->ff_size
) {
480 rl_remove(io_start
, io_end
- 1, &fp
->ff_invalidranges
);
482 retval
= cluster_write(vp
, uio
, fp
->ff_size
, filesize
, zero_off
,
483 tail_off
, devBlockSize
, lflag
| IO_NOZERODIRTY
);
485 if (uio
->uio_offset
> fp
->ff_size
) {
486 fp
->ff_size
= uio
->uio_offset
;
488 ubc_setsize(vp
, fp
->ff_size
); /* XXX check errors */
490 if (resid
> uio
->uio_resid
)
491 cp
->c_flag
|= C_CHANGE
| C_UPDATE
;
493 while (retval
== E_NONE
&& uio
->uio_resid
> 0) {
494 logBlockNo
= currOffset
/ PAGE_SIZE
;
495 blkoffset
= currOffset
& PAGE_MASK
;
497 if ((filebytes
- currOffset
) < PAGE_SIZE_64
)
498 fragSize
= filebytes
- ((off_t
)logBlockNo
* PAGE_SIZE_64
);
500 fragSize
= PAGE_SIZE
;
501 xfersize
= fragSize
- blkoffset
;
503 /* Make any adjustments for boundary conditions */
504 if (currOffset
+ (off_t
)xfersize
> writelimit
)
505 xfersize
= writelimit
- currOffset
;
508 * There is no need to read into bp if:
509 * We start on a block boundary and will overwrite the whole block
513 if ((blkoffset
== 0) && (xfersize
>= fragSize
)) {
514 bp
= getblk(vp
, logBlockNo
, fragSize
, 0, 0, BLK_READ
);
517 if (bp
->b_blkno
== -1) {
519 retval
= EIO
; /* XXX */
524 if (currOffset
== fp
->ff_size
&& blkoffset
== 0) {
525 bp
= getblk(vp
, logBlockNo
, fragSize
, 0, 0, BLK_READ
);
527 if (bp
->b_blkno
== -1) {
529 retval
= EIO
; /* XXX */
534 * This I/O transfer is not sufficiently aligned,
535 * so read the affected block into a buffer:
537 retval
= bread(vp
, logBlockNo
, fragSize
, ap
->a_cred
, &bp
);
538 if (retval
!= E_NONE
) {
546 /* See if we are starting to write within file boundaries:
547 * If not, then we need to present a "hole" for the area
548 * between the current EOF and the start of the current
551 * Note that currOffset is only less than uio_offset if
552 * uio_offset > LEOF...
554 if (uio
->uio_offset
> currOffset
) {
555 clearSize
= MIN(uio
->uio_offset
- currOffset
, xfersize
);
556 bzero(bp
->b_data
+ blkoffset
, clearSize
);
557 currOffset
+= clearSize
;
558 blkoffset
+= clearSize
;
559 xfersize
-= clearSize
;
563 retval
= uiomove((caddr_t
)bp
->b_data
+ blkoffset
, (int)xfersize
, uio
);
564 currOffset
+= xfersize
;
567 if (ioflag
& IO_SYNC
) {
568 (void)VOP_BWRITE(bp
);
569 } else if ((xfersize
+ blkoffset
) == fragSize
) {
570 bp
->b_flags
|= B_AGE
;
576 /* Update the EOF if we just extended the file
577 * (the PEOF has already been moved out and the
578 * block mapping table has been updated):
580 if (currOffset
> fp
->ff_size
) {
581 fp
->ff_size
= currOffset
;
583 ubc_setsize(vp
, fp
->ff_size
); /* XXX check errors */
585 if (retval
|| (resid
== 0))
587 cp
->c_flag
|= C_CHANGE
| C_UPDATE
;
593 * If we successfully wrote any data, and we are not the superuser
594 * we clear the setuid and setgid bits as a precaution against
597 if (resid
> uio
->uio_resid
&& ap
->a_cred
&& ap
->a_cred
->cr_uid
!= 0)
598 cp
->c_mode
&= ~(S_ISUID
| S_ISGID
);
601 if (ioflag
& IO_UNIT
) {
602 (void)VOP_TRUNCATE(vp
, origFileSize
,
603 ioflag
& IO_SYNC
, ap
->a_cred
, uio
->uio_procp
);
604 uio
->uio_offset
-= resid
- uio
->uio_resid
;
605 uio
->uio_resid
= resid
;
606 filebytes
= (off_t
)fp
->ff_blocks
* (off_t
)vcb
->blockSize
;
608 } else if (resid
> uio
->uio_resid
&& (ioflag
& IO_SYNC
)) {
610 retval
= VOP_UPDATE(vp
, &tv
, &tv
, 1);
613 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 0)) | DBG_FUNC_END
,
614 (int)uio
->uio_offset
, uio
->uio_resid
, (int)fp
->ff_size
, (int)filebytes
, 0);
629 IN struct ucred *cred;
638 struct vop_ioctl_args
/* {
643 struct ucred *a_cred;
647 switch (ap
->a_command
) {
649 register struct cnode
*cp
;
650 register struct vnode
*vp
;
651 register struct radvisory
*ra
;
653 int devBlockSize
= 0;
658 if (vp
->v_type
!= VREG
)
661 VOP_LEASE(vp
, ap
->a_p
, ap
->a_cred
, LEASE_READ
);
662 error
= vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, ap
->a_p
);
666 ra
= (struct radvisory
*)(ap
->a_data
);
670 if (ra
->ra_offset
>= fp
->ff_size
) {
671 VOP_UNLOCK(vp
, 0, ap
->a_p
);
674 VOP_DEVBLOCKSIZE(cp
->c_devvp
, &devBlockSize
);
676 error
= advisory_read(vp
, fp
->ff_size
, ra
->ra_offset
, ra
->ra_count
, devBlockSize
);
677 VOP_UNLOCK(vp
, 0, ap
->a_p
);
682 case 2: /* F_READBOOTBLOCKS */
683 case 3: /* F_WRITEBOOTBLOCKS */
685 struct vnode
*vp
= ap
->a_vp
;
686 struct vnode
*devvp
= NULL
;
687 struct fbootstraptransfer
*btd
= (struct fbootstraptransfer
*)ap
->a_data
;
697 if ((vp
->v_flag
& VROOT
) == 0) return EINVAL
;
698 if (btd
->fbt_offset
+ btd
->fbt_length
> 1024) return EINVAL
;
700 devvp
= VTOHFS(vp
)->hfs_devvp
;
701 aiov
.iov_base
= btd
->fbt_buffer
;
702 aiov
.iov_len
= btd
->fbt_length
;
704 auio
.uio_iov
= &aiov
;
706 auio
.uio_offset
= btd
->fbt_offset
;
707 auio
.uio_resid
= btd
->fbt_length
;
708 auio
.uio_segflg
= UIO_USERSPACE
;
709 auio
.uio_rw
= (ap
->a_command
== 3) ? UIO_WRITE
: UIO_READ
; /* F_WRITEBOOTSTRAP / F_READBOOTSTRAP */
710 auio
.uio_procp
= ap
->a_p
;
712 VOP_DEVBLOCKSIZE(devvp
, &devBlockSize
);
714 while (auio
.uio_resid
> 0) {
715 blockNumber
= auio
.uio_offset
/ devBlockSize
;
716 error
= bread(devvp
, blockNumber
, devBlockSize
, ap
->a_cred
, &bp
);
722 blockOffset
= auio
.uio_offset
% devBlockSize
;
723 xfersize
= devBlockSize
- blockOffset
;
724 error
= uiomove((caddr_t
)bp
->b_data
+ blockOffset
, (int)xfersize
, &auio
);
729 if (auio
.uio_rw
== UIO_WRITE
) {
730 error
= VOP_BWRITE(bp
);
731 if (error
) return error
;
739 case _IOC(IOC_OUT
,'h', 4, 0): /* Create date in local time */
741 *(time_t *)(ap
->a_data
) = to_bsd_time(VTOVCB(ap
->a_vp
)->localCreateDate
);
749 /* Should never get here */
756 struct vop_select_args
/* {
760 struct ucred *a_cred;
766 * We should really check to see if I/O is possible.
772 * Bmap converts a the logical block number of a file to its physical block
773 * number on the disk.
777 * vp - address of vnode file the file
778 * bn - which logical block to convert to a physical block number.
779 * vpp - returns the vnode for the block special file holding the filesystem
780 * containing the file of interest
781 * bnp - address of where to return the filesystem physical block number
788 OUT struct vnode **vpp;
793 * Converts a logical block number to a physical block, and optionally returns
794 * the amount of remaining blocks in a run. The logical block is based on hfsNode.logBlockSize.
795 * The physical block number is based on the device block size, currently its 512.
796 * The block run is returned in logical blocks, and is the REMAINING amount of blocks
801 struct vop_bmap_args
/* {
804 struct vnode **a_vpp;
809 struct vnode
*vp
= ap
->a_vp
;
810 struct cnode
*cp
= VTOC(vp
);
811 struct filefork
*fp
= VTOF(vp
);
812 struct hfsmount
*hfsmp
= VTOHFS(vp
);
814 daddr_t logBlockSize
;
815 size_t bytesContAvail
= 0;
817 struct proc
*p
= NULL
;
819 struct rl_entry
*invalid_range
;
820 enum rl_overlaptype overlaptype
;
823 * Check for underlying vnode requests and ensure that logical
824 * to physical mapping is requested.
826 if (ap
->a_vpp
!= NULL
)
827 *ap
->a_vpp
= cp
->c_devvp
;
828 if (ap
->a_bnp
== NULL
)
831 /* Only clustered I/O should have delayed allocations. */
832 DBG_ASSERT(fp
->ff_unallocblocks
== 0);
834 logBlockSize
= GetLogicalBlockSize(vp
);
835 blockposition
= (off_t
)ap
->a_bn
* (off_t
)logBlockSize
;
837 lockExtBtree
= overflow_extents(fp
);
840 retval
= hfs_metafilelocking(hfsmp
, kHFSExtentsFileID
,
841 LK_EXCLUSIVE
| LK_CANRECURSE
, p
);
846 retval
= MacToVFSError(
847 MapFileBlockC (HFSTOVCB(hfsmp
),
854 if (lockExtBtree
) (void) hfs_metafilelocking(hfsmp
, kHFSExtentsFileID
, LK_RELEASE
, p
);
856 if (retval
== E_NONE
) {
857 /* Adjust the mapping information for invalid file ranges: */
858 overlaptype
= rl_scan(&fp
->ff_invalidranges
,
860 blockposition
+ MAXPHYSIO
- 1,
862 if (overlaptype
!= RL_NOOVERLAP
) {
863 switch(overlaptype
) {
864 case RL_MATCHINGOVERLAP
:
865 case RL_OVERLAPCONTAINSRANGE
:
866 case RL_OVERLAPSTARTSBEFORE
:
867 /* There's no valid block for this byte offset: */
868 *ap
->a_bnp
= (daddr_t
)-1;
869 bytesContAvail
= invalid_range
->rl_end
+ 1 - blockposition
;
872 case RL_OVERLAPISCONTAINED
:
873 case RL_OVERLAPENDSAFTER
:
874 /* The range of interest hits an invalid block before the end: */
875 if (invalid_range
->rl_start
== blockposition
) {
876 /* There's actually no valid information to be had starting here: */
877 *ap
->a_bnp
= (daddr_t
)-1;
878 if ((fp
->ff_size
> (invalid_range
->rl_end
+ 1)) &&
879 (invalid_range
->rl_end
+ 1 - blockposition
< bytesContAvail
)) {
880 bytesContAvail
= invalid_range
->rl_end
+ 1 - blockposition
;
883 bytesContAvail
= invalid_range
->rl_start
- blockposition
;
887 if (bytesContAvail
> MAXPHYSIO
) bytesContAvail
= MAXPHYSIO
;
890 /* Figure out how many read ahead blocks there are */
891 if (ap
->a_runp
!= NULL
) {
892 if (can_cluster(logBlockSize
)) {
893 /* Make sure this result never goes negative: */
894 *ap
->a_runp
= (bytesContAvail
< logBlockSize
) ? 0 : (bytesContAvail
/ logBlockSize
) - 1;
904 /* blktooff converts logical block number to file offset */
908 struct vop_blktooff_args
/* {
914 if (ap
->a_vp
== NULL
)
916 *ap
->a_offset
= (off_t
)ap
->a_lblkno
* PAGE_SIZE_64
;
923 struct vop_offtoblk_args
/* {
929 if (ap
->a_vp
== NULL
)
931 *ap
->a_lblkno
= ap
->a_offset
/ PAGE_SIZE_64
;
938 struct vop_cmap_args
/* {
947 struct hfsmount
*hfsmp
= VTOHFS(ap
->a_vp
);
948 struct filefork
*fp
= VTOF(ap
->a_vp
);
949 size_t bytesContAvail
= 0;
951 int lockExtBtree
= 0;
952 struct proc
*p
= NULL
;
953 struct rl_entry
*invalid_range
;
954 enum rl_overlaptype overlaptype
;
957 * Check for underlying vnode requests and ensure that logical
958 * to physical mapping is requested.
960 if (ap
->a_bpn
== NULL
)
963 if (overflow_extents(fp
) || fp
->ff_unallocblocks
) {
966 if (retval
= hfs_metafilelocking(hfsmp
, kHFSExtentsFileID
, LK_EXCLUSIVE
| LK_CANRECURSE
, p
)) {
972 * Check for any delayed allocations.
974 if (fp
->ff_unallocblocks
) {
975 SInt64 reqbytes
, actbytes
;
977 reqbytes
= (SInt64
)fp
->ff_unallocblocks
*
978 (SInt64
)HFSTOVCB(hfsmp
)->blockSize
;
980 * Release the blocks on loan and aquire some real ones.
981 * Note that we can race someone else for these blocks
982 * (and lose) so cmap needs to handle a failure here.
983 * Currently this race can't occur because all allocations
984 * are protected by an exclusive lock on the Extents
987 HFSTOVCB(hfsmp
)->loanedBlocks
-= fp
->ff_unallocblocks
;
988 FTOC(fp
)->c_blocks
-= fp
->ff_unallocblocks
;
989 fp
->ff_blocks
-= fp
->ff_unallocblocks
;
990 fp
->ff_unallocblocks
= 0;
992 while (retval
== 0 && reqbytes
> 0) {
993 retval
= MacToVFSError(ExtendFileC(HFSTOVCB(hfsmp
),
994 (FCB
*)fp
, reqbytes
, 0,
995 kEFAllMask
| kEFNoClumpMask
, &actbytes
));
996 if (retval
== 0 && actbytes
== 0)
1000 fp
->ff_unallocblocks
=
1001 reqbytes
/ HFSTOVCB(hfsmp
)->blockSize
;
1002 HFSTOVCB(hfsmp
)->loanedBlocks
+= fp
->ff_unallocblocks
;
1003 FTOC(fp
)->c_blocks
+= fp
->ff_unallocblocks
;
1004 fp
->ff_blocks
+= fp
->ff_unallocblocks
;
1006 reqbytes
-= actbytes
;
1010 (void) hfs_metafilelocking(hfsmp
, kHFSExtentsFileID
, LK_RELEASE
, p
);
1013 VTOC(ap
->a_vp
)->c_flag
|= C_MODIFIED
;
1016 retval
= MacToVFSError(
1017 MapFileBlockC (HFSTOVCB(hfsmp
),
1025 (void) hfs_metafilelocking(hfsmp
, kHFSExtentsFileID
, LK_RELEASE
, p
);
1027 if (retval
== E_NONE
) {
1028 /* Adjust the mapping information for invalid file ranges: */
1029 overlaptype
= rl_scan(&fp
->ff_invalidranges
,
1031 ap
->a_foffset
+ (off_t
)bytesContAvail
- 1,
1033 if (overlaptype
!= RL_NOOVERLAP
) {
1034 switch(overlaptype
) {
1035 case RL_MATCHINGOVERLAP
:
1036 case RL_OVERLAPCONTAINSRANGE
:
1037 case RL_OVERLAPSTARTSBEFORE
:
1038 /* There's no valid block for this byte offset: */
1039 *ap
->a_bpn
= (daddr_t
)-1;
1041 /* There's no point limiting the amount to be returned if the
1042 invalid range that was hit extends all the way to the EOF
1043 (i.e. there's no valid bytes between the end of this range
1044 and the file's EOF):
1046 if ((fp
->ff_size
> (invalid_range
->rl_end
+ 1)) &&
1047 (invalid_range
->rl_end
+ 1 - ap
->a_foffset
< bytesContAvail
)) {
1048 bytesContAvail
= invalid_range
->rl_end
+ 1 - ap
->a_foffset
;
1052 case RL_OVERLAPISCONTAINED
:
1053 case RL_OVERLAPENDSAFTER
:
1054 /* The range of interest hits an invalid block before the end: */
1055 if (invalid_range
->rl_start
== ap
->a_foffset
) {
1056 /* There's actually no valid information to be had starting here: */
1057 *ap
->a_bpn
= (daddr_t
)-1;
1058 if ((fp
->ff_size
> (invalid_range
->rl_end
+ 1)) &&
1059 (invalid_range
->rl_end
+ 1 - ap
->a_foffset
< bytesContAvail
)) {
1060 bytesContAvail
= invalid_range
->rl_end
+ 1 - ap
->a_foffset
;
1063 bytesContAvail
= invalid_range
->rl_start
- ap
->a_foffset
;
1067 if (bytesContAvail
> ap
->a_size
) bytesContAvail
= ap
->a_size
;
1070 if (ap
->a_run
) *ap
->a_run
= bytesContAvail
;
1074 *(int *)ap
->a_poff
= 0;
1081 * Read or write a buffer that is not contiguous on disk. We loop over
1082 * each device block, copying to or from caller's buffer.
1084 * We could be a bit more efficient by transferring as much data as is
1085 * contiguous. But since this routine should rarely be called, and that
1086 * would be more complicated; best to keep it simple.
1089 hfs_strategy_fragmented(struct buf
*bp
)
1091 register struct vnode
*vp
= bp
->b_vp
;
1092 register struct cnode
*cp
= VTOC(vp
);
1093 register struct vnode
*devvp
= cp
->c_devvp
;
1094 caddr_t ioaddr
; /* Address of fragment within bp */
1095 struct buf
*frag
= NULL
; /* For reading or writing a single block */
1097 long remaining
; /* Bytes (in bp) left to transfer */
1098 off_t offset
; /* Logical offset of current fragment in vp */
1099 u_long block_size
; /* Size of one device block (and one I/O) */
1101 /* Make sure we redo this mapping for the next I/O */
1102 bp
->b_blkno
= bp
->b_lblkno
;
1104 /* Set up the logical position and number of bytes to read/write */
1105 offset
= (off_t
) bp
->b_lblkno
* (off_t
) GetLogicalBlockSize(vp
);
1106 block_size
= VTOHFS(vp
)->hfs_phys_block_size
;
1108 /* Get an empty buffer to do the deblocking */
1109 frag
= geteblk(block_size
);
1110 if (ISSET(bp
->b_flags
, B_READ
))
1111 SET(frag
->b_flags
, B_READ
);
1113 for (ioaddr
= bp
->b_data
, remaining
= bp
->b_bcount
; remaining
!= 0;
1114 ioaddr
+= block_size
, offset
+= block_size
,
1115 remaining
-= block_size
) {
1116 frag
->b_resid
= frag
->b_bcount
;
1117 CLR(frag
->b_flags
, B_DONE
);
1119 /* Map the current position to a physical block number */
1120 retval
= VOP_CMAP(vp
, offset
, block_size
, &frag
->b_lblkno
,
1126 * Did we try to read a hole?
1127 * (Should never happen for metadata!)
1129 if ((long)frag
->b_lblkno
== -1) {
1130 bzero(ioaddr
, block_size
);
1134 /* If writing, copy before I/O */
1135 if (!ISSET(bp
->b_flags
, B_READ
))
1136 bcopy(ioaddr
, frag
->b_data
, block_size
);
1138 /* Call the device to do the I/O and wait for it */
1139 frag
->b_blkno
= frag
->b_lblkno
;
1140 frag
->b_vp
= devvp
; /* Used to dispatch via VOP_STRATEGY */
1141 frag
->b_dev
= devvp
->v_rdev
;
1142 retval
= VOP_STRATEGY(frag
);
1146 retval
= biowait(frag
);
1150 /* If reading, copy after the I/O */
1151 if (ISSET(bp
->b_flags
, B_READ
))
1152 bcopy(frag
->b_data
, ioaddr
, block_size
);
1156 SET(frag
->b_flags
, B_INVAL
);
1159 if ((bp
->b_error
= retval
) != 0)
1160 SET(bp
->b_flags
, B_ERROR
);
1162 biodone(bp
); /* This I/O is now complete */
1168 * Calculate the logical to physical mapping if not done already,
1169 * then call the device strategy routine.
1172 # IN struct buf *bp;
1176 struct vop_strategy_args
/* {
1180 register struct buf
*bp
= ap
->a_bp
;
1181 register struct vnode
*vp
= bp
->b_vp
;
1182 register struct cnode
*cp
= VTOC(vp
);
1185 size_t bytes_contig
;
1187 if ( !(bp
->b_flags
& B_VECTORLIST
)) {
1188 if (vp
->v_type
== VBLK
|| vp
->v_type
== VCHR
)
1189 panic("hfs_strategy: device vnode passed!");
1191 if (bp
->b_flags
& B_PAGELIST
) {
1193 * If we have a page list associated with this bp,
1194 * then go through cluster_bp since it knows how to
1195 * deal with a page request that might span non-
1196 * contiguous physical blocks on the disk...
1198 retval
= cluster_bp(bp
);
1200 bp
->b_dev
= vp
->v_rdev
;
1206 * If we don't already know the filesystem relative block
1207 * number then get it using VOP_BMAP(). If VOP_BMAP()
1208 * returns the block number as -1 then we've got a hole in
1209 * the file. Although HFS filesystems don't create files with
1210 * holes, invalidating of subranges of the file (lazy zero
1211 * filling) may create such a situation.
1213 if (bp
->b_blkno
== bp
->b_lblkno
) {
1214 offset
= (off_t
) bp
->b_lblkno
*
1215 (off_t
) GetLogicalBlockSize(vp
);
1217 if ((retval
= VOP_CMAP(vp
, offset
, bp
->b_bcount
,
1218 &bp
->b_blkno
, &bytes_contig
, NULL
))) {
1219 bp
->b_error
= retval
;
1220 bp
->b_flags
|= B_ERROR
;
1224 if (bytes_contig
< bp
->b_bcount
)
1227 * We were asked to read a block that wasn't
1228 * contiguous, so we have to read each of the
1229 * pieces and copy them into the buffer.
1230 * Since ordinary file I/O goes through
1231 * cluster_io (which won't ask us for
1232 * discontiguous data), this is probably an
1233 * attempt to read or write metadata.
1235 return hfs_strategy_fragmented(bp
);
1237 if ((long)bp
->b_blkno
== -1)
1240 if ((long)bp
->b_blkno
== -1) {
1244 if (bp
->b_validend
== 0) {
1246 * Record the exact size of the I/O transfer about to
1249 bp
->b_validend
= bp
->b_bcount
;
1253 bp
->b_dev
= vp
->v_rdev
;
1255 return VOCALL (vp
->v_op
, VOFFSET(vop_strategy
), ap
);
1261 #% truncate vp L L L
1264 IN struct vnode *vp;
1266 IN int flags; (IO_SYNC)
1267 IN struct ucred *cred;
1270 * Truncate a cnode to at most length size, freeing (or adding) the
1273 int hfs_truncate(ap
)
1274 struct vop_truncate_args
/* {
1278 struct ucred *a_cred;
1282 register struct vnode
*vp
= ap
->a_vp
;
1283 register struct cnode
*cp
= VTOC(vp
);
1284 struct filefork
*fp
= VTOF(vp
);
1290 off_t actualBytesAdded
;
1295 if (vp
->v_type
!= VREG
&& vp
->v_type
!= VLNK
)
1296 return (EISDIR
); /* cannot truncate an HFS directory! */
1298 length
= ap
->a_length
;
1299 blksize
= VTOVCB(vp
)->blockSize
;
1300 fileblocks
= fp
->ff_blocks
;
1301 filebytes
= (off_t
)fileblocks
* (off_t
)blksize
;
1303 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 7)) | DBG_FUNC_START
,
1304 (int)length
, (int)fp
->ff_size
, (int)filebytes
, 0, 0);
1309 if ((!ISHFSPLUS(VTOVCB(vp
))) && (length
> (off_t
)MAXHFSFILESIZE
))
1317 * We cannot just check if fp->ff_size == length (as an optimization)
1318 * since there may be extra physical blocks that also need truncation.
1321 if (retval
= hfs_getinoquota(cp
))
1326 * Lengthen the size of the file. We must ensure that the
1327 * last byte of the file is allocated. Since the smallest
1328 * value of ff_size is 0, length will be at least 1.
1330 if (length
> fp
->ff_size
) {
1332 retval
= hfs_chkdq(cp
, (int64_t)(roundup(length
- filebytes
, fp
->ff_clumpsize
)),
1338 * If we don't have enough physical space then
1339 * we need to extend the physical size.
1341 if (length
> filebytes
) {
1344 /* All or nothing and don't round up to clumpsize. */
1345 eflags
= kEFAllMask
| kEFNoClumpMask
;
1347 if (suser(ap
->a_cred
, NULL
) != 0)
1348 eflags
|= kEFReserveMask
; /* keep a reserve */
1350 /* lock extents b-tree (also protects volume bitmap) */
1351 retval
= hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_EXCLUSIVE
, ap
->a_p
);
1355 while ((length
> filebytes
) && (retval
== E_NONE
)) {
1356 bytesToAdd
= length
- filebytes
;
1357 retval
= MacToVFSError(ExtendFileC(VTOVCB(vp
),
1362 &actualBytesAdded
));
1364 filebytes
= (off_t
)fp
->ff_blocks
* (off_t
)blksize
;
1365 if (actualBytesAdded
== 0 && retval
== E_NONE
) {
1366 if (length
> filebytes
)
1371 (void) hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_RELEASE
, ap
->a_p
);
1375 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 7)) | DBG_FUNC_NONE
,
1376 (int)length
, (int)fp
->ff_size
, (int)filebytes
, 0, 0);
1379 if (!(ap
->a_flags
& IO_NOZEROFILL
)) {
1380 if (UBCINFOEXISTS(vp
) && retval
== E_NONE
) {
1381 struct rl_entry
*invalid_range
;
1385 zero_limit
= (fp
->ff_size
+ (PAGE_SIZE_64
- 1)) & ~PAGE_MASK_64
;
1386 if (length
< zero_limit
) zero_limit
= length
;
1388 if (length
> fp
->ff_size
) {
1389 /* Extending the file: time to fill out the current last page w. zeroes? */
1390 if ((fp
->ff_size
& PAGE_MASK_64
) &&
1391 (rl_scan(&fp
->ff_invalidranges
, fp
->ff_size
& ~PAGE_MASK_64
,
1392 fp
->ff_size
- 1, &invalid_range
) == RL_NOOVERLAP
)) {
1394 /* There's some valid data at the start of the (current) last page
1395 of the file, so zero out the remainder of that page to ensure the
1396 entire page contains valid data. Since there is no invalid range
1397 possible past the (current) eof, there's no need to remove anything
1398 from the invalid range list before calling cluster_write(): */
1399 VOP_DEVBLOCKSIZE(cp
->c_devvp
, &devBlockSize
);
1400 retval
= cluster_write(vp
, (struct uio
*) 0, fp
->ff_size
, zero_limit
,
1401 fp
->ff_size
, (off_t
)0, devBlockSize
,
1402 (ap
->a_flags
& IO_SYNC
) | IO_HEADZEROFILL
| IO_NOZERODIRTY
);
1403 if (retval
) goto Err_Exit
;
1405 /* Merely invalidate the remaining area, if necessary: */
1406 if (length
> zero_limit
) {
1407 rl_add(zero_limit
, length
- 1, &fp
->ff_invalidranges
);
1408 cp
->c_zftimeout
= time
.tv_sec
+ ZFTIMELIMIT
;
1411 /* The page containing the (current) eof is invalid: just add the
1412 remainder of the page to the invalid list, along with the area
1413 being newly allocated:
1415 rl_add(fp
->ff_size
, length
- 1, &fp
->ff_invalidranges
);
1416 cp
->c_zftimeout
= time
.tv_sec
+ ZFTIMELIMIT
;
1420 panic("hfs_truncate: invoked on non-UBC object?!");
1423 cp
->c_flag
|= C_UPDATE
;
1424 fp
->ff_size
= length
;
1427 ubc_setsize(vp
, fp
->ff_size
); /* XXX check errors */
1429 } else { /* Shorten the size of the file */
1431 if (fp
->ff_size
> length
) {
1433 * Any buffers that are past the truncation point need to be
1434 * invalidated (to maintain buffer cache consistency). For
1435 * simplicity, we invalidate all the buffers by calling vinvalbuf.
1438 ubc_setsize(vp
, length
); /* XXX check errors */
1440 vflags
= ((length
> 0) ? V_SAVE
: 0) | V_SAVEMETA
;
1441 retval
= vinvalbuf(vp
, vflags
, ap
->a_cred
, ap
->a_p
, 0, 0);
1443 /* Any space previously marked as invalid is now irrelevant: */
1444 rl_remove(length
, fp
->ff_size
- 1, &fp
->ff_invalidranges
);
1448 * Account for any unmapped blocks. Note that the new
1449 * file length can still end up with unmapped blocks.
1451 if (fp
->ff_unallocblocks
> 0) {
1452 u_int32_t finalblks
;
1454 /* lock extents b-tree */
1455 retval
= hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
,
1456 LK_EXCLUSIVE
, ap
->a_p
);
1460 VTOVCB(vp
)->loanedBlocks
-= fp
->ff_unallocblocks
;
1461 cp
->c_blocks
-= fp
->ff_unallocblocks
;
1462 fp
->ff_blocks
-= fp
->ff_unallocblocks
;
1463 fp
->ff_unallocblocks
= 0;
1465 finalblks
= (length
+ blksize
- 1) / blksize
;
1466 if (finalblks
> fp
->ff_blocks
) {
1467 /* calculate required unmapped blocks */
1468 fp
->ff_unallocblocks
= finalblks
- fp
->ff_blocks
;
1469 VTOVCB(vp
)->loanedBlocks
+= fp
->ff_unallocblocks
;
1470 cp
->c_blocks
+= fp
->ff_unallocblocks
;
1471 fp
->ff_blocks
+= fp
->ff_unallocblocks
;
1473 (void) hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
,
1474 LK_RELEASE
, ap
->a_p
);
1478 * For a TBE process the deallocation of the file blocks is
1479 * delayed until the file is closed. And hfs_close calls
1480 * truncate with the IO_NDELAY flag set. So when IO_NDELAY
1481 * isn't set, we make sure this isn't a TBE process.
1483 if ((ap
->a_flags
& IO_NDELAY
) || (!ISSET(ap
->a_p
->p_flag
, P_TBE
))) {
1485 off_t savedbytes
= ((off_t
)fp
->ff_blocks
* (off_t
)blksize
);
1487 /* lock extents b-tree (also protects volume bitmap) */
1488 retval
= hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_EXCLUSIVE
, ap
->a_p
);
1492 if (fp
->ff_unallocblocks
== 0)
1493 retval
= MacToVFSError(TruncateFileC(VTOVCB(vp
),
1494 (FCB
*)fp
, length
, false));
1496 (void) hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_RELEASE
, ap
->a_p
);
1497 filebytes
= (off_t
)fp
->ff_blocks
* (off_t
)blksize
;
1501 /* These are bytesreleased */
1502 (void) hfs_chkdq(cp
, (int64_t)-(savedbytes
- filebytes
), NOCRED
, 0);
1505 /* Only set update flag if the logical length changes */
1506 if (fp
->ff_size
!= length
)
1507 cp
->c_flag
|= C_UPDATE
;
1508 fp
->ff_size
= length
;
1510 cp
->c_flag
|= C_CHANGE
;
1511 retval
= VOP_UPDATE(vp
, &tv
, &tv
, MNT_WAIT
);
1513 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 7)) | DBG_FUNC_NONE
,
1514 -1, -1, -1, retval
, 0);
1519 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 7)) | DBG_FUNC_END
,
1520 (int)length
, (int)fp
->ff_size
, (int)filebytes
, retval
, 0);
1529 #% allocate vp L L L
1532 IN struct vnode *vp;
1535 OUT off_t *bytesallocated;
1537 IN struct ucred *cred;
1540 * allocate a cnode to at most length size
1542 int hfs_allocate(ap
)
1543 struct vop_allocate_args
/* {
1547 off_t *a_bytesallocated;
1549 struct ucred *a_cred;
1553 struct vnode
*vp
= ap
->a_vp
;
1554 struct cnode
*cp
= VTOC(vp
);
1555 struct filefork
*fp
= VTOF(vp
);
1556 off_t length
= ap
->a_length
;
1558 off_t moreBytesRequested
;
1559 off_t actualBytesAdded
;
1564 int retval
, retval2
;
1566 UInt32 extendFlags
=0; /* For call to ExtendFileC */
1568 *(ap
->a_bytesallocated
) = 0;
1569 fileblocks
= fp
->ff_blocks
;
1570 filebytes
= (off_t
)fileblocks
* (off_t
)VTOVCB(vp
)->blockSize
;
1572 if (length
< (off_t
)0)
1574 if (vp
->v_type
!= VREG
&& vp
->v_type
!= VLNK
)
1576 if ((ap
->a_flags
& ALLOCATEFROMVOL
) && (length
<= filebytes
))
1579 /* Fill in the flags word for the call to Extend the file */
1581 if (ap
->a_flags
& ALLOCATECONTIG
)
1582 extendFlags
|= kEFContigMask
;
1584 if (ap
->a_flags
& ALLOCATEALL
)
1585 extendFlags
|= kEFAllMask
;
1587 if (suser(ap
->a_cred
, NULL
) != 0)
1588 extendFlags
|= kEFReserveMask
;
1593 startingPEOF
= filebytes
;
1595 if (ap
->a_flags
& ALLOCATEFROMPEOF
)
1596 length
+= filebytes
;
1597 else if (ap
->a_flags
& ALLOCATEFROMVOL
)
1598 blockHint
= ap
->a_offset
/ VTOVCB(vp
)->blockSize
;
1600 /* If no changes are necesary, then we're done */
1601 if (filebytes
== length
)
1605 * Lengthen the size of the file. We must ensure that the
1606 * last byte of the file is allocated. Since the smallest
1607 * value of filebytes is 0, length will be at least 1.
1609 if (length
> filebytes
) {
1610 moreBytesRequested
= length
- filebytes
;
1613 retval
= hfs_chkdq(cp
, (int64_t)(roundup(moreBytesRequested
, fp
->ff_clumpsize
)),
1619 /* lock extents b-tree (also protects volume bitmap) */
1620 retval
= hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_EXCLUSIVE
, ap
->a_p
);
1621 if (retval
) goto Err_Exit
;
1623 retval
= MacToVFSError(ExtendFileC(VTOVCB(vp
),
1628 &actualBytesAdded
));
1630 *(ap
->a_bytesallocated
) = actualBytesAdded
;
1631 filebytes
= (off_t
)fp
->ff_blocks
* (off_t
)VTOVCB(vp
)->blockSize
;
1632 (void) hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_RELEASE
, ap
->a_p
);
1635 * if we get an error and no changes were made then exit
1636 * otherwise we must do the VOP_UPDATE to reflect the changes
1638 if (retval
&& (startingPEOF
== filebytes
))
1642 * Adjust actualBytesAdded to be allocation block aligned, not
1643 * clump size aligned.
1644 * NOTE: So what we are reporting does not affect reality
1645 * until the file is closed, when we truncate the file to allocation
1648 if ((actualBytesAdded
!= 0) && (moreBytesRequested
< actualBytesAdded
))
1649 *(ap
->a_bytesallocated
) =
1650 roundup(moreBytesRequested
, (off_t
)VTOVCB(vp
)->blockSize
);
1652 } else { /* Shorten the size of the file */
1654 if (fp
->ff_size
> length
) {
1656 * Any buffers that are past the truncation point need to be
1657 * invalidated (to maintain buffer cache consistency). For
1658 * simplicity, we invalidate all the buffers by calling vinvalbuf.
1660 vflags
= ((length
> 0) ? V_SAVE
: 0) | V_SAVEMETA
;
1661 (void) vinvalbuf(vp
, vflags
, ap
->a_cred
, ap
->a_p
, 0, 0);
1664 /* lock extents b-tree (also protects volume bitmap) */
1665 retval
= hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_EXCLUSIVE
, ap
->a_p
);
1666 if (retval
) goto Err_Exit
;
1668 retval
= MacToVFSError(
1674 (void) hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_RELEASE
, ap
->a_p
);
1675 filebytes
= (off_t
)fp
->ff_blocks
* (off_t
)VTOVCB(vp
)->blockSize
;
1677 * if we get an error and no changes were made then exit
1678 * otherwise we must do the VOP_UPDATE to reflect the changes
1680 if (retval
&& (startingPEOF
== filebytes
)) goto Err_Exit
;
1682 /* These are bytesreleased */
1683 (void) hfs_chkdq(cp
, (int64_t)-((startingPEOF
- filebytes
)), NOCRED
,0);
1686 if (fp
->ff_size
> filebytes
) {
1687 fp
->ff_size
= filebytes
;
1690 ubc_setsize(vp
, fp
->ff_size
); /* XXX check errors */
1695 cp
->c_flag
|= C_CHANGE
| C_UPDATE
;
1696 retval2
= VOP_UPDATE(vp
, &tv
, &tv
, MNT_WAIT
);
1706 * pagein for HFS filesystem
1710 struct vop_pagein_args
/* {
1713 vm_offset_t a_pl_offset,
1716 struct ucred *a_cred,
1720 register struct vnode
*vp
= ap
->a_vp
;
1721 int devBlockSize
= 0;
1724 if (vp
->v_type
!= VREG
&& vp
->v_type
!= VLNK
)
1725 panic("hfs_pagein: vp not UBC type\n");
1727 VOP_DEVBLOCKSIZE(VTOC(vp
)->c_devvp
, &devBlockSize
);
1729 error
= cluster_pagein(vp
, ap
->a_pl
, ap
->a_pl_offset
, ap
->a_f_offset
,
1730 ap
->a_size
, (off_t
)VTOF(vp
)->ff_size
, devBlockSize
,
1736 * pageout for HFS filesystem.
1740 struct vop_pageout_args
/* {
1743 vm_offset_t a_pl_offset,
1746 struct ucred *a_cred,
1750 struct vnode
*vp
= ap
->a_vp
;
1751 struct cnode
*cp
= VTOC(vp
);
1752 struct filefork
*fp
= VTOF(vp
);
1754 int devBlockSize
= 0;
1759 panic("hfs_pageout: Not a VREG: vp=%x", vp
);
1761 VOP_DEVBLOCKSIZE(cp
->c_devvp
, &devBlockSize
);
1762 filesize
= fp
->ff_size
;
1763 end_of_range
= ap
->a_f_offset
+ ap
->a_size
- 1;
1765 if (end_of_range
>= filesize
)
1766 end_of_range
= (off_t
)(filesize
- 1);
1767 if (ap
->a_f_offset
< filesize
)
1768 rl_remove(ap
->a_f_offset
, end_of_range
, &fp
->ff_invalidranges
);
1770 retval
= cluster_pageout(vp
, ap
->a_pl
, ap
->a_pl_offset
, ap
->a_f_offset
, ap
->a_size
,
1771 filesize
, devBlockSize
, ap
->a_flags
);
1774 * If we successfully wrote any data, and we are not the superuser
1775 * we clear the setuid and setgid bits as a precaution against
1778 if (retval
== 0 && ap
->a_cred
&& ap
->a_cred
->cr_uid
!= 0)
1779 cp
->c_mode
&= ~(S_ISUID
| S_ISGID
);
1785 * Intercept B-Tree node writes to unswap them if necessary.
1788 # IN struct buf *bp;
1792 struct vop_bwrite_args
/* {
1797 #if BYTE_ORDER == LITTLE_ENDIAN
1798 register struct buf
*bp
= ap
->a_bp
;
1799 register struct vnode
*vp
= bp
->b_vp
;
1800 BlockDescriptor block
;
1802 /* Trap B-Tree writes */
1803 if ((VTOC(vp
)->c_fileid
== kHFSExtentsFileID
) ||
1804 (VTOC(vp
)->c_fileid
== kHFSCatalogFileID
)) {
1806 /* Swap if the B-Tree node is in native byte order */
1807 if (((UInt16
*)((char *)bp
->b_data
+ bp
->b_bcount
- 2))[0] == 0x000e) {
1808 /* Prepare the block pointer */
1809 block
.blockHeader
= bp
;
1810 block
.buffer
= bp
->b_data
;
1811 /* not found in cache ==> came from disk */
1812 block
.blockReadFromDisk
= (bp
->b_flags
& B_CACHE
) == 0;
1813 block
.blockSize
= bp
->b_bcount
;
1815 /* Endian un-swap B-Tree node */
1816 SWAP_BT_NODE (&block
, ISHFSPLUS (VTOVCB(vp
)), VTOC(vp
)->c_fileid
, 1);
1819 /* We don't check to make sure that it's 0x0e00 because it could be all zeros */
1822 /* This buffer shouldn't be locked anymore but if it is clear it */
1823 if (ISSET(ap
->a_bp
->b_flags
, B_LOCKED
)) {
1824 CLR(ap
->a_bp
->b_flags
, B_LOCKED
);
1825 printf("hfs_bwrite: called with lock bit set\n");
1827 retval
= vn_bwrite (ap
);