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