]> git.saurik.com Git - apple/xnu.git/blame - bsd/hfs/hfs_readwrite.c
xnu-344.12.2.tar.gz
[apple/xnu.git] / bsd / hfs / hfs_readwrite.c
CommitLineData
1c79356b 1/*
9bccf70c 2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
1c79356b
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
11 *
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
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/* @(#)hfs_readwrite.c 1.0
23 *
9bccf70c 24 * (c) 1998-2001 Apple Computer, Inc. All Rights Reserved
1c79356b 25 *
1c79356b
A
26 * hfs_readwrite.c -- vnode operations to deal with reading and writing files.
27 *
1c79356b
A
28 */
29
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>
35#include <sys/stat.h>
36#include <sys/buf.h>
37#include <sys/proc.h>
1c79356b
A
38#include <sys/vnode.h>
39#include <sys/uio.h>
40
41#include <miscfs/specfs/specdev.h>
42
1c79356b
A
43#include <sys/ubc.h>
44#include <vm/vm_pageout.h>
45
1c79356b
A
46#include <sys/kdebug.h>
47
48#include "hfs.h"
1c79356b 49#include "hfs_endian.h"
9bccf70c 50#include "hfs_quota.h"
1c79356b
A
51#include "hfscommon/headers/FileMgrInternal.h"
52#include "hfscommon/headers/BTreesInternal.h"
9bccf70c
A
53#include "hfs_cnode.h"
54#include "hfs_dbg.h"
1c79356b 55
9bccf70c 56extern int overflow_extents(struct filefork *fp);
1c79356b
A
57
58#define can_cluster(size) ((((size & (4096-1))) == 0) && (size <= (MAXPHYSIO/2)))
59
60enum {
61 MAXHFSFILESIZE = 0x7FFFFFFF /* this needs to go in the mount structure */
62};
63
64extern u_int32_t GetLogicalBlockSize(struct vnode *vp);
65
1c79356b
A
66
67/*****************************************************************************
68*
69* Operations on vnodes
70*
71*****************************************************************************/
72
73/*
74#% read vp L L L
75#
76 vop_read {
77 IN struct vnode *vp;
78 INOUT struct uio *uio;
79 IN int ioflag;
80 IN struct ucred *cred;
81
82 */
83
84int
85hfs_read(ap)
9bccf70c
A
86 struct vop_read_args /* {
87 struct vnode *a_vp;
88 struct uio *a_uio;
89 int a_ioflag;
90 struct ucred *a_cred;
91 } */ *ap;
1c79356b 92{
9bccf70c
A
93 register struct uio *uio = ap->a_uio;
94 register struct vnode *vp = ap->a_vp;
95 struct cnode *cp;
96 struct filefork *fp;
97 struct buf *bp;
98 daddr_t logBlockNo;
99 u_long fragSize, moveSize, startOffset, ioxfersize;
100 int devBlockSize = 0;
101 off_t bytesRemaining;
102 int retval = 0;
103 off_t filesize;
104 off_t filebytes;
105
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 */
113
114 cp = VTOC(vp);
115 fp = VTOF(vp);
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))
120 return (EFBIG);
121 else
122 return (0);
123 }
1c79356b 124
9bccf70c 125 VOP_DEVBLOCKSIZE(cp->c_devvp, &devBlockSize);
1c79356b 126
9bccf70c
A
127 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_START,
128 (int)uio->uio_offset, uio->uio_resid, (int)filesize, (int)filebytes, 0);
1c79356b 129
9bccf70c
A
130 if (UBCISVALID(vp)) {
131 retval = cluster_read(vp, uio, filesize, devBlockSize, 0);
132 } else {
1c79356b 133
9bccf70c 134 for (retval = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
1c79356b 135
9bccf70c 136 if ((bytesRemaining = (filesize - uio->uio_offset)) <= 0)
1c79356b
A
137 break;
138
139 logBlockNo = (daddr_t)(uio->uio_offset / PAGE_SIZE_64);
140 startOffset = (u_long) (uio->uio_offset & PAGE_MASK_64);
141 fragSize = PAGE_SIZE;
142
9bccf70c 143 if (((logBlockNo * PAGE_SIZE) + fragSize) < filesize)
1c79356b
A
144 ioxfersize = fragSize;
145 else {
9bccf70c 146 ioxfersize = filesize - (logBlockNo * PAGE_SIZE);
1c79356b
A
147 ioxfersize = (ioxfersize + (devBlockSize - 1)) & ~(devBlockSize - 1);
148 }
9bccf70c
A
149 moveSize = ioxfersize;
150 moveSize -= startOffset;
1c79356b
A
151
152 if (bytesRemaining < moveSize)
153 moveSize = bytesRemaining;
154
155 if (uio->uio_resid < moveSize) {
156 moveSize = uio->uio_resid;
1c79356b
A
157 };
158 if (moveSize == 0) {
159 break;
160 };
161
9bccf70c 162 if (( uio->uio_offset + fragSize) >= filesize) {
1c79356b
A
163 retval = bread(vp, logBlockNo, ioxfersize, NOCRED, &bp);
164
165 } else if (logBlockNo - 1 == vp->v_lastr && !(vp->v_flag & VRAOFF)) {
166 daddr_t nextLogBlockNo = logBlockNo + 1;
167 int nextsize;
168
169 if (((nextLogBlockNo * PAGE_SIZE) +
9bccf70c 170 (daddr_t)fragSize) < filesize)
1c79356b
A
171 nextsize = fragSize;
172 else {
9bccf70c 173 nextsize = filesize - (nextLogBlockNo * PAGE_SIZE);
1c79356b
A
174 nextsize = (nextsize + (devBlockSize - 1)) & ~(devBlockSize - 1);
175 }
176 retval = breadn(vp, logBlockNo, ioxfersize, &nextLogBlockNo, &nextsize, 1, NOCRED, &bp);
177 } else {
178 retval = bread(vp, logBlockNo, ioxfersize, NOCRED, &bp);
179 };
180
181 if (retval != E_NONE) {
182 if (bp) {
183 brelse(bp);
184 bp = NULL;
185 }
186 break;
187 };
188 vp->v_lastr = logBlockNo;
189
190 /*
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.
196 */
197 ioxfersize -= bp->b_resid;
198
199 if (ioxfersize < moveSize) { /* XXX PPD This should take the offset into account, too! */
200 if (ioxfersize == 0)
201 break;
202 moveSize = ioxfersize;
203 }
204 if ((startOffset + moveSize) > bp->b_bcount)
205 panic("hfs_read: bad startOffset or moveSize\n");
206
1c79356b
A
207 if ((retval = uiomove((caddr_t)bp->b_data + startOffset, (int)moveSize, uio)))
208 break;
209
9bccf70c
A
210 if (S_ISREG(cp->c_mode) &&
211 (((startOffset + moveSize) == fragSize) || (uio->uio_offset == filesize))) {
1c79356b
A
212 bp->b_flags |= B_AGE;
213 };
214
1c79356b
A
215 brelse(bp);
216 /* Start of loop resets bp to NULL before reaching outside this block... */
217 }
218
9bccf70c
A
219 if (bp != NULL) {
220 brelse(bp);
221 }
222 }
1c79356b 223
9bccf70c 224 cp->c_flag |= C_ACCESS;
1c79356b 225
9bccf70c
A
226 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_END,
227 (int)uio->uio_offset, uio->uio_resid, (int)filesize, (int)filebytes, 0);
1c79356b 228
9bccf70c 229 return (retval);
1c79356b
A
230}
231
232/*
233 * Write data to a file or directory.
234#% write vp L L L
235#
236 vop_write {
237 IN struct vnode *vp;
238 INOUT struct uio *uio;
239 IN int ioflag;
240 IN struct ucred *cred;
241
242 */
243int
244hfs_write(ap)
9bccf70c
A
245 struct vop_write_args /* {
246 struct vnode *a_vp;
247 struct uio *a_uio;
248 int a_ioflag;
249 struct ucred *a_cred;
250 } */ *ap;
1c79356b 251{
9bccf70c
A
252 struct vnode *vp = ap->a_vp;
253 struct uio *uio = ap->a_uio;
254 struct cnode *cp;
255 struct filefork *fp;
256 struct buf *bp;
257 struct proc *p;
258 struct timeval tv;
259 ExtendedVCB *vcb;
0b4e3aa0 260 int devBlockSize = 0;
1c79356b
A
261 daddr_t logBlockNo;
262 long fragSize;
263 off_t origFileSize, currOffset, writelimit, bytesToAdd;
264 off_t actualBytesAdded;
265 u_long blkoffset, resid, xfersize, clearSize;
9bccf70c 266 int eflags, ioflag;
1c79356b 267 int retval;
9bccf70c
A
268 off_t filebytes;
269 u_long fileblocks;
b4c24cb9
A
270 struct hfsmount *hfsmp;
271 int started_tr = 0, grabbed_lock = 0;
1c79356b 272
9bccf70c 273 ioflag = ap->a_ioflag;
1c79356b 274
9bccf70c
A
275 if (uio->uio_offset < 0)
276 return (EINVAL);
277 if (uio->uio_resid == 0)
278 return (E_NONE);
279 if (vp->v_type != VREG && vp->v_type != VLNK)
280 return (EISDIR); /* Can only write files */
281
282 cp = VTOC(vp);
283 fp = VTOF(vp);
284 vcb = VTOVCB(vp);
285 fileblocks = fp->ff_blocks;
286 filebytes = (off_t)fileblocks * (off_t)vcb->blockSize;
287
288 if (ioflag & IO_APPEND)
289 uio->uio_offset = fp->ff_size;
290 if ((cp->c_flags & APPEND) && uio->uio_offset != fp->ff_size)
291 return (EPERM);
1c79356b 292
b4c24cb9
A
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;
296
297 extd = &cp->c_datafork->ff_data.cf_extents[0];
298 if (extd->startBlock == VTOVCB(vp)->vcbJinfoBlock || extd->startBlock == VTOHFS(vp)->jnl_start) {
299 return EPERM;
300 }
301 }
302
1c79356b
A
303 writelimit = uio->uio_offset + uio->uio_resid;
304
9bccf70c
A
305 /*
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.
308 */
309 p = uio->uio_procp;
310 if (vp->v_type == VREG && p &&
311 writelimit > p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
312 psignal(p, SIGXFSZ);
313 return (EFBIG);
314 }
315 p = current_proc();
1c79356b 316
9bccf70c 317 VOP_DEVBLOCKSIZE(cp->c_devvp, &devBlockSize);
1c79356b 318
9bccf70c
A
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;
1c79356b 323
9bccf70c
A
324 /*
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
330 * currOffset.
331 *
332 * The following is true at all times:
333 * currOffset <= LEOF <= uio->uio_offset <= writelimit
334 */
335 currOffset = MIN(uio->uio_offset, fp->ff_size);
1c79356b 336
9bccf70c
A
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);
339 retval = 0;
1c79356b 340
9bccf70c
A
341 /* Now test if we need to extend the file */
342 /* Doing so will adjust the filebytes for us */
1c79356b 343
9bccf70c
A
344#if QUOTA
345 if(writelimit > filebytes) {
346 bytesToAdd = writelimit - filebytes;
1c79356b 347
b4c24cb9 348 retval = hfs_chkdq(cp, (int64_t)(roundup(bytesToAdd, vcb->blockSize)),
9bccf70c
A
349 ap->a_cred, 0);
350 if (retval)
351 return (retval);
352 }
353#endif /* QUOTA */
1c79356b 354
b4c24cb9
A
355 hfsmp = VTOHFS(vp);
356 if (writelimit > filebytes) {
357 hfs_global_shared_lock_acquire(hfsmp);
358 grabbed_lock = 1;
359 }
360 if (hfsmp->jnl && (writelimit > filebytes)) {
361 if (journal_start_transaction(hfsmp->jnl) != 0) {
362 hfs_global_shared_lock_release(hfsmp);
363 return EINVAL;
364 }
365 started_tr = 1;
366 }
367
9bccf70c 368 while (writelimit > filebytes) {
1c79356b 369
9bccf70c
A
370 bytesToAdd = writelimit - filebytes;
371 if (suser(ap->a_cred, NULL) != 0)
372 eflags |= kEFReserveMask;
373
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)
377 break;
378
379 retval = MacToVFSError(ExtendFileC (vcb, (FCB*)fp, bytesToAdd,
380 0, eflags, &actualBytesAdded));
381
382 (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_RELEASE, p);
383 if ((actualBytesAdded == 0) && (retval == E_NONE))
384 retval = ENOSPC;
385 if (retval != E_NONE)
386 break;
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);
390 }
1c79356b 391
b4c24cb9
A
392 // XXXdbg
393 if (started_tr) {
394 hfs_flushvolumeheader(hfsmp, MNT_NOWAIT, 0);
395 journal_end_transaction(hfsmp->jnl);
396 started_tr = 0;
397 }
398 if (grabbed_lock) {
399 hfs_global_shared_lock_release(hfsmp);
400 grabbed_lock = 0;
401 }
402
0b4e3aa0
A
403 if (UBCISVALID(vp) && retval == E_NONE) {
404 off_t filesize;
405 off_t zero_off;
406 off_t tail_off;
407 off_t inval_start;
408 off_t inval_end;
409 off_t io_start, io_end;
410 int lflag;
411 struct rl_entry *invalid_range;
412
9bccf70c 413 if (writelimit > fp->ff_size)
0b4e3aa0
A
414 filesize = writelimit;
415 else
9bccf70c 416 filesize = fp->ff_size;
1c79356b 417
0b4e3aa0 418 lflag = (ioflag & IO_SYNC);
1c79356b 419
9bccf70c 420 if (uio->uio_offset <= fp->ff_size) {
0b4e3aa0
A
421 zero_off = uio->uio_offset & ~PAGE_MASK_64;
422
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:
426 */
9bccf70c 427 if (rl_scan(&fp->ff_invalidranges, zero_off, uio->uio_offset - 1, &invalid_range) != RL_NOOVERLAP)
0b4e3aa0 428 lflag |= IO_HEADZEROFILL;
0b4e3aa0 429 } else {
9bccf70c 430 off_t eof_page_base = fp->ff_size & ~PAGE_MASK_64;
0b4e3aa0 431
9bccf70c 432 /* The bytes between fp->ff_size and uio->uio_offset must never be
0b4e3aa0
A
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.
439
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.
443 */
9bccf70c 444 inval_start = (fp->ff_size + (PAGE_SIZE_64 - 1)) & ~PAGE_MASK_64;
0b4e3aa0 445 inval_end = uio->uio_offset & ~PAGE_MASK_64;
9bccf70c 446 zero_off = fp->ff_size;
0b4e3aa0 447
9bccf70c
A
448 if ((fp->ff_size & PAGE_MASK_64) &&
449 (rl_scan(&fp->ff_invalidranges,
0b4e3aa0 450 eof_page_base,
9bccf70c 451 fp->ff_size - 1,
0b4e3aa0
A
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:
460 */
461 if (inval_end > eof_page_base) {
462 inval_start = eof_page_base;
463 } else {
464 zero_off = eof_page_base;
465 };
466 };
467
468 if (inval_start < inval_end) {
469 /* There's some range of data that's going to be marked invalid */
470
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:
475 */
9bccf70c
A
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);
0b4e3aa0
A
480 if (retval) goto ioerr_exit;
481 };
482
483 /* Mark the remaining area of the newly allocated space as invalid: */
9bccf70c
A
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;
0b4e3aa0
A
487 };
488
489 if (uio->uio_offset > zero_off) lflag |= IO_HEADZEROFILL;
490 };
1c79356b 491
0b4e3aa0
A
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:
494 */
495 tail_off = (writelimit + (PAGE_SIZE_64 - 1)) & ~PAGE_MASK_64;
496 if (tail_off > filesize) tail_off = filesize;
497 if (tail_off > writelimit) {
9bccf70c 498 if (rl_scan(&fp->ff_invalidranges, writelimit, tail_off - 1, &invalid_range) != RL_NOOVERLAP) {
0b4e3aa0
A
499 lflag |= IO_TAILZEROFILL;
500 };
501 };
502
503 /*
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:
507 *
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
511 * tries to write it:
512 */
513 io_start = (lflag & IO_HEADZEROFILL) ? zero_off : uio->uio_offset;
514 io_end = (lflag & IO_TAILZEROFILL) ? tail_off : writelimit;
9bccf70c
A
515 if (io_start < fp->ff_size) {
516 rl_remove(io_start, io_end - 1, &fp->ff_invalidranges);
0b4e3aa0 517 };
9bccf70c
A
518 retval = cluster_write(vp, uio, fp->ff_size, filesize, zero_off,
519 tail_off, devBlockSize, lflag | IO_NOZERODIRTY);
0b4e3aa0 520
9bccf70c
A
521 if (uio->uio_offset > fp->ff_size) {
522 fp->ff_size = uio->uio_offset;
1c79356b 523
9bccf70c 524 ubc_setsize(vp, fp->ff_size); /* XXX check errors */
0b4e3aa0 525 }
9bccf70c
A
526 if (resid > uio->uio_resid)
527 cp->c_flag |= C_CHANGE | C_UPDATE;
528 } else {
529 while (retval == E_NONE && uio->uio_resid > 0) {
530 logBlockNo = currOffset / PAGE_SIZE;
531 blkoffset = currOffset & PAGE_MASK;
532
533 if ((filebytes - currOffset) < PAGE_SIZE_64)
534 fragSize = filebytes - ((off_t)logBlockNo * PAGE_SIZE_64);
535 else
536 fragSize = PAGE_SIZE;
537 xfersize = fragSize - blkoffset;
538
539 /* Make any adjustments for boundary conditions */
540 if (currOffset + (off_t)xfersize > writelimit)
541 xfersize = writelimit - currOffset;
542
543 /*
544 * There is no need to read into bp if:
545 * We start on a block boundary and will overwrite the whole block
546 *
547 * OR
548 */
549 if ((blkoffset == 0) && (xfersize >= fragSize)) {
550 bp = getblk(vp, logBlockNo, fragSize, 0, 0, BLK_READ);
551 retval = 0;
552
553 if (bp->b_blkno == -1) {
554 brelse(bp);
555 retval = EIO; /* XXX */
556 break;
557 }
558 } else {
559
560 if (currOffset == fp->ff_size && blkoffset == 0) {
561 bp = getblk(vp, logBlockNo, fragSize, 0, 0, BLK_READ);
562 retval = 0;
563 if (bp->b_blkno == -1) {
564 brelse(bp);
565 retval = EIO; /* XXX */
566 break;
567 }
568 } else {
569 /*
570 * This I/O transfer is not sufficiently aligned,
571 * so read the affected block into a buffer:
572 */
573 retval = bread(vp, logBlockNo, fragSize, ap->a_cred, &bp);
574 if (retval != E_NONE) {
575 if (bp)
576 brelse(bp);
577 break;
578 }
579 }
580 }
581
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
585 * I/O operation:
586 *
587 * Note that currOffset is only less than uio_offset if
588 * uio_offset > LEOF...
589 */
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;
596 }
597
598 if (xfersize > 0) {
599 retval = uiomove((caddr_t)bp->b_data + blkoffset, (int)xfersize, uio);
600 currOffset += xfersize;
601 }
602
603 if (ioflag & IO_SYNC) {
604 (void)VOP_BWRITE(bp);
605 } else if ((xfersize + blkoffset) == fragSize) {
606 bp->b_flags |= B_AGE;
607 bawrite(bp);
608 } else {
609 bdwrite(bp);
610 }
611
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):
615 */
616 if (currOffset > fp->ff_size) {
617 fp->ff_size = currOffset;
618 if (UBCISVALID(vp))
619 ubc_setsize(vp, fp->ff_size); /* XXX check errors */
620 }
621 if (retval || (resid == 0))
622 break;
623 cp->c_flag |= C_CHANGE | C_UPDATE;
624 } /* endwhile */
625 }
0b4e3aa0
A
626
627ioerr_exit:
9bccf70c 628 /*
0b4e3aa0 629 * If we successfully wrote any data, and we are not the superuser
9bccf70c
A
630 * we clear the setuid and setgid bits as a precaution against
631 * tampering.
632 */
633 if (resid > uio->uio_resid && ap->a_cred && ap->a_cred->cr_uid != 0)
634 cp->c_mode &= ~(S_ISUID | S_ISGID);
635
636 if (retval) {
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;
643 }
644 } else if (resid > uio->uio_resid && (ioflag & IO_SYNC)) {
645 tv = time;
646 retval = VOP_UPDATE(vp, &tv, &tv, 1);
647 }
1c79356b 648
9bccf70c
A
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);
1c79356b 651
9bccf70c 652 return (retval);
1c79356b
A
653}
654
655
656/*
657
658#% ioctl vp U U U
659#
660 vop_ioctl {
661 IN struct vnode *vp;
662 IN u_long command;
663 IN caddr_t data;
664 IN int fflag;
665 IN struct ucred *cred;
666 IN struct proc *p;
667
668 */
669
670
671/* ARGSUSED */
672int
673hfs_ioctl(ap)
9bccf70c
A
674 struct vop_ioctl_args /* {
675 struct vnode *a_vp;
676 int a_command;
677 caddr_t a_data;
678 int a_fflag;
679 struct ucred *a_cred;
680 struct proc *a_p;
681 } */ *ap;
1c79356b 682{
9bccf70c
A
683 switch (ap->a_command) {
684 case 1: {
685 register struct cnode *cp;
686 register struct vnode *vp;
687 register struct radvisory *ra;
688 struct filefork *fp;
689 int devBlockSize = 0;
690 int error;
691
692 vp = ap->a_vp;
693
694 if (vp->v_type != VREG)
695 return EINVAL;
696
697 VOP_LEASE(vp, ap->a_p, ap->a_cred, LEASE_READ);
698 error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, ap->a_p);
699 if (error)
700 return (error);
701
702 ra = (struct radvisory *)(ap->a_data);
703 cp = VTOC(vp);
704 fp = VTOF(vp);
705
706 if (ra->ra_offset >= fp->ff_size) {
707 VOP_UNLOCK(vp, 0, ap->a_p);
708 return (EFBIG);
709 }
710 VOP_DEVBLOCKSIZE(cp->c_devvp, &devBlockSize);
1c79356b 711
9bccf70c
A
712 error = advisory_read(vp, fp->ff_size, ra->ra_offset, ra->ra_count, devBlockSize);
713 VOP_UNLOCK(vp, 0, ap->a_p);
1c79356b 714
9bccf70c 715 return (error);
1c79356b 716 }
1c79356b 717
0b4e3aa0
A
718 case 2: /* F_READBOOTBLOCKS */
719 case 3: /* F_WRITEBOOTBLOCKS */
720 {
1c79356b 721 struct vnode *vp = ap->a_vp;
9bccf70c 722 struct vnode *devvp = NULL;
1c79356b 723 struct fbootstraptransfer *btd = (struct fbootstraptransfer *)ap->a_data;
0b4e3aa0 724 int devBlockSize;
1c79356b
A
725 int error;
726 struct iovec aiov;
727 struct uio auio;
728 u_long blockNumber;
729 u_long blockOffset;
730 u_long xfersize;
731 struct buf *bp;
732
0b4e3aa0
A
733 if ((vp->v_flag & VROOT) == 0) return EINVAL;
734 if (btd->fbt_offset + btd->fbt_length > 1024) return EINVAL;
1c79356b 735
9bccf70c 736 devvp = VTOHFS(vp)->hfs_devvp;
1c79356b
A
737 aiov.iov_base = btd->fbt_buffer;
738 aiov.iov_len = btd->fbt_length;
739
740 auio.uio_iov = &aiov;
741 auio.uio_iovcnt = 1;
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;
747
9bccf70c 748 VOP_DEVBLOCKSIZE(devvp, &devBlockSize);
1c79356b
A
749
750 while (auio.uio_resid > 0) {
751 blockNumber = auio.uio_offset / devBlockSize;
9bccf70c 752 error = bread(devvp, blockNumber, devBlockSize, ap->a_cred, &bp);
1c79356b 753 if (error) {
0b4e3aa0
A
754 if (bp) brelse(bp);
755 return error;
756 };
1c79356b 757
0b4e3aa0 758 blockOffset = auio.uio_offset % devBlockSize;
1c79356b
A
759 xfersize = devBlockSize - blockOffset;
760 error = uiomove((caddr_t)bp->b_data + blockOffset, (int)xfersize, &auio);
0b4e3aa0
A
761 if (error) {
762 brelse(bp);
763 return error;
764 };
765 if (auio.uio_rw == UIO_WRITE) {
766 error = VOP_BWRITE(bp);
767 if (error) return error;
768 } else {
769 brelse(bp);
770 };
771 };
1c79356b 772 };
0b4e3aa0
A
773 return 0;
774
775 case _IOC(IOC_OUT,'h', 4, 0): /* Create date in local time */
776 {
777 *(time_t *)(ap->a_data) = to_bsd_time(VTOVCB(ap->a_vp)->localCreateDate);
778 return 0;
779 }
1c79356b 780
0b4e3aa0 781 default:
0b4e3aa0 782 return (ENOTTY);
1c79356b
A
783 }
784
0b4e3aa0
A
785 /* Should never get here */
786 return 0;
1c79356b
A
787}
788
789/* ARGSUSED */
790int
791hfs_select(ap)
9bccf70c
A
792 struct vop_select_args /* {
793 struct vnode *a_vp;
794 int a_which;
795 int a_fflags;
796 struct ucred *a_cred;
797 void *a_wql;
798 struct proc *a_p;
799 } */ *ap;
1c79356b 800{
9bccf70c
A
801 /*
802 * We should really check to see if I/O is possible.
803 */
804 return (1);
1c79356b
A
805}
806
1c79356b
A
807/*
808 * Bmap converts a the logical block number of a file to its physical block
809 * number on the disk.
810 */
811
812/*
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
818#% bmap vp L L L
819#% bmap vpp - U -
820#
821 vop_bmap {
822 IN struct vnode *vp;
823 IN daddr_t bn;
824 OUT struct vnode **vpp;
825 IN daddr_t *bnp;
826 OUT int *runp;
827 */
828/*
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
833 */
834
835int
836hfs_bmap(ap)
9bccf70c
A
837 struct vop_bmap_args /* {
838 struct vnode *a_vp;
839 daddr_t a_bn;
840 struct vnode **a_vpp;
841 daddr_t *a_bnp;
842 int *a_runp;
843 } */ *ap;
1c79356b 844{
9bccf70c
A
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);
849 int retval = E_NONE;
1c79356b
A
850 daddr_t logBlockSize;
851 size_t bytesContAvail = 0;
0b4e3aa0 852 off_t blockposition;
1c79356b
A
853 struct proc *p = NULL;
854 int lockExtBtree;
0b4e3aa0
A
855 struct rl_entry *invalid_range;
856 enum rl_overlaptype overlaptype;
1c79356b 857
9bccf70c
A
858 /*
859 * Check for underlying vnode requests and ensure that logical
860 * to physical mapping is requested.
861 */
862 if (ap->a_vpp != NULL)
863 *ap->a_vpp = cp->c_devvp;
864 if (ap->a_bnp == NULL)
865 return (0);
866
867 /* Only clustered I/O should have delayed allocations. */
868 DBG_ASSERT(fp->ff_unallocblocks == 0);
869
870 logBlockSize = GetLogicalBlockSize(vp);
871 blockposition = (off_t)ap->a_bn * (off_t)logBlockSize;
872
873 lockExtBtree = overflow_extents(fp);
874 if (lockExtBtree) {
875 p = current_proc();
876 retval = hfs_metafilelocking(hfsmp, kHFSExtentsFileID,
877 LK_EXCLUSIVE | LK_CANRECURSE, p);
878 if (retval)
879 return (retval);
880 }
1c79356b 881
9bccf70c 882 retval = MacToVFSError(
0b4e3aa0 883 MapFileBlockC (HFSTOVCB(hfsmp),
9bccf70c 884 (FCB*)fp,
0b4e3aa0
A
885 MAXPHYSIO,
886 blockposition,
887 ap->a_bnp,
888 &bytesContAvail));
1c79356b
A
889
890 if (lockExtBtree) (void) hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_RELEASE, p);
891
892 if (retval == E_NONE) {
0b4e3aa0 893 /* Adjust the mapping information for invalid file ranges: */
9bccf70c 894 overlaptype = rl_scan(&fp->ff_invalidranges,
0b4e3aa0
A
895 blockposition,
896 blockposition + MAXPHYSIO - 1,
897 &invalid_range);
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;
906 break;
907
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;
9bccf70c 914 if ((fp->ff_size > (invalid_range->rl_end + 1)) &&
0b4e3aa0
A
915 (invalid_range->rl_end + 1 - blockposition < bytesContAvail)) {
916 bytesContAvail = invalid_range->rl_end + 1 - blockposition;
917 };
918 } else {
919 bytesContAvail = invalid_range->rl_start - blockposition;
920 };
921 break;
922 };
923 if (bytesContAvail > MAXPHYSIO) bytesContAvail = MAXPHYSIO;
924 };
925
1c79356b
A
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;
931 } else {
932 *ap->a_runp = 0;
933 };
934 };
935 };
936
1c79356b
A
937 return (retval);
938}
939
940/* blktooff converts logical block number to file offset */
941
942int
943hfs_blktooff(ap)
9bccf70c
A
944 struct vop_blktooff_args /* {
945 struct vnode *a_vp;
946 daddr_t a_lblkno;
947 off_t *a_offset;
948 } */ *ap;
1c79356b
A
949{
950 if (ap->a_vp == NULL)
951 return (EINVAL);
952 *ap->a_offset = (off_t)ap->a_lblkno * PAGE_SIZE_64;
953
954 return(0);
955}
956
957int
958hfs_offtoblk(ap)
9bccf70c
A
959 struct vop_offtoblk_args /* {
960 struct vnode *a_vp;
961 off_t a_offset;
962 daddr_t *a_lblkno;
963 } */ *ap;
1c79356b 964{
1c79356b
A
965 if (ap->a_vp == NULL)
966 return (EINVAL);
967 *ap->a_lblkno = ap->a_offset / PAGE_SIZE_64;
968
969 return(0);
970}
971
972int
973hfs_cmap(ap)
9bccf70c
A
974 struct vop_cmap_args /* {
975 struct vnode *a_vp;
976 off_t a_foffset;
977 size_t a_size;
978 daddr_t *a_bpn;
979 size_t *a_run;
980 void *a_poff;
981 } */ *ap;
1c79356b 982{
9bccf70c
A
983 struct hfsmount *hfsmp = VTOHFS(ap->a_vp);
984 struct filefork *fp = VTOF(ap->a_vp);
1c79356b
A
985 size_t bytesContAvail = 0;
986 int retval = E_NONE;
9bccf70c 987 int lockExtBtree = 0;
1c79356b 988 struct proc *p = NULL;
0b4e3aa0
A
989 struct rl_entry *invalid_range;
990 enum rl_overlaptype overlaptype;
b4c24cb9 991 int started_tr = 0, grabbed_lock = 0;
1c79356b 992
9bccf70c
A
993 /*
994 * Check for underlying vnode requests and ensure that logical
995 * to physical mapping is requested.
996 */
997 if (ap->a_bpn == NULL)
998 return (0);
999
b4c24cb9
A
1000 p = current_proc();
1001 if (fp->ff_unallocblocks) {
9bccf70c 1002 lockExtBtree = 1;
b4c24cb9
A
1003
1004 // XXXdbg
1005 hfs_global_shared_lock_acquire(hfsmp);
1006 grabbed_lock = 1;
1007
1008 if (hfsmp->jnl) {
1009 if (journal_start_transaction(hfsmp->jnl) != 0) {
1010 hfs_global_shared_lock_release(hfsmp);
1011 return EINVAL;
1012 } else {
1013 started_tr = 1;
1014 }
1015 }
1016
9bccf70c 1017 if (retval = hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_EXCLUSIVE | LK_CANRECURSE, p)) {
b4c24cb9
A
1018 if (started_tr) {
1019 journal_end_transaction(hfsmp->jnl);
1020 }
1021 if (grabbed_lock) {
1022 hfs_global_shared_lock_release(hfsmp);
1023 }
9bccf70c 1024 return (retval);
b4c24cb9
A
1025 }
1026 } else if (overflow_extents(fp)) {
1027 lockExtBtree = 1;
1028 if (retval = hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_EXCLUSIVE | LK_CANRECURSE, p)) {
1029 return retval;
1030 }
9bccf70c 1031 }
1c79356b 1032
9bccf70c
A
1033 /*
1034 * Check for any delayed allocations.
1035 */
1036 if (fp->ff_unallocblocks) {
1037 SInt64 reqbytes, actbytes;
1c79356b 1038
9bccf70c
A
1039 reqbytes = (SInt64)fp->ff_unallocblocks *
1040 (SInt64)HFSTOVCB(hfsmp)->blockSize;
1041 /*
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
1047 * Overflow file.
1048 */
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;
1053
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)
1059 retval = ENOSPC;
1060
1061 if (retval) {
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;
1067 }
1068 reqbytes -= actbytes;
1069 }
1c79356b 1070
9bccf70c 1071 if (retval) {
b4c24cb9
A
1072 (void) hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_RELEASE, p);
1073 if (started_tr) {
1074 hfs_flushvolumeheader(hfsmp, MNT_NOWAIT, 0);
1075 journal_end_transaction(hfsmp->jnl);
1076 }
1077 if (grabbed_lock) {
1078 hfs_global_shared_lock_release(hfsmp);
1079 }
1080 return (retval);
1081 }
9bccf70c
A
1082 VTOC(ap->a_vp)->c_flag |= C_MODIFIED;
1083 }
1084
1085 retval = MacToVFSError(
1c79356b 1086 MapFileBlockC (HFSTOVCB(hfsmp),
9bccf70c 1087 (FCB *)fp,
1c79356b
A
1088 ap->a_size,
1089 ap->a_foffset,
1090 ap->a_bpn,
1091 &bytesContAvail));
1092
9bccf70c
A
1093 if (lockExtBtree)
1094 (void) hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_RELEASE, p);
1c79356b 1095
b4c24cb9
A
1096 // XXXdbg
1097 if (started_tr) {
1098 hfs_flushvolumeheader(hfsmp, MNT_NOWAIT, 0);
1099 journal_end_transaction(hfsmp->jnl);
1100 started_tr = 0;
1101 }
1102 if (grabbed_lock) {
1103 hfs_global_shared_lock_release(hfsmp);
1104 grabbed_lock = 0;
1105 }
1106
0b4e3aa0
A
1107 if (retval == E_NONE) {
1108 /* Adjust the mapping information for invalid file ranges: */
9bccf70c 1109 overlaptype = rl_scan(&fp->ff_invalidranges,
0b4e3aa0
A
1110 ap->a_foffset,
1111 ap->a_foffset + (off_t)bytesContAvail - 1,
1112 &invalid_range);
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;
1120
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):
1125 */
9bccf70c 1126 if ((fp->ff_size > (invalid_range->rl_end + 1)) &&
0b4e3aa0
A
1127 (invalid_range->rl_end + 1 - ap->a_foffset < bytesContAvail)) {
1128 bytesContAvail = invalid_range->rl_end + 1 - ap->a_foffset;
1129 };
1130 break;
1131
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;
9bccf70c 1138 if ((fp->ff_size > (invalid_range->rl_end + 1)) &&
0b4e3aa0
A
1139 (invalid_range->rl_end + 1 - ap->a_foffset < bytesContAvail)) {
1140 bytesContAvail = invalid_range->rl_end + 1 - ap->a_foffset;
1141 };
1142 } else {
1143 bytesContAvail = invalid_range->rl_start - ap->a_foffset;
1144 };
1145 break;
1146 };
1147 if (bytesContAvail > ap->a_size) bytesContAvail = ap->a_size;
1148 };
1149
1150 if (ap->a_run) *ap->a_run = bytesContAvail;
1151 };
1c79356b 1152
9bccf70c
A
1153 if (ap->a_poff)
1154 *(int *)ap->a_poff = 0;
1c79356b 1155
9bccf70c
A
1156 return (retval);
1157}
1c79356b 1158
1c79356b 1159
9bccf70c
A
1160/*
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.
1163 *
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.
1167 */
1168static int
1169hfs_strategy_fragmented(struct buf *bp)
1170{
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 */
1176 int retval = 0;
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) */
1180
1181 /* Make sure we redo this mapping for the next I/O */
1182 bp->b_blkno = bp->b_lblkno;
1183
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;
1187
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);
1192
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);
1198
1199 /* Map the current position to a physical block number */
1200 retval = VOP_CMAP(vp, offset, block_size, &frag->b_lblkno,
1201 NULL, NULL);
1202 if (retval != 0)
1203 break;
1c79356b 1204
9bccf70c
A
1205 /*
1206 * Did we try to read a hole?
1207 * (Should never happen for metadata!)
1208 */
1209 if ((long)frag->b_lblkno == -1) {
1210 bzero(ioaddr, block_size);
1211 continue;
1212 }
1213
1214 /* If writing, copy before I/O */
1215 if (!ISSET(bp->b_flags, B_READ))
1216 bcopy(ioaddr, frag->b_data, block_size);
1217
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);
1223 frag->b_vp = NULL;
1224 if (retval != 0)
1225 break;
1226 retval = biowait(frag);
1227 if (retval != 0)
1228 break;
1229
1230 /* If reading, copy after the I/O */
1231 if (ISSET(bp->b_flags, B_READ))
1232 bcopy(frag->b_data, ioaddr, block_size);
1233 }
1234
1235 frag->b_vp = NULL;
b4c24cb9
A
1236 //
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
1240 // files.
9bccf70c
A
1241 SET(frag->b_flags, B_INVAL);
1242 brelse(frag);
1243
1244 if ((bp->b_error = retval) != 0)
1245 SET(bp->b_flags, B_ERROR);
1246
1247 biodone(bp); /* This I/O is now complete */
1248 return retval;
1c79356b
A
1249}
1250
9bccf70c 1251
1c79356b
A
1252/*
1253 * Calculate the logical to physical mapping if not done already,
1254 * then call the device strategy routine.
1255#
1256#vop_strategy {
1257# IN struct buf *bp;
1258 */
1259int
1260hfs_strategy(ap)
9bccf70c
A
1261 struct vop_strategy_args /* {
1262 struct buf *a_bp;
1263 } */ *ap;
1c79356b 1264{
9bccf70c
A
1265 register struct buf *bp = ap->a_bp;
1266 register struct vnode *vp = bp->b_vp;
1267 register struct cnode *cp = VTOC(vp);
1268 int retval = 0;
1269 off_t offset;
1270 size_t bytes_contig;
1271
1272 if ( !(bp->b_flags & B_VECTORLIST)) {
1273 if (vp->v_type == VBLK || vp->v_type == VCHR)
1274 panic("hfs_strategy: device vnode passed!");
1c79356b 1275
9bccf70c
A
1276 if (bp->b_flags & B_PAGELIST) {
1277 /*
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...
1282 */
1283 retval = cluster_bp(bp);
1284 vp = cp->c_devvp;
1285 bp->b_dev = vp->v_rdev;
1c79356b 1286
9bccf70c
A
1287 return (retval);
1288 }
1289
1290 /*
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.
1297 */
1298 if (bp->b_blkno == bp->b_lblkno) {
1299 offset = (off_t) bp->b_lblkno *
1300 (off_t) GetLogicalBlockSize(vp);
1301
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;
1306 biodone(bp);
1307 return (retval);
1308 }
1309 if (bytes_contig < bp->b_bcount)
1310 {
1311 /*
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.
1319 */
1320 return hfs_strategy_fragmented(bp);
1321 }
1322 if ((long)bp->b_blkno == -1)
1323 clrbuf(bp);
1324 }
1325 if ((long)bp->b_blkno == -1) {
1326 biodone(bp);
1327 return (0);
1328 }
1329 if (bp->b_validend == 0) {
1330 /*
1331 * Record the exact size of the I/O transfer about to
1332 * be made:
1333 */
1334 bp->b_validend = bp->b_bcount;
1335 }
1c79356b 1336 }
9bccf70c
A
1337 vp = cp->c_devvp;
1338 bp->b_dev = vp->v_rdev;
1c79356b 1339
9bccf70c 1340 return VOCALL (vp->v_op, VOFFSET(vop_strategy), ap);
1c79356b
A
1341}
1342
1343
1c79356b
A
1344/*
1345#
1346#% truncate vp L L L
1347#
1348vop_truncate {
1349 IN struct vnode *vp;
1350 IN off_t length;
1351 IN int flags; (IO_SYNC)
1352 IN struct ucred *cred;
1353 IN struct proc *p;
1354};
9bccf70c 1355 * Truncate a cnode to at most length size, freeing (or adding) the
1c79356b
A
1356 * disk blocks.
1357 */
1358int hfs_truncate(ap)
9bccf70c
A
1359 struct vop_truncate_args /* {
1360 struct vnode *a_vp;
1361 off_t a_length;
1362 int a_flags;
1363 struct ucred *a_cred;
1364 struct proc *a_p;
1365 } */ *ap;
1c79356b 1366{
9bccf70c
A
1367 register struct vnode *vp = ap->a_vp;
1368 register struct cnode *cp = VTOC(vp);
1369 struct filefork *fp = VTOF(vp);
1370 off_t length;
1371 long vflags;
1372 struct timeval tv;
1373 int retval;
1374 off_t bytesToAdd;
1375 off_t actualBytesAdded;
1376 off_t filebytes;
1377 u_long fileblocks;
1378 int blksize;
b4c24cb9 1379 struct hfsmount *hfsmp;
9bccf70c
A
1380
1381 if (vp->v_type != VREG && vp->v_type != VLNK)
1382 return (EISDIR); /* cannot truncate an HFS directory! */
1383
1384 length = ap->a_length;
1385 blksize = VTOVCB(vp)->blockSize;
1386 fileblocks = fp->ff_blocks;
1387 filebytes = (off_t)fileblocks * (off_t)blksize;
1388
1389 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 7)) | DBG_FUNC_START,
1390 (int)length, (int)fp->ff_size, (int)filebytes, 0, 0);
1391
1392 if (length < 0)
1393 return (EINVAL);
1c79356b 1394
9bccf70c
A
1395 if ((!ISHFSPLUS(VTOVCB(vp))) && (length > (off_t)MAXHFSFILESIZE))
1396 return (EFBIG);
1c79356b 1397
b4c24cb9 1398 hfsmp = VTOHFS(vp);
1c79356b 1399
9bccf70c
A
1400 tv = time;
1401 retval = E_NONE;
1c79356b 1402
9bccf70c
A
1403 /*
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.
1406 */
1407#if QUOTA
1408 if (retval = hfs_getinoquota(cp))
1409 return(retval);
1410#endif /* QUOTA */
1c79356b 1411
9bccf70c
A
1412 /*
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.
1416 */
1417 if (length > fp->ff_size) {
1418#if QUOTA
b4c24cb9 1419 retval = hfs_chkdq(cp, (int64_t)(roundup(length - filebytes, blksize)),
9bccf70c
A
1420 ap->a_cred, 0);
1421 if (retval)
1422 goto Err_Exit;
1423#endif /* QUOTA */
1424 /*
1425 * If we don't have enough physical space then
1426 * we need to extend the physical size.
1427 */
1428 if (length > filebytes) {
1429 int eflags;
1c79356b 1430
9bccf70c
A
1431 /* All or nothing and don't round up to clumpsize. */
1432 eflags = kEFAllMask | kEFNoClumpMask;
1c79356b 1433
9bccf70c
A
1434 if (suser(ap->a_cred, NULL) != 0)
1435 eflags |= kEFReserveMask; /* keep a reserve */
1c79356b 1436
b4c24cb9
A
1437 // XXXdbg
1438 hfs_global_shared_lock_acquire(hfsmp);
1439 if (hfsmp->jnl) {
1440 if (journal_start_transaction(hfsmp->jnl) != 0) {
1441 retval = EINVAL;
1442 goto Err_Exit;
1443 }
1444 }
1445
9bccf70c
A
1446 /* lock extents b-tree (also protects volume bitmap) */
1447 retval = hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_EXCLUSIVE, ap->a_p);
b4c24cb9
A
1448 if (retval) {
1449 if (hfsmp->jnl) {
1450 journal_end_transaction(hfsmp->jnl);
1451 }
1452 hfs_global_shared_lock_release(hfsmp);
1453
9bccf70c 1454 goto Err_Exit;
b4c24cb9 1455 }
1c79356b 1456
9bccf70c
A
1457 while ((length > filebytes) && (retval == E_NONE)) {
1458 bytesToAdd = length - filebytes;
1459 retval = MacToVFSError(ExtendFileC(VTOVCB(vp),
1460 (FCB*)fp,
1c79356b 1461 bytesToAdd,
0b4e3aa0 1462 0,
9bccf70c 1463 eflags,
1c79356b
A
1464 &actualBytesAdded));
1465
9bccf70c
A
1466 filebytes = (off_t)fp->ff_blocks * (off_t)blksize;
1467 if (actualBytesAdded == 0 && retval == E_NONE) {
1468 if (length > filebytes)
1469 length = filebytes;
1470 break;
1471 }
1472 } /* endwhile */
b4c24cb9 1473
9bccf70c 1474 (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_RELEASE, ap->a_p);
b4c24cb9
A
1475
1476 // XXXdbg
1477 if (hfsmp->jnl) {
1478 hfs_flushvolumeheader(hfsmp, MNT_NOWAIT, 0);
1479 journal_end_transaction(hfsmp->jnl);
1480 }
1481 hfs_global_shared_lock_release(hfsmp);
1482
9bccf70c
A
1483 if (retval)
1484 goto Err_Exit;
1485
1486 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 7)) | DBG_FUNC_NONE,
1487 (int)length, (int)fp->ff_size, (int)filebytes, 0, 0);
1c79356b 1488 }
1c79356b 1489
9bccf70c
A
1490 if (!(ap->a_flags & IO_NOZEROFILL)) {
1491 if (UBCINFOEXISTS(vp) && retval == E_NONE) {
1492 struct rl_entry *invalid_range;
1493 int devBlockSize;
1494 off_t zero_limit;
0b4e3aa0 1495
9bccf70c
A
1496 zero_limit = (fp->ff_size + (PAGE_SIZE_64 - 1)) & ~PAGE_MASK_64;
1497 if (length < zero_limit) zero_limit = length;
1498
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)) {
0b4e3aa0
A
1504
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(): */
9bccf70c
A
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);
0b4e3aa0
A
1514 if (retval) goto Err_Exit;
1515
1516 /* Merely invalidate the remaining area, if necessary: */
9bccf70c
A
1517 if (length > zero_limit) {
1518 rl_add(zero_limit, length - 1, &fp->ff_invalidranges);
1519 cp->c_zftimeout = time.tv_sec + ZFTIMELIMIT;
1520 }
1521 } else {
0b4e3aa0
A
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:
1525 */
9bccf70c
A
1526 rl_add(fp->ff_size, length - 1, &fp->ff_invalidranges);
1527 cp->c_zftimeout = time.tv_sec + ZFTIMELIMIT;
1528 };
1529 }
1530 } else {
1531 panic("hfs_truncate: invoked on non-UBC object?!");
1532 };
1533 }
1534 cp->c_flag |= C_UPDATE;
1535 fp->ff_size = length;
0b4e3aa0 1536
9bccf70c
A
1537 if (UBCISVALID(vp))
1538 ubc_setsize(vp, fp->ff_size); /* XXX check errors */
0b4e3aa0 1539
9bccf70c 1540 } else { /* Shorten the size of the file */
0b4e3aa0 1541
9bccf70c
A
1542 if (fp->ff_size > length) {
1543 /*
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.
1547 */
1548 if (UBCISVALID(vp))
1549 ubc_setsize(vp, length); /* XXX check errors */
0b4e3aa0 1550
9bccf70c
A
1551 vflags = ((length > 0) ? V_SAVE : 0) | V_SAVEMETA;
1552 retval = vinvalbuf(vp, vflags, ap->a_cred, ap->a_p, 0, 0);
1553
1554 /* Any space previously marked as invalid is now irrelevant: */
1555 rl_remove(length, fp->ff_size - 1, &fp->ff_invalidranges);
1556 }
1c79356b 1557
9bccf70c
A
1558 /*
1559 * Account for any unmapped blocks. Note that the new
1560 * file length can still end up with unmapped blocks.
1561 */
1562 if (fp->ff_unallocblocks > 0) {
1563 u_int32_t finalblks;
1c79356b 1564
9bccf70c
A
1565 /* lock extents b-tree */
1566 retval = hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID,
1567 LK_EXCLUSIVE, ap->a_p);
1568 if (retval)
1569 goto Err_Exit;
1c79356b 1570
9bccf70c
A
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;
1575
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;
1583 }
1584 (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID,
1585 LK_RELEASE, ap->a_p);
1586 }
1c79356b 1587
9bccf70c
A
1588 /*
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.
1593 */
1594 if ((ap->a_flags & IO_NDELAY) || (!ISSET(ap->a_p->p_flag, P_TBE))) {
1595#if QUOTA
1596 off_t savedbytes = ((off_t)fp->ff_blocks * (off_t)blksize);
1597#endif /* QUOTA */
b4c24cb9
A
1598 // XXXdbg
1599 hfs_global_shared_lock_acquire(hfsmp);
1600 if (hfsmp->jnl) {
1601 if (journal_start_transaction(hfsmp->jnl) != 0) {
1602 retval = EINVAL;
1603 goto Err_Exit;
1604 }
1605 }
1606
9bccf70c
A
1607 /* lock extents b-tree (also protects volume bitmap) */
1608 retval = hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_EXCLUSIVE, ap->a_p);
b4c24cb9
A
1609 if (retval) {
1610 if (hfsmp->jnl) {
1611 journal_end_transaction(hfsmp->jnl);
1612 }
1613 hfs_global_shared_lock_release(hfsmp);
9bccf70c 1614 goto Err_Exit;
b4c24cb9 1615 }
9bccf70c
A
1616
1617 if (fp->ff_unallocblocks == 0)
1618 retval = MacToVFSError(TruncateFileC(VTOVCB(vp),
1619 (FCB*)fp, length, false));
1c79356b 1620
9bccf70c 1621 (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_RELEASE, ap->a_p);
b4c24cb9
A
1622
1623 // XXXdbg
1624 if (hfsmp->jnl) {
1625 hfs_flushvolumeheader(hfsmp, MNT_NOWAIT, 0);
1626 journal_end_transaction(hfsmp->jnl);
1627 }
1628 hfs_global_shared_lock_release(hfsmp);
1629
9bccf70c
A
1630 filebytes = (off_t)fp->ff_blocks * (off_t)blksize;
1631 if (retval)
1632 goto Err_Exit;
1633#if QUOTA
1634 /* These are bytesreleased */
1635 (void) hfs_chkdq(cp, (int64_t)-(savedbytes - filebytes), NOCRED, 0);
1636#endif /* QUOTA */
1637 }
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;
1c79356b 1642 }
9bccf70c
A
1643 cp->c_flag |= C_CHANGE;
1644 retval = VOP_UPDATE(vp, &tv, &tv, MNT_WAIT);
1645 if (retval) {
0b4e3aa0 1646 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 7)) | DBG_FUNC_NONE,
1c79356b 1647 -1, -1, -1, retval, 0);
9bccf70c 1648 }
1c79356b 1649
9bccf70c 1650Err_Exit:
1c79356b 1651
9bccf70c
A
1652 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 7)) | DBG_FUNC_END,
1653 (int)length, (int)fp->ff_size, (int)filebytes, retval, 0);
1c79356b 1654
9bccf70c 1655 return (retval);
1c79356b
A
1656}
1657
1658
1659
1660/*
1661#
1662#% allocate vp L L L
1663#
1664vop_allocate {
0b4e3aa0
A
1665 IN struct vnode *vp;
1666 IN off_t length;
1667 IN int flags;
1668 OUT off_t *bytesallocated;
1669 IN off_t offset;
1670 IN struct ucred *cred;
1671 IN struct proc *p;
1c79356b 1672};
9bccf70c 1673 * allocate a cnode to at most length size
1c79356b
A
1674 */
1675int hfs_allocate(ap)
9bccf70c
A
1676 struct vop_allocate_args /* {
1677 struct vnode *a_vp;
1678 off_t a_length;
1679 u_int32_t a_flags;
1680 off_t *a_bytesallocated;
1681 off_t a_offset;
1682 struct ucred *a_cred;
1683 struct proc *a_p;
1684 } */ *ap;
1c79356b 1685{
9bccf70c
A
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;
1690 off_t startingPEOF;
1691 off_t moreBytesRequested;
1692 off_t actualBytesAdded;
1693 off_t filebytes;
1694 u_long fileblocks;
1695 long vflags;
1696 struct timeval tv;
1697 int retval, retval2;
1698 UInt32 blockHint;
1699 UInt32 extendFlags =0; /* For call to ExtendFileC */
b4c24cb9
A
1700 struct hfsmount *hfsmp;
1701
1702 hfsmp = VTOHFS(vp);
9bccf70c
A
1703
1704 *(ap->a_bytesallocated) = 0;
1705 fileblocks = fp->ff_blocks;
1706 filebytes = (off_t)fileblocks * (off_t)VTOVCB(vp)->blockSize;
1707
1708 if (length < (off_t)0)
1709 return (EINVAL);
1710 if (vp->v_type != VREG && vp->v_type != VLNK)
1711 return (EISDIR);
1712 if ((ap->a_flags & ALLOCATEFROMVOL) && (length <= filebytes))
1713 return (EINVAL);
0b4e3aa0 1714
9bccf70c 1715 /* Fill in the flags word for the call to Extend the file */
1c79356b 1716
9bccf70c 1717 if (ap->a_flags & ALLOCATECONTIG)
1c79356b 1718 extendFlags |= kEFContigMask;
1c79356b 1719
9bccf70c 1720 if (ap->a_flags & ALLOCATEALL)
1c79356b 1721 extendFlags |= kEFAllMask;
1c79356b 1722
9bccf70c
A
1723 if (suser(ap->a_cred, NULL) != 0)
1724 extendFlags |= kEFReserveMask;
1c79356b 1725
9bccf70c
A
1726 tv = time;
1727 retval = E_NONE;
1728 blockHint = 0;
1729 startingPEOF = filebytes;
1c79356b 1730
9bccf70c
A
1731 if (ap->a_flags & ALLOCATEFROMPEOF)
1732 length += filebytes;
1733 else if (ap->a_flags & ALLOCATEFROMVOL)
1734 blockHint = ap->a_offset / VTOVCB(vp)->blockSize;
1c79356b 1735
9bccf70c
A
1736 /* If no changes are necesary, then we're done */
1737 if (filebytes == length)
1738 goto Std_Exit;
1c79356b 1739
9bccf70c
A
1740 /*
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.
1744 */
1745 if (length > filebytes) {
1746 moreBytesRequested = length - filebytes;
1c79356b 1747
9bccf70c 1748#if QUOTA
b4c24cb9
A
1749 retval = hfs_chkdq(cp,
1750 (int64_t)(roundup(moreBytesRequested, VTOVCB(vp)->blockSize)),
9bccf70c
A
1751 ap->a_cred, 0);
1752 if (retval)
1753 return (retval);
1754
1755#endif /* QUOTA */
b4c24cb9
A
1756 // XXXdbg
1757 hfs_global_shared_lock_acquire(hfsmp);
1758 if (hfsmp->jnl) {
1759 if (journal_start_transaction(hfsmp->jnl) != 0) {
1760 retval = EINVAL;
1761 goto Err_Exit;
1762 }
1763 }
1764
1c79356b 1765 /* lock extents b-tree (also protects volume bitmap) */
9bccf70c 1766 retval = hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_EXCLUSIVE, ap->a_p);
b4c24cb9
A
1767 if (retval) {
1768 if (hfsmp->jnl) {
1769 journal_end_transaction(hfsmp->jnl);
1770 }
1771 hfs_global_shared_lock_release(hfsmp);
1772 goto Err_Exit;
1773 }
1c79356b 1774
9bccf70c
A
1775 retval = MacToVFSError(ExtendFileC(VTOVCB(vp),
1776 (FCB*)fp,
1777 moreBytesRequested,
1778 blockHint,
1779 extendFlags,
1780 &actualBytesAdded));
1c79356b
A
1781
1782 *(ap->a_bytesallocated) = actualBytesAdded;
9bccf70c 1783 filebytes = (off_t)fp->ff_blocks * (off_t)VTOVCB(vp)->blockSize;
b4c24cb9 1784
9bccf70c 1785 (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_RELEASE, ap->a_p);
1c79356b 1786
b4c24cb9
A
1787 // XXXdbg
1788 if (hfsmp->jnl) {
1789 hfs_flushvolumeheader(hfsmp, MNT_NOWAIT, 0);
1790 journal_end_transaction(hfsmp->jnl);
1791 }
1792 hfs_global_shared_lock_release(hfsmp);
1793
1c79356b
A
1794 /*
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
1797 */
9bccf70c
A
1798 if (retval && (startingPEOF == filebytes))
1799 goto Err_Exit;
1c79356b 1800
9bccf70c
A
1801 /*
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
1806 * block size.
1807 */
0b4e3aa0
A
1808 if ((actualBytesAdded != 0) && (moreBytesRequested < actualBytesAdded))
1809 *(ap->a_bytesallocated) =
1810 roundup(moreBytesRequested, (off_t)VTOVCB(vp)->blockSize);
1c79356b 1811
9bccf70c 1812 } else { /* Shorten the size of the file */
1c79356b 1813
9bccf70c 1814 if (fp->ff_size > length) {
1c79356b
A
1815 /*
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.
1819 */
1820 vflags = ((length > 0) ? V_SAVE : 0) | V_SAVEMETA;
1821 (void) vinvalbuf(vp, vflags, ap->a_cred, ap->a_p, 0, 0);
1822 }
1823
b4c24cb9
A
1824 // XXXdbg
1825 hfs_global_shared_lock_acquire(hfsmp);
1826 if (hfsmp->jnl) {
1827 if (journal_start_transaction(hfsmp->jnl) != 0) {
1828 retval = EINVAL;
1829 goto Err_Exit;
1830 }
1831 }
1832
9bccf70c
A
1833 /* lock extents b-tree (also protects volume bitmap) */
1834 retval = hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_EXCLUSIVE, ap->a_p);
b4c24cb9
A
1835 if (retval) {
1836 if (hfsmp->jnl) {
1837 journal_end_transaction(hfsmp->jnl);
1838 }
1839 hfs_global_shared_lock_release(hfsmp);
1840
1841 goto Err_Exit;
1842 }
1c79356b 1843
9bccf70c 1844 retval = MacToVFSError(
1c79356b 1845 TruncateFileC(
9bccf70c
A
1846 VTOVCB(vp),
1847 (FCB*)fp,
1c79356b
A
1848 length,
1849 false));
9bccf70c
A
1850 (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_RELEASE, ap->a_p);
1851 filebytes = (off_t)fp->ff_blocks * (off_t)VTOVCB(vp)->blockSize;
b4c24cb9
A
1852
1853 if (hfsmp->jnl) {
1854 hfs_flushvolumeheader(hfsmp, MNT_NOWAIT, 0);
1855 journal_end_transaction(hfsmp->jnl);
1856 }
1857 hfs_global_shared_lock_release(hfsmp);
1858
1859
1c79356b
A
1860 /*
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
1863 */
9bccf70c
A
1864 if (retval && (startingPEOF == filebytes)) goto Err_Exit;
1865#if QUOTA
1866 /* These are bytesreleased */
1867 (void) hfs_chkdq(cp, (int64_t)-((startingPEOF - filebytes)), NOCRED,0);
1868#endif /* QUOTA */
1c79356b 1869
9bccf70c
A
1870 if (fp->ff_size > filebytes) {
1871 fp->ff_size = filebytes;
1c79356b
A
1872
1873 if (UBCISVALID(vp))
9bccf70c
A
1874 ubc_setsize(vp, fp->ff_size); /* XXX check errors */
1875 }
1876 }
1c79356b
A
1877
1878Std_Exit:
9bccf70c 1879 cp->c_flag |= C_CHANGE | C_UPDATE;
1c79356b
A
1880 retval2 = VOP_UPDATE(vp, &tv, &tv, MNT_WAIT);
1881
9bccf70c
A
1882 if (retval == 0)
1883 retval = retval2;
1c79356b 1884Err_Exit:
9bccf70c 1885 return (retval);
1c79356b
A
1886}
1887
1888
9bccf70c
A
1889/*
1890 * pagein for HFS filesystem
1891 */
1c79356b
A
1892int
1893hfs_pagein(ap)
1894 struct vop_pagein_args /* {
1895 struct vnode *a_vp,
1896 upl_t a_pl,
1897 vm_offset_t a_pl_offset,
1898 off_t a_f_offset,
1899 size_t a_size,
1900 struct ucred *a_cred,
1901 int a_flags
1902 } */ *ap;
1903{
9bccf70c
A
1904 register struct vnode *vp = ap->a_vp;
1905 int devBlockSize = 0;
1906 int error;
1c79356b 1907
9bccf70c
A
1908 if (vp->v_type != VREG && vp->v_type != VLNK)
1909 panic("hfs_pagein: vp not UBC type\n");
1c79356b 1910
9bccf70c 1911 VOP_DEVBLOCKSIZE(VTOC(vp)->c_devvp, &devBlockSize);
1c79356b 1912
9bccf70c
A
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,
1915 ap->a_flags);
1916 return (error);
1c79356b
A
1917}
1918
1919/*
1920 * pageout for HFS filesystem.
1921 */
1922int
1923hfs_pageout(ap)
1924 struct vop_pageout_args /* {
1925 struct vnode *a_vp,
1926 upl_t a_pl,
1927 vm_offset_t a_pl_offset,
1928 off_t a_f_offset,
1929 size_t a_size,
1930 struct ucred *a_cred,
1931 int a_flags
1932 } */ *ap;
1933{
9bccf70c
A
1934 struct vnode *vp = ap->a_vp;
1935 struct cnode *cp = VTOC(vp);
1936 struct filefork *fp = VTOF(vp);
1937 int retval;
1938 int devBlockSize = 0;
1939 off_t end_of_range;
1940 off_t filesize;
1c79356b
A
1941
1942 if (UBCINVALID(vp))
1943 panic("hfs_pageout: Not a VREG: vp=%x", vp);
1944
9bccf70c
A
1945 VOP_DEVBLOCKSIZE(cp->c_devvp, &devBlockSize);
1946 filesize = fp->ff_size;
0b4e3aa0
A
1947 end_of_range = ap->a_f_offset + ap->a_size - 1;
1948
9bccf70c
A
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);
0b4e3aa0 1953
1c79356b 1954 retval = cluster_pageout(vp, ap->a_pl, ap->a_pl_offset, ap->a_f_offset, ap->a_size,
9bccf70c 1955 filesize, devBlockSize, ap->a_flags);
0b4e3aa0 1956
1c79356b
A
1957 /*
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
1960 * tampering.
1961 */
1962 if (retval == 0 && ap->a_cred && ap->a_cred->cr_uid != 0)
9bccf70c 1963 cp->c_mode &= ~(S_ISUID | S_ISGID);
1c79356b 1964
1c79356b
A
1965 return (retval);
1966}
1967
1968/*
1969 * Intercept B-Tree node writes to unswap them if necessary.
1970#
1971#vop_bwrite {
1972# IN struct buf *bp;
1973 */
1974int
1975hfs_bwrite(ap)
9bccf70c
A
1976 struct vop_bwrite_args /* {
1977 struct buf *a_bp;
1978 } */ *ap;
1c79356b 1979{
9bccf70c 1980 int retval = 0;
9bccf70c
A
1981 register struct buf *bp = ap->a_bp;
1982 register struct vnode *vp = bp->b_vp;
b4c24cb9 1983#if BYTE_ORDER == LITTLE_ENDIAN
9bccf70c
A
1984 BlockDescriptor block;
1985
1986 /* Trap B-Tree writes */
1987 if ((VTOC(vp)->c_fileid == kHFSExtentsFileID) ||
1988 (VTOC(vp)->c_fileid == kHFSCatalogFileID)) {
1989
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;
1c79356b 1998
9bccf70c
A
1999 /* Endian un-swap B-Tree node */
2000 SWAP_BT_NODE (&block, ISHFSPLUS (VTOVCB(vp)), VTOC(vp)->c_fileid, 1);
2001 }
1c79356b 2002
9bccf70c
A
2003 /* We don't check to make sure that it's 0x0e00 because it could be all zeros */
2004 }
1c79356b 2005#endif
9bccf70c 2006 /* This buffer shouldn't be locked anymore but if it is clear it */
b4c24cb9
A
2007 if (ISSET(bp->b_flags, B_LOCKED)) {
2008 // XXXdbg
2009 if (VTOHFS(vp)->jnl) {
2010 panic("hfs: CLEARING the lock bit on bp 0x%x\n", bp);
2011 }
2012 CLR(bp->b_flags, B_LOCKED);
9bccf70c
A
2013 printf("hfs_bwrite: called with lock bit set\n");
2014 }
2015 retval = vn_bwrite (ap);
1c79356b 2016
9bccf70c 2017 return (retval);
1c79356b 2018}