[DRBD-cvs] svn commit by phil - r2286 - trunk/drbd - This finally
fixes the send_from_worker's context patch
drbd-cvs at lists.linbit.com
drbd-cvs at lists.linbit.com
Wed Jul 19 10:40:04 CEST 2006
Author: phil
Date: 2006-07-19 10:40:02 +0200 (Wed, 19 Jul 2006)
New Revision: 2286
Modified:
trunk/drbd/drbd_main.c
trunk/drbd/drbd_req.c
trunk/drbd/drbd_worker.c
Log:
This finally fixes the send_from_worker's context patch.
We had memory corruption ( access after free() )
Modified: trunk/drbd/drbd_main.c
===================================================================
--- trunk/drbd/drbd_main.c 2006-07-18 14:32:20 UTC (rev 2285)
+++ trunk/drbd/drbd_main.c 2006-07-19 08:40:02 UTC (rev 2286)
@@ -230,22 +230,6 @@
spin_unlock_irq(&mdev->tl_lock);
}
-STATIC void tl_cancel(drbd_dev *mdev, drbd_request_t *req)
-{
- struct drbd_barrier *b;
-
- spin_lock_irq(&mdev->tl_lock);
-
- b=req->barrier;
- b->n_req--;
-
- list_del(&req->tl_requests);
- hlist_del(&req->colision);
- req->rq_status &= ~RQ_DRBD_IN_TL;
-
- spin_unlock_irq(&mdev->tl_lock);
-}
-
/**
* tl_add_barrier: Creates a new barrier object and links it into the
* transfer log. It returns the the newest (but not the just created
@@ -294,15 +278,18 @@
spin_unlock_irq(&mdev->tl_lock);
D_ASSERT(b->br_number == barrier_nr);
+ D_ASSERT(b->n_req == set_size);
+
+#ifdef DBG_ASSERTS
if(b->br_number != barrier_nr) {
DUMPI(b->br_number);
DUMPI(barrier_nr);
}
- D_ASSERT(b->n_req == set_size);
if(b->n_req != set_size) {
DUMPI(b->n_req);
DUMPI(set_size);
}
+#endif
kfree(b);
}
@@ -348,6 +335,7 @@
r = ( req->barrier == mdev->newest_barrier );
list_del(&req->tl_requests);
hlist_del(&req->colision);
+ // req->barrier->n_req--; // Barrier migh be free'ed already!
if( req->rq_status & RQ_DRBD_RECVW ) wake_up(&mdev->cstate_wait);
@@ -358,35 +346,20 @@
void tl_clear(drbd_dev *mdev)
{
struct list_head *le,*tle;
- struct drbd_barrier *b,*f,*new_first;
+ struct drbd_barrier *b,*f;
struct drbd_request *r;
sector_t sector;
unsigned int size;
- new_first=kmalloc(sizeof(struct drbd_barrier),GFP_NOIO);
- if(!new_first) {
- ERR("could not kmalloc() barrier\n");
- }
-
- /* FIXME if indeed we could not kmalloc, this will Oops!
- * can we somehow just recycle one of the existing barriers?
- */
- INIT_LIST_HEAD(&new_first->requests);
- new_first->next=0;
- new_first->br_number=4711;
- new_first->n_req=0;
-
spin_lock_irq(&mdev->tl_lock);
b=mdev->oldest_barrier;
- mdev->oldest_barrier = new_first;
- mdev->newest_barrier = new_first;
+ mdev->oldest_barrier = NULL;
+ mdev->newest_barrier = NULL;
spin_unlock_irq(&mdev->tl_lock);
- inc_ap_pending(mdev); // Since we count the old first as well...
-
- while ( b ) {
+ while ( 1 ) {
list_for_each_safe(le, tle, &b->requests) {
r = list_entry(le, struct drbd_request,tl_requests);
// bi_size and bi_sector are modified in bio_endio!
@@ -406,9 +379,24 @@
f=b;
b=b->next;
list_del(&f->requests);
+ if (!b) break;
kfree(f);
dec_ap_pending(mdev); // for the barrier
}
+
+ // f is now the last barrier, we use it as new first barrier.
+
+ INIT_LIST_HEAD(&f->requests);
+ f->next=NULL;
+ f->br_number=4711;
+ f->n_req=0;
+
+ spin_lock_irq(&mdev->tl_lock);
+
+ mdev->oldest_barrier = f;
+ mdev->newest_barrier = f;
+
+ spin_unlock_irq(&mdev->tl_lock);
}
STATIC unsigned int ee_hash_fn(drbd_dev *mdev, sector_t sector)
Modified: trunk/drbd/drbd_req.c
===================================================================
--- trunk/drbd/drbd_req.c 2006-07-18 14:32:20 UTC (rev 2285)
+++ trunk/drbd/drbd_req.c 2006-07-19 08:40:02 UTC (rev 2286)
@@ -77,8 +77,9 @@
if(tl_dependence(mdev,req))
set_bit(ISSUE_BARRIER,&mdev->flags);
} else {
- list_del(&req->w.list); // we have the tl_lock...
+ list_del(&req->tl_requests); // we have the tl_lock...
hlist_del(&req->colision);
+ // req->barrier->n_req--; // Barrier migh be free'ed !
}
}
Modified: trunk/drbd/drbd_worker.c
===================================================================
--- trunk/drbd/drbd_worker.c 2006-07-18 14:32:20 UTC (rev 2285)
+++ trunk/drbd/drbd_worker.c 2006-07-19 08:40:02 UTC (rev 2286)
@@ -562,12 +562,13 @@
drbd_request_t *req = (drbd_request_t *)w;
int ok;
+ inc_ap_pending(mdev); // Right here, since tl_clear() will decrease it
+
if (unlikely(cancel)) {
/* Nothing to do, here. tl_clear() does the work. */
return 1;
}
- inc_ap_pending(mdev);
ok = drbd_send_dblock(mdev,req);
if (!ok) {
if (mdev->state.conn >= Connected)
More information about the drbd-cvs
mailing list