From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 4828 invoked by alias); 19 Jun 2008 19:32:32 -0000 Received: (qmail 4798 invoked by uid 9475); 19 Jun 2008 19:32:31 -0000 Date: Thu, 19 Jun 2008 19:32:00 -0000 Message-ID: <20080619193231.4781.qmail@sourceware.org> From: bmarzins@sourceware.org To: cluster-cvs@sources.redhat.com, cluster-devel@redhat.com Subject: Cluster Project branch, master, updated. cluster-2.99.04-30-g0b92210 X-Git-Refname: refs/heads/master X-Git-Reftype: branch X-Git-Oldrev: f41206811767703628f5b43c406beb85f8e80c54 X-Git-Newrev: 0b922103eb3c7d5d99aa77fc30dc3ddfa22f8521 Mailing-List: contact cluster-cvs-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Post: List-Help: , Sender: cluster-cvs-owner@sourceware.org X-SW-Source: 2008-q2/txt/msg00506.txt.bz2 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=0b922103eb3c7d5d99aa77fc30dc3ddfa22f8521 The branch, master has been updated via 0b922103eb3c7d5d99aa77fc30dc3ddfa22f8521 (commit) from f41206811767703628f5b43c406beb85f8e80c54 (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 0b922103eb3c7d5d99aa77fc30dc3ddfa22f8521 Author: Benjamin Marzinski Date: Thu Jun 19 14:01:20 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. Conflicts: gnbd-kernel/src/gnbd.c ----------------------------------------------------------------------- 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 22c2da8..a52252d 100644 --- a/gnbd-kernel/src/gnbd.c +++ b/gnbd-kernel/src/gnbd.c @@ -253,6 +253,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 error = req->errors ? -EIO : 0; @@ -380,13 +400,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) { @@ -409,13 +430,18 @@ 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; @@ -510,6 +536,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; @@ -522,8 +551,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); @@ -532,6 +562,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) { @@ -539,6 +572,8 @@ void gnbd_clear_que(struct gnbd_device *dev) gnbd_end_request(req); } } while (req); + + return 0; } /* @@ -692,7 +727,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); @@ -960,6 +997,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.bus_id, "gnbd%d", i); err = device_register(&gnbd_dev[i].class_dev); diff --git a/gnbd-kernel/src/gnbd.h b/gnbd-kernel/src/gnbd.h index 9bb259b..7af7f0e 100644 --- a/gnbd-kernel/src/gnbd.h +++ b/gnbd-kernel/src/gnbd.h @@ -43,6 +43,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