--- linux-2.4.16/drivers/block/nbd.c.orig Fri Oct 26 18:39:02 2001 +++ linux-2.4.16/drivers/block/nbd.c Thu Dec 6 17:50:32 2001 @@ -24,7 +24,9 @@ * 01-3-11 Make nbd work with new Linux block layer code. It now supports * plugging like all the other block devices. Also added in MSG_MORE to * reduce number of partial TCP segments sent. - * + * 01-12-06 Make nbd cleanly killable; fix some locking issues; acknowledge + * and log network errors; make default device size 2TB. + * * possible FIXME: make set_sock / set_blksize / set_size / do_it one syscall * why not: would need verify_area and friends, would share yet another * structure with userland @@ -94,18 +96,10 @@ int result; struct msghdr msg; struct iovec iov; - unsigned long flags; - sigset_t oldset; oldfs = get_fs(); set_fs(get_ds()); - spin_lock_irqsave(¤t->sigmask_lock, flags); - oldset = current->blocked; - sigfillset(¤t->blocked); - recalc_sigpending(current); - spin_unlock_irqrestore(¤t->sigmask_lock, flags); - do { sock->sk->allocation = GFP_NOIO; @@ -125,6 +119,12 @@ else result = sock_recvmsg(sock, &msg, size, 0); + if(signal_pending(current)) { + printk(KERN_WARNING "NBD caught signal\n"); + result = -EINTR; + break; + } + if (result <= 0) { #ifdef PARANOIA printk(KERN_ERR "NBD: %s - sock=%ld at buf=%ld, size=%d returned %d.\n", @@ -136,11 +136,6 @@ buf += result; } while (size > 0); - spin_lock_irqsave(¤t->sigmask_lock, flags); - current->blocked = oldset; - recalc_sigpending(current); - spin_unlock_irqrestore(¤t->sigmask_lock, flags); - set_fs(oldfs); return result; } @@ -336,8 +331,27 @@ spin_unlock_irq(&io_request_lock); down (&lo->queue_lock); + if(!lo->file) { + up(&lo->queue_lock); + spin_lock_irq(&io_request_lock); + printk(KERN_ERR "NBD: fail between accept and semaphore, file lost\n"); + req->errors++; + nbd_end_request(req); + continue; + } + list_add(&req->queue, &lo->queue_head); nbd_send_req(lo->sock, req); /* Why does this block? */ + if(req->errors) { + printk(KERN_ERR "NBD: nbd_send_req failed\n"); + list_del(&req->queue); + + up(&lo->queue_lock); + spin_lock_irq(&io_request_lock); + nbd_end_request(req); + + continue; + } up (&lo->queue_lock); spin_lock_irq(&io_request_lock); @@ -387,12 +401,14 @@ printk(KERN_ERR "nbd: Some requests are in progress -> can not turn off.\n"); return -EBUSY; } - up(&lo->queue_lock); file = lo->file; - if (!file) + if (!file) { + up(&lo->queue_lock); return -EINVAL; + } lo->file = NULL; lo->sock = NULL; + up(&lo->queue_lock); fput(file); return 0; case NBD_SET_SOCK: @@ -433,9 +449,29 @@ if (!lo->file) return -EINVAL; nbd_do_it(lo); + /* on return tidy up in case we have a signal */ + printk(KERN_WARNING "NBD: nbd_do_it returned\n"); + /* Forcibly shutdown the socket causing all listeners + * to error + * + * FIXME: This code is duplicated from sys_shutdown, but + * there should be a more generic interface rather than + * calling socket ops directly here */ + lo->sock->ops->shutdown(lo->sock, 2); + down(&lo->queue_lock); + printk(KERN_WARNING "NBD: lock acquired\n"); + nbd_clear_que(lo); + file = lo->file; + lo->file = NULL; + lo->sock = NULL; + up(&lo->queue_lock); + if(file) + fput(file); return lo->harderror; case NBD_CLEAR_QUE: + down(&lo->queue_lock); nbd_clear_que(lo); + up(&lo->queue_lock); return 0; #ifdef PARANOIA case NBD_PRINT_DEBUG: @@ -512,7 +548,7 @@ init_MUTEX(&nbd_dev[i].queue_lock); nbd_blksizes[i] = 1024; nbd_blksize_bits[i] = 10; - nbd_bytesizes[i] = 0x7ffffc00; /* 2GB */ + nbd_bytesizes[i] = ((u64)0x7ffffc00) << 10; /* 2TB */ nbd_sizes[i] = nbd_bytesizes[i] >> BLOCK_SIZE_BITS; register_disk(NULL, MKDEV(MAJOR_NR,i), 1, &nbd_fops, nbd_bytesizes[i]>>9);