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
;
270 struct hfsmount
*hfsmp
;
271 int started_tr
= 0, grabbed_lock
= 0;
273 ioflag
= ap
->a_ioflag
;
275 if (uio
->uio_offset
< 0)
277 if (uio
->uio_resid
== 0)
279 if (vp
->v_type
!= VREG
&& vp
->v_type
!= VLNK
)
280 return (EISDIR
); /* Can only write files */
285 fileblocks
= fp
->ff_blocks
;
286 filebytes
= (off_t
)fileblocks
* (off_t
)vcb
->blockSize
;
288 if (ioflag
& IO_APPEND
)
289 uio
->uio_offset
= fp
->ff_size
;
290 if ((cp
->c_flags
& APPEND
) && uio
->uio_offset
!= fp
->ff_size
)
293 // XXXdbg - don't allow modification of the journal or journal_info_block
294 if (VTOHFS(vp
)->jnl
&& cp
->c_datafork
) {
295 struct HFSPlusExtentDescriptor
*extd
;
297 extd
= &cp
->c_datafork
->ff_data
.cf_extents
[0];
298 if (extd
->startBlock
== VTOVCB(vp
)->vcbJinfoBlock
|| extd
->startBlock
== VTOHFS(vp
)->jnl_start
) {
303 writelimit
= uio
->uio_offset
+ uio
->uio_resid
;
306 * Maybe this should be above the vnode op call, but so long as
307 * file servers have no limits, I don't think it matters.
310 if (vp
->v_type
== VREG
&& p
&&
311 writelimit
> p
->p_rlimit
[RLIMIT_FSIZE
].rlim_cur
) {
317 VOP_DEVBLOCKSIZE(cp
->c_devvp
, &devBlockSize
);
319 resid
= uio
->uio_resid
;
320 origFileSize
= fp
->ff_size
;
321 eflags
= kEFDeferMask
; /* defer file block allocations */
322 filebytes
= (off_t
)fp
->ff_blocks
* (off_t
)vcb
->blockSize
;
325 * NOTE: In the following loop there are two positions tracked:
326 * currOffset is the current I/O starting offset. currOffset
327 * is never >LEOF; the LEOF is nudged along with currOffset as
328 * data is zeroed or written. uio->uio_offset is the start of
329 * the current I/O operation. It may be arbitrarily beyond
332 * The following is true at all times:
333 * currOffset <= LEOF <= uio->uio_offset <= writelimit
335 currOffset
= MIN(uio
->uio_offset
, fp
->ff_size
);
337 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 0)) | DBG_FUNC_START
,
338 (int)uio
->uio_offset
, uio
->uio_resid
, (int)fp
->ff_size
, (int)filebytes
, 0);
341 /* Now test if we need to extend the file */
342 /* Doing so will adjust the filebytes for us */
345 if(writelimit
> filebytes
) {
346 bytesToAdd
= writelimit
- filebytes
;
348 retval
= hfs_chkdq(cp
, (int64_t)(roundup(bytesToAdd
, vcb
->blockSize
)),
356 if (writelimit
> filebytes
) {
357 hfs_global_shared_lock_acquire(hfsmp
);
360 if (hfsmp
->jnl
&& (writelimit
> filebytes
)) {
361 if (journal_start_transaction(hfsmp
->jnl
) != 0) {
362 hfs_global_shared_lock_release(hfsmp
);
368 while (writelimit
> filebytes
) {
370 bytesToAdd
= writelimit
- filebytes
;
371 if (suser(ap
->a_cred
, NULL
) != 0)
372 eflags
|= kEFReserveMask
;
374 /* lock extents b-tree (also protects volume bitmap) */
375 retval
= hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_EXCLUSIVE
, current_proc());
376 if (retval
!= E_NONE
)
379 retval
= MacToVFSError(ExtendFileC (vcb
, (FCB
*)fp
, bytesToAdd
,
380 0, eflags
, &actualBytesAdded
));
382 (void) hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_RELEASE
, p
);
383 if ((actualBytesAdded
== 0) && (retval
== E_NONE
))
385 if (retval
!= E_NONE
)
387 filebytes
= (off_t
)fp
->ff_blocks
* (off_t
)vcb
->blockSize
;
388 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 0)) | DBG_FUNC_NONE
,
389 (int)uio
->uio_offset
, uio
->uio_resid
, (int)fp
->ff_size
, (int)filebytes
, 0);
394 hfs_flushvolumeheader(hfsmp
, MNT_NOWAIT
, 0);
395 journal_end_transaction(hfsmp
->jnl
);
399 hfs_global_shared_lock_release(hfsmp
);
403 if (UBCISVALID(vp
) && retval
== E_NONE
) {
409 off_t io_start
, io_end
;
411 struct rl_entry
*invalid_range
;
413 if (writelimit
> fp
->ff_size
)
414 filesize
= writelimit
;
416 filesize
= fp
->ff_size
;
418 lflag
= (ioflag
& IO_SYNC
);
420 if (uio
->uio_offset
<= fp
->ff_size
) {
421 zero_off
= uio
->uio_offset
& ~PAGE_MASK_64
;
423 /* Check to see whether the area between the zero_offset and the start
424 of the transfer to see whether is invalid and should be zero-filled
425 as part of the transfer:
427 if (rl_scan(&fp
->ff_invalidranges
, zero_off
, uio
->uio_offset
- 1, &invalid_range
) != RL_NOOVERLAP
)
428 lflag
|= IO_HEADZEROFILL
;
430 off_t eof_page_base
= fp
->ff_size
& ~PAGE_MASK_64
;
432 /* The bytes between fp->ff_size and uio->uio_offset must never be
433 read without being zeroed. The current last block is filled with zeroes
434 if it holds valid data but in all cases merely do a little bookkeeping
435 to track the area from the end of the current last page to the start of
436 the area actually written. For the same reason only the bytes up to the
437 start of the page where this write will start is invalidated; any remainder
438 before uio->uio_offset is explicitly zeroed as part of the cluster_write.
440 Note that inval_start, the start of the page after the current EOF,
441 may be past the start of the write, in which case the zeroing
442 will be handled by the cluser_write of the actual data.
444 inval_start
= (fp
->ff_size
+ (PAGE_SIZE_64
- 1)) & ~PAGE_MASK_64
;
445 inval_end
= uio
->uio_offset
& ~PAGE_MASK_64
;
446 zero_off
= fp
->ff_size
;
448 if ((fp
->ff_size
& PAGE_MASK_64
) &&
449 (rl_scan(&fp
->ff_invalidranges
,
452 &invalid_range
) != RL_NOOVERLAP
)) {
453 /* The page containing the EOF is not valid, so the
454 entire page must be made inaccessible now. If the write
455 starts on a page beyond the page containing the eof
456 (inval_end > eof_page_base), add the
457 whole page to the range to be invalidated. Otherwise
458 (i.e. if the write starts on the same page), zero-fill
459 the entire page explicitly now:
461 if (inval_end
> eof_page_base
) {
462 inval_start
= eof_page_base
;
464 zero_off
= eof_page_base
;
468 if (inval_start
< inval_end
) {
469 /* There's some range of data that's going to be marked invalid */
471 if (zero_off
< inval_start
) {
472 /* The pages between inval_start and inval_end are going to be invalidated,
473 and the actual write will start on a page past inval_end. Now's the last
474 chance to zero-fill the page containing the EOF:
476 retval
= cluster_write(vp
, (struct uio
*) 0,
477 fp
->ff_size
, inval_start
,
478 zero_off
, (off_t
)0, devBlockSize
,
479 lflag
| IO_HEADZEROFILL
| IO_NOZERODIRTY
);
480 if (retval
) goto ioerr_exit
;
483 /* Mark the remaining area of the newly allocated space as invalid: */
484 rl_add(inval_start
, inval_end
- 1 , &fp
->ff_invalidranges
);
485 cp
->c_zftimeout
= time
.tv_sec
+ ZFTIMELIMIT
;
486 zero_off
= fp
->ff_size
= inval_end
;
489 if (uio
->uio_offset
> zero_off
) lflag
|= IO_HEADZEROFILL
;
492 /* Check to see whether the area between the end of the write and the end of
493 the page it falls in is invalid and should be zero-filled as part of the transfer:
495 tail_off
= (writelimit
+ (PAGE_SIZE_64
- 1)) & ~PAGE_MASK_64
;
496 if (tail_off
> filesize
) tail_off
= filesize
;
497 if (tail_off
> writelimit
) {
498 if (rl_scan(&fp
->ff_invalidranges
, writelimit
, tail_off
- 1, &invalid_range
) != RL_NOOVERLAP
) {
499 lflag
|= IO_TAILZEROFILL
;
504 * if the write starts beyond the current EOF (possibly advanced in the
505 * zeroing of the last block, above), then we'll zero fill from the current EOF
506 * to where the write begins:
508 * NOTE: If (and ONLY if) the portion of the file about to be written is
509 * before the current EOF it might be marked as invalid now and must be
510 * made readable (removed from the invalid ranges) before cluster_write
513 io_start
= (lflag
& IO_HEADZEROFILL
) ? zero_off
: uio
->uio_offset
;
514 io_end
= (lflag
& IO_TAILZEROFILL
) ? tail_off
: writelimit
;
515 if (io_start
< fp
->ff_size
) {
516 rl_remove(io_start
, io_end
- 1, &fp
->ff_invalidranges
);
518 retval
= cluster_write(vp
, uio
, fp
->ff_size
, filesize
, zero_off
,
519 tail_off
, devBlockSize
, lflag
| IO_NOZERODIRTY
);
521 if (uio
->uio_offset
> fp
->ff_size
) {
522 fp
->ff_size
= uio
->uio_offset
;
524 ubc_setsize(vp
, fp
->ff_size
); /* XXX check errors */
526 if (resid
> uio
->uio_resid
)
527 cp
->c_flag
|= C_CHANGE
| C_UPDATE
;
529 while (retval
== E_NONE
&& uio
->uio_resid
> 0) {
530 logBlockNo
= currOffset
/ PAGE_SIZE
;
531 blkoffset
= currOffset
& PAGE_MASK
;
533 if ((filebytes
- currOffset
) < PAGE_SIZE_64
)
534 fragSize
= filebytes
- ((off_t
)logBlockNo
* PAGE_SIZE_64
);
536 fragSize
= PAGE_SIZE
;
537 xfersize
= fragSize
- blkoffset
;
539 /* Make any adjustments for boundary conditions */
540 if (currOffset
+ (off_t
)xfersize
> writelimit
)
541 xfersize
= writelimit
- currOffset
;
544 * There is no need to read into bp if:
545 * We start on a block boundary and will overwrite the whole block
549 if ((blkoffset
== 0) && (xfersize
>= fragSize
)) {
550 bp
= getblk(vp
, logBlockNo
, fragSize
, 0, 0, BLK_READ
);
553 if (bp
->b_blkno
== -1) {
555 retval
= EIO
; /* XXX */
560 if (currOffset
== fp
->ff_size
&& blkoffset
== 0) {
561 bp
= getblk(vp
, logBlockNo
, fragSize
, 0, 0, BLK_READ
);
563 if (bp
->b_blkno
== -1) {
565 retval
= EIO
; /* XXX */
570 * This I/O transfer is not sufficiently aligned,
571 * so read the affected block into a buffer:
573 retval
= bread(vp
, logBlockNo
, fragSize
, ap
->a_cred
, &bp
);
574 if (retval
!= E_NONE
) {
582 /* See if we are starting to write within file boundaries:
583 * If not, then we need to present a "hole" for the area
584 * between the current EOF and the start of the current
587 * Note that currOffset is only less than uio_offset if
588 * uio_offset > LEOF...
590 if (uio
->uio_offset
> currOffset
) {
591 clearSize
= MIN(uio
->uio_offset
- currOffset
, xfersize
);
592 bzero(bp
->b_data
+ blkoffset
, clearSize
);
593 currOffset
+= clearSize
;
594 blkoffset
+= clearSize
;
595 xfersize
-= clearSize
;
599 retval
= uiomove((caddr_t
)bp
->b_data
+ blkoffset
, (int)xfersize
, uio
);
600 currOffset
+= xfersize
;
603 if (ioflag
& IO_SYNC
) {
604 (void)VOP_BWRITE(bp
);
605 } else if ((xfersize
+ blkoffset
) == fragSize
) {
606 bp
->b_flags
|= B_AGE
;
612 /* Update the EOF if we just extended the file
613 * (the PEOF has already been moved out and the
614 * block mapping table has been updated):
616 if (currOffset
> fp
->ff_size
) {
617 fp
->ff_size
= currOffset
;
619 ubc_setsize(vp
, fp
->ff_size
); /* XXX check errors */
621 if (retval
|| (resid
== 0))
623 cp
->c_flag
|= C_CHANGE
| C_UPDATE
;
629 * If we successfully wrote any data, and we are not the superuser
630 * we clear the setuid and setgid bits as a precaution against
633 if (resid
> uio
->uio_resid
&& ap
->a_cred
&& ap
->a_cred
->cr_uid
!= 0)
634 cp
->c_mode
&= ~(S_ISUID
| S_ISGID
);
637 if (ioflag
& IO_UNIT
) {
638 (void)VOP_TRUNCATE(vp
, origFileSize
,
639 ioflag
& IO_SYNC
, ap
->a_cred
, uio
->uio_procp
);
640 uio
->uio_offset
-= resid
- uio
->uio_resid
;
641 uio
->uio_resid
= resid
;
642 filebytes
= (off_t
)fp
->ff_blocks
* (off_t
)vcb
->blockSize
;
644 } else if (resid
> uio
->uio_resid
&& (ioflag
& IO_SYNC
)) {
646 retval
= VOP_UPDATE(vp
, &tv
, &tv
, 1);
649 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 0)) | DBG_FUNC_END
,
650 (int)uio
->uio_offset
, uio
->uio_resid
, (int)fp
->ff_size
, (int)filebytes
, 0);
665 IN struct ucred *cred;
674 struct vop_ioctl_args
/* {
679 struct ucred *a_cred;
683 switch (ap
->a_command
) {
685 register struct cnode
*cp
;
686 register struct vnode
*vp
;
687 register struct radvisory
*ra
;
689 int devBlockSize
= 0;
694 if (vp
->v_type
!= VREG
)
697 VOP_LEASE(vp
, ap
->a_p
, ap
->a_cred
, LEASE_READ
);
698 error
= vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, ap
->a_p
);
702 ra
= (struct radvisory
*)(ap
->a_data
);
706 if (ra
->ra_offset
>= fp
->ff_size
) {
707 VOP_UNLOCK(vp
, 0, ap
->a_p
);
710 VOP_DEVBLOCKSIZE(cp
->c_devvp
, &devBlockSize
);
712 error
= advisory_read(vp
, fp
->ff_size
, ra
->ra_offset
, ra
->ra_count
, devBlockSize
);
713 VOP_UNLOCK(vp
, 0, ap
->a_p
);
718 case 2: /* F_READBOOTBLOCKS */
719 case 3: /* F_WRITEBOOTBLOCKS */
721 struct vnode
*vp
= ap
->a_vp
;
722 struct vnode
*devvp
= NULL
;
723 struct fbootstraptransfer
*btd
= (struct fbootstraptransfer
*)ap
->a_data
;
733 if ((vp
->v_flag
& VROOT
) == 0) return EINVAL
;
734 if (btd
->fbt_offset
+ btd
->fbt_length
> 1024) return EINVAL
;
736 devvp
= VTOHFS(vp
)->hfs_devvp
;
737 aiov
.iov_base
= btd
->fbt_buffer
;
738 aiov
.iov_len
= btd
->fbt_length
;
740 auio
.uio_iov
= &aiov
;
742 auio
.uio_offset
= btd
->fbt_offset
;
743 auio
.uio_resid
= btd
->fbt_length
;
744 auio
.uio_segflg
= UIO_USERSPACE
;
745 auio
.uio_rw
= (ap
->a_command
== 3) ? UIO_WRITE
: UIO_READ
; /* F_WRITEBOOTSTRAP / F_READBOOTSTRAP */
746 auio
.uio_procp
= ap
->a_p
;
748 VOP_DEVBLOCKSIZE(devvp
, &devBlockSize
);
750 while (auio
.uio_resid
> 0) {
751 blockNumber
= auio
.uio_offset
/ devBlockSize
;
752 error
= bread(devvp
, blockNumber
, devBlockSize
, ap
->a_cred
, &bp
);
758 blockOffset
= auio
.uio_offset
% devBlockSize
;
759 xfersize
= devBlockSize
- blockOffset
;
760 error
= uiomove((caddr_t
)bp
->b_data
+ blockOffset
, (int)xfersize
, &auio
);
765 if (auio
.uio_rw
== UIO_WRITE
) {
766 error
= VOP_BWRITE(bp
);
767 if (error
) return error
;
775 case _IOC(IOC_OUT
,'h', 4, 0): /* Create date in local time */
777 *(time_t *)(ap
->a_data
) = to_bsd_time(VTOVCB(ap
->a_vp
)->localCreateDate
);
785 /* Should never get here */
792 struct vop_select_args
/* {
796 struct ucred *a_cred;
802 * We should really check to see if I/O is possible.
808 * Bmap converts a the logical block number of a file to its physical block
809 * number on the disk.
813 * vp - address of vnode file the file
814 * bn - which logical block to convert to a physical block number.
815 * vpp - returns the vnode for the block special file holding the filesystem
816 * containing the file of interest
817 * bnp - address of where to return the filesystem physical block number
824 OUT struct vnode **vpp;
829 * Converts a logical block number to a physical block, and optionally returns
830 * the amount of remaining blocks in a run. The logical block is based on hfsNode.logBlockSize.
831 * The physical block number is based on the device block size, currently its 512.
832 * The block run is returned in logical blocks, and is the REMAINING amount of blocks
837 struct vop_bmap_args
/* {
840 struct vnode **a_vpp;
845 struct vnode
*vp
= ap
->a_vp
;
846 struct cnode
*cp
= VTOC(vp
);
847 struct filefork
*fp
= VTOF(vp
);
848 struct hfsmount
*hfsmp
= VTOHFS(vp
);
850 daddr_t logBlockSize
;
851 size_t bytesContAvail
= 0;
853 struct proc
*p
= NULL
;
855 struct rl_entry
*invalid_range
;
856 enum rl_overlaptype overlaptype
;
859 * Check for underlying vnode requests and ensure that logical
860 * to physical mapping is requested.
862 if (ap
->a_vpp
!= NULL
)
863 *ap
->a_vpp
= cp
->c_devvp
;
864 if (ap
->a_bnp
== NULL
)
867 /* Only clustered I/O should have delayed allocations. */
868 DBG_ASSERT(fp
->ff_unallocblocks
== 0);
870 logBlockSize
= GetLogicalBlockSize(vp
);
871 blockposition
= (off_t
)ap
->a_bn
* (off_t
)logBlockSize
;
873 lockExtBtree
= overflow_extents(fp
);
876 retval
= hfs_metafilelocking(hfsmp
, kHFSExtentsFileID
,
877 LK_EXCLUSIVE
| LK_CANRECURSE
, p
);
882 retval
= MacToVFSError(
883 MapFileBlockC (HFSTOVCB(hfsmp
),
890 if (lockExtBtree
) (void) hfs_metafilelocking(hfsmp
, kHFSExtentsFileID
, LK_RELEASE
, p
);
892 if (retval
== E_NONE
) {
893 /* Adjust the mapping information for invalid file ranges: */
894 overlaptype
= rl_scan(&fp
->ff_invalidranges
,
896 blockposition
+ MAXPHYSIO
- 1,
898 if (overlaptype
!= RL_NOOVERLAP
) {
899 switch(overlaptype
) {
900 case RL_MATCHINGOVERLAP
:
901 case RL_OVERLAPCONTAINSRANGE
:
902 case RL_OVERLAPSTARTSBEFORE
:
903 /* There's no valid block for this byte offset: */
904 *ap
->a_bnp
= (daddr_t
)-1;
905 bytesContAvail
= invalid_range
->rl_end
+ 1 - blockposition
;
908 case RL_OVERLAPISCONTAINED
:
909 case RL_OVERLAPENDSAFTER
:
910 /* The range of interest hits an invalid block before the end: */
911 if (invalid_range
->rl_start
== blockposition
) {
912 /* There's actually no valid information to be had starting here: */
913 *ap
->a_bnp
= (daddr_t
)-1;
914 if ((fp
->ff_size
> (invalid_range
->rl_end
+ 1)) &&
915 (invalid_range
->rl_end
+ 1 - blockposition
< bytesContAvail
)) {
916 bytesContAvail
= invalid_range
->rl_end
+ 1 - blockposition
;
919 bytesContAvail
= invalid_range
->rl_start
- blockposition
;
923 if (bytesContAvail
> MAXPHYSIO
) bytesContAvail
= MAXPHYSIO
;
926 /* Figure out how many read ahead blocks there are */
927 if (ap
->a_runp
!= NULL
) {
928 if (can_cluster(logBlockSize
)) {
929 /* Make sure this result never goes negative: */
930 *ap
->a_runp
= (bytesContAvail
< logBlockSize
) ? 0 : (bytesContAvail
/ logBlockSize
) - 1;
940 /* blktooff converts logical block number to file offset */
944 struct vop_blktooff_args
/* {
950 if (ap
->a_vp
== NULL
)
952 *ap
->a_offset
= (off_t
)ap
->a_lblkno
* PAGE_SIZE_64
;
959 struct vop_offtoblk_args
/* {
965 if (ap
->a_vp
== NULL
)
967 *ap
->a_lblkno
= ap
->a_offset
/ PAGE_SIZE_64
;
974 struct vop_cmap_args
/* {
983 struct hfsmount
*hfsmp
= VTOHFS(ap
->a_vp
);
984 struct filefork
*fp
= VTOF(ap
->a_vp
);
985 size_t bytesContAvail
= 0;
987 int lockExtBtree
= 0;
988 struct proc
*p
= NULL
;
989 struct rl_entry
*invalid_range
;
990 enum rl_overlaptype overlaptype
;
991 int started_tr
= 0, grabbed_lock
= 0;
994 * Check for underlying vnode requests and ensure that logical
995 * to physical mapping is requested.
997 if (ap
->a_bpn
== NULL
)
1002 if (fp
->ff_unallocblocks
) {
1006 hfs_global_shared_lock_acquire(hfsmp
);
1010 if (journal_start_transaction(hfsmp
->jnl
) != 0) {
1011 hfs_global_shared_lock_release(hfsmp
);
1018 if (retval
= hfs_metafilelocking(hfsmp
, kHFSExtentsFileID
, LK_EXCLUSIVE
| LK_CANRECURSE
, p
)) {
1020 journal_end_transaction(hfsmp
->jnl
);
1023 hfs_global_shared_lock_release(hfsmp
);
1027 } else if (overflow_extents(fp
)) {
1029 if (retval
= hfs_metafilelocking(hfsmp
, kHFSExtentsFileID
, LK_EXCLUSIVE
| LK_CANRECURSE
, p
)) {
1035 * Check for any delayed allocations.
1037 if (fp
->ff_unallocblocks
) {
1038 SInt64 reqbytes
, actbytes
;
1041 // Make sure we have a transaction. It's possible
1042 // that we came in and fp->ff_unallocblocks was zero
1043 // but during the time we blocked acquiring the extents
1044 // btree, ff_unallocblocks became non-zero and so we
1045 // will need to start a transaction.
1047 if (hfsmp
->jnl
&& started_tr
== 0) {
1049 (void) hfs_metafilelocking(hfsmp
, kHFSExtentsFileID
, LK_RELEASE
, p
);
1056 reqbytes
= (SInt64
)fp
->ff_unallocblocks
*
1057 (SInt64
)HFSTOVCB(hfsmp
)->blockSize
;
1059 * Release the blocks on loan and aquire some real ones.
1060 * Note that we can race someone else for these blocks
1061 * (and lose) so cmap needs to handle a failure here.
1062 * Currently this race can't occur because all allocations
1063 * are protected by an exclusive lock on the Extents
1066 HFSTOVCB(hfsmp
)->loanedBlocks
-= fp
->ff_unallocblocks
;
1067 FTOC(fp
)->c_blocks
-= fp
->ff_unallocblocks
;
1068 fp
->ff_blocks
-= fp
->ff_unallocblocks
;
1069 fp
->ff_unallocblocks
= 0;
1071 while (retval
== 0 && reqbytes
> 0) {
1072 retval
= MacToVFSError(ExtendFileC(HFSTOVCB(hfsmp
),
1073 (FCB
*)fp
, reqbytes
, 0,
1074 kEFAllMask
| kEFNoClumpMask
, &actbytes
));
1075 if (retval
== 0 && actbytes
== 0)
1079 fp
->ff_unallocblocks
=
1080 reqbytes
/ HFSTOVCB(hfsmp
)->blockSize
;
1081 HFSTOVCB(hfsmp
)->loanedBlocks
+= fp
->ff_unallocblocks
;
1082 FTOC(fp
)->c_blocks
+= fp
->ff_unallocblocks
;
1083 fp
->ff_blocks
+= fp
->ff_unallocblocks
;
1085 reqbytes
-= actbytes
;
1089 (void) hfs_metafilelocking(hfsmp
, kHFSExtentsFileID
, LK_RELEASE
, p
);
1091 hfs_flushvolumeheader(hfsmp
, MNT_NOWAIT
, 0);
1092 journal_end_transaction(hfsmp
->jnl
);
1095 hfs_global_shared_lock_release(hfsmp
);
1099 VTOC(ap
->a_vp
)->c_flag
|= C_MODIFIED
;
1102 retval
= MacToVFSError(
1103 MapFileBlockC (HFSTOVCB(hfsmp
),
1111 (void) hfs_metafilelocking(hfsmp
, kHFSExtentsFileID
, LK_RELEASE
, p
);
1115 hfs_flushvolumeheader(hfsmp
, MNT_NOWAIT
, 0);
1116 journal_end_transaction(hfsmp
->jnl
);
1120 hfs_global_shared_lock_release(hfsmp
);
1124 if (retval
== E_NONE
) {
1125 /* Adjust the mapping information for invalid file ranges: */
1126 overlaptype
= rl_scan(&fp
->ff_invalidranges
,
1128 ap
->a_foffset
+ (off_t
)bytesContAvail
- 1,
1130 if (overlaptype
!= RL_NOOVERLAP
) {
1131 switch(overlaptype
) {
1132 case RL_MATCHINGOVERLAP
:
1133 case RL_OVERLAPCONTAINSRANGE
:
1134 case RL_OVERLAPSTARTSBEFORE
:
1135 /* There's no valid block for this byte offset: */
1136 *ap
->a_bpn
= (daddr_t
)-1;
1138 /* There's no point limiting the amount to be returned if the
1139 invalid range that was hit extends all the way to the EOF
1140 (i.e. there's no valid bytes between the end of this range
1141 and the file's EOF):
1143 if ((fp
->ff_size
> (invalid_range
->rl_end
+ 1)) &&
1144 (invalid_range
->rl_end
+ 1 - ap
->a_foffset
< bytesContAvail
)) {
1145 bytesContAvail
= invalid_range
->rl_end
+ 1 - ap
->a_foffset
;
1149 case RL_OVERLAPISCONTAINED
:
1150 case RL_OVERLAPENDSAFTER
:
1151 /* The range of interest hits an invalid block before the end: */
1152 if (invalid_range
->rl_start
== ap
->a_foffset
) {
1153 /* There's actually no valid information to be had starting here: */
1154 *ap
->a_bpn
= (daddr_t
)-1;
1155 if ((fp
->ff_size
> (invalid_range
->rl_end
+ 1)) &&
1156 (invalid_range
->rl_end
+ 1 - ap
->a_foffset
< bytesContAvail
)) {
1157 bytesContAvail
= invalid_range
->rl_end
+ 1 - ap
->a_foffset
;
1160 bytesContAvail
= invalid_range
->rl_start
- ap
->a_foffset
;
1164 if (bytesContAvail
> ap
->a_size
) bytesContAvail
= ap
->a_size
;
1167 if (ap
->a_run
) *ap
->a_run
= bytesContAvail
;
1171 *(int *)ap
->a_poff
= 0;
1178 * Read or write a buffer that is not contiguous on disk. We loop over
1179 * each device block, copying to or from caller's buffer.
1181 * We could be a bit more efficient by transferring as much data as is
1182 * contiguous. But since this routine should rarely be called, and that
1183 * would be more complicated; best to keep it simple.
1186 hfs_strategy_fragmented(struct buf
*bp
)
1188 register struct vnode
*vp
= bp
->b_vp
;
1189 register struct cnode
*cp
= VTOC(vp
);
1190 register struct vnode
*devvp
= cp
->c_devvp
;
1191 caddr_t ioaddr
; /* Address of fragment within bp */
1192 struct buf
*frag
= NULL
; /* For reading or writing a single block */
1194 long remaining
; /* Bytes (in bp) left to transfer */
1195 off_t offset
; /* Logical offset of current fragment in vp */
1196 u_long block_size
; /* Size of one device block (and one I/O) */
1198 /* Make sure we redo this mapping for the next I/O */
1199 bp
->b_blkno
= bp
->b_lblkno
;
1201 /* Set up the logical position and number of bytes to read/write */
1202 offset
= (off_t
) bp
->b_lblkno
* (off_t
) GetLogicalBlockSize(vp
);
1203 block_size
= VTOHFS(vp
)->hfs_phys_block_size
;
1205 /* Get an empty buffer to do the deblocking */
1206 frag
= geteblk(block_size
);
1207 if (ISSET(bp
->b_flags
, B_READ
))
1208 SET(frag
->b_flags
, B_READ
);
1210 for (ioaddr
= bp
->b_data
, remaining
= bp
->b_bcount
; remaining
!= 0;
1211 ioaddr
+= block_size
, offset
+= block_size
,
1212 remaining
-= block_size
) {
1213 frag
->b_resid
= frag
->b_bcount
;
1214 CLR(frag
->b_flags
, B_DONE
);
1216 /* Map the current position to a physical block number */
1217 retval
= VOP_CMAP(vp
, offset
, block_size
, &frag
->b_lblkno
,
1223 * Did we try to read a hole?
1224 * (Should never happen for metadata!)
1226 if ((long)frag
->b_lblkno
== -1) {
1227 bzero(ioaddr
, block_size
);
1231 /* If writing, copy before I/O */
1232 if (!ISSET(bp
->b_flags
, B_READ
))
1233 bcopy(ioaddr
, frag
->b_data
, block_size
);
1235 /* Call the device to do the I/O and wait for it */
1236 frag
->b_blkno
= frag
->b_lblkno
;
1237 frag
->b_vp
= devvp
; /* Used to dispatch via VOP_STRATEGY */
1238 frag
->b_dev
= devvp
->v_rdev
;
1239 retval
= VOP_STRATEGY(frag
);
1243 retval
= biowait(frag
);
1247 /* If reading, copy after the I/O */
1248 if (ISSET(bp
->b_flags
, B_READ
))
1249 bcopy(frag
->b_data
, ioaddr
, block_size
);
1254 // XXXdbg - in the case that this is a meta-data block, it won't affect
1255 // the journal because this bp is for a physical disk block,
1256 // not a logical block that is part of the catalog or extents
1258 SET(frag
->b_flags
, B_INVAL
);
1261 if ((bp
->b_error
= retval
) != 0)
1262 SET(bp
->b_flags
, B_ERROR
);
1264 biodone(bp
); /* This I/O is now complete */
1270 * Calculate the logical to physical mapping if not done already,
1271 * then call the device strategy routine.
1274 # IN struct buf *bp;
1278 struct vop_strategy_args
/* {
1282 register struct buf
*bp
= ap
->a_bp
;
1283 register struct vnode
*vp
= bp
->b_vp
;
1284 register struct cnode
*cp
= VTOC(vp
);
1287 size_t bytes_contig
;
1289 if ( !(bp
->b_flags
& B_VECTORLIST
)) {
1290 if (vp
->v_type
== VBLK
|| vp
->v_type
== VCHR
)
1291 panic("hfs_strategy: device vnode passed!");
1293 if (bp
->b_flags
& B_PAGELIST
) {
1295 * If we have a page list associated with this bp,
1296 * then go through cluster_bp since it knows how to
1297 * deal with a page request that might span non-
1298 * contiguous physical blocks on the disk...
1300 retval
= cluster_bp(bp
);
1302 bp
->b_dev
= vp
->v_rdev
;
1308 * If we don't already know the filesystem relative block
1309 * number then get it using VOP_BMAP(). If VOP_BMAP()
1310 * returns the block number as -1 then we've got a hole in
1311 * the file. Although HFS filesystems don't create files with
1312 * holes, invalidating of subranges of the file (lazy zero
1313 * filling) may create such a situation.
1315 if (bp
->b_blkno
== bp
->b_lblkno
) {
1316 offset
= (off_t
) bp
->b_lblkno
*
1317 (off_t
) GetLogicalBlockSize(vp
);
1319 if ((retval
= VOP_CMAP(vp
, offset
, bp
->b_bcount
,
1320 &bp
->b_blkno
, &bytes_contig
, NULL
))) {
1321 bp
->b_error
= retval
;
1322 bp
->b_flags
|= B_ERROR
;
1326 if (bytes_contig
< bp
->b_bcount
)
1329 * We were asked to read a block that wasn't
1330 * contiguous, so we have to read each of the
1331 * pieces and copy them into the buffer.
1332 * Since ordinary file I/O goes through
1333 * cluster_io (which won't ask us for
1334 * discontiguous data), this is probably an
1335 * attempt to read or write metadata.
1337 return hfs_strategy_fragmented(bp
);
1339 if ((long)bp
->b_blkno
== -1)
1342 if ((long)bp
->b_blkno
== -1) {
1346 if (bp
->b_validend
== 0) {
1348 * Record the exact size of the I/O transfer about to
1351 bp
->b_validend
= bp
->b_bcount
;
1355 bp
->b_dev
= vp
->v_rdev
;
1357 return VOCALL (vp
->v_op
, VOFFSET(vop_strategy
), ap
);
1363 #% truncate vp L L L
1366 IN struct vnode *vp;
1368 IN int flags; (IO_SYNC)
1369 IN struct ucred *cred;
1372 * Truncate a cnode to at most length size, freeing (or adding) the
1375 int hfs_truncate(ap
)
1376 struct vop_truncate_args
/* {
1380 struct ucred *a_cred;
1384 register struct vnode
*vp
= ap
->a_vp
;
1385 register struct cnode
*cp
= VTOC(vp
);
1386 struct filefork
*fp
= VTOF(vp
);
1392 off_t actualBytesAdded
;
1396 struct hfsmount
*hfsmp
;
1398 if (vp
->v_type
!= VREG
&& vp
->v_type
!= VLNK
)
1399 return (EISDIR
); /* cannot truncate an HFS directory! */
1401 length
= ap
->a_length
;
1402 blksize
= VTOVCB(vp
)->blockSize
;
1403 fileblocks
= fp
->ff_blocks
;
1404 filebytes
= (off_t
)fileblocks
* (off_t
)blksize
;
1406 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 7)) | DBG_FUNC_START
,
1407 (int)length
, (int)fp
->ff_size
, (int)filebytes
, 0, 0);
1412 if ((!ISHFSPLUS(VTOVCB(vp
))) && (length
> (off_t
)MAXHFSFILESIZE
))
1421 * We cannot just check if fp->ff_size == length (as an optimization)
1422 * since there may be extra physical blocks that also need truncation.
1425 if (retval
= hfs_getinoquota(cp
))
1430 * Lengthen the size of the file. We must ensure that the
1431 * last byte of the file is allocated. Since the smallest
1432 * value of ff_size is 0, length will be at least 1.
1434 if (length
> fp
->ff_size
) {
1436 retval
= hfs_chkdq(cp
, (int64_t)(roundup(length
- filebytes
, blksize
)),
1442 * If we don't have enough physical space then
1443 * we need to extend the physical size.
1445 if (length
> filebytes
) {
1448 /* All or nothing and don't round up to clumpsize. */
1449 eflags
= kEFAllMask
| kEFNoClumpMask
;
1451 if (suser(ap
->a_cred
, NULL
) != 0)
1452 eflags
|= kEFReserveMask
; /* keep a reserve */
1455 hfs_global_shared_lock_acquire(hfsmp
);
1457 if (journal_start_transaction(hfsmp
->jnl
) != 0) {
1463 /* lock extents b-tree (also protects volume bitmap) */
1464 retval
= hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_EXCLUSIVE
, ap
->a_p
);
1467 journal_end_transaction(hfsmp
->jnl
);
1469 hfs_global_shared_lock_release(hfsmp
);
1474 while ((length
> filebytes
) && (retval
== E_NONE
)) {
1475 bytesToAdd
= length
- filebytes
;
1476 retval
= MacToVFSError(ExtendFileC(VTOVCB(vp
),
1481 &actualBytesAdded
));
1483 filebytes
= (off_t
)fp
->ff_blocks
* (off_t
)blksize
;
1484 if (actualBytesAdded
== 0 && retval
== E_NONE
) {
1485 if (length
> filebytes
)
1491 (void) hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_RELEASE
, ap
->a_p
);
1495 hfs_flushvolumeheader(hfsmp
, MNT_NOWAIT
, 0);
1496 journal_end_transaction(hfsmp
->jnl
);
1498 hfs_global_shared_lock_release(hfsmp
);
1503 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 7)) | DBG_FUNC_NONE
,
1504 (int)length
, (int)fp
->ff_size
, (int)filebytes
, 0, 0);
1507 if (!(ap
->a_flags
& IO_NOZEROFILL
)) {
1508 if (UBCINFOEXISTS(vp
) && retval
== E_NONE
) {
1509 struct rl_entry
*invalid_range
;
1513 zero_limit
= (fp
->ff_size
+ (PAGE_SIZE_64
- 1)) & ~PAGE_MASK_64
;
1514 if (length
< zero_limit
) zero_limit
= length
;
1516 if (length
> fp
->ff_size
) {
1517 /* Extending the file: time to fill out the current last page w. zeroes? */
1518 if ((fp
->ff_size
& PAGE_MASK_64
) &&
1519 (rl_scan(&fp
->ff_invalidranges
, fp
->ff_size
& ~PAGE_MASK_64
,
1520 fp
->ff_size
- 1, &invalid_range
) == RL_NOOVERLAP
)) {
1522 /* There's some valid data at the start of the (current) last page
1523 of the file, so zero out the remainder of that page to ensure the
1524 entire page contains valid data. Since there is no invalid range
1525 possible past the (current) eof, there's no need to remove anything
1526 from the invalid range list before calling cluster_write(): */
1527 VOP_DEVBLOCKSIZE(cp
->c_devvp
, &devBlockSize
);
1528 retval
= cluster_write(vp
, (struct uio
*) 0, fp
->ff_size
, zero_limit
,
1529 fp
->ff_size
, (off_t
)0, devBlockSize
,
1530 (ap
->a_flags
& IO_SYNC
) | IO_HEADZEROFILL
| IO_NOZERODIRTY
);
1531 if (retval
) goto Err_Exit
;
1533 /* Merely invalidate the remaining area, if necessary: */
1534 if (length
> zero_limit
) {
1535 rl_add(zero_limit
, length
- 1, &fp
->ff_invalidranges
);
1536 cp
->c_zftimeout
= time
.tv_sec
+ ZFTIMELIMIT
;
1539 /* The page containing the (current) eof is invalid: just add the
1540 remainder of the page to the invalid list, along with the area
1541 being newly allocated:
1543 rl_add(fp
->ff_size
, length
- 1, &fp
->ff_invalidranges
);
1544 cp
->c_zftimeout
= time
.tv_sec
+ ZFTIMELIMIT
;
1548 panic("hfs_truncate: invoked on non-UBC object?!");
1551 cp
->c_flag
|= C_UPDATE
;
1552 fp
->ff_size
= length
;
1555 ubc_setsize(vp
, fp
->ff_size
); /* XXX check errors */
1557 } else { /* Shorten the size of the file */
1559 if (fp
->ff_size
> length
) {
1561 * Any buffers that are past the truncation point need to be
1562 * invalidated (to maintain buffer cache consistency). For
1563 * simplicity, we invalidate all the buffers by calling vinvalbuf.
1566 ubc_setsize(vp
, length
); /* XXX check errors */
1568 vflags
= ((length
> 0) ? V_SAVE
: 0) | V_SAVEMETA
;
1569 retval
= vinvalbuf(vp
, vflags
, ap
->a_cred
, ap
->a_p
, 0, 0);
1571 /* Any space previously marked as invalid is now irrelevant: */
1572 rl_remove(length
, fp
->ff_size
- 1, &fp
->ff_invalidranges
);
1576 * Account for any unmapped blocks. Note that the new
1577 * file length can still end up with unmapped blocks.
1579 if (fp
->ff_unallocblocks
> 0) {
1580 u_int32_t finalblks
;
1582 /* lock extents b-tree */
1583 retval
= hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
,
1584 LK_EXCLUSIVE
, ap
->a_p
);
1588 VTOVCB(vp
)->loanedBlocks
-= fp
->ff_unallocblocks
;
1589 cp
->c_blocks
-= fp
->ff_unallocblocks
;
1590 fp
->ff_blocks
-= fp
->ff_unallocblocks
;
1591 fp
->ff_unallocblocks
= 0;
1593 finalblks
= (length
+ blksize
- 1) / blksize
;
1594 if (finalblks
> fp
->ff_blocks
) {
1595 /* calculate required unmapped blocks */
1596 fp
->ff_unallocblocks
= finalblks
- fp
->ff_blocks
;
1597 VTOVCB(vp
)->loanedBlocks
+= fp
->ff_unallocblocks
;
1598 cp
->c_blocks
+= fp
->ff_unallocblocks
;
1599 fp
->ff_blocks
+= fp
->ff_unallocblocks
;
1601 (void) hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
,
1602 LK_RELEASE
, ap
->a_p
);
1606 * For a TBE process the deallocation of the file blocks is
1607 * delayed until the file is closed. And hfs_close calls
1608 * truncate with the IO_NDELAY flag set. So when IO_NDELAY
1609 * isn't set, we make sure this isn't a TBE process.
1611 if ((ap
->a_flags
& IO_NDELAY
) || (!ISSET(ap
->a_p
->p_flag
, P_TBE
))) {
1613 off_t savedbytes
= ((off_t
)fp
->ff_blocks
* (off_t
)blksize
);
1616 hfs_global_shared_lock_acquire(hfsmp
);
1618 if (journal_start_transaction(hfsmp
->jnl
) != 0) {
1624 /* lock extents b-tree (also protects volume bitmap) */
1625 retval
= hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_EXCLUSIVE
, ap
->a_p
);
1628 journal_end_transaction(hfsmp
->jnl
);
1630 hfs_global_shared_lock_release(hfsmp
);
1634 if (fp
->ff_unallocblocks
== 0)
1635 retval
= MacToVFSError(TruncateFileC(VTOVCB(vp
),
1636 (FCB
*)fp
, length
, false));
1638 (void) hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_RELEASE
, ap
->a_p
);
1642 hfs_flushvolumeheader(hfsmp
, MNT_NOWAIT
, 0);
1643 journal_end_transaction(hfsmp
->jnl
);
1645 hfs_global_shared_lock_release(hfsmp
);
1647 filebytes
= (off_t
)fp
->ff_blocks
* (off_t
)blksize
;
1651 /* These are bytesreleased */
1652 (void) hfs_chkdq(cp
, (int64_t)-(savedbytes
- filebytes
), NOCRED
, 0);
1655 /* Only set update flag if the logical length changes */
1656 if (fp
->ff_size
!= length
)
1657 cp
->c_flag
|= C_UPDATE
;
1658 fp
->ff_size
= length
;
1660 cp
->c_flag
|= C_CHANGE
;
1661 retval
= VOP_UPDATE(vp
, &tv
, &tv
, MNT_WAIT
);
1663 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 7)) | DBG_FUNC_NONE
,
1664 -1, -1, -1, retval
, 0);
1669 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 7)) | DBG_FUNC_END
,
1670 (int)length
, (int)fp
->ff_size
, (int)filebytes
, retval
, 0);
1679 #% allocate vp L L L
1682 IN struct vnode *vp;
1685 OUT off_t *bytesallocated;
1687 IN struct ucred *cred;
1690 * allocate a cnode to at most length size
1692 int hfs_allocate(ap
)
1693 struct vop_allocate_args
/* {
1697 off_t *a_bytesallocated;
1699 struct ucred *a_cred;
1703 struct vnode
*vp
= ap
->a_vp
;
1704 struct cnode
*cp
= VTOC(vp
);
1705 struct filefork
*fp
= VTOF(vp
);
1706 off_t length
= ap
->a_length
;
1708 off_t moreBytesRequested
;
1709 off_t actualBytesAdded
;
1714 int retval
, retval2
;
1716 UInt32 extendFlags
=0; /* For call to ExtendFileC */
1717 struct hfsmount
*hfsmp
;
1721 *(ap
->a_bytesallocated
) = 0;
1722 fileblocks
= fp
->ff_blocks
;
1723 filebytes
= (off_t
)fileblocks
* (off_t
)VTOVCB(vp
)->blockSize
;
1725 if (length
< (off_t
)0)
1727 if (vp
->v_type
!= VREG
&& vp
->v_type
!= VLNK
)
1729 if ((ap
->a_flags
& ALLOCATEFROMVOL
) && (length
<= filebytes
))
1732 /* Fill in the flags word for the call to Extend the file */
1734 if (ap
->a_flags
& ALLOCATECONTIG
)
1735 extendFlags
|= kEFContigMask
;
1737 if (ap
->a_flags
& ALLOCATEALL
)
1738 extendFlags
|= kEFAllMask
;
1740 if (suser(ap
->a_cred
, NULL
) != 0)
1741 extendFlags
|= kEFReserveMask
;
1746 startingPEOF
= filebytes
;
1748 if (ap
->a_flags
& ALLOCATEFROMPEOF
)
1749 length
+= filebytes
;
1750 else if (ap
->a_flags
& ALLOCATEFROMVOL
)
1751 blockHint
= ap
->a_offset
/ VTOVCB(vp
)->blockSize
;
1753 /* If no changes are necesary, then we're done */
1754 if (filebytes
== length
)
1758 * Lengthen the size of the file. We must ensure that the
1759 * last byte of the file is allocated. Since the smallest
1760 * value of filebytes is 0, length will be at least 1.
1762 if (length
> filebytes
) {
1763 moreBytesRequested
= length
- filebytes
;
1766 retval
= hfs_chkdq(cp
,
1767 (int64_t)(roundup(moreBytesRequested
, VTOVCB(vp
)->blockSize
)),
1774 hfs_global_shared_lock_acquire(hfsmp
);
1776 if (journal_start_transaction(hfsmp
->jnl
) != 0) {
1782 /* lock extents b-tree (also protects volume bitmap) */
1783 retval
= hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_EXCLUSIVE
, ap
->a_p
);
1786 journal_end_transaction(hfsmp
->jnl
);
1788 hfs_global_shared_lock_release(hfsmp
);
1792 retval
= MacToVFSError(ExtendFileC(VTOVCB(vp
),
1797 &actualBytesAdded
));
1799 *(ap
->a_bytesallocated
) = actualBytesAdded
;
1800 filebytes
= (off_t
)fp
->ff_blocks
* (off_t
)VTOVCB(vp
)->blockSize
;
1802 (void) hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_RELEASE
, ap
->a_p
);
1806 hfs_flushvolumeheader(hfsmp
, MNT_NOWAIT
, 0);
1807 journal_end_transaction(hfsmp
->jnl
);
1809 hfs_global_shared_lock_release(hfsmp
);
1812 * if we get an error and no changes were made then exit
1813 * otherwise we must do the VOP_UPDATE to reflect the changes
1815 if (retval
&& (startingPEOF
== filebytes
))
1819 * Adjust actualBytesAdded to be allocation block aligned, not
1820 * clump size aligned.
1821 * NOTE: So what we are reporting does not affect reality
1822 * until the file is closed, when we truncate the file to allocation
1825 if ((actualBytesAdded
!= 0) && (moreBytesRequested
< actualBytesAdded
))
1826 *(ap
->a_bytesallocated
) =
1827 roundup(moreBytesRequested
, (off_t
)VTOVCB(vp
)->blockSize
);
1829 } else { /* Shorten the size of the file */
1831 if (fp
->ff_size
> length
) {
1833 * Any buffers that are past the truncation point need to be
1834 * invalidated (to maintain buffer cache consistency). For
1835 * simplicity, we invalidate all the buffers by calling vinvalbuf.
1837 vflags
= ((length
> 0) ? V_SAVE
: 0) | V_SAVEMETA
;
1838 (void) vinvalbuf(vp
, vflags
, ap
->a_cred
, ap
->a_p
, 0, 0);
1842 hfs_global_shared_lock_acquire(hfsmp
);
1844 if (journal_start_transaction(hfsmp
->jnl
) != 0) {
1850 /* lock extents b-tree (also protects volume bitmap) */
1851 retval
= hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_EXCLUSIVE
, ap
->a_p
);
1854 journal_end_transaction(hfsmp
->jnl
);
1856 hfs_global_shared_lock_release(hfsmp
);
1861 retval
= MacToVFSError(
1867 (void) hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_RELEASE
, ap
->a_p
);
1868 filebytes
= (off_t
)fp
->ff_blocks
* (off_t
)VTOVCB(vp
)->blockSize
;
1871 hfs_flushvolumeheader(hfsmp
, MNT_NOWAIT
, 0);
1872 journal_end_transaction(hfsmp
->jnl
);
1874 hfs_global_shared_lock_release(hfsmp
);
1878 * if we get an error and no changes were made then exit
1879 * otherwise we must do the VOP_UPDATE to reflect the changes
1881 if (retval
&& (startingPEOF
== filebytes
)) goto Err_Exit
;
1883 /* These are bytesreleased */
1884 (void) hfs_chkdq(cp
, (int64_t)-((startingPEOF
- filebytes
)), NOCRED
,0);
1887 if (fp
->ff_size
> filebytes
) {
1888 fp
->ff_size
= filebytes
;
1891 ubc_setsize(vp
, fp
->ff_size
); /* XXX check errors */
1896 cp
->c_flag
|= C_CHANGE
| C_UPDATE
;
1897 retval2
= VOP_UPDATE(vp
, &tv
, &tv
, MNT_WAIT
);
1907 * pagein for HFS filesystem
1911 struct vop_pagein_args
/* {
1914 vm_offset_t a_pl_offset,
1917 struct ucred *a_cred,
1921 register struct vnode
*vp
= ap
->a_vp
;
1922 int devBlockSize
= 0;
1925 if (vp
->v_type
!= VREG
&& vp
->v_type
!= VLNK
)
1926 panic("hfs_pagein: vp not UBC type\n");
1928 VOP_DEVBLOCKSIZE(VTOC(vp
)->c_devvp
, &devBlockSize
);
1930 error
= cluster_pagein(vp
, ap
->a_pl
, ap
->a_pl_offset
, ap
->a_f_offset
,
1931 ap
->a_size
, (off_t
)VTOF(vp
)->ff_size
, devBlockSize
,
1937 * pageout for HFS filesystem.
1941 struct vop_pageout_args
/* {
1944 vm_offset_t a_pl_offset,
1947 struct ucred *a_cred,
1951 struct vnode
*vp
= ap
->a_vp
;
1952 struct cnode
*cp
= VTOC(vp
);
1953 struct filefork
*fp
= VTOF(vp
);
1955 int devBlockSize
= 0;
1960 panic("hfs_pageout: Not a VREG: vp=%x", vp
);
1962 VOP_DEVBLOCKSIZE(cp
->c_devvp
, &devBlockSize
);
1963 filesize
= fp
->ff_size
;
1964 end_of_range
= ap
->a_f_offset
+ ap
->a_size
- 1;
1966 if (end_of_range
>= filesize
)
1967 end_of_range
= (off_t
)(filesize
- 1);
1968 if (ap
->a_f_offset
< filesize
)
1969 rl_remove(ap
->a_f_offset
, end_of_range
, &fp
->ff_invalidranges
);
1971 retval
= cluster_pageout(vp
, ap
->a_pl
, ap
->a_pl_offset
, ap
->a_f_offset
, ap
->a_size
,
1972 filesize
, devBlockSize
, ap
->a_flags
);
1975 * If we successfully wrote any data, and we are not the superuser
1976 * we clear the setuid and setgid bits as a precaution against
1979 if (retval
== 0 && ap
->a_cred
&& ap
->a_cred
->cr_uid
!= 0)
1980 cp
->c_mode
&= ~(S_ISUID
| S_ISGID
);
1986 * Intercept B-Tree node writes to unswap them if necessary.
1989 # IN struct buf *bp;
1993 struct vop_bwrite_args
/* {
1998 register struct buf
*bp
= ap
->a_bp
;
1999 register struct vnode
*vp
= bp
->b_vp
;
2000 #if BYTE_ORDER == LITTLE_ENDIAN
2001 BlockDescriptor block
;
2003 /* Trap B-Tree writes */
2004 if ((VTOC(vp
)->c_fileid
== kHFSExtentsFileID
) ||
2005 (VTOC(vp
)->c_fileid
== kHFSCatalogFileID
)) {
2007 /* Swap if the B-Tree node is in native byte order */
2008 if (((UInt16
*)((char *)bp
->b_data
+ bp
->b_bcount
- 2))[0] == 0x000e) {
2009 /* Prepare the block pointer */
2010 block
.blockHeader
= bp
;
2011 block
.buffer
= bp
->b_data
;
2012 /* not found in cache ==> came from disk */
2013 block
.blockReadFromDisk
= (bp
->b_flags
& B_CACHE
) == 0;
2014 block
.blockSize
= bp
->b_bcount
;
2016 /* Endian un-swap B-Tree node */
2017 SWAP_BT_NODE (&block
, ISHFSPLUS (VTOVCB(vp
)), VTOC(vp
)->c_fileid
, 1);
2020 /* We don't check to make sure that it's 0x0e00 because it could be all zeros */
2023 /* This buffer shouldn't be locked anymore but if it is clear it */
2024 if (ISSET(bp
->b_flags
, B_LOCKED
)) {
2026 if (VTOHFS(vp
)->jnl
) {
2027 panic("hfs: CLEARING the lock bit on bp 0x%x\n", bp
);
2029 CLR(bp
->b_flags
, B_LOCKED
);
2030 printf("hfs_bwrite: called with lock bit set\n");
2032 retval
= vn_bwrite (ap
);