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
)
1001 if (fp
->ff_unallocblocks
) {
1005 hfs_global_shared_lock_acquire(hfsmp
);
1009 if (journal_start_transaction(hfsmp
->jnl
) != 0) {
1010 hfs_global_shared_lock_release(hfsmp
);
1017 if (retval
= hfs_metafilelocking(hfsmp
, kHFSExtentsFileID
, LK_EXCLUSIVE
| LK_CANRECURSE
, p
)) {
1019 journal_end_transaction(hfsmp
->jnl
);
1022 hfs_global_shared_lock_release(hfsmp
);
1026 } else if (overflow_extents(fp
)) {
1028 if (retval
= hfs_metafilelocking(hfsmp
, kHFSExtentsFileID
, LK_EXCLUSIVE
| LK_CANRECURSE
, p
)) {
1034 * Check for any delayed allocations.
1036 if (fp
->ff_unallocblocks
) {
1037 SInt64 reqbytes
, actbytes
;
1039 reqbytes
= (SInt64
)fp
->ff_unallocblocks
*
1040 (SInt64
)HFSTOVCB(hfsmp
)->blockSize
;
1042 * Release the blocks on loan and aquire some real ones.
1043 * Note that we can race someone else for these blocks
1044 * (and lose) so cmap needs to handle a failure here.
1045 * Currently this race can't occur because all allocations
1046 * are protected by an exclusive lock on the Extents
1049 HFSTOVCB(hfsmp
)->loanedBlocks
-= fp
->ff_unallocblocks
;
1050 FTOC(fp
)->c_blocks
-= fp
->ff_unallocblocks
;
1051 fp
->ff_blocks
-= fp
->ff_unallocblocks
;
1052 fp
->ff_unallocblocks
= 0;
1054 while (retval
== 0 && reqbytes
> 0) {
1055 retval
= MacToVFSError(ExtendFileC(HFSTOVCB(hfsmp
),
1056 (FCB
*)fp
, reqbytes
, 0,
1057 kEFAllMask
| kEFNoClumpMask
, &actbytes
));
1058 if (retval
== 0 && actbytes
== 0)
1062 fp
->ff_unallocblocks
=
1063 reqbytes
/ HFSTOVCB(hfsmp
)->blockSize
;
1064 HFSTOVCB(hfsmp
)->loanedBlocks
+= fp
->ff_unallocblocks
;
1065 FTOC(fp
)->c_blocks
+= fp
->ff_unallocblocks
;
1066 fp
->ff_blocks
+= fp
->ff_unallocblocks
;
1068 reqbytes
-= actbytes
;
1072 (void) hfs_metafilelocking(hfsmp
, kHFSExtentsFileID
, LK_RELEASE
, p
);
1074 hfs_flushvolumeheader(hfsmp
, MNT_NOWAIT
, 0);
1075 journal_end_transaction(hfsmp
->jnl
);
1078 hfs_global_shared_lock_release(hfsmp
);
1082 VTOC(ap
->a_vp
)->c_flag
|= C_MODIFIED
;
1085 retval
= MacToVFSError(
1086 MapFileBlockC (HFSTOVCB(hfsmp
),
1094 (void) hfs_metafilelocking(hfsmp
, kHFSExtentsFileID
, LK_RELEASE
, p
);
1098 hfs_flushvolumeheader(hfsmp
, MNT_NOWAIT
, 0);
1099 journal_end_transaction(hfsmp
->jnl
);
1103 hfs_global_shared_lock_release(hfsmp
);
1107 if (retval
== E_NONE
) {
1108 /* Adjust the mapping information for invalid file ranges: */
1109 overlaptype
= rl_scan(&fp
->ff_invalidranges
,
1111 ap
->a_foffset
+ (off_t
)bytesContAvail
- 1,
1113 if (overlaptype
!= RL_NOOVERLAP
) {
1114 switch(overlaptype
) {
1115 case RL_MATCHINGOVERLAP
:
1116 case RL_OVERLAPCONTAINSRANGE
:
1117 case RL_OVERLAPSTARTSBEFORE
:
1118 /* There's no valid block for this byte offset: */
1119 *ap
->a_bpn
= (daddr_t
)-1;
1121 /* There's no point limiting the amount to be returned if the
1122 invalid range that was hit extends all the way to the EOF
1123 (i.e. there's no valid bytes between the end of this range
1124 and the file's EOF):
1126 if ((fp
->ff_size
> (invalid_range
->rl_end
+ 1)) &&
1127 (invalid_range
->rl_end
+ 1 - ap
->a_foffset
< bytesContAvail
)) {
1128 bytesContAvail
= invalid_range
->rl_end
+ 1 - ap
->a_foffset
;
1132 case RL_OVERLAPISCONTAINED
:
1133 case RL_OVERLAPENDSAFTER
:
1134 /* The range of interest hits an invalid block before the end: */
1135 if (invalid_range
->rl_start
== ap
->a_foffset
) {
1136 /* There's actually no valid information to be had starting here: */
1137 *ap
->a_bpn
= (daddr_t
)-1;
1138 if ((fp
->ff_size
> (invalid_range
->rl_end
+ 1)) &&
1139 (invalid_range
->rl_end
+ 1 - ap
->a_foffset
< bytesContAvail
)) {
1140 bytesContAvail
= invalid_range
->rl_end
+ 1 - ap
->a_foffset
;
1143 bytesContAvail
= invalid_range
->rl_start
- ap
->a_foffset
;
1147 if (bytesContAvail
> ap
->a_size
) bytesContAvail
= ap
->a_size
;
1150 if (ap
->a_run
) *ap
->a_run
= bytesContAvail
;
1154 *(int *)ap
->a_poff
= 0;
1161 * Read or write a buffer that is not contiguous on disk. We loop over
1162 * each device block, copying to or from caller's buffer.
1164 * We could be a bit more efficient by transferring as much data as is
1165 * contiguous. But since this routine should rarely be called, and that
1166 * would be more complicated; best to keep it simple.
1169 hfs_strategy_fragmented(struct buf
*bp
)
1171 register struct vnode
*vp
= bp
->b_vp
;
1172 register struct cnode
*cp
= VTOC(vp
);
1173 register struct vnode
*devvp
= cp
->c_devvp
;
1174 caddr_t ioaddr
; /* Address of fragment within bp */
1175 struct buf
*frag
= NULL
; /* For reading or writing a single block */
1177 long remaining
; /* Bytes (in bp) left to transfer */
1178 off_t offset
; /* Logical offset of current fragment in vp */
1179 u_long block_size
; /* Size of one device block (and one I/O) */
1181 /* Make sure we redo this mapping for the next I/O */
1182 bp
->b_blkno
= bp
->b_lblkno
;
1184 /* Set up the logical position and number of bytes to read/write */
1185 offset
= (off_t
) bp
->b_lblkno
* (off_t
) GetLogicalBlockSize(vp
);
1186 block_size
= VTOHFS(vp
)->hfs_phys_block_size
;
1188 /* Get an empty buffer to do the deblocking */
1189 frag
= geteblk(block_size
);
1190 if (ISSET(bp
->b_flags
, B_READ
))
1191 SET(frag
->b_flags
, B_READ
);
1193 for (ioaddr
= bp
->b_data
, remaining
= bp
->b_bcount
; remaining
!= 0;
1194 ioaddr
+= block_size
, offset
+= block_size
,
1195 remaining
-= block_size
) {
1196 frag
->b_resid
= frag
->b_bcount
;
1197 CLR(frag
->b_flags
, B_DONE
);
1199 /* Map the current position to a physical block number */
1200 retval
= VOP_CMAP(vp
, offset
, block_size
, &frag
->b_lblkno
,
1206 * Did we try to read a hole?
1207 * (Should never happen for metadata!)
1209 if ((long)frag
->b_lblkno
== -1) {
1210 bzero(ioaddr
, block_size
);
1214 /* If writing, copy before I/O */
1215 if (!ISSET(bp
->b_flags
, B_READ
))
1216 bcopy(ioaddr
, frag
->b_data
, block_size
);
1218 /* Call the device to do the I/O and wait for it */
1219 frag
->b_blkno
= frag
->b_lblkno
;
1220 frag
->b_vp
= devvp
; /* Used to dispatch via VOP_STRATEGY */
1221 frag
->b_dev
= devvp
->v_rdev
;
1222 retval
= VOP_STRATEGY(frag
);
1226 retval
= biowait(frag
);
1230 /* If reading, copy after the I/O */
1231 if (ISSET(bp
->b_flags
, B_READ
))
1232 bcopy(frag
->b_data
, ioaddr
, block_size
);
1237 // XXXdbg - in the case that this is a meta-data block, it won't affect
1238 // the journal because this bp is for a physical disk block,
1239 // not a logical block that is part of the catalog or extents
1241 SET(frag
->b_flags
, B_INVAL
);
1244 if ((bp
->b_error
= retval
) != 0)
1245 SET(bp
->b_flags
, B_ERROR
);
1247 biodone(bp
); /* This I/O is now complete */
1253 * Calculate the logical to physical mapping if not done already,
1254 * then call the device strategy routine.
1257 # IN struct buf *bp;
1261 struct vop_strategy_args
/* {
1265 register struct buf
*bp
= ap
->a_bp
;
1266 register struct vnode
*vp
= bp
->b_vp
;
1267 register struct cnode
*cp
= VTOC(vp
);
1270 size_t bytes_contig
;
1272 if ( !(bp
->b_flags
& B_VECTORLIST
)) {
1273 if (vp
->v_type
== VBLK
|| vp
->v_type
== VCHR
)
1274 panic("hfs_strategy: device vnode passed!");
1276 if (bp
->b_flags
& B_PAGELIST
) {
1278 * If we have a page list associated with this bp,
1279 * then go through cluster_bp since it knows how to
1280 * deal with a page request that might span non-
1281 * contiguous physical blocks on the disk...
1283 retval
= cluster_bp(bp
);
1285 bp
->b_dev
= vp
->v_rdev
;
1291 * If we don't already know the filesystem relative block
1292 * number then get it using VOP_BMAP(). If VOP_BMAP()
1293 * returns the block number as -1 then we've got a hole in
1294 * the file. Although HFS filesystems don't create files with
1295 * holes, invalidating of subranges of the file (lazy zero
1296 * filling) may create such a situation.
1298 if (bp
->b_blkno
== bp
->b_lblkno
) {
1299 offset
= (off_t
) bp
->b_lblkno
*
1300 (off_t
) GetLogicalBlockSize(vp
);
1302 if ((retval
= VOP_CMAP(vp
, offset
, bp
->b_bcount
,
1303 &bp
->b_blkno
, &bytes_contig
, NULL
))) {
1304 bp
->b_error
= retval
;
1305 bp
->b_flags
|= B_ERROR
;
1309 if (bytes_contig
< bp
->b_bcount
)
1312 * We were asked to read a block that wasn't
1313 * contiguous, so we have to read each of the
1314 * pieces and copy them into the buffer.
1315 * Since ordinary file I/O goes through
1316 * cluster_io (which won't ask us for
1317 * discontiguous data), this is probably an
1318 * attempt to read or write metadata.
1320 return hfs_strategy_fragmented(bp
);
1322 if ((long)bp
->b_blkno
== -1)
1325 if ((long)bp
->b_blkno
== -1) {
1329 if (bp
->b_validend
== 0) {
1331 * Record the exact size of the I/O transfer about to
1334 bp
->b_validend
= bp
->b_bcount
;
1338 bp
->b_dev
= vp
->v_rdev
;
1340 return VOCALL (vp
->v_op
, VOFFSET(vop_strategy
), ap
);
1346 #% truncate vp L L L
1349 IN struct vnode *vp;
1351 IN int flags; (IO_SYNC)
1352 IN struct ucred *cred;
1355 * Truncate a cnode to at most length size, freeing (or adding) the
1358 int hfs_truncate(ap
)
1359 struct vop_truncate_args
/* {
1363 struct ucred *a_cred;
1367 register struct vnode
*vp
= ap
->a_vp
;
1368 register struct cnode
*cp
= VTOC(vp
);
1369 struct filefork
*fp
= VTOF(vp
);
1375 off_t actualBytesAdded
;
1379 struct hfsmount
*hfsmp
;
1381 if (vp
->v_type
!= VREG
&& vp
->v_type
!= VLNK
)
1382 return (EISDIR
); /* cannot truncate an HFS directory! */
1384 length
= ap
->a_length
;
1385 blksize
= VTOVCB(vp
)->blockSize
;
1386 fileblocks
= fp
->ff_blocks
;
1387 filebytes
= (off_t
)fileblocks
* (off_t
)blksize
;
1389 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 7)) | DBG_FUNC_START
,
1390 (int)length
, (int)fp
->ff_size
, (int)filebytes
, 0, 0);
1395 if ((!ISHFSPLUS(VTOVCB(vp
))) && (length
> (off_t
)MAXHFSFILESIZE
))
1404 * We cannot just check if fp->ff_size == length (as an optimization)
1405 * since there may be extra physical blocks that also need truncation.
1408 if (retval
= hfs_getinoquota(cp
))
1413 * Lengthen the size of the file. We must ensure that the
1414 * last byte of the file is allocated. Since the smallest
1415 * value of ff_size is 0, length will be at least 1.
1417 if (length
> fp
->ff_size
) {
1419 retval
= hfs_chkdq(cp
, (int64_t)(roundup(length
- filebytes
, blksize
)),
1425 * If we don't have enough physical space then
1426 * we need to extend the physical size.
1428 if (length
> filebytes
) {
1431 /* All or nothing and don't round up to clumpsize. */
1432 eflags
= kEFAllMask
| kEFNoClumpMask
;
1434 if (suser(ap
->a_cred
, NULL
) != 0)
1435 eflags
|= kEFReserveMask
; /* keep a reserve */
1438 hfs_global_shared_lock_acquire(hfsmp
);
1440 if (journal_start_transaction(hfsmp
->jnl
) != 0) {
1446 /* lock extents b-tree (also protects volume bitmap) */
1447 retval
= hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_EXCLUSIVE
, ap
->a_p
);
1450 journal_end_transaction(hfsmp
->jnl
);
1452 hfs_global_shared_lock_release(hfsmp
);
1457 while ((length
> filebytes
) && (retval
== E_NONE
)) {
1458 bytesToAdd
= length
- filebytes
;
1459 retval
= MacToVFSError(ExtendFileC(VTOVCB(vp
),
1464 &actualBytesAdded
));
1466 filebytes
= (off_t
)fp
->ff_blocks
* (off_t
)blksize
;
1467 if (actualBytesAdded
== 0 && retval
== E_NONE
) {
1468 if (length
> filebytes
)
1474 (void) hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_RELEASE
, ap
->a_p
);
1478 hfs_flushvolumeheader(hfsmp
, MNT_NOWAIT
, 0);
1479 journal_end_transaction(hfsmp
->jnl
);
1481 hfs_global_shared_lock_release(hfsmp
);
1486 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 7)) | DBG_FUNC_NONE
,
1487 (int)length
, (int)fp
->ff_size
, (int)filebytes
, 0, 0);
1490 if (!(ap
->a_flags
& IO_NOZEROFILL
)) {
1491 if (UBCINFOEXISTS(vp
) && retval
== E_NONE
) {
1492 struct rl_entry
*invalid_range
;
1496 zero_limit
= (fp
->ff_size
+ (PAGE_SIZE_64
- 1)) & ~PAGE_MASK_64
;
1497 if (length
< zero_limit
) zero_limit
= length
;
1499 if (length
> fp
->ff_size
) {
1500 /* Extending the file: time to fill out the current last page w. zeroes? */
1501 if ((fp
->ff_size
& PAGE_MASK_64
) &&
1502 (rl_scan(&fp
->ff_invalidranges
, fp
->ff_size
& ~PAGE_MASK_64
,
1503 fp
->ff_size
- 1, &invalid_range
) == RL_NOOVERLAP
)) {
1505 /* There's some valid data at the start of the (current) last page
1506 of the file, so zero out the remainder of that page to ensure the
1507 entire page contains valid data. Since there is no invalid range
1508 possible past the (current) eof, there's no need to remove anything
1509 from the invalid range list before calling cluster_write(): */
1510 VOP_DEVBLOCKSIZE(cp
->c_devvp
, &devBlockSize
);
1511 retval
= cluster_write(vp
, (struct uio
*) 0, fp
->ff_size
, zero_limit
,
1512 fp
->ff_size
, (off_t
)0, devBlockSize
,
1513 (ap
->a_flags
& IO_SYNC
) | IO_HEADZEROFILL
| IO_NOZERODIRTY
);
1514 if (retval
) goto Err_Exit
;
1516 /* Merely invalidate the remaining area, if necessary: */
1517 if (length
> zero_limit
) {
1518 rl_add(zero_limit
, length
- 1, &fp
->ff_invalidranges
);
1519 cp
->c_zftimeout
= time
.tv_sec
+ ZFTIMELIMIT
;
1522 /* The page containing the (current) eof is invalid: just add the
1523 remainder of the page to the invalid list, along with the area
1524 being newly allocated:
1526 rl_add(fp
->ff_size
, length
- 1, &fp
->ff_invalidranges
);
1527 cp
->c_zftimeout
= time
.tv_sec
+ ZFTIMELIMIT
;
1531 panic("hfs_truncate: invoked on non-UBC object?!");
1534 cp
->c_flag
|= C_UPDATE
;
1535 fp
->ff_size
= length
;
1538 ubc_setsize(vp
, fp
->ff_size
); /* XXX check errors */
1540 } else { /* Shorten the size of the file */
1542 if (fp
->ff_size
> length
) {
1544 * Any buffers that are past the truncation point need to be
1545 * invalidated (to maintain buffer cache consistency). For
1546 * simplicity, we invalidate all the buffers by calling vinvalbuf.
1549 ubc_setsize(vp
, length
); /* XXX check errors */
1551 vflags
= ((length
> 0) ? V_SAVE
: 0) | V_SAVEMETA
;
1552 retval
= vinvalbuf(vp
, vflags
, ap
->a_cred
, ap
->a_p
, 0, 0);
1554 /* Any space previously marked as invalid is now irrelevant: */
1555 rl_remove(length
, fp
->ff_size
- 1, &fp
->ff_invalidranges
);
1559 * Account for any unmapped blocks. Note that the new
1560 * file length can still end up with unmapped blocks.
1562 if (fp
->ff_unallocblocks
> 0) {
1563 u_int32_t finalblks
;
1565 /* lock extents b-tree */
1566 retval
= hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
,
1567 LK_EXCLUSIVE
, ap
->a_p
);
1571 VTOVCB(vp
)->loanedBlocks
-= fp
->ff_unallocblocks
;
1572 cp
->c_blocks
-= fp
->ff_unallocblocks
;
1573 fp
->ff_blocks
-= fp
->ff_unallocblocks
;
1574 fp
->ff_unallocblocks
= 0;
1576 finalblks
= (length
+ blksize
- 1) / blksize
;
1577 if (finalblks
> fp
->ff_blocks
) {
1578 /* calculate required unmapped blocks */
1579 fp
->ff_unallocblocks
= finalblks
- fp
->ff_blocks
;
1580 VTOVCB(vp
)->loanedBlocks
+= fp
->ff_unallocblocks
;
1581 cp
->c_blocks
+= fp
->ff_unallocblocks
;
1582 fp
->ff_blocks
+= fp
->ff_unallocblocks
;
1584 (void) hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
,
1585 LK_RELEASE
, ap
->a_p
);
1589 * For a TBE process the deallocation of the file blocks is
1590 * delayed until the file is closed. And hfs_close calls
1591 * truncate with the IO_NDELAY flag set. So when IO_NDELAY
1592 * isn't set, we make sure this isn't a TBE process.
1594 if ((ap
->a_flags
& IO_NDELAY
) || (!ISSET(ap
->a_p
->p_flag
, P_TBE
))) {
1596 off_t savedbytes
= ((off_t
)fp
->ff_blocks
* (off_t
)blksize
);
1599 hfs_global_shared_lock_acquire(hfsmp
);
1601 if (journal_start_transaction(hfsmp
->jnl
) != 0) {
1607 /* lock extents b-tree (also protects volume bitmap) */
1608 retval
= hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_EXCLUSIVE
, ap
->a_p
);
1611 journal_end_transaction(hfsmp
->jnl
);
1613 hfs_global_shared_lock_release(hfsmp
);
1617 if (fp
->ff_unallocblocks
== 0)
1618 retval
= MacToVFSError(TruncateFileC(VTOVCB(vp
),
1619 (FCB
*)fp
, length
, false));
1621 (void) hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_RELEASE
, ap
->a_p
);
1625 hfs_flushvolumeheader(hfsmp
, MNT_NOWAIT
, 0);
1626 journal_end_transaction(hfsmp
->jnl
);
1628 hfs_global_shared_lock_release(hfsmp
);
1630 filebytes
= (off_t
)fp
->ff_blocks
* (off_t
)blksize
;
1634 /* These are bytesreleased */
1635 (void) hfs_chkdq(cp
, (int64_t)-(savedbytes
- filebytes
), NOCRED
, 0);
1638 /* Only set update flag if the logical length changes */
1639 if (fp
->ff_size
!= length
)
1640 cp
->c_flag
|= C_UPDATE
;
1641 fp
->ff_size
= length
;
1643 cp
->c_flag
|= C_CHANGE
;
1644 retval
= VOP_UPDATE(vp
, &tv
, &tv
, MNT_WAIT
);
1646 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 7)) | DBG_FUNC_NONE
,
1647 -1, -1, -1, retval
, 0);
1652 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 7)) | DBG_FUNC_END
,
1653 (int)length
, (int)fp
->ff_size
, (int)filebytes
, retval
, 0);
1662 #% allocate vp L L L
1665 IN struct vnode *vp;
1668 OUT off_t *bytesallocated;
1670 IN struct ucred *cred;
1673 * allocate a cnode to at most length size
1675 int hfs_allocate(ap
)
1676 struct vop_allocate_args
/* {
1680 off_t *a_bytesallocated;
1682 struct ucred *a_cred;
1686 struct vnode
*vp
= ap
->a_vp
;
1687 struct cnode
*cp
= VTOC(vp
);
1688 struct filefork
*fp
= VTOF(vp
);
1689 off_t length
= ap
->a_length
;
1691 off_t moreBytesRequested
;
1692 off_t actualBytesAdded
;
1697 int retval
, retval2
;
1699 UInt32 extendFlags
=0; /* For call to ExtendFileC */
1700 struct hfsmount
*hfsmp
;
1704 *(ap
->a_bytesallocated
) = 0;
1705 fileblocks
= fp
->ff_blocks
;
1706 filebytes
= (off_t
)fileblocks
* (off_t
)VTOVCB(vp
)->blockSize
;
1708 if (length
< (off_t
)0)
1710 if (vp
->v_type
!= VREG
&& vp
->v_type
!= VLNK
)
1712 if ((ap
->a_flags
& ALLOCATEFROMVOL
) && (length
<= filebytes
))
1715 /* Fill in the flags word for the call to Extend the file */
1717 if (ap
->a_flags
& ALLOCATECONTIG
)
1718 extendFlags
|= kEFContigMask
;
1720 if (ap
->a_flags
& ALLOCATEALL
)
1721 extendFlags
|= kEFAllMask
;
1723 if (suser(ap
->a_cred
, NULL
) != 0)
1724 extendFlags
|= kEFReserveMask
;
1729 startingPEOF
= filebytes
;
1731 if (ap
->a_flags
& ALLOCATEFROMPEOF
)
1732 length
+= filebytes
;
1733 else if (ap
->a_flags
& ALLOCATEFROMVOL
)
1734 blockHint
= ap
->a_offset
/ VTOVCB(vp
)->blockSize
;
1736 /* If no changes are necesary, then we're done */
1737 if (filebytes
== length
)
1741 * Lengthen the size of the file. We must ensure that the
1742 * last byte of the file is allocated. Since the smallest
1743 * value of filebytes is 0, length will be at least 1.
1745 if (length
> filebytes
) {
1746 moreBytesRequested
= length
- filebytes
;
1749 retval
= hfs_chkdq(cp
,
1750 (int64_t)(roundup(moreBytesRequested
, VTOVCB(vp
)->blockSize
)),
1757 hfs_global_shared_lock_acquire(hfsmp
);
1759 if (journal_start_transaction(hfsmp
->jnl
) != 0) {
1765 /* lock extents b-tree (also protects volume bitmap) */
1766 retval
= hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_EXCLUSIVE
, ap
->a_p
);
1769 journal_end_transaction(hfsmp
->jnl
);
1771 hfs_global_shared_lock_release(hfsmp
);
1775 retval
= MacToVFSError(ExtendFileC(VTOVCB(vp
),
1780 &actualBytesAdded
));
1782 *(ap
->a_bytesallocated
) = actualBytesAdded
;
1783 filebytes
= (off_t
)fp
->ff_blocks
* (off_t
)VTOVCB(vp
)->blockSize
;
1785 (void) hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_RELEASE
, ap
->a_p
);
1789 hfs_flushvolumeheader(hfsmp
, MNT_NOWAIT
, 0);
1790 journal_end_transaction(hfsmp
->jnl
);
1792 hfs_global_shared_lock_release(hfsmp
);
1795 * if we get an error and no changes were made then exit
1796 * otherwise we must do the VOP_UPDATE to reflect the changes
1798 if (retval
&& (startingPEOF
== filebytes
))
1802 * Adjust actualBytesAdded to be allocation block aligned, not
1803 * clump size aligned.
1804 * NOTE: So what we are reporting does not affect reality
1805 * until the file is closed, when we truncate the file to allocation
1808 if ((actualBytesAdded
!= 0) && (moreBytesRequested
< actualBytesAdded
))
1809 *(ap
->a_bytesallocated
) =
1810 roundup(moreBytesRequested
, (off_t
)VTOVCB(vp
)->blockSize
);
1812 } else { /* Shorten the size of the file */
1814 if (fp
->ff_size
> length
) {
1816 * Any buffers that are past the truncation point need to be
1817 * invalidated (to maintain buffer cache consistency). For
1818 * simplicity, we invalidate all the buffers by calling vinvalbuf.
1820 vflags
= ((length
> 0) ? V_SAVE
: 0) | V_SAVEMETA
;
1821 (void) vinvalbuf(vp
, vflags
, ap
->a_cred
, ap
->a_p
, 0, 0);
1825 hfs_global_shared_lock_acquire(hfsmp
);
1827 if (journal_start_transaction(hfsmp
->jnl
) != 0) {
1833 /* lock extents b-tree (also protects volume bitmap) */
1834 retval
= hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_EXCLUSIVE
, ap
->a_p
);
1837 journal_end_transaction(hfsmp
->jnl
);
1839 hfs_global_shared_lock_release(hfsmp
);
1844 retval
= MacToVFSError(
1850 (void) hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_RELEASE
, ap
->a_p
);
1851 filebytes
= (off_t
)fp
->ff_blocks
* (off_t
)VTOVCB(vp
)->blockSize
;
1854 hfs_flushvolumeheader(hfsmp
, MNT_NOWAIT
, 0);
1855 journal_end_transaction(hfsmp
->jnl
);
1857 hfs_global_shared_lock_release(hfsmp
);
1861 * if we get an error and no changes were made then exit
1862 * otherwise we must do the VOP_UPDATE to reflect the changes
1864 if (retval
&& (startingPEOF
== filebytes
)) goto Err_Exit
;
1866 /* These are bytesreleased */
1867 (void) hfs_chkdq(cp
, (int64_t)-((startingPEOF
- filebytes
)), NOCRED
,0);
1870 if (fp
->ff_size
> filebytes
) {
1871 fp
->ff_size
= filebytes
;
1874 ubc_setsize(vp
, fp
->ff_size
); /* XXX check errors */
1879 cp
->c_flag
|= C_CHANGE
| C_UPDATE
;
1880 retval2
= VOP_UPDATE(vp
, &tv
, &tv
, MNT_WAIT
);
1890 * pagein for HFS filesystem
1894 struct vop_pagein_args
/* {
1897 vm_offset_t a_pl_offset,
1900 struct ucred *a_cred,
1904 register struct vnode
*vp
= ap
->a_vp
;
1905 int devBlockSize
= 0;
1908 if (vp
->v_type
!= VREG
&& vp
->v_type
!= VLNK
)
1909 panic("hfs_pagein: vp not UBC type\n");
1911 VOP_DEVBLOCKSIZE(VTOC(vp
)->c_devvp
, &devBlockSize
);
1913 error
= cluster_pagein(vp
, ap
->a_pl
, ap
->a_pl_offset
, ap
->a_f_offset
,
1914 ap
->a_size
, (off_t
)VTOF(vp
)->ff_size
, devBlockSize
,
1920 * pageout for HFS filesystem.
1924 struct vop_pageout_args
/* {
1927 vm_offset_t a_pl_offset,
1930 struct ucred *a_cred,
1934 struct vnode
*vp
= ap
->a_vp
;
1935 struct cnode
*cp
= VTOC(vp
);
1936 struct filefork
*fp
= VTOF(vp
);
1938 int devBlockSize
= 0;
1943 panic("hfs_pageout: Not a VREG: vp=%x", vp
);
1945 VOP_DEVBLOCKSIZE(cp
->c_devvp
, &devBlockSize
);
1946 filesize
= fp
->ff_size
;
1947 end_of_range
= ap
->a_f_offset
+ ap
->a_size
- 1;
1949 if (end_of_range
>= filesize
)
1950 end_of_range
= (off_t
)(filesize
- 1);
1951 if (ap
->a_f_offset
< filesize
)
1952 rl_remove(ap
->a_f_offset
, end_of_range
, &fp
->ff_invalidranges
);
1954 retval
= cluster_pageout(vp
, ap
->a_pl
, ap
->a_pl_offset
, ap
->a_f_offset
, ap
->a_size
,
1955 filesize
, devBlockSize
, ap
->a_flags
);
1958 * If we successfully wrote any data, and we are not the superuser
1959 * we clear the setuid and setgid bits as a precaution against
1962 if (retval
== 0 && ap
->a_cred
&& ap
->a_cred
->cr_uid
!= 0)
1963 cp
->c_mode
&= ~(S_ISUID
| S_ISGID
);
1969 * Intercept B-Tree node writes to unswap them if necessary.
1972 # IN struct buf *bp;
1976 struct vop_bwrite_args
/* {
1981 register struct buf
*bp
= ap
->a_bp
;
1982 register struct vnode
*vp
= bp
->b_vp
;
1983 #if BYTE_ORDER == LITTLE_ENDIAN
1984 BlockDescriptor block
;
1986 /* Trap B-Tree writes */
1987 if ((VTOC(vp
)->c_fileid
== kHFSExtentsFileID
) ||
1988 (VTOC(vp
)->c_fileid
== kHFSCatalogFileID
)) {
1990 /* Swap if the B-Tree node is in native byte order */
1991 if (((UInt16
*)((char *)bp
->b_data
+ bp
->b_bcount
- 2))[0] == 0x000e) {
1992 /* Prepare the block pointer */
1993 block
.blockHeader
= bp
;
1994 block
.buffer
= bp
->b_data
;
1995 /* not found in cache ==> came from disk */
1996 block
.blockReadFromDisk
= (bp
->b_flags
& B_CACHE
) == 0;
1997 block
.blockSize
= bp
->b_bcount
;
1999 /* Endian un-swap B-Tree node */
2000 SWAP_BT_NODE (&block
, ISHFSPLUS (VTOVCB(vp
)), VTOC(vp
)->c_fileid
, 1);
2003 /* We don't check to make sure that it's 0x0e00 because it could be all zeros */
2006 /* This buffer shouldn't be locked anymore but if it is clear it */
2007 if (ISSET(bp
->b_flags
, B_LOCKED
)) {
2009 if (VTOHFS(vp
)->jnl
) {
2010 panic("hfs: CLEARING the lock bit on bp 0x%x\n", bp
);
2012 CLR(bp
->b_flags
, B_LOCKED
);
2013 printf("hfs_bwrite: called with lock bit set\n");
2015 retval
= vn_bwrite (ap
);