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