Re-implement read-modify-write backend strategy. This version is a lot more
clean locking-wise and will consume less CPU power on needless moving-around.
This commit is contained in:
parent
0a3cb580be
commit
4eb9ccfea3
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: udf_strat_rmw.c,v 1.20 2009/07/02 16:56:35 reinoud Exp $ */
|
||||
/* $NetBSD: udf_strat_rmw.c,v 1.21 2009/07/06 17:13:38 reinoud Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006, 2008 Reinoud Zandijk
|
||||
@ -28,7 +28,7 @@
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__KERNEL_RCSID(0, "$NetBSD: udf_strat_rmw.c,v 1.20 2009/07/02 16:56:35 reinoud Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: udf_strat_rmw.c,v 1.21 2009/07/06 17:13:38 reinoud Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
|
||||
@ -79,7 +79,7 @@ __KERNEL_RCSID(0, "$NetBSD: udf_strat_rmw.c,v 1.20 2009/07/02 16:56:35 reinoud E
|
||||
#define UDF_SHED_READING 2
|
||||
#define UDF_SHED_WRITING 3
|
||||
#define UDF_SHED_SEQWRITING 4
|
||||
#define UDF_SHED_IDLE 5 /* resting */
|
||||
#define UDF_SHED_IDLE 5 /* refcnt'd */
|
||||
#define UDF_SHED_FREE 6 /* recycleable */
|
||||
#define UDF_SHED_MAX 6+1
|
||||
|
||||
@ -105,6 +105,9 @@ struct udf_eccline {
|
||||
uint32_t flags;
|
||||
uint32_t start_sector; /* physical */
|
||||
|
||||
const char *fname;
|
||||
int sline;
|
||||
|
||||
struct buf *buf;
|
||||
void *blob;
|
||||
|
||||
@ -141,22 +144,29 @@ struct strat_private {
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
#define UDF_LOCK_ECCLINE(eccline) udf_lock_eccline(eccline)
|
||||
#define UDF_UNLOCK_ECCLINE(eccline) udf_unlock_eccline(eccline)
|
||||
#define UDF_LOCK_ECCLINE(eccline) udf_lock_eccline(eccline, __FILE__, __LINE__)
|
||||
#define UDF_UNLOCK_ECCLINE(eccline) udf_unlock_eccline(eccline, __FILE__, __LINE__)
|
||||
|
||||
/* can be called with or without discstrat lock */
|
||||
static void
|
||||
udf_lock_eccline(struct udf_eccline *eccline)
|
||||
udf_lock_eccline(struct udf_eccline *eccline, const char *fname, int sline)
|
||||
{
|
||||
struct strat_private *priv = PRIV(eccline->ump);
|
||||
int waslocked, ret;
|
||||
|
||||
KASSERT(mutex_owned(&priv->discstrat_mutex));
|
||||
|
||||
waslocked = mutex_owned(&priv->discstrat_mutex);
|
||||
if (!waslocked)
|
||||
mutex_enter(&priv->discstrat_mutex);
|
||||
|
||||
/* wait until its unlocked first */
|
||||
eccline->refcnt++;
|
||||
while (eccline->flags & ECC_LOCKED) {
|
||||
DPRINTF(ECCLINE, ("waiting for lock at %s:%d\n",
|
||||
fname, sline));
|
||||
DPRINTF(ECCLINE, ("was locked at %s:%d\n",
|
||||
eccline->fname, eccline->sline));
|
||||
eccline->flags |= ECC_WANTED;
|
||||
ret = cv_timedwait(&priv->discstrat_cv, &priv->discstrat_mutex,
|
||||
hz/8);
|
||||
@ -166,6 +176,10 @@ udf_lock_eccline(struct udf_eccline *eccline)
|
||||
}
|
||||
eccline->flags |= ECC_LOCKED;
|
||||
eccline->flags &= ~ECC_WANTED;
|
||||
eccline->refcnt--;
|
||||
|
||||
eccline->fname = fname;
|
||||
eccline->sline = sline;
|
||||
|
||||
if (!waslocked)
|
||||
mutex_exit(&priv->discstrat_mutex);
|
||||
@ -174,11 +188,13 @@ udf_lock_eccline(struct udf_eccline *eccline)
|
||||
|
||||
/* can be called with or without discstrat lock */
|
||||
static void
|
||||
udf_unlock_eccline(struct udf_eccline *eccline)
|
||||
udf_unlock_eccline(struct udf_eccline *eccline, const char *fname, int sline)
|
||||
{
|
||||
struct strat_private *priv = PRIV(eccline->ump);
|
||||
int waslocked;
|
||||
|
||||
KASSERT(mutex_owned(&priv->discstrat_mutex));
|
||||
|
||||
waslocked = mutex_owned(&priv->discstrat_mutex);
|
||||
if (!waslocked)
|
||||
mutex_enter(&priv->discstrat_mutex);
|
||||
@ -196,28 +212,21 @@ static void
|
||||
udf_dispose_eccline(struct udf_eccline *eccline)
|
||||
{
|
||||
struct strat_private *priv = PRIV(eccline->ump);
|
||||
struct buf *ret;
|
||||
|
||||
KASSERT(mutex_owned(&priv->discstrat_mutex));
|
||||
|
||||
KASSERT(eccline->refcnt == 0);
|
||||
KASSERT(eccline->dirty == 0);
|
||||
|
||||
DPRINTF(ECCLINE, ("dispose eccline with start sector %d, "
|
||||
"present %0"PRIx64"\n", eccline->start_sector,
|
||||
eccline->present));
|
||||
|
||||
if (eccline->queued_on) {
|
||||
ret = bufq_cancel(priv->queues[eccline->queued_on], eccline->buf);
|
||||
KASSERT(ret == eccline->buf);
|
||||
priv->num_queued[eccline->queued_on]--;
|
||||
}
|
||||
LIST_REMOVE(eccline, hashchain);
|
||||
KASSERT(eccline->refcnt == 0);
|
||||
KASSERT(eccline->dirty == 0);
|
||||
KASSERT(eccline->queued_on == 0);
|
||||
KASSERT(eccline->flags & ECC_FLOATING);
|
||||
KASSERT(eccline->flags & ECC_LOCKED);
|
||||
|
||||
if (eccline->flags & ECC_FLOATING) {
|
||||
eccline->flags &= ~ECC_FLOATING;
|
||||
priv->num_floating--;
|
||||
}
|
||||
LIST_REMOVE(eccline, hashchain);
|
||||
priv->num_floating--;
|
||||
|
||||
putiobuf(eccline->buf);
|
||||
pool_put(&priv->ecclineblob_pool, eccline->blob);
|
||||
@ -230,71 +239,68 @@ static void
|
||||
udf_push_eccline(struct udf_eccline *eccline, int newqueue)
|
||||
{
|
||||
struct strat_private *priv = PRIV(eccline->ump);
|
||||
struct buf *ret;
|
||||
int curqueue;
|
||||
|
||||
KASSERT(mutex_owned(&priv->discstrat_mutex));
|
||||
|
||||
DPRINTF(PARANOIA, ("DEBUG: buf %p pushed on queue %d\n", eccline->buf, newqueue));
|
||||
|
||||
/* requeue */
|
||||
curqueue = eccline->queued_on;
|
||||
if (curqueue) {
|
||||
ret = bufq_cancel(priv->queues[curqueue], eccline->buf);
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
if (ret == NULL) {
|
||||
int i;
|
||||
|
||||
printf("udf_push_eccline: bufq_cancel can't find "
|
||||
"buffer %p on queue %d; "
|
||||
"dumping queues\n", eccline->buf, curqueue);
|
||||
for (i = 1; i < UDF_SHED_MAX; i++) {
|
||||
printf("queue %d\n\t", i);
|
||||
ret = bufq_get(priv->queues[i]);
|
||||
while (ret) {
|
||||
printf("%p ", ret);
|
||||
if (BTOE(ret)->queued_on != i)
|
||||
printf("WRONGQ ");
|
||||
if (ret == eccline->buf)
|
||||
printf("[<-] ");
|
||||
if (ret == bufq_peek(priv->queues[i])) {
|
||||
printf("LOOP ");
|
||||
break;
|
||||
}
|
||||
ret = bufq_get(priv->queues[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
panic("fatal queue bug; exit");
|
||||
}
|
||||
#endif
|
||||
|
||||
KASSERT(ret == eccline->buf);
|
||||
priv->num_queued[curqueue]--;
|
||||
}
|
||||
KASSERT(eccline->queued_on == 0);
|
||||
KASSERT(eccline->flags & ECC_FLOATING);
|
||||
|
||||
/* set buffer block numbers to make sure its queued correctly */
|
||||
eccline->buf->b_lblkno = eccline->start_sector;
|
||||
eccline->buf->b_blkno = eccline->start_sector;
|
||||
eccline->buf->b_rawblkno = eccline->start_sector;
|
||||
|
||||
vfs_timestamp(&priv->last_queued[newqueue]);
|
||||
eccline->flags &= ~ECC_FLOATING;
|
||||
priv->num_floating--;
|
||||
eccline->queued_on = newqueue;
|
||||
priv->num_queued[newqueue]++;
|
||||
bufq_put(priv->queues[newqueue], eccline->buf);
|
||||
vfs_timestamp(&priv->last_queued[newqueue]);
|
||||
|
||||
if (eccline->flags & ECC_FLOATING) {
|
||||
eccline->flags &= ~ECC_FLOATING;
|
||||
priv->num_floating--;
|
||||
}
|
||||
UDF_UNLOCK_ECCLINE(eccline);
|
||||
|
||||
/* tickle disc strategy statemachine */
|
||||
/* XXX tickle disc strategy statemachine */
|
||||
if (newqueue != UDF_SHED_IDLE)
|
||||
cv_signal(&priv->discstrat_cv);
|
||||
}
|
||||
|
||||
|
||||
static struct udf_eccline *
|
||||
udf_peek_eccline(struct strat_private *priv, int queued_on)
|
||||
{
|
||||
struct udf_eccline *eccline;
|
||||
struct buf *buf;
|
||||
|
||||
KASSERT(mutex_owned(&priv->discstrat_mutex));
|
||||
|
||||
for(;;) {
|
||||
buf = bufq_peek(priv->queues[queued_on]);
|
||||
/* could have been a race, but we'll revisit later */
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
eccline = BTOE(buf);
|
||||
UDF_LOCK_ECCLINE(eccline);
|
||||
|
||||
/* might have changed before we obtained the lock */
|
||||
if (eccline->queued_on == queued_on)
|
||||
break;
|
||||
|
||||
UDF_UNLOCK_ECCLINE(eccline);
|
||||
}
|
||||
|
||||
KASSERT(eccline->queued_on == queued_on);
|
||||
KASSERT((eccline->flags & ECC_FLOATING) == 0);
|
||||
|
||||
DPRINTF(PARANOIA, ("DEBUG: buf %p peeked at queue %d\n",
|
||||
eccline->buf, queued_on));
|
||||
|
||||
return eccline;
|
||||
}
|
||||
|
||||
|
||||
static struct udf_eccline *
|
||||
udf_pop_eccline(struct strat_private *priv, int queued_on)
|
||||
{
|
||||
@ -303,19 +309,29 @@ udf_pop_eccline(struct strat_private *priv, int queued_on)
|
||||
|
||||
KASSERT(mutex_owned(&priv->discstrat_mutex));
|
||||
|
||||
buf = bufq_get(priv->queues[queued_on]);
|
||||
if (buf == NULL) {
|
||||
KASSERT(priv->num_queued[queued_on] == 0);
|
||||
return NULL;
|
||||
for(;;) {
|
||||
buf = bufq_get(priv->queues[queued_on]);
|
||||
if (buf == NULL) {
|
||||
// KASSERT(priv->num_queued[queued_on] == 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
eccline = BTOE(buf);
|
||||
UDF_LOCK_ECCLINE(eccline);
|
||||
|
||||
/* might have changed before we obtained the lock */
|
||||
if (eccline->queued_on == queued_on)
|
||||
break;
|
||||
|
||||
UDF_UNLOCK_ECCLINE(eccline);
|
||||
}
|
||||
|
||||
eccline = BTOE(buf);
|
||||
KASSERT(eccline->queued_on == queued_on);
|
||||
eccline->queued_on = 0;
|
||||
priv->num_queued[queued_on]--;
|
||||
KASSERT((eccline->flags & ECC_FLOATING) == 0);
|
||||
|
||||
priv->num_queued[queued_on]--;
|
||||
eccline->queued_on = 0;
|
||||
|
||||
if (eccline->flags & ECC_FLOATING)
|
||||
panic("popping already marked floating eccline");
|
||||
eccline->flags |= ECC_FLOATING;
|
||||
priv->num_floating++;
|
||||
|
||||
@ -326,6 +342,28 @@ udf_pop_eccline(struct strat_private *priv, int queued_on)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
udf_unqueue_eccline(struct strat_private *priv, struct udf_eccline *eccline)
|
||||
{
|
||||
struct buf *ret;
|
||||
|
||||
UDF_LOCK_ECCLINE(eccline);
|
||||
if (eccline->queued_on == 0) {
|
||||
KASSERT(eccline->flags & ECC_FLOATING);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = bufq_cancel(priv->queues[eccline->queued_on], eccline->buf);
|
||||
KASSERT(ret == eccline->buf);
|
||||
|
||||
priv->num_queued[eccline->queued_on]--;
|
||||
eccline->queued_on = 0;
|
||||
|
||||
eccline->flags |= ECC_FLOATING;
|
||||
priv->num_floating++;
|
||||
}
|
||||
|
||||
|
||||
static struct udf_eccline *
|
||||
udf_geteccline(struct udf_mount *ump, uint32_t sector, int flags)
|
||||
{
|
||||
@ -336,11 +374,13 @@ udf_geteccline(struct udf_mount *ump, uint32_t sector, int flags)
|
||||
int line, line_offset;
|
||||
int num_busy, ret;
|
||||
|
||||
mutex_enter(&priv->discstrat_mutex);
|
||||
|
||||
/* lookup in our line cache hashtable */
|
||||
line_offset = sector % ump->packet_size;
|
||||
start_sector = sector - line_offset;
|
||||
line = (start_sector/ump->packet_size) & UDF_ECCBUF_HASHMASK;
|
||||
|
||||
mutex_enter(&priv->discstrat_mutex);
|
||||
KASSERT(priv->thread_running);
|
||||
|
||||
retry:
|
||||
@ -349,22 +389,15 @@ retry:
|
||||
if (eccline->start_sector == start_sector) {
|
||||
DPRINTF(ECCLINE, ("\tfound eccline, start_sector %d\n",
|
||||
eccline->start_sector));
|
||||
udf_unqueue_eccline(priv, eccline);
|
||||
|
||||
UDF_LOCK_ECCLINE(eccline);
|
||||
/* move from freelist (!) */
|
||||
if (eccline->queued_on == UDF_SHED_FREE) {
|
||||
DPRINTF(ECCLINE, ("was on freelist\n"));
|
||||
KASSERT(eccline->refcnt == 0);
|
||||
udf_push_eccline(eccline, UDF_SHED_IDLE);
|
||||
}
|
||||
eccline->refcnt++;
|
||||
mutex_exit(&priv->discstrat_mutex);
|
||||
return eccline;
|
||||
}
|
||||
}
|
||||
|
||||
DPRINTF(ECCLINE, ("\tnot found in eccline cache\n"));
|
||||
/* not found in eccline cache */
|
||||
DPRINTF(ECCLINE, ("\tnot found in eccline cache\n"));
|
||||
|
||||
lb_size = udf_rw32(ump->logical_vol->lb_size);
|
||||
blobsize = ump->packet_size * lb_size;
|
||||
@ -396,23 +429,21 @@ retry:
|
||||
}
|
||||
|
||||
/* push back line if we're waiting for it or its locked */
|
||||
if (eccline->flags & (ECC_WANTED | ECC_LOCKED)) {
|
||||
/* XXX what were they doing on the free list anyway? */
|
||||
udf_push_eccline(eccline, UDF_SHED_WAITING);
|
||||
if (eccline->flags & ECC_WANTED) {
|
||||
/* we won a race, but someone else needed it */
|
||||
udf_push_eccline(eccline, UDF_SHED_FREE);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
/* unlink this entry */
|
||||
LIST_REMOVE(eccline, hashchain);
|
||||
|
||||
KASSERT(eccline->flags & ECC_FLOATING);
|
||||
|
||||
KASSERT(eccline->queued_on == 0);
|
||||
|
||||
eccline_blob = eccline->blob;
|
||||
memset(eccline, 0, sizeof(struct udf_eccline));
|
||||
eccline->flags = ECC_FLOATING;
|
||||
eccline->flags = ECC_FLOATING | ECC_LOCKED;
|
||||
} else {
|
||||
memset(eccline, 0, sizeof(struct udf_eccline));
|
||||
eccline->flags = ECC_FLOATING;
|
||||
eccline->flags = ECC_FLOATING | ECC_LOCKED;
|
||||
priv->num_floating++;
|
||||
}
|
||||
|
||||
@ -422,12 +453,14 @@ retry:
|
||||
eccline->buf->b_private = eccline; /* IMPORTANT */
|
||||
|
||||
/* initialise eccline blob */
|
||||
/* XXX memset expensive and strictly not needed XXX */
|
||||
memset(eccline->blob, 0, blobsize);
|
||||
|
||||
eccline->ump = ump;
|
||||
eccline->present = eccline->readin = eccline->dirty = 0;
|
||||
eccline->error = 0;
|
||||
eccline->refcnt = 0;
|
||||
memset(eccline->bufs, 0, UDF_MAX_PACKET_SIZE * sizeof(struct buf *));
|
||||
|
||||
eccline->start_sector = start_sector;
|
||||
eccline->buf->b_lblkno = start_sector;
|
||||
@ -440,9 +473,10 @@ retry:
|
||||
* TODO possible optimalisation for checking overlap with partitions
|
||||
* to get a clue on future eccline usage
|
||||
*/
|
||||
eccline->refcnt++;
|
||||
UDF_LOCK_ECCLINE(eccline);
|
||||
|
||||
KASSERT(eccline->refcnt == 0);
|
||||
KASSERT(eccline->flags & ECC_FLOATING);
|
||||
KASSERT(eccline->flags & ECC_LOCKED);
|
||||
mutex_exit(&priv->discstrat_mutex);
|
||||
|
||||
return eccline;
|
||||
@ -455,32 +489,45 @@ udf_puteccline(struct udf_eccline *eccline)
|
||||
struct strat_private *priv = PRIV(eccline->ump);
|
||||
struct udf_mount *ump = eccline->ump;
|
||||
uint64_t allbits = ((uint64_t) 1 << ump->packet_size)-1;
|
||||
int new_queue;
|
||||
|
||||
mutex_enter(&priv->discstrat_mutex);
|
||||
|
||||
/* clear directly all readin requests from present ones */
|
||||
if (eccline->readin & eccline->present) {
|
||||
/* clear all read bits that are already read in */
|
||||
eccline->readin &= (~eccline->present) & allbits;
|
||||
wakeup(eccline);
|
||||
}
|
||||
|
||||
DPRINTF(ECCLINE, ("put eccline start sector %d, refcnt %d\n",
|
||||
eccline->start_sector, eccline->refcnt));
|
||||
|
||||
KASSERT(eccline->flags & ECC_LOCKED);
|
||||
KASSERT(eccline->flags & ECC_FLOATING);
|
||||
|
||||
/* clear all read bits that are already read in */
|
||||
if (eccline->readin & eccline->present)
|
||||
eccline->readin &= (~eccline->present) & allbits;
|
||||
|
||||
/* if we have active nodes we dont set it on seqwriting */
|
||||
if (eccline->refcnt > 1)
|
||||
eccline->flags &= ~ECC_SEQWRITING;
|
||||
|
||||
vfs_timestamp(&eccline->wait_time);
|
||||
eccline->wait_time.tv_sec += ECC_WAITTIME;
|
||||
udf_push_eccline(eccline, UDF_SHED_WAITING);
|
||||
/* select state */
|
||||
new_queue = UDF_SHED_FREE;
|
||||
if (eccline->refcnt > 0)
|
||||
new_queue = UDF_SHED_IDLE;
|
||||
if (eccline->flags & ECC_WANTED)
|
||||
new_queue = UDF_SHED_IDLE;
|
||||
if (eccline->readin)
|
||||
new_queue = UDF_SHED_READING;
|
||||
if (eccline->dirty) {
|
||||
new_queue = UDF_SHED_WAITING;
|
||||
vfs_timestamp(&eccline->wait_time);
|
||||
eccline->wait_time.tv_sec += ECC_WAITTIME;
|
||||
|
||||
KASSERT(eccline->refcnt >= 1);
|
||||
eccline->refcnt--;
|
||||
UDF_UNLOCK_ECCLINE(eccline);
|
||||
if (eccline->present == allbits) {
|
||||
new_queue = UDF_SHED_WRITING;
|
||||
if (eccline->flags & ECC_SEQWRITING)
|
||||
new_queue = UDF_SHED_SEQWRITING;
|
||||
}
|
||||
}
|
||||
udf_push_eccline(eccline, new_queue);
|
||||
|
||||
wakeup(eccline);
|
||||
mutex_exit(&priv->discstrat_mutex);
|
||||
}
|
||||
|
||||
@ -545,7 +592,10 @@ udf_free_nodedscr_rmw(struct udf_strat_args *args)
|
||||
eccsect = sectornr - eccline->start_sector;
|
||||
|
||||
bit = (uint64_t) 1 << eccsect;
|
||||
KASSERT(eccline->present & bit);
|
||||
|
||||
eccline->readin &= ~bit; /* just in case */
|
||||
/* XXX eccline->dirty? */
|
||||
|
||||
KASSERT(eccline->refcnt >= 1);
|
||||
eccline->refcnt--;
|
||||
@ -560,6 +610,7 @@ udf_read_nodedscr_rmw(struct udf_strat_args *args)
|
||||
union dscrptr **dscrptr = &args->dscr;
|
||||
struct udf_mount *ump = args->ump;
|
||||
struct long_ad *icb = args->icb;
|
||||
struct strat_private *priv;
|
||||
struct udf_eccline *eccline;
|
||||
uint64_t bit;
|
||||
uint32_t sectornr, dummy;
|
||||
@ -586,22 +637,28 @@ udf_read_nodedscr_rmw(struct udf_strat_args *args)
|
||||
KASSERT(eccline->bufs[eccsect] == NULL);
|
||||
udf_puteccline(eccline);
|
||||
|
||||
/* wait for completion; XXX remodel to lock bit code */
|
||||
error = 0;
|
||||
while ((eccline->present & bit) == 0) {
|
||||
tsleep(eccline, PRIBIO+1, "udflvdrd", hz/8);
|
||||
if (eccline->error & bit) {
|
||||
KASSERT(eccline->refcnt >= 1);
|
||||
eccline->refcnt--; /* undo temp refcnt */
|
||||
*dscrptr = NULL;
|
||||
return EIO; /* XXX error code */
|
||||
}
|
||||
/* wait for completion */
|
||||
priv = PRIV(eccline->ump);
|
||||
mutex_enter(&priv->discstrat_mutex);
|
||||
while (((eccline->present | eccline->error) & bit) == 0) {
|
||||
error = cv_timedwait(&priv->discstrat_cv,
|
||||
&priv->discstrat_mutex,
|
||||
hz/8);
|
||||
if (error == EWOULDBLOCK)
|
||||
DPRINTF(LOCKING, ("eccline waiting for read\n"));
|
||||
}
|
||||
mutex_exit(&priv->discstrat_mutex);
|
||||
|
||||
/* reget our line */
|
||||
eccline = udf_geteccline(ump, sectornr, 0);
|
||||
KASSERT(eccline->refcnt >= 1);
|
||||
eccline->refcnt--; /* undo refcnt */
|
||||
|
||||
if (eccline->error & bit) {
|
||||
*dscrptr = NULL;
|
||||
udf_puteccline(eccline);
|
||||
return EIO; /* XXX error code */
|
||||
}
|
||||
}
|
||||
|
||||
*dscrptr = (union dscrptr *)
|
||||
@ -634,6 +691,7 @@ udf_read_nodedscr_rmw(struct udf_strat_args *args)
|
||||
return error;
|
||||
}
|
||||
|
||||
/* we have a hold since it has a node descriptor */
|
||||
eccline->refcnt++;
|
||||
udf_puteccline(eccline);
|
||||
|
||||
@ -663,7 +721,7 @@ udf_write_nodedscr_rmw(struct udf_strat_args *args)
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/* add reference to the vnode to prevent recycling */
|
||||
/* paranoia: add reference to the vnode to prevent recycling */
|
||||
vhold(udf_node->vnode);
|
||||
|
||||
/* get our eccline */
|
||||
@ -699,14 +757,14 @@ udf_write_nodedscr_rmw(struct udf_strat_args *args)
|
||||
|
||||
KASSERT(udf_tagsize(dscrptr, sector_size) <= sector_size);
|
||||
|
||||
udf_puteccline(eccline);
|
||||
|
||||
holdrele(udf_node->vnode);
|
||||
udf_node->outstanding_nodedscr--;
|
||||
if (udf_node->outstanding_nodedscr == 0) {
|
||||
/* XXX still using wakeup! */
|
||||
UDF_UNLOCK_NODE(udf_node, 0);
|
||||
wakeup(&udf_node->outstanding_nodedscr);
|
||||
}
|
||||
holdrele(udf_node->vnode);
|
||||
udf_puteccline(eccline);
|
||||
|
||||
/* XXX waitfor not used */
|
||||
return 0;
|
||||
@ -765,7 +823,7 @@ udf_queuebuf_rmw(struct udf_strat_args *args)
|
||||
bpos = 0;
|
||||
while (buf_len) {
|
||||
len = MIN(buf_len, sector_size);
|
||||
if (eccsect == ump->packet_size) {
|
||||
if ((eccsect < 0) || (eccsect >= ump->packet_size)) {
|
||||
udf_puteccline(eccline);
|
||||
eccline = udf_geteccline(ump, sectornr, 0);
|
||||
eccsect = sectornr - eccline->start_sector;
|
||||
@ -800,24 +858,11 @@ udf_queuebuf_rmw(struct udf_strat_args *args)
|
||||
"type %d, b_resid %d, b_bcount %d, b_bufsize %d\n",
|
||||
buf, (uint32_t) buf->b_blkno / blks, buf->b_udf_c_type,
|
||||
buf->b_resid, buf->b_bcount, buf->b_bufsize));
|
||||
|
||||
/* if we have FIDs fixup using buffer's sector number(s) */
|
||||
if (buf->b_udf_c_type == UDF_C_FIDS) {
|
||||
if (buf->b_udf_c_type == UDF_C_FIDS)
|
||||
panic("UDF_C_FIDS in SHED_WRITING!\n");
|
||||
#if 0
|
||||
buf_len = buf->b_bcount;
|
||||
sectornr = our_sectornr;
|
||||
bpos = 0;
|
||||
while (buf_len) {
|
||||
len = MIN(buf_len, sector_size);
|
||||
fidblk = (uint8_t *) buf->b_data + bpos;
|
||||
udf_fixup_fid_block(fidblk, sector_size,
|
||||
0, len, sectornr);
|
||||
sectornr++;
|
||||
bpos += len;
|
||||
buf_len -= len;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
udf_fixup_node_internals(ump, buf->b_data, buf->b_udf_c_type);
|
||||
|
||||
/* copy parts into the bufs and set for writing */
|
||||
@ -828,7 +873,7 @@ udf_queuebuf_rmw(struct udf_strat_args *args)
|
||||
bpos = 0;
|
||||
while (buf_len) {
|
||||
len = MIN(buf_len, sector_size);
|
||||
if (eccsect == ump->packet_size) {
|
||||
if ((eccsect < 0) || (eccsect >= ump->packet_size)) {
|
||||
udf_puteccline(eccline);
|
||||
eccline = udf_geteccline(ump, sectornr, 0);
|
||||
eccsect = sectornr - eccline->start_sector;
|
||||
@ -976,8 +1021,10 @@ udf_shedule_read_callback(struct buf *buf)
|
||||
int sector_size = ump->discinfo.sector_size;
|
||||
int error, i, len;
|
||||
|
||||
DPRINTF(ECCLINE, ("read callback called\n"));
|
||||
DPRINTF(ECCLINE, ("read callback called on buf %p\n", buf));
|
||||
|
||||
/* post process read action */
|
||||
KASSERT(eccline->flags & ECC_LOCKED);
|
||||
error = buf->b_error;
|
||||
for (i = 0; i < ump->packet_size; i++) {
|
||||
bit = (uint64_t) 1 << i;
|
||||
@ -1008,7 +1055,6 @@ udf_shedule_read_callback(struct buf *buf)
|
||||
*/
|
||||
|
||||
udf_puteccline(eccline);
|
||||
|
||||
DPRINTF(ECCLINE, ("read callback finished\n"));
|
||||
}
|
||||
|
||||
@ -1019,10 +1065,12 @@ udf_shedule_write_callback(struct buf *buf)
|
||||
struct udf_eccline *eccline = BTOE(buf);
|
||||
struct udf_mount *ump = eccline->ump;
|
||||
uint64_t bit;
|
||||
int error, i, len;
|
||||
int error, i;
|
||||
|
||||
DPRINTF(ECCLINE, ("write callback called on buf %p\n", buf));
|
||||
|
||||
DPRINTF(ECCLINE, ("write callback called buf %p\n", buf));
|
||||
/* post process write action */
|
||||
KASSERT(eccline->flags & ECC_LOCKED);
|
||||
error = buf->b_error;
|
||||
for (i = 0; i < ump->packet_size; i++) {
|
||||
bit = (uint64_t) 1 << i;
|
||||
@ -1033,20 +1081,18 @@ udf_shedule_write_callback(struct buf *buf)
|
||||
} else {
|
||||
eccline->dirty &= ~bit;
|
||||
}
|
||||
if (eccline->bufs[i]) {
|
||||
len = eccline->bufs_len[i];
|
||||
nestiobuf_done(eccline->bufs[i], len, error);
|
||||
eccline->bufs[i] = NULL;
|
||||
}
|
||||
|
||||
KASSERT(eccline->bufs[i] == 0);
|
||||
}
|
||||
KASSERT(eccline->dirty == 0);
|
||||
|
||||
KASSERT(error == 0);
|
||||
|
||||
/*
|
||||
* XXX TODO on write errors allocate a sparable entry and reissue
|
||||
*/
|
||||
|
||||
udf_puteccline(eccline);
|
||||
DPRINTF(ECCLINE, ("write callback finished\n"));
|
||||
}
|
||||
|
||||
|
||||
@ -1062,6 +1108,8 @@ udf_issue_eccline(struct udf_eccline *eccline, int queued_on)
|
||||
int blks = sector_size / DEV_BSIZE;
|
||||
int i;
|
||||
|
||||
KASSERT(eccline->flags & ECC_LOCKED);
|
||||
|
||||
if (queued_on == UDF_SHED_READING) {
|
||||
DPRINTF(SHEDULE, ("udf_issue_eccline reading : "));
|
||||
/* read all bits that are not yet present */
|
||||
@ -1096,10 +1144,13 @@ udf_issue_eccline(struct udf_eccline *eccline, int queued_on)
|
||||
nestbuf->b_blkno = buf->b_blkno + i*blks;
|
||||
nestbuf->b_rawblkno = buf->b_rawblkno + i*blks;
|
||||
|
||||
DPRINTF(SHEDULE, ("sector %d ",
|
||||
start + i));
|
||||
/* call asynchronous */
|
||||
VOP_STRATEGY(ump->devvp, nestbuf);
|
||||
DPRINTF(SHEDULE, ("sector %d ", start + i));
|
||||
|
||||
/* mutex dance since it could lock */
|
||||
mutex_exit(&priv->discstrat_mutex);
|
||||
/* call asynchronous */
|
||||
VOP_STRATEGY(ump->devvp, nestbuf);
|
||||
mutex_enter(&priv->discstrat_mutex);
|
||||
}
|
||||
DPRINTF(SHEDULE, ("\n"));
|
||||
return;
|
||||
@ -1110,13 +1161,8 @@ udf_issue_eccline(struct udf_eccline *eccline, int queued_on)
|
||||
DPRINTF(SHEDULE, ("\n\tpresent %"PRIx64", readin %"PRIx64", "
|
||||
"dirty %"PRIx64"\n\t", eccline->present, eccline->readin,
|
||||
eccline->dirty));
|
||||
if (eccline->present != allbits) {
|
||||
/* requeue to read-only */
|
||||
DPRINTF(SHEDULE, ("\n\t-> not complete, requeue to "
|
||||
"reading\n"));
|
||||
udf_push_eccline(eccline, UDF_SHED_READING);
|
||||
return;
|
||||
}
|
||||
KASSERT(eccline->present == allbits);
|
||||
|
||||
start = eccline->start_sector;
|
||||
buf = eccline->buf;
|
||||
buf->b_flags = B_WRITE | B_ASYNC;
|
||||
@ -1133,6 +1179,7 @@ udf_issue_eccline(struct udf_eccline *eccline, int queued_on)
|
||||
buf->b_proc = NULL;
|
||||
}
|
||||
|
||||
/* mutex dance since it could lock */
|
||||
mutex_exit(&priv->discstrat_mutex);
|
||||
/* call asynchronous */
|
||||
DPRINTF(SHEDULE, ("sector %d for %d\n",
|
||||
@ -1150,7 +1197,7 @@ udf_discstrat_thread(void *arg)
|
||||
struct udf_eccline *eccline;
|
||||
struct timespec now, *last;
|
||||
uint64_t allbits = ((uint64_t) 1 << ump->packet_size)-1;
|
||||
int new_queue, wait, work, num, cnt;
|
||||
int new_queue, wait, work;
|
||||
|
||||
work = 1;
|
||||
priv->thread_running = 1;
|
||||
@ -1161,12 +1208,26 @@ udf_discstrat_thread(void *arg)
|
||||
vfs_timestamp(&now);
|
||||
|
||||
/* maintenance: handle eccline state machine */
|
||||
num = priv->num_queued[UDF_SHED_WAITING];
|
||||
cnt = 0;
|
||||
while (cnt < num) {
|
||||
for(;;) {
|
||||
/* only peek at it */
|
||||
eccline = udf_peek_eccline(priv, UDF_SHED_WAITING);
|
||||
if (eccline == NULL)
|
||||
break;
|
||||
|
||||
/* all others are later, so if not satisfied, abort */
|
||||
if ((eccline->wait_time.tv_sec - now.tv_sec > 0)) {
|
||||
UDF_UNLOCK_ECCLINE(eccline);
|
||||
break;
|
||||
}
|
||||
|
||||
/* release */
|
||||
UDF_UNLOCK_ECCLINE(eccline);
|
||||
|
||||
/* do get it */
|
||||
eccline = udf_pop_eccline(priv, UDF_SHED_WAITING);
|
||||
/* requeue */
|
||||
new_queue = UDF_SHED_FREE;
|
||||
|
||||
/* requeue according to state */
|
||||
new_queue = UDF_SHED_FREE; /* unlikely */
|
||||
if (eccline->refcnt > 0)
|
||||
new_queue = UDF_SHED_IDLE;
|
||||
if (eccline->flags & ECC_WANTED)
|
||||
@ -1174,22 +1235,14 @@ udf_discstrat_thread(void *arg)
|
||||
if (eccline->readin)
|
||||
new_queue = UDF_SHED_READING;
|
||||
if (eccline->dirty) {
|
||||
new_queue = UDF_SHED_WAITING;
|
||||
if ((eccline->wait_time.tv_sec - now.tv_sec <= 0) ||
|
||||
((eccline->present == allbits) &&
|
||||
(eccline->flags & ECC_SEQWRITING)))
|
||||
{
|
||||
new_queue = UDF_SHED_READING;
|
||||
if (eccline->present == allbits) {
|
||||
new_queue = UDF_SHED_WRITING;
|
||||
if (eccline->flags & ECC_SEQWRITING)
|
||||
new_queue = UDF_SHED_SEQWRITING;
|
||||
if (eccline->present != allbits)
|
||||
new_queue = UDF_SHED_READING;
|
||||
}
|
||||
}
|
||||
if (eccline->flags & ECC_LOCKED)
|
||||
new_queue = UDF_SHED_WAITING;
|
||||
udf_push_eccline(eccline, new_queue);
|
||||
cnt++;
|
||||
}
|
||||
|
||||
/* maintenance: free excess ecclines */
|
||||
@ -1197,9 +1250,10 @@ udf_discstrat_thread(void *arg)
|
||||
eccline = udf_pop_eccline(priv, UDF_SHED_FREE);
|
||||
KASSERT(eccline);
|
||||
KASSERT(eccline->refcnt == 0);
|
||||
if (eccline->flags & (ECC_WANTED | ECC_LOCKED)) {
|
||||
udf_push_eccline(eccline, UDF_SHED_IDLE);
|
||||
if (eccline->flags & ECC_WANTED) {
|
||||
/* we won the race, but we dont want to win */
|
||||
DPRINTF(ECCLINE, ("Tried removing, pushed back to free list\n"));
|
||||
udf_push_eccline(eccline, UDF_SHED_IDLE);
|
||||
} else {
|
||||
DPRINTF(ECCLINE, ("Removing entry from free list\n"));
|
||||
udf_dispose_eccline(eccline);
|
||||
@ -1218,10 +1272,6 @@ udf_discstrat_thread(void *arg)
|
||||
new_queue = priv->cur_queue;
|
||||
DPRINTF(ECCLINE, ("UDF_ISSUE_ECCLINE\n"));
|
||||
|
||||
/* complete the `get' by locking and refcounting it */
|
||||
UDF_LOCK_ECCLINE(eccline);
|
||||
eccline->refcnt++;
|
||||
|
||||
udf_issue_eccline(eccline, priv->cur_queue);
|
||||
} else {
|
||||
/* don't switch too quickly */
|
||||
@ -1278,17 +1328,18 @@ udf_discstrat_thread(void *arg)
|
||||
|
||||
/* tear down remaining ecclines */
|
||||
mutex_enter(&priv->discstrat_mutex);
|
||||
KASSERT(bufq_peek(priv->queues[UDF_SHED_WAITING]) == NULL);
|
||||
KASSERT(bufq_peek(priv->queues[UDF_SHED_IDLE]) == NULL);
|
||||
KASSERT(bufq_peek(priv->queues[UDF_SHED_READING]) == NULL);
|
||||
KASSERT(bufq_peek(priv->queues[UDF_SHED_WRITING]) == NULL);
|
||||
KASSERT(bufq_peek(priv->queues[UDF_SHED_SEQWRITING]) == NULL);
|
||||
|
||||
KASSERT(priv->num_queued[UDF_SHED_WAITING] == 0);
|
||||
KASSERT(priv->num_queued[UDF_SHED_IDLE] == 0);
|
||||
KASSERT(priv->num_queued[UDF_SHED_READING] == 0);
|
||||
KASSERT(priv->num_queued[UDF_SHED_WRITING] == 0);
|
||||
KASSERT(priv->num_queued[UDF_SHED_SEQWRITING] == 0);
|
||||
|
||||
KASSERT(bufq_peek(priv->queues[UDF_SHED_WAITING]) == NULL);
|
||||
KASSERT(bufq_peek(priv->queues[UDF_SHED_IDLE]) == NULL);
|
||||
KASSERT(bufq_peek(priv->queues[UDF_SHED_READING]) == NULL);
|
||||
KASSERT(bufq_peek(priv->queues[UDF_SHED_WRITING]) == NULL);
|
||||
KASSERT(bufq_peek(priv->queues[UDF_SHED_SEQWRITING]) == NULL);
|
||||
eccline = udf_pop_eccline(priv, UDF_SHED_FREE);
|
||||
while (eccline) {
|
||||
udf_dispose_eccline(eccline);
|
||||
|
Loading…
Reference in New Issue
Block a user