1994-05-24 10:09:53 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 1982, 1986, 1991, 1993
|
|
|
|
* The Regents of the University of California. All rights reserved.
|
|
|
|
* (c) UNIX System Laboratories, Inc.
|
|
|
|
* All or some portions of this file are derived from material licensed
|
|
|
|
* to the University of California by American Telephone and Telegraph
|
|
|
|
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
|
|
|
|
* the permission of UNIX System Laboratories, Inc.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
|
|
* must display the following acknowledgement:
|
|
|
|
* This product includes software developed by the University of
|
|
|
|
* California, Berkeley and its contributors.
|
|
|
|
* 4. Neither the name of the University nor the names of its contributors
|
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*
|
|
|
|
* @(#)kern_subr.c 8.3 (Berkeley) 1/21/94
|
1999-08-28 01:08:13 +00:00
|
|
|
* $FreeBSD$
|
1994-05-24 10:09:53 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
1999-02-22 16:57:48 +00:00
|
|
|
#include <sys/kernel.h>
|
2000-09-07 01:33:02 +00:00
|
|
|
#include <sys/ktr.h>
|
2001-05-01 08:13:21 +00:00
|
|
|
#include <sys/lock.h>
|
|
|
|
#include <sys/mutex.h>
|
1994-05-24 10:09:53 +00:00
|
|
|
#include <sys/proc.h>
|
|
|
|
#include <sys/malloc.h>
|
1999-02-02 12:11:01 +00:00
|
|
|
#include <sys/resourcevar.h>
|
2001-06-18 20:24:54 +00:00
|
|
|
#include <sys/sysctl.h>
|
VM level code cleanups.
1) Start using TSM.
Struct procs continue to point to upages structure, after being freed.
Struct vmspace continues to point to pte object and kva space for kstack.
u_map is now superfluous.
2) vm_map's don't need to be reference counted. They always exist either
in the kernel or in a vmspace. The vmspaces are managed by reference
counts.
3) Remove the "wired" vm_map nonsense.
4) No need to keep a cache of kernel stack kva's.
5) Get rid of strange looking ++var, and change to var++.
6) Change more data structures to use our "zone" allocator. Added
struct proc, struct vmspace and struct vnode. This saves a significant
amount of kva space and physical memory. Additionally, this enables
TSM for the zone managed memory.
7) Keep ioopt disabled for now.
8) Remove the now bogus "single use" map concept.
9) Use generation counts or id's for data structures residing in TSM, where
it allows us to avoid unneeded restart overhead during traversals, where
blocking might occur.
10) Account better for memory deficits, so the pageout daemon will be able
to make enough memory available (experimental.)
11) Fix some vnode locking problems. (From Tor, I think.)
12) Add a check in ufs_lookup, to avoid lots of unneeded calls to bcmp.
(experimental.)
13) Significantly shrink, cleanup, and make slightly faster the vm_fault.c
code. Use generation counts, get rid of unneded collpase operations,
and clean up the cluster code.
14) Make vm_zone more suitable for TSM.
This commit is partially as a result of discussions and contributions from
other people, including DG, Tor Egge, PHK, and probably others that I
have forgotten to attribute (so let me know, if I forgot.)
This is not the infamous, final cleanup of the vnode stuff, but a necessary
step. Vnode mgmt should be correct, but things might still change, and
there is still some missing stuff (like ioopt, and physical backing of
non-merged cache files, debugging of layering concepts.)
1998-01-22 17:30:44 +00:00
|
|
|
#include <sys/vnode.h>
|
1997-12-19 09:03:37 +00:00
|
|
|
|
|
|
|
#include <vm/vm.h>
|
|
|
|
#include <vm/vm_page.h>
|
|
|
|
#include <vm/vm_map.h>
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2001-06-18 20:24:54 +00:00
|
|
|
SYSCTL_INT(_kern, KERN_IOV_MAX, iov_max, CTLFLAG_RD, NULL, UIO_MAXIOV,
|
|
|
|
"Maximum number of elements in an I/O vector; sysconf(_SC_IOV_MAX)");
|
|
|
|
|
1994-05-25 09:21:21 +00:00
|
|
|
int
|
1994-05-24 10:09:53 +00:00
|
|
|
uiomove(cp, n, uio)
|
|
|
|
register caddr_t cp;
|
|
|
|
register int n;
|
|
|
|
register struct uio *uio;
|
|
|
|
{
|
2001-09-12 08:38:13 +00:00
|
|
|
struct thread *td = curthread;
|
1994-05-24 10:09:53 +00:00
|
|
|
register struct iovec *iov;
|
|
|
|
u_int cnt;
|
1999-03-12 03:09:29 +00:00
|
|
|
int error = 0;
|
|
|
|
int save = 0;
|
1994-05-24 10:09:53 +00:00
|
|
|
|
1999-01-08 17:31:30 +00:00
|
|
|
KASSERT(uio->uio_rw == UIO_READ || uio->uio_rw == UIO_WRITE,
|
1999-01-10 01:58:29 +00:00
|
|
|
("uiomove: mode"));
|
2001-09-12 08:38:13 +00:00
|
|
|
KASSERT(uio->uio_segflg != UIO_USERSPACE || uio->uio_td == curthread,
|
1999-01-10 01:58:29 +00:00
|
|
|
("uiomove proc"));
|
1999-01-08 17:31:30 +00:00
|
|
|
|
2001-09-12 08:38:13 +00:00
|
|
|
if (td) {
|
2001-09-13 22:33:37 +00:00
|
|
|
mtx_lock_spin(&sched_lock);
|
2001-09-12 08:38:13 +00:00
|
|
|
save = td->td_flags & TDF_DEADLKTREAT;
|
|
|
|
td->td_flags |= TDF_DEADLKTREAT;
|
2001-09-13 22:33:37 +00:00
|
|
|
mtx_unlock_spin(&sched_lock);
|
1999-03-12 03:09:29 +00:00
|
|
|
}
|
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
while (n > 0 && uio->uio_resid) {
|
|
|
|
iov = uio->uio_iov;
|
|
|
|
cnt = iov->iov_len;
|
|
|
|
if (cnt == 0) {
|
|
|
|
uio->uio_iov++;
|
|
|
|
uio->uio_iovcnt--;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (cnt > n)
|
|
|
|
cnt = n;
|
1995-02-12 09:11:47 +00:00
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
switch (uio->uio_segflg) {
|
|
|
|
|
|
|
|
case UIO_USERSPACE:
|
2001-01-10 04:43:51 +00:00
|
|
|
if (ticks - PCPU_GET(switchticks) >= hogticks)
|
1999-02-02 12:11:01 +00:00
|
|
|
uio_yield();
|
1994-05-24 10:09:53 +00:00
|
|
|
if (uio->uio_rw == UIO_READ)
|
|
|
|
error = copyout(cp, iov->iov_base, cnt);
|
|
|
|
else
|
|
|
|
error = copyin(iov->iov_base, cp, cnt);
|
|
|
|
if (error)
|
2002-02-08 20:19:44 +00:00
|
|
|
goto out;
|
1994-05-24 10:09:53 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case UIO_SYSSPACE:
|
|
|
|
if (uio->uio_rw == UIO_READ)
|
|
|
|
bcopy((caddr_t)cp, iov->iov_base, cnt);
|
|
|
|
else
|
|
|
|
bcopy(iov->iov_base, (caddr_t)cp, cnt);
|
1997-12-19 09:03:37 +00:00
|
|
|
break;
|
|
|
|
case UIO_NOCOPY:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
iov->iov_base += cnt;
|
|
|
|
iov->iov_len -= cnt;
|
|
|
|
uio->uio_resid -= cnt;
|
|
|
|
uio->uio_offset += cnt;
|
|
|
|
cp += cnt;
|
|
|
|
n -= cnt;
|
|
|
|
}
|
2002-02-08 20:19:44 +00:00
|
|
|
out:
|
2001-09-12 08:38:13 +00:00
|
|
|
if (td != curthread) printf("uiomove: IT CHANGED!");
|
|
|
|
td = curthread; /* Might things have changed in copyin/copyout? */
|
2001-09-13 22:33:37 +00:00
|
|
|
if (td) {
|
|
|
|
mtx_lock_spin(&sched_lock);
|
2001-09-12 08:38:13 +00:00
|
|
|
td->td_flags = (td->td_flags & ~TDF_DEADLKTREAT) | save;
|
2001-09-13 22:33:37 +00:00
|
|
|
mtx_unlock_spin(&sched_lock);
|
|
|
|
}
|
1999-03-12 03:09:29 +00:00
|
|
|
return (error);
|
1997-12-19 09:03:37 +00:00
|
|
|
}
|
|
|
|
|
2002-05-05 22:42:40 +00:00
|
|
|
#ifdef ENABLE_VFS_IOOPT
|
|
|
|
/*
|
|
|
|
* Experimental support for zero-copy I/O
|
|
|
|
*/
|
1997-12-19 09:03:37 +00:00
|
|
|
int
|
|
|
|
uiomoveco(cp, n, uio, obj)
|
|
|
|
caddr_t cp;
|
|
|
|
int n;
|
|
|
|
struct uio *uio;
|
|
|
|
struct vm_object *obj;
|
|
|
|
{
|
|
|
|
struct iovec *iov;
|
|
|
|
u_int cnt;
|
|
|
|
int error;
|
|
|
|
|
1999-01-08 17:31:30 +00:00
|
|
|
KASSERT(uio->uio_rw == UIO_READ || uio->uio_rw == UIO_WRITE,
|
1999-01-10 01:58:29 +00:00
|
|
|
("uiomoveco: mode"));
|
2001-09-12 08:38:13 +00:00
|
|
|
KASSERT(uio->uio_segflg != UIO_USERSPACE || uio->uio_td == curthread,
|
1999-01-10 01:58:29 +00:00
|
|
|
("uiomoveco proc"));
|
1999-01-08 17:31:30 +00:00
|
|
|
|
1997-12-19 09:03:37 +00:00
|
|
|
while (n > 0 && uio->uio_resid) {
|
|
|
|
iov = uio->uio_iov;
|
|
|
|
cnt = iov->iov_len;
|
|
|
|
if (cnt == 0) {
|
|
|
|
uio->uio_iov++;
|
|
|
|
uio->uio_iovcnt--;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (cnt > n)
|
|
|
|
cnt = n;
|
|
|
|
|
|
|
|
switch (uio->uio_segflg) {
|
|
|
|
|
|
|
|
case UIO_USERSPACE:
|
2001-01-10 04:43:51 +00:00
|
|
|
if (ticks - PCPU_GET(switchticks) >= hogticks)
|
1999-02-02 12:11:01 +00:00
|
|
|
uio_yield();
|
1997-12-19 09:03:37 +00:00
|
|
|
if (uio->uio_rw == UIO_READ) {
|
1999-07-08 06:06:00 +00:00
|
|
|
#ifdef ENABLE_VFS_IOOPT
|
VM level code cleanups.
1) Start using TSM.
Struct procs continue to point to upages structure, after being freed.
Struct vmspace continues to point to pte object and kva space for kstack.
u_map is now superfluous.
2) vm_map's don't need to be reference counted. They always exist either
in the kernel or in a vmspace. The vmspaces are managed by reference
counts.
3) Remove the "wired" vm_map nonsense.
4) No need to keep a cache of kernel stack kva's.
5) Get rid of strange looking ++var, and change to var++.
6) Change more data structures to use our "zone" allocator. Added
struct proc, struct vmspace and struct vnode. This saves a significant
amount of kva space and physical memory. Additionally, this enables
TSM for the zone managed memory.
7) Keep ioopt disabled for now.
8) Remove the now bogus "single use" map concept.
9) Use generation counts or id's for data structures residing in TSM, where
it allows us to avoid unneeded restart overhead during traversals, where
blocking might occur.
10) Account better for memory deficits, so the pageout daemon will be able
to make enough memory available (experimental.)
11) Fix some vnode locking problems. (From Tor, I think.)
12) Add a check in ufs_lookup, to avoid lots of unneeded calls to bcmp.
(experimental.)
13) Significantly shrink, cleanup, and make slightly faster the vm_fault.c
code. Use generation counts, get rid of unneded collpase operations,
and clean up the cluster code.
14) Make vm_zone more suitable for TSM.
This commit is partially as a result of discussions and contributions from
other people, including DG, Tor Egge, PHK, and probably others that I
have forgotten to attribute (so let me know, if I forgot.)
This is not the infamous, final cleanup of the vnode stuff, but a necessary
step. Vnode mgmt should be correct, but things might still change, and
there is still some missing stuff (like ioopt, and physical backing of
non-merged cache files, debugging of layering concepts.)
1998-01-22 17:30:44 +00:00
|
|
|
if (vfs_ioopt && ((cnt & PAGE_MASK) == 0) &&
|
1998-07-15 02:32:35 +00:00
|
|
|
((((intptr_t) iov->iov_base) & PAGE_MASK) == 0) &&
|
1997-12-19 09:03:37 +00:00
|
|
|
((uio->uio_offset & PAGE_MASK) == 0) &&
|
1998-07-15 02:32:35 +00:00
|
|
|
((((intptr_t) cp) & PAGE_MASK) == 0)) {
|
1997-12-19 09:03:37 +00:00
|
|
|
error = vm_uiomove(&curproc->p_vmspace->vm_map, obj,
|
|
|
|
uio->uio_offset, cnt,
|
Make our v_usecount vnode reference count work identically to the
original BSD code. The association between the vnode and the vm_object
no longer includes reference counts. The major difference is that
vm_object's are no longer freed gratuitiously from the vnode, and so
once an object is created for the vnode, it will last as long as the
vnode does.
When a vnode object reference count is incremented, then the underlying
vnode reference count is incremented also. The two "objects" are now
more intimately related, and so the interactions are now much less
complex.
When vnodes are now normally placed onto the free queue with an object still
attached. The rundown of the object happens at vnode rundown time, and
happens with exactly the same filesystem semantics of the original VFS
code. There is absolutely no need for vnode_pager_uncache and other
travesties like that anymore.
A side-effect of these changes is that SMP locking should be much simpler,
the I/O copyin/copyout optimizations work, NFS should be more ponderable,
and further work on layered filesystems should be less frustrating, because
of the totally coherent management of the vnode objects and vnodes.
Please be careful with your system while running this code, but I would
greatly appreciate feedback as soon a reasonably possible.
1998-01-06 05:26:17 +00:00
|
|
|
(vm_offset_t) iov->iov_base, NULL);
|
1999-07-08 06:06:00 +00:00
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
{
|
1997-12-19 09:03:37 +00:00
|
|
|
error = copyout(cp, iov->iov_base, cnt);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
error = copyin(iov->iov_base, cp, cnt);
|
|
|
|
}
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case UIO_SYSSPACE:
|
|
|
|
if (uio->uio_rw == UIO_READ)
|
|
|
|
bcopy((caddr_t)cp, iov->iov_base, cnt);
|
|
|
|
else
|
|
|
|
bcopy(iov->iov_base, (caddr_t)cp, cnt);
|
1994-05-24 10:09:53 +00:00
|
|
|
break;
|
1995-04-04 02:01:13 +00:00
|
|
|
case UIO_NOCOPY:
|
|
|
|
break;
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
iov->iov_base += cnt;
|
|
|
|
iov->iov_len -= cnt;
|
|
|
|
uio->uio_resid -= cnt;
|
|
|
|
uio->uio_offset += cnt;
|
|
|
|
cp += cnt;
|
|
|
|
n -= cnt;
|
|
|
|
}
|
1995-02-12 09:11:47 +00:00
|
|
|
return (0);
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
|
2002-05-05 22:42:40 +00:00
|
|
|
/*
|
|
|
|
* Experimental support for zero-copy I/O
|
|
|
|
*/
|
Make our v_usecount vnode reference count work identically to the
original BSD code. The association between the vnode and the vm_object
no longer includes reference counts. The major difference is that
vm_object's are no longer freed gratuitiously from the vnode, and so
once an object is created for the vnode, it will last as long as the
vnode does.
When a vnode object reference count is incremented, then the underlying
vnode reference count is incremented also. The two "objects" are now
more intimately related, and so the interactions are now much less
complex.
When vnodes are now normally placed onto the free queue with an object still
attached. The rundown of the object happens at vnode rundown time, and
happens with exactly the same filesystem semantics of the original VFS
code. There is absolutely no need for vnode_pager_uncache and other
travesties like that anymore.
A side-effect of these changes is that SMP locking should be much simpler,
the I/O copyin/copyout optimizations work, NFS should be more ponderable,
and further work on layered filesystems should be less frustrating, because
of the totally coherent management of the vnode objects and vnodes.
Please be careful with your system while running this code, but I would
greatly appreciate feedback as soon a reasonably possible.
1998-01-06 05:26:17 +00:00
|
|
|
int
|
|
|
|
uioread(n, uio, obj, nread)
|
|
|
|
int n;
|
|
|
|
struct uio *uio;
|
|
|
|
struct vm_object *obj;
|
|
|
|
int *nread;
|
|
|
|
{
|
|
|
|
int npagesmoved;
|
|
|
|
struct iovec *iov;
|
|
|
|
u_int cnt, tcnt;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
*nread = 0;
|
1998-02-05 03:32:49 +00:00
|
|
|
if (vfs_ioopt < 2)
|
VM level code cleanups.
1) Start using TSM.
Struct procs continue to point to upages structure, after being freed.
Struct vmspace continues to point to pte object and kva space for kstack.
u_map is now superfluous.
2) vm_map's don't need to be reference counted. They always exist either
in the kernel or in a vmspace. The vmspaces are managed by reference
counts.
3) Remove the "wired" vm_map nonsense.
4) No need to keep a cache of kernel stack kva's.
5) Get rid of strange looking ++var, and change to var++.
6) Change more data structures to use our "zone" allocator. Added
struct proc, struct vmspace and struct vnode. This saves a significant
amount of kva space and physical memory. Additionally, this enables
TSM for the zone managed memory.
7) Keep ioopt disabled for now.
8) Remove the now bogus "single use" map concept.
9) Use generation counts or id's for data structures residing in TSM, where
it allows us to avoid unneeded restart overhead during traversals, where
blocking might occur.
10) Account better for memory deficits, so the pageout daemon will be able
to make enough memory available (experimental.)
11) Fix some vnode locking problems. (From Tor, I think.)
12) Add a check in ufs_lookup, to avoid lots of unneeded calls to bcmp.
(experimental.)
13) Significantly shrink, cleanup, and make slightly faster the vm_fault.c
code. Use generation counts, get rid of unneded collpase operations,
and clean up the cluster code.
14) Make vm_zone more suitable for TSM.
This commit is partially as a result of discussions and contributions from
other people, including DG, Tor Egge, PHK, and probably others that I
have forgotten to attribute (so let me know, if I forgot.)
This is not the infamous, final cleanup of the vnode stuff, but a necessary
step. Vnode mgmt should be correct, but things might still change, and
there is still some missing stuff (like ioopt, and physical backing of
non-merged cache files, debugging of layering concepts.)
1998-01-22 17:30:44 +00:00
|
|
|
return 0;
|
1998-02-05 03:32:49 +00:00
|
|
|
|
Make our v_usecount vnode reference count work identically to the
original BSD code. The association between the vnode and the vm_object
no longer includes reference counts. The major difference is that
vm_object's are no longer freed gratuitiously from the vnode, and so
once an object is created for the vnode, it will last as long as the
vnode does.
When a vnode object reference count is incremented, then the underlying
vnode reference count is incremented also. The two "objects" are now
more intimately related, and so the interactions are now much less
complex.
When vnodes are now normally placed onto the free queue with an object still
attached. The rundown of the object happens at vnode rundown time, and
happens with exactly the same filesystem semantics of the original VFS
code. There is absolutely no need for vnode_pager_uncache and other
travesties like that anymore.
A side-effect of these changes is that SMP locking should be much simpler,
the I/O copyin/copyout optimizations work, NFS should be more ponderable,
and further work on layered filesystems should be less frustrating, because
of the totally coherent management of the vnode objects and vnodes.
Please be careful with your system while running this code, but I would
greatly appreciate feedback as soon a reasonably possible.
1998-01-06 05:26:17 +00:00
|
|
|
error = 0;
|
|
|
|
|
|
|
|
while (n > 0 && uio->uio_resid) {
|
|
|
|
iov = uio->uio_iov;
|
|
|
|
cnt = iov->iov_len;
|
|
|
|
if (cnt == 0) {
|
|
|
|
uio->uio_iov++;
|
|
|
|
uio->uio_iovcnt--;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (cnt > n)
|
|
|
|
cnt = n;
|
|
|
|
|
|
|
|
if ((uio->uio_segflg == UIO_USERSPACE) &&
|
1998-07-15 02:32:35 +00:00
|
|
|
((((intptr_t) iov->iov_base) & PAGE_MASK) == 0) &&
|
Make our v_usecount vnode reference count work identically to the
original BSD code. The association between the vnode and the vm_object
no longer includes reference counts. The major difference is that
vm_object's are no longer freed gratuitiously from the vnode, and so
once an object is created for the vnode, it will last as long as the
vnode does.
When a vnode object reference count is incremented, then the underlying
vnode reference count is incremented also. The two "objects" are now
more intimately related, and so the interactions are now much less
complex.
When vnodes are now normally placed onto the free queue with an object still
attached. The rundown of the object happens at vnode rundown time, and
happens with exactly the same filesystem semantics of the original VFS
code. There is absolutely no need for vnode_pager_uncache and other
travesties like that anymore.
A side-effect of these changes is that SMP locking should be much simpler,
the I/O copyin/copyout optimizations work, NFS should be more ponderable,
and further work on layered filesystems should be less frustrating, because
of the totally coherent management of the vnode objects and vnodes.
Please be careful with your system while running this code, but I would
greatly appreciate feedback as soon a reasonably possible.
1998-01-06 05:26:17 +00:00
|
|
|
((uio->uio_offset & PAGE_MASK) == 0) ) {
|
|
|
|
|
|
|
|
if (cnt < PAGE_SIZE)
|
|
|
|
break;
|
|
|
|
|
|
|
|
cnt &= ~PAGE_MASK;
|
|
|
|
|
2001-01-10 04:43:51 +00:00
|
|
|
if (ticks - PCPU_GET(switchticks) >= hogticks)
|
1999-02-02 12:11:01 +00:00
|
|
|
uio_yield();
|
Make our v_usecount vnode reference count work identically to the
original BSD code. The association between the vnode and the vm_object
no longer includes reference counts. The major difference is that
vm_object's are no longer freed gratuitiously from the vnode, and so
once an object is created for the vnode, it will last as long as the
vnode does.
When a vnode object reference count is incremented, then the underlying
vnode reference count is incremented also. The two "objects" are now
more intimately related, and so the interactions are now much less
complex.
When vnodes are now normally placed onto the free queue with an object still
attached. The rundown of the object happens at vnode rundown time, and
happens with exactly the same filesystem semantics of the original VFS
code. There is absolutely no need for vnode_pager_uncache and other
travesties like that anymore.
A side-effect of these changes is that SMP locking should be much simpler,
the I/O copyin/copyout optimizations work, NFS should be more ponderable,
and further work on layered filesystems should be less frustrating, because
of the totally coherent management of the vnode objects and vnodes.
Please be careful with your system while running this code, but I would
greatly appreciate feedback as soon a reasonably possible.
1998-01-06 05:26:17 +00:00
|
|
|
error = vm_uiomove(&curproc->p_vmspace->vm_map, obj,
|
|
|
|
uio->uio_offset, cnt,
|
|
|
|
(vm_offset_t) iov->iov_base, &npagesmoved);
|
|
|
|
|
|
|
|
if (npagesmoved == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
tcnt = npagesmoved * PAGE_SIZE;
|
1998-08-04 09:21:04 +00:00
|
|
|
cnt = tcnt;
|
Make our v_usecount vnode reference count work identically to the
original BSD code. The association between the vnode and the vm_object
no longer includes reference counts. The major difference is that
vm_object's are no longer freed gratuitiously from the vnode, and so
once an object is created for the vnode, it will last as long as the
vnode does.
When a vnode object reference count is incremented, then the underlying
vnode reference count is incremented also. The two "objects" are now
more intimately related, and so the interactions are now much less
complex.
When vnodes are now normally placed onto the free queue with an object still
attached. The rundown of the object happens at vnode rundown time, and
happens with exactly the same filesystem semantics of the original VFS
code. There is absolutely no need for vnode_pager_uncache and other
travesties like that anymore.
A side-effect of these changes is that SMP locking should be much simpler,
the I/O copyin/copyout optimizations work, NFS should be more ponderable,
and further work on layered filesystems should be less frustrating, because
of the totally coherent management of the vnode objects and vnodes.
Please be careful with your system while running this code, but I would
greatly appreciate feedback as soon a reasonably possible.
1998-01-06 05:26:17 +00:00
|
|
|
|
|
|
|
if (error)
|
|
|
|
break;
|
|
|
|
|
|
|
|
iov->iov_base += cnt;
|
|
|
|
iov->iov_len -= cnt;
|
|
|
|
uio->uio_resid -= cnt;
|
|
|
|
uio->uio_offset += cnt;
|
|
|
|
*nread += cnt;
|
|
|
|
n -= cnt;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return error;
|
|
|
|
}
|
1999-07-08 06:06:00 +00:00
|
|
|
#endif
|
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
/*
|
|
|
|
* Give next character to user as result of read.
|
|
|
|
*/
|
1994-05-25 09:21:21 +00:00
|
|
|
int
|
1994-05-24 10:09:53 +00:00
|
|
|
ureadc(c, uio)
|
|
|
|
register int c;
|
|
|
|
register struct uio *uio;
|
|
|
|
{
|
|
|
|
register struct iovec *iov;
|
|
|
|
|
|
|
|
again:
|
|
|
|
if (uio->uio_iovcnt == 0 || uio->uio_resid == 0)
|
|
|
|
panic("ureadc");
|
|
|
|
iov = uio->uio_iov;
|
|
|
|
if (iov->iov_len == 0) {
|
|
|
|
uio->uio_iovcnt--;
|
|
|
|
uio->uio_iov++;
|
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
switch (uio->uio_segflg) {
|
|
|
|
|
|
|
|
case UIO_USERSPACE:
|
|
|
|
if (subyte(iov->iov_base, c) < 0)
|
|
|
|
return (EFAULT);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case UIO_SYSSPACE:
|
|
|
|
*iov->iov_base = c;
|
|
|
|
break;
|
|
|
|
|
1995-04-30 05:11:46 +00:00
|
|
|
case UIO_NOCOPY:
|
|
|
|
break;
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
iov->iov_base++;
|
|
|
|
iov->iov_len--;
|
|
|
|
uio->uio_resid--;
|
|
|
|
uio->uio_offset++;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* General routine to allocate a hash table.
|
|
|
|
*/
|
|
|
|
void *
|
|
|
|
hashinit(elements, type, hashmask)
|
1997-10-10 18:14:23 +00:00
|
|
|
int elements;
|
|
|
|
struct malloc_type *type;
|
1994-05-24 10:09:53 +00:00
|
|
|
u_long *hashmask;
|
|
|
|
{
|
|
|
|
long hashsize;
|
2000-05-26 02:09:24 +00:00
|
|
|
LIST_HEAD(generic, generic) *hashtbl;
|
1994-05-24 10:09:53 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
if (elements <= 0)
|
1995-05-08 23:11:12 +00:00
|
|
|
panic("hashinit: bad elements");
|
1994-05-24 10:09:53 +00:00
|
|
|
for (hashsize = 1; hashsize <= elements; hashsize <<= 1)
|
|
|
|
continue;
|
|
|
|
hashsize >>= 1;
|
|
|
|
hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl), type, M_WAITOK);
|
|
|
|
for (i = 0; i < hashsize; i++)
|
|
|
|
LIST_INIT(&hashtbl[i]);
|
|
|
|
*hashmask = hashsize - 1;
|
|
|
|
return (hashtbl);
|
|
|
|
}
|
1995-04-04 02:01:13 +00:00
|
|
|
|
1995-04-09 01:19:25 +00:00
|
|
|
static int primes[] = { 1, 13, 31, 61, 127, 251, 509, 761, 1021, 1531, 2039,
|
|
|
|
2557, 3067, 3583, 4093, 4603, 5119, 5623, 6143, 6653,
|
1995-04-04 02:01:13 +00:00
|
|
|
7159, 7673, 8191, 12281, 16381, 24571, 32749 };
|
1997-05-28 00:47:27 +00:00
|
|
|
#define NPRIMES (sizeof(primes) / sizeof(primes[0]))
|
1995-04-04 02:01:13 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* General routine to allocate a prime number sized hash table.
|
|
|
|
*/
|
|
|
|
void *
|
|
|
|
phashinit(elements, type, nentries)
|
1997-10-10 18:14:23 +00:00
|
|
|
int elements;
|
|
|
|
struct malloc_type *type;
|
1995-04-04 02:01:13 +00:00
|
|
|
u_long *nentries;
|
|
|
|
{
|
|
|
|
long hashsize;
|
2000-05-26 02:09:24 +00:00
|
|
|
LIST_HEAD(generic, generic) *hashtbl;
|
1995-04-04 02:01:13 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
if (elements <= 0)
|
1995-05-08 23:11:12 +00:00
|
|
|
panic("phashinit: bad elements");
|
1995-04-04 02:01:13 +00:00
|
|
|
for (i = 1, hashsize = primes[1]; hashsize <= elements;) {
|
|
|
|
i++;
|
|
|
|
if (i == NPRIMES)
|
|
|
|
break;
|
|
|
|
hashsize = primes[i];
|
|
|
|
}
|
|
|
|
hashsize = primes[i - 1];
|
|
|
|
hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl), type, M_WAITOK);
|
|
|
|
for (i = 0; i < hashsize; i++)
|
|
|
|
LIST_INIT(&hashtbl[i]);
|
|
|
|
*nentries = hashsize;
|
|
|
|
return (hashtbl);
|
|
|
|
}
|
1999-02-02 12:11:01 +00:00
|
|
|
|
2001-09-26 06:54:32 +00:00
|
|
|
void
|
1999-02-02 12:11:01 +00:00
|
|
|
uio_yield()
|
|
|
|
{
|
2001-09-12 08:38:13 +00:00
|
|
|
struct thread *td;
|
1999-02-02 12:11:01 +00:00
|
|
|
|
2001-09-12 08:38:13 +00:00
|
|
|
td = curthread;
|
Change and clean the mutex lock interface.
mtx_enter(lock, type) becomes:
mtx_lock(lock) for sleep locks (MTX_DEF-initialized locks)
mtx_lock_spin(lock) for spin locks (MTX_SPIN-initialized)
similarily, for releasing a lock, we now have:
mtx_unlock(lock) for MTX_DEF and mtx_unlock_spin(lock) for MTX_SPIN.
We change the caller interface for the two different types of locks
because the semantics are entirely different for each case, and this
makes it explicitly clear and, at the same time, it rids us of the
extra `type' argument.
The enter->lock and exit->unlock change has been made with the idea
that we're "locking data" and not "entering locked code" in mind.
Further, remove all additional "flags" previously passed to the
lock acquire/release routines with the exception of two:
MTX_QUIET and MTX_NOSWITCH
The functionality of these flags is preserved and they can be passed
to the lock/unlock routines by calling the corresponding wrappers:
mtx_{lock, unlock}_flags(lock, flag(s)) and
mtx_{lock, unlock}_spin_flags(lock, flag(s)) for MTX_DEF and MTX_SPIN
locks, respectively.
Re-inline some lock acq/rel code; in the sleep lock case, we only
inline the _obtain_lock()s in order to ensure that the inlined code
fits into a cache line. In the spin lock case, we inline recursion and
actually only perform a function call if we need to spin. This change
has been made with the idea that we generally tend to avoid spin locks
and that also the spin locks that we do have and are heavily used
(i.e. sched_lock) do recurse, and therefore in an effort to reduce
function call overhead for some architectures (such as alpha), we
inline recursion for this case.
Create a new malloc type for the witness code and retire from using
the M_DEV type. The new type is called M_WITNESS and is only declared
if WITNESS is enabled.
Begin cleaning up some machdep/mutex.h code - specifically updated the
"optimized" inlined code in alpha/mutex.h and wrote MTX_LOCK_SPIN
and MTX_UNLOCK_SPIN asm macros for the i386/mutex.h as we presently
need those.
Finally, caught up to the interface changes in all sys code.
Contributors: jake, jhb, jasone (in no particular order)
2001-02-09 06:11:45 +00:00
|
|
|
mtx_lock_spin(&sched_lock);
|
Change the preemption code for software interrupt thread schedules and
mutex releases to not require flags for the cases when preemption is
not allowed:
The purpose of the MTX_NOSWITCH and SWI_NOSWITCH flags is to prevent
switching to a higher priority thread on mutex releease and swi schedule,
respectively when that switch is not safe. Now that the critical section
API maintains a per-thread nesting count, the kernel can easily check
whether or not it should switch without relying on flags from the
programmer. This fixes a few bugs in that all current callers of
swi_sched() used SWI_NOSWITCH, when in fact, only the ones called from
fast interrupt handlers and the swi_sched of softclock needed this flag.
Note that to ensure that swi_sched()'s in clock and fast interrupt
handlers do not switch, these handlers have to be explicitly wrapped
in critical_enter/exit pairs. Presently, just wrapping the handlers is
sufficient, but in the future with the fully preemptive kernel, the
interrupt must be EOI'd before critical_exit() is called. (critical_exit()
can switch due to a deferred preemption in a fully preemptive kernel.)
I've tested the changes to the interrupt code on i386 and alpha. I have
not tested ia64, but the interrupt code is almost identical to the alpha
code, so I expect it will work fine. PowerPC and ARM do not yet have
interrupt code in the tree so they shouldn't be broken. Sparc64 is
broken, but that's been ok'd by jake and tmm who will be fixing the
interrupt code for sparc64 shortly.
Reviewed by: peter
Tested on: i386, alpha
2002-01-05 08:47:13 +00:00
|
|
|
DROP_GIANT();
|
2002-02-11 20:37:54 +00:00
|
|
|
td->td_priority = td->td_ksegrp->kg_user_pri; /* XXXKSE */
|
2001-09-12 08:38:13 +00:00
|
|
|
setrunqueue(td);
|
|
|
|
td->td_proc->p_stats->p_ru.ru_nivcsw++;
|
1999-02-02 12:11:01 +00:00
|
|
|
mi_switch();
|
Change and clean the mutex lock interface.
mtx_enter(lock, type) becomes:
mtx_lock(lock) for sleep locks (MTX_DEF-initialized locks)
mtx_lock_spin(lock) for spin locks (MTX_SPIN-initialized)
similarily, for releasing a lock, we now have:
mtx_unlock(lock) for MTX_DEF and mtx_unlock_spin(lock) for MTX_SPIN.
We change the caller interface for the two different types of locks
because the semantics are entirely different for each case, and this
makes it explicitly clear and, at the same time, it rids us of the
extra `type' argument.
The enter->lock and exit->unlock change has been made with the idea
that we're "locking data" and not "entering locked code" in mind.
Further, remove all additional "flags" previously passed to the
lock acquire/release routines with the exception of two:
MTX_QUIET and MTX_NOSWITCH
The functionality of these flags is preserved and they can be passed
to the lock/unlock routines by calling the corresponding wrappers:
mtx_{lock, unlock}_flags(lock, flag(s)) and
mtx_{lock, unlock}_spin_flags(lock, flag(s)) for MTX_DEF and MTX_SPIN
locks, respectively.
Re-inline some lock acq/rel code; in the sleep lock case, we only
inline the _obtain_lock()s in order to ensure that the inlined code
fits into a cache line. In the spin lock case, we inline recursion and
actually only perform a function call if we need to spin. This change
has been made with the idea that we generally tend to avoid spin locks
and that also the spin locks that we do have and are heavily used
(i.e. sched_lock) do recurse, and therefore in an effort to reduce
function call overhead for some architectures (such as alpha), we
inline recursion for this case.
Create a new malloc type for the witness code and retire from using
the M_DEV type. The new type is called M_WITNESS and is only declared
if WITNESS is enabled.
Begin cleaning up some machdep/mutex.h code - specifically updated the
"optimized" inlined code in alpha/mutex.h and wrote MTX_LOCK_SPIN
and MTX_UNLOCK_SPIN asm macros for the i386/mutex.h as we presently
need those.
Finally, caught up to the interface changes in all sys code.
Contributors: jake, jhb, jasone (in no particular order)
2001-02-09 06:11:45 +00:00
|
|
|
mtx_unlock_spin(&sched_lock);
|
2000-11-16 02:16:44 +00:00
|
|
|
PICKUP_GIANT();
|
1999-02-02 12:11:01 +00:00
|
|
|
}
|
2001-02-16 14:31:49 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
copyinfrom(const void *src, void *dst, size_t len, int seg)
|
|
|
|
{
|
|
|
|
int error = 0;
|
|
|
|
|
|
|
|
switch (seg) {
|
|
|
|
case UIO_USERSPACE:
|
|
|
|
error = copyin(src, dst, len);
|
|
|
|
break;
|
|
|
|
case UIO_SYSSPACE:
|
|
|
|
bcopy(src, dst, len);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
panic("copyinfrom: bad seg %d\n", seg);
|
|
|
|
}
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
copyinstrfrom(const void *src, void *dst, size_t len, size_t *copied, int seg)
|
|
|
|
{
|
|
|
|
int error = 0;
|
|
|
|
|
|
|
|
switch (seg) {
|
|
|
|
case UIO_USERSPACE:
|
|
|
|
error = copyinstr(src, dst, len, copied);
|
|
|
|
break;
|
|
|
|
case UIO_SYSSPACE:
|
|
|
|
error = copystr(src, dst, len, copied);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
panic("copyinstrfrom: bad seg %d\n", seg);
|
|
|
|
}
|
|
|
|
return (error);
|
|
|
|
}
|