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