]> git.saurik.com Git - apple/xnu.git/blob - bsd/ufs/ufs/ufs_readwrite.c
5afd4a8a0da5772b8eb81da10a862b8c93dbdd73
[apple/xnu.git] / bsd / ufs / ufs / ufs_readwrite.c
1 /*
2 * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
29 */
30 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
31 /*-
32 * Copyright (c) 1993
33 * The Regents of the University of California. All rights reserved.
34 *
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
37 * are met:
38 * 1. Redistributions of source code must retain the above copyright
39 * notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 * notice, this list of conditions and the following disclaimer in the
42 * documentation and/or other materials provided with the distribution.
43 * 3. All advertising materials mentioning features or use of this software
44 * must display the following acknowledgement:
45 * This product includes software developed by the University of
46 * California, Berkeley and its contributors.
47 * 4. Neither the name of the University nor the names of its contributors
48 * may be used to endorse or promote products derived from this software
49 * without specific prior written permission.
50 *
51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * SUCH DAMAGE.
62 *
63 * @(#)ufs_readwrite.c 8.11 (Berkeley) 5/8/95
64 */
65
66 #include <sys/buf_internal.h>
67 #include <sys/uio_internal.h>
68
69
70 #define BLKSIZE(a, b, c) blksize(a, b, c)
71 #define FS struct fs
72 #define I_FS i_fs
73
74
75
76 /*
77 * Vnode op for reading.
78 */
79 /* ARGSUSED */
80 ffs_read(ap)
81 struct vnop_read_args /* {
82 struct vnode *a_vp;
83 struct uio *a_uio;
84 int a_ioflag;
85 vfs_context_t a_context;
86 } */ *ap;
87 {
88 return(ffs_read_internal(ap->a_vp, ap->a_uio, ap->a_ioflag));
89 }
90
91
92 int
93 ffs_read_internal(vnode_t vp, struct uio *uio, int ioflag)
94 {
95 struct inode *ip;
96 FS *fs;
97 buf_t bp = (struct buf *)0;
98 ufs_daddr_t lbn, nextlbn;
99 off_t bytesinfile;
100 long size, xfersize, blkoffset;
101 int error;
102 u_short mode;
103 #if REV_ENDIAN_FS
104 int rev_endian=0;
105 #endif /* REV_ENDIAN_FS */
106
107 ip = VTOI(vp);
108 mode = ip->i_mode;
109
110 #if REV_ENDIAN_FS
111 rev_endian=(vp->v_mount->mnt_flag & MNT_REVEND);
112 #endif /* REV_ENDIAN_FS */
113
114 #if DIAGNOSTIC
115 if (uio->uio_rw != UIO_READ)
116 panic("ffs_read: invalid uio_rw = %x", uio->uio_rw);
117
118 if (vp->v_type == VLNK) {
119 if ((int)ip->i_size < vp->v_mount->mnt_maxsymlinklen)
120 panic("ffs_read: short symlink = %d", ip->i_size);
121 } else if (vp->v_type != VREG && vp->v_type != VDIR)
122 panic("ffs_read: invalid v_type = %x", vp->v_type);
123 #endif
124 fs = ip->I_FS;
125 if (uio->uio_offset < 0)
126 return (EINVAL);
127 if (uio->uio_offset > fs->fs_maxfilesize)
128 return (EFBIG);
129
130 if (UBCINFOEXISTS(vp)) {
131 error = cluster_read(vp, uio, (off_t)ip->i_size, 0);
132 } else {
133 for (error = 0, bp = NULL; uio_resid(uio) > 0;
134 bp = NULL) {
135 char *buf_data;
136
137 if ((bytesinfile = ip->i_size - uio->uio_offset) <= 0)
138 break;
139 lbn = lblkno(fs, uio->uio_offset);
140 nextlbn = lbn + 1;
141 size = BLKSIZE(fs, ip, lbn);
142 blkoffset = blkoff(fs, uio->uio_offset);
143 xfersize = fs->fs_bsize - blkoffset;
144 // LP64todo - fix this
145 if (uio_resid(uio) < xfersize)
146 xfersize = uio_resid(uio);
147 if (bytesinfile < xfersize)
148 xfersize = bytesinfile;
149
150 if (lblktosize(fs, nextlbn) >= ip->i_size)
151 error = (int)buf_bread(vp, (daddr64_t)((unsigned)lbn), size, NOCRED, &bp);
152 else if (lbn - 1 == ip->i_lastr && !(vp->v_flag & VRAOFF)) {
153 int nextsize = BLKSIZE(fs, ip, nextlbn);
154 error = (int)buf_breadn(vp, (daddr64_t)((unsigned)lbn),
155 size, &nextlbn, &nextsize, 1, NOCRED, &bp);
156 } else
157 error = (int)buf_bread(vp, lbn, size, NOCRED, &bp);
158 if (error)
159 break;
160 ip->i_lastr = lbn;
161
162 /*
163 * We should only get non-zero buffer resid when an I/O error
164 * has occurred, which should cause us to break above.
165 * However, if the short read did not cause an error,
166 * then we want to ensure that we do not uiomove bad
167 * or uninitialized data.
168 */
169 size -= buf_resid(bp);
170 if (size < xfersize) {
171 if (size == 0)
172 break;
173 xfersize = size;
174 }
175 buf_data = (char *)buf_dataptr(bp);
176 #if REV_ENDIAN_FS
177 if (rev_endian && S_ISDIR(mode)) {
178 byte_swap_dir_block_in(buf_data + blkoffset, xfersize);
179 }
180 #endif /* REV_ENDIAN_FS */
181 if (error =
182 uiomove(buf_data + blkoffset, (int)xfersize, uio)) {
183 #if REV_ENDIAN_FS
184 if (rev_endian && S_ISDIR(mode)) {
185 byte_swap_dir_block_in(buf_data + blkoffset, xfersize);
186 }
187 #endif /* REV_ENDIAN_FS */
188 break;
189 }
190
191 #if REV_ENDIAN_FS
192 if (rev_endian && S_ISDIR(mode)) {
193 byte_swap_dir_out(buf_data + blkoffset, xfersize);
194 }
195 #endif /* REV_ENDIAN_FS */
196 if (S_ISREG(mode) && (xfersize + blkoffset == fs->fs_bsize ||
197 uio->uio_offset == ip->i_size))
198 buf_markaged(bp);
199 buf_brelse(bp);
200 }
201 }
202 if (bp != NULL)
203 buf_brelse(bp);
204 ip->i_flag |= IN_ACCESS;
205 return (error);
206 }
207
208 /*
209 * Vnode op for writing.
210 */
211 ffs_write(ap)
212 struct vnop_write_args /* {
213 struct vnode *a_vp;
214 struct uio *a_uio;
215 int a_ioflag;
216 vfs_context_t a_context;
217 } */ *ap;
218 {
219 return(ffs_write_internal(ap->a_vp, ap->a_uio, ap->a_ioflag, vfs_context_ucred(ap->a_context)));
220 }
221
222
223 ffs_write_internal(vnode_t vp, struct uio *uio, int ioflag, ucred_t cred)
224 {
225 buf_t bp;
226 proc_t p;
227 struct inode *ip;
228 FS *fs;
229 ufs_daddr_t lbn;
230 off_t osize;
231 int blkoffset, flags, resid, rsd, size, xfersize;
232 int save_error=0, save_size=0;
233 int blkalloc = 0;
234 int error = 0;
235 int file_extended = 0;
236 int doingdirectory = 0;
237
238 #if REV_ENDIAN_FS
239 int rev_endian=0;
240 #endif /* REV_ENDIAN_FS */
241
242 ip = VTOI(vp);
243 #if REV_ENDIAN_FS
244 rev_endian=(vp->v_mount->mnt_flag & MNT_REVEND);
245 #endif /* REV_ENDIAN_FS */
246
247 #if DIAGNOSTIC
248 if (uio->uio_rw != UIO_WRITE)
249 panic("ffs_write: uio_rw = %x\n", uio->uio_rw);
250 #endif
251
252 switch (vp->v_type) {
253 case VREG:
254 if (ioflag & IO_APPEND)
255 uio->uio_offset = ip->i_size;
256 if ((ip->i_flags & APPEND) && uio->uio_offset != ip->i_size)
257 return (EPERM);
258 /* FALLTHROUGH */
259 case VLNK:
260 break;
261 case VDIR:
262 doingdirectory = 1;
263 if ((ioflag & IO_SYNC) == 0)
264 panic("ffs_write: nonsync dir write");
265 break;
266 default:
267 panic("ffs_write: invalid v_type=%x", vp->v_type);
268 }
269
270 fs = ip->I_FS;
271 if (uio->uio_offset < 0 ||
272 (u_int64_t)uio->uio_offset + uio_resid(uio) > fs->fs_maxfilesize)
273 return (EFBIG);
274 if (uio_resid(uio) == 0)
275 return (0);
276
277 // LP64todo - fix this
278 resid = uio_resid(uio);
279 osize = ip->i_size;
280 flags = 0;
281 if ((ioflag & IO_SYNC) && !((vp)->v_mount->mnt_flag & MNT_ASYNC))
282 flags = B_SYNC;
283
284 if (UBCINFOEXISTS(vp)) {
285 off_t filesize;
286 off_t endofwrite;
287 off_t local_offset;
288 off_t head_offset;
289 int local_flags;
290 int first_block;
291 int fboff;
292 int fblk;
293 int loopcount;
294
295 // LP64todo - fix this
296 endofwrite = uio->uio_offset + uio_resid(uio);
297
298 if (endofwrite > ip->i_size) {
299 filesize = endofwrite;
300 file_extended = 1;
301 } else
302 filesize = ip->i_size;
303
304 head_offset = ip->i_size;
305
306 /* Go ahead and allocate the block that are going to be written */
307 // LP64todo - fix this
308 rsd = uio_resid(uio);
309 local_offset = uio->uio_offset;
310 local_flags = 0;
311 if ((ioflag & IO_SYNC) && !((vp)->v_mount->mnt_flag & MNT_ASYNC))
312 local_flags = B_SYNC;
313 local_flags |= B_NOBUFF;
314
315 first_block = 1;
316 fboff = 0;
317 fblk = 0;
318 loopcount = 0;
319
320 for (error = 0; rsd > 0;) {
321 blkalloc = 0;
322 lbn = lblkno(fs, local_offset);
323 blkoffset = blkoff(fs, local_offset);
324 xfersize = fs->fs_bsize - blkoffset;
325 if (first_block)
326 fboff = blkoffset;
327 if (rsd < xfersize)
328 xfersize = rsd;
329 if (fs->fs_bsize > xfersize)
330 local_flags |= B_CLRBUF;
331 else
332 local_flags &= ~B_CLRBUF;
333
334 /* Allocate block without reading into a buf */
335 error = ffs_balloc(ip,
336 lbn, blkoffset + xfersize, cred,
337 &bp, local_flags, &blkalloc);
338 if (error)
339 break;
340 if (first_block) {
341 fblk = blkalloc;
342 first_block = 0;
343 }
344 loopcount++;
345
346 rsd -= xfersize;
347 local_offset += (off_t)xfersize;
348 if (local_offset > ip->i_size)
349 ip->i_size = local_offset;
350 }
351
352 if(error) {
353 save_error = error;
354 save_size = rsd;
355 uio_setresid(uio, (uio_resid(uio) - rsd));
356 if (file_extended)
357 filesize -= rsd;
358 }
359
360 flags = ioflag & IO_SYNC ? IO_SYNC : 0;
361 /* flags |= IO_NOZEROVALID; */
362
363 if((error == 0) && fblk && fboff) {
364 if( fblk > fs->fs_bsize)
365 panic("ffs_balloc : allocated more than bsize(head)");
366 /* We need to zero out the head */
367 head_offset = uio->uio_offset - (off_t)fboff ;
368 flags |= IO_HEADZEROFILL;
369 /* flags &= ~IO_NOZEROVALID; */
370 }
371
372 if((error == 0) && blkalloc && ((blkalloc - xfersize) > 0)) {
373 /* We need to zero out the tail */
374 if( blkalloc > fs->fs_bsize)
375 panic("ffs_balloc : allocated more than bsize(tail)");
376 local_offset += (blkalloc - xfersize);
377 if (loopcount == 1) {
378 /* blkalloc is same as fblk; so no need to check again*/
379 local_offset -= fboff;
380 }
381 flags |= IO_TAILZEROFILL;
382 /* Freshly allocated block; bzero even if
383 * find a page
384 */
385 /* flags &= ~IO_NOZEROVALID; */
386 }
387 /*
388 * if the write starts beyond the current EOF then
389 * we we'll zero fill from the current EOF to where the write begins
390 */
391
392 error = cluster_write(vp, uio, osize, filesize, head_offset, local_offset, flags);
393
394 if (uio->uio_offset > osize) {
395 if (error && ((ioflag & IO_UNIT)==0))
396 (void)ffs_truncate_internal(vp, uio->uio_offset, ioflag & IO_SYNC, cred);
397 ip->i_size = uio->uio_offset;
398 ubc_setsize(vp, (off_t)ip->i_size);
399 }
400 if(save_error) {
401 uio_setresid(uio, (uio_resid(uio) + save_size));
402 if(!error)
403 error = save_error;
404 }
405 ip->i_flag |= IN_CHANGE | IN_UPDATE;
406 } else {
407 flags = 0;
408 if ((ioflag & IO_SYNC) && !((vp)->v_mount->mnt_flag & MNT_ASYNC))
409 flags = B_SYNC;
410
411 for (error = 0; uio_resid(uio) > 0;) {
412 char *buf_data;
413
414 lbn = lblkno(fs, uio->uio_offset);
415 blkoffset = blkoff(fs, uio->uio_offset);
416 xfersize = fs->fs_bsize - blkoffset;
417 if (uio_resid(uio) < xfersize)
418 // LP64todo - fix this
419 xfersize = uio_resid(uio);
420
421 if (fs->fs_bsize > xfersize)
422 flags |= B_CLRBUF;
423 else
424 flags &= ~B_CLRBUF;
425
426 error = ffs_balloc(ip, lbn, blkoffset + xfersize, cred, &bp, flags, 0);
427 if (error)
428 break;
429 if (uio->uio_offset + xfersize > ip->i_size) {
430 ip->i_size = uio->uio_offset + xfersize;
431 ubc_setsize(vp, (u_long)ip->i_size);
432 }
433
434 size = BLKSIZE(fs, ip, lbn) - buf_resid(bp);
435 if (size < xfersize)
436 xfersize = size;
437
438 buf_data = (char *)buf_dataptr(bp);
439
440 error = uiomove(buf_data + blkoffset, (int)xfersize, uio);
441 #if REV_ENDIAN_FS
442 if (rev_endian && S_ISDIR(ip->i_mode)) {
443 byte_swap_dir_out(buf_data + blkoffset, xfersize);
444 }
445 #endif /* REV_ENDIAN_FS */
446 if (doingdirectory == 0 && (ioflag & IO_SYNC))
447 (void)buf_bwrite(bp);
448 else if (xfersize + blkoffset == fs->fs_bsize) {
449 buf_markaged(bp);
450 buf_bdwrite(bp);
451 }
452 else
453 buf_bdwrite(bp);
454 if (error || xfersize == 0)
455 break;
456 ip->i_flag |= IN_CHANGE | IN_UPDATE;
457 }
458 }
459 /*
460 * If we successfully wrote any data, and we are not the superuser
461 * we clear the setuid and setgid bits as a precaution against
462 * tampering.
463 */
464 if (resid > uio_resid(uio) && cred && suser(cred, NULL))
465 ip->i_mode &= ~(ISUID | ISGID);
466 if (resid > uio_resid(uio))
467 VN_KNOTE(vp, NOTE_WRITE | (file_extended ? NOTE_EXTEND : 0));
468 if (error) {
469 if (ioflag & IO_UNIT) {
470 (void)ffs_truncate_internal(vp, osize, ioflag & IO_SYNC, cred);
471 // LP64todo - fix this
472 uio->uio_offset -= resid - uio_resid(uio);
473 uio_setresid(uio, resid);
474 }
475 } else if (resid > uio_resid(uio) && (ioflag & IO_SYNC)) {
476 struct timeval tv;
477
478 microtime(&tv);
479 error = ffs_update(vp, &tv, &tv, 1);
480 }
481 return (error);
482 }
483
484 /*
485 * Vnode op for pagein.
486 * Similar to ffs_read()
487 */
488 /* ARGSUSED */
489 ffs_pagein(ap)
490 struct vnop_pagein_args /* {
491 struct vnode *a_vp,
492 upl_t a_pl,
493 vm_offset_t a_pl_offset,
494 off_t a_f_offset,
495 size_t a_size,
496 int a_flags
497 vfs_context_t a_context;
498 } */ *ap;
499 {
500 register struct vnode *vp = ap->a_vp;
501 upl_t pl = ap->a_pl;
502 size_t size= ap->a_size;
503 off_t f_offset = ap->a_f_offset;
504 vm_offset_t pl_offset = ap->a_pl_offset;
505 int flags = ap->a_flags;
506 register struct inode *ip;
507 int error;
508
509 ip = VTOI(vp);
510
511 /* check pageins for reg file only and ubc info is present*/
512 if (UBCINVALID(vp))
513 panic("ffs_pagein: Not a VREG: vp=%x", vp);
514 if (UBCINFOMISSING(vp))
515 panic("ffs_pagein: No mapping: vp=%x", vp);
516
517 #if DIAGNOSTIC
518 if (vp->v_type == VLNK) {
519 if ((int)ip->i_size < vp->v_mount->mnt_maxsymlinklen)
520 panic("%s: short symlink", "ffs_pagein");
521 } else if (vp->v_type != VREG && vp->v_type != VDIR)
522 panic("%s: type %d", "ffs_pagein", vp->v_type);
523 #endif
524
525 error = cluster_pagein(vp, pl, pl_offset, f_offset, size, (off_t)ip->i_size, flags);
526
527 /* ip->i_flag |= IN_ACCESS; */
528 return (error);
529 }
530
531 /*
532 * Vnode op for pageout.
533 * Similar to ffs_write()
534 * make sure the buf is not in hash queue when you return
535 */
536 ffs_pageout(ap)
537 struct vnop_pageout_args /* {
538 struct vnode *a_vp,
539 upl_t a_pl,
540 vm_offset_t a_pl_offset,
541 off_t a_f_offset,
542 size_t a_size,
543 int a_flags
544 vfs_context_t a_context;
545 } */ *ap;
546 {
547 register struct vnode *vp = ap->a_vp;
548 upl_t pl = ap->a_pl;
549 size_t size= ap->a_size;
550 off_t f_offset = ap->a_f_offset;
551 vm_offset_t pl_offset = ap->a_pl_offset;
552 int flags = ap->a_flags;
553 register struct inode *ip;
554 register FS *fs;
555 int error ;
556 size_t xfer_size = 0;
557 int local_flags=0;
558 off_t local_offset;
559 int resid, blkoffset;
560 size_t xsize, lsize;
561 daddr_t lbn;
562 int save_error =0, save_size=0;
563 vm_offset_t lupl_offset;
564 int nocommit = flags & UPL_NOCOMMIT;
565 int devBlockSize = 0;
566 struct buf *bp;
567
568 ip = VTOI(vp);
569
570 /* check pageouts for reg file only and ubc info is present*/
571 if (UBCINVALID(vp))
572 panic("ffs_pageout: Not a VREG: vp=%x", vp);
573 if (UBCINFOMISSING(vp))
574 panic("ffs_pageout: No mapping: vp=%x", vp);
575
576 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
577 if (!nocommit)
578 ubc_upl_abort_range(pl, pl_offset, size,
579 UPL_ABORT_FREE_ON_EMPTY);
580 return (EROFS);
581 }
582 fs = ip->I_FS;
583
584 if (f_offset < 0 || f_offset >= ip->i_size) {
585 if (!nocommit)
586 ubc_upl_abort_range(pl, pl_offset, size,
587 UPL_ABORT_FREE_ON_EMPTY);
588 return (EINVAL);
589 }
590
591 /*
592 * once we enable multi-page pageouts we will
593 * need to make sure we abort any pages in the upl
594 * that we don't issue an I/O for
595 */
596 if (f_offset + size > ip->i_size)
597 xfer_size = ip->i_size - f_offset;
598 else
599 xfer_size = size;
600
601 devBlockSize = vfs_devblocksize(vnode_mount(vp));
602
603 if (xfer_size & (PAGE_SIZE - 1)) {
604 /* if not a multiple of page size
605 * then round up to be a multiple
606 * the physical disk block size
607 */
608 xfer_size = (xfer_size + (devBlockSize - 1)) & ~(devBlockSize - 1);
609 }
610
611 /*
612 * once the block allocation is moved to ufs_blockmap
613 * we can remove all the size and offset checks above
614 * cluster_pageout does all of this now
615 * we need to continue to do it here so as not to
616 * allocate blocks that aren't going to be used because
617 * of a bogus parameter being passed in
618 */
619 local_flags = 0;
620 resid = xfer_size;
621 local_offset = f_offset;
622 for (error = 0; resid > 0;) {
623 lbn = lblkno(fs, local_offset);
624 blkoffset = blkoff(fs, local_offset);
625 xsize = fs->fs_bsize - blkoffset;
626 if (resid < xsize)
627 xsize = resid;
628 /* Allocate block without reading into a buf */
629 error = ffs_blkalloc(ip,
630 lbn, blkoffset + xsize, vfs_context_ucred(ap->a_context),
631 local_flags);
632 if (error)
633 break;
634 resid -= xsize;
635 local_offset += (off_t)xsize;
636 }
637
638 if (error) {
639 save_size = resid;
640 save_error = error;
641 xfer_size -= save_size;
642 }
643
644
645 error = cluster_pageout(vp, pl, pl_offset, f_offset, round_page_32(xfer_size), ip->i_size, flags);
646
647 if(save_error) {
648 lupl_offset = size - save_size;
649 resid = round_page_32(save_size);
650 if (!nocommit)
651 ubc_upl_abort_range(pl, lupl_offset, resid,
652 UPL_ABORT_FREE_ON_EMPTY);
653 if(!error)
654 error= save_error;
655 }
656 return (error);
657 }