2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 /* @(#)hfs_readwrite.c 1.0
27 * (c) 1998-2001 Apple Computer, Inc. All Rights Reserved
29 * hfs_readwrite.c -- vnode operations to deal with reading and writing files.
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/resourcevar.h>
36 #include <sys/kernel.h>
37 #include <sys/fcntl.h>
41 #include <sys/vnode.h>
44 #include <miscfs/specfs/specdev.h>
47 #include <vm/vm_pageout.h>
49 #include <sys/kdebug.h>
52 #include "hfs_endian.h"
53 #include "hfs_quota.h"
54 #include "hfscommon/headers/FileMgrInternal.h"
55 #include "hfscommon/headers/BTreesInternal.h"
56 #include "hfs_cnode.h"
59 extern int overflow_extents(struct filefork
*fp
);
61 #define can_cluster(size) ((((size & (4096-1))) == 0) && (size <= (MAXPHYSIO/2)))
64 MAXHFSFILESIZE
= 0x7FFFFFFF /* this needs to go in the mount structure */
67 extern u_int32_t
GetLogicalBlockSize(struct vnode
*vp
);
70 /*****************************************************************************
72 * Operations on vnodes
74 *****************************************************************************/
81 INOUT struct uio *uio;
83 IN struct ucred *cred;
89 struct vop_read_args
/* {
96 register struct uio
*uio
= ap
->a_uio
;
97 register struct vnode
*vp
= ap
->a_vp
;
102 u_long fragSize
, moveSize
, startOffset
, ioxfersize
;
103 int devBlockSize
= 0;
104 off_t bytesRemaining
;
109 /* Preflight checks */
110 if (vp
->v_type
!= VREG
&& vp
->v_type
!= VLNK
)
111 return (EISDIR
); /* HFS can only read files */
112 if (uio
->uio_resid
== 0)
113 return (0); /* Nothing left to do */
114 if (uio
->uio_offset
< 0)
115 return (EINVAL
); /* cant read from a negative offset */
119 filesize
= fp
->ff_size
;
120 filebytes
= (off_t
)fp
->ff_blocks
* (off_t
)VTOVCB(vp
)->blockSize
;
121 if (uio
->uio_offset
> filesize
) {
122 if ((!ISHFSPLUS(VTOVCB(vp
))) && (uio
->uio_offset
> (off_t
)MAXHFSFILESIZE
))
128 VOP_DEVBLOCKSIZE(cp
->c_devvp
, &devBlockSize
);
130 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 12)) | DBG_FUNC_START
,
131 (int)uio
->uio_offset
, uio
->uio_resid
, (int)filesize
, (int)filebytes
, 0);
133 if (UBCISVALID(vp
)) {
134 retval
= cluster_read(vp
, uio
, filesize
, devBlockSize
, 0);
137 for (retval
= 0, bp
= NULL
; uio
->uio_resid
> 0; bp
= NULL
) {
139 if ((bytesRemaining
= (filesize
- uio
->uio_offset
)) <= 0)
142 logBlockNo
= (daddr_t
)(uio
->uio_offset
/ PAGE_SIZE_64
);
143 startOffset
= (u_long
) (uio
->uio_offset
& PAGE_MASK_64
);
144 fragSize
= PAGE_SIZE
;
146 if (((logBlockNo
* PAGE_SIZE
) + fragSize
) < filesize
)
147 ioxfersize
= fragSize
;
149 ioxfersize
= filesize
- (logBlockNo
* PAGE_SIZE
);
150 ioxfersize
= (ioxfersize
+ (devBlockSize
- 1)) & ~(devBlockSize
- 1);
152 moveSize
= ioxfersize
;
153 moveSize
-= startOffset
;
155 if (bytesRemaining
< moveSize
)
156 moveSize
= bytesRemaining
;
158 if (uio
->uio_resid
< moveSize
) {
159 moveSize
= uio
->uio_resid
;
165 if (( uio
->uio_offset
+ fragSize
) >= filesize
) {
166 retval
= bread(vp
, logBlockNo
, ioxfersize
, NOCRED
, &bp
);
168 } else if (logBlockNo
- 1 == vp
->v_lastr
&& !(vp
->v_flag
& VRAOFF
)) {
169 daddr_t nextLogBlockNo
= logBlockNo
+ 1;
172 if (((nextLogBlockNo
* PAGE_SIZE
) +
173 (daddr_t
)fragSize
) < filesize
)
176 nextsize
= filesize
- (nextLogBlockNo
* PAGE_SIZE
);
177 nextsize
= (nextsize
+ (devBlockSize
- 1)) & ~(devBlockSize
- 1);
179 retval
= breadn(vp
, logBlockNo
, ioxfersize
, &nextLogBlockNo
, &nextsize
, 1, NOCRED
, &bp
);
181 retval
= bread(vp
, logBlockNo
, ioxfersize
, NOCRED
, &bp
);
184 if (retval
!= E_NONE
) {
191 vp
->v_lastr
= logBlockNo
;
194 * We should only get non-zero b_resid when an I/O retval
195 * has occurred, which should cause us to break above.
196 * However, if the short read did not cause an retval,
197 * then we want to ensure that we do not uiomove bad
198 * or uninitialized data.
200 ioxfersize
-= bp
->b_resid
;
202 if (ioxfersize
< moveSize
) { /* XXX PPD This should take the offset into account, too! */
205 moveSize
= ioxfersize
;
207 if ((startOffset
+ moveSize
) > bp
->b_bcount
)
208 panic("hfs_read: bad startOffset or moveSize\n");
210 if ((retval
= uiomove((caddr_t
)bp
->b_data
+ startOffset
, (int)moveSize
, uio
)))
213 if (S_ISREG(cp
->c_mode
) &&
214 (((startOffset
+ moveSize
) == fragSize
) || (uio
->uio_offset
== filesize
))) {
215 bp
->b_flags
|= B_AGE
;
219 /* Start of loop resets bp to NULL before reaching outside this block... */
227 cp
->c_flag
|= C_ACCESS
;
229 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 12)) | DBG_FUNC_END
,
230 (int)uio
->uio_offset
, uio
->uio_resid
, (int)filesize
, (int)filebytes
, 0);
236 * Write data to a file or directory.
241 INOUT struct uio *uio;
243 IN struct ucred *cred;
248 struct vop_write_args
/* {
252 struct ucred *a_cred;
255 struct vnode
*vp
= ap
->a_vp
;
256 struct uio
*uio
= ap
->a_uio
;
263 int devBlockSize
= 0;
266 off_t origFileSize
, currOffset
, writelimit
, bytesToAdd
;
267 off_t actualBytesAdded
;
268 u_long blkoffset
, resid
, xfersize
, clearSize
;
273 struct hfsmount
*hfsmp
;
274 int started_tr
= 0, grabbed_lock
= 0;
276 ioflag
= ap
->a_ioflag
;
278 if (uio
->uio_offset
< 0)
280 if (uio
->uio_resid
== 0)
282 if (vp
->v_type
!= VREG
&& vp
->v_type
!= VLNK
)
283 return (EISDIR
); /* Can only write files */
288 fileblocks
= fp
->ff_blocks
;
289 filebytes
= (off_t
)fileblocks
* (off_t
)vcb
->blockSize
;
291 if (ioflag
& IO_APPEND
)
292 uio
->uio_offset
= fp
->ff_size
;
293 if ((cp
->c_flags
& APPEND
) && uio
->uio_offset
!= fp
->ff_size
)
296 // XXXdbg - don't allow modification of the journal or journal_info_block
297 if (VTOHFS(vp
)->jnl
&& cp
->c_datafork
) {
298 struct HFSPlusExtentDescriptor
*extd
;
300 extd
= &cp
->c_datafork
->ff_data
.cf_extents
[0];
301 if (extd
->startBlock
== VTOVCB(vp
)->vcbJinfoBlock
|| extd
->startBlock
== VTOHFS(vp
)->jnl_start
) {
306 writelimit
= uio
->uio_offset
+ uio
->uio_resid
;
309 * Maybe this should be above the vnode op call, but so long as
310 * file servers have no limits, I don't think it matters.
313 if (vp
->v_type
== VREG
&& p
&&
314 writelimit
> p
->p_rlimit
[RLIMIT_FSIZE
].rlim_cur
) {
320 VOP_DEVBLOCKSIZE(cp
->c_devvp
, &devBlockSize
);
322 resid
= uio
->uio_resid
;
323 origFileSize
= fp
->ff_size
;
324 eflags
= kEFDeferMask
; /* defer file block allocations */
325 filebytes
= (off_t
)fp
->ff_blocks
* (off_t
)vcb
->blockSize
;
328 * NOTE: In the following loop there are two positions tracked:
329 * currOffset is the current I/O starting offset. currOffset
330 * is never >LEOF; the LEOF is nudged along with currOffset as
331 * data is zeroed or written. uio->uio_offset is the start of
332 * the current I/O operation. It may be arbitrarily beyond
335 * The following is true at all times:
336 * currOffset <= LEOF <= uio->uio_offset <= writelimit
338 currOffset
= MIN(uio
->uio_offset
, fp
->ff_size
);
340 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 0)) | DBG_FUNC_START
,
341 (int)uio
->uio_offset
, uio
->uio_resid
, (int)fp
->ff_size
, (int)filebytes
, 0);
344 /* Now test if we need to extend the file */
345 /* Doing so will adjust the filebytes for us */
348 if(writelimit
> filebytes
) {
349 bytesToAdd
= writelimit
- filebytes
;
351 retval
= hfs_chkdq(cp
, (int64_t)(roundup(bytesToAdd
, vcb
->blockSize
)),
359 if (writelimit
> filebytes
) {
360 hfs_global_shared_lock_acquire(hfsmp
);
363 if (hfsmp
->jnl
&& (writelimit
> filebytes
)) {
364 if (journal_start_transaction(hfsmp
->jnl
) != 0) {
365 hfs_global_shared_lock_release(hfsmp
);
371 while (writelimit
> filebytes
) {
373 bytesToAdd
= writelimit
- filebytes
;
374 if (suser(ap
->a_cred
, NULL
) != 0)
375 eflags
|= kEFReserveMask
;
377 /* lock extents b-tree (also protects volume bitmap) */
378 retval
= hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_EXCLUSIVE
, current_proc());
379 if (retval
!= E_NONE
)
382 retval
= MacToVFSError(ExtendFileC (vcb
, (FCB
*)fp
, bytesToAdd
,
383 0, eflags
, &actualBytesAdded
));
385 (void) hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_RELEASE
, p
);
386 if ((actualBytesAdded
== 0) && (retval
== E_NONE
))
388 if (retval
!= E_NONE
)
390 filebytes
= (off_t
)fp
->ff_blocks
* (off_t
)vcb
->blockSize
;
391 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 0)) | DBG_FUNC_NONE
,
392 (int)uio
->uio_offset
, uio
->uio_resid
, (int)fp
->ff_size
, (int)filebytes
, 0);
397 hfs_flushvolumeheader(hfsmp
, MNT_NOWAIT
, 0);
398 journal_end_transaction(hfsmp
->jnl
);
402 hfs_global_shared_lock_release(hfsmp
);
406 if (UBCISVALID(vp
) && retval
== E_NONE
) {
412 off_t io_start
, io_end
;
414 struct rl_entry
*invalid_range
;
416 if (writelimit
> fp
->ff_size
)
417 filesize
= writelimit
;
419 filesize
= fp
->ff_size
;
421 lflag
= (ioflag
& IO_SYNC
);
423 if (uio
->uio_offset
<= fp
->ff_size
) {
424 zero_off
= uio
->uio_offset
& ~PAGE_MASK_64
;
426 /* Check to see whether the area between the zero_offset and the start
427 of the transfer to see whether is invalid and should be zero-filled
428 as part of the transfer:
430 if (rl_scan(&fp
->ff_invalidranges
, zero_off
, uio
->uio_offset
- 1, &invalid_range
) != RL_NOOVERLAP
)
431 lflag
|= IO_HEADZEROFILL
;
433 off_t eof_page_base
= fp
->ff_size
& ~PAGE_MASK_64
;
435 /* The bytes between fp->ff_size and uio->uio_offset must never be
436 read without being zeroed. The current last block is filled with zeroes
437 if it holds valid data but in all cases merely do a little bookkeeping
438 to track the area from the end of the current last page to the start of
439 the area actually written. For the same reason only the bytes up to the
440 start of the page where this write will start is invalidated; any remainder
441 before uio->uio_offset is explicitly zeroed as part of the cluster_write.
443 Note that inval_start, the start of the page after the current EOF,
444 may be past the start of the write, in which case the zeroing
445 will be handled by the cluser_write of the actual data.
447 inval_start
= (fp
->ff_size
+ (PAGE_SIZE_64
- 1)) & ~PAGE_MASK_64
;
448 inval_end
= uio
->uio_offset
& ~PAGE_MASK_64
;
449 zero_off
= fp
->ff_size
;
451 if ((fp
->ff_size
& PAGE_MASK_64
) &&
452 (rl_scan(&fp
->ff_invalidranges
,
455 &invalid_range
) != RL_NOOVERLAP
)) {
456 /* The page containing the EOF is not valid, so the
457 entire page must be made inaccessible now. If the write
458 starts on a page beyond the page containing the eof
459 (inval_end > eof_page_base), add the
460 whole page to the range to be invalidated. Otherwise
461 (i.e. if the write starts on the same page), zero-fill
462 the entire page explicitly now:
464 if (inval_end
> eof_page_base
) {
465 inval_start
= eof_page_base
;
467 zero_off
= eof_page_base
;
471 if (inval_start
< inval_end
) {
472 /* There's some range of data that's going to be marked invalid */
474 if (zero_off
< inval_start
) {
475 /* The pages between inval_start and inval_end are going to be invalidated,
476 and the actual write will start on a page past inval_end. Now's the last
477 chance to zero-fill the page containing the EOF:
479 retval
= cluster_write(vp
, (struct uio
*) 0,
480 fp
->ff_size
, inval_start
,
481 zero_off
, (off_t
)0, devBlockSize
,
482 lflag
| IO_HEADZEROFILL
| IO_NOZERODIRTY
);
483 if (retval
) goto ioerr_exit
;
486 /* Mark the remaining area of the newly allocated space as invalid: */
487 rl_add(inval_start
, inval_end
- 1 , &fp
->ff_invalidranges
);
488 cp
->c_zftimeout
= time
.tv_sec
+ ZFTIMELIMIT
;
489 zero_off
= fp
->ff_size
= inval_end
;
492 if (uio
->uio_offset
> zero_off
) lflag
|= IO_HEADZEROFILL
;
495 /* Check to see whether the area between the end of the write and the end of
496 the page it falls in is invalid and should be zero-filled as part of the transfer:
498 tail_off
= (writelimit
+ (PAGE_SIZE_64
- 1)) & ~PAGE_MASK_64
;
499 if (tail_off
> filesize
) tail_off
= filesize
;
500 if (tail_off
> writelimit
) {
501 if (rl_scan(&fp
->ff_invalidranges
, writelimit
, tail_off
- 1, &invalid_range
) != RL_NOOVERLAP
) {
502 lflag
|= IO_TAILZEROFILL
;
507 * if the write starts beyond the current EOF (possibly advanced in the
508 * zeroing of the last block, above), then we'll zero fill from the current EOF
509 * to where the write begins:
511 * NOTE: If (and ONLY if) the portion of the file about to be written is
512 * before the current EOF it might be marked as invalid now and must be
513 * made readable (removed from the invalid ranges) before cluster_write
516 io_start
= (lflag
& IO_HEADZEROFILL
) ? zero_off
: uio
->uio_offset
;
517 io_end
= (lflag
& IO_TAILZEROFILL
) ? tail_off
: writelimit
;
518 if (io_start
< fp
->ff_size
) {
519 rl_remove(io_start
, io_end
- 1, &fp
->ff_invalidranges
);
521 retval
= cluster_write(vp
, uio
, fp
->ff_size
, filesize
, zero_off
,
522 tail_off
, devBlockSize
, lflag
| IO_NOZERODIRTY
);
524 if (uio
->uio_offset
> fp
->ff_size
) {
525 fp
->ff_size
= uio
->uio_offset
;
527 ubc_setsize(vp
, fp
->ff_size
); /* XXX check errors */
529 if (resid
> uio
->uio_resid
)
530 cp
->c_flag
|= C_CHANGE
| C_UPDATE
;
532 while (retval
== E_NONE
&& uio
->uio_resid
> 0) {
533 logBlockNo
= currOffset
/ PAGE_SIZE
;
534 blkoffset
= currOffset
& PAGE_MASK
;
536 if ((filebytes
- currOffset
) < PAGE_SIZE_64
)
537 fragSize
= filebytes
- ((off_t
)logBlockNo
* PAGE_SIZE_64
);
539 fragSize
= PAGE_SIZE
;
540 xfersize
= fragSize
- blkoffset
;
542 /* Make any adjustments for boundary conditions */
543 if (currOffset
+ (off_t
)xfersize
> writelimit
)
544 xfersize
= writelimit
- currOffset
;
547 * There is no need to read into bp if:
548 * We start on a block boundary and will overwrite the whole block
552 if ((blkoffset
== 0) && (xfersize
>= fragSize
)) {
553 bp
= getblk(vp
, logBlockNo
, fragSize
, 0, 0, BLK_READ
);
556 if (bp
->b_blkno
== -1) {
558 retval
= EIO
; /* XXX */
563 if (currOffset
== fp
->ff_size
&& blkoffset
== 0) {
564 bp
= getblk(vp
, logBlockNo
, fragSize
, 0, 0, BLK_READ
);
566 if (bp
->b_blkno
== -1) {
568 retval
= EIO
; /* XXX */
573 * This I/O transfer is not sufficiently aligned,
574 * so read the affected block into a buffer:
576 retval
= bread(vp
, logBlockNo
, fragSize
, ap
->a_cred
, &bp
);
577 if (retval
!= E_NONE
) {
585 /* See if we are starting to write within file boundaries:
586 * If not, then we need to present a "hole" for the area
587 * between the current EOF and the start of the current
590 * Note that currOffset is only less than uio_offset if
591 * uio_offset > LEOF...
593 if (uio
->uio_offset
> currOffset
) {
594 clearSize
= MIN(uio
->uio_offset
- currOffset
, xfersize
);
595 bzero(bp
->b_data
+ blkoffset
, clearSize
);
596 currOffset
+= clearSize
;
597 blkoffset
+= clearSize
;
598 xfersize
-= clearSize
;
602 retval
= uiomove((caddr_t
)bp
->b_data
+ blkoffset
, (int)xfersize
, uio
);
603 currOffset
+= xfersize
;
606 if (ioflag
& IO_SYNC
) {
607 (void)VOP_BWRITE(bp
);
608 } else if ((xfersize
+ blkoffset
) == fragSize
) {
609 bp
->b_flags
|= B_AGE
;
615 /* Update the EOF if we just extended the file
616 * (the PEOF has already been moved out and the
617 * block mapping table has been updated):
619 if (currOffset
> fp
->ff_size
) {
620 fp
->ff_size
= currOffset
;
622 ubc_setsize(vp
, fp
->ff_size
); /* XXX check errors */
624 if (retval
|| (resid
== 0))
626 cp
->c_flag
|= C_CHANGE
| C_UPDATE
;
632 * If we successfully wrote any data, and we are not the superuser
633 * we clear the setuid and setgid bits as a precaution against
636 if (resid
> uio
->uio_resid
&& ap
->a_cred
&& ap
->a_cred
->cr_uid
!= 0)
637 cp
->c_mode
&= ~(S_ISUID
| S_ISGID
);
640 if (ioflag
& IO_UNIT
) {
641 (void)VOP_TRUNCATE(vp
, origFileSize
,
642 ioflag
& IO_SYNC
, ap
->a_cred
, uio
->uio_procp
);
643 uio
->uio_offset
-= resid
- uio
->uio_resid
;
644 uio
->uio_resid
= resid
;
645 filebytes
= (off_t
)fp
->ff_blocks
* (off_t
)vcb
->blockSize
;
647 } else if (resid
> uio
->uio_resid
&& (ioflag
& IO_SYNC
)) {
649 retval
= VOP_UPDATE(vp
, &tv
, &tv
, 1);
652 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 0)) | DBG_FUNC_END
,
653 (int)uio
->uio_offset
, uio
->uio_resid
, (int)fp
->ff_size
, (int)filebytes
, 0);
668 IN struct ucred *cred;
677 struct vop_ioctl_args
/* {
682 struct ucred *a_cred;
686 switch (ap
->a_command
) {
688 register struct cnode
*cp
;
689 register struct vnode
*vp
;
690 register struct radvisory
*ra
;
692 int devBlockSize
= 0;
697 if (vp
->v_type
!= VREG
)
700 VOP_LEASE(vp
, ap
->a_p
, ap
->a_cred
, LEASE_READ
);
701 error
= vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, ap
->a_p
);
705 ra
= (struct radvisory
*)(ap
->a_data
);
709 if (ra
->ra_offset
>= fp
->ff_size
) {
710 VOP_UNLOCK(vp
, 0, ap
->a_p
);
713 VOP_DEVBLOCKSIZE(cp
->c_devvp
, &devBlockSize
);
715 error
= advisory_read(vp
, fp
->ff_size
, ra
->ra_offset
, ra
->ra_count
, devBlockSize
);
716 VOP_UNLOCK(vp
, 0, ap
->a_p
);
721 case 2: /* F_READBOOTBLOCKS */
722 case 3: /* F_WRITEBOOTBLOCKS */
724 struct vnode
*vp
= ap
->a_vp
;
725 struct vnode
*devvp
= NULL
;
726 struct fbootstraptransfer
*btd
= (struct fbootstraptransfer
*)ap
->a_data
;
736 if ((vp
->v_flag
& VROOT
) == 0) return EINVAL
;
737 if (btd
->fbt_offset
+ btd
->fbt_length
> 1024) return EINVAL
;
739 devvp
= VTOHFS(vp
)->hfs_devvp
;
740 aiov
.iov_base
= btd
->fbt_buffer
;
741 aiov
.iov_len
= btd
->fbt_length
;
743 auio
.uio_iov
= &aiov
;
745 auio
.uio_offset
= btd
->fbt_offset
;
746 auio
.uio_resid
= btd
->fbt_length
;
747 auio
.uio_segflg
= UIO_USERSPACE
;
748 auio
.uio_rw
= (ap
->a_command
== 3) ? UIO_WRITE
: UIO_READ
; /* F_WRITEBOOTSTRAP / F_READBOOTSTRAP */
749 auio
.uio_procp
= ap
->a_p
;
751 VOP_DEVBLOCKSIZE(devvp
, &devBlockSize
);
753 while (auio
.uio_resid
> 0) {
754 blockNumber
= auio
.uio_offset
/ devBlockSize
;
755 error
= bread(devvp
, blockNumber
, devBlockSize
, ap
->a_cred
, &bp
);
761 blockOffset
= auio
.uio_offset
% devBlockSize
;
762 xfersize
= devBlockSize
- blockOffset
;
763 error
= uiomove((caddr_t
)bp
->b_data
+ blockOffset
, (int)xfersize
, &auio
);
768 if (auio
.uio_rw
== UIO_WRITE
) {
769 error
= VOP_BWRITE(bp
);
770 if (error
) return error
;
778 case _IOC(IOC_OUT
,'h', 4, 0): /* Create date in local time */
780 *(time_t *)(ap
->a_data
) = to_bsd_time(VTOVCB(ap
->a_vp
)->localCreateDate
);
788 /* Should never get here */
795 struct vop_select_args
/* {
799 struct ucred *a_cred;
805 * We should really check to see if I/O is possible.
811 * Bmap converts a the logical block number of a file to its physical block
812 * number on the disk.
816 * vp - address of vnode file the file
817 * bn - which logical block to convert to a physical block number.
818 * vpp - returns the vnode for the block special file holding the filesystem
819 * containing the file of interest
820 * bnp - address of where to return the filesystem physical block number
827 OUT struct vnode **vpp;
832 * Converts a logical block number to a physical block, and optionally returns
833 * the amount of remaining blocks in a run. The logical block is based on hfsNode.logBlockSize.
834 * The physical block number is based on the device block size, currently its 512.
835 * The block run is returned in logical blocks, and is the REMAINING amount of blocks
840 struct vop_bmap_args
/* {
843 struct vnode **a_vpp;
848 struct vnode
*vp
= ap
->a_vp
;
849 struct cnode
*cp
= VTOC(vp
);
850 struct filefork
*fp
= VTOF(vp
);
851 struct hfsmount
*hfsmp
= VTOHFS(vp
);
853 daddr_t logBlockSize
;
854 size_t bytesContAvail
= 0;
856 struct proc
*p
= NULL
;
858 struct rl_entry
*invalid_range
;
859 enum rl_overlaptype overlaptype
;
862 * Check for underlying vnode requests and ensure that logical
863 * to physical mapping is requested.
865 if (ap
->a_vpp
!= NULL
)
866 *ap
->a_vpp
= cp
->c_devvp
;
867 if (ap
->a_bnp
== NULL
)
870 /* Only clustered I/O should have delayed allocations. */
871 DBG_ASSERT(fp
->ff_unallocblocks
== 0);
873 logBlockSize
= GetLogicalBlockSize(vp
);
874 blockposition
= (off_t
)ap
->a_bn
* (off_t
)logBlockSize
;
876 lockExtBtree
= overflow_extents(fp
);
879 retval
= hfs_metafilelocking(hfsmp
, kHFSExtentsFileID
,
880 LK_EXCLUSIVE
| LK_CANRECURSE
, p
);
885 retval
= MacToVFSError(
886 MapFileBlockC (HFSTOVCB(hfsmp
),
893 if (lockExtBtree
) (void) hfs_metafilelocking(hfsmp
, kHFSExtentsFileID
, LK_RELEASE
, p
);
895 if (retval
== E_NONE
) {
896 /* Adjust the mapping information for invalid file ranges: */
897 overlaptype
= rl_scan(&fp
->ff_invalidranges
,
899 blockposition
+ MAXPHYSIO
- 1,
901 if (overlaptype
!= RL_NOOVERLAP
) {
902 switch(overlaptype
) {
903 case RL_MATCHINGOVERLAP
:
904 case RL_OVERLAPCONTAINSRANGE
:
905 case RL_OVERLAPSTARTSBEFORE
:
906 /* There's no valid block for this byte offset: */
907 *ap
->a_bnp
= (daddr_t
)-1;
908 bytesContAvail
= invalid_range
->rl_end
+ 1 - blockposition
;
911 case RL_OVERLAPISCONTAINED
:
912 case RL_OVERLAPENDSAFTER
:
913 /* The range of interest hits an invalid block before the end: */
914 if (invalid_range
->rl_start
== blockposition
) {
915 /* There's actually no valid information to be had starting here: */
916 *ap
->a_bnp
= (daddr_t
)-1;
917 if ((fp
->ff_size
> (invalid_range
->rl_end
+ 1)) &&
918 (invalid_range
->rl_end
+ 1 - blockposition
< bytesContAvail
)) {
919 bytesContAvail
= invalid_range
->rl_end
+ 1 - blockposition
;
922 bytesContAvail
= invalid_range
->rl_start
- blockposition
;
926 if (bytesContAvail
> MAXPHYSIO
) bytesContAvail
= MAXPHYSIO
;
929 /* Figure out how many read ahead blocks there are */
930 if (ap
->a_runp
!= NULL
) {
931 if (can_cluster(logBlockSize
)) {
932 /* Make sure this result never goes negative: */
933 *ap
->a_runp
= (bytesContAvail
< logBlockSize
) ? 0 : (bytesContAvail
/ logBlockSize
) - 1;
943 /* blktooff converts logical block number to file offset */
947 struct vop_blktooff_args
/* {
953 if (ap
->a_vp
== NULL
)
955 *ap
->a_offset
= (off_t
)ap
->a_lblkno
* PAGE_SIZE_64
;
962 struct vop_offtoblk_args
/* {
968 if (ap
->a_vp
== NULL
)
970 *ap
->a_lblkno
= ap
->a_offset
/ PAGE_SIZE_64
;
977 struct vop_cmap_args
/* {
986 struct hfsmount
*hfsmp
= VTOHFS(ap
->a_vp
);
987 struct filefork
*fp
= VTOF(ap
->a_vp
);
988 size_t bytesContAvail
= 0;
990 int lockExtBtree
= 0;
991 struct proc
*p
= NULL
;
992 struct rl_entry
*invalid_range
;
993 enum rl_overlaptype overlaptype
;
994 int started_tr
= 0, grabbed_lock
= 0;
997 * Check for underlying vnode requests and ensure that logical
998 * to physical mapping is requested.
1000 if (ap
->a_bpn
== NULL
)
1005 if (fp
->ff_unallocblocks
) {
1009 hfs_global_shared_lock_acquire(hfsmp
);
1013 if (journal_start_transaction(hfsmp
->jnl
) != 0) {
1014 hfs_global_shared_lock_release(hfsmp
);
1021 if (retval
= hfs_metafilelocking(hfsmp
, kHFSExtentsFileID
, LK_EXCLUSIVE
| LK_CANRECURSE
, p
)) {
1023 journal_end_transaction(hfsmp
->jnl
);
1026 hfs_global_shared_lock_release(hfsmp
);
1030 } else if (overflow_extents(fp
)) {
1032 if (retval
= hfs_metafilelocking(hfsmp
, kHFSExtentsFileID
, LK_EXCLUSIVE
| LK_CANRECURSE
, p
)) {
1038 * Check for any delayed allocations.
1040 if (fp
->ff_unallocblocks
) {
1041 SInt64 reqbytes
, actbytes
;
1044 // Make sure we have a transaction. It's possible
1045 // that we came in and fp->ff_unallocblocks was zero
1046 // but during the time we blocked acquiring the extents
1047 // btree, ff_unallocblocks became non-zero and so we
1048 // will need to start a transaction.
1050 if (hfsmp
->jnl
&& started_tr
== 0) {
1052 (void) hfs_metafilelocking(hfsmp
, kHFSExtentsFileID
, LK_RELEASE
, p
);
1059 reqbytes
= (SInt64
)fp
->ff_unallocblocks
*
1060 (SInt64
)HFSTOVCB(hfsmp
)->blockSize
;
1062 * Release the blocks on loan and aquire some real ones.
1063 * Note that we can race someone else for these blocks
1064 * (and lose) so cmap needs to handle a failure here.
1065 * Currently this race can't occur because all allocations
1066 * are protected by an exclusive lock on the Extents
1069 HFSTOVCB(hfsmp
)->loanedBlocks
-= fp
->ff_unallocblocks
;
1070 FTOC(fp
)->c_blocks
-= fp
->ff_unallocblocks
;
1071 fp
->ff_blocks
-= fp
->ff_unallocblocks
;
1072 fp
->ff_unallocblocks
= 0;
1074 while (retval
== 0 && reqbytes
> 0) {
1075 retval
= MacToVFSError(ExtendFileC(HFSTOVCB(hfsmp
),
1076 (FCB
*)fp
, reqbytes
, 0,
1077 kEFAllMask
| kEFNoClumpMask
, &actbytes
));
1078 if (retval
== 0 && actbytes
== 0)
1082 fp
->ff_unallocblocks
=
1083 reqbytes
/ HFSTOVCB(hfsmp
)->blockSize
;
1084 HFSTOVCB(hfsmp
)->loanedBlocks
+= fp
->ff_unallocblocks
;
1085 FTOC(fp
)->c_blocks
+= fp
->ff_unallocblocks
;
1086 fp
->ff_blocks
+= fp
->ff_unallocblocks
;
1088 reqbytes
-= actbytes
;
1092 (void) hfs_metafilelocking(hfsmp
, kHFSExtentsFileID
, LK_RELEASE
, p
);
1094 hfs_flushvolumeheader(hfsmp
, MNT_NOWAIT
, 0);
1095 journal_end_transaction(hfsmp
->jnl
);
1098 hfs_global_shared_lock_release(hfsmp
);
1102 VTOC(ap
->a_vp
)->c_flag
|= C_MODIFIED
;
1105 retval
= MacToVFSError(
1106 MapFileBlockC (HFSTOVCB(hfsmp
),
1114 (void) hfs_metafilelocking(hfsmp
, kHFSExtentsFileID
, LK_RELEASE
, p
);
1118 hfs_flushvolumeheader(hfsmp
, MNT_NOWAIT
, 0);
1119 journal_end_transaction(hfsmp
->jnl
);
1123 hfs_global_shared_lock_release(hfsmp
);
1127 if (retval
== E_NONE
) {
1128 /* Adjust the mapping information for invalid file ranges: */
1129 overlaptype
= rl_scan(&fp
->ff_invalidranges
,
1131 ap
->a_foffset
+ (off_t
)bytesContAvail
- 1,
1133 if (overlaptype
!= RL_NOOVERLAP
) {
1134 switch(overlaptype
) {
1135 case RL_MATCHINGOVERLAP
:
1136 case RL_OVERLAPCONTAINSRANGE
:
1137 case RL_OVERLAPSTARTSBEFORE
:
1138 /* There's no valid block for this byte offset: */
1139 *ap
->a_bpn
= (daddr_t
)-1;
1141 /* There's no point limiting the amount to be returned if the
1142 invalid range that was hit extends all the way to the EOF
1143 (i.e. there's no valid bytes between the end of this range
1144 and the file's EOF):
1146 if ((fp
->ff_size
> (invalid_range
->rl_end
+ 1)) &&
1147 (invalid_range
->rl_end
+ 1 - ap
->a_foffset
< bytesContAvail
)) {
1148 bytesContAvail
= invalid_range
->rl_end
+ 1 - ap
->a_foffset
;
1152 case RL_OVERLAPISCONTAINED
:
1153 case RL_OVERLAPENDSAFTER
:
1154 /* The range of interest hits an invalid block before the end: */
1155 if (invalid_range
->rl_start
== ap
->a_foffset
) {
1156 /* There's actually no valid information to be had starting here: */
1157 *ap
->a_bpn
= (daddr_t
)-1;
1158 if ((fp
->ff_size
> (invalid_range
->rl_end
+ 1)) &&
1159 (invalid_range
->rl_end
+ 1 - ap
->a_foffset
< bytesContAvail
)) {
1160 bytesContAvail
= invalid_range
->rl_end
+ 1 - ap
->a_foffset
;
1163 bytesContAvail
= invalid_range
->rl_start
- ap
->a_foffset
;
1167 if (bytesContAvail
> ap
->a_size
) bytesContAvail
= ap
->a_size
;
1170 if (ap
->a_run
) *ap
->a_run
= bytesContAvail
;
1174 *(int *)ap
->a_poff
= 0;
1181 * Read or write a buffer that is not contiguous on disk. We loop over
1182 * each device block, copying to or from caller's buffer.
1184 * We could be a bit more efficient by transferring as much data as is
1185 * contiguous. But since this routine should rarely be called, and that
1186 * would be more complicated; best to keep it simple.
1189 hfs_strategy_fragmented(struct buf
*bp
)
1191 register struct vnode
*vp
= bp
->b_vp
;
1192 register struct cnode
*cp
= VTOC(vp
);
1193 register struct vnode
*devvp
= cp
->c_devvp
;
1194 caddr_t ioaddr
; /* Address of fragment within bp */
1195 struct buf
*frag
= NULL
; /* For reading or writing a single block */
1197 long remaining
; /* Bytes (in bp) left to transfer */
1198 off_t offset
; /* Logical offset of current fragment in vp */
1199 u_long block_size
; /* Size of one device block (and one I/O) */
1201 /* Make sure we redo this mapping for the next I/O */
1202 bp
->b_blkno
= bp
->b_lblkno
;
1204 /* Set up the logical position and number of bytes to read/write */
1205 offset
= (off_t
) bp
->b_lblkno
* (off_t
) GetLogicalBlockSize(vp
);
1206 block_size
= VTOHFS(vp
)->hfs_phys_block_size
;
1208 /* Get an empty buffer to do the deblocking */
1209 frag
= geteblk(block_size
);
1210 if (ISSET(bp
->b_flags
, B_READ
))
1211 SET(frag
->b_flags
, B_READ
);
1213 for (ioaddr
= bp
->b_data
, remaining
= bp
->b_bcount
; remaining
!= 0;
1214 ioaddr
+= block_size
, offset
+= block_size
,
1215 remaining
-= block_size
) {
1216 frag
->b_resid
= frag
->b_bcount
;
1217 CLR(frag
->b_flags
, B_DONE
);
1219 /* Map the current position to a physical block number */
1220 retval
= VOP_CMAP(vp
, offset
, block_size
, &frag
->b_lblkno
,
1226 * Did we try to read a hole?
1227 * (Should never happen for metadata!)
1229 if ((long)frag
->b_lblkno
== -1) {
1230 bzero(ioaddr
, block_size
);
1234 /* If writing, copy before I/O */
1235 if (!ISSET(bp
->b_flags
, B_READ
))
1236 bcopy(ioaddr
, frag
->b_data
, block_size
);
1238 /* Call the device to do the I/O and wait for it */
1239 frag
->b_blkno
= frag
->b_lblkno
;
1240 frag
->b_vp
= devvp
; /* Used to dispatch via VOP_STRATEGY */
1241 frag
->b_dev
= devvp
->v_rdev
;
1242 retval
= VOP_STRATEGY(frag
);
1246 retval
= biowait(frag
);
1250 /* If reading, copy after the I/O */
1251 if (ISSET(bp
->b_flags
, B_READ
))
1252 bcopy(frag
->b_data
, ioaddr
, block_size
);
1257 // XXXdbg - in the case that this is a meta-data block, it won't affect
1258 // the journal because this bp is for a physical disk block,
1259 // not a logical block that is part of the catalog or extents
1261 SET(frag
->b_flags
, B_INVAL
);
1264 if ((bp
->b_error
= retval
) != 0)
1265 SET(bp
->b_flags
, B_ERROR
);
1267 biodone(bp
); /* This I/O is now complete */
1273 * Calculate the logical to physical mapping if not done already,
1274 * then call the device strategy routine.
1277 # IN struct buf *bp;
1281 struct vop_strategy_args
/* {
1285 register struct buf
*bp
= ap
->a_bp
;
1286 register struct vnode
*vp
= bp
->b_vp
;
1287 register struct cnode
*cp
= VTOC(vp
);
1290 size_t bytes_contig
;
1292 if ( !(bp
->b_flags
& B_VECTORLIST
)) {
1293 if (vp
->v_type
== VBLK
|| vp
->v_type
== VCHR
)
1294 panic("hfs_strategy: device vnode passed!");
1296 if (bp
->b_flags
& B_PAGELIST
) {
1298 * If we have a page list associated with this bp,
1299 * then go through cluster_bp since it knows how to
1300 * deal with a page request that might span non-
1301 * contiguous physical blocks on the disk...
1303 retval
= cluster_bp(bp
);
1305 bp
->b_dev
= vp
->v_rdev
;
1311 * If we don't already know the filesystem relative block
1312 * number then get it using VOP_BMAP(). If VOP_BMAP()
1313 * returns the block number as -1 then we've got a hole in
1314 * the file. Although HFS filesystems don't create files with
1315 * holes, invalidating of subranges of the file (lazy zero
1316 * filling) may create such a situation.
1318 if (bp
->b_blkno
== bp
->b_lblkno
) {
1319 offset
= (off_t
) bp
->b_lblkno
*
1320 (off_t
) GetLogicalBlockSize(vp
);
1322 if ((retval
= VOP_CMAP(vp
, offset
, bp
->b_bcount
,
1323 &bp
->b_blkno
, &bytes_contig
, NULL
))) {
1324 bp
->b_error
= retval
;
1325 bp
->b_flags
|= B_ERROR
;
1329 if (bytes_contig
< bp
->b_bcount
)
1332 * We were asked to read a block that wasn't
1333 * contiguous, so we have to read each of the
1334 * pieces and copy them into the buffer.
1335 * Since ordinary file I/O goes through
1336 * cluster_io (which won't ask us for
1337 * discontiguous data), this is probably an
1338 * attempt to read or write metadata.
1340 return hfs_strategy_fragmented(bp
);
1342 if ((long)bp
->b_blkno
== -1)
1345 if ((long)bp
->b_blkno
== -1) {
1349 if (bp
->b_validend
== 0) {
1351 * Record the exact size of the I/O transfer about to
1354 bp
->b_validend
= bp
->b_bcount
;
1358 bp
->b_dev
= vp
->v_rdev
;
1360 return VOCALL (vp
->v_op
, VOFFSET(vop_strategy
), ap
);
1366 #% truncate vp L L L
1369 IN struct vnode *vp;
1371 IN int flags; (IO_SYNC)
1372 IN struct ucred *cred;
1375 * Truncate a cnode to at most length size, freeing (or adding) the
1378 int hfs_truncate(ap
)
1379 struct vop_truncate_args
/* {
1383 struct ucred *a_cred;
1387 register struct vnode
*vp
= ap
->a_vp
;
1388 register struct cnode
*cp
= VTOC(vp
);
1389 struct filefork
*fp
= VTOF(vp
);
1395 off_t actualBytesAdded
;
1399 struct hfsmount
*hfsmp
;
1401 if (vp
->v_type
!= VREG
&& vp
->v_type
!= VLNK
)
1402 return (EISDIR
); /* cannot truncate an HFS directory! */
1404 length
= ap
->a_length
;
1405 blksize
= VTOVCB(vp
)->blockSize
;
1406 fileblocks
= fp
->ff_blocks
;
1407 filebytes
= (off_t
)fileblocks
* (off_t
)blksize
;
1409 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 7)) | DBG_FUNC_START
,
1410 (int)length
, (int)fp
->ff_size
, (int)filebytes
, 0, 0);
1415 if ((!ISHFSPLUS(VTOVCB(vp
))) && (length
> (off_t
)MAXHFSFILESIZE
))
1424 * We cannot just check if fp->ff_size == length (as an optimization)
1425 * since there may be extra physical blocks that also need truncation.
1428 if (retval
= hfs_getinoquota(cp
))
1433 * Lengthen the size of the file. We must ensure that the
1434 * last byte of the file is allocated. Since the smallest
1435 * value of ff_size is 0, length will be at least 1.
1437 if (length
> fp
->ff_size
) {
1439 retval
= hfs_chkdq(cp
, (int64_t)(roundup(length
- filebytes
, blksize
)),
1445 * If we don't have enough physical space then
1446 * we need to extend the physical size.
1448 if (length
> filebytes
) {
1451 /* All or nothing and don't round up to clumpsize. */
1452 eflags
= kEFAllMask
| kEFNoClumpMask
;
1454 if (suser(ap
->a_cred
, NULL
) != 0)
1455 eflags
|= kEFReserveMask
; /* keep a reserve */
1458 hfs_global_shared_lock_acquire(hfsmp
);
1460 if (journal_start_transaction(hfsmp
->jnl
) != 0) {
1466 /* lock extents b-tree (also protects volume bitmap) */
1467 retval
= hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_EXCLUSIVE
, ap
->a_p
);
1470 journal_end_transaction(hfsmp
->jnl
);
1472 hfs_global_shared_lock_release(hfsmp
);
1477 while ((length
> filebytes
) && (retval
== E_NONE
)) {
1478 bytesToAdd
= length
- filebytes
;
1479 retval
= MacToVFSError(ExtendFileC(VTOVCB(vp
),
1484 &actualBytesAdded
));
1486 filebytes
= (off_t
)fp
->ff_blocks
* (off_t
)blksize
;
1487 if (actualBytesAdded
== 0 && retval
== E_NONE
) {
1488 if (length
> filebytes
)
1494 (void) hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_RELEASE
, ap
->a_p
);
1498 hfs_flushvolumeheader(hfsmp
, MNT_NOWAIT
, 0);
1499 journal_end_transaction(hfsmp
->jnl
);
1501 hfs_global_shared_lock_release(hfsmp
);
1506 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 7)) | DBG_FUNC_NONE
,
1507 (int)length
, (int)fp
->ff_size
, (int)filebytes
, 0, 0);
1510 if (!(ap
->a_flags
& IO_NOZEROFILL
)) {
1511 if (UBCINFOEXISTS(vp
) && retval
== E_NONE
) {
1512 struct rl_entry
*invalid_range
;
1516 zero_limit
= (fp
->ff_size
+ (PAGE_SIZE_64
- 1)) & ~PAGE_MASK_64
;
1517 if (length
< zero_limit
) zero_limit
= length
;
1519 if (length
> fp
->ff_size
) {
1520 /* Extending the file: time to fill out the current last page w. zeroes? */
1521 if ((fp
->ff_size
& PAGE_MASK_64
) &&
1522 (rl_scan(&fp
->ff_invalidranges
, fp
->ff_size
& ~PAGE_MASK_64
,
1523 fp
->ff_size
- 1, &invalid_range
) == RL_NOOVERLAP
)) {
1525 /* There's some valid data at the start of the (current) last page
1526 of the file, so zero out the remainder of that page to ensure the
1527 entire page contains valid data. Since there is no invalid range
1528 possible past the (current) eof, there's no need to remove anything
1529 from the invalid range list before calling cluster_write(): */
1530 VOP_DEVBLOCKSIZE(cp
->c_devvp
, &devBlockSize
);
1531 retval
= cluster_write(vp
, (struct uio
*) 0, fp
->ff_size
, zero_limit
,
1532 fp
->ff_size
, (off_t
)0, devBlockSize
,
1533 (ap
->a_flags
& IO_SYNC
) | IO_HEADZEROFILL
| IO_NOZERODIRTY
);
1534 if (retval
) goto Err_Exit
;
1536 /* Merely invalidate the remaining area, if necessary: */
1537 if (length
> zero_limit
) {
1538 rl_add(zero_limit
, length
- 1, &fp
->ff_invalidranges
);
1539 cp
->c_zftimeout
= time
.tv_sec
+ ZFTIMELIMIT
;
1542 /* The page containing the (current) eof is invalid: just add the
1543 remainder of the page to the invalid list, along with the area
1544 being newly allocated:
1546 rl_add(fp
->ff_size
, length
- 1, &fp
->ff_invalidranges
);
1547 cp
->c_zftimeout
= time
.tv_sec
+ ZFTIMELIMIT
;
1551 panic("hfs_truncate: invoked on non-UBC object?!");
1554 cp
->c_flag
|= C_UPDATE
;
1555 fp
->ff_size
= length
;
1558 ubc_setsize(vp
, fp
->ff_size
); /* XXX check errors */
1560 } else { /* Shorten the size of the file */
1562 if (fp
->ff_size
> length
) {
1564 * Any buffers that are past the truncation point need to be
1565 * invalidated (to maintain buffer cache consistency). For
1566 * simplicity, we invalidate all the buffers by calling vinvalbuf.
1569 ubc_setsize(vp
, length
); /* XXX check errors */
1571 vflags
= ((length
> 0) ? V_SAVE
: 0) | V_SAVEMETA
;
1572 retval
= vinvalbuf(vp
, vflags
, ap
->a_cred
, ap
->a_p
, 0, 0);
1574 /* Any space previously marked as invalid is now irrelevant: */
1575 rl_remove(length
, fp
->ff_size
- 1, &fp
->ff_invalidranges
);
1579 * Account for any unmapped blocks. Note that the new
1580 * file length can still end up with unmapped blocks.
1582 if (fp
->ff_unallocblocks
> 0) {
1583 u_int32_t finalblks
;
1585 /* lock extents b-tree */
1586 retval
= hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
,
1587 LK_EXCLUSIVE
, ap
->a_p
);
1591 VTOVCB(vp
)->loanedBlocks
-= fp
->ff_unallocblocks
;
1592 cp
->c_blocks
-= fp
->ff_unallocblocks
;
1593 fp
->ff_blocks
-= fp
->ff_unallocblocks
;
1594 fp
->ff_unallocblocks
= 0;
1596 finalblks
= (length
+ blksize
- 1) / blksize
;
1597 if (finalblks
> fp
->ff_blocks
) {
1598 /* calculate required unmapped blocks */
1599 fp
->ff_unallocblocks
= finalblks
- fp
->ff_blocks
;
1600 VTOVCB(vp
)->loanedBlocks
+= fp
->ff_unallocblocks
;
1601 cp
->c_blocks
+= fp
->ff_unallocblocks
;
1602 fp
->ff_blocks
+= fp
->ff_unallocblocks
;
1604 (void) hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
,
1605 LK_RELEASE
, ap
->a_p
);
1609 * For a TBE process the deallocation of the file blocks is
1610 * delayed until the file is closed. And hfs_close calls
1611 * truncate with the IO_NDELAY flag set. So when IO_NDELAY
1612 * isn't set, we make sure this isn't a TBE process.
1614 if ((ap
->a_flags
& IO_NDELAY
) || (!ISSET(ap
->a_p
->p_flag
, P_TBE
))) {
1616 off_t savedbytes
= ((off_t
)fp
->ff_blocks
* (off_t
)blksize
);
1619 hfs_global_shared_lock_acquire(hfsmp
);
1621 if (journal_start_transaction(hfsmp
->jnl
) != 0) {
1627 /* lock extents b-tree (also protects volume bitmap) */
1628 retval
= hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_EXCLUSIVE
, ap
->a_p
);
1631 journal_end_transaction(hfsmp
->jnl
);
1633 hfs_global_shared_lock_release(hfsmp
);
1637 if (fp
->ff_unallocblocks
== 0)
1638 retval
= MacToVFSError(TruncateFileC(VTOVCB(vp
),
1639 (FCB
*)fp
, length
, false));
1641 (void) hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_RELEASE
, ap
->a_p
);
1645 hfs_flushvolumeheader(hfsmp
, MNT_NOWAIT
, 0);
1646 journal_end_transaction(hfsmp
->jnl
);
1648 hfs_global_shared_lock_release(hfsmp
);
1650 filebytes
= (off_t
)fp
->ff_blocks
* (off_t
)blksize
;
1654 /* These are bytesreleased */
1655 (void) hfs_chkdq(cp
, (int64_t)-(savedbytes
- filebytes
), NOCRED
, 0);
1658 /* Only set update flag if the logical length changes */
1659 if (fp
->ff_size
!= length
)
1660 cp
->c_flag
|= C_UPDATE
;
1661 fp
->ff_size
= length
;
1663 cp
->c_flag
|= C_CHANGE
;
1664 retval
= VOP_UPDATE(vp
, &tv
, &tv
, MNT_WAIT
);
1666 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 7)) | DBG_FUNC_NONE
,
1667 -1, -1, -1, retval
, 0);
1672 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW
, 7)) | DBG_FUNC_END
,
1673 (int)length
, (int)fp
->ff_size
, (int)filebytes
, retval
, 0);
1682 #% allocate vp L L L
1685 IN struct vnode *vp;
1688 OUT off_t *bytesallocated;
1690 IN struct ucred *cred;
1693 * allocate a cnode to at most length size
1695 int hfs_allocate(ap
)
1696 struct vop_allocate_args
/* {
1700 off_t *a_bytesallocated;
1702 struct ucred *a_cred;
1706 struct vnode
*vp
= ap
->a_vp
;
1707 struct cnode
*cp
= VTOC(vp
);
1708 struct filefork
*fp
= VTOF(vp
);
1709 off_t length
= ap
->a_length
;
1711 off_t moreBytesRequested
;
1712 off_t actualBytesAdded
;
1717 int retval
, retval2
;
1719 UInt32 extendFlags
=0; /* For call to ExtendFileC */
1720 struct hfsmount
*hfsmp
;
1724 *(ap
->a_bytesallocated
) = 0;
1725 fileblocks
= fp
->ff_blocks
;
1726 filebytes
= (off_t
)fileblocks
* (off_t
)VTOVCB(vp
)->blockSize
;
1728 if (length
< (off_t
)0)
1730 if (vp
->v_type
!= VREG
&& vp
->v_type
!= VLNK
)
1732 if ((ap
->a_flags
& ALLOCATEFROMVOL
) && (length
<= filebytes
))
1735 /* Fill in the flags word for the call to Extend the file */
1737 if (ap
->a_flags
& ALLOCATECONTIG
)
1738 extendFlags
|= kEFContigMask
;
1740 if (ap
->a_flags
& ALLOCATEALL
)
1741 extendFlags
|= kEFAllMask
;
1743 if (suser(ap
->a_cred
, NULL
) != 0)
1744 extendFlags
|= kEFReserveMask
;
1749 startingPEOF
= filebytes
;
1751 if (ap
->a_flags
& ALLOCATEFROMPEOF
)
1752 length
+= filebytes
;
1753 else if (ap
->a_flags
& ALLOCATEFROMVOL
)
1754 blockHint
= ap
->a_offset
/ VTOVCB(vp
)->blockSize
;
1756 /* If no changes are necesary, then we're done */
1757 if (filebytes
== length
)
1761 * Lengthen the size of the file. We must ensure that the
1762 * last byte of the file is allocated. Since the smallest
1763 * value of filebytes is 0, length will be at least 1.
1765 if (length
> filebytes
) {
1766 moreBytesRequested
= length
- filebytes
;
1769 retval
= hfs_chkdq(cp
,
1770 (int64_t)(roundup(moreBytesRequested
, VTOVCB(vp
)->blockSize
)),
1777 hfs_global_shared_lock_acquire(hfsmp
);
1779 if (journal_start_transaction(hfsmp
->jnl
) != 0) {
1785 /* lock extents b-tree (also protects volume bitmap) */
1786 retval
= hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_EXCLUSIVE
, ap
->a_p
);
1789 journal_end_transaction(hfsmp
->jnl
);
1791 hfs_global_shared_lock_release(hfsmp
);
1795 retval
= MacToVFSError(ExtendFileC(VTOVCB(vp
),
1800 &actualBytesAdded
));
1802 *(ap
->a_bytesallocated
) = actualBytesAdded
;
1803 filebytes
= (off_t
)fp
->ff_blocks
* (off_t
)VTOVCB(vp
)->blockSize
;
1805 (void) hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_RELEASE
, ap
->a_p
);
1809 hfs_flushvolumeheader(hfsmp
, MNT_NOWAIT
, 0);
1810 journal_end_transaction(hfsmp
->jnl
);
1812 hfs_global_shared_lock_release(hfsmp
);
1815 * if we get an error and no changes were made then exit
1816 * otherwise we must do the VOP_UPDATE to reflect the changes
1818 if (retval
&& (startingPEOF
== filebytes
))
1822 * Adjust actualBytesAdded to be allocation block aligned, not
1823 * clump size aligned.
1824 * NOTE: So what we are reporting does not affect reality
1825 * until the file is closed, when we truncate the file to allocation
1828 if ((actualBytesAdded
!= 0) && (moreBytesRequested
< actualBytesAdded
))
1829 *(ap
->a_bytesallocated
) =
1830 roundup(moreBytesRequested
, (off_t
)VTOVCB(vp
)->blockSize
);
1832 } else { /* Shorten the size of the file */
1834 if (fp
->ff_size
> length
) {
1836 * Any buffers that are past the truncation point need to be
1837 * invalidated (to maintain buffer cache consistency). For
1838 * simplicity, we invalidate all the buffers by calling vinvalbuf.
1840 vflags
= ((length
> 0) ? V_SAVE
: 0) | V_SAVEMETA
;
1841 (void) vinvalbuf(vp
, vflags
, ap
->a_cred
, ap
->a_p
, 0, 0);
1845 hfs_global_shared_lock_acquire(hfsmp
);
1847 if (journal_start_transaction(hfsmp
->jnl
) != 0) {
1853 /* lock extents b-tree (also protects volume bitmap) */
1854 retval
= hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_EXCLUSIVE
, ap
->a_p
);
1857 journal_end_transaction(hfsmp
->jnl
);
1859 hfs_global_shared_lock_release(hfsmp
);
1864 retval
= MacToVFSError(
1870 (void) hfs_metafilelocking(VTOHFS(vp
), kHFSExtentsFileID
, LK_RELEASE
, ap
->a_p
);
1871 filebytes
= (off_t
)fp
->ff_blocks
* (off_t
)VTOVCB(vp
)->blockSize
;
1874 hfs_flushvolumeheader(hfsmp
, MNT_NOWAIT
, 0);
1875 journal_end_transaction(hfsmp
->jnl
);
1877 hfs_global_shared_lock_release(hfsmp
);
1881 * if we get an error and no changes were made then exit
1882 * otherwise we must do the VOP_UPDATE to reflect the changes
1884 if (retval
&& (startingPEOF
== filebytes
)) goto Err_Exit
;
1886 /* These are bytesreleased */
1887 (void) hfs_chkdq(cp
, (int64_t)-((startingPEOF
- filebytes
)), NOCRED
,0);
1890 if (fp
->ff_size
> filebytes
) {
1891 fp
->ff_size
= filebytes
;
1894 ubc_setsize(vp
, fp
->ff_size
); /* XXX check errors */
1899 cp
->c_flag
|= C_CHANGE
| C_UPDATE
;
1900 retval2
= VOP_UPDATE(vp
, &tv
, &tv
, MNT_WAIT
);
1910 * pagein for HFS filesystem
1914 struct vop_pagein_args
/* {
1917 vm_offset_t a_pl_offset,
1920 struct ucred *a_cred,
1924 register struct vnode
*vp
= ap
->a_vp
;
1925 int devBlockSize
= 0;
1928 if (vp
->v_type
!= VREG
&& vp
->v_type
!= VLNK
)
1929 panic("hfs_pagein: vp not UBC type\n");
1931 VOP_DEVBLOCKSIZE(VTOC(vp
)->c_devvp
, &devBlockSize
);
1933 error
= cluster_pagein(vp
, ap
->a_pl
, ap
->a_pl_offset
, ap
->a_f_offset
,
1934 ap
->a_size
, (off_t
)VTOF(vp
)->ff_size
, devBlockSize
,
1940 * pageout for HFS filesystem.
1944 struct vop_pageout_args
/* {
1947 vm_offset_t a_pl_offset,
1950 struct ucred *a_cred,
1954 struct vnode
*vp
= ap
->a_vp
;
1955 struct cnode
*cp
= VTOC(vp
);
1956 struct filefork
*fp
= VTOF(vp
);
1958 int devBlockSize
= 0;
1963 panic("hfs_pageout: Not a VREG: vp=%x", vp
);
1965 VOP_DEVBLOCKSIZE(cp
->c_devvp
, &devBlockSize
);
1966 filesize
= fp
->ff_size
;
1967 end_of_range
= ap
->a_f_offset
+ ap
->a_size
- 1;
1969 if (end_of_range
>= filesize
)
1970 end_of_range
= (off_t
)(filesize
- 1);
1971 if (ap
->a_f_offset
< filesize
)
1972 rl_remove(ap
->a_f_offset
, end_of_range
, &fp
->ff_invalidranges
);
1974 retval
= cluster_pageout(vp
, ap
->a_pl
, ap
->a_pl_offset
, ap
->a_f_offset
, ap
->a_size
,
1975 filesize
, devBlockSize
, ap
->a_flags
);
1978 * If we successfully wrote any data, and we are not the superuser
1979 * we clear the setuid and setgid bits as a precaution against
1982 if (retval
== 0 && ap
->a_cred
&& ap
->a_cred
->cr_uid
!= 0)
1983 cp
->c_mode
&= ~(S_ISUID
| S_ISGID
);
1989 * Intercept B-Tree node writes to unswap them if necessary.
1992 # IN struct buf *bp;
1996 struct vop_bwrite_args
/* {
2001 register struct buf
*bp
= ap
->a_bp
;
2002 register struct vnode
*vp
= bp
->b_vp
;
2003 #if BYTE_ORDER == LITTLE_ENDIAN
2004 BlockDescriptor block
;
2006 /* Trap B-Tree writes */
2007 if ((VTOC(vp
)->c_fileid
== kHFSExtentsFileID
) ||
2008 (VTOC(vp
)->c_fileid
== kHFSCatalogFileID
)) {
2010 /* Swap if the B-Tree node is in native byte order */
2011 if (((UInt16
*)((char *)bp
->b_data
+ bp
->b_bcount
- 2))[0] == 0x000e) {
2012 /* Prepare the block pointer */
2013 block
.blockHeader
= bp
;
2014 block
.buffer
= bp
->b_data
;
2015 /* not found in cache ==> came from disk */
2016 block
.blockReadFromDisk
= (bp
->b_flags
& B_CACHE
) == 0;
2017 block
.blockSize
= bp
->b_bcount
;
2019 /* Endian un-swap B-Tree node */
2020 SWAP_BT_NODE (&block
, ISHFSPLUS (VTOVCB(vp
)), VTOC(vp
)->c_fileid
, 1);
2023 /* We don't check to make sure that it's 0x0e00 because it could be all zeros */
2026 /* This buffer shouldn't be locked anymore but if it is clear it */
2027 if (ISSET(bp
->b_flags
, B_LOCKED
)) {
2029 if (VTOHFS(vp
)->jnl
) {
2030 panic("hfs: CLEARING the lock bit on bp 0x%x\n", bp
);
2032 CLR(bp
->b_flags
, B_LOCKED
);
2033 printf("hfs_bwrite: called with lock bit set\n");
2035 retval
= vn_bwrite (ap
);