]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/ubc_subr.c
xnu-517.9.4.tar.gz
[apple/xnu.git] / bsd / kern / ubc_subr.c
1 /*
2 * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * File: ubc_subr.c
24 * Author: Umesh Vaishampayan [umeshv@apple.com]
25 * 05-Aug-1999 umeshv Created.
26 *
27 * Functions related to Unified Buffer cache.
28 *
29 * Caller of UBC functions MUST have a valid reference on the vnode.
30 *
31 */
32
33 #undef DIAGNOSTIC
34 #define DIAGNOSTIC 1
35
36 #include <sys/types.h>
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/lock.h>
40 #include <sys/ubc.h>
41 #include <sys/mount.h>
42 #include <sys/vnode.h>
43 #include <sys/ubc.h>
44 #include <sys/ucred.h>
45 #include <sys/proc.h>
46 #include <sys/buf.h>
47
48 #include <mach/mach_types.h>
49 #include <mach/memory_object_types.h>
50
51 #include <kern/zalloc.h>
52
53 #if DIAGNOSTIC
54 #if defined(assert)
55 #undef assert()
56 #endif
57 #define assert(cond) \
58 ((void) ((cond) ? 0 : panic("%s:%d (%s)", __FILE__, __LINE__, # cond)))
59 #else
60 #include <kern/assert.h>
61 #endif /* DIAGNOSTIC */
62
63 struct zone *ubc_info_zone;
64
65 /* lock for changes to struct UBC */
66 static __inline__ void
67 ubc_lock(struct vnode *vp)
68 {
69 /* For now, just use the v_interlock */
70 simple_lock(&vp->v_interlock);
71 }
72
73 /* unlock */
74 static __inline__ void
75 ubc_unlock(struct vnode *vp)
76 {
77 /* For now, just use the v_interlock */
78 simple_unlock(&vp->v_interlock);
79 }
80
81 /*
82 * Serialize the requests to the VM
83 * Returns:
84 * 0 - Failure
85 * 1 - Sucessful in acquiring the lock
86 * 2 - Sucessful in acquiring the lock recursively
87 * do not call ubc_unbusy()
88 * [This is strange, but saves 4 bytes in struct ubc_info]
89 */
90 static int
91 ubc_busy(struct vnode *vp)
92 {
93 register struct ubc_info *uip;
94
95 if (!UBCINFOEXISTS(vp))
96 return (0);
97
98 uip = vp->v_ubcinfo;
99
100 while (ISSET(uip->ui_flags, UI_BUSY)) {
101
102 if (uip->ui_owner == (void *)current_act())
103 return (2);
104
105 SET(uip->ui_flags, UI_WANTED);
106 (void) tsleep((caddr_t)&vp->v_ubcinfo, PINOD, "ubcbusy", 0);
107
108 if (!UBCINFOEXISTS(vp))
109 return (0);
110 }
111 uip->ui_owner = (void *)current_act();
112
113 SET(uip->ui_flags, UI_BUSY);
114
115 return (1);
116 }
117
118 static void
119 ubc_unbusy(struct vnode *vp)
120 {
121 register struct ubc_info *uip;
122
123 if (!UBCINFOEXISTS(vp)) {
124 wakeup((caddr_t)&vp->v_ubcinfo);
125 return;
126 }
127 uip = vp->v_ubcinfo;
128 CLR(uip->ui_flags, UI_BUSY);
129 uip->ui_owner = (void *)NULL;
130
131 if (ISSET(uip->ui_flags, UI_WANTED)) {
132 CLR(uip->ui_flags, UI_WANTED);
133 wakeup((caddr_t)&vp->v_ubcinfo);
134 }
135 }
136
137 /*
138 * Initialization of the zone for Unified Buffer Cache.
139 */
140 __private_extern__ void
141 ubc_init()
142 {
143 int i;
144
145 i = (vm_size_t) sizeof (struct ubc_info);
146 /* XXX the number of elements should be tied in to maxvnodes */
147 ubc_info_zone = zinit (i, 10000*i, 8192, "ubc_info zone");
148 return;
149 }
150
151 /*
152 * Initialize a ubc_info structure for a vnode.
153 */
154 int
155 ubc_info_init(struct vnode *vp)
156 {
157 register struct ubc_info *uip;
158 void * pager;
159 struct vattr vattr;
160 struct proc *p = current_proc();
161 int error = 0;
162 kern_return_t kret;
163 memory_object_control_t control;
164
165 if (!UBCISVALID(vp))
166 return (EINVAL);
167
168 ubc_lock(vp);
169 if (ISSET(vp->v_flag, VUINIT)) {
170 /*
171 * other thread is already doing this
172 * wait till done
173 */
174 while (ISSET(vp->v_flag, VUINIT)) {
175 SET(vp->v_flag, VUWANT); /* XXX overloaded! */
176 ubc_unlock(vp);
177 (void) tsleep((caddr_t)vp, PINOD, "ubcinfo", 0);
178 ubc_lock(vp);
179 }
180 ubc_unlock(vp);
181 return (0);
182 } else {
183 SET(vp->v_flag, VUINIT);
184 }
185
186 uip = vp->v_ubcinfo;
187 if ((uip == UBC_INFO_NULL) || (uip == UBC_NOINFO)) {
188 ubc_unlock(vp);
189 uip = (struct ubc_info *) zalloc(ubc_info_zone);
190 uip->ui_pager = MEMORY_OBJECT_NULL;
191 uip->ui_control = MEMORY_OBJECT_CONTROL_NULL;
192 uip->ui_flags = UI_INITED;
193 uip->ui_vnode = vp;
194 uip->ui_ucred = NOCRED;
195 uip->ui_refcount = 1;
196 uip->ui_size = 0;
197 uip->ui_mapped = 0;
198 uip->ui_owner = (void *)NULL;
199 ubc_lock(vp);
200 }
201 #if DIAGNOSTIC
202 else
203 Debugger("ubc_info_init: already");
204 #endif /* DIAGNOSTIC */
205
206 assert(uip->ui_flags != UI_NONE);
207 assert(uip->ui_vnode == vp);
208
209 #if 0
210 if(ISSET(uip->ui_flags, UI_HASPAGER))
211 goto done;
212 #endif /* 0 */
213
214 /* now set this ubc_info in the vnode */
215 vp->v_ubcinfo = uip;
216 SET(uip->ui_flags, UI_HASPAGER);
217 ubc_unlock(vp);
218 pager = (void *)vnode_pager_setup(vp, uip->ui_pager);
219 assert(pager);
220 ubc_setpager(vp, pager);
221
222 /*
223 * Note: We can not use VOP_GETATTR() to get accurate
224 * value of ui_size. Thanks to NFS.
225 * nfs_getattr() can call vinvalbuf() and in this case
226 * ubc_info is not set up to deal with that.
227 * So use bogus size.
228 */
229
230 /*
231 * create a vnode - vm_object association
232 * memory_object_create_named() creates a "named" reference on the
233 * memory object we hold this reference as long as the vnode is
234 * "alive." Since memory_object_create_named() took its own reference
235 * on the vnode pager we passed it, we can drop the reference
236 * vnode_pager_setup() returned here.
237 */
238 kret = memory_object_create_named(pager,
239 (memory_object_size_t)uip->ui_size, &control);
240 vnode_pager_deallocate(pager);
241 if (kret != KERN_SUCCESS)
242 panic("ubc_info_init: memory_object_create_named returned %d", kret);
243
244 assert(control);
245 uip->ui_control = control; /* cache the value of the mo control */
246 SET(uip->ui_flags, UI_HASOBJREF); /* with a named reference */
247 /* create a pager reference on the vnode */
248 error = vnode_pager_vget(vp);
249 if (error)
250 panic("ubc_info_init: vnode_pager_vget error = %d", error);
251
252 /* initialize the size */
253 error = VOP_GETATTR(vp, &vattr, p->p_ucred, p);
254
255 ubc_lock(vp);
256 uip->ui_size = (error ? 0: vattr.va_size);
257
258 done:
259 CLR(vp->v_flag, VUINIT);
260 if (ISSET(vp->v_flag, VUWANT)) {
261 CLR(vp->v_flag, VUWANT);
262 ubc_unlock(vp);
263 wakeup((caddr_t)vp);
264 } else
265 ubc_unlock(vp);
266
267 return (error);
268 }
269
270 /* Free the ubc_info */
271 static void
272 ubc_info_free(struct ubc_info *uip)
273 {
274 struct ucred *credp;
275
276 credp = uip->ui_ucred;
277 if (credp != NOCRED) {
278 uip->ui_ucred = NOCRED;
279 crfree(credp);
280 }
281
282 if (uip->ui_control != MEMORY_OBJECT_CONTROL_NULL)
283 memory_object_control_deallocate(uip->ui_control);
284
285 zfree(ubc_info_zone, (vm_offset_t)uip);
286 return;
287 }
288
289 void
290 ubc_info_deallocate(struct ubc_info *uip)
291 {
292
293 assert(uip->ui_refcount > 0);
294
295 if (uip->ui_refcount-- == 1) {
296 struct vnode *vp;
297
298 vp = uip->ui_vnode;
299 if (ISSET(uip->ui_flags, UI_WANTED)) {
300 CLR(uip->ui_flags, UI_WANTED);
301 wakeup((caddr_t)&vp->v_ubcinfo);
302 }
303
304 ubc_info_free(uip);
305 }
306 }
307
308 /*
309 * Communicate with VM the size change of the file
310 * returns 1 on success, 0 on failure
311 */
312 int
313 ubc_setsize(struct vnode *vp, off_t nsize)
314 {
315 off_t osize; /* ui_size before change */
316 off_t lastpg, olastpgend, lastoff;
317 struct ubc_info *uip;
318 memory_object_control_t control;
319 kern_return_t kret;
320
321 if (nsize < (off_t)0)
322 return (0);
323
324 if (UBCINVALID(vp))
325 return (0);
326
327 if (!UBCINFOEXISTS(vp))
328 return (0);
329
330 uip = vp->v_ubcinfo;
331 osize = uip->ui_size; /* call ubc_getsize() ??? */
332 /* Update the size before flushing the VM */
333 uip->ui_size = nsize;
334
335 if (nsize >= osize) /* Nothing more to do */
336 return (1); /* return success */
337
338 /*
339 * When the file shrinks, invalidate the pages beyond the
340 * new size. Also get rid of garbage beyond nsize on the
341 * last page. The ui_size already has the nsize. This
342 * insures that the pageout would not write beyond the new
343 * end of the file.
344 */
345
346 lastpg = trunc_page_64(nsize);
347 olastpgend = round_page_64(osize);
348 control = uip->ui_control;
349 assert(control);
350 lastoff = (nsize & PAGE_MASK_64);
351
352 /*
353 * If length is multiple of page size, we should not flush
354 * invalidating is sufficient
355 */
356 if (!lastoff) {
357 /* invalidate last page and old contents beyond nsize */
358 kret = memory_object_lock_request(control,
359 (memory_object_offset_t)lastpg,
360 (memory_object_size_t)(olastpgend - lastpg),
361 MEMORY_OBJECT_RETURN_NONE, MEMORY_OBJECT_DATA_FLUSH,
362 VM_PROT_NO_CHANGE);
363 if (kret != KERN_SUCCESS)
364 printf("ubc_setsize: invalidate failed (error = %d)\n", kret);
365
366 return ((kret == KERN_SUCCESS) ? 1 : 0);
367 }
368
369 /* flush the last page */
370 kret = memory_object_lock_request(control,
371 (memory_object_offset_t)lastpg,
372 PAGE_SIZE_64,
373 MEMORY_OBJECT_RETURN_DIRTY, FALSE,
374 VM_PROT_NO_CHANGE);
375
376 if (kret == KERN_SUCCESS) {
377 /* invalidate last page and old contents beyond nsize */
378 kret = memory_object_lock_request(control,
379 (memory_object_offset_t)lastpg,
380 (memory_object_size_t)(olastpgend - lastpg),
381 MEMORY_OBJECT_RETURN_NONE, MEMORY_OBJECT_DATA_FLUSH,
382 VM_PROT_NO_CHANGE);
383 if (kret != KERN_SUCCESS)
384 printf("ubc_setsize: invalidate failed (error = %d)\n", kret);
385 } else
386 printf("ubc_setsize: flush failed (error = %d)\n", kret);
387
388 return ((kret == KERN_SUCCESS) ? 1 : 0);
389 }
390
391 /*
392 * Get the size of the file
393 */
394 off_t
395 ubc_getsize(struct vnode *vp)
396 {
397 return (vp->v_ubcinfo->ui_size);
398 }
399
400 /*
401 * Caller indicate that the object corresponding to the vnode
402 * can not be cached in object cache. Make it so.
403 * returns 1 on success, 0 on failure
404 */
405 int
406 ubc_uncache(struct vnode *vp)
407 {
408 kern_return_t kret;
409 struct ubc_info *uip;
410 int recursed;
411 memory_object_control_t control;
412 memory_object_perf_info_data_t perf;
413
414 if (!UBCINFOEXISTS(vp))
415 return (0);
416
417 if ((recursed = ubc_busy(vp)) == 0)
418 return (0);
419
420 uip = vp->v_ubcinfo;
421
422 assert(uip != UBC_INFO_NULL);
423
424 /*
425 * AGE it so that vfree() can make sure that it
426 * would get recycled soon after the last reference is gone
427 * This will insure that .nfs turds would not linger
428 */
429 vagevp(vp);
430
431 /* set the "do not cache" bit */
432 SET(uip->ui_flags, UI_DONTCACHE);
433
434 control = uip->ui_control;
435 assert(control);
436
437 perf.cluster_size = PAGE_SIZE; /* XXX use real cluster_size. */
438 perf.may_cache = FALSE;
439 kret = memory_object_change_attributes(control,
440 MEMORY_OBJECT_PERFORMANCE_INFO,
441 (memory_object_info_t) &perf,
442 MEMORY_OBJECT_PERF_INFO_COUNT);
443
444 if (kret != KERN_SUCCESS) {
445 printf("ubc_uncache: memory_object_change_attributes_named "
446 "kret = %d", kret);
447 if (recursed == 1)
448 ubc_unbusy(vp);
449 return (0);
450 }
451
452 ubc_release_named(vp);
453
454 if (recursed == 1)
455 ubc_unbusy(vp);
456 return (1);
457 }
458
459 /*
460 * call ubc_clean() and ubc_uncache() on all the vnodes
461 * for this mount point.
462 * returns 1 on success, 0 on failure
463 */
464 __private_extern__ int
465 ubc_umount(struct mount *mp)
466 {
467 struct proc *p = current_proc();
468 struct vnode *vp, *nvp;
469 int ret = 1;
470
471 loop:
472 simple_lock(&mntvnode_slock);
473 for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) {
474 if (vp->v_mount != mp) {
475 simple_unlock(&mntvnode_slock);
476 goto loop;
477 }
478 nvp = vp->v_mntvnodes.le_next;
479 simple_unlock(&mntvnode_slock);
480 if (UBCINFOEXISTS(vp)) {
481
482 /*
483 * Must get a valid reference on the vnode
484 * before callig UBC functions
485 */
486 if (vget(vp, 0, p)) {
487 ret = 0;
488 simple_lock(&mntvnode_slock);
489 continue; /* move on to the next vnode */
490 }
491 ret &= ubc_clean(vp, 0); /* do not invalidate */
492 ret &= ubc_uncache(vp);
493 vrele(vp);
494 }
495 simple_lock(&mntvnode_slock);
496 }
497 simple_unlock(&mntvnode_slock);
498 return (ret);
499 }
500
501 /*
502 * Call ubc_unmount() for all filesystems.
503 * The list is traversed in reverse order
504 * of mounting to avoid dependencies.
505 */
506 __private_extern__ void
507 ubc_unmountall()
508 {
509 struct mount *mp, *nmp;
510
511 /*
512 * Since this only runs when rebooting, it is not interlocked.
513 */
514 for (mp = mountlist.cqh_last; mp != (void *)&mountlist; mp = nmp) {
515 nmp = mp->mnt_list.cqe_prev;
516 (void) ubc_umount(mp);
517 }
518 }
519
520 /* Get the credentials */
521 struct ucred *
522 ubc_getcred(struct vnode *vp)
523 {
524 struct ubc_info *uip;
525
526 uip = vp->v_ubcinfo;
527
528 if (UBCINVALID(vp))
529 return (NOCRED);
530
531 return (uip->ui_ucred);
532 }
533
534 /*
535 * Set the credentials
536 * existing credentials are not changed
537 * returns 1 on success and 0 on failure
538 */
539 int
540 ubc_setcred(struct vnode *vp, struct proc *p)
541 {
542 struct ubc_info *uip;
543 struct ucred *credp;
544
545 uip = vp->v_ubcinfo;
546
547 if (UBCINVALID(vp))
548 return (0);
549
550 credp = uip->ui_ucred;
551 if (credp == NOCRED) {
552 crhold(p->p_ucred);
553 uip->ui_ucred = p->p_ucred;
554 }
555
556 return (1);
557 }
558
559 /* Get the pager */
560 __private_extern__ memory_object_t
561 ubc_getpager(struct vnode *vp)
562 {
563 struct ubc_info *uip;
564
565 uip = vp->v_ubcinfo;
566
567 if (UBCINVALID(vp))
568 return (0);
569
570 return (uip->ui_pager);
571 }
572
573 /*
574 * Get the memory object associated with this vnode
575 * If the vnode was reactivated, memory object would not exist.
576 * Unless "do not rectivate" was specified, look it up using the pager.
577 * If hold was requested create an object reference of one does not
578 * exist already.
579 */
580
581 memory_object_control_t
582 ubc_getobject(struct vnode *vp, int flags)
583 {
584 struct ubc_info *uip;
585 int recursed;
586 memory_object_control_t control;
587
588 if (UBCINVALID(vp))
589 return (0);
590
591 if (flags & UBC_FOR_PAGEOUT)
592 return(vp->v_ubcinfo->ui_control);
593
594 if ((recursed = ubc_busy(vp)) == 0)
595 return (0);
596
597 uip = vp->v_ubcinfo;
598 control = uip->ui_control;
599
600 if ((flags & UBC_HOLDOBJECT) && (!ISSET(uip->ui_flags, UI_HASOBJREF))) {
601
602 /*
603 * Take a temporary reference on the ubc info so that it won't go
604 * away during our recovery attempt.
605 */
606 ubc_lock(vp);
607 uip->ui_refcount++;
608 ubc_unlock(vp);
609 if (memory_object_recover_named(control, TRUE) == KERN_SUCCESS) {
610 SET(uip->ui_flags, UI_HASOBJREF);
611 } else {
612 control = MEMORY_OBJECT_CONTROL_NULL;
613 }
614 if (recursed == 1)
615 ubc_unbusy(vp);
616 ubc_info_deallocate(uip);
617
618 } else {
619 if (recursed == 1)
620 ubc_unbusy(vp);
621 }
622
623 return (control);
624 }
625
626 /* Set the pager */
627 int
628 ubc_setpager(struct vnode *vp, memory_object_t pager)
629 {
630 struct ubc_info *uip;
631
632 uip = vp->v_ubcinfo;
633
634 if (UBCINVALID(vp))
635 return (0);
636
637 uip->ui_pager = pager;
638 return (1);
639 }
640
641 int
642 ubc_setflags(struct vnode * vp, int flags)
643 {
644 struct ubc_info *uip;
645
646 if (UBCINVALID(vp))
647 return (0);
648
649 uip = vp->v_ubcinfo;
650
651 SET(uip->ui_flags, flags);
652
653 return (1);
654 }
655
656 int
657 ubc_clearflags(struct vnode * vp, int flags)
658 {
659 struct ubc_info *uip;
660
661 if (UBCINVALID(vp))
662 return (0);
663
664 uip = vp->v_ubcinfo;
665
666 CLR(uip->ui_flags, flags);
667
668 return (1);
669 }
670
671
672 int
673 ubc_issetflags(struct vnode * vp, int flags)
674 {
675 struct ubc_info *uip;
676
677 if (UBCINVALID(vp))
678 return (0);
679
680 uip = vp->v_ubcinfo;
681
682 return (ISSET(uip->ui_flags, flags));
683 }
684
685 off_t
686 ubc_blktooff(struct vnode *vp, daddr_t blkno)
687 {
688 off_t file_offset;
689 int error;
690
691 if (UBCINVALID(vp))
692 return ((off_t)-1);
693
694 error = VOP_BLKTOOFF(vp, blkno, &file_offset);
695 if (error)
696 file_offset = -1;
697
698 return (file_offset);
699 }
700
701 daddr_t
702 ubc_offtoblk(struct vnode *vp, off_t offset)
703 {
704 daddr_t blkno;
705 int error = 0;
706
707 if (UBCINVALID(vp)) {
708 return ((daddr_t)-1);
709 }
710
711 error = VOP_OFFTOBLK(vp, offset, &blkno);
712 if (error)
713 blkno = -1;
714
715 return (blkno);
716 }
717
718 /*
719 * Cause the file data in VM to be pushed out to the storage
720 * it also causes all currently valid pages to be released
721 * returns 1 on success, 0 on failure
722 */
723 int
724 ubc_clean(struct vnode *vp, int invalidate)
725 {
726 off_t size;
727 struct ubc_info *uip;
728 memory_object_control_t control;
729 kern_return_t kret;
730 int flags = 0;
731
732 if (UBCINVALID(vp))
733 return (0);
734
735 if (!UBCINFOEXISTS(vp))
736 return (0);
737
738 /*
739 * if invalidate was requested, write dirty data and then discard
740 * the resident pages
741 */
742 if (invalidate)
743 flags = (MEMORY_OBJECT_DATA_FLUSH | MEMORY_OBJECT_DATA_NO_CHANGE);
744
745 uip = vp->v_ubcinfo;
746 size = uip->ui_size; /* call ubc_getsize() ??? */
747
748 control = uip->ui_control;
749 assert(control);
750
751 cluster_release(vp);
752 vp->v_clen = 0;
753
754 /* Write the dirty data in the file and discard cached pages */
755 kret = memory_object_lock_request(control,
756 (memory_object_offset_t)0,
757 (memory_object_size_t)round_page_64(size),
758 MEMORY_OBJECT_RETURN_ALL, flags,
759 VM_PROT_NO_CHANGE);
760
761 if (kret != KERN_SUCCESS)
762 printf("ubc_clean: clean failed (error = %d)\n", kret);
763
764 return ((kret == KERN_SUCCESS) ? 1 : 0);
765 }
766
767 /*
768 * Cause the file data in VM to be pushed out to the storage
769 * currently valid pages are NOT invalidated
770 * returns 1 on success, 0 on failure
771 */
772 int
773 ubc_pushdirty(struct vnode *vp)
774 {
775 off_t size;
776 struct ubc_info *uip;
777 memory_object_control_t control;
778 kern_return_t kret;
779
780 if (UBCINVALID(vp))
781 return (0);
782
783 if (!UBCINFOEXISTS(vp))
784 return (0);
785
786 uip = vp->v_ubcinfo;
787 size = uip->ui_size; /* call ubc_getsize() ??? */
788
789 control = uip->ui_control;
790 assert(control);
791
792 vp->v_flag &= ~VHASDIRTY;
793 vp->v_clen = 0;
794
795 /* Write the dirty data in the file and discard cached pages */
796 kret = memory_object_lock_request(control,
797 (memory_object_offset_t)0,
798 (memory_object_size_t)round_page_64(size),
799 MEMORY_OBJECT_RETURN_DIRTY, FALSE,
800 VM_PROT_NO_CHANGE);
801
802 if (kret != KERN_SUCCESS)
803 printf("ubc_pushdirty: flush failed (error = %d)\n", kret);
804
805 return ((kret == KERN_SUCCESS) ? 1 : 0);
806 }
807
808 /*
809 * Cause the file data in VM to be pushed out to the storage
810 * currently valid pages are NOT invalidated
811 * returns 1 on success, 0 on failure
812 */
813 int
814 ubc_pushdirty_range(struct vnode *vp, off_t offset, off_t size)
815 {
816 struct ubc_info *uip;
817 memory_object_control_t control;
818 kern_return_t kret;
819
820 if (UBCINVALID(vp))
821 return (0);
822
823 if (!UBCINFOEXISTS(vp))
824 return (0);
825
826 uip = vp->v_ubcinfo;
827
828 control = uip->ui_control;
829 assert(control);
830
831 /* Write any dirty pages in the requested range of the file: */
832 kret = memory_object_lock_request(control,
833 (memory_object_offset_t)offset,
834 (memory_object_size_t)round_page_64(size),
835 MEMORY_OBJECT_RETURN_DIRTY, FALSE,
836 VM_PROT_NO_CHANGE);
837
838 if (kret != KERN_SUCCESS)
839 printf("ubc_pushdirty_range: flush failed (error = %d)\n", kret);
840
841 return ((kret == KERN_SUCCESS) ? 1 : 0);
842 }
843
844 /*
845 * Make sure the vm object does not vanish
846 * returns 1 if the hold count was incremented
847 * returns 0 if the hold count was not incremented
848 * This return value should be used to balance
849 * ubc_hold() and ubc_rele().
850 */
851 int
852 ubc_hold(struct vnode *vp)
853 {
854 struct ubc_info *uip;
855 int recursed;
856 memory_object_control_t object;
857
858 retry:
859
860 if (UBCINVALID(vp))
861 return (0);
862
863 ubc_lock(vp);
864 if (ISSET(vp->v_flag, VUINIT)) {
865 /*
866 * other thread is not done initializing this
867 * yet, wait till it's done and try again
868 */
869 while (ISSET(vp->v_flag, VUINIT)) {
870 SET(vp->v_flag, VUWANT); /* XXX overloaded! */
871 ubc_unlock(vp);
872 (void) tsleep((caddr_t)vp, PINOD, "ubchold", 0);
873 ubc_lock(vp);
874 }
875 ubc_unlock(vp);
876 goto retry;
877 }
878 ubc_unlock(vp);
879
880 if ((recursed = ubc_busy(vp)) == 0) {
881 /* must be invalid or dying vnode */
882 assert(UBCINVALID(vp) ||
883 ((vp->v_flag & VXLOCK) || (vp->v_flag & VTERMINATE)));
884 return (0);
885 }
886
887 uip = vp->v_ubcinfo;
888 assert(uip->ui_control != MEMORY_OBJECT_CONTROL_NULL);
889
890 ubc_lock(vp);
891 uip->ui_refcount++;
892 ubc_unlock(vp);
893
894 if (!ISSET(uip->ui_flags, UI_HASOBJREF)) {
895 if (memory_object_recover_named(uip->ui_control, TRUE)
896 != KERN_SUCCESS) {
897 if (recursed == 1)
898 ubc_unbusy(vp);
899 ubc_info_deallocate(uip);
900 return (0);
901 }
902 SET(uip->ui_flags, UI_HASOBJREF);
903 }
904 if (recursed == 1)
905 ubc_unbusy(vp);
906
907 assert(uip->ui_refcount > 0);
908
909 return (1);
910 }
911
912 /*
913 * Drop the holdcount.
914 * release the reference on the vm object if the this is "uncached"
915 * ubc_info.
916 */
917 void
918 ubc_rele(struct vnode *vp)
919 {
920 struct ubc_info *uip;
921
922 if (UBCINVALID(vp))
923 return;
924
925 if (!UBCINFOEXISTS(vp)) {
926 /* nothing more to do for a dying vnode */
927 if ((vp->v_flag & VXLOCK) || (vp->v_flag & VTERMINATE))
928 return;
929 panic("ubc_rele: can not");
930 }
931
932 uip = vp->v_ubcinfo;
933
934 if (uip->ui_refcount == 1)
935 panic("ubc_rele: ui_refcount");
936
937 --uip->ui_refcount;
938
939 if ((uip->ui_refcount == 1)
940 && ISSET(uip->ui_flags, UI_DONTCACHE))
941 (void) ubc_release_named(vp);
942
943 return;
944 }
945
946 /*
947 * The vnode is mapped explicitly, mark it so.
948 */
949 __private_extern__ void
950 ubc_map(struct vnode *vp)
951 {
952 struct ubc_info *uip;
953
954 if (UBCINVALID(vp))
955 return;
956
957 if (!UBCINFOEXISTS(vp))
958 return;
959
960 ubc_lock(vp);
961 uip = vp->v_ubcinfo;
962
963 SET(uip->ui_flags, UI_WASMAPPED);
964 uip->ui_mapped = 1;
965 ubc_unlock(vp);
966
967 return;
968 }
969
970 /*
971 * Release the memory object reference on the vnode
972 * only if it is not in use
973 * Return 1 if the reference was released, 0 otherwise.
974 */
975 int
976 ubc_release_named(struct vnode *vp)
977 {
978 struct ubc_info *uip;
979 int recursed;
980 memory_object_control_t control;
981 kern_return_t kret = KERN_FAILURE;
982
983 if (UBCINVALID(vp))
984 return (0);
985
986 if ((recursed = ubc_busy(vp)) == 0)
987 return (0);
988 uip = vp->v_ubcinfo;
989
990 /* can not release held or mapped vnodes */
991 if (ISSET(uip->ui_flags, UI_HASOBJREF) &&
992 (uip->ui_refcount == 1) && !uip->ui_mapped) {
993 control = uip->ui_control;
994 assert(control);
995
996 // XXXdbg
997 if (vp->v_flag & VDELETED) {
998 ubc_setsize(vp, (off_t)0);
999 }
1000
1001 CLR(uip->ui_flags, UI_HASOBJREF);
1002 kret = memory_object_release_name(control,
1003 MEMORY_OBJECT_RESPECT_CACHE);
1004 }
1005
1006 if (recursed == 1)
1007 ubc_unbusy(vp);
1008 return ((kret != KERN_SUCCESS) ? 0 : 1);
1009 }
1010
1011 /*
1012 * This function used to called by extensions directly. Some may
1013 * still exist with this behavior. In those cases, we will do the
1014 * release as part of reclaiming or cleaning the vnode. We don't
1015 * need anything explicit - so just stub this out until those callers
1016 * get cleaned up.
1017 */
1018 int
1019 ubc_release(
1020 struct vnode *vp)
1021 {
1022 return 0;
1023 }
1024
1025 /*
1026 * destroy the named reference for a given vnode
1027 */
1028 __private_extern__ int
1029 ubc_destroy_named(
1030 struct vnode *vp)
1031 {
1032 memory_object_control_t control;
1033 struct proc *p;
1034 struct ubc_info *uip;
1035 kern_return_t kret;
1036
1037 /*
1038 * We may already have had the object terminated
1039 * and the ubcinfo released as a side effect of
1040 * some earlier processing. If so, pretend we did
1041 * it, because it probably was a result of our
1042 * efforts.
1043 */
1044 if (!UBCINFOEXISTS(vp))
1045 return (1);
1046
1047 uip = vp->v_ubcinfo;
1048
1049 /* can not destroy held vnodes */
1050 if (uip->ui_refcount > 1)
1051 return (0);
1052
1053 /*
1054 * Terminate the memory object.
1055 * memory_object_destroy() will result in
1056 * vnode_pager_no_senders().
1057 * That will release the pager reference
1058 * and the vnode will move to the free list.
1059 */
1060 control = ubc_getobject(vp, UBC_HOLDOBJECT);
1061 if (control != MEMORY_OBJECT_CONTROL_NULL) {
1062
1063 if (ISSET(vp->v_flag, VTERMINATE))
1064 panic("ubc_destroy_named: already teminating");
1065 SET(vp->v_flag, VTERMINATE);
1066
1067 kret = memory_object_destroy(control, 0);
1068 if (kret != KERN_SUCCESS)
1069 return (0);
1070
1071 /*
1072 * memory_object_destroy() is asynchronous
1073 * with respect to vnode_pager_no_senders().
1074 * wait for vnode_pager_no_senders() to clear
1075 * VTERMINATE
1076 */
1077 while (ISSET(vp->v_flag, VTERMINATE)) {
1078 SET(vp->v_flag, VTERMWANT);
1079 (void)tsleep((caddr_t)&vp->v_ubcinfo,
1080 PINOD, "ubc_destroy_named", 0);
1081 }
1082 }
1083 return (1);
1084 }
1085
1086
1087 /*
1088 * Invalidate a range in the memory object that backs this
1089 * vnode. The offset is truncated to the page boundary and the
1090 * size is adjusted to include the last page in the range.
1091 */
1092 int
1093 ubc_invalidate(struct vnode *vp, off_t offset, size_t size)
1094 {
1095 struct ubc_info *uip;
1096 memory_object_control_t control;
1097 kern_return_t kret;
1098 off_t toff;
1099 size_t tsize;
1100
1101 if (UBCINVALID(vp))
1102 return (0);
1103
1104 if (!UBCINFOEXISTS(vp))
1105 return (0);
1106
1107 toff = trunc_page_64(offset);
1108 tsize = (size_t)(round_page_64(offset+size) - toff);
1109 uip = vp->v_ubcinfo;
1110 control = uip->ui_control;
1111 assert(control);
1112
1113 /* invalidate pages in the range requested */
1114 kret = memory_object_lock_request(control,
1115 (memory_object_offset_t)toff,
1116 (memory_object_size_t)tsize,
1117 MEMORY_OBJECT_RETURN_NONE,
1118 (MEMORY_OBJECT_DATA_NO_CHANGE| MEMORY_OBJECT_DATA_FLUSH),
1119 VM_PROT_NO_CHANGE);
1120 if (kret != KERN_SUCCESS)
1121 printf("ubc_invalidate: invalidate failed (error = %d)\n", kret);
1122
1123 return ((kret == KERN_SUCCESS) ? 1 : 0);
1124 }
1125
1126 /*
1127 * Find out whether a vnode is in use by UBC
1128 * Returns 1 if file is in use by UBC, 0 if not
1129 */
1130 int
1131 ubc_isinuse(struct vnode *vp, int busycount)
1132 {
1133 if (!UBCINFOEXISTS(vp))
1134 return (0);
1135
1136 if (busycount == 0) {
1137 printf("ubc_isinuse: called without a valid reference"
1138 ": v_tag = %d\v", vp->v_tag);
1139 vprint("ubc_isinuse", vp);
1140 return (0);
1141 }
1142
1143 if (vp->v_usecount > busycount+1)
1144 return (1);
1145
1146 if ((vp->v_usecount == busycount+1)
1147 && (vp->v_ubcinfo->ui_mapped == 1))
1148 return (1);
1149 else
1150 return (0);
1151 }
1152
1153 /*
1154 * The backdoor routine to clear the ui_mapped.
1155 * MUST only be called by the VM
1156 *
1157 * Note that this routine is not called under funnel. There are numerous
1158 * things about the calling sequence that make this work on SMP.
1159 * Any code change in those paths can break this.
1160 *
1161 */
1162 __private_extern__ void
1163 ubc_unmap(struct vnode *vp)
1164 {
1165 struct ubc_info *uip;
1166 boolean_t funnel_state;
1167
1168 if (UBCINVALID(vp))
1169 return;
1170
1171 if (!UBCINFOEXISTS(vp))
1172 return;
1173
1174 ubc_lock(vp);
1175 uip = vp->v_ubcinfo;
1176 uip->ui_mapped = 0;
1177 if ((uip->ui_refcount > 1) || !ISSET(uip->ui_flags, UI_DONTCACHE)) {
1178 ubc_unlock(vp);
1179 return;
1180 }
1181 ubc_unlock(vp);
1182
1183 funnel_state = thread_funnel_set(kernel_flock, TRUE);
1184 (void) ubc_release_named(vp);
1185 (void) thread_funnel_set(kernel_flock, funnel_state);
1186 }
1187
1188 kern_return_t
1189 ubc_page_op(
1190 struct vnode *vp,
1191 off_t f_offset,
1192 int ops,
1193 ppnum_t *phys_entryp,
1194 int *flagsp)
1195 {
1196 memory_object_control_t control;
1197
1198 control = ubc_getobject(vp, UBC_FLAGS_NONE);
1199 if (control == MEMORY_OBJECT_CONTROL_NULL)
1200 return KERN_INVALID_ARGUMENT;
1201
1202 return (memory_object_page_op(control,
1203 (memory_object_offset_t)f_offset,
1204 ops,
1205 phys_entryp,
1206 flagsp));
1207 }
1208
1209 __private_extern__ kern_return_t
1210 ubc_page_op_with_control(
1211 memory_object_control_t control,
1212 off_t f_offset,
1213 int ops,
1214 ppnum_t *phys_entryp,
1215 int *flagsp)
1216 {
1217 return (memory_object_page_op(control,
1218 (memory_object_offset_t)f_offset,
1219 ops,
1220 phys_entryp,
1221 flagsp));
1222 }
1223
1224 kern_return_t
1225 ubc_range_op(
1226 struct vnode *vp,
1227 off_t f_offset_beg,
1228 off_t f_offset_end,
1229 int ops,
1230 int *range)
1231 {
1232 memory_object_control_t control;
1233
1234 control = ubc_getobject(vp, UBC_FLAGS_NONE);
1235 if (control == MEMORY_OBJECT_CONTROL_NULL)
1236 return KERN_INVALID_ARGUMENT;
1237
1238 return (memory_object_range_op(control,
1239 (memory_object_offset_t)f_offset_beg,
1240 (memory_object_offset_t)f_offset_end,
1241 ops,
1242 range));
1243 }
1244
1245 kern_return_t
1246 ubc_create_upl(
1247 struct vnode *vp,
1248 off_t f_offset,
1249 long bufsize,
1250 upl_t *uplp,
1251 upl_page_info_t **plp,
1252 int uplflags)
1253 {
1254 memory_object_control_t control;
1255 int count;
1256 int ubcflags;
1257 off_t file_offset;
1258 kern_return_t kr;
1259
1260 if (bufsize & 0xfff)
1261 return KERN_INVALID_ARGUMENT;
1262
1263 if (uplflags & UPL_FOR_PAGEOUT) {
1264 uplflags &= ~UPL_FOR_PAGEOUT;
1265 ubcflags = UBC_FOR_PAGEOUT;
1266 } else
1267 ubcflags = UBC_FLAGS_NONE;
1268
1269 control = ubc_getobject(vp, ubcflags);
1270 if (control == MEMORY_OBJECT_CONTROL_NULL)
1271 return KERN_INVALID_ARGUMENT;
1272
1273 if (uplflags & UPL_WILL_BE_DUMPED) {
1274 uplflags &= ~UPL_WILL_BE_DUMPED;
1275 uplflags |= (UPL_NO_SYNC|UPL_SET_INTERNAL);
1276 } else
1277 uplflags |= (UPL_NO_SYNC|UPL_CLEAN_IN_PLACE|UPL_SET_INTERNAL);
1278 count = 0;
1279 kr = memory_object_upl_request(control, f_offset, bufsize,
1280 uplp, NULL, &count, uplflags);
1281 if (plp != NULL)
1282 *plp = UPL_GET_INTERNAL_PAGE_LIST(*uplp);
1283 return kr;
1284 }
1285
1286
1287 kern_return_t
1288 ubc_upl_map(
1289 upl_t upl,
1290 vm_offset_t *dst_addr)
1291 {
1292 return (vm_upl_map(kernel_map, upl, dst_addr));
1293 }
1294
1295
1296 kern_return_t
1297 ubc_upl_unmap(
1298 upl_t upl)
1299 {
1300 return(vm_upl_unmap(kernel_map, upl));
1301 }
1302
1303 kern_return_t
1304 ubc_upl_commit(
1305 upl_t upl)
1306 {
1307 upl_page_info_t *pl;
1308 kern_return_t kr;
1309
1310 pl = UPL_GET_INTERNAL_PAGE_LIST(upl);
1311 kr = upl_commit(upl, pl, MAX_UPL_TRANSFER);
1312 upl_deallocate(upl);
1313 return kr;
1314 }
1315
1316
1317 kern_return_t
1318 ubc_upl_commit_range(
1319 upl_t upl,
1320 vm_offset_t offset,
1321 vm_size_t size,
1322 int flags)
1323 {
1324 upl_page_info_t *pl;
1325 boolean_t empty;
1326 kern_return_t kr;
1327
1328 if (flags & UPL_COMMIT_FREE_ON_EMPTY)
1329 flags |= UPL_COMMIT_NOTIFY_EMPTY;
1330
1331 pl = UPL_GET_INTERNAL_PAGE_LIST(upl);
1332
1333 kr = upl_commit_range(upl, offset, size, flags,
1334 pl, MAX_UPL_TRANSFER, &empty);
1335
1336 if((flags & UPL_COMMIT_FREE_ON_EMPTY) && empty)
1337 upl_deallocate(upl);
1338
1339 return kr;
1340 }
1341
1342 kern_return_t
1343 ubc_upl_abort_range(
1344 upl_t upl,
1345 vm_offset_t offset,
1346 vm_size_t size,
1347 int abort_flags)
1348 {
1349 kern_return_t kr;
1350 boolean_t empty = FALSE;
1351
1352 if (abort_flags & UPL_ABORT_FREE_ON_EMPTY)
1353 abort_flags |= UPL_ABORT_NOTIFY_EMPTY;
1354
1355 kr = upl_abort_range(upl, offset, size, abort_flags, &empty);
1356
1357 if((abort_flags & UPL_ABORT_FREE_ON_EMPTY) && empty)
1358 upl_deallocate(upl);
1359
1360 return kr;
1361 }
1362
1363 kern_return_t
1364 ubc_upl_abort(
1365 upl_t upl,
1366 int abort_type)
1367 {
1368 kern_return_t kr;
1369
1370 kr = upl_abort(upl, abort_type);
1371 upl_deallocate(upl);
1372 return kr;
1373 }
1374
1375 upl_page_info_t *
1376 ubc_upl_pageinfo(
1377 upl_t upl)
1378 {
1379 return (UPL_GET_INTERNAL_PAGE_LIST(upl));
1380 }