File: [local] / sys / kern / vfs_cluster.c (download)
Revision 1.1.1.1 (vendor branch), Tue Mar 4 16:15:04 2008 UTC (16 years, 4 months ago) by nbrk
Branch: OPENBSD_4_2_BASE, MAIN
CVS Tags: jornada-partial-support-wip, HEAD Changes since 1.1: +0 -0 lines
Import of OpenBSD 4.2 release kernel tree with initial code to support
Jornada 720/728, StrongARM 1110-based handheld PC.
At this point kernel roots on NFS and boots into vfs_mountroot() and traps.
What is supported:
- glass console, Jornada framebuffer (jfb) works in 16bpp direct color mode
(needs some palette tweaks for non black/white/blue colors, i think)
- saic, SA11x0 interrupt controller (needs cleanup)
- sacom, SA11x0 UART (supported only as boot console for now)
- SA11x0 GPIO controller fully supported (but can't handle multiple interrupt
handlers on one gpio pin)
- sassp, SSP port on SA11x0 that attaches spibus
- Jornada microcontroller (jmcu) to control kbd, battery, etc throught
the SPI bus (wskbd attaches on jmcu, but not tested)
- tod functions seem work
- initial code for SA-1111 (chip companion) : this is TODO
Next important steps, i think:
- gpio and intc on sa1111
- pcmcia support for sa11x0 (and sa1111 help logic)
- REAL root on nfs when we have PCMCIA support (we may use any of supported pccard NICs)
- root on wd0! (using already supported PCMCIA-ATA)
|
/* $OpenBSD: vfs_cluster.c,v 1.37 2007/05/26 20:26:51 pedro Exp $ */
/* $NetBSD: vfs_cluster.c,v 1.12 1996/04/22 01:39:05 christos Exp $ */
/*
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
*
* 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. 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.
*
* @(#)vfs_cluster.c 8.8 (Berkeley) 7/28/94
*/
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/buf.h>
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/malloc.h>
#include <sys/systm.h>
#include <sys/resourcevar.h>
#include <uvm/uvm_extern.h>
void cluster_wbuild(struct vnode *, struct buf *, long, daddr64_t, int,
daddr64_t);
struct cluster_save *cluster_collectbufs(struct vnode *, struct cluster_info *,
struct buf *);
/*
* Do clustered write for FFS.
*
* Three cases:
* 1. Write is not sequential (write asynchronously)
* Write is sequential:
* 2. beginning of cluster - begin cluster
* 3. middle of a cluster - add to cluster
* 4. end of a cluster - asynchronously write cluster
*/
void
cluster_write(struct buf *bp, struct cluster_info *ci, u_quad_t filesize)
{
struct vnode *vp;
daddr64_t lbn;
int maxclen, cursize;
vp = bp->b_vp;
lbn = bp->b_lblkno;
/* Initialize vnode to beginning of file. */
if (lbn == 0)
ci->ci_lasta = ci->ci_clen = ci->ci_cstart = ci->ci_lastw = 0;
if (ci->ci_clen == 0 || lbn != ci->ci_lastw + 1 ||
(bp->b_blkno != ci->ci_lasta + btodb(bp->b_bcount))) {
maxclen = MAXBSIZE / vp->v_mount->mnt_stat.f_iosize - 1;
if (ci->ci_clen != 0) {
/*
* Next block is not sequential.
*
* If we are not writing at end of file, the process
* seeked to another point in the file since its
* last write, or we have reached our maximum
* cluster size, then push the previous cluster.
* Otherwise try reallocating to make it sequential.
*/
cursize = ci->ci_lastw - ci->ci_cstart + 1;
if (((u_quad_t)(lbn + 1)) * bp->b_bcount != filesize ||
lbn != ci->ci_lastw + 1 || ci->ci_clen <= cursize) {
cluster_wbuild(vp, NULL, bp->b_bcount,
ci->ci_cstart, cursize, lbn);
} else {
struct buf **bpp, **endbp;
struct cluster_save *buflist;
buflist = cluster_collectbufs(vp, ci, bp);
endbp = &buflist->bs_children
[buflist->bs_nchildren - 1];
if (VOP_REALLOCBLKS(vp, buflist)) {
/*
* Failed, push the previous cluster.
*/
for (bpp = buflist->bs_children;
bpp < endbp; bpp++)
brelse(*bpp);
free(buflist, M_VCLUSTER);
cluster_wbuild(vp, NULL, bp->b_bcount,
ci->ci_cstart, cursize, lbn);
} else {
/*
* Succeeded, keep building cluster.
*/
for (bpp = buflist->bs_children;
bpp <= endbp; bpp++)
bdwrite(*bpp);
free(buflist, M_VCLUSTER);
ci->ci_lastw = lbn;
ci->ci_lasta = bp->b_blkno;
return;
}
}
}
/*
* Consider beginning a cluster.
* If at end of file, make cluster as large as possible,
* otherwise find size of existing cluster.
*/
if ((u_quad_t)(lbn + 1) * (u_quad_t)bp->b_bcount != filesize &&
(VOP_BMAP(vp, lbn, NULL, &bp->b_blkno, &maxclen) ||
bp->b_blkno == -1)) {
bawrite(bp);
ci->ci_clen = 0;
ci->ci_lasta = bp->b_blkno;
ci->ci_cstart = lbn + 1;
ci->ci_lastw = lbn;
return;
}
ci->ci_clen = maxclen;
if (maxclen == 0) { /* I/O not contiguous */
ci->ci_cstart = lbn + 1;
bawrite(bp);
} else { /* Wait for rest of cluster */
ci->ci_cstart = lbn;
bdwrite(bp);
}
} else if (lbn == ci->ci_cstart + ci->ci_clen) {
/*
* At end of cluster, write it out.
*/
cluster_wbuild(vp, bp, bp->b_bcount, ci->ci_cstart,
ci->ci_clen + 1, lbn);
ci->ci_clen = 0;
ci->ci_cstart = lbn + 1;
} else
/*
* In the middle of a cluster, so just delay the
* I/O for now.
*/
bdwrite(bp);
ci->ci_lastw = lbn;
ci->ci_lasta = bp->b_blkno;
}
/*
* The last lbn argument is the current block on which I/O is being
* performed. Check to see that it doesn't fall in the middle of
* the current block (if last_bp == NULL).
*/
void
cluster_wbuild(struct vnode *vp, struct buf *last_bp, long size,
daddr64_t start_lbn, int len, daddr64_t lbn)
{
struct buf *bp;
#ifdef DIAGNOSTIC
if (size != vp->v_mount->mnt_stat.f_iosize)
panic("cluster_wbuild: size %ld != filesize %ld",
size, vp->v_mount->mnt_stat.f_iosize);
#endif
redo:
while ((!incore(vp, start_lbn) || start_lbn == lbn) && len) {
++start_lbn;
--len;
}
/* Get more memory for current buffer */
if (len <= 1) {
if (last_bp) {
bawrite(last_bp);
} else if (len) {
bp = getblk(vp, start_lbn, size, 0, 0);
/*
* The buffer could have already been flushed out of
* the cache. If that has happened, we'll get a new
* buffer here with random data, just drop it.
*/
if ((bp->b_flags & B_DELWRI) == 0)
brelse(bp);
else
bawrite(bp);
}
return;
}
bp = getblk(vp, start_lbn, size, 0, 0);
if (!(bp->b_flags & B_DELWRI)) {
++start_lbn;
--len;
brelse(bp);
goto redo;
}
++start_lbn;
--len;
bawrite(bp);
goto redo;
}
/*
* Collect together all the buffers in a cluster.
* Plus add one additional buffer.
*/
struct cluster_save *
cluster_collectbufs(struct vnode *vp, struct cluster_info *ci,
struct buf *last_bp)
{
struct cluster_save *buflist;
daddr64_t lbn;
int i, len;
len = ci->ci_lastw - ci->ci_cstart + 1;
buflist = malloc(sizeof(struct buf *) * (len + 1) + sizeof(*buflist),
M_VCLUSTER, M_WAITOK);
buflist->bs_nchildren = 0;
buflist->bs_children = (struct buf **)(buflist + 1);
for (lbn = ci->ci_cstart, i = 0; i < len; lbn++, i++)
(void)bread(vp, lbn, last_bp->b_bcount, NOCRED,
&buflist->bs_children[i]);
buflist->bs_children[i] = last_bp;
buflist->bs_nchildren = i + 1;
return (buflist);
}