diff options
Diffstat (limited to 'drivers/block')
-rw-r--r-- | drivers/block/nbd.c | 93 |
1 files changed, 62 insertions, 31 deletions
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 89bdafd88dbd..cb136a919f2a 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c | |||
@@ -113,12 +113,42 @@ static void nbd_end_request(struct request *req) | |||
113 | spin_unlock_irqrestore(q->queue_lock, flags); | 113 | spin_unlock_irqrestore(q->queue_lock, flags); |
114 | } | 114 | } |
115 | 115 | ||
116 | static void sock_shutdown(struct nbd_device *lo, int lock) | ||
117 | { | ||
118 | /* Forcibly shutdown the socket causing all listeners | ||
119 | * to error | ||
120 | * | ||
121 | * FIXME: This code is duplicated from sys_shutdown, but | ||
122 | * there should be a more generic interface rather than | ||
123 | * calling socket ops directly here */ | ||
124 | if (lock) | ||
125 | mutex_lock(&lo->tx_lock); | ||
126 | if (lo->sock) { | ||
127 | printk(KERN_WARNING "%s: shutting down socket\n", | ||
128 | lo->disk->disk_name); | ||
129 | lo->sock->ops->shutdown(lo->sock, SEND_SHUTDOWN|RCV_SHUTDOWN); | ||
130 | lo->sock = NULL; | ||
131 | } | ||
132 | if (lock) | ||
133 | mutex_unlock(&lo->tx_lock); | ||
134 | } | ||
135 | |||
136 | static void nbd_xmit_timeout(unsigned long arg) | ||
137 | { | ||
138 | struct task_struct *task = (struct task_struct *)arg; | ||
139 | |||
140 | printk(KERN_WARNING "nbd: killing hung xmit (%s, pid: %d)\n", | ||
141 | task->comm, task->pid); | ||
142 | force_sig(SIGKILL, task); | ||
143 | } | ||
144 | |||
116 | /* | 145 | /* |
117 | * Send or receive packet. | 146 | * Send or receive packet. |
118 | */ | 147 | */ |
119 | static int sock_xmit(struct socket *sock, int send, void *buf, int size, | 148 | static int sock_xmit(struct nbd_device *lo, int send, void *buf, int size, |
120 | int msg_flags) | 149 | int msg_flags) |
121 | { | 150 | { |
151 | struct socket *sock = lo->sock; | ||
122 | int result; | 152 | int result; |
123 | struct msghdr msg; | 153 | struct msghdr msg; |
124 | struct kvec iov; | 154 | struct kvec iov; |
@@ -139,9 +169,20 @@ static int sock_xmit(struct socket *sock, int send, void *buf, int size, | |||
139 | msg.msg_controllen = 0; | 169 | msg.msg_controllen = 0; |
140 | msg.msg_flags = msg_flags | MSG_NOSIGNAL; | 170 | msg.msg_flags = msg_flags | MSG_NOSIGNAL; |
141 | 171 | ||
142 | if (send) | 172 | if (send) { |
173 | struct timer_list ti; | ||
174 | |||
175 | if (lo->xmit_timeout) { | ||
176 | init_timer(&ti); | ||
177 | ti.function = nbd_xmit_timeout; | ||
178 | ti.data = (unsigned long)current; | ||
179 | ti.expires = jiffies + lo->xmit_timeout; | ||
180 | add_timer(&ti); | ||
181 | } | ||
143 | result = kernel_sendmsg(sock, &msg, &iov, 1, size); | 182 | result = kernel_sendmsg(sock, &msg, &iov, 1, size); |
144 | else | 183 | if (lo->xmit_timeout) |
184 | del_timer_sync(&ti); | ||
185 | } else | ||
145 | result = kernel_recvmsg(sock, &msg, &iov, 1, size, 0); | 186 | result = kernel_recvmsg(sock, &msg, &iov, 1, size, 0); |
146 | 187 | ||
147 | if (signal_pending(current)) { | 188 | if (signal_pending(current)) { |
@@ -150,6 +191,7 @@ static int sock_xmit(struct socket *sock, int send, void *buf, int size, | |||
150 | current->pid, current->comm, | 191 | current->pid, current->comm, |
151 | dequeue_signal_lock(current, ¤t->blocked, &info)); | 192 | dequeue_signal_lock(current, ¤t->blocked, &info)); |
152 | result = -EINTR; | 193 | result = -EINTR; |
194 | sock_shutdown(lo, !send); | ||
153 | break; | 195 | break; |
154 | } | 196 | } |
155 | 197 | ||
@@ -167,23 +209,22 @@ static int sock_xmit(struct socket *sock, int send, void *buf, int size, | |||
167 | return result; | 209 | return result; |
168 | } | 210 | } |
169 | 211 | ||
170 | static inline int sock_send_bvec(struct socket *sock, struct bio_vec *bvec, | 212 | static inline int sock_send_bvec(struct nbd_device *lo, struct bio_vec *bvec, |
171 | int flags) | 213 | int flags) |
172 | { | 214 | { |
173 | int result; | 215 | int result; |
174 | void *kaddr = kmap(bvec->bv_page); | 216 | void *kaddr = kmap(bvec->bv_page); |
175 | result = sock_xmit(sock, 1, kaddr + bvec->bv_offset, bvec->bv_len, | 217 | result = sock_xmit(lo, 1, kaddr + bvec->bv_offset, bvec->bv_len, flags); |
176 | flags); | ||
177 | kunmap(bvec->bv_page); | 218 | kunmap(bvec->bv_page); |
178 | return result; | 219 | return result; |
179 | } | 220 | } |
180 | 221 | ||
222 | /* always call with the tx_lock held */ | ||
181 | static int nbd_send_req(struct nbd_device *lo, struct request *req) | 223 | static int nbd_send_req(struct nbd_device *lo, struct request *req) |
182 | { | 224 | { |
183 | int result, flags; | 225 | int result, flags; |
184 | struct nbd_request request; | 226 | struct nbd_request request; |
185 | unsigned long size = req->nr_sectors << 9; | 227 | unsigned long size = req->nr_sectors << 9; |
186 | struct socket *sock = lo->sock; | ||
187 | 228 | ||
188 | request.magic = htonl(NBD_REQUEST_MAGIC); | 229 | request.magic = htonl(NBD_REQUEST_MAGIC); |
189 | request.type = htonl(nbd_cmd(req)); | 230 | request.type = htonl(nbd_cmd(req)); |
@@ -196,8 +237,8 @@ static int nbd_send_req(struct nbd_device *lo, struct request *req) | |||
196 | nbdcmd_to_ascii(nbd_cmd(req)), | 237 | nbdcmd_to_ascii(nbd_cmd(req)), |
197 | (unsigned long long)req->sector << 9, | 238 | (unsigned long long)req->sector << 9, |
198 | req->nr_sectors << 9); | 239 | req->nr_sectors << 9); |
199 | result = sock_xmit(sock, 1, &request, sizeof(request), | 240 | result = sock_xmit(lo, 1, &request, sizeof(request), |
200 | (nbd_cmd(req) == NBD_CMD_WRITE)? MSG_MORE: 0); | 241 | (nbd_cmd(req) == NBD_CMD_WRITE) ? MSG_MORE : 0); |
201 | if (result <= 0) { | 242 | if (result <= 0) { |
202 | printk(KERN_ERR "%s: Send control failed (result %d)\n", | 243 | printk(KERN_ERR "%s: Send control failed (result %d)\n", |
203 | lo->disk->disk_name, result); | 244 | lo->disk->disk_name, result); |
@@ -217,7 +258,7 @@ static int nbd_send_req(struct nbd_device *lo, struct request *req) | |||
217 | flags = MSG_MORE; | 258 | flags = MSG_MORE; |
218 | dprintk(DBG_TX, "%s: request %p: sending %d bytes data\n", | 259 | dprintk(DBG_TX, "%s: request %p: sending %d bytes data\n", |
219 | lo->disk->disk_name, req, bvec->bv_len); | 260 | lo->disk->disk_name, req, bvec->bv_len); |
220 | result = sock_send_bvec(sock, bvec, flags); | 261 | result = sock_send_bvec(lo, bvec, flags); |
221 | if (result <= 0) { | 262 | if (result <= 0) { |
222 | printk(KERN_ERR "%s: Send data failed (result %d)\n", | 263 | printk(KERN_ERR "%s: Send data failed (result %d)\n", |
223 | lo->disk->disk_name, result); | 264 | lo->disk->disk_name, result); |
@@ -257,11 +298,11 @@ out: | |||
257 | return ERR_PTR(err); | 298 | return ERR_PTR(err); |
258 | } | 299 | } |
259 | 300 | ||
260 | static inline int sock_recv_bvec(struct socket *sock, struct bio_vec *bvec) | 301 | static inline int sock_recv_bvec(struct nbd_device *lo, struct bio_vec *bvec) |
261 | { | 302 | { |
262 | int result; | 303 | int result; |
263 | void *kaddr = kmap(bvec->bv_page); | 304 | void *kaddr = kmap(bvec->bv_page); |
264 | result = sock_xmit(sock, 0, kaddr + bvec->bv_offset, bvec->bv_len, | 305 | result = sock_xmit(lo, 0, kaddr + bvec->bv_offset, bvec->bv_len, |
265 | MSG_WAITALL); | 306 | MSG_WAITALL); |
266 | kunmap(bvec->bv_page); | 307 | kunmap(bvec->bv_page); |
267 | return result; | 308 | return result; |
@@ -273,10 +314,9 @@ static struct request *nbd_read_stat(struct nbd_device *lo) | |||
273 | int result; | 314 | int result; |
274 | struct nbd_reply reply; | 315 | struct nbd_reply reply; |
275 | struct request *req; | 316 | struct request *req; |
276 | struct socket *sock = lo->sock; | ||
277 | 317 | ||
278 | reply.magic = 0; | 318 | reply.magic = 0; |
279 | result = sock_xmit(sock, 0, &reply, sizeof(reply), MSG_WAITALL); | 319 | result = sock_xmit(lo, 0, &reply, sizeof(reply), MSG_WAITALL); |
280 | if (result <= 0) { | 320 | if (result <= 0) { |
281 | printk(KERN_ERR "%s: Receive control failed (result %d)\n", | 321 | printk(KERN_ERR "%s: Receive control failed (result %d)\n", |
282 | lo->disk->disk_name, result); | 322 | lo->disk->disk_name, result); |
@@ -317,7 +357,7 @@ static struct request *nbd_read_stat(struct nbd_device *lo) | |||
317 | struct bio_vec *bvec; | 357 | struct bio_vec *bvec; |
318 | 358 | ||
319 | rq_for_each_segment(bvec, req, iter) { | 359 | rq_for_each_segment(bvec, req, iter) { |
320 | result = sock_recv_bvec(sock, bvec); | 360 | result = sock_recv_bvec(lo, bvec); |
321 | if (result <= 0) { | 361 | if (result <= 0) { |
322 | printk(KERN_ERR "%s: Receive data failed (result %d)\n", | 362 | printk(KERN_ERR "%s: Receive data failed (result %d)\n", |
323 | lo->disk->disk_name, result); | 363 | lo->disk->disk_name, result); |
@@ -392,6 +432,7 @@ static void nbd_clear_que(struct nbd_device *lo) | |||
392 | } | 432 | } |
393 | } | 433 | } |
394 | 434 | ||
435 | |||
395 | /* | 436 | /* |
396 | * We always wait for result of write, for now. It would be nice to make it optional | 437 | * We always wait for result of write, for now. It would be nice to make it optional |
397 | * in future | 438 | * in future |
@@ -500,7 +541,9 @@ static int nbd_ioctl(struct inode *inode, struct file *file, | |||
500 | sreq.nr_sectors = 0; | 541 | sreq.nr_sectors = 0; |
501 | if (!lo->sock) | 542 | if (!lo->sock) |
502 | return -EINVAL; | 543 | return -EINVAL; |
544 | mutex_lock(&lo->tx_lock); | ||
503 | nbd_send_req(lo, &sreq); | 545 | nbd_send_req(lo, &sreq); |
546 | mutex_unlock(&lo->tx_lock); | ||
504 | return 0; | 547 | return 0; |
505 | 548 | ||
506 | case NBD_CLEAR_SOCK: | 549 | case NBD_CLEAR_SOCK: |
@@ -544,6 +587,9 @@ static int nbd_ioctl(struct inode *inode, struct file *file, | |||
544 | set_blocksize(inode->i_bdev, lo->blksize); | 587 | set_blocksize(inode->i_bdev, lo->blksize); |
545 | set_capacity(lo->disk, lo->bytesize >> 9); | 588 | set_capacity(lo->disk, lo->bytesize >> 9); |
546 | return 0; | 589 | return 0; |
590 | case NBD_SET_TIMEOUT: | ||
591 | lo->xmit_timeout = arg * HZ; | ||
592 | return 0; | ||
547 | case NBD_SET_SIZE_BLOCKS: | 593 | case NBD_SET_SIZE_BLOCKS: |
548 | lo->bytesize = ((u64) arg) * lo->blksize; | 594 | lo->bytesize = ((u64) arg) * lo->blksize; |
549 | inode->i_bdev->bd_inode->i_size = lo->bytesize; | 595 | inode->i_bdev->bd_inode->i_size = lo->bytesize; |
@@ -556,22 +602,7 @@ static int nbd_ioctl(struct inode *inode, struct file *file, | |||
556 | error = nbd_do_it(lo); | 602 | error = nbd_do_it(lo); |
557 | if (error) | 603 | if (error) |
558 | return error; | 604 | return error; |
559 | /* on return tidy up in case we have a signal */ | 605 | sock_shutdown(lo, 1); |
560 | /* Forcibly shutdown the socket causing all listeners | ||
561 | * to error | ||
562 | * | ||
563 | * FIXME: This code is duplicated from sys_shutdown, but | ||
564 | * there should be a more generic interface rather than | ||
565 | * calling socket ops directly here */ | ||
566 | mutex_lock(&lo->tx_lock); | ||
567 | if (lo->sock) { | ||
568 | printk(KERN_WARNING "%s: shutting down socket\n", | ||
569 | lo->disk->disk_name); | ||
570 | lo->sock->ops->shutdown(lo->sock, | ||
571 | SEND_SHUTDOWN|RCV_SHUTDOWN); | ||
572 | lo->sock = NULL; | ||
573 | } | ||
574 | mutex_unlock(&lo->tx_lock); | ||
575 | file = lo->file; | 606 | file = lo->file; |
576 | lo->file = NULL; | 607 | lo->file = NULL; |
577 | nbd_clear_que(lo); | 608 | nbd_clear_que(lo); |