]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/ubc_subr.c
xnu-344.21.74.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 *
d7e50217 6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
1c79356b 7 *
d7e50217
A
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
1c79356b
A
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
d7e50217
A
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.
1c79356b
A
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 *
0b4e3aa0
A
32 * Caller of UBC functions MUST have a valid reference on the vnode.
33 *
1c79356b
A
34 */
35
0b4e3aa0 36#undef DIAGNOSTIC
1c79356b
A
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) \
9bccf70c 61 ((void) ((cond) ? 0 : panic("%s:%d (%s)", __FILE__, __LINE__, # cond)))
1c79356b
A
62#else
63#include <kern/assert.h>
64#endif /* DIAGNOSTIC */
65
66struct zone *ubc_info_zone;
67
0b4e3aa0
A
68/* lock for changes to struct UBC */
69static __inline__ void
70ubc_lock(struct vnode *vp)
1c79356b 71{
0b4e3aa0
A
72 /* For now, just use the v_interlock */
73 simple_lock(&vp->v_interlock);
74}
1c79356b 75
0b4e3aa0
A
76/* unlock */
77static __inline__ void
78ubc_unlock(struct vnode *vp)
79{
80 /* For now, just use the v_interlock */
81 simple_unlock(&vp->v_interlock);
1c79356b
A
82}
83
b4c24cb9
A
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 */
93static int
94ubc_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
121static void
122ubc_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
1c79356b
A
140/*
141 * Initialization of the zone for Unified Buffer Cache.
142 */
0b4e3aa0 143__private_extern__ void
1c79356b
A
144ubc_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 */
157int
158ubc_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;
0b4e3aa0 166 memory_object_control_t control;
1c79356b 167
0b4e3aa0
A
168 if (!UBCISVALID(vp))
169 return (EINVAL);
1c79356b
A
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);
0b4e3aa0
A
193 uip->ui_pager = MEMORY_OBJECT_NULL;
194 uip->ui_control = MEMORY_OBJECT_CONTROL_NULL;
195 uip->ui_flags = UI_INITED;
1c79356b
A
196 uip->ui_vnode = vp;
197 uip->ui_ucred = NOCRED;
0b4e3aa0
A
198 uip->ui_refcount = 1;
199 uip->ui_size = 0;
200 uip->ui_mapped = 0;
b4c24cb9 201 uip->ui_owner = (void *)NULL;
0b4e3aa0 202 ubc_lock(vp);
1c79356b 203 }
0b4e3aa0
A
204#if DIAGNOSTIC
205 else
206 Debugger("ubc_info_init: already");
207#endif /* DIAGNOSTIC */
1c79356b
A
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);
0b4e3aa0 223 ubc_setpager(vp, pager);
1c79356b
A
224
225 /*
0b4e3aa0
A
226 * Note: We can not use VOP_GETATTR() to get accurate
227 * value of ui_size. Thanks to NFS.
1c79356b
A
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
1c79356b 233 /*
0b4e3aa0
A
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.
1c79356b 240 */
0b4e3aa0
A
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);
1c79356b 246
0b4e3aa0
A
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 */
1c79356b 250 /* create a pager reference on the vnode */
0b4e3aa0 251 error = vnode_pager_vget(vp);
1c79356b 252 if (error)
0b4e3aa0 253 panic("ubc_info_init: vnode_pager_vget error = %d", error);
1c79356b
A
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
261done:
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
0b4e3aa0 270 return (error);
1c79356b
A
271}
272
273/* Free the ubc_info */
0b4e3aa0
A
274static void
275ubc_info_free(struct ubc_info *uip)
1c79356b 276{
1c79356b
A
277 struct ucred *credp;
278
1c79356b
A
279 credp = uip->ui_ucred;
280 if (credp != NOCRED) {
281 uip->ui_ucred = NOCRED;
282 crfree(credp);
283 }
0b4e3aa0
A
284
285 if (uip->ui_control != MEMORY_OBJECT_CONTROL_NULL)
286 memory_object_control_deallocate(uip->ui_control);
287
1c79356b
A
288 zfree(ubc_info_zone, (vm_offset_t)uip);
289 return;
290}
291
0b4e3aa0
A
292void
293ubc_info_deallocate(struct ubc_info *uip)
294{
b4c24cb9 295
0b4e3aa0
A
296 assert(uip->ui_refcount > 0);
297
b4c24cb9
A
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
0b4e3aa0 307 ubc_info_free(uip);
b4c24cb9 308 }
0b4e3aa0
A
309}
310
1c79356b
A
311/*
312 * Communicate with VM the size change of the file
313 * returns 1 on success, 0 on failure
314 */
315int
316ubc_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;
0b4e3aa0 321 memory_object_control_t control;
1c79356b 322 kern_return_t kret;
1c79356b 323
1c79356b 324 assert(nsize >= (off_t)0);
1c79356b
A
325
326 if (UBCINVALID(vp))
0b4e3aa0 327 return (0);
1c79356b
A
328
329 if (!UBCINFOEXISTS(vp))
0b4e3aa0 330 return (0);
1c79356b
A
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 */
0b4e3aa0 338 return (1); /* return success */
1c79356b
A
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
1c79356b
A
348 lastpg = trunc_page_64(nsize);
349 olastpgend = round_page_64(osize);
0b4e3aa0
A
350 control = uip->ui_control;
351 assert(control);
1c79356b
A
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) {
1c79356b 359 /* invalidate last page and old contents beyond nsize */
0b4e3aa0
A
360 kret = memory_object_lock_request(control,
361 (memory_object_offset_t)lastpg,
1c79356b 362 (memory_object_size_t)(olastpgend - lastpg),
0b4e3aa0
A
363 MEMORY_OBJECT_RETURN_NONE, MEMORY_OBJECT_DATA_FLUSH,
364 VM_PROT_NO_CHANGE);
1c79356b
A
365 if (kret != KERN_SUCCESS)
366 printf("ubc_setsize: invalidate failed (error = %d)\n", kret);
367
1c79356b
A
368 return ((kret == KERN_SUCCESS) ? 1 : 0);
369 }
370
1c79356b 371 /* flush the last page */
0b4e3aa0
A
372 kret = memory_object_lock_request(control,
373 (memory_object_offset_t)lastpg,
1c79356b 374 PAGE_SIZE_64,
0b4e3aa0
A
375 MEMORY_OBJECT_RETURN_DIRTY, FALSE,
376 VM_PROT_NO_CHANGE);
1c79356b
A
377
378 if (kret == KERN_SUCCESS) {
1c79356b 379 /* invalidate last page and old contents beyond nsize */
0b4e3aa0
A
380 kret = memory_object_lock_request(control,
381 (memory_object_offset_t)lastpg,
1c79356b 382 (memory_object_size_t)(olastpgend - lastpg),
0b4e3aa0
A
383 MEMORY_OBJECT_RETURN_NONE, MEMORY_OBJECT_DATA_FLUSH,
384 VM_PROT_NO_CHANGE);
1c79356b
A
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
1c79356b
A
390 return ((kret == KERN_SUCCESS) ? 1 : 0);
391}
392
393/*
394 * Get the size of the file
1c79356b
A
395 */
396off_t
397ubc_getsize(struct vnode *vp)
398{
1c79356b
A
399 return (vp->v_ubcinfo->ui_size);
400}
401
1c79356b
A
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
1c79356b
A
406 */
407int
408ubc_uncache(struct vnode *vp)
409{
1c79356b
A
410 kern_return_t kret;
411 struct ubc_info *uip;
b4c24cb9 412 int recursed;
0b4e3aa0 413 memory_object_control_t control;
1c79356b 414 memory_object_perf_info_data_t perf;
1c79356b
A
415
416 if (!UBCINFOEXISTS(vp))
417 return (0);
418
b4c24cb9
A
419 if ((recursed = ubc_busy(vp)) == 0)
420 return (0);
421
1c79356b
A
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
0b4e3aa0
A
436 control = uip->ui_control;
437 assert(control);
1c79356b
A
438
439 perf.cluster_size = PAGE_SIZE; /* XXX use real cluster_size. */
440 perf.may_cache = FALSE;
0b4e3aa0 441 kret = memory_object_change_attributes(control,
1c79356b
A
442 MEMORY_OBJECT_PERFORMANCE_INFO,
443 (memory_object_info_t) &perf,
0b4e3aa0 444 MEMORY_OBJECT_PERF_INFO_COUNT);
1c79356b
A
445
446 if (kret != KERN_SUCCESS) {
0b4e3aa0 447 printf("ubc_uncache: memory_object_change_attributes_named "
1c79356b 448 "kret = %d", kret);
b4c24cb9
A
449 if (recursed == 1)
450 ubc_unbusy(vp);
1c79356b
A
451 return (0);
452 }
453
0b4e3aa0
A
454 ubc_release_named(vp);
455
b4c24cb9
A
456 if (recursed == 1)
457 ubc_unbusy(vp);
1c79356b
A
458 return (1);
459}
460
1c79356b
A
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 */
0b4e3aa0 466__private_extern__ int
1c79356b
A
467ubc_umount(struct mount *mp)
468{
469 struct proc *p = current_proc();
470 struct vnode *vp, *nvp;
471 int ret = 1;
472
473loop:
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)) {
0b4e3aa0
A
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 }
1c79356b
A
493 ret &= ubc_clean(vp, 0); /* do not invalidate */
494 ret &= ubc_uncache(vp);
0b4e3aa0 495 vrele(vp);
1c79356b
A
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 */
0b4e3aa0 508__private_extern__ void
1c79356b
A
509ubc_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 */
523struct ucred *
524ubc_getcred(struct vnode *vp)
525{
526 struct ubc_info *uip;
527
1c79356b
A
528 uip = vp->v_ubcinfo;
529
0b4e3aa0 530 if (UBCINVALID(vp))
1c79356b 531 return (NOCRED);
1c79356b
A
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 */
1c79356b
A
541int
542ubc_setcred(struct vnode *vp, struct proc *p)
543{
544 struct ubc_info *uip;
545 struct ucred *credp;
546
1c79356b
A
547 uip = vp->v_ubcinfo;
548
0b4e3aa0 549 if (UBCINVALID(vp))
1c79356b 550 return (0);
1c79356b
A
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 */
0b4e3aa0 562__private_extern__ memory_object_t
1c79356b
A
563ubc_getpager(struct vnode *vp)
564{
565 struct ubc_info *uip;
566
1c79356b
A
567 uip = vp->v_ubcinfo;
568
0b4e3aa0 569 if (UBCINVALID(vp))
1c79356b 570 return (0);
1c79356b
A
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.
1c79356b
A
579 * If hold was requested create an object reference of one does not
580 * exist already.
581 */
582
0b4e3aa0
A
583memory_object_control_t
584ubc_getobject(struct vnode *vp, int flags)
1c79356b
A
585{
586 struct ubc_info *uip;
b4c24cb9 587 int recursed;
0b4e3aa0 588 memory_object_control_t control;
1c79356b 589
0b4e3aa0
A
590 if (UBCINVALID(vp))
591 return (0);
1c79356b 592
d7e50217
A
593 if (flags & UBC_FOR_PAGEOUT)
594 return(vp->v_ubcinfo->ui_control);
595
b4c24cb9
A
596 if ((recursed = ubc_busy(vp)) == 0)
597 return (0);
1c79356b 598
b4c24cb9 599 uip = vp->v_ubcinfo;
0b4e3aa0 600 control = uip->ui_control;
1c79356b 601
0b4e3aa0 602 if ((flags & UBC_HOLDOBJECT) && (!ISSET(uip->ui_flags, UI_HASOBJREF))) {
1c79356b 603
0b4e3aa0
A
604 /*
605 * Take a temporary reference on the ubc info so that it won't go
606 * away during our recovery attempt.
607 */
b4c24cb9 608 ubc_lock(vp);
0b4e3aa0
A
609 uip->ui_refcount++;
610 ubc_unlock(vp);
611 if (memory_object_recover_named(control, TRUE) == KERN_SUCCESS) {
1c79356b 612 SET(uip->ui_flags, UI_HASOBJREF);
0b4e3aa0
A
613 } else {
614 control = MEMORY_OBJECT_CONTROL_NULL;
1c79356b 615 }
b4c24cb9
A
616 if (recursed == 1)
617 ubc_unbusy(vp);
0b4e3aa0 618 ubc_info_deallocate(uip);
1c79356b 619
0b4e3aa0 620 } else {
b4c24cb9
A
621 if (recursed == 1)
622 ubc_unbusy(vp);
1c79356b
A
623 }
624
0b4e3aa0 625 return (control);
1c79356b
A
626}
627
628/* Set the pager */
629int
0b4e3aa0 630ubc_setpager(struct vnode *vp, memory_object_t pager)
1c79356b
A
631{
632 struct ubc_info *uip;
633
1c79356b
A
634 uip = vp->v_ubcinfo;
635
0b4e3aa0 636 if (UBCINVALID(vp))
1c79356b 637 return (0);
1c79356b
A
638
639 uip->ui_pager = pager;
640 return (1);
641}
642
643int
644ubc_setflags(struct vnode * vp, int flags)
645{
646 struct ubc_info *uip;
647
0b4e3aa0
A
648 if (UBCINVALID(vp))
649 return (0);
1c79356b
A
650
651 uip = vp->v_ubcinfo;
652
1c79356b
A
653 SET(uip->ui_flags, flags);
654
0b4e3aa0 655 return (1);
1c79356b
A
656}
657
658int
659ubc_clearflags(struct vnode * vp, int flags)
660{
661 struct ubc_info *uip;
662
0b4e3aa0
A
663 if (UBCINVALID(vp))
664 return (0);
1c79356b
A
665
666 uip = vp->v_ubcinfo;
667
1c79356b
A
668 CLR(uip->ui_flags, flags);
669
0b4e3aa0 670 return (1);
1c79356b
A
671}
672
673
674int
675ubc_issetflags(struct vnode * vp, int flags)
676{
677 struct ubc_info *uip;
678
0b4e3aa0
A
679 if (UBCINVALID(vp))
680 return (0);
1c79356b
A
681
682 uip = vp->v_ubcinfo;
683
0b4e3aa0 684 return (ISSET(uip->ui_flags, flags));
1c79356b
A
685}
686
687off_t
688ubc_blktooff(struct vnode *vp, daddr_t blkno)
689{
690 off_t file_offset;
691 int error;
692
0b4e3aa0 693 if (UBCINVALID(vp))
1c79356b 694 return ((off_t)-1);
1c79356b
A
695
696 error = VOP_BLKTOOFF(vp, blkno, &file_offset);
697 if (error)
698 file_offset = -1;
699
700 return (file_offset);
701}
0b4e3aa0 702
1c79356b
A
703daddr_t
704ubc_offtoblk(struct vnode *vp, off_t offset)
705{
706 daddr_t blkno;
0b4e3aa0 707 int error = 0;
1c79356b 708
1c79356b
A
709 if (UBCINVALID(vp)) {
710 return ((daddr_t)-1);
711 }
712
713 error = VOP_OFFTOBLK(vp, offset, &blkno);
714 if (error)
715 blkno = -1;
716
717 return (blkno);
718}
719
720/*
721 * Cause the file data in VM to be pushed out to the storage
722 * it also causes all currently valid pages to be released
723 * returns 1 on success, 0 on failure
724 */
725int
726ubc_clean(struct vnode *vp, int invalidate)
727{
728 off_t size;
729 struct ubc_info *uip;
0b4e3aa0 730 memory_object_control_t control;
1c79356b
A
731 kern_return_t kret;
732 int flags = 0;
1c79356b
A
733
734 if (UBCINVALID(vp))
0b4e3aa0 735 return (0);
1c79356b
A
736
737 if (!UBCINFOEXISTS(vp))
0b4e3aa0 738 return (0);
1c79356b
A
739
740 /*
741 * if invalidate was requested, write dirty data and then discard
742 * the resident pages
743 */
744 if (invalidate)
745 flags = (MEMORY_OBJECT_DATA_FLUSH | MEMORY_OBJECT_DATA_NO_CHANGE);
746
1c79356b
A
747 uip = vp->v_ubcinfo;
748 size = uip->ui_size; /* call ubc_getsize() ??? */
749
0b4e3aa0
A
750 control = uip->ui_control;
751 assert(control);
1c79356b
A
752
753 vp->v_flag &= ~VHASDIRTY;
754 vp->v_clen = 0;
755
756 /* Write the dirty data in the file and discard cached pages */
0b4e3aa0
A
757 kret = memory_object_lock_request(control,
758 (memory_object_offset_t)0,
1c79356b
A
759 (memory_object_size_t)round_page_64(size),
760 MEMORY_OBJECT_RETURN_ALL, flags,
0b4e3aa0 761 VM_PROT_NO_CHANGE);
1c79356b 762
0b4e3aa0 763 if (kret != KERN_SUCCESS)
1c79356b 764 printf("ubc_clean: clean failed (error = %d)\n", kret);
1c79356b
A
765
766 return ((kret == KERN_SUCCESS) ? 1 : 0);
767}
768
769/*
770 * Cause the file data in VM to be pushed out to the storage
771 * currently valid pages are NOT invalidated
772 * returns 1 on success, 0 on failure
773 */
774int
775ubc_pushdirty(struct vnode *vp)
776{
777 off_t size;
778 struct ubc_info *uip;
0b4e3aa0 779 memory_object_control_t control;
1c79356b 780 kern_return_t kret;
1c79356b
A
781
782 if (UBCINVALID(vp))
0b4e3aa0 783 return (0);
1c79356b
A
784
785 if (!UBCINFOEXISTS(vp))
0b4e3aa0 786 return (0);
1c79356b 787
1c79356b
A
788 uip = vp->v_ubcinfo;
789 size = uip->ui_size; /* call ubc_getsize() ??? */
790
0b4e3aa0
A
791 control = uip->ui_control;
792 assert(control);
1c79356b
A
793
794 vp->v_flag &= ~VHASDIRTY;
795 vp->v_clen = 0;
796
797 /* Write the dirty data in the file and discard cached pages */
0b4e3aa0
A
798 kret = memory_object_lock_request(control,
799 (memory_object_offset_t)0,
1c79356b 800 (memory_object_size_t)round_page_64(size),
0b4e3aa0
A
801 MEMORY_OBJECT_RETURN_DIRTY, FALSE,
802 VM_PROT_NO_CHANGE);
1c79356b 803
0b4e3aa0 804 if (kret != KERN_SUCCESS)
1c79356b 805 printf("ubc_pushdirty: flush failed (error = %d)\n", kret);
1c79356b 806
0b4e3aa0
A
807 return ((kret == KERN_SUCCESS) ? 1 : 0);
808}
809
810/*
811 * Cause the file data in VM to be pushed out to the storage
812 * currently valid pages are NOT invalidated
813 * returns 1 on success, 0 on failure
814 */
815int
816ubc_pushdirty_range(struct vnode *vp, off_t offset, off_t size)
817{
818 struct ubc_info *uip;
819 memory_object_control_t control;
820 kern_return_t kret;
821
822 if (UBCINVALID(vp))
823 return (0);
824
825 if (!UBCINFOEXISTS(vp))
826 return (0);
827
828 uip = vp->v_ubcinfo;
829
830 control = uip->ui_control;
831 assert(control);
832
833 /* Write any dirty pages in the requested range of the file: */
834 kret = memory_object_lock_request(control,
835 (memory_object_offset_t)offset,
836 (memory_object_size_t)round_page_64(size),
837 MEMORY_OBJECT_RETURN_DIRTY, FALSE,
838 VM_PROT_NO_CHANGE);
839
840 if (kret != KERN_SUCCESS)
841 printf("ubc_pushdirty_range: flush failed (error = %d)\n", kret);
1c79356b
A
842
843 return ((kret == KERN_SUCCESS) ? 1 : 0);
844}
845
846/*
847 * Make sure the vm object does not vanish
848 * returns 1 if the hold count was incremented
849 * returns 0 if the hold count was not incremented
850 * This return value should be used to balance
851 * ubc_hold() and ubc_rele().
852 */
853int
854ubc_hold(struct vnode *vp)
855{
856 struct ubc_info *uip;
b4c24cb9 857 int recursed;
0b4e3aa0 858 memory_object_control_t object;
1c79356b
A
859
860 if (UBCINVALID(vp))
861 return (0);
862
b4c24cb9 863 if ((recursed = ubc_busy(vp)) == 0) {
0b4e3aa0
A
864 /* must be invalid or dying vnode */
865 assert(UBCINVALID(vp) ||
b4c24cb9 866 ((vp->v_flag & VXLOCK) || (vp->v_flag & VTERMINATE)));
0b4e3aa0 867 return (0);
1c79356b 868 }
0b4e3aa0 869
1c79356b 870 uip = vp->v_ubcinfo;
0b4e3aa0 871 assert(uip->ui_control != MEMORY_OBJECT_CONTROL_NULL);
1c79356b 872
0b4e3aa0
A
873 ubc_lock(vp);
874 uip->ui_refcount++;
b4c24cb9 875 ubc_unlock(vp);
1c79356b 876
0b4e3aa0 877 if (!ISSET(uip->ui_flags, UI_HASOBJREF)) {
b4c24cb9
A
878 if (memory_object_recover_named(uip->ui_control, TRUE)
879 != KERN_SUCCESS) {
880 if (recursed == 1)
881 ubc_unbusy(vp);
0b4e3aa0
A
882 ubc_info_deallocate(uip);
883 return (0);
884 }
0b4e3aa0 885 SET(uip->ui_flags, UI_HASOBJREF);
0b4e3aa0 886 }
b4c24cb9
A
887 if (recursed == 1)
888 ubc_unbusy(vp);
0b4e3aa0
A
889
890 assert(uip->ui_refcount > 0);
b4c24cb9 891
1c79356b
A
892 return (1);
893}
894
0b4e3aa0
A
895/*
896 * Drop the holdcount.
897 * release the reference on the vm object if the this is "uncached"
898 * ubc_info.
899 */
1c79356b
A
900void
901ubc_rele(struct vnode *vp)
902{
903 struct ubc_info *uip;
1c79356b
A
904
905 if (UBCINVALID(vp))
906 return;
907
908 if (!UBCINFOEXISTS(vp)) {
909 /* nothing more to do for a dying vnode */
910 if ((vp->v_flag & VXLOCK) || (vp->v_flag & VTERMINATE))
911 return;
912 panic("ubc_rele: can not");
913 }
914
915 uip = vp->v_ubcinfo;
916
0b4e3aa0
A
917 if (uip->ui_refcount == 1)
918 panic("ubc_rele: ui_refcount");
1c79356b 919
0b4e3aa0 920 --uip->ui_refcount;
1c79356b 921
0b4e3aa0
A
922 if ((uip->ui_refcount == 1)
923 && ISSET(uip->ui_flags, UI_DONTCACHE))
924 (void) ubc_release_named(vp);
1c79356b
A
925
926 return;
927}
928
929/*
0b4e3aa0 930 * The vnode is mapped explicitly, mark it so.
1c79356b 931 */
0b4e3aa0 932__private_extern__ void
1c79356b
A
933ubc_map(struct vnode *vp)
934{
935 struct ubc_info *uip;
1c79356b 936
0b4e3aa0 937 if (UBCINVALID(vp))
1c79356b 938 return;
1c79356b
A
939
940 if (!UBCINFOEXISTS(vp))
0b4e3aa0 941 return;
1c79356b 942
0b4e3aa0 943 ubc_lock(vp);
1c79356b
A
944 uip = vp->v_ubcinfo;
945
946 SET(uip->ui_flags, UI_WASMAPPED);
947 uip->ui_mapped = 1;
948 ubc_unlock(vp);
949
1c79356b 950 return;
1c79356b
A
951}
952
953/*
954 * Release the memory object reference on the vnode
955 * only if it is not in use
956 * Return 1 if the reference was released, 0 otherwise.
957 */
958int
0b4e3aa0 959ubc_release_named(struct vnode *vp)
1c79356b
A
960{
961 struct ubc_info *uip;
b4c24cb9 962 int recursed;
0b4e3aa0 963 memory_object_control_t control;
b4c24cb9 964 kern_return_t kret = KERN_FAILURE;
1c79356b
A
965
966 if (UBCINVALID(vp))
967 return (0);
968
b4c24cb9 969 if ((recursed = ubc_busy(vp)) == 0)
0b4e3aa0 970 return (0);
1c79356b
A
971 uip = vp->v_ubcinfo;
972
0b4e3aa0
A
973 /* can not release held or mapped vnodes */
974 if (ISSET(uip->ui_flags, UI_HASOBJREF) &&
b4c24cb9 975 (uip->ui_refcount == 1) && !uip->ui_mapped) {
0b4e3aa0
A
976 control = uip->ui_control;
977 assert(control);
978 CLR(uip->ui_flags, UI_HASOBJREF);
979 kret = memory_object_release_name(control,
980 MEMORY_OBJECT_RESPECT_CACHE);
b4c24cb9
A
981 }
982
983 if (recursed == 1)
984 ubc_unbusy(vp);
985 return ((kret != KERN_SUCCESS) ? 0 : 1);
0b4e3aa0 986}
1c79356b 987
0b4e3aa0
A
988/*
989 * This function used to called by extensions directly. Some may
990 * still exist with this behavior. In those cases, we will do the
991 * release as part of reclaiming or cleaning the vnode. We don't
992 * need anything explicit - so just stub this out until those callers
993 * get cleaned up.
994 */
995int
996ubc_release(
997 struct vnode *vp)
998{
999 return 0;
1000}
1001
1002/*
1003 * destroy the named reference for a given vnode
1004 */
1005__private_extern__ int
1006ubc_destroy_named(
1007 struct vnode *vp)
1008{
1009 memory_object_control_t control;
1010 struct proc *p;
1011 struct ubc_info *uip;
1012 kern_return_t kret;
1013
1014 /*
1015 * We may already have had the object terminated
1016 * and the ubcinfo released as a side effect of
1017 * some earlier processing. If so, pretend we did
1018 * it, because it probably was a result of our
1019 * efforts.
1020 */
1021 if (!UBCINFOEXISTS(vp))
1c79356b 1022 return (1);
0b4e3aa0
A
1023
1024 uip = vp->v_ubcinfo;
1025
1026 /* can not destroy held vnodes */
1027 if (uip->ui_refcount > 1)
1c79356b 1028 return (0);
0b4e3aa0
A
1029
1030 /*
1031 * Terminate the memory object.
1032 * memory_object_destroy() will result in
1033 * vnode_pager_no_senders().
1034 * That will release the pager reference
1035 * and the vnode will move to the free list.
1036 */
1037 control = ubc_getobject(vp, UBC_HOLDOBJECT);
1038 if (control != MEMORY_OBJECT_CONTROL_NULL) {
1039
1040 if (ISSET(vp->v_flag, VTERMINATE))
1041 panic("ubc_destroy_named: already teminating");
1042 SET(vp->v_flag, VTERMINATE);
1043
1044 kret = memory_object_destroy(control, 0);
1045 if (kret != KERN_SUCCESS)
1046 return (0);
1047
1048 /*
1049 * memory_object_destroy() is asynchronous
1050 * with respect to vnode_pager_no_senders().
1051 * wait for vnode_pager_no_senders() to clear
1052 * VTERMINATE
1053 */
1054 while (ISSET(vp->v_flag, VTERMINATE)) {
1055 SET(vp->v_flag, VTERMWANT);
1056 (void)tsleep((caddr_t)&vp->v_ubcinfo,
1057 PINOD, "ubc_destroy_named", 0);
1058 }
1059 }
1060 return (1);
1c79356b
A
1061}
1062
0b4e3aa0 1063
1c79356b
A
1064/*
1065 * Invalidate a range in the memory object that backs this
1066 * vnode. The offset is truncated to the page boundary and the
1067 * size is adjusted to include the last page in the range.
1068 */
1069int
1070ubc_invalidate(struct vnode *vp, off_t offset, size_t size)
1071{
1072 struct ubc_info *uip;
0b4e3aa0 1073 memory_object_control_t control;
1c79356b
A
1074 kern_return_t kret;
1075 off_t toff;
1076 size_t tsize;
1c79356b
A
1077
1078 if (UBCINVALID(vp))
0b4e3aa0 1079 return (0);
1c79356b
A
1080
1081 if (!UBCINFOEXISTS(vp))
0b4e3aa0 1082 return (0);
1c79356b 1083
1c79356b
A
1084 toff = trunc_page_64(offset);
1085 tsize = (size_t)(round_page_64(offset+size) - toff);
1086 uip = vp->v_ubcinfo;
0b4e3aa0
A
1087 control = uip->ui_control;
1088 assert(control);
1c79356b
A
1089
1090 /* invalidate pages in the range requested */
0b4e3aa0
A
1091 kret = memory_object_lock_request(control,
1092 (memory_object_offset_t)toff,
1c79356b
A
1093 (memory_object_size_t)tsize,
1094 MEMORY_OBJECT_RETURN_NONE,
1095 (MEMORY_OBJECT_DATA_NO_CHANGE| MEMORY_OBJECT_DATA_FLUSH),
0b4e3aa0 1096 VM_PROT_NO_CHANGE);
1c79356b
A
1097 if (kret != KERN_SUCCESS)
1098 printf("ubc_invalidate: invalidate failed (error = %d)\n", kret);
1099
1c79356b
A
1100 return ((kret == KERN_SUCCESS) ? 1 : 0);
1101}
1102
1103/*
1104 * Find out whether a vnode is in use by UBC
1105 * Returns 1 if file is in use by UBC, 0 if not
1106 */
1107int
1108ubc_isinuse(struct vnode *vp, int tookref)
1109{
1110 int busycount = tookref ? 2 : 1;
1111
1112 if (!UBCINFOEXISTS(vp))
0b4e3aa0 1113 return (0);
1c79356b 1114
9bccf70c
A
1115 if (tookref == 0) {
1116 printf("ubc_isinuse: called without a valid reference"
1117 ": v_tag = %d\v", vp->v_tag);
1118 vprint("ubc_isinuse", vp);
1119 return (0);
1120 }
1121
1c79356b
A
1122 if (vp->v_usecount > busycount)
1123 return (1);
1124
1125 if ((vp->v_usecount == busycount)
1126 && (vp->v_ubcinfo->ui_mapped == 1))
0b4e3aa0 1127 return (1);
1c79356b 1128 else
0b4e3aa0 1129 return (0);
1c79356b
A
1130}
1131
1c79356b 1132/*
0b4e3aa0 1133 * The backdoor routine to clear the ui_mapped.
1c79356b
A
1134 * MUST only be called by the VM
1135 *
0b4e3aa0
A
1136 * Note that this routine is not called under funnel. There are numerous
1137 * things about the calling sequence that make this work on SMP.
1c79356b
A
1138 * Any code change in those paths can break this.
1139 *
1c79356b 1140 */
0b4e3aa0 1141__private_extern__ void
1c79356b
A
1142ubc_unmap(struct vnode *vp)
1143{
1144 struct ubc_info *uip;
0b4e3aa0 1145 boolean_t funnel_state;
1c79356b 1146
0b4e3aa0 1147 if (UBCINVALID(vp))
1c79356b 1148 return;
1c79356b
A
1149
1150 if (!UBCINFOEXISTS(vp))
0b4e3aa0 1151 return;
1c79356b
A
1152
1153 ubc_lock(vp);
1154 uip = vp->v_ubcinfo;
1c79356b 1155 uip->ui_mapped = 0;
0b4e3aa0
A
1156 if ((uip->ui_refcount > 1) || !ISSET(uip->ui_flags, UI_DONTCACHE)) {
1157 ubc_unlock(vp);
1158 return;
1159 }
1c79356b
A
1160 ubc_unlock(vp);
1161
0b4e3aa0
A
1162 funnel_state = thread_funnel_set(kernel_flock, TRUE);
1163 (void) ubc_release_named(vp);
1164 (void) thread_funnel_set(kernel_flock, funnel_state);
1165}
1166
1167kern_return_t
1168ubc_page_op(
1169 struct vnode *vp,
1170 off_t f_offset,
1171 int ops,
d7e50217 1172 ppnum_t *phys_entryp,
0b4e3aa0
A
1173 int *flagsp)
1174{
1175 memory_object_control_t control;
1176
1177 control = ubc_getobject(vp, UBC_FLAGS_NONE);
1178 if (control == MEMORY_OBJECT_CONTROL_NULL)
1179 return KERN_INVALID_ARGUMENT;
1180
1181 return (memory_object_page_op(control,
1182 (memory_object_offset_t)f_offset,
1183 ops,
1184 phys_entryp,
1185 flagsp));
1186}
1187
1188kern_return_t
1189ubc_create_upl(
1190 struct vnode *vp,
1191 off_t f_offset,
1192 long bufsize,
1193 upl_t *uplp,
1194 upl_page_info_t **plp,
1195 int uplflags)
1196{
1197 memory_object_control_t control;
d7e50217
A
1198 int count;
1199 int ubcflags;
1200 off_t file_offset;
1201 kern_return_t kr;
0b4e3aa0
A
1202
1203 if (bufsize & 0xfff)
1204 return KERN_INVALID_ARGUMENT;
1205
d7e50217
A
1206 if (uplflags & UPL_FOR_PAGEOUT) {
1207 uplflags &= ~UPL_FOR_PAGEOUT;
1208 ubcflags = UBC_FOR_PAGEOUT;
1209 } else
1210 ubcflags = UBC_FLAGS_NONE;
1211
1212 control = ubc_getobject(vp, ubcflags);
0b4e3aa0
A
1213 if (control == MEMORY_OBJECT_CONTROL_NULL)
1214 return KERN_INVALID_ARGUMENT;
1215
1216 uplflags |= (UPL_NO_SYNC|UPL_CLEAN_IN_PLACE|UPL_SET_INTERNAL);
1217 count = 0;
1218 kr = memory_object_upl_request(control, f_offset, bufsize,
1219 uplp, NULL, &count, uplflags);
1220 if (plp != NULL)
1221 *plp = UPL_GET_INTERNAL_PAGE_LIST(*uplp);
1222 return kr;
1223}
1224
1225
1226kern_return_t
1227ubc_upl_map(
1228 upl_t upl,
1229 vm_offset_t *dst_addr)
1230{
1231 return (vm_upl_map(kernel_map, upl, dst_addr));
1232}
1233
1234
1235kern_return_t
1236ubc_upl_unmap(
1237 upl_t upl)
1238{
1239 return(vm_upl_unmap(kernel_map, upl));
1240}
1241
1242kern_return_t
1243ubc_upl_commit(
1244 upl_t upl)
1245{
1246 upl_page_info_t *pl;
1247 kern_return_t kr;
1248
1249 pl = UPL_GET_INTERNAL_PAGE_LIST(upl);
1250 kr = upl_commit(upl, pl, MAX_UPL_TRANSFER);
1251 upl_deallocate(upl);
1252 return kr;
1c79356b
A
1253}
1254
0b4e3aa0
A
1255
1256kern_return_t
1257ubc_upl_commit_range(
1258 upl_t upl,
1259 vm_offset_t offset,
1260 vm_size_t size,
1261 int flags)
1262{
1263 upl_page_info_t *pl;
1264 boolean_t empty;
1265 kern_return_t kr;
1266
1267 if (flags & UPL_COMMIT_FREE_ON_EMPTY)
1268 flags |= UPL_COMMIT_NOTIFY_EMPTY;
1269
1270 pl = UPL_GET_INTERNAL_PAGE_LIST(upl);
1271
1272 kr = upl_commit_range(upl, offset, size, flags,
1273 pl, MAX_UPL_TRANSFER, &empty);
1274
1275 if((flags & UPL_COMMIT_FREE_ON_EMPTY) && empty)
1276 upl_deallocate(upl);
1277
1278 return kr;
1279}
1280
1281kern_return_t
1282ubc_upl_abort_range(
1283 upl_t upl,
1284 vm_offset_t offset,
1285 vm_size_t size,
1286 int abort_flags)
1287{
1288 kern_return_t kr;
1289 boolean_t empty = FALSE;
1290
1291 if (abort_flags & UPL_ABORT_FREE_ON_EMPTY)
1292 abort_flags |= UPL_ABORT_NOTIFY_EMPTY;
1293
1294 kr = upl_abort_range(upl, offset, size, abort_flags, &empty);
1295
1296 if((abort_flags & UPL_ABORT_FREE_ON_EMPTY) && empty)
1297 upl_deallocate(upl);
1298
1299 return kr;
1300}
1301
1302kern_return_t
1303ubc_upl_abort(
1304 upl_t upl,
1305 int abort_type)
1306{
1307 kern_return_t kr;
1308
1309 kr = upl_abort(upl, abort_type);
1310 upl_deallocate(upl);
1311 return kr;
1312}
1313
1314upl_page_info_t *
1315ubc_upl_pageinfo(
1316 upl_t upl)
1317{
1318 return (UPL_GET_INTERNAL_PAGE_LIST(upl));
1319}