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