Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ncpfs: make sure server connection survives a kill

Use internal buffers instead of the ones supplied by the caller
so that a caller can be interrupted without having to abort the
entire ncp connection.

Signed-off-by: Pierre Ossman <ossman@cendio.se>
Acked-by: Petr Vandrovec <petr@vandrovec.name>

authored by

Pierre Ossman and committed by
Pierre Ossman
c5f93cf1 c3442e29

+103 -62
+14 -2
fs/ncpfs/inode.c
··· 576 576 server->packet = vmalloc(NCP_PACKET_SIZE); 577 577 if (server->packet == NULL) 578 578 goto out_nls; 579 + server->txbuf = vmalloc(NCP_PACKET_SIZE); 580 + if (server->txbuf == NULL) 581 + goto out_packet; 582 + server->rxbuf = vmalloc(NCP_PACKET_SIZE); 583 + if (server->rxbuf == NULL) 584 + goto out_txbuf; 579 585 580 586 sock->sk->sk_data_ready = ncp_tcp_data_ready; 581 587 sock->sk->sk_error_report = ncp_tcp_error_report; ··· 603 597 error = ncp_connect(server); 604 598 ncp_unlock_server(server); 605 599 if (error < 0) 606 - goto out_packet; 600 + goto out_rxbuf; 607 601 DPRINTK("ncp_fill_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb)); 608 602 609 603 error = -EMSGSIZE; /* -EREMOTESIDEINCOMPATIBLE */ ··· 672 666 ncp_lock_server(server); 673 667 ncp_disconnect(server); 674 668 ncp_unlock_server(server); 675 - out_packet: 669 + out_rxbuf: 676 670 ncp_stop_tasks(server); 671 + vfree(server->rxbuf); 672 + out_txbuf: 673 + vfree(server->txbuf); 674 + out_packet: 677 675 vfree(server->packet); 678 676 out_nls: 679 677 #ifdef CONFIG_NCPFS_NLS ··· 733 723 734 724 kfree(server->priv.data); 735 725 kfree(server->auth.object_name); 726 + vfree(server->rxbuf); 727 + vfree(server->txbuf); 736 728 vfree(server->packet); 737 729 sb->s_fs_info = NULL; 738 730 kfree(server);
+87 -60
fs/ncpfs/sock.c
··· 14 14 #include <linux/socket.h> 15 15 #include <linux/fcntl.h> 16 16 #include <linux/stat.h> 17 + #include <linux/string.h> 17 18 #include <asm/uaccess.h> 18 19 #include <linux/in.h> 19 20 #include <linux/net.h> ··· 56 55 struct ncp_request_reply { 57 56 struct list_head req; 58 57 wait_queue_head_t wq; 59 - struct ncp_reply_header* reply_buf; 58 + atomic_t refs; 59 + unsigned char* reply_buf; 60 60 size_t datalen; 61 61 int result; 62 - enum { RQ_DONE, RQ_INPROGRESS, RQ_QUEUED, RQ_IDLE } status; 62 + enum { RQ_DONE, RQ_INPROGRESS, RQ_QUEUED, RQ_IDLE, RQ_ABANDONED } status; 63 63 struct kvec* tx_ciov; 64 64 size_t tx_totallen; 65 65 size_t tx_iovlen; ··· 68 66 u_int16_t tx_type; 69 67 u_int32_t sign[6]; 70 68 }; 69 + 70 + static inline struct ncp_request_reply* ncp_alloc_req(void) 71 + { 72 + struct ncp_request_reply *req; 73 + 74 + req = kmalloc(sizeof(struct ncp_request_reply), GFP_KERNEL); 75 + if (!req) 76 + return NULL; 77 + 78 + init_waitqueue_head(&req->wq); 79 + atomic_set(&req->refs, (1)); 80 + req->status = RQ_IDLE; 81 + 82 + return req; 83 + } 84 + 85 + static void ncp_req_get(struct ncp_request_reply *req) 86 + { 87 + atomic_inc(&req->refs); 88 + } 89 + 90 + static void ncp_req_put(struct ncp_request_reply *req) 91 + { 92 + if (atomic_dec_and_test(&req->refs)) 93 + kfree(req); 94 + } 71 95 72 96 void ncp_tcp_data_ready(struct sock *sk, int len) 73 97 { ··· 129 101 schedule_work(&server->timeout_tq); 130 102 } 131 103 132 - static inline void ncp_finish_request(struct ncp_request_reply *req, int result) 104 + static inline void ncp_finish_request(struct ncp_server *server, struct ncp_request_reply *req, int result) 133 105 { 134 106 req->result = result; 107 + if (req->status != RQ_ABANDONED) 108 + memcpy(req->reply_buf, server->rxbuf, req->datalen); 135 109 req->status = RQ_DONE; 136 110 wake_up_all(&req->wq); 111 + ncp_req_put(req); 137 112 } 138 113 139 - static void __abort_ncp_connection(struct ncp_server *server, struct ncp_request_reply *aborted, int err) 114 + static void __abort_ncp_connection(struct ncp_server *server) 140 115 { 141 116 struct ncp_request_reply *req; 142 117 ··· 149 118 req = list_entry(server->tx.requests.next, struct ncp_request_reply, req); 150 119 151 120 list_del_init(&req->req); 152 - if (req == aborted) { 153 - ncp_finish_request(req, err); 154 - } else { 155 - ncp_finish_request(req, -EIO); 156 - } 121 + ncp_finish_request(server, req, -EIO); 157 122 } 158 123 req = server->rcv.creq; 159 124 if (req) { 160 125 server->rcv.creq = NULL; 161 - if (req == aborted) { 162 - ncp_finish_request(req, err); 163 - } else { 164 - ncp_finish_request(req, -EIO); 165 - } 126 + ncp_finish_request(server, req, -EIO); 166 127 server->rcv.ptr = NULL; 167 128 server->rcv.state = 0; 168 129 } 169 130 req = server->tx.creq; 170 131 if (req) { 171 132 server->tx.creq = NULL; 172 - if (req == aborted) { 173 - ncp_finish_request(req, err); 174 - } else { 175 - ncp_finish_request(req, -EIO); 176 - } 133 + ncp_finish_request(server, req, -EIO); 177 134 } 178 135 } 179 136 ··· 179 160 break; 180 161 case RQ_QUEUED: 181 162 list_del_init(&req->req); 182 - ncp_finish_request(req, err); 163 + ncp_finish_request(server, req, err); 183 164 break; 184 165 case RQ_INPROGRESS: 185 - __abort_ncp_connection(server, req, err); 166 + req->status = RQ_ABANDONED; 167 + break; 168 + case RQ_ABANDONED: 186 169 break; 187 170 } 188 171 } ··· 198 177 199 178 static inline void __ncptcp_abort(struct ncp_server *server) 200 179 { 201 - __abort_ncp_connection(server, NULL, 0); 180 + __abort_ncp_connection(server); 202 181 } 203 182 204 183 static int ncpdgram_send(struct socket *sock, struct ncp_request_reply *req) ··· 315 294 316 295 static inline void __ncp_start_request(struct ncp_server *server, struct ncp_request_reply *req) 317 296 { 297 + /* we copy the data so that we do not depend on the caller 298 + staying alive */ 299 + memcpy(server->txbuf, req->tx_iov[1].iov_base, req->tx_iov[1].iov_len); 300 + req->tx_iov[1].iov_base = server->txbuf; 301 + 318 302 if (server->ncp_sock->type == SOCK_STREAM) 319 303 ncptcp_start_request(server, req); 320 304 else ··· 334 308 printk(KERN_ERR "ncpfs: tcp: Server died\n"); 335 309 return -EIO; 336 310 } 311 + ncp_req_get(req); 337 312 if (server->tx.creq || server->rcv.creq) { 338 313 req->status = RQ_QUEUED; 339 314 list_add_tail(&req->req, &server->tx.requests); ··· 436 409 server->timeout_last = NCP_MAX_RPC_TIMEOUT; 437 410 mod_timer(&server->timeout_tm, jiffies + NCP_MAX_RPC_TIMEOUT); 438 411 } else if (reply.type == NCP_REPLY) { 439 - result = _recv(sock, (void*)req->reply_buf, req->datalen, MSG_DONTWAIT); 412 + result = _recv(sock, server->rxbuf, req->datalen, MSG_DONTWAIT); 440 413 #ifdef CONFIG_NCPFS_PACKET_SIGNING 441 414 if (result >= 0 && server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) { 442 415 if (result < 8 + 8) { ··· 446 419 447 420 result -= 8; 448 421 hdrl = sock->sk->sk_family == AF_INET ? 8 : 6; 449 - if (sign_verify_reply(server, ((char*)req->reply_buf) + hdrl, result - hdrl, cpu_to_le32(result), ((char*)req->reply_buf) + result)) { 422 + if (sign_verify_reply(server, server->rxbuf + hdrl, result - hdrl, cpu_to_le32(result), server->rxbuf + result)) { 450 423 printk(KERN_INFO "ncpfs: Signature violation\n"); 451 424 result = -EIO; 452 425 } ··· 455 428 #endif 456 429 del_timer(&server->timeout_tm); 457 430 server->rcv.creq = NULL; 458 - ncp_finish_request(req, result); 431 + ncp_finish_request(server, req, result); 459 432 __ncp_next_request(server); 460 433 mutex_unlock(&server->rcv.creq_mutex); 461 434 continue; ··· 503 476 mutex_lock(&server->rcv.creq_mutex); 504 477 __ncpdgram_timeout_proc(server); 505 478 mutex_unlock(&server->rcv.creq_mutex); 506 - } 507 - 508 - static inline void ncp_init_req(struct ncp_request_reply* req) 509 - { 510 - init_waitqueue_head(&req->wq); 511 - req->status = RQ_IDLE; 512 479 } 513 480 514 481 static int do_tcp_rcv(struct ncp_server *server, void *buffer, size_t len) ··· 622 601 goto skipdata; 623 602 } 624 603 req->datalen = datalen - 8; 625 - req->reply_buf->type = NCP_REPLY; 626 - server->rcv.ptr = (unsigned char*)(req->reply_buf) + 2; 604 + ((struct ncp_reply_header*)server->rxbuf)->type = NCP_REPLY; 605 + server->rcv.ptr = server->rxbuf + 2; 627 606 server->rcv.len = datalen - 10; 628 607 server->rcv.state = 1; 629 608 break; ··· 636 615 case 1: 637 616 req = server->rcv.creq; 638 617 if (req->tx_type != NCP_ALLOC_SLOT_REQUEST) { 639 - if (req->reply_buf->sequence != server->sequence) { 618 + if (((struct ncp_reply_header*)server->rxbuf)->sequence != server->sequence) { 640 619 printk(KERN_ERR "ncpfs: tcp: Bad sequence number\n"); 641 620 __ncp_abort_request(server, req, -EIO); 642 621 return -EIO; 643 622 } 644 - if ((req->reply_buf->conn_low | (req->reply_buf->conn_high << 8)) != server->connection) { 623 + if ((((struct ncp_reply_header*)server->rxbuf)->conn_low | (((struct ncp_reply_header*)server->rxbuf)->conn_high << 8)) != server->connection) { 645 624 printk(KERN_ERR "ncpfs: tcp: Connection number mismatch\n"); 646 625 __ncp_abort_request(server, req, -EIO); 647 626 return -EIO; ··· 649 628 } 650 629 #ifdef CONFIG_NCPFS_PACKET_SIGNING 651 630 if (server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) { 652 - if (sign_verify_reply(server, (unsigned char*)(req->reply_buf) + 6, req->datalen - 6, cpu_to_be32(req->datalen + 16), &server->rcv.buf.type)) { 631 + if (sign_verify_reply(server, server->rxbuf + 6, req->datalen - 6, cpu_to_be32(req->datalen + 16), &server->rcv.buf.type)) { 653 632 printk(KERN_ERR "ncpfs: tcp: Signature violation\n"); 654 633 __ncp_abort_request(server, req, -EIO); 655 634 return -EIO; 656 635 } 657 636 } 658 637 #endif 659 - ncp_finish_request(req, req->datalen); 638 + ncp_finish_request(server, req, req->datalen); 660 639 nextreq:; 661 640 __ncp_next_request(server); 662 641 case 2: ··· 666 645 server->rcv.state = 0; 667 646 break; 668 647 case 3: 669 - ncp_finish_request(server->rcv.creq, -EIO); 648 + ncp_finish_request(server, server->rcv.creq, -EIO); 670 649 goto nextreq; 671 650 case 5: 672 651 info_server(server, 0, server->unexpected_packet.data, server->unexpected_packet.len); ··· 696 675 } 697 676 698 677 static int do_ncp_rpc_call(struct ncp_server *server, int size, 699 - struct ncp_reply_header* reply_buf, int max_reply_size) 678 + unsigned char* reply_buf, int max_reply_size) 700 679 { 701 680 int result; 702 - struct ncp_request_reply req; 681 + struct ncp_request_reply *req; 703 682 704 - ncp_init_req(&req); 705 - req.reply_buf = reply_buf; 706 - req.datalen = max_reply_size; 707 - req.tx_iov[1].iov_base = server->packet; 708 - req.tx_iov[1].iov_len = size; 709 - req.tx_iovlen = 1; 710 - req.tx_totallen = size; 711 - req.tx_type = *(u_int16_t*)server->packet; 683 + req = ncp_alloc_req(); 684 + if (!req) 685 + return -ENOMEM; 712 686 713 - result = ncp_add_request(server, &req); 714 - if (result < 0) { 715 - return result; 687 + req->reply_buf = reply_buf; 688 + req->datalen = max_reply_size; 689 + req->tx_iov[1].iov_base = server->packet; 690 + req->tx_iov[1].iov_len = size; 691 + req->tx_iovlen = 1; 692 + req->tx_totallen = size; 693 + req->tx_type = *(u_int16_t*)server->packet; 694 + 695 + result = ncp_add_request(server, req); 696 + if (result < 0) 697 + goto out; 698 + 699 + if (wait_event_interruptible(req->wq, req->status == RQ_DONE)) { 700 + ncp_abort_request(server, req, -EINTR); 701 + result = -EINTR; 702 + goto out; 716 703 } 717 - if (wait_event_interruptible(req.wq, req.status == RQ_DONE)) { 718 - ncp_abort_request(server, &req, -EIO); 719 - } 720 - return req.result; 704 + 705 + result = req->result; 706 + 707 + out: 708 + ncp_req_put(req); 709 + 710 + return result; 721 711 } 722 712 723 713 /* ··· 783 751 784 752 DDPRINTK("do_ncp_rpc_call returned %d\n", result); 785 753 786 - if (result < 0) { 787 - /* There was a problem with I/O, so the connections is 788 - * no longer usable. */ 789 - ncp_invalidate_conn(server); 790 - } 791 754 return result; 792 755 } 793 756
+2
include/linux/ncp_fs_sb.h
··· 50 50 int packet_size; 51 51 unsigned char *packet; /* Here we prepare requests and 52 52 receive replies */ 53 + unsigned char *txbuf; /* Storage for current request */ 54 + unsigned char *rxbuf; /* Storage for reply to current request */ 53 55 54 56 int lock; /* To prevent mismatch in protocols. */ 55 57 struct mutex mutex;