]> git.saurik.com Git - apple/xnu.git/blame - bsd/hfs/hfs_readwrite.c
xnu-517.3.7.tar.gz
[apple/xnu.git] / bsd / hfs / hfs_readwrite.c
CommitLineData
1c79356b 1/*
55e303ae 2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
1c79356b
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
43866e37 6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
1c79356b 7 *
43866e37
A
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
13 * file.
14 *
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
1c79356b
A
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
43866e37
A
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.
1c79356b
A
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25/* @(#)hfs_readwrite.c 1.0
26 *
9bccf70c 27 * (c) 1998-2001 Apple Computer, Inc. All Rights Reserved
1c79356b 28 *
1c79356b
A
29 * hfs_readwrite.c -- vnode operations to deal with reading and writing files.
30 *
1c79356b
A
31 */
32
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>
55e303ae 38#include <sys/filedesc.h>
1c79356b
A
39#include <sys/stat.h>
40#include <sys/buf.h>
41#include <sys/proc.h>
1c79356b
A
42#include <sys/vnode.h>
43#include <sys/uio.h>
44
45#include <miscfs/specfs/specdev.h>
46
1c79356b
A
47#include <sys/ubc.h>
48#include <vm/vm_pageout.h>
49
1c79356b
A
50#include <sys/kdebug.h>
51
52#include "hfs.h"
1c79356b 53#include "hfs_endian.h"
9bccf70c 54#include "hfs_quota.h"
1c79356b
A
55#include "hfscommon/headers/FileMgrInternal.h"
56#include "hfscommon/headers/BTreesInternal.h"
9bccf70c
A
57#include "hfs_cnode.h"
58#include "hfs_dbg.h"
1c79356b 59
9bccf70c 60extern int overflow_extents(struct filefork *fp);
1c79356b
A
61
62#define can_cluster(size) ((((size & (4096-1))) == 0) && (size <= (MAXPHYSIO/2)))
63
64enum {
65 MAXHFSFILESIZE = 0x7FFFFFFF /* this needs to go in the mount structure */
66};
67
68extern u_int32_t GetLogicalBlockSize(struct vnode *vp);
69
55e303ae
A
70static int hfs_clonelink(struct vnode *, int, struct ucred *, struct proc *);
71static int hfs_clonefile(struct vnode *, int, int, int, struct ucred *, struct proc *);
72static int hfs_clonesysfile(struct vnode *, int, int, int, struct ucred *, struct proc *);
73
1c79356b
A
74
75/*****************************************************************************
76*
77* Operations on vnodes
78*
79*****************************************************************************/
80
81/*
82#% read vp L L L
83#
84 vop_read {
85 IN struct vnode *vp;
86 INOUT struct uio *uio;
87 IN int ioflag;
88 IN struct ucred *cred;
89
90 */
91
92int
93hfs_read(ap)
9bccf70c
A
94 struct vop_read_args /* {
95 struct vnode *a_vp;
96 struct uio *a_uio;
97 int a_ioflag;
98 struct ucred *a_cred;
99 } */ *ap;
1c79356b 100{
9bccf70c
A
101 register struct uio *uio = ap->a_uio;
102 register struct vnode *vp = ap->a_vp;
103 struct cnode *cp;
104 struct filefork *fp;
9bccf70c 105 int devBlockSize = 0;
9bccf70c
A
106 int retval = 0;
107 off_t filesize;
108 off_t filebytes;
55e303ae
A
109 off_t start_resid = uio->uio_resid;
110
9bccf70c
A
111
112 /* Preflight checks */
55e303ae
A
113 if ((vp->v_type != VREG) || !UBCINFOEXISTS(vp))
114 return (EPERM); /* can only read regular files */
9bccf70c
A
115 if (uio->uio_resid == 0)
116 return (0); /* Nothing left to do */
117 if (uio->uio_offset < 0)
118 return (EINVAL); /* cant read from a negative offset */
119
120 cp = VTOC(vp);
121 fp = VTOF(vp);
122 filesize = fp->ff_size;
123 filebytes = (off_t)fp->ff_blocks * (off_t)VTOVCB(vp)->blockSize;
124 if (uio->uio_offset > filesize) {
125 if ((!ISHFSPLUS(VTOVCB(vp))) && (uio->uio_offset > (off_t)MAXHFSFILESIZE))
126 return (EFBIG);
127 else
128 return (0);
129 }
1c79356b 130
9bccf70c 131 VOP_DEVBLOCKSIZE(cp->c_devvp, &devBlockSize);
1c79356b 132
9bccf70c
A
133 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_START,
134 (int)uio->uio_offset, uio->uio_resid, (int)filesize, (int)filebytes, 0);
1c79356b 135
55e303ae 136 retval = cluster_read(vp, uio, filesize, devBlockSize, 0);
1c79356b 137
9bccf70c 138 cp->c_flag |= C_ACCESS;
1c79356b 139
9bccf70c
A
140 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_END,
141 (int)uio->uio_offset, uio->uio_resid, (int)filesize, (int)filebytes, 0);
1c79356b 142
55e303ae
A
143 /*
144 * Keep track blocks read
145 */
146 if (VTOHFS(vp)->hfc_stage == HFC_RECORDING && retval == 0) {
147 /*
148 * If this file hasn't been seen since the start of
149 * the current sampling period then start over.
150 */
151 if (cp->c_atime < VTOHFS(vp)->hfc_timebase) {
152 fp->ff_bytesread = start_resid - uio->uio_resid;
153 cp->c_atime = time.tv_sec;
154 } else {
155 fp->ff_bytesread += start_resid - uio->uio_resid;
156 }
157 }
158
9bccf70c 159 return (retval);
1c79356b
A
160}
161
162/*
163 * Write data to a file or directory.
164#% write vp L L L
165#
166 vop_write {
167 IN struct vnode *vp;
168 INOUT struct uio *uio;
169 IN int ioflag;
170 IN struct ucred *cred;
171
172 */
173int
174hfs_write(ap)
9bccf70c
A
175 struct vop_write_args /* {
176 struct vnode *a_vp;
177 struct uio *a_uio;
178 int a_ioflag;
179 struct ucred *a_cred;
180 } */ *ap;
1c79356b 181{
9bccf70c
A
182 struct vnode *vp = ap->a_vp;
183 struct uio *uio = ap->a_uio;
184 struct cnode *cp;
185 struct filefork *fp;
9bccf70c
A
186 struct proc *p;
187 struct timeval tv;
188 ExtendedVCB *vcb;
55e303ae
A
189 int devBlockSize = 0;
190 off_t origFileSize, writelimit, bytesToAdd;
191 off_t actualBytesAdded;
192 u_long resid;
193 int eflags, ioflag;
194 int retval;
9bccf70c 195 off_t filebytes;
b4c24cb9
A
196 struct hfsmount *hfsmp;
197 int started_tr = 0, grabbed_lock = 0;
1c79356b 198
1c79356b 199
9bccf70c
A
200 if (uio->uio_offset < 0)
201 return (EINVAL);
202 if (uio->uio_resid == 0)
203 return (E_NONE);
55e303ae
A
204 if ((vp->v_type != VREG) || !UBCINFOEXISTS(vp))
205 return (EPERM); /* Can only write regular files */
9bccf70c 206
55e303ae 207 ioflag = ap->a_ioflag;
9bccf70c
A
208 cp = VTOC(vp);
209 fp = VTOF(vp);
210 vcb = VTOVCB(vp);
55e303ae 211 filebytes = (off_t)fp->ff_blocks * (off_t)vcb->blockSize;
9bccf70c
A
212
213 if (ioflag & IO_APPEND)
214 uio->uio_offset = fp->ff_size;
215 if ((cp->c_flags & APPEND) && uio->uio_offset != fp->ff_size)
216 return (EPERM);
1c79356b 217
b4c24cb9
A
218 // XXXdbg - don't allow modification of the journal or journal_info_block
219 if (VTOHFS(vp)->jnl && cp->c_datafork) {
220 struct HFSPlusExtentDescriptor *extd;
221
55e303ae 222 extd = &cp->c_datafork->ff_extents[0];
b4c24cb9
A
223 if (extd->startBlock == VTOVCB(vp)->vcbJinfoBlock || extd->startBlock == VTOHFS(vp)->jnl_start) {
224 return EPERM;
225 }
226 }
227
1c79356b
A
228 writelimit = uio->uio_offset + uio->uio_resid;
229
9bccf70c
A
230 /*
231 * Maybe this should be above the vnode op call, but so long as
232 * file servers have no limits, I don't think it matters.
233 */
234 p = uio->uio_procp;
235 if (vp->v_type == VREG && p &&
236 writelimit > p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
237 psignal(p, SIGXFSZ);
238 return (EFBIG);
239 }
240 p = current_proc();
1c79356b 241
9bccf70c 242 VOP_DEVBLOCKSIZE(cp->c_devvp, &devBlockSize);
1c79356b 243
9bccf70c
A
244 resid = uio->uio_resid;
245 origFileSize = fp->ff_size;
246 eflags = kEFDeferMask; /* defer file block allocations */
247 filebytes = (off_t)fp->ff_blocks * (off_t)vcb->blockSize;
1c79356b 248
9bccf70c
A
249 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 0)) | DBG_FUNC_START,
250 (int)uio->uio_offset, uio->uio_resid, (int)fp->ff_size, (int)filebytes, 0);
251 retval = 0;
1c79356b 252
9bccf70c
A
253 /* Now test if we need to extend the file */
254 /* Doing so will adjust the filebytes for us */
1c79356b 255
9bccf70c
A
256#if QUOTA
257 if(writelimit > filebytes) {
258 bytesToAdd = writelimit - filebytes;
1c79356b 259
b4c24cb9 260 retval = hfs_chkdq(cp, (int64_t)(roundup(bytesToAdd, vcb->blockSize)),
9bccf70c
A
261 ap->a_cred, 0);
262 if (retval)
263 return (retval);
264 }
265#endif /* QUOTA */
1c79356b 266
b4c24cb9 267 hfsmp = VTOHFS(vp);
55e303ae
A
268
269#ifdef HFS_SPARSE_DEV
270 /*
271 * When the underlying device is sparse and space
272 * is low (< 8MB), stop doing delayed allocations
273 * and begin doing synchronous I/O.
274 */
275 if ((hfsmp->hfs_flags & HFS_HAS_SPARSE_DEVICE) &&
276 (hfs_freeblks(hfsmp, 0) < 2048)) {
277 eflags &= ~kEFDeferMask;
278 ioflag |= IO_SYNC;
279 }
280#endif /* HFS_SPARSE_DEV */
281
b4c24cb9
A
282 if (writelimit > filebytes) {
283 hfs_global_shared_lock_acquire(hfsmp);
284 grabbed_lock = 1;
285 }
286 if (hfsmp->jnl && (writelimit > filebytes)) {
287 if (journal_start_transaction(hfsmp->jnl) != 0) {
288 hfs_global_shared_lock_release(hfsmp);
289 return EINVAL;
290 }
291 started_tr = 1;
292 }
293
9bccf70c 294 while (writelimit > filebytes) {
9bccf70c 295 bytesToAdd = writelimit - filebytes;
55e303ae 296 if (ap->a_cred && suser(ap->a_cred, NULL) != 0)
9bccf70c
A
297 eflags |= kEFReserveMask;
298
299 /* lock extents b-tree (also protects volume bitmap) */
300 retval = hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_EXCLUSIVE, current_proc());
301 if (retval != E_NONE)
302 break;
55e303ae
A
303
304 /* Files that are changing size are not hot file candidates. */
305 if (hfsmp->hfc_stage == HFC_RECORDING) {
306 fp->ff_bytesread = 0;
307 }
9bccf70c
A
308 retval = MacToVFSError(ExtendFileC (vcb, (FCB*)fp, bytesToAdd,
309 0, eflags, &actualBytesAdded));
310
311 (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_RELEASE, p);
312 if ((actualBytesAdded == 0) && (retval == E_NONE))
313 retval = ENOSPC;
314 if (retval != E_NONE)
315 break;
316 filebytes = (off_t)fp->ff_blocks * (off_t)vcb->blockSize;
317 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 0)) | DBG_FUNC_NONE,
318 (int)uio->uio_offset, uio->uio_resid, (int)fp->ff_size, (int)filebytes, 0);
319 }
1c79356b 320
b4c24cb9
A
321 // XXXdbg
322 if (started_tr) {
55e303ae
A
323 tv = time;
324 VOP_UPDATE(vp, &tv, &tv, 1);
325
b4c24cb9
A
326 hfs_flushvolumeheader(hfsmp, MNT_NOWAIT, 0);
327 journal_end_transaction(hfsmp->jnl);
328 started_tr = 0;
329 }
330 if (grabbed_lock) {
331 hfs_global_shared_lock_release(hfsmp);
332 grabbed_lock = 0;
333 }
334
55e303ae 335 if (retval == E_NONE) {
0b4e3aa0
A
336 off_t filesize;
337 off_t zero_off;
338 off_t tail_off;
339 off_t inval_start;
340 off_t inval_end;
341 off_t io_start, io_end;
342 int lflag;
343 struct rl_entry *invalid_range;
344
9bccf70c 345 if (writelimit > fp->ff_size)
0b4e3aa0
A
346 filesize = writelimit;
347 else
9bccf70c 348 filesize = fp->ff_size;
1c79356b 349
0b4e3aa0 350 lflag = (ioflag & IO_SYNC);
1c79356b 351
9bccf70c 352 if (uio->uio_offset <= fp->ff_size) {
0b4e3aa0
A
353 zero_off = uio->uio_offset & ~PAGE_MASK_64;
354
355 /* Check to see whether the area between the zero_offset and the start
356 of the transfer to see whether is invalid and should be zero-filled
357 as part of the transfer:
358 */
55e303ae
A
359 if (uio->uio_offset > zero_off) {
360 if (rl_scan(&fp->ff_invalidranges, zero_off, uio->uio_offset - 1, &invalid_range) != RL_NOOVERLAP)
361 lflag |= IO_HEADZEROFILL;
362 }
0b4e3aa0 363 } else {
9bccf70c 364 off_t eof_page_base = fp->ff_size & ~PAGE_MASK_64;
0b4e3aa0 365
9bccf70c 366 /* The bytes between fp->ff_size and uio->uio_offset must never be
0b4e3aa0
A
367 read without being zeroed. The current last block is filled with zeroes
368 if it holds valid data but in all cases merely do a little bookkeeping
369 to track the area from the end of the current last page to the start of
370 the area actually written. For the same reason only the bytes up to the
371 start of the page where this write will start is invalidated; any remainder
372 before uio->uio_offset is explicitly zeroed as part of the cluster_write.
373
374 Note that inval_start, the start of the page after the current EOF,
375 may be past the start of the write, in which case the zeroing
376 will be handled by the cluser_write of the actual data.
377 */
9bccf70c 378 inval_start = (fp->ff_size + (PAGE_SIZE_64 - 1)) & ~PAGE_MASK_64;
0b4e3aa0 379 inval_end = uio->uio_offset & ~PAGE_MASK_64;
9bccf70c 380 zero_off = fp->ff_size;
0b4e3aa0 381
9bccf70c
A
382 if ((fp->ff_size & PAGE_MASK_64) &&
383 (rl_scan(&fp->ff_invalidranges,
0b4e3aa0 384 eof_page_base,
9bccf70c 385 fp->ff_size - 1,
0b4e3aa0
A
386 &invalid_range) != RL_NOOVERLAP)) {
387 /* The page containing the EOF is not valid, so the
388 entire page must be made inaccessible now. If the write
389 starts on a page beyond the page containing the eof
390 (inval_end > eof_page_base), add the
391 whole page to the range to be invalidated. Otherwise
392 (i.e. if the write starts on the same page), zero-fill
393 the entire page explicitly now:
394 */
395 if (inval_end > eof_page_base) {
396 inval_start = eof_page_base;
397 } else {
398 zero_off = eof_page_base;
399 };
400 };
401
402 if (inval_start < inval_end) {
403 /* There's some range of data that's going to be marked invalid */
404
405 if (zero_off < inval_start) {
406 /* The pages between inval_start and inval_end are going to be invalidated,
407 and the actual write will start on a page past inval_end. Now's the last
408 chance to zero-fill the page containing the EOF:
409 */
9bccf70c
A
410 retval = cluster_write(vp, (struct uio *) 0,
411 fp->ff_size, inval_start,
412 zero_off, (off_t)0, devBlockSize,
413 lflag | IO_HEADZEROFILL | IO_NOZERODIRTY);
0b4e3aa0
A
414 if (retval) goto ioerr_exit;
415 };
416
417 /* Mark the remaining area of the newly allocated space as invalid: */
9bccf70c
A
418 rl_add(inval_start, inval_end - 1 , &fp->ff_invalidranges);
419 cp->c_zftimeout = time.tv_sec + ZFTIMELIMIT;
420 zero_off = fp->ff_size = inval_end;
0b4e3aa0
A
421 };
422
423 if (uio->uio_offset > zero_off) lflag |= IO_HEADZEROFILL;
424 };
1c79356b 425
0b4e3aa0
A
426 /* Check to see whether the area between the end of the write and the end of
427 the page it falls in is invalid and should be zero-filled as part of the transfer:
428 */
429 tail_off = (writelimit + (PAGE_SIZE_64 - 1)) & ~PAGE_MASK_64;
430 if (tail_off > filesize) tail_off = filesize;
431 if (tail_off > writelimit) {
9bccf70c 432 if (rl_scan(&fp->ff_invalidranges, writelimit, tail_off - 1, &invalid_range) != RL_NOOVERLAP) {
0b4e3aa0
A
433 lflag |= IO_TAILZEROFILL;
434 };
435 };
436
437 /*
438 * if the write starts beyond the current EOF (possibly advanced in the
439 * zeroing of the last block, above), then we'll zero fill from the current EOF
440 * to where the write begins:
441 *
442 * NOTE: If (and ONLY if) the portion of the file about to be written is
443 * before the current EOF it might be marked as invalid now and must be
444 * made readable (removed from the invalid ranges) before cluster_write
445 * tries to write it:
446 */
447 io_start = (lflag & IO_HEADZEROFILL) ? zero_off : uio->uio_offset;
448 io_end = (lflag & IO_TAILZEROFILL) ? tail_off : writelimit;
9bccf70c
A
449 if (io_start < fp->ff_size) {
450 rl_remove(io_start, io_end - 1, &fp->ff_invalidranges);
0b4e3aa0 451 };
9bccf70c
A
452 retval = cluster_write(vp, uio, fp->ff_size, filesize, zero_off,
453 tail_off, devBlockSize, lflag | IO_NOZERODIRTY);
0b4e3aa0 454
9bccf70c
A
455 if (uio->uio_offset > fp->ff_size) {
456 fp->ff_size = uio->uio_offset;
1c79356b 457
9bccf70c 458 ubc_setsize(vp, fp->ff_size); /* XXX check errors */
0b4e3aa0 459 }
9bccf70c
A
460 if (resid > uio->uio_resid)
461 cp->c_flag |= C_CHANGE | C_UPDATE;
9bccf70c 462 }
0b4e3aa0 463
55e303ae
A
464 HFS_KNOTE(vp, NOTE_WRITE);
465
0b4e3aa0 466ioerr_exit:
9bccf70c 467 /*
0b4e3aa0 468 * If we successfully wrote any data, and we are not the superuser
9bccf70c
A
469 * we clear the setuid and setgid bits as a precaution against
470 * tampering.
471 */
472 if (resid > uio->uio_resid && ap->a_cred && ap->a_cred->cr_uid != 0)
473 cp->c_mode &= ~(S_ISUID | S_ISGID);
474
475 if (retval) {
476 if (ioflag & IO_UNIT) {
477 (void)VOP_TRUNCATE(vp, origFileSize,
478 ioflag & IO_SYNC, ap->a_cred, uio->uio_procp);
479 uio->uio_offset -= resid - uio->uio_resid;
480 uio->uio_resid = resid;
481 filebytes = (off_t)fp->ff_blocks * (off_t)vcb->blockSize;
482 }
483 } else if (resid > uio->uio_resid && (ioflag & IO_SYNC)) {
484 tv = time;
485 retval = VOP_UPDATE(vp, &tv, &tv, 1);
486 }
55e303ae 487 vcb->vcbWrCnt++;
1c79356b 488
9bccf70c
A
489 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 0)) | DBG_FUNC_END,
490 (int)uio->uio_offset, uio->uio_resid, (int)fp->ff_size, (int)filebytes, 0);
1c79356b 491
9bccf70c 492 return (retval);
1c79356b
A
493}
494
495
55e303ae
A
496#ifdef HFS_SPARSE_DEV
497struct hfs_backingstoreinfo {
498 int signature; /* == 3419115 */
499 int version; /* version of this struct (1) */
500 int backingfd; /* disk image file (on backing fs) */
501 int bandsize; /* sparse disk image band size */
502};
503
504#define HFSIOC_SETBACKINGSTOREINFO _IOW('h', 7, struct hfs_backingstoreinfo)
505#define HFSIOC_CLRBACKINGSTOREINFO _IO('h', 8)
506
507#define HFS_SETBACKINGSTOREINFO IOCBASECMD(HFSIOC_SETBACKINGSTOREINFO)
508#define HFS_CLRBACKINGSTOREINFO IOCBASECMD(HFSIOC_CLRBACKINGSTOREINFO)
509
510#endif /* HFS_SPARSE_DEV */
511
1c79356b
A
512/*
513
514#% ioctl vp U U U
515#
516 vop_ioctl {
517 IN struct vnode *vp;
518 IN u_long command;
519 IN caddr_t data;
520 IN int fflag;
521 IN struct ucred *cred;
522 IN struct proc *p;
523
524 */
525
526
527/* ARGSUSED */
528int
529hfs_ioctl(ap)
9bccf70c
A
530 struct vop_ioctl_args /* {
531 struct vnode *a_vp;
532 int a_command;
533 caddr_t a_data;
534 int a_fflag;
535 struct ucred *a_cred;
536 struct proc *a_p;
537 } */ *ap;
1c79356b 538{
9bccf70c 539 switch (ap->a_command) {
55e303ae
A
540
541#ifdef HFS_SPARSE_DEV
542 case HFS_SETBACKINGSTOREINFO: {
543 struct hfsmount * hfsmp;
544 struct vnode * bsfs_rootvp;
545 struct vnode * di_vp;
546 struct file * di_fp;
547 struct hfs_backingstoreinfo *bsdata;
548 int error = 0;
549
550 hfsmp = VTOHFS(ap->a_vp);
551 if (hfsmp->hfs_flags & HFS_HAS_SPARSE_DEVICE) {
552 return (EALREADY);
553 }
554 if (ap->a_p->p_ucred->cr_uid != 0 &&
555 ap->a_p->p_ucred->cr_uid != (HFSTOVFS(hfsmp))->mnt_stat.f_owner) {
556 return (EACCES); /* must be owner of file system */
557 }
558 bsdata = (struct hfs_backingstoreinfo *)ap->a_data;
559 if (bsdata == NULL) {
560 return (EINVAL);
561 }
562 if (error = fdgetf(ap->a_p, bsdata->backingfd, &di_fp)) {
563 return (error);
564 }
565 if (fref(di_fp) == -1) {
566 return (EBADF);
567 }
568 if (di_fp->f_type != DTYPE_VNODE) {
569 frele(di_fp);
570 return (EINVAL);
571 }
572 di_vp = (struct vnode *)di_fp->f_data;
573 if (ap->a_vp->v_mount == di_vp->v_mount) {
574 frele(di_fp);
575 return (EINVAL);
576 }
577
578 /*
579 * Obtain the backing fs root vnode and keep a reference
580 * on it. This reference will be dropped in hfs_unmount.
581 */
582 error = VFS_ROOT(di_vp->v_mount, &bsfs_rootvp);
583 if (error) {
584 frele(di_fp);
585 return (error);
586 }
587 VOP_UNLOCK(bsfs_rootvp, 0, ap->a_p); /* Hold on to the reference */
588
589 hfsmp->hfs_backingfs_rootvp = bsfs_rootvp;
590 hfsmp->hfs_flags |= HFS_HAS_SPARSE_DEVICE;
591 hfsmp->hfs_sparsebandblks = bsdata->bandsize / HFSTOVCB(hfsmp)->blockSize;
592 hfsmp->hfs_sparsebandblks *= 4;
593
594 frele(di_fp);
595 return (0);
596 }
597 case HFS_CLRBACKINGSTOREINFO: {
598 struct hfsmount * hfsmp;
599 struct vnode * tmpvp;
600
601 hfsmp = VTOHFS(ap->a_vp);
602 if (ap->a_p->p_ucred->cr_uid != 0 &&
603 ap->a_p->p_ucred->cr_uid != (HFSTOVFS(hfsmp))->mnt_stat.f_owner) {
604 return (EACCES); /* must be owner of file system */
605 }
606 if ((hfsmp->hfs_flags & HFS_HAS_SPARSE_DEVICE) &&
607 hfsmp->hfs_backingfs_rootvp) {
608
609 hfsmp->hfs_flags &= ~HFS_HAS_SPARSE_DEVICE;
610 tmpvp = hfsmp->hfs_backingfs_rootvp;
611 hfsmp->hfs_backingfs_rootvp = NULLVP;
612 hfsmp->hfs_sparsebandblks = 0;
613 vrele(tmpvp);
614 }
615 return (0);
616 }
617#endif /* HFS_SPARSE_DEV */
618
619 case 6: {
620 int error;
621
622 ap->a_vp->v_flag |= VFULLFSYNC;
623 error = VOP_FSYNC(ap->a_vp, ap->a_cred, MNT_NOWAIT, ap->a_p);
624 ap->a_vp->v_flag &= ~VFULLFSYNC;
625
626 return error;
627 }
628 case 5: {
629 register struct vnode *vp;
9bccf70c 630 register struct cnode *cp;
55e303ae
A
631 struct filefork *fp;
632 int error;
633
634 vp = ap->a_vp;
635 cp = VTOC(vp);
636 fp = VTOF(vp);
637
638 if (vp->v_type != VREG)
639 return EINVAL;
640
641 VOP_LEASE(vp, ap->a_p, ap->a_cred, LEASE_READ);
642 error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, ap->a_p);
643 if (error)
644 return (error);
645
646 /*
647 * used by regression test to determine if
648 * all the dirty pages (via write) have been cleaned
649 * after a call to 'fsysnc'.
650 */
651 error = is_file_clean(vp, fp->ff_size);
652 VOP_UNLOCK(vp, 0, ap->a_p);
653
654 return (error);
655 }
656
657 case 1: {
9bccf70c
A
658 register struct vnode *vp;
659 register struct radvisory *ra;
55e303ae 660 register struct cnode *cp;
9bccf70c
A
661 struct filefork *fp;
662 int devBlockSize = 0;
663 int error;
664
665 vp = ap->a_vp;
666
667 if (vp->v_type != VREG)
668 return EINVAL;
669
670 VOP_LEASE(vp, ap->a_p, ap->a_cred, LEASE_READ);
671 error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, ap->a_p);
672 if (error)
673 return (error);
674
675 ra = (struct radvisory *)(ap->a_data);
676 cp = VTOC(vp);
677 fp = VTOF(vp);
678
679 if (ra->ra_offset >= fp->ff_size) {
680 VOP_UNLOCK(vp, 0, ap->a_p);
681 return (EFBIG);
682 }
683 VOP_DEVBLOCKSIZE(cp->c_devvp, &devBlockSize);
1c79356b 684
9bccf70c
A
685 error = advisory_read(vp, fp->ff_size, ra->ra_offset, ra->ra_count, devBlockSize);
686 VOP_UNLOCK(vp, 0, ap->a_p);
1c79356b 687
9bccf70c 688 return (error);
1c79356b 689 }
1c79356b 690
0b4e3aa0
A
691 case 2: /* F_READBOOTBLOCKS */
692 case 3: /* F_WRITEBOOTBLOCKS */
693 {
1c79356b 694 struct vnode *vp = ap->a_vp;
9bccf70c 695 struct vnode *devvp = NULL;
1c79356b 696 struct fbootstraptransfer *btd = (struct fbootstraptransfer *)ap->a_data;
0b4e3aa0 697 int devBlockSize;
1c79356b
A
698 int error;
699 struct iovec aiov;
700 struct uio auio;
701 u_long blockNumber;
702 u_long blockOffset;
703 u_long xfersize;
704 struct buf *bp;
705
0b4e3aa0
A
706 if ((vp->v_flag & VROOT) == 0) return EINVAL;
707 if (btd->fbt_offset + btd->fbt_length > 1024) return EINVAL;
1c79356b 708
9bccf70c 709 devvp = VTOHFS(vp)->hfs_devvp;
1c79356b
A
710 aiov.iov_base = btd->fbt_buffer;
711 aiov.iov_len = btd->fbt_length;
712
713 auio.uio_iov = &aiov;
714 auio.uio_iovcnt = 1;
715 auio.uio_offset = btd->fbt_offset;
716 auio.uio_resid = btd->fbt_length;
717 auio.uio_segflg = UIO_USERSPACE;
718 auio.uio_rw = (ap->a_command == 3) ? UIO_WRITE : UIO_READ; /* F_WRITEBOOTSTRAP / F_READBOOTSTRAP */
719 auio.uio_procp = ap->a_p;
720
9bccf70c 721 VOP_DEVBLOCKSIZE(devvp, &devBlockSize);
1c79356b
A
722
723 while (auio.uio_resid > 0) {
724 blockNumber = auio.uio_offset / devBlockSize;
9bccf70c 725 error = bread(devvp, blockNumber, devBlockSize, ap->a_cred, &bp);
1c79356b 726 if (error) {
0b4e3aa0
A
727 if (bp) brelse(bp);
728 return error;
729 };
1c79356b 730
0b4e3aa0 731 blockOffset = auio.uio_offset % devBlockSize;
1c79356b
A
732 xfersize = devBlockSize - blockOffset;
733 error = uiomove((caddr_t)bp->b_data + blockOffset, (int)xfersize, &auio);
0b4e3aa0
A
734 if (error) {
735 brelse(bp);
736 return error;
737 };
738 if (auio.uio_rw == UIO_WRITE) {
739 error = VOP_BWRITE(bp);
740 if (error) return error;
741 } else {
742 brelse(bp);
743 };
744 };
1c79356b 745 };
0b4e3aa0
A
746 return 0;
747
748 case _IOC(IOC_OUT,'h', 4, 0): /* Create date in local time */
749 {
750 *(time_t *)(ap->a_data) = to_bsd_time(VTOVCB(ap->a_vp)->localCreateDate);
751 return 0;
752 }
1c79356b 753
0b4e3aa0 754 default:
0b4e3aa0 755 return (ENOTTY);
1c79356b
A
756 }
757
0b4e3aa0
A
758 /* Should never get here */
759 return 0;
1c79356b
A
760}
761
762/* ARGSUSED */
763int
764hfs_select(ap)
9bccf70c
A
765 struct vop_select_args /* {
766 struct vnode *a_vp;
767 int a_which;
768 int a_fflags;
769 struct ucred *a_cred;
770 void *a_wql;
771 struct proc *a_p;
772 } */ *ap;
1c79356b 773{
9bccf70c
A
774 /*
775 * We should really check to see if I/O is possible.
776 */
777 return (1);
1c79356b
A
778}
779
1c79356b
A
780/*
781 * Bmap converts a the logical block number of a file to its physical block
782 * number on the disk.
783 */
784
785/*
786 * vp - address of vnode file the file
787 * bn - which logical block to convert to a physical block number.
788 * vpp - returns the vnode for the block special file holding the filesystem
789 * containing the file of interest
790 * bnp - address of where to return the filesystem physical block number
791#% bmap vp L L L
792#% bmap vpp - U -
793#
794 vop_bmap {
795 IN struct vnode *vp;
796 IN daddr_t bn;
797 OUT struct vnode **vpp;
798 IN daddr_t *bnp;
799 OUT int *runp;
800 */
801/*
802 * Converts a logical block number to a physical block, and optionally returns
803 * the amount of remaining blocks in a run. The logical block is based on hfsNode.logBlockSize.
804 * The physical block number is based on the device block size, currently its 512.
805 * The block run is returned in logical blocks, and is the REMAINING amount of blocks
806 */
807
808int
809hfs_bmap(ap)
9bccf70c
A
810 struct vop_bmap_args /* {
811 struct vnode *a_vp;
812 daddr_t a_bn;
813 struct vnode **a_vpp;
814 daddr_t *a_bnp;
815 int *a_runp;
816 } */ *ap;
1c79356b 817{
9bccf70c
A
818 struct vnode *vp = ap->a_vp;
819 struct cnode *cp = VTOC(vp);
820 struct filefork *fp = VTOF(vp);
821 struct hfsmount *hfsmp = VTOHFS(vp);
822 int retval = E_NONE;
1c79356b
A
823 daddr_t logBlockSize;
824 size_t bytesContAvail = 0;
0b4e3aa0 825 off_t blockposition;
1c79356b
A
826 struct proc *p = NULL;
827 int lockExtBtree;
0b4e3aa0
A
828 struct rl_entry *invalid_range;
829 enum rl_overlaptype overlaptype;
1c79356b 830
9bccf70c
A
831 /*
832 * Check for underlying vnode requests and ensure that logical
833 * to physical mapping is requested.
834 */
835 if (ap->a_vpp != NULL)
836 *ap->a_vpp = cp->c_devvp;
837 if (ap->a_bnp == NULL)
838 return (0);
839
840 /* Only clustered I/O should have delayed allocations. */
841 DBG_ASSERT(fp->ff_unallocblocks == 0);
842
843 logBlockSize = GetLogicalBlockSize(vp);
844 blockposition = (off_t)ap->a_bn * (off_t)logBlockSize;
845
846 lockExtBtree = overflow_extents(fp);
847 if (lockExtBtree) {
848 p = current_proc();
849 retval = hfs_metafilelocking(hfsmp, kHFSExtentsFileID,
850 LK_EXCLUSIVE | LK_CANRECURSE, p);
851 if (retval)
852 return (retval);
853 }
1c79356b 854
9bccf70c 855 retval = MacToVFSError(
0b4e3aa0 856 MapFileBlockC (HFSTOVCB(hfsmp),
9bccf70c 857 (FCB*)fp,
0b4e3aa0
A
858 MAXPHYSIO,
859 blockposition,
860 ap->a_bnp,
861 &bytesContAvail));
1c79356b
A
862
863 if (lockExtBtree) (void) hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_RELEASE, p);
864
865 if (retval == E_NONE) {
0b4e3aa0 866 /* Adjust the mapping information for invalid file ranges: */
9bccf70c 867 overlaptype = rl_scan(&fp->ff_invalidranges,
0b4e3aa0
A
868 blockposition,
869 blockposition + MAXPHYSIO - 1,
870 &invalid_range);
871 if (overlaptype != RL_NOOVERLAP) {
872 switch(overlaptype) {
873 case RL_MATCHINGOVERLAP:
874 case RL_OVERLAPCONTAINSRANGE:
875 case RL_OVERLAPSTARTSBEFORE:
876 /* There's no valid block for this byte offset: */
877 *ap->a_bnp = (daddr_t)-1;
878 bytesContAvail = invalid_range->rl_end + 1 - blockposition;
879 break;
880
881 case RL_OVERLAPISCONTAINED:
882 case RL_OVERLAPENDSAFTER:
883 /* The range of interest hits an invalid block before the end: */
884 if (invalid_range->rl_start == blockposition) {
885 /* There's actually no valid information to be had starting here: */
886 *ap->a_bnp = (daddr_t)-1;
9bccf70c 887 if ((fp->ff_size > (invalid_range->rl_end + 1)) &&
0b4e3aa0
A
888 (invalid_range->rl_end + 1 - blockposition < bytesContAvail)) {
889 bytesContAvail = invalid_range->rl_end + 1 - blockposition;
890 };
891 } else {
892 bytesContAvail = invalid_range->rl_start - blockposition;
893 };
894 break;
895 };
896 if (bytesContAvail > MAXPHYSIO) bytesContAvail = MAXPHYSIO;
897 };
898
1c79356b
A
899 /* Figure out how many read ahead blocks there are */
900 if (ap->a_runp != NULL) {
901 if (can_cluster(logBlockSize)) {
902 /* Make sure this result never goes negative: */
903 *ap->a_runp = (bytesContAvail < logBlockSize) ? 0 : (bytesContAvail / logBlockSize) - 1;
904 } else {
905 *ap->a_runp = 0;
906 };
907 };
908 };
909
1c79356b
A
910 return (retval);
911}
912
913/* blktooff converts logical block number to file offset */
914
915int
916hfs_blktooff(ap)
9bccf70c
A
917 struct vop_blktooff_args /* {
918 struct vnode *a_vp;
919 daddr_t a_lblkno;
920 off_t *a_offset;
921 } */ *ap;
1c79356b
A
922{
923 if (ap->a_vp == NULL)
924 return (EINVAL);
925 *ap->a_offset = (off_t)ap->a_lblkno * PAGE_SIZE_64;
926
927 return(0);
928}
929
930int
931hfs_offtoblk(ap)
9bccf70c
A
932 struct vop_offtoblk_args /* {
933 struct vnode *a_vp;
934 off_t a_offset;
935 daddr_t *a_lblkno;
936 } */ *ap;
1c79356b 937{
1c79356b
A
938 if (ap->a_vp == NULL)
939 return (EINVAL);
940 *ap->a_lblkno = ap->a_offset / PAGE_SIZE_64;
941
942 return(0);
943}
944
945int
946hfs_cmap(ap)
9bccf70c
A
947 struct vop_cmap_args /* {
948 struct vnode *a_vp;
949 off_t a_foffset;
950 size_t a_size;
951 daddr_t *a_bpn;
952 size_t *a_run;
953 void *a_poff;
954 } */ *ap;
1c79356b 955{
9bccf70c
A
956 struct hfsmount *hfsmp = VTOHFS(ap->a_vp);
957 struct filefork *fp = VTOF(ap->a_vp);
1c79356b
A
958 size_t bytesContAvail = 0;
959 int retval = E_NONE;
9bccf70c 960 int lockExtBtree = 0;
1c79356b 961 struct proc *p = NULL;
0b4e3aa0
A
962 struct rl_entry *invalid_range;
963 enum rl_overlaptype overlaptype;
b4c24cb9 964 int started_tr = 0, grabbed_lock = 0;
55e303ae 965 struct timeval tv;
1c79356b 966
9bccf70c
A
967 /*
968 * Check for underlying vnode requests and ensure that logical
969 * to physical mapping is requested.
970 */
971 if (ap->a_bpn == NULL)
972 return (0);
973
b4c24cb9 974 p = current_proc();
55e303ae
A
975
976 if (ISSET(VTOC(ap->a_vp)->c_flag, C_NOBLKMAP)) {
977 /*
978 * File blocks are getting remapped. Wait until its finished.
979 */
980 SET(VTOC(ap->a_vp)->c_flag, C_WBLKMAP);
981 (void) tsleep((caddr_t)VTOC(ap->a_vp), PINOD, "hfs_cmap", 0);
982 if (ISSET(VTOC(ap->a_vp)->c_flag, C_NOBLKMAP))
983 panic("hfs_cmap: no mappable blocks");
984 }
985
d12e1678 986 retry:
b4c24cb9 987 if (fp->ff_unallocblocks) {
9bccf70c 988 lockExtBtree = 1;
b4c24cb9
A
989
990 // XXXdbg
991 hfs_global_shared_lock_acquire(hfsmp);
992 grabbed_lock = 1;
993
994 if (hfsmp->jnl) {
995 if (journal_start_transaction(hfsmp->jnl) != 0) {
996 hfs_global_shared_lock_release(hfsmp);
997 return EINVAL;
998 } else {
999 started_tr = 1;
1000 }
1001 }
1002
9bccf70c 1003 if (retval = hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_EXCLUSIVE | LK_CANRECURSE, p)) {
b4c24cb9
A
1004 if (started_tr) {
1005 journal_end_transaction(hfsmp->jnl);
1006 }
1007 if (grabbed_lock) {
1008 hfs_global_shared_lock_release(hfsmp);
1009 }
9bccf70c 1010 return (retval);
b4c24cb9
A
1011 }
1012 } else if (overflow_extents(fp)) {
1013 lockExtBtree = 1;
1014 if (retval = hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_EXCLUSIVE | LK_CANRECURSE, p)) {
1015 return retval;
1016 }
9bccf70c 1017 }
1c79356b 1018
9bccf70c
A
1019 /*
1020 * Check for any delayed allocations.
1021 */
1022 if (fp->ff_unallocblocks) {
1023 SInt64 reqbytes, actbytes;
1c79356b 1024
55e303ae 1025 //
d12e1678
A
1026 // Make sure we have a transaction. It's possible
1027 // that we came in and fp->ff_unallocblocks was zero
1028 // but during the time we blocked acquiring the extents
1029 // btree, ff_unallocblocks became non-zero and so we
1030 // will need to start a transaction.
1031 //
1032 if (hfsmp->jnl && started_tr == 0) {
1033 if (lockExtBtree) {
1034 (void) hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_RELEASE, p);
1035 lockExtBtree = 0;
1036 }
55e303ae 1037
d12e1678
A
1038 goto retry;
1039 }
1040
9bccf70c
A
1041 reqbytes = (SInt64)fp->ff_unallocblocks *
1042 (SInt64)HFSTOVCB(hfsmp)->blockSize;
1043 /*
1044 * Release the blocks on loan and aquire some real ones.
1045 * Note that we can race someone else for these blocks
1046 * (and lose) so cmap needs to handle a failure here.
1047 * Currently this race can't occur because all allocations
1048 * are protected by an exclusive lock on the Extents
1049 * Overflow file.
1050 */
1051 HFSTOVCB(hfsmp)->loanedBlocks -= fp->ff_unallocblocks;
1052 FTOC(fp)->c_blocks -= fp->ff_unallocblocks;
1053 fp->ff_blocks -= fp->ff_unallocblocks;
1054 fp->ff_unallocblocks = 0;
1055
55e303ae
A
1056 /* Files that are changing size are not hot file candidates. */
1057 if (hfsmp->hfc_stage == HFC_RECORDING) {
1058 fp->ff_bytesread = 0;
1059 }
9bccf70c
A
1060 while (retval == 0 && reqbytes > 0) {
1061 retval = MacToVFSError(ExtendFileC(HFSTOVCB(hfsmp),
1062 (FCB*)fp, reqbytes, 0,
1063 kEFAllMask | kEFNoClumpMask, &actbytes));
1064 if (retval == 0 && actbytes == 0)
1065 retval = ENOSPC;
1066
1067 if (retval) {
1068 fp->ff_unallocblocks =
1069 reqbytes / HFSTOVCB(hfsmp)->blockSize;
1070 HFSTOVCB(hfsmp)->loanedBlocks += fp->ff_unallocblocks;
1071 FTOC(fp)->c_blocks += fp->ff_unallocblocks;
1072 fp->ff_blocks += fp->ff_unallocblocks;
1073 }
1074 reqbytes -= actbytes;
1075 }
1c79356b 1076
9bccf70c 1077 if (retval) {
b4c24cb9 1078 (void) hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_RELEASE, p);
55e303ae 1079 VTOC(ap->a_vp)->c_flag |= C_MODIFIED;
b4c24cb9 1080 if (started_tr) {
55e303ae
A
1081 tv = time;
1082 VOP_UPDATE(ap->a_vp, &tv, &tv, 1);
1083
b4c24cb9
A
1084 hfs_flushvolumeheader(hfsmp, MNT_NOWAIT, 0);
1085 journal_end_transaction(hfsmp->jnl);
1086 }
1087 if (grabbed_lock) {
1088 hfs_global_shared_lock_release(hfsmp);
1089 }
1090 return (retval);
1091 }
9bccf70c
A
1092 }
1093
1094 retval = MacToVFSError(
1c79356b 1095 MapFileBlockC (HFSTOVCB(hfsmp),
9bccf70c 1096 (FCB *)fp,
1c79356b
A
1097 ap->a_size,
1098 ap->a_foffset,
1099 ap->a_bpn,
1100 &bytesContAvail));
1101
9bccf70c
A
1102 if (lockExtBtree)
1103 (void) hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_RELEASE, p);
1c79356b 1104
b4c24cb9
A
1105 // XXXdbg
1106 if (started_tr) {
55e303ae
A
1107 tv = time;
1108 retval = VOP_UPDATE(ap->a_vp, &tv, &tv, 1);
1109
b4c24cb9
A
1110 hfs_flushvolumeheader(hfsmp, MNT_NOWAIT, 0);
1111 journal_end_transaction(hfsmp->jnl);
1112 started_tr = 0;
1113 }
1114 if (grabbed_lock) {
1115 hfs_global_shared_lock_release(hfsmp);
1116 grabbed_lock = 0;
1117 }
1118
0b4e3aa0
A
1119 if (retval == E_NONE) {
1120 /* Adjust the mapping information for invalid file ranges: */
9bccf70c 1121 overlaptype = rl_scan(&fp->ff_invalidranges,
0b4e3aa0
A
1122 ap->a_foffset,
1123 ap->a_foffset + (off_t)bytesContAvail - 1,
1124 &invalid_range);
1125 if (overlaptype != RL_NOOVERLAP) {
1126 switch(overlaptype) {
1127 case RL_MATCHINGOVERLAP:
1128 case RL_OVERLAPCONTAINSRANGE:
1129 case RL_OVERLAPSTARTSBEFORE:
1130 /* There's no valid block for this byte offset: */
1131 *ap->a_bpn = (daddr_t)-1;
1132
1133 /* There's no point limiting the amount to be returned if the
1134 invalid range that was hit extends all the way to the EOF
1135 (i.e. there's no valid bytes between the end of this range
1136 and the file's EOF):
1137 */
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 break;
1143
1144 case RL_OVERLAPISCONTAINED:
1145 case RL_OVERLAPENDSAFTER:
1146 /* The range of interest hits an invalid block before the end: */
1147 if (invalid_range->rl_start == ap->a_foffset) {
1148 /* There's actually no valid information to be had starting here: */
1149 *ap->a_bpn = (daddr_t)-1;
9bccf70c 1150 if ((fp->ff_size > (invalid_range->rl_end + 1)) &&
0b4e3aa0
A
1151 (invalid_range->rl_end + 1 - ap->a_foffset < bytesContAvail)) {
1152 bytesContAvail = invalid_range->rl_end + 1 - ap->a_foffset;
1153 };
1154 } else {
1155 bytesContAvail = invalid_range->rl_start - ap->a_foffset;
1156 };
1157 break;
1158 };
1159 if (bytesContAvail > ap->a_size) bytesContAvail = ap->a_size;
1160 };
1161
1162 if (ap->a_run) *ap->a_run = bytesContAvail;
1163 };
1c79356b 1164
9bccf70c
A
1165 if (ap->a_poff)
1166 *(int *)ap->a_poff = 0;
1c79356b 1167
9bccf70c
A
1168 return (retval);
1169}
1c79356b 1170
1c79356b 1171
9bccf70c
A
1172/*
1173 * Read or write a buffer that is not contiguous on disk. We loop over
1174 * each device block, copying to or from caller's buffer.
1175 *
1176 * We could be a bit more efficient by transferring as much data as is
1177 * contiguous. But since this routine should rarely be called, and that
1178 * would be more complicated; best to keep it simple.
1179 */
1180static int
1181hfs_strategy_fragmented(struct buf *bp)
1182{
1183 register struct vnode *vp = bp->b_vp;
1184 register struct cnode *cp = VTOC(vp);
1185 register struct vnode *devvp = cp->c_devvp;
1186 caddr_t ioaddr; /* Address of fragment within bp */
1187 struct buf *frag = NULL; /* For reading or writing a single block */
1188 int retval = 0;
1189 long remaining; /* Bytes (in bp) left to transfer */
1190 off_t offset; /* Logical offset of current fragment in vp */
1191 u_long block_size; /* Size of one device block (and one I/O) */
1192
1193 /* Make sure we redo this mapping for the next I/O */
1194 bp->b_blkno = bp->b_lblkno;
1195
1196 /* Set up the logical position and number of bytes to read/write */
1197 offset = (off_t) bp->b_lblkno * (off_t) GetLogicalBlockSize(vp);
1198 block_size = VTOHFS(vp)->hfs_phys_block_size;
1199
1200 /* Get an empty buffer to do the deblocking */
1201 frag = geteblk(block_size);
1202 if (ISSET(bp->b_flags, B_READ))
1203 SET(frag->b_flags, B_READ);
1204
1205 for (ioaddr = bp->b_data, remaining = bp->b_bcount; remaining != 0;
1206 ioaddr += block_size, offset += block_size,
1207 remaining -= block_size) {
1208 frag->b_resid = frag->b_bcount;
1209 CLR(frag->b_flags, B_DONE);
1210
1211 /* Map the current position to a physical block number */
1212 retval = VOP_CMAP(vp, offset, block_size, &frag->b_lblkno,
1213 NULL, NULL);
1214 if (retval != 0)
1215 break;
1c79356b 1216
9bccf70c
A
1217 /*
1218 * Did we try to read a hole?
1219 * (Should never happen for metadata!)
1220 */
1221 if ((long)frag->b_lblkno == -1) {
1222 bzero(ioaddr, block_size);
1223 continue;
1224 }
1225
1226 /* If writing, copy before I/O */
1227 if (!ISSET(bp->b_flags, B_READ))
1228 bcopy(ioaddr, frag->b_data, block_size);
1229
1230 /* Call the device to do the I/O and wait for it */
1231 frag->b_blkno = frag->b_lblkno;
1232 frag->b_vp = devvp; /* Used to dispatch via VOP_STRATEGY */
1233 frag->b_dev = devvp->v_rdev;
1234 retval = VOP_STRATEGY(frag);
1235 frag->b_vp = NULL;
1236 if (retval != 0)
1237 break;
1238 retval = biowait(frag);
1239 if (retval != 0)
1240 break;
1241
1242 /* If reading, copy after the I/O */
1243 if (ISSET(bp->b_flags, B_READ))
1244 bcopy(frag->b_data, ioaddr, block_size);
1245 }
1246
1247 frag->b_vp = NULL;
b4c24cb9
A
1248 //
1249 // XXXdbg - in the case that this is a meta-data block, it won't affect
1250 // the journal because this bp is for a physical disk block,
1251 // not a logical block that is part of the catalog or extents
1252 // files.
9bccf70c
A
1253 SET(frag->b_flags, B_INVAL);
1254 brelse(frag);
1255
1256 if ((bp->b_error = retval) != 0)
1257 SET(bp->b_flags, B_ERROR);
1258
1259 biodone(bp); /* This I/O is now complete */
1260 return retval;
1c79356b
A
1261}
1262
9bccf70c 1263
1c79356b
A
1264/*
1265 * Calculate the logical to physical mapping if not done already,
1266 * then call the device strategy routine.
1267#
1268#vop_strategy {
1269# IN struct buf *bp;
1270 */
1271int
1272hfs_strategy(ap)
9bccf70c
A
1273 struct vop_strategy_args /* {
1274 struct buf *a_bp;
1275 } */ *ap;
1c79356b 1276{
9bccf70c
A
1277 register struct buf *bp = ap->a_bp;
1278 register struct vnode *vp = bp->b_vp;
1279 register struct cnode *cp = VTOC(vp);
1280 int retval = 0;
1281 off_t offset;
1282 size_t bytes_contig;
1283
1284 if ( !(bp->b_flags & B_VECTORLIST)) {
1285 if (vp->v_type == VBLK || vp->v_type == VCHR)
1286 panic("hfs_strategy: device vnode passed!");
1c79356b 1287
9bccf70c
A
1288 if (bp->b_flags & B_PAGELIST) {
1289 /*
1290 * If we have a page list associated with this bp,
1291 * then go through cluster_bp since it knows how to
1292 * deal with a page request that might span non-
1293 * contiguous physical blocks on the disk...
1294 */
1295 retval = cluster_bp(bp);
1296 vp = cp->c_devvp;
1297 bp->b_dev = vp->v_rdev;
1c79356b 1298
9bccf70c
A
1299 return (retval);
1300 }
1301
1302 /*
1303 * If we don't already know the filesystem relative block
1304 * number then get it using VOP_BMAP(). If VOP_BMAP()
1305 * returns the block number as -1 then we've got a hole in
1306 * the file. Although HFS filesystems don't create files with
1307 * holes, invalidating of subranges of the file (lazy zero
1308 * filling) may create such a situation.
1309 */
1310 if (bp->b_blkno == bp->b_lblkno) {
1311 offset = (off_t) bp->b_lblkno *
1312 (off_t) GetLogicalBlockSize(vp);
1313
1314 if ((retval = VOP_CMAP(vp, offset, bp->b_bcount,
1315 &bp->b_blkno, &bytes_contig, NULL))) {
1316 bp->b_error = retval;
1317 bp->b_flags |= B_ERROR;
1318 biodone(bp);
1319 return (retval);
1320 }
1321 if (bytes_contig < bp->b_bcount)
1322 {
1323 /*
1324 * We were asked to read a block that wasn't
1325 * contiguous, so we have to read each of the
1326 * pieces and copy them into the buffer.
1327 * Since ordinary file I/O goes through
1328 * cluster_io (which won't ask us for
1329 * discontiguous data), this is probably an
1330 * attempt to read or write metadata.
1331 */
1332 return hfs_strategy_fragmented(bp);
1333 }
1334 if ((long)bp->b_blkno == -1)
1335 clrbuf(bp);
1336 }
1337 if ((long)bp->b_blkno == -1) {
1338 biodone(bp);
1339 return (0);
1340 }
1341 if (bp->b_validend == 0) {
1342 /*
1343 * Record the exact size of the I/O transfer about to
1344 * be made:
1345 */
1346 bp->b_validend = bp->b_bcount;
1347 }
1c79356b 1348 }
9bccf70c
A
1349 vp = cp->c_devvp;
1350 bp->b_dev = vp->v_rdev;
1c79356b 1351
9bccf70c 1352 return VOCALL (vp->v_op, VOFFSET(vop_strategy), ap);
1c79356b
A
1353}
1354
1355
55e303ae 1356static int do_hfs_truncate(ap)
9bccf70c
A
1357 struct vop_truncate_args /* {
1358 struct vnode *a_vp;
1359 off_t a_length;
1360 int a_flags;
1361 struct ucred *a_cred;
1362 struct proc *a_p;
1363 } */ *ap;
1c79356b 1364{
9bccf70c
A
1365 register struct vnode *vp = ap->a_vp;
1366 register struct cnode *cp = VTOC(vp);
1367 struct filefork *fp = VTOF(vp);
1368 off_t length;
1369 long vflags;
1370 struct timeval tv;
1371 int retval;
1372 off_t bytesToAdd;
1373 off_t actualBytesAdded;
1374 off_t filebytes;
1375 u_long fileblocks;
1376 int blksize;
b4c24cb9 1377 struct hfsmount *hfsmp;
9bccf70c
A
1378
1379 if (vp->v_type != VREG && vp->v_type != VLNK)
1380 return (EISDIR); /* cannot truncate an HFS directory! */
1381
1382 length = ap->a_length;
1383 blksize = VTOVCB(vp)->blockSize;
1384 fileblocks = fp->ff_blocks;
1385 filebytes = (off_t)fileblocks * (off_t)blksize;
1386
1387 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 7)) | DBG_FUNC_START,
1388 (int)length, (int)fp->ff_size, (int)filebytes, 0, 0);
1389
1390 if (length < 0)
1391 return (EINVAL);
1c79356b 1392
9bccf70c
A
1393 if ((!ISHFSPLUS(VTOVCB(vp))) && (length > (off_t)MAXHFSFILESIZE))
1394 return (EFBIG);
1c79356b 1395
b4c24cb9 1396 hfsmp = VTOHFS(vp);
1c79356b 1397
9bccf70c
A
1398 tv = time;
1399 retval = E_NONE;
1c79356b 1400
55e303ae
A
1401 /* Files that are changing size are not hot file candidates. */
1402 if (hfsmp->hfc_stage == HFC_RECORDING) {
1403 fp->ff_bytesread = 0;
1404 }
1405
9bccf70c
A
1406 /*
1407 * We cannot just check if fp->ff_size == length (as an optimization)
1408 * since there may be extra physical blocks that also need truncation.
1409 */
1410#if QUOTA
1411 if (retval = hfs_getinoquota(cp))
1412 return(retval);
1413#endif /* QUOTA */
1c79356b 1414
9bccf70c
A
1415 /*
1416 * Lengthen the size of the file. We must ensure that the
1417 * last byte of the file is allocated. Since the smallest
1418 * value of ff_size is 0, length will be at least 1.
1419 */
1420 if (length > fp->ff_size) {
1421#if QUOTA
b4c24cb9 1422 retval = hfs_chkdq(cp, (int64_t)(roundup(length - filebytes, blksize)),
9bccf70c
A
1423 ap->a_cred, 0);
1424 if (retval)
1425 goto Err_Exit;
1426#endif /* QUOTA */
1427 /*
1428 * If we don't have enough physical space then
1429 * we need to extend the physical size.
1430 */
1431 if (length > filebytes) {
1432 int eflags;
55e303ae 1433 u_long blockHint = 0;
1c79356b 1434
9bccf70c
A
1435 /* All or nothing and don't round up to clumpsize. */
1436 eflags = kEFAllMask | kEFNoClumpMask;
1c79356b 1437
55e303ae 1438 if (ap->a_cred && suser(ap->a_cred, NULL) != 0)
9bccf70c 1439 eflags |= kEFReserveMask; /* keep a reserve */
1c79356b 1440
55e303ae
A
1441 /*
1442 * Allocate Journal and Quota files in metadata zone.
1443 */
1444 if (filebytes == 0 &&
1445 hfsmp->hfs_flags & HFS_METADATA_ZONE &&
1446 hfs_virtualmetafile(cp)) {
1447 eflags |= kEFMetadataMask;
1448 blockHint = hfsmp->hfs_metazone_start;
1449 }
b4c24cb9
A
1450 // XXXdbg
1451 hfs_global_shared_lock_acquire(hfsmp);
1452 if (hfsmp->jnl) {
1453 if (journal_start_transaction(hfsmp->jnl) != 0) {
1454 retval = EINVAL;
1455 goto Err_Exit;
1456 }
1457 }
1458
9bccf70c
A
1459 /* lock extents b-tree (also protects volume bitmap) */
1460 retval = hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_EXCLUSIVE, ap->a_p);
b4c24cb9
A
1461 if (retval) {
1462 if (hfsmp->jnl) {
1463 journal_end_transaction(hfsmp->jnl);
1464 }
1465 hfs_global_shared_lock_release(hfsmp);
1466
9bccf70c 1467 goto Err_Exit;
b4c24cb9 1468 }
1c79356b 1469
9bccf70c
A
1470 while ((length > filebytes) && (retval == E_NONE)) {
1471 bytesToAdd = length - filebytes;
1472 retval = MacToVFSError(ExtendFileC(VTOVCB(vp),
1473 (FCB*)fp,
1c79356b 1474 bytesToAdd,
55e303ae 1475 blockHint,
9bccf70c 1476 eflags,
1c79356b
A
1477 &actualBytesAdded));
1478
9bccf70c
A
1479 filebytes = (off_t)fp->ff_blocks * (off_t)blksize;
1480 if (actualBytesAdded == 0 && retval == E_NONE) {
1481 if (length > filebytes)
1482 length = filebytes;
1483 break;
1484 }
1485 } /* endwhile */
b4c24cb9 1486
9bccf70c 1487 (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_RELEASE, ap->a_p);
b4c24cb9
A
1488
1489 // XXXdbg
1490 if (hfsmp->jnl) {
55e303ae
A
1491 tv = time;
1492 VOP_UPDATE(vp, &tv, &tv, 1);
1493
b4c24cb9
A
1494 hfs_flushvolumeheader(hfsmp, MNT_NOWAIT, 0);
1495 journal_end_transaction(hfsmp->jnl);
1496 }
1497 hfs_global_shared_lock_release(hfsmp);
1498
9bccf70c
A
1499 if (retval)
1500 goto Err_Exit;
1501
1502 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 7)) | DBG_FUNC_NONE,
1503 (int)length, (int)fp->ff_size, (int)filebytes, 0, 0);
1c79356b 1504 }
1c79356b 1505
9bccf70c
A
1506 if (!(ap->a_flags & IO_NOZEROFILL)) {
1507 if (UBCINFOEXISTS(vp) && retval == E_NONE) {
1508 struct rl_entry *invalid_range;
1509 int devBlockSize;
1510 off_t zero_limit;
0b4e3aa0 1511
9bccf70c
A
1512 zero_limit = (fp->ff_size + (PAGE_SIZE_64 - 1)) & ~PAGE_MASK_64;
1513 if (length < zero_limit) zero_limit = length;
1514
1515 if (length > fp->ff_size) {
1516 /* Extending the file: time to fill out the current last page w. zeroes? */
1517 if ((fp->ff_size & PAGE_MASK_64) &&
1518 (rl_scan(&fp->ff_invalidranges, fp->ff_size & ~PAGE_MASK_64,
1519 fp->ff_size - 1, &invalid_range) == RL_NOOVERLAP)) {
0b4e3aa0
A
1520
1521 /* There's some valid data at the start of the (current) last page
1522 of the file, so zero out the remainder of that page to ensure the
1523 entire page contains valid data. Since there is no invalid range
1524 possible past the (current) eof, there's no need to remove anything
1525 from the invalid range list before calling cluster_write(): */
9bccf70c
A
1526 VOP_DEVBLOCKSIZE(cp->c_devvp, &devBlockSize);
1527 retval = cluster_write(vp, (struct uio *) 0, fp->ff_size, zero_limit,
1528 fp->ff_size, (off_t)0, devBlockSize,
1529 (ap->a_flags & IO_SYNC) | IO_HEADZEROFILL | IO_NOZERODIRTY);
0b4e3aa0
A
1530 if (retval) goto Err_Exit;
1531
1532 /* Merely invalidate the remaining area, if necessary: */
9bccf70c
A
1533 if (length > zero_limit) {
1534 rl_add(zero_limit, length - 1, &fp->ff_invalidranges);
1535 cp->c_zftimeout = time.tv_sec + ZFTIMELIMIT;
1536 }
1537 } else {
0b4e3aa0
A
1538 /* The page containing the (current) eof is invalid: just add the
1539 remainder of the page to the invalid list, along with the area
1540 being newly allocated:
1541 */
9bccf70c
A
1542 rl_add(fp->ff_size, length - 1, &fp->ff_invalidranges);
1543 cp->c_zftimeout = time.tv_sec + ZFTIMELIMIT;
1544 };
1545 }
1546 } else {
1547 panic("hfs_truncate: invoked on non-UBC object?!");
1548 };
1549 }
1550 cp->c_flag |= C_UPDATE;
1551 fp->ff_size = length;
0b4e3aa0 1552
9bccf70c
A
1553 if (UBCISVALID(vp))
1554 ubc_setsize(vp, fp->ff_size); /* XXX check errors */
0b4e3aa0 1555
9bccf70c 1556 } else { /* Shorten the size of the file */
0b4e3aa0 1557
9bccf70c
A
1558 if (fp->ff_size > length) {
1559 /*
1560 * Any buffers that are past the truncation point need to be
1561 * invalidated (to maintain buffer cache consistency). For
1562 * simplicity, we invalidate all the buffers by calling vinvalbuf.
1563 */
1564 if (UBCISVALID(vp))
1565 ubc_setsize(vp, length); /* XXX check errors */
0b4e3aa0 1566
9bccf70c
A
1567 vflags = ((length > 0) ? V_SAVE : 0) | V_SAVEMETA;
1568 retval = vinvalbuf(vp, vflags, ap->a_cred, ap->a_p, 0, 0);
1569
1570 /* Any space previously marked as invalid is now irrelevant: */
1571 rl_remove(length, fp->ff_size - 1, &fp->ff_invalidranges);
1572 }
1c79356b 1573
9bccf70c
A
1574 /*
1575 * Account for any unmapped blocks. Note that the new
1576 * file length can still end up with unmapped blocks.
1577 */
1578 if (fp->ff_unallocblocks > 0) {
1579 u_int32_t finalblks;
1c79356b 1580
9bccf70c
A
1581 /* lock extents b-tree */
1582 retval = hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID,
1583 LK_EXCLUSIVE, ap->a_p);
1584 if (retval)
1585 goto Err_Exit;
1c79356b 1586
9bccf70c
A
1587 VTOVCB(vp)->loanedBlocks -= fp->ff_unallocblocks;
1588 cp->c_blocks -= fp->ff_unallocblocks;
1589 fp->ff_blocks -= fp->ff_unallocblocks;
1590 fp->ff_unallocblocks = 0;
1591
1592 finalblks = (length + blksize - 1) / blksize;
1593 if (finalblks > fp->ff_blocks) {
1594 /* calculate required unmapped blocks */
1595 fp->ff_unallocblocks = finalblks - fp->ff_blocks;
1596 VTOVCB(vp)->loanedBlocks += fp->ff_unallocblocks;
1597 cp->c_blocks += fp->ff_unallocblocks;
1598 fp->ff_blocks += fp->ff_unallocblocks;
1599 }
1600 (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID,
1601 LK_RELEASE, ap->a_p);
1602 }
1c79356b 1603
9bccf70c
A
1604 /*
1605 * For a TBE process the deallocation of the file blocks is
1606 * delayed until the file is closed. And hfs_close calls
1607 * truncate with the IO_NDELAY flag set. So when IO_NDELAY
1608 * isn't set, we make sure this isn't a TBE process.
1609 */
1610 if ((ap->a_flags & IO_NDELAY) || (!ISSET(ap->a_p->p_flag, P_TBE))) {
1611#if QUOTA
1612 off_t savedbytes = ((off_t)fp->ff_blocks * (off_t)blksize);
1613#endif /* QUOTA */
b4c24cb9
A
1614 // XXXdbg
1615 hfs_global_shared_lock_acquire(hfsmp);
1616 if (hfsmp->jnl) {
1617 if (journal_start_transaction(hfsmp->jnl) != 0) {
1618 retval = EINVAL;
1619 goto Err_Exit;
1620 }
1621 }
1622
9bccf70c
A
1623 /* lock extents b-tree (also protects volume bitmap) */
1624 retval = hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_EXCLUSIVE, ap->a_p);
b4c24cb9
A
1625 if (retval) {
1626 if (hfsmp->jnl) {
1627 journal_end_transaction(hfsmp->jnl);
1628 }
1629 hfs_global_shared_lock_release(hfsmp);
9bccf70c 1630 goto Err_Exit;
b4c24cb9 1631 }
9bccf70c
A
1632
1633 if (fp->ff_unallocblocks == 0)
1634 retval = MacToVFSError(TruncateFileC(VTOVCB(vp),
1635 (FCB*)fp, length, false));
1c79356b 1636
9bccf70c 1637 (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_RELEASE, ap->a_p);
b4c24cb9
A
1638
1639 // XXXdbg
1640 if (hfsmp->jnl) {
55e303ae
A
1641 tv = time;
1642 VOP_UPDATE(vp, &tv, &tv, 1);
1643
b4c24cb9
A
1644 hfs_flushvolumeheader(hfsmp, MNT_NOWAIT, 0);
1645 journal_end_transaction(hfsmp->jnl);
1646 }
1647 hfs_global_shared_lock_release(hfsmp);
1648
9bccf70c
A
1649 filebytes = (off_t)fp->ff_blocks * (off_t)blksize;
1650 if (retval)
1651 goto Err_Exit;
1652#if QUOTA
1653 /* These are bytesreleased */
1654 (void) hfs_chkdq(cp, (int64_t)-(savedbytes - filebytes), NOCRED, 0);
1655#endif /* QUOTA */
1656 }
1657 /* Only set update flag if the logical length changes */
1658 if (fp->ff_size != length)
1659 cp->c_flag |= C_UPDATE;
1660 fp->ff_size = length;
1c79356b 1661 }
9bccf70c
A
1662 cp->c_flag |= C_CHANGE;
1663 retval = VOP_UPDATE(vp, &tv, &tv, MNT_WAIT);
1664 if (retval) {
0b4e3aa0 1665 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 7)) | DBG_FUNC_NONE,
1c79356b 1666 -1, -1, -1, retval, 0);
9bccf70c 1667 }
1c79356b 1668
9bccf70c 1669Err_Exit:
1c79356b 1670
9bccf70c
A
1671 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 7)) | DBG_FUNC_END,
1672 (int)length, (int)fp->ff_size, (int)filebytes, retval, 0);
1c79356b 1673
9bccf70c 1674 return (retval);
1c79356b
A
1675}
1676
1677
55e303ae
A
1678/*
1679#
1680#% truncate vp L L L
1681#
1682vop_truncate {
1683 IN struct vnode *vp;
1684 IN off_t length;
1685 IN int flags; (IO_SYNC)
1686 IN struct ucred *cred;
1687 IN struct proc *p;
1688};
1689 * Truncate a cnode to at most length size, freeing (or adding) the
1690 * disk blocks.
1691 */
1692int hfs_truncate(ap)
1693 struct vop_truncate_args /* {
1694 struct vnode *a_vp;
1695 off_t a_length;
1696 int a_flags;
1697 struct ucred *a_cred;
1698 struct proc *a_p;
1699 } */ *ap;
1700{
1701 register struct vnode *vp = ap->a_vp;
1702 register struct cnode *cp = VTOC(vp);
1703 struct filefork *fp = VTOF(vp);
1704 off_t length;
1705 off_t filebytes;
1706 u_long fileblocks;
1707 int blksize, error;
1708 u_int64_t nsize;
1709
1710 if (vp->v_type != VREG && vp->v_type != VLNK)
1711 return (EISDIR); /* cannot truncate an HFS directory! */
1712
1713 length = ap->a_length;
1714 blksize = VTOVCB(vp)->blockSize;
1715 fileblocks = fp->ff_blocks;
1716 filebytes = (off_t)fileblocks * (off_t)blksize;
1717
1718 // have to loop truncating or growing files that are
1719 // really big because otherwise transactions can get
1720 // enormous and consume too many kernel resources.
1721 if (length < filebytes && (filebytes - length) > HFS_BIGFILE_SIZE) {
1722 while (filebytes > length) {
1723 if ((filebytes - length) > HFS_BIGFILE_SIZE) {
1724 filebytes -= HFS_BIGFILE_SIZE;
1725 } else {
1726 filebytes = length;
1727 }
1728
1729 ap->a_length = filebytes;
1730 error = do_hfs_truncate(ap);
1731 if (error)
1732 break;
1733 }
1734 } else if (length > filebytes && (length - filebytes) > HFS_BIGFILE_SIZE) {
1735 while (filebytes < length) {
1736 if ((length - filebytes) > HFS_BIGFILE_SIZE) {
1737 filebytes += HFS_BIGFILE_SIZE;
1738 } else {
1739 filebytes = (length - filebytes);
1740 }
1741
1742 ap->a_length = filebytes;
1743 error = do_hfs_truncate(ap);
1744 if (error)
1745 break;
1746 }
1747 } else {
1748 error = do_hfs_truncate(ap);
1749 }
1750
1751 return error;
1752}
1753
1754
1c79356b
A
1755
1756/*
1757#
1758#% allocate vp L L L
1759#
1760vop_allocate {
0b4e3aa0
A
1761 IN struct vnode *vp;
1762 IN off_t length;
1763 IN int flags;
1764 OUT off_t *bytesallocated;
1765 IN off_t offset;
1766 IN struct ucred *cred;
1767 IN struct proc *p;
1c79356b 1768};
9bccf70c 1769 * allocate a cnode to at most length size
1c79356b
A
1770 */
1771int hfs_allocate(ap)
9bccf70c
A
1772 struct vop_allocate_args /* {
1773 struct vnode *a_vp;
1774 off_t a_length;
1775 u_int32_t a_flags;
1776 off_t *a_bytesallocated;
1777 off_t a_offset;
1778 struct ucred *a_cred;
1779 struct proc *a_p;
1780 } */ *ap;
1c79356b 1781{
9bccf70c
A
1782 struct vnode *vp = ap->a_vp;
1783 struct cnode *cp = VTOC(vp);
1784 struct filefork *fp = VTOF(vp);
55e303ae 1785 ExtendedVCB *vcb = VTOVCB(vp);
9bccf70c
A
1786 off_t length = ap->a_length;
1787 off_t startingPEOF;
1788 off_t moreBytesRequested;
1789 off_t actualBytesAdded;
1790 off_t filebytes;
1791 u_long fileblocks;
1792 long vflags;
1793 struct timeval tv;
1794 int retval, retval2;
1795 UInt32 blockHint;
55e303ae 1796 UInt32 extendFlags; /* For call to ExtendFileC */
b4c24cb9
A
1797 struct hfsmount *hfsmp;
1798
1799 hfsmp = VTOHFS(vp);
9bccf70c
A
1800
1801 *(ap->a_bytesallocated) = 0;
1802 fileblocks = fp->ff_blocks;
55e303ae 1803 filebytes = (off_t)fileblocks * (off_t)vcb->blockSize;
9bccf70c
A
1804
1805 if (length < (off_t)0)
1806 return (EINVAL);
55e303ae 1807 if (vp->v_type != VREG)
9bccf70c 1808 return (EISDIR);
55e303ae 1809 if ((ap->a_flags & ALLOCATEFROMVOL) && (length < filebytes))
9bccf70c 1810 return (EINVAL);
0b4e3aa0 1811
9bccf70c 1812 /* Fill in the flags word for the call to Extend the file */
1c79356b 1813
55e303ae 1814 extendFlags = kEFNoClumpMask;
9bccf70c 1815 if (ap->a_flags & ALLOCATECONTIG)
1c79356b 1816 extendFlags |= kEFContigMask;
9bccf70c 1817 if (ap->a_flags & ALLOCATEALL)
1c79356b 1818 extendFlags |= kEFAllMask;
55e303ae 1819 if (ap->a_cred && suser(ap->a_cred, NULL) != 0)
9bccf70c 1820 extendFlags |= kEFReserveMask;
1c79356b 1821
9bccf70c
A
1822 tv = time;
1823 retval = E_NONE;
1824 blockHint = 0;
1825 startingPEOF = filebytes;
1c79356b 1826
9bccf70c
A
1827 if (ap->a_flags & ALLOCATEFROMPEOF)
1828 length += filebytes;
1829 else if (ap->a_flags & ALLOCATEFROMVOL)
1830 blockHint = ap->a_offset / VTOVCB(vp)->blockSize;
1c79356b 1831
9bccf70c
A
1832 /* If no changes are necesary, then we're done */
1833 if (filebytes == length)
1834 goto Std_Exit;
1c79356b 1835
9bccf70c
A
1836 /*
1837 * Lengthen the size of the file. We must ensure that the
1838 * last byte of the file is allocated. Since the smallest
1839 * value of filebytes is 0, length will be at least 1.
1840 */
1841 if (length > filebytes) {
1842 moreBytesRequested = length - filebytes;
1c79356b 1843
9bccf70c 1844#if QUOTA
b4c24cb9 1845 retval = hfs_chkdq(cp,
55e303ae 1846 (int64_t)(roundup(moreBytesRequested, vcb->blockSize)),
9bccf70c
A
1847 ap->a_cred, 0);
1848 if (retval)
1849 return (retval);
1850
1851#endif /* QUOTA */
55e303ae
A
1852 /*
1853 * Metadata zone checks.
1854 */
1855 if (hfsmp->hfs_flags & HFS_METADATA_ZONE) {
1856 /*
1857 * Allocate Journal and Quota files in metadata zone.
1858 */
1859 if (hfs_virtualmetafile(cp)) {
1860 extendFlags |= kEFMetadataMask;
1861 blockHint = hfsmp->hfs_metazone_start;
1862 } else if ((blockHint >= hfsmp->hfs_metazone_start) &&
1863 (blockHint <= hfsmp->hfs_metazone_end)) {
1864 /*
1865 * Move blockHint outside metadata zone.
1866 */
1867 blockHint = hfsmp->hfs_metazone_end + 1;
1868 }
1869 }
1870
b4c24cb9
A
1871 // XXXdbg
1872 hfs_global_shared_lock_acquire(hfsmp);
1873 if (hfsmp->jnl) {
1874 if (journal_start_transaction(hfsmp->jnl) != 0) {
1875 retval = EINVAL;
1876 goto Err_Exit;
1877 }
1878 }
1879
1c79356b 1880 /* lock extents b-tree (also protects volume bitmap) */
9bccf70c 1881 retval = hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_EXCLUSIVE, ap->a_p);
b4c24cb9
A
1882 if (retval) {
1883 if (hfsmp->jnl) {
1884 journal_end_transaction(hfsmp->jnl);
1885 }
1886 hfs_global_shared_lock_release(hfsmp);
1887 goto Err_Exit;
1888 }
1c79356b 1889
55e303ae 1890 retval = MacToVFSError(ExtendFileC(vcb,
9bccf70c
A
1891 (FCB*)fp,
1892 moreBytesRequested,
1893 blockHint,
1894 extendFlags,
1895 &actualBytesAdded));
1c79356b
A
1896
1897 *(ap->a_bytesallocated) = actualBytesAdded;
55e303ae 1898 filebytes = (off_t)fp->ff_blocks * (off_t)vcb->blockSize;
b4c24cb9 1899
9bccf70c 1900 (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_RELEASE, ap->a_p);
1c79356b 1901
b4c24cb9
A
1902 // XXXdbg
1903 if (hfsmp->jnl) {
55e303ae
A
1904 tv = time;
1905 VOP_UPDATE(vp, &tv, &tv, 1);
1906
b4c24cb9
A
1907 hfs_flushvolumeheader(hfsmp, MNT_NOWAIT, 0);
1908 journal_end_transaction(hfsmp->jnl);
1909 }
1910 hfs_global_shared_lock_release(hfsmp);
1911
1c79356b
A
1912 /*
1913 * if we get an error and no changes were made then exit
1914 * otherwise we must do the VOP_UPDATE to reflect the changes
1915 */
9bccf70c
A
1916 if (retval && (startingPEOF == filebytes))
1917 goto Err_Exit;
1c79356b 1918
9bccf70c
A
1919 /*
1920 * Adjust actualBytesAdded to be allocation block aligned, not
1921 * clump size aligned.
1922 * NOTE: So what we are reporting does not affect reality
1923 * until the file is closed, when we truncate the file to allocation
1924 * block size.
1925 */
0b4e3aa0
A
1926 if ((actualBytesAdded != 0) && (moreBytesRequested < actualBytesAdded))
1927 *(ap->a_bytesallocated) =
55e303ae 1928 roundup(moreBytesRequested, (off_t)vcb->blockSize);
1c79356b 1929
9bccf70c 1930 } else { /* Shorten the size of the file */
1c79356b 1931
9bccf70c 1932 if (fp->ff_size > length) {
1c79356b
A
1933 /*
1934 * Any buffers that are past the truncation point need to be
1935 * invalidated (to maintain buffer cache consistency). For
1936 * simplicity, we invalidate all the buffers by calling vinvalbuf.
1937 */
1938 vflags = ((length > 0) ? V_SAVE : 0) | V_SAVEMETA;
1939 (void) vinvalbuf(vp, vflags, ap->a_cred, ap->a_p, 0, 0);
1940 }
1941
b4c24cb9
A
1942 // XXXdbg
1943 hfs_global_shared_lock_acquire(hfsmp);
1944 if (hfsmp->jnl) {
1945 if (journal_start_transaction(hfsmp->jnl) != 0) {
1946 retval = EINVAL;
1947 goto Err_Exit;
1948 }
1949 }
1950
9bccf70c
A
1951 /* lock extents b-tree (also protects volume bitmap) */
1952 retval = hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_EXCLUSIVE, ap->a_p);
b4c24cb9
A
1953 if (retval) {
1954 if (hfsmp->jnl) {
1955 journal_end_transaction(hfsmp->jnl);
1956 }
1957 hfs_global_shared_lock_release(hfsmp);
1958
1959 goto Err_Exit;
1960 }
1c79356b 1961
9bccf70c 1962 retval = MacToVFSError(
1c79356b 1963 TruncateFileC(
55e303ae 1964 vcb,
9bccf70c 1965 (FCB*)fp,
1c79356b
A
1966 length,
1967 false));
9bccf70c 1968 (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_RELEASE, ap->a_p);
55e303ae 1969 filebytes = (off_t)fp->ff_blocks * (off_t)vcb->blockSize;
b4c24cb9
A
1970
1971 if (hfsmp->jnl) {
55e303ae
A
1972 tv = time;
1973 VOP_UPDATE(vp, &tv, &tv, 1);
1974
b4c24cb9
A
1975 hfs_flushvolumeheader(hfsmp, MNT_NOWAIT, 0);
1976 journal_end_transaction(hfsmp->jnl);
1977 }
1978 hfs_global_shared_lock_release(hfsmp);
1979
1980
1c79356b
A
1981 /*
1982 * if we get an error and no changes were made then exit
1983 * otherwise we must do the VOP_UPDATE to reflect the changes
1984 */
9bccf70c
A
1985 if (retval && (startingPEOF == filebytes)) goto Err_Exit;
1986#if QUOTA
1987 /* These are bytesreleased */
1988 (void) hfs_chkdq(cp, (int64_t)-((startingPEOF - filebytes)), NOCRED,0);
1989#endif /* QUOTA */
1c79356b 1990
9bccf70c
A
1991 if (fp->ff_size > filebytes) {
1992 fp->ff_size = filebytes;
1c79356b
A
1993
1994 if (UBCISVALID(vp))
9bccf70c
A
1995 ubc_setsize(vp, fp->ff_size); /* XXX check errors */
1996 }
1997 }
1c79356b
A
1998
1999Std_Exit:
9bccf70c 2000 cp->c_flag |= C_CHANGE | C_UPDATE;
1c79356b
A
2001 retval2 = VOP_UPDATE(vp, &tv, &tv, MNT_WAIT);
2002
9bccf70c
A
2003 if (retval == 0)
2004 retval = retval2;
1c79356b 2005Err_Exit:
9bccf70c 2006 return (retval);
1c79356b
A
2007}
2008
2009
9bccf70c
A
2010/*
2011 * pagein for HFS filesystem
2012 */
1c79356b
A
2013int
2014hfs_pagein(ap)
2015 struct vop_pagein_args /* {
2016 struct vnode *a_vp,
2017 upl_t a_pl,
2018 vm_offset_t a_pl_offset,
2019 off_t a_f_offset,
2020 size_t a_size,
2021 struct ucred *a_cred,
2022 int a_flags
2023 } */ *ap;
2024{
9bccf70c
A
2025 register struct vnode *vp = ap->a_vp;
2026 int devBlockSize = 0;
2027 int error;
1c79356b 2028
55e303ae 2029 if (vp->v_type != VREG)
9bccf70c 2030 panic("hfs_pagein: vp not UBC type\n");
1c79356b 2031
9bccf70c 2032 VOP_DEVBLOCKSIZE(VTOC(vp)->c_devvp, &devBlockSize);
1c79356b 2033
9bccf70c
A
2034 error = cluster_pagein(vp, ap->a_pl, ap->a_pl_offset, ap->a_f_offset,
2035 ap->a_size, (off_t)VTOF(vp)->ff_size, devBlockSize,
2036 ap->a_flags);
55e303ae
A
2037 /*
2038 * Keep track blocks read
2039 */
2040 if (VTOHFS(vp)->hfc_stage == HFC_RECORDING && error == 0) {
2041 struct cnode *cp;
2042
2043 cp = VTOC(vp);
2044 /*
2045 * If this file hasn't been seen since the start of
2046 * the current sampling period then start over.
2047 */
2048 if (cp->c_atime < VTOHFS(vp)->hfc_timebase)
2049 VTOF(vp)->ff_bytesread = ap->a_size;
2050 else
2051 VTOF(vp)->ff_bytesread += ap->a_size;
2052
2053 cp->c_flag |= C_ACCESS;
2054 }
2055
9bccf70c 2056 return (error);
1c79356b
A
2057}
2058
2059/*
2060 * pageout for HFS filesystem.
2061 */
2062int
2063hfs_pageout(ap)
2064 struct vop_pageout_args /* {
2065 struct vnode *a_vp,
2066 upl_t a_pl,
2067 vm_offset_t a_pl_offset,
2068 off_t a_f_offset,
2069 size_t a_size,
2070 struct ucred *a_cred,
2071 int a_flags
2072 } */ *ap;
2073{
9bccf70c
A
2074 struct vnode *vp = ap->a_vp;
2075 struct cnode *cp = VTOC(vp);
2076 struct filefork *fp = VTOF(vp);
2077 int retval;
2078 int devBlockSize = 0;
2079 off_t end_of_range;
2080 off_t filesize;
1c79356b
A
2081
2082 if (UBCINVALID(vp))
2083 panic("hfs_pageout: Not a VREG: vp=%x", vp);
2084
9bccf70c
A
2085 VOP_DEVBLOCKSIZE(cp->c_devvp, &devBlockSize);
2086 filesize = fp->ff_size;
0b4e3aa0
A
2087 end_of_range = ap->a_f_offset + ap->a_size - 1;
2088
55e303ae
A
2089 if (cp->c_flag & C_RELOCATING) {
2090 if (end_of_range < (filesize / 2)) {
2091 return (EBUSY);
2092 }
2093 }
2094
9bccf70c
A
2095 if (end_of_range >= filesize)
2096 end_of_range = (off_t)(filesize - 1);
55e303ae 2097 if (ap->a_f_offset < filesize) {
9bccf70c 2098 rl_remove(ap->a_f_offset, end_of_range, &fp->ff_invalidranges);
55e303ae
A
2099 cp->c_flag |= C_MODIFIED; /* leof is dirty */
2100 }
0b4e3aa0 2101
1c79356b 2102 retval = cluster_pageout(vp, ap->a_pl, ap->a_pl_offset, ap->a_f_offset, ap->a_size,
9bccf70c 2103 filesize, devBlockSize, ap->a_flags);
0b4e3aa0 2104
1c79356b
A
2105 /*
2106 * If we successfully wrote any data, and we are not the superuser
2107 * we clear the setuid and setgid bits as a precaution against
2108 * tampering.
2109 */
2110 if (retval == 0 && ap->a_cred && ap->a_cred->cr_uid != 0)
9bccf70c 2111 cp->c_mode &= ~(S_ISUID | S_ISGID);
1c79356b 2112
1c79356b
A
2113 return (retval);
2114}
2115
2116/*
2117 * Intercept B-Tree node writes to unswap them if necessary.
2118#
2119#vop_bwrite {
2120# IN struct buf *bp;
2121 */
2122int
2123hfs_bwrite(ap)
9bccf70c
A
2124 struct vop_bwrite_args /* {
2125 struct buf *a_bp;
2126 } */ *ap;
1c79356b 2127{
9bccf70c 2128 int retval = 0;
9bccf70c
A
2129 register struct buf *bp = ap->a_bp;
2130 register struct vnode *vp = bp->b_vp;
b4c24cb9 2131#if BYTE_ORDER == LITTLE_ENDIAN
9bccf70c
A
2132 BlockDescriptor block;
2133
2134 /* Trap B-Tree writes */
2135 if ((VTOC(vp)->c_fileid == kHFSExtentsFileID) ||
2136 (VTOC(vp)->c_fileid == kHFSCatalogFileID)) {
2137
2138 /* Swap if the B-Tree node is in native byte order */
2139 if (((UInt16 *)((char *)bp->b_data + bp->b_bcount - 2))[0] == 0x000e) {
2140 /* Prepare the block pointer */
2141 block.blockHeader = bp;
2142 block.buffer = bp->b_data;
2143 /* not found in cache ==> came from disk */
2144 block.blockReadFromDisk = (bp->b_flags & B_CACHE) == 0;
2145 block.blockSize = bp->b_bcount;
1c79356b 2146
9bccf70c
A
2147 /* Endian un-swap B-Tree node */
2148 SWAP_BT_NODE (&block, ISHFSPLUS (VTOVCB(vp)), VTOC(vp)->c_fileid, 1);
2149 }
1c79356b 2150
9bccf70c
A
2151 /* We don't check to make sure that it's 0x0e00 because it could be all zeros */
2152 }
1c79356b 2153#endif
9bccf70c 2154 /* This buffer shouldn't be locked anymore but if it is clear it */
b4c24cb9
A
2155 if (ISSET(bp->b_flags, B_LOCKED)) {
2156 // XXXdbg
2157 if (VTOHFS(vp)->jnl) {
2158 panic("hfs: CLEARING the lock bit on bp 0x%x\n", bp);
2159 }
2160 CLR(bp->b_flags, B_LOCKED);
9bccf70c
A
2161 printf("hfs_bwrite: called with lock bit set\n");
2162 }
2163 retval = vn_bwrite (ap);
1c79356b 2164
9bccf70c 2165 return (retval);
1c79356b 2166}
55e303ae
A
2167
2168/*
2169 * Relocate a file to a new location on disk
2170 * cnode must be locked on entry
2171 *
2172 * Relocation occurs by cloning the file's data from its
2173 * current set of blocks to a new set of blocks. During
2174 * the relocation all of the blocks (old and new) are
2175 * owned by the file.
2176 *
2177 * -----------------
2178 * |///////////////|
2179 * -----------------
2180 * 0 N (file offset)
2181 *
2182 * ----------------- -----------------
2183 * |///////////////| | | STEP 1 (aquire new blocks)
2184 * ----------------- -----------------
2185 * 0 N N+1 2N
2186 *
2187 * ----------------- -----------------
2188 * |///////////////| |///////////////| STEP 2 (clone data)
2189 * ----------------- -----------------
2190 * 0 N N+1 2N
2191 *
2192 * -----------------
2193 * |///////////////| STEP 3 (head truncate blocks)
2194 * -----------------
2195 * 0 N
2196 *
2197 * During steps 2 and 3 page-outs to file offsets less
2198 * than or equal to N are suspended.
2199 *
2200 * During step 3 page-ins to the file get supended.
2201 */
2202__private_extern__
2203int
2204hfs_relocate(vp, blockHint, cred, p)
2205 struct vnode *vp;
2206 u_int32_t blockHint;
2207 struct ucred *cred;
2208 struct proc *p;
2209{
2210 struct filefork *fp;
2211 struct hfsmount *hfsmp;
2212 ExtendedVCB *vcb;
2213
2214 u_int32_t headblks;
2215 u_int32_t datablks;
2216 u_int32_t blksize;
2217 u_int32_t realsize;
2218 u_int32_t growsize;
2219 u_int32_t nextallocsave;
2220 u_int32_t sector_a;
2221 u_int32_t sector_b;
2222 int eflags;
2223 u_int32_t oldstart; /* debug only */
2224 off_t newbytes;
2225 int retval;
2226
2227 if (vp->v_type != VREG && vp->v_type != VLNK) {
2228 return (EPERM);
2229 }
2230
2231 hfsmp = VTOHFS(vp);
2232 if (hfsmp->hfs_flags & HFS_FRAGMENTED_FREESPACE) {
2233 return (ENOSPC);
2234 }
2235
2236 fp = VTOF(vp);
2237 if (fp->ff_unallocblocks)
2238 return (EINVAL);
2239 vcb = VTOVCB(vp);
2240 blksize = vcb->blockSize;
2241 if (blockHint == 0)
2242 blockHint = vcb->nextAllocation;
2243
2244 if ((fp->ff_size > (u_int64_t)0x7fffffff) ||
2245 (vp->v_type == VLNK && fp->ff_size > blksize)) {
2246 return (EFBIG);
2247 }
2248
2249 headblks = fp->ff_blocks;
2250 datablks = howmany(fp->ff_size, blksize);
2251 growsize = datablks * blksize;
2252 realsize = fp->ff_size;
2253 eflags = kEFContigMask | kEFAllMask | kEFNoClumpMask;
2254 if (blockHint >= hfsmp->hfs_metazone_start &&
2255 blockHint <= hfsmp->hfs_metazone_end)
2256 eflags |= kEFMetadataMask;
2257
2258 hfs_global_shared_lock_acquire(hfsmp);
2259 if (hfsmp->jnl) {
2260 if (journal_start_transaction(hfsmp->jnl) != 0) {
2261 return (EINVAL);
2262 }
2263 }
2264
2265 /* Lock extents b-tree (also protects volume bitmap) */
2266 retval = hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_EXCLUSIVE, p);
2267 if (retval)
2268 goto out2;
2269
2270 retval = MapFileBlockC(vcb, (FCB *)fp, 1, growsize - 1, &sector_a, NULL);
2271 if (retval) {
2272 retval = MacToVFSError(retval);
2273 goto out;
2274 }
2275
2276 /*
2277 * STEP 1 - aquire new allocation blocks.
2278 */
2279 nextallocsave = vcb->nextAllocation;
2280 retval = ExtendFileC(vcb, (FCB*)fp, growsize, blockHint, eflags, &newbytes);
2281 if (eflags & kEFMetadataMask)
2282 vcb->nextAllocation = nextallocsave;
2283
2284 retval = MacToVFSError(retval);
2285 if (retval == 0) {
2286 VTOC(vp)->c_flag |= C_MODIFIED;
2287 if (newbytes < growsize) {
2288 retval = ENOSPC;
2289 goto restore;
2290 } else if (fp->ff_blocks < (headblks + datablks)) {
2291 printf("hfs_relocate: allocation failed");
2292 retval = ENOSPC;
2293 goto restore;
2294 }
2295
2296 retval = MapFileBlockC(vcb, (FCB *)fp, 1, growsize, &sector_b, NULL);
2297 if (retval) {
2298 retval = MacToVFSError(retval);
2299 } else if ((sector_a + 1) == sector_b) {
2300 retval = ENOSPC;
2301 goto restore;
2302 } else if ((eflags & kEFMetadataMask) &&
2303 ((((u_int64_t)sector_b * hfsmp->hfs_phys_block_size) / blksize) >
2304 hfsmp->hfs_metazone_end)) {
2305 printf("hfs_relocate: didn't move into metadata zone\n");
2306 retval = ENOSPC;
2307 goto restore;
2308 }
2309 }
2310 if (retval) {
2311 /*
2312 * Check to see if failure is due to excessive fragmentation.
2313 */
2314 if (retval == ENOSPC &&
2315 hfs_freeblks(hfsmp, 0) > (datablks * 2)) {
2316 hfsmp->hfs_flags |= HFS_FRAGMENTED_FREESPACE;
2317 }
2318 goto out;
2319 }
2320
2321 fp->ff_size = fp->ff_blocks * blksize;
2322 if (UBCISVALID(vp))
2323 (void) ubc_setsize(vp, fp->ff_size);
2324
2325 /*
2326 * STEP 2 - clone data into the new allocation blocks.
2327 */
2328
2329 if (vp->v_type == VLNK)
2330 retval = hfs_clonelink(vp, blksize, cred, p);
2331 else if (vp->v_flag & VSYSTEM)
2332 retval = hfs_clonesysfile(vp, headblks, datablks, blksize, cred, p);
2333 else
2334 retval = hfs_clonefile(vp, headblks, datablks, blksize, cred, p);
2335
2336 if (retval)
2337 goto restore;
2338
2339 oldstart = fp->ff_extents[0].startBlock;
2340
2341 /*
2342 * STEP 3 - switch to clone and remove old blocks.
2343 */
2344 SET(VTOC(vp)->c_flag, C_NOBLKMAP); /* suspend page-ins */
2345
2346 retval = HeadTruncateFile(vcb, (FCB*)fp, headblks);
2347
2348 CLR(VTOC(vp)->c_flag, C_NOBLKMAP); /* resume page-ins */
2349 if (ISSET(VTOC(vp)->c_flag, C_WBLKMAP))
2350 wakeup(VTOC(vp));
2351 if (retval)
2352 goto restore;
2353
2354 fp->ff_size = realsize;
2355 if (UBCISVALID(vp)) {
2356 (void) ubc_setsize(vp, realsize);
2357 (void) vinvalbuf(vp, V_SAVE, cred, p, 0, 0);
2358 }
2359
2360 CLR(VTOC(vp)->c_flag, C_RELOCATING); /* Resume page-outs for this file. */
2361out:
2362 (void) hfs_metafilelocking(VTOHFS(vp), kHFSExtentsFileID, LK_RELEASE, p);
2363
2364 retval = VOP_FSYNC(vp, cred, MNT_WAIT, p);
2365out2:
2366 if (hfsmp->jnl) {
2367 if (VTOC(vp)->c_cnid < kHFSFirstUserCatalogNodeID)
2368 (void) hfs_flushvolumeheader(hfsmp, MNT_WAIT, HFS_ALTFLUSH);
2369 else
2370 (void) hfs_flushvolumeheader(hfsmp, MNT_NOWAIT, 0);
2371 journal_end_transaction(hfsmp->jnl);
2372 }
2373 hfs_global_shared_lock_release(hfsmp);
2374
2375 return (retval);
2376
2377restore:
2378 /*
2379 * Give back any newly allocated space.
2380 */
2381 if (fp->ff_size != realsize)
2382 fp->ff_size = realsize;
2383 (void) TruncateFileC(vcb, (FCB*)fp, fp->ff_size, false);
2384 if (UBCISVALID(vp))
2385 (void) ubc_setsize(vp, fp->ff_size);
2386 CLR(VTOC(vp)->c_flag, C_RELOCATING);
2387 goto out;
2388}
2389
2390
2391/*
2392 * Clone a symlink.
2393 *
2394 */
2395static int
2396hfs_clonelink(struct vnode *vp, int blksize, struct ucred *cred, struct proc *p)
2397{
2398 struct buf *head_bp = NULL;
2399 struct buf *tail_bp = NULL;
2400 int error;
2401
2402
2403 error = meta_bread(vp, 0, blksize, cred, &head_bp);
2404 if (error)
2405 goto out;
2406
2407 tail_bp = getblk(vp, 1, blksize, 0, 0, BLK_META);
2408 if (tail_bp == NULL) {
2409 error = EIO;
2410 goto out;
2411 }
2412 bcopy(head_bp->b_data, tail_bp->b_data, blksize);
2413 error = bwrite(tail_bp);
2414out:
2415 if (head_bp) {
2416 head_bp->b_flags |= B_INVAL;
2417 brelse(head_bp);
2418 }
2419 (void) vinvalbuf(vp, V_SAVE, cred, p, 0, 0);
2420
2421 return (error);
2422}
2423
2424/*
2425 * Clone a file's data within the file.
2426 *
2427 */
2428static int
2429hfs_clonefile(struct vnode *vp, int blkstart, int blkcnt, int blksize,
2430 struct ucred *cred, struct proc *p)
2431{
2432 caddr_t bufp;
2433 size_t writebase;
2434 size_t bufsize;
2435 size_t copysize;
2436 size_t iosize;
2437 size_t filesize;
2438 size_t offset;
2439 struct uio auio;
2440 struct iovec aiov;
2441 int devblocksize;
2442 int didhold;
2443 int error;
2444
2445
2446 if ((error = vinvalbuf(vp, V_SAVE, cred, p, 0, 0))) {
2447 printf("hfs_clonefile: vinvalbuf failed - %d\n", error);
2448 return (error);
2449 }
2450
2451 if (!ubc_clean(vp, 1)) {
2452 printf("hfs_clonefile: not ubc_clean\n");
2453 return (EIO); /* XXX error code */
2454 }
2455
2456 /*
2457 * Suspend page-outs for this file.
2458 */
2459 SET(VTOC(vp)->c_flag, C_RELOCATING);
2460
2461 filesize = VTOF(vp)->ff_size;
2462 writebase = blkstart * blksize;
2463 copysize = blkcnt * blksize;
2464 iosize = bufsize = MIN(copysize, 4096 * 16);
2465 offset = 0;
2466
2467 if (kmem_alloc(kernel_map, (vm_offset_t *)&bufp, bufsize)) {
2468 return (ENOMEM);
2469 }
2470
2471 VOP_DEVBLOCKSIZE(VTOC(vp)->c_devvp, &devblocksize);
2472
2473 auio.uio_iov = &aiov;
2474 auio.uio_iovcnt = 1;
2475 auio.uio_segflg = UIO_SYSSPACE;
2476 auio.uio_procp = p;
2477
2478 while (offset < copysize) {
2479 iosize = MIN(copysize - offset, iosize);
2480
2481 aiov.iov_base = bufp;
2482 aiov.iov_len = iosize;
2483 auio.uio_resid = iosize;
2484 auio.uio_offset = offset;
2485 auio.uio_rw = UIO_READ;
2486
2487 error = cluster_read(vp, &auio, copysize, devblocksize, 0);
2488 if (error) {
2489 printf("hfs_clonefile: cluster_read failed - %d\n", error);
2490 break;
2491 }
2492 if (auio.uio_resid != 0) {
2493 printf("clonedata: cluster_read: uio_resid = %d\n", (int)auio.uio_resid);
2494 error = EIO;
2495 break;
2496 }
2497
2498
2499 aiov.iov_base = bufp;
2500 aiov.iov_len = iosize;
2501 auio.uio_resid = iosize;
2502 auio.uio_offset = writebase + offset;
2503 auio.uio_rw = UIO_WRITE;
2504
2505 error = cluster_write(vp, &auio, filesize + offset,
2506 filesize + offset + iosize,
2507 auio.uio_offset, 0, devblocksize, 0);
2508 if (error) {
2509 printf("hfs_clonefile: cluster_write failed - %d\n", error);
2510 break;
2511 }
2512 if (auio.uio_resid != 0) {
2513 printf("hfs_clonefile: cluster_write failed - uio_resid not zero\n");
2514 error = EIO;
2515 break;
2516 }
2517 offset += iosize;
2518 }
2519 if (error == 0) {
2520 /* Clean the pages in VM. */
2521 didhold = ubc_hold(vp);
2522 if (didhold)
2523 (void) ubc_clean(vp, 1);
2524
2525 /*
2526 * Clean out all associated buffers.
2527 */
2528 (void) vinvalbuf(vp, V_SAVE, cred, p, 0, 0);
2529
2530 if (didhold)
2531 ubc_rele(vp);
2532 }
2533 kmem_free(kernel_map, (vm_offset_t)bufp, bufsize);
2534
2535 return (error);
2536}
2537
2538/*
2539 * Clone a system (metadata) file.
2540 *
2541 */
2542static int
2543hfs_clonesysfile(struct vnode *vp, int blkstart, int blkcnt, int blksize,
2544 struct ucred *cred, struct proc *p)
2545{
2546 caddr_t bufp;
2547 char * offset;
2548 size_t bufsize;
2549 size_t iosize;
2550 struct buf *bp = NULL;
2551 daddr_t blkno;
2552 daddr_t blk;
2553 int breadcnt;
2554 int i;
2555 int error = 0;
2556
2557
2558 iosize = GetLogicalBlockSize(vp);
2559 bufsize = MIN(blkcnt * blksize, 1024 * 1024) & ~(iosize - 1);
2560 breadcnt = bufsize / iosize;
2561
2562 if (kmem_alloc(kernel_map, (vm_offset_t *)&bufp, bufsize)) {
2563 return (ENOMEM);
2564 }
2565 blkstart = (blkstart * blksize) / iosize;
2566 blkcnt = (blkcnt * blksize) / iosize;
2567 blkno = 0;
2568
2569 while (blkno < blkcnt) {
2570 /*
2571 * Read up to a megabyte
2572 */
2573 offset = bufp;
2574 for (i = 0, blk = blkno; (i < breadcnt) && (blk < blkcnt); ++i, ++blk) {
2575 error = meta_bread(vp, blk, iosize, cred, &bp);
2576 if (error) {
2577 printf("hfs_clonesysfile: meta_bread error %d\n", error);
2578 goto out;
2579 }
2580 if (bp->b_bcount != iosize) {
2581 printf("hfs_clonesysfile: b_bcount is only %d\n", bp->b_bcount);
2582 goto out;
2583 }
2584
2585 bcopy(bp->b_data, offset, iosize);
2586 bp->b_flags |= B_INVAL;
2587 brelse(bp);
2588 bp = NULL;
2589 offset += iosize;
2590 }
2591
2592 /*
2593 * Write up to a megabyte
2594 */
2595 offset = bufp;
2596 for (i = 0; (i < breadcnt) && (blkno < blkcnt); ++i, ++blkno) {
2597 bp = getblk(vp, blkstart + blkno, iosize, 0, 0, BLK_META);
2598 if (bp == NULL) {
2599 printf("hfs_clonesysfile: getblk failed on blk %d\n", blkstart + blkno);
2600 error = EIO;
2601 goto out;
2602 }
2603 bcopy(offset, bp->b_data, iosize);
2604 error = bwrite(bp);
2605 bp = NULL;
2606 if (error)
2607 goto out;
2608 offset += iosize;
2609 }
2610 }
2611out:
2612 if (bp) {
2613 brelse(bp);
2614 }
2615
2616 kmem_free(kernel_map, (vm_offset_t)bufp, bufsize);
2617
2618 error = VOP_FSYNC(vp, cred, MNT_WAIT, p);
2619
2620 return (error);
2621}
2622