From mboxrd@z Thu Jan 1 00:00:00 1970 From: bmarzins@sourceware.org Date: 9 Nov 2006 21:22:40 -0000 Subject: [Cluster-devel] cluster/gnbd-kernel/src gnbd.c Message-ID: <20061109212240.7063.qmail@sourceware.org> List-Id: To: cluster-devel.redhat.com MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit CVSROOT: /cvs/cluster Module name: cluster Branch: RHEL4 Changes by: bmarzins at sourceware.org 2006-11-09 21:22:40 Modified files: gnbd-kernel/src: gnbd.c Log message: It was previously possible to confuse gnbd by sending a process a signal while gnbd was writing to the socket (bz 210453). This usually hangs the socket, but can possibly cause data corruption. To fix this gnbd now only handles signals for gnbd_recvd. GNBD blocks all signals for all other processes while it is going socket IO, so that a partial IO will never be send to the server, except when the connection is lost. Patches: http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gnbd-kernel/src/gnbd.c.diff?cvsroot=cluster&only_with_tag=RHEL4&r1=1.6.2.2&r2=1.6.2.3 --- cluster/gnbd-kernel/src/gnbd.c 2005/05/09 23:05:17 1.6.2.2 +++ cluster/gnbd-kernel/src/gnbd.c 2006/11/09 21:22:40 1.6.2.3 @@ -289,7 +289,7 @@ * Send or receive packet. */ static int sock_xmit(struct socket *sock, int send, void *buf, int size, - int msg_flags) + int msg_flags, int can_signal) { mm_segment_t oldfs; int result; @@ -300,13 +300,12 @@ oldfs = get_fs(); set_fs(get_ds()); - /* Allow interception of SIGKILL only - * Don't allow other signals to interrupt the transmission */ spin_lock_irqsave(¤t->sighand->siglock, flags); oldset = current->blocked; sigfillset(¤t->blocked); - sigdelsetmask(¤t->blocked, sigmask(SIGKILL) | sigmask(SIGTERM) | - sigmask(SIGHUP)); + if (can_signal) + sigdelsetmask(¤t->blocked, sigmask(SIGKILL) | + sigmask(SIGTERM) | sigmask(SIGHUP)); recalc_sigpending(); spin_unlock_irqrestore(¤t->sighand->siglock, flags); @@ -328,7 +327,7 @@ else result = sock_recvmsg(sock, &msg, size, 0); - if (signal_pending(current)) { + if (can_signal && signal_pending(current)) { siginfo_t info; spin_lock_irqsave(¤t->sighand->siglock, flags); printk(KERN_WARNING "gnbd (pid %d: %s) got signal %d\n", @@ -358,21 +357,22 @@ } static inline int sock_send_bvec(struct socket *sock, struct bio_vec *bvec, - int flags) + int flags, int can_signal) { int result; void *kaddr = kmap(bvec->bv_page); result = sock_xmit(sock, 1, kaddr + bvec->bv_offset, bvec->bv_len, - flags); + flags, can_signal); kunmap(bvec->bv_page); return result; } -#define gnbd_send_req(dev, req) __gnbd_send_req((dev), (dev)->sock, (req)) +#define gnbd_send_req(dev, req, can_sig) \ +__gnbd_send_req((dev), (dev)->sock, (req), (can_sig)) int __gnbd_send_req(struct gnbd_device *dev, struct socket *sock, - struct request *req) + struct request *req, int can_signal) { int result, i, flags; struct gnbd_request request; @@ -399,7 +399,8 @@ (unsigned long long)req->sector << 9, req->nr_sectors << 9); result = sock_xmit(sock, 1, &request, sizeof(request), - (gnbd_cmd(req) == GNBD_CMD_WRITE)? MSG_MORE: 0); + (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); @@ -421,7 +422,8 @@ dprintk(DBG_TX, "%s: request %p: sending %d bytes data\n", dev->disk->disk_name, req, bvec->bv_len); - result = sock_send_bvec(sock, bvec, flags); + result = sock_send_bvec(sock, bvec, flags, + can_signal); if (result < 0) { printk(KERN_ERR "%s: Send data failed (result %d)\n", dev->disk->disk_name, @@ -459,7 +461,7 @@ int result; void *kaddr = kmap(bvec->bv_page); result = sock_xmit(sock, 0, kaddr + bvec->bv_offset, bvec->bv_len, - MSG_WAITALL); + MSG_WAITALL, 1); kunmap(bvec->bv_page); return result; } @@ -495,7 +497,7 @@ BUG_ON(dev->magic != GNBD_MAGIC); - while((result = sock_xmit(sock, 0, &reply,sizeof(reply), MSG_WAITALL)) > 0){ + while((result = sock_xmit(sock, 0, &reply,sizeof(reply), MSG_WAITALL, 1)) > 0){ if (ntohl(reply.magic) == GNBD_KEEP_ALIVE_MAGIC) /* FIXME -- I should reset the wait time here */ continue; @@ -610,7 +612,7 @@ list_add(&req->queuelist, &dev->queue_head); spin_unlock(&dev->queue_lock); - err = gnbd_send_req(dev, req); + err = gnbd_send_req(dev, req, 0); spin_lock_irq(q->queue_lock); if (err) @@ -642,7 +644,7 @@ printk("resending requests\n"); list_for_each(tmp, &dev->queue_head) { req = list_entry(tmp, struct request, queuelist); - err = __gnbd_send_req(dev, sock, req); + err = __gnbd_send_req(dev, sock, req, 1); if (err){ printk("failed trying to resend request (%d)\n", err); @@ -706,7 +708,7 @@ /* There is no one using the device, you can disconnect it */ if (dev->sock == NULL) return -ENOTCONN; - gnbd_send_req(dev, &shutdown_req); + gnbd_send_req(dev, &shutdown_req, 1); return 0; case GNBD_CLEAR_QUE: if (down_interruptible(&dev->do_it_lock)) @@ -783,7 +785,7 @@ list_add(&ping_req.queuelist, &dev->queue_head); } spin_unlock(&dev->queue_lock); - gnbd_send_req(dev, &ping_req); /* ignore the errors */ + gnbd_send_req(dev, &ping_req, 1); /* ignore the errors */ return 0; case GNBD_PRINT_DEBUG: printk(KERN_INFO "%s: next = %p, prev = %p, head = %p\n",