Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / net / tux / abuf.c
1 /*
2  * TUX - Integrated Application Protocols Layer and Object Cache
3  *
4  * Copyright (C) 2000, 2001, Ingo Molnar <mingo@redhat.com>
5  *
6  * abuf.c: async buffer-sending
7  */
8
9 #include <net/tux.h>
10
11 /****************************************************************
12  *      This program is free software; you can redistribute it and/or modify
13  *      it under the terms of the GNU General Public License as published by
14  *      the Free Software Foundation; either version 2, or (at your option)
15  *      any later version.
16  *
17  *      This program is distributed in the hope that it will be useful,
18  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
19  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  *      GNU General Public License for more details.
21  *
22  *      You should have received a copy of the GNU General Public License
23  *      along with this program; if not, write to the Free Software
24  *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25  *
26  ****************************************************************/
27
28 char * get_abuf (tux_req_t *req, unsigned int max_size)
29 {
30         threadinfo_t *ti = req->ti;
31         struct page *page;
32         char *buf;
33         unsigned int offset;
34         unsigned int left;
35
36         if (req->abuf.page || req->abuf.buf || req->abuf.size)
37                 TUX_BUG();
38
39         if (max_size > PAGE_SIZE)
40                 BUG();
41         offset = ti->header_offset;
42         if (offset > PAGE_SIZE)
43                 TUX_BUG();
44         left = PAGE_SIZE - offset;
45         if (!max_size)
46                 BUG();
47         page = ti->header_cache;
48         if ((left < max_size) || !page) {
49                 while (!(page = alloc_pages(GFP_KERNEL, 0))) {
50                         if (net_ratelimit())
51                                 printk(KERN_WARNING "tux: OOM in get_abuf()!\n");
52                         current->state = TASK_UNINTERRUPTIBLE;
53                         schedule_timeout(1);
54                 }
55
56                 if (ti->header_cache)
57                         __free_page(ti->header_cache);
58                 ti->header_cache = page;
59                 ti->header_offset = 0;
60                 offset = 0;
61         }
62         buf = page_address(page) + offset;
63
64         if (!page)
65                 BUG();
66         req->abuf.page = page;
67         req->abuf.buf = buf;
68         req->abuf.size = 0;
69         req->abuf.offset = offset;
70         req->abuf.flags = 0;
71         get_page(req->abuf.page);
72
73         return buf;
74 }
75
76 static void do_send_abuf (tux_req_t *req, int cachemiss);
77
78 void send_abuf (tux_req_t *req, unsigned int size, unsigned long flags)
79 {
80         threadinfo_t *ti = req->ti;
81
82         Dprintk("send_abuf(req: %p, sock: %p): %p(%p), size:%d, off:%d, flags:%08lx\n", req, req->sock, req->abuf.page, req->abuf.buf, size, req->abuf.offset, flags);
83
84         ti->header_offset += size;
85         if (ti->header_offset > PAGE_SIZE)
86                 TUX_BUG();
87         if (req->abuf.offset + req->abuf.size > PAGE_SIZE)
88                 TUX_BUG();
89
90         req->abuf.flags = flags | MSG_NOSIGNAL;
91         req->abuf.size = size;
92
93         add_tux_atom(req, do_send_abuf);
94 }
95
96 static void do_send_abuf (tux_req_t *req, int cachemiss)
97 {
98         int ret;
99
100         if (req->magic != TUX_MAGIC)
101                 TUX_BUG();
102         if (!req->sock)
103                 TUX_BUG();
104         tcp_sk(req->sock->sk)->nonagle = 2;
105
106 repeat:
107         Dprintk("do_send_abuf(%p,%d): %p(%p), size:%d, off:%d, flags:%08lx\n",
108                         req, cachemiss,
109                         req->abuf.page, req->abuf.buf, req->abuf.size,
110                         req->abuf.offset, req->abuf.flags);
111
112         if (tux_zerocopy_header)
113                 ret = tcp_sendpage(req->sock, req->abuf.page,
114                         req->abuf.offset, req->abuf.size, req->abuf.flags);
115         else {
116                 mm_segment_t oldmm;
117                 oldmm = get_fs(); set_fs(KERNEL_DS);
118                 ret = send_sync_buf(req, req->sock, req->abuf.buf,
119                         req->abuf.size, req->abuf.flags);
120                 set_fs(oldmm);
121         }
122
123
124         Dprintk("do_send_abuf: ret: %d\n", ret);
125         if (!ret)
126                 TUX_BUG();
127
128         if (ret < 0) {
129                 if (ret != -EAGAIN) {
130                         TDprintk("ret: %d, req->error = TUX_ERROR_CONN_CLOSE.\n", ret);
131                         req->error = TUX_ERROR_CONN_CLOSE;
132                         req->atom_idx = 0;
133                         req->in_file->f_pos = 0;
134                         __free_page(req->abuf.page);
135                         memset(&req->abuf, 0, sizeof(req->abuf));
136                         zap_request(req, cachemiss);
137                         return;
138                 }
139                 add_tux_atom(req, do_send_abuf);
140                 if (add_output_space_event(req, req->sock)) {
141                         del_tux_atom(req);
142                         goto repeat;
143                 }
144                 return;
145         }
146
147         req->abuf.buf += ret;
148         req->abuf.offset += ret;
149         req->abuf.size -= ret;
150
151         if ((int)req->abuf.size < 0)
152                 TUX_BUG();
153         if (req->abuf.size > 0)
154                 goto repeat;
155
156         Dprintk("DONE do_send_abuf: %p(%p), size:%d, off:%d, flags:%08lx\n",
157                         req->abuf.page, req->abuf.buf, req->abuf.size,
158                         req->abuf.offset, req->abuf.flags);
159
160         if (req->abuf.page)
161                 __free_page(req->abuf.page);
162         else
163                 if (printk_ratelimit())
164                         WARN_ON(1);
165
166         memset(&req->abuf, 0, sizeof(req->abuf));
167
168         add_req_to_workqueue(req);
169 }
170
171 void __send_async_message (tux_req_t *req, const char *message,
172                                 int status, unsigned int size, int push)
173 {
174         unsigned int flags;
175         char *buf;
176
177         Dprintk("TUX: sending %d reply (%d bytes)!\n", status, size);
178         Dprintk("request %p, reply: %s\n", req, message);
179         if (!size)
180                 TUX_BUG();
181         buf = get_abuf(req, size);
182         memcpy(buf, message, size);
183
184         req->status = status;
185         flags = MSG_DONTWAIT;
186         if (!push)
187                 flags |= MSG_MORE;
188         send_abuf(req, size, flags);
189         add_req_to_workqueue(req);
190 }