/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* University Copyright- Copyright (c) 1982, 1986, 1988
* The Regents of the University of California
* All Rights Reserved
*
* University Acknowledgment- Portions of this document are derived from
* software developed by the University of California, Berkeley, and its
* contributors.
*/
#include <sys/sysmacros.h>
#include <sys/tnf_probe.h>
#include <vm/seg_kmem.h>
extern int maxphys;
void
{
}
/*
* use kmem_cache_create for physio buffers. This has shown
* a better cache distribution compared to buffers on the
* stack. It also avoids semaphore construction/deconstruction
* per request
*/
/* ARGSUSED */
static int
{
return (0);
}
/* ARGSUSED */
static void
{
}
void
physio_bufs_init(void)
{
sizeof (struct buf), 0, physio_buf_constructor,
}
/*
* initiate raw I/O request
*
* allocate buf header if necessary
* adjust max size of each I/O request
* lock down user pages and verify access protections
* call driver's strategy routine to submit request
* wait for I/O completion
* unlock user pages and free allocated buf header
*/
int
{
ssize_t c;
char *a;
int error = 0;
int allocbuf = 0;
/* Kernel probe */
} else {
}
"getbuf_start: bp %p", bp);
allocbuf = 1;
}
} else {
}
/*
* We need to prepare this buffer for the io:::start probe, including
* NULL'ing out the file, clearing the offset, and filling in the
* b_dip field.
*/
} else {
}
while (uio->uio_iovcnt > 0) {
break;
if (uio->uio_loffset < 0) {
break;
}
#ifdef _ILP32
/*
* For 32-bit kernels, check against SPEC_MAXOFFSET_T
* which represents the maximum size that can be
* supported by the IO subsystem.
* XXX this code assumes a D_64BIT driver.
*/
break;
}
#endif /* _ILP32 */
/*
* Don't count on b_addr remaining untouched by the
* code below (it may be reset because someone does
* a bp_mapin on the buffer) -- reset from the iov
* each time through, updating the iov's base address
* instead.
*/
"as_pagelock_start: bp %p", bp);
"as_pagelock_end:");
if (error != 0) {
break;
}
}
/*
* unlock the pages
*/
"as_pageunlock_start: bp %p", bp);
"as_pageunlock_end:");
uio->uio_loffset += c;
/* bp->b_resid - temp kludge for tape drives */
break;
}
/* bp->b_resid - temp kludge for tape drives */
break;
uio->uio_iovcnt--;
}
if (allocbuf) {
}
/* Kernel probe */
return (error);
}
/*
* Returns 0 on success, or an error on failure.
*
* However, for compatibility, its interface should not
* be changed and it should not be removed from the kernel.
*/
int
{
}
/*
* This function temporarily "borrows" user pages for kernel use. If
* "cow" is on, it also sets up copy-on-write protection (only feasible
* on MAP_PRIVATE segment) on the user mappings, to protect the borrowed
* pages from any changes by the user. The caller is responsible for
* unlocking and tearing down cow settings when it's done with the pages.
* For an example, see kcfree().
*
* Pages behind [uaddr..uaddr+*lenp] under address space "as" are locked
* (shared), and mapped into kernel address range [kaddr..kaddr+*lenp] if
* kaddr != -1. On entering this function, cached_ppp contains a list
* of pages that are mapped into [kaddr..kaddr+*lenp] already (from a
* previous call). Thus if same pages remain behind [uaddr..uaddr+*lenp],
* the kernel map won't need to be reloaded again.
*
* For cow == 1, if the pages are anonymous pages, it also bumps the anon
* reference count, and change the user-mapping to read-only. This
* scheme should work on all types of segment drivers. But to be safe,
* we check against segvn here.
*
* Since this function is used to emulate copyin() semantic, it checks
* to make sure the user-mappings allow "user-read".
*
* On exit "lenp" contains the number of bytes successfully locked and
* mapped in. For the unsuccessful ones, the caller can fall back to
* copyin().
*
* Error return:
* ENOTSUP - operation like this is not supported either on this segment
* type, or on this platform type.
*/
int
{
long i;
int flags;
*lenp = 0;
if (cow) {
return (EINVAL);
}
/*
* The COW scheme should work for all segment types.
* But to be safe, we check against segvn.
*/
return (ENOTSUP);
return (ENOTSUP);
}
}
/*
* If (cow), hat_softlock will also change the usr protection to RO.
* This is the first step toward setting up cow. Before we
* bump up an_refcnt, we can't allow any cow-fault on this
* address. Otherwise segvn_fault will change the protection back
* to RW upon seeing an_refcnt == 1.
* The solution is to hold the writer lock on "as".
*/
i = 0;
while (i < size) {
if (cow) {
/*
* Another solution is to hold SE_EXCL on pp, and
* disable PROT_WRITE. This also works for MAP_SHARED
* segment. The disadvantage is that it locks the
* page from being used by anybody else.
*/
/*
* Since we are holding the as lock, this avoids a
* potential race with anon_decref. (segvn_unmap and
* segvn_free needs the as writer lock to do anon_free.)
*/
#if 0
/*
* Consider the following senario (unlikey
* though):
* 1. an_refcnt == 2
* 2. we solftlock the page.
* 3. cow ocurrs on this addr. So a new ap,
* page and mapping is established on addr.
* 4. an_refcnt drops to 1 (segvn_faultpage
* -> anon_decref(oldap))
* 5. the last ref to ap also drops (from
* another as). It ends up blocked inside
* anon_decref trying to get page's excl lock.
* 6. Later kcfree unlocks the page, call
* anon_decref -> oops, ap is gone already.
*
* Holding as writer lock solves all problems.
*/
else
#endif
}
} else {
}
if (pp != *cached_ppp) {
if (*cached_ppp == NULL)
else
flags = HAT_LOAD_REMAP |
/*
* In order to cache the kernel mapping after
* the user page is unlocked, we call
* hat_devload instead of hat_memload so
* that the kernel mapping we set up here is
* "invisible" to the rest of the world. This
* is not very pretty. But as long as the
* caller bears the responsibility of keeping
* cache consistency, we should be ok -
* HAT_NOCONSIST will get us a uncached
* mapping on VAC. hat_softlock will flush
* a VAC_WRITEBACK cache. Therefore the kaddr
* doesn't have to be of the same vcolor as
* uaddr.
* The alternative is - change hat_devload
* to get a cached mapping. Allocate a kaddr
* with the same vcolor as uaddr. Then
* hat_softlock won't need to flush the VAC.
*/
*cached_ppp = pp;
}
}
cached_ppp++;
app++;
++i;
}
if (cow) {
}
/*
* If the address is not mapped yet, we call as_fault to
* fault the pages in. We could've fallen back to copy and
* let it fault in the pages. But for a mapped file, we
* normally reference each page only once. For zero-copy to
* be of any use, we'd better fall in the page now and try
* again.
*/
first = 0;
if (cow)
goto tryagain;
}
switch (res) {
case FC_NOSUPPORT:
return (ENOTSUP);
case FC_PROT: /* Pretend we don't know about it. This will be */
/* caught by the caller when uiomove fails. */
case FC_NOMAP:
case FC_OBJERR:
default:
return (0);
}
}