public inbox for cluster-cvs@sourceware.org
help / color / mirror / Atom feed
From: bmarzins@sourceware.org
To: cluster-cvs@sources.redhat.com, cluster-devel@redhat.com
Subject: Cluster Project branch, RHEL5, updated. cmirror_1_1_15-120-g656a865
Date: Thu, 19 Jun 2008 18:36:00 -0000	[thread overview]
Message-ID: <20080619183607.16272.qmail@sourceware.org> (raw)

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Cluster Project".

http://sources.redhat.com/git/gitweb.cgi?p=cluster.git;a=commitdiff;h=656a865047bb5f6f9461a7cde7a78d45602fc1fa

The branch, RHEL5 has been updated
       via  656a865047bb5f6f9461a7cde7a78d45602fc1fa (commit)
      from  215796bbd78788ce810d7e12288e8fa7341bbf5d (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 656a865047bb5f6f9461a7cde7a78d45602fc1fa
Author: Benjamin Marzinski <bmarzins@redhat.com>
Date:   Thu Jun 19 13:14:43 2008 -0500

    gnbd-kernel: Fix receiver race
    
    It is possible to have the gnbd receiver process finish and end a request before
    the sending process has finished using the request structure.  This can cause a
    kernel panic.
    
    This fix adds a waitqueue (tx_wait) and a pointer to the request currently
    being send (current_request) to the gnbd device structure.  current_request is
    set before any request is sent to the server. When the send is complete, it is
    cleared and the wait_queue is woken.  A new function, wait_for_send() is called
    whenever it is possible for a call to gnbd_end_request() to interleave with a
    send. It waits on the waitqueue if the request about to be ended is currently
    being sent.

-----------------------------------------------------------------------

Summary of changes:
 gnbd-kernel/src/gnbd.c |   47 +++++++++++++++++++++++++++++++++++++++++++----
 gnbd-kernel/src/gnbd.h |    2 ++
 2 files changed, 45 insertions(+), 4 deletions(-)

diff --git a/gnbd-kernel/src/gnbd.c b/gnbd-kernel/src/gnbd.c
index d637141..41b0c2b 100644
--- a/gnbd-kernel/src/gnbd.c
+++ b/gnbd-kernel/src/gnbd.c
@@ -267,6 +267,26 @@ static const char *gnbdcmd_to_ascii(int cmd)
 }
 #endif /* NDEBUG */
 
+
+static int wait_for_send(struct request *req, struct gnbd_device *dev)
+{
+	DECLARE_WAITQUEUE(wait, current);
+
+	add_wait_queue(&dev->tx_wait, &wait);
+	while(dev->current_request == req) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (signal_pending(current)) {
+			printk(KERN_WARNING "gnbd (pid %d: %s) wait interrupted by signal\n",
+				current->pid, current->comm);
+			return -EINTR;
+		}
+		schedule();
+	}
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&dev->tx_wait, &wait);
+	return 0;
+}
+
 static void gnbd_end_request(struct request *req)
 {
 	int uptodate = (req->errors == 0) ? 1 : 0;
@@ -396,13 +416,14 @@ int __gnbd_send_req(struct gnbd_device *dev, struct socket *sock,
 			gnbdcmd_to_ascii(gnbd_cmd(req)),
 			(unsigned long long)req->sector << 9,
 			req->nr_sectors << 9);
+	dev->current_request = req;
 	result = sock_xmit(sock, 1, &request, sizeof(request),
 			(gnbd_cmd(req) == GNBD_CMD_WRITE)? MSG_MORE: 0,
 			can_signal);
 	if (result < 0) {
 		printk(KERN_ERR "%s: Send control failed (result %d)\n",
 				dev->disk->disk_name, result);
-		goto error_out;
+		goto send_error_out;
 	}
 
 	if (gnbd_cmd(req) == GNBD_CMD_WRITE) {
@@ -426,14 +447,19 @@ int __gnbd_send_req(struct gnbd_device *dev, struct socket *sock,
 					printk(KERN_ERR "%s: Send data failed (result %d)\n",
 							dev->disk->disk_name,
 							result);
-					goto error_out;
+					goto send_error_out;
 				}
 			}
 		}
 	}
+	dev->current_request = NULL;
+	wake_up(&dev->tx_wait);
 	up(&dev->tx_lock);
 	return 0;
 
+send_error_out:
+	dev->current_request = NULL;
+	wake_up(&dev->tx_wait);
 error_out:
 	up(&dev->tx_lock);
 	return result;
@@ -530,6 +556,9 @@ int gnbd_do_it(struct gnbd_device *dev)
 				return result;
 		}
 remove_req:
+		result = wait_for_send(req, dev);
+		if (result != 0)
+			return result;
 		spin_lock(&dev->queue_lock);
 		list_del_init(&req->queuelist);
 		dev->last_received = jiffies;
@@ -542,8 +571,9 @@ remove_req:
 	return result;
 }
 
-void gnbd_clear_que(struct gnbd_device *dev)
+int gnbd_clear_que(struct gnbd_device *dev)
 {
+	int err;
 	struct request *req;
 
 	BUG_ON(dev->magic != GNBD_MAGIC);
@@ -552,6 +582,9 @@ void gnbd_clear_que(struct gnbd_device *dev)
 		req = NULL;
 		if (!list_empty(&dev->queue_head)) {
 			req = list_entry(dev->queue_head.next, struct request, queuelist);
+			err = wait_for_send(req, dev);
+			if (err)
+				return err;
 			list_del_init(&req->queuelist);
 		}
 		if (req && req != &ping_req) {
@@ -559,6 +592,8 @@ void gnbd_clear_que(struct gnbd_device *dev)
 			gnbd_end_request(req);
 		}
 	} while (req);
+
+	return 0;
 }
 
 /*
@@ -712,7 +747,9 @@ static int gnbd_ctl_ioctl(struct inode *inode, struct file *file,
 		if (down_interruptible(&dev->do_it_lock))
 			return -EBUSY;
 		dev->receiver_pid = -1;
-		gnbd_clear_que(dev);
+		error = gnbd_clear_que(dev);
+		if (error)
+			return error;
 		bdev = dev->bdev;
 		if (bdev) {
 			blk_run_queue(dev->disk->queue);
@@ -982,6 +1019,8 @@ static int __init gnbd_init(void)
 		INIT_LIST_HEAD(&gnbd_dev[i].queue_head);
 		init_MUTEX(&gnbd_dev[i].tx_lock);
 		init_MUTEX(&gnbd_dev[i].do_it_lock);
+		init_waitqueue_head(&gnbd_dev[i].tx_wait);
+		gnbd_dev[i].current_request = NULL;
 		gnbd_dev[i].class_dev.class = &gnbd_class;
 		sprintf(gnbd_dev[i].class_dev.class_id, "gnbd%d", i);
 		err = class_device_register(&gnbd_dev[i].class_dev);
diff --git a/gnbd-kernel/src/gnbd.h b/gnbd-kernel/src/gnbd.h
index b88ad26..50da10b 100644
--- a/gnbd-kernel/src/gnbd.h
+++ b/gnbd-kernel/src/gnbd.h
@@ -56,6 +56,8 @@ struct gnbd_device {
 	char name[32];
 	unsigned long last_received;
 	struct block_device *bdev;
+	struct request *current_request;
+	wait_queue_head_t tx_wait;
 };
 
 #endif /* __KERNEL__ */


hooks/post-receive
--
Cluster Project


                 reply	other threads:[~2008-06-19 18:36 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20080619183607.16272.qmail@sourceware.org \
    --to=bmarzins@sourceware.org \
    --cc=cluster-cvs@sources.redhat.com \
    --cc=cluster-devel@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).