[PATCH] hrtimers: prevent possible itimer DoS
[linux-2.6.22.y-op.git] / fs / afs / vlclient.c
blob7b0e3192ee390a46a20e7e2639f4a3fa57cc06c3
1 /* vlclient.c: AFS Volume Location Service client
3 * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
12 #include <linux/init.h>
13 #include <linux/sched.h>
14 #include <rxrpc/rxrpc.h>
15 #include <rxrpc/transport.h>
16 #include <rxrpc/connection.h>
17 #include <rxrpc/call.h>
18 #include "server.h"
19 #include "volume.h"
20 #include "vlclient.h"
21 #include "kafsasyncd.h"
22 #include "kafstimod.h"
23 #include "errors.h"
24 #include "internal.h"
26 #define VLGETENTRYBYID 503 /* AFS Get Cache Entry By ID operation ID */
27 #define VLGETENTRYBYNAME 504 /* AFS Get Cache Entry By Name operation ID */
28 #define VLPROBE 514 /* AFS Probe Volume Location Service operation ID */
30 static void afs_rxvl_get_entry_by_id_attn(struct rxrpc_call *call);
31 static void afs_rxvl_get_entry_by_id_error(struct rxrpc_call *call);
33 /*****************************************************************************/
35 * map afs VL abort codes to/from Linux error codes
36 * - called with call->lock held
38 static void afs_rxvl_aemap(struct rxrpc_call *call)
40 int err;
42 _enter("{%u,%u,%d}",
43 call->app_err_state, call->app_abort_code, call->app_errno);
45 switch (call->app_err_state) {
46 case RXRPC_ESTATE_LOCAL_ABORT:
47 call->app_abort_code = -call->app_errno;
48 return;
50 case RXRPC_ESTATE_PEER_ABORT:
51 switch (call->app_abort_code) {
52 case AFSVL_IDEXIST: err = -EEXIST; break;
53 case AFSVL_IO: err = -EREMOTEIO; break;
54 case AFSVL_NAMEEXIST: err = -EEXIST; break;
55 case AFSVL_CREATEFAIL: err = -EREMOTEIO; break;
56 case AFSVL_NOENT: err = -ENOMEDIUM; break;
57 case AFSVL_EMPTY: err = -ENOMEDIUM; break;
58 case AFSVL_ENTDELETED: err = -ENOMEDIUM; break;
59 case AFSVL_BADNAME: err = -EINVAL; break;
60 case AFSVL_BADINDEX: err = -EINVAL; break;
61 case AFSVL_BADVOLTYPE: err = -EINVAL; break;
62 case AFSVL_BADSERVER: err = -EINVAL; break;
63 case AFSVL_BADPARTITION: err = -EINVAL; break;
64 case AFSVL_REPSFULL: err = -EFBIG; break;
65 case AFSVL_NOREPSERVER: err = -ENOENT; break;
66 case AFSVL_DUPREPSERVER: err = -EEXIST; break;
67 case AFSVL_RWNOTFOUND: err = -ENOENT; break;
68 case AFSVL_BADREFCOUNT: err = -EINVAL; break;
69 case AFSVL_SIZEEXCEEDED: err = -EINVAL; break;
70 case AFSVL_BADENTRY: err = -EINVAL; break;
71 case AFSVL_BADVOLIDBUMP: err = -EINVAL; break;
72 case AFSVL_IDALREADYHASHED: err = -EINVAL; break;
73 case AFSVL_ENTRYLOCKED: err = -EBUSY; break;
74 case AFSVL_BADVOLOPER: err = -EBADRQC; break;
75 case AFSVL_BADRELLOCKTYPE: err = -EINVAL; break;
76 case AFSVL_RERELEASE: err = -EREMOTEIO; break;
77 case AFSVL_BADSERVERFLAG: err = -EINVAL; break;
78 case AFSVL_PERM: err = -EACCES; break;
79 case AFSVL_NOMEM: err = -EREMOTEIO; break;
80 default:
81 err = afs_abort_to_error(call->app_abort_code);
82 break;
84 call->app_errno = err;
85 return;
87 default:
88 return;
90 } /* end afs_rxvl_aemap() */
92 #if 0
93 /*****************************************************************************/
95 * probe a volume location server to see if it is still alive -- unused
97 static int afs_rxvl_probe(struct afs_server *server, int alloc_flags)
99 struct rxrpc_connection *conn;
100 struct rxrpc_call *call;
101 struct kvec piov[1];
102 size_t sent;
103 int ret;
104 __be32 param[1];
106 DECLARE_WAITQUEUE(myself, current);
108 /* get hold of the vlserver connection */
109 ret = afs_server_get_vlconn(server, &conn);
110 if (ret < 0)
111 goto out;
113 /* create a call through that connection */
114 ret = rxrpc_create_call(conn, NULL, NULL, afs_rxvl_aemap, &call);
115 if (ret < 0) {
116 printk("kAFS: Unable to create call: %d\n", ret);
117 goto out_put_conn;
119 call->app_opcode = VLPROBE;
121 /* we want to get event notifications from the call */
122 add_wait_queue(&call->waitq, &myself);
124 /* marshall the parameters */
125 param[0] = htonl(VLPROBE);
126 piov[0].iov_len = sizeof(param);
127 piov[0].iov_base = param;
129 /* send the parameters to the server */
130 ret = rxrpc_call_write_data(call, 1, piov, RXRPC_LAST_PACKET,
131 alloc_flags, 0, &sent);
132 if (ret < 0)
133 goto abort;
135 /* wait for the reply to completely arrive */
136 for (;;) {
137 set_current_state(TASK_INTERRUPTIBLE);
138 if (call->app_call_state != RXRPC_CSTATE_CLNT_RCV_REPLY ||
139 signal_pending(current))
140 break;
141 schedule();
143 set_current_state(TASK_RUNNING);
145 ret = -EINTR;
146 if (signal_pending(current))
147 goto abort;
149 switch (call->app_call_state) {
150 case RXRPC_CSTATE_ERROR:
151 ret = call->app_errno;
152 goto out_unwait;
154 case RXRPC_CSTATE_CLNT_GOT_REPLY:
155 ret = 0;
156 goto out_unwait;
158 default:
159 BUG();
162 abort:
163 set_current_state(TASK_UNINTERRUPTIBLE);
164 rxrpc_call_abort(call, ret);
165 schedule();
167 out_unwait:
168 set_current_state(TASK_RUNNING);
169 remove_wait_queue(&call->waitq, &myself);
170 rxrpc_put_call(call);
171 out_put_conn:
172 rxrpc_put_connection(conn);
173 out:
174 return ret;
176 } /* end afs_rxvl_probe() */
177 #endif
179 /*****************************************************************************/
181 * look up a volume location database entry by name
183 int afs_rxvl_get_entry_by_name(struct afs_server *server,
184 const char *volname,
185 unsigned volnamesz,
186 struct afs_cache_vlocation *entry)
188 DECLARE_WAITQUEUE(myself, current);
190 struct rxrpc_connection *conn;
191 struct rxrpc_call *call;
192 struct kvec piov[3];
193 unsigned tmp;
194 size_t sent;
195 int ret, loop;
196 __be32 *bp, param[2], zero;
198 _enter(",%*.*s,%u,", volnamesz, volnamesz, volname, volnamesz);
200 memset(entry, 0, sizeof(*entry));
202 /* get hold of the vlserver connection */
203 ret = afs_server_get_vlconn(server, &conn);
204 if (ret < 0)
205 goto out;
207 /* create a call through that connection */
208 ret = rxrpc_create_call(conn, NULL, NULL, afs_rxvl_aemap, &call);
209 if (ret < 0) {
210 printk("kAFS: Unable to create call: %d\n", ret);
211 goto out_put_conn;
213 call->app_opcode = VLGETENTRYBYNAME;
215 /* we want to get event notifications from the call */
216 add_wait_queue(&call->waitq, &myself);
218 /* marshall the parameters */
219 piov[1].iov_len = volnamesz;
220 piov[1].iov_base = (char *) volname;
222 zero = 0;
223 piov[2].iov_len = (4 - (piov[1].iov_len & 3)) & 3;
224 piov[2].iov_base = &zero;
226 param[0] = htonl(VLGETENTRYBYNAME);
227 param[1] = htonl(piov[1].iov_len);
229 piov[0].iov_len = sizeof(param);
230 piov[0].iov_base = param;
232 /* send the parameters to the server */
233 ret = rxrpc_call_write_data(call, 3, piov, RXRPC_LAST_PACKET, GFP_NOFS,
234 0, &sent);
235 if (ret < 0)
236 goto abort;
238 /* wait for the reply to completely arrive */
239 bp = rxrpc_call_alloc_scratch(call, 384);
241 ret = rxrpc_call_read_data(call, bp, 384,
242 RXRPC_CALL_READ_BLOCK |
243 RXRPC_CALL_READ_ALL);
244 if (ret < 0) {
245 if (ret == -ECONNABORTED) {
246 ret = call->app_errno;
247 goto out_unwait;
249 goto abort;
252 /* unmarshall the reply */
253 for (loop = 0; loop < 64; loop++)
254 entry->name[loop] = ntohl(*bp++);
255 bp++; /* final NUL */
257 bp++; /* type */
258 entry->nservers = ntohl(*bp++);
260 for (loop = 0; loop < 8; loop++)
261 entry->servers[loop].s_addr = *bp++;
263 bp += 8; /* partition IDs */
265 for (loop = 0; loop < 8; loop++) {
266 tmp = ntohl(*bp++);
267 if (tmp & AFS_VLSF_RWVOL)
268 entry->srvtmask[loop] |= AFS_VOL_VTM_RW;
269 if (tmp & AFS_VLSF_ROVOL)
270 entry->srvtmask[loop] |= AFS_VOL_VTM_RO;
271 if (tmp & AFS_VLSF_BACKVOL)
272 entry->srvtmask[loop] |= AFS_VOL_VTM_BAK;
275 entry->vid[0] = ntohl(*bp++);
276 entry->vid[1] = ntohl(*bp++);
277 entry->vid[2] = ntohl(*bp++);
279 bp++; /* clone ID */
281 tmp = ntohl(*bp++); /* flags */
282 if (tmp & AFS_VLF_RWEXISTS)
283 entry->vidmask |= AFS_VOL_VTM_RW;
284 if (tmp & AFS_VLF_ROEXISTS)
285 entry->vidmask |= AFS_VOL_VTM_RO;
286 if (tmp & AFS_VLF_BACKEXISTS)
287 entry->vidmask |= AFS_VOL_VTM_BAK;
289 ret = -ENOMEDIUM;
290 if (!entry->vidmask)
291 goto abort;
293 /* success */
294 entry->rtime = get_seconds();
295 ret = 0;
297 out_unwait:
298 set_current_state(TASK_RUNNING);
299 remove_wait_queue(&call->waitq, &myself);
300 rxrpc_put_call(call);
301 out_put_conn:
302 rxrpc_put_connection(conn);
303 out:
304 _leave(" = %d", ret);
305 return ret;
307 abort:
308 set_current_state(TASK_UNINTERRUPTIBLE);
309 rxrpc_call_abort(call, ret);
310 schedule();
311 goto out_unwait;
312 } /* end afs_rxvl_get_entry_by_name() */
314 /*****************************************************************************/
316 * look up a volume location database entry by ID
318 int afs_rxvl_get_entry_by_id(struct afs_server *server,
319 afs_volid_t volid,
320 afs_voltype_t voltype,
321 struct afs_cache_vlocation *entry)
323 DECLARE_WAITQUEUE(myself, current);
325 struct rxrpc_connection *conn;
326 struct rxrpc_call *call;
327 struct kvec piov[1];
328 unsigned tmp;
329 size_t sent;
330 int ret, loop;
331 __be32 *bp, param[3];
333 _enter(",%x,%d,", volid, voltype);
335 memset(entry, 0, sizeof(*entry));
337 /* get hold of the vlserver connection */
338 ret = afs_server_get_vlconn(server, &conn);
339 if (ret < 0)
340 goto out;
342 /* create a call through that connection */
343 ret = rxrpc_create_call(conn, NULL, NULL, afs_rxvl_aemap, &call);
344 if (ret < 0) {
345 printk("kAFS: Unable to create call: %d\n", ret);
346 goto out_put_conn;
348 call->app_opcode = VLGETENTRYBYID;
350 /* we want to get event notifications from the call */
351 add_wait_queue(&call->waitq, &myself);
353 /* marshall the parameters */
354 param[0] = htonl(VLGETENTRYBYID);
355 param[1] = htonl(volid);
356 param[2] = htonl(voltype);
358 piov[0].iov_len = sizeof(param);
359 piov[0].iov_base = param;
361 /* send the parameters to the server */
362 ret = rxrpc_call_write_data(call, 1, piov, RXRPC_LAST_PACKET, GFP_NOFS,
363 0, &sent);
364 if (ret < 0)
365 goto abort;
367 /* wait for the reply to completely arrive */
368 bp = rxrpc_call_alloc_scratch(call, 384);
370 ret = rxrpc_call_read_data(call, bp, 384,
371 RXRPC_CALL_READ_BLOCK |
372 RXRPC_CALL_READ_ALL);
373 if (ret < 0) {
374 if (ret == -ECONNABORTED) {
375 ret = call->app_errno;
376 goto out_unwait;
378 goto abort;
381 /* unmarshall the reply */
382 for (loop = 0; loop < 64; loop++)
383 entry->name[loop] = ntohl(*bp++);
384 bp++; /* final NUL */
386 bp++; /* type */
387 entry->nservers = ntohl(*bp++);
389 for (loop = 0; loop < 8; loop++)
390 entry->servers[loop].s_addr = *bp++;
392 bp += 8; /* partition IDs */
394 for (loop = 0; loop < 8; loop++) {
395 tmp = ntohl(*bp++);
396 if (tmp & AFS_VLSF_RWVOL)
397 entry->srvtmask[loop] |= AFS_VOL_VTM_RW;
398 if (tmp & AFS_VLSF_ROVOL)
399 entry->srvtmask[loop] |= AFS_VOL_VTM_RO;
400 if (tmp & AFS_VLSF_BACKVOL)
401 entry->srvtmask[loop] |= AFS_VOL_VTM_BAK;
404 entry->vid[0] = ntohl(*bp++);
405 entry->vid[1] = ntohl(*bp++);
406 entry->vid[2] = ntohl(*bp++);
408 bp++; /* clone ID */
410 tmp = ntohl(*bp++); /* flags */
411 if (tmp & AFS_VLF_RWEXISTS)
412 entry->vidmask |= AFS_VOL_VTM_RW;
413 if (tmp & AFS_VLF_ROEXISTS)
414 entry->vidmask |= AFS_VOL_VTM_RO;
415 if (tmp & AFS_VLF_BACKEXISTS)
416 entry->vidmask |= AFS_VOL_VTM_BAK;
418 ret = -ENOMEDIUM;
419 if (!entry->vidmask)
420 goto abort;
422 #if 0 /* TODO: remove */
423 entry->nservers = 3;
424 entry->servers[0].s_addr = htonl(0xac101249);
425 entry->servers[1].s_addr = htonl(0xac101243);
426 entry->servers[2].s_addr = htonl(0xac10125b /*0xac10125b*/);
428 entry->srvtmask[0] = AFS_VOL_VTM_RO;
429 entry->srvtmask[1] = AFS_VOL_VTM_RO;
430 entry->srvtmask[2] = AFS_VOL_VTM_RO | AFS_VOL_VTM_RW;
431 #endif
433 /* success */
434 entry->rtime = get_seconds();
435 ret = 0;
437 out_unwait:
438 set_current_state(TASK_RUNNING);
439 remove_wait_queue(&call->waitq, &myself);
440 rxrpc_put_call(call);
441 out_put_conn:
442 rxrpc_put_connection(conn);
443 out:
444 _leave(" = %d", ret);
445 return ret;
447 abort:
448 set_current_state(TASK_UNINTERRUPTIBLE);
449 rxrpc_call_abort(call, ret);
450 schedule();
451 goto out_unwait;
452 } /* end afs_rxvl_get_entry_by_id() */
454 /*****************************************************************************/
456 * look up a volume location database entry by ID asynchronously
458 int afs_rxvl_get_entry_by_id_async(struct afs_async_op *op,
459 afs_volid_t volid,
460 afs_voltype_t voltype)
462 struct rxrpc_connection *conn;
463 struct rxrpc_call *call;
464 struct kvec piov[1];
465 size_t sent;
466 int ret;
467 __be32 param[3];
469 _enter(",%x,%d,", volid, voltype);
471 /* get hold of the vlserver connection */
472 ret = afs_server_get_vlconn(op->server, &conn);
473 if (ret < 0) {
474 _leave(" = %d", ret);
475 return ret;
478 /* create a call through that connection */
479 ret = rxrpc_create_call(conn,
480 afs_rxvl_get_entry_by_id_attn,
481 afs_rxvl_get_entry_by_id_error,
482 afs_rxvl_aemap,
483 &op->call);
484 rxrpc_put_connection(conn);
486 if (ret < 0) {
487 printk("kAFS: Unable to create call: %d\n", ret);
488 _leave(" = %d", ret);
489 return ret;
492 op->call->app_opcode = VLGETENTRYBYID;
493 op->call->app_user = op;
495 call = op->call;
496 rxrpc_get_call(call);
498 /* send event notifications from the call to kafsasyncd */
499 afs_kafsasyncd_begin_op(op);
501 /* marshall the parameters */
502 param[0] = htonl(VLGETENTRYBYID);
503 param[1] = htonl(volid);
504 param[2] = htonl(voltype);
506 piov[0].iov_len = sizeof(param);
507 piov[0].iov_base = param;
509 /* allocate result read buffer in scratch space */
510 call->app_scr_ptr = rxrpc_call_alloc_scratch(op->call, 384);
512 /* send the parameters to the server */
513 ret = rxrpc_call_write_data(call, 1, piov, RXRPC_LAST_PACKET, GFP_NOFS,
514 0, &sent);
515 if (ret < 0) {
516 rxrpc_call_abort(call, ret); /* handle from kafsasyncd */
517 ret = 0;
518 goto out;
521 /* wait for the reply to completely arrive */
522 ret = rxrpc_call_read_data(call, call->app_scr_ptr, 384, 0);
523 switch (ret) {
524 case 0:
525 case -EAGAIN:
526 case -ECONNABORTED:
527 ret = 0;
528 break; /* all handled by kafsasyncd */
530 default:
531 rxrpc_call_abort(call, ret); /* make kafsasyncd handle it */
532 ret = 0;
533 break;
536 out:
537 rxrpc_put_call(call);
538 _leave(" = %d", ret);
539 return ret;
541 } /* end afs_rxvl_get_entry_by_id_async() */
543 /*****************************************************************************/
545 * attend to the asynchronous get VLDB entry by ID
547 int afs_rxvl_get_entry_by_id_async2(struct afs_async_op *op,
548 struct afs_cache_vlocation *entry)
550 __be32 *bp;
551 __u32 tmp;
552 int loop, ret;
554 _enter("{op=%p cst=%u}", op, op->call->app_call_state);
556 memset(entry, 0, sizeof(*entry));
558 if (op->call->app_call_state == RXRPC_CSTATE_COMPLETE) {
559 /* operation finished */
560 afs_kafsasyncd_terminate_op(op);
562 bp = op->call->app_scr_ptr;
564 /* unmarshall the reply */
565 for (loop = 0; loop < 64; loop++)
566 entry->name[loop] = ntohl(*bp++);
567 bp++; /* final NUL */
569 bp++; /* type */
570 entry->nservers = ntohl(*bp++);
572 for (loop = 0; loop < 8; loop++)
573 entry->servers[loop].s_addr = *bp++;
575 bp += 8; /* partition IDs */
577 for (loop = 0; loop < 8; loop++) {
578 tmp = ntohl(*bp++);
579 if (tmp & AFS_VLSF_RWVOL)
580 entry->srvtmask[loop] |= AFS_VOL_VTM_RW;
581 if (tmp & AFS_VLSF_ROVOL)
582 entry->srvtmask[loop] |= AFS_VOL_VTM_RO;
583 if (tmp & AFS_VLSF_BACKVOL)
584 entry->srvtmask[loop] |= AFS_VOL_VTM_BAK;
587 entry->vid[0] = ntohl(*bp++);
588 entry->vid[1] = ntohl(*bp++);
589 entry->vid[2] = ntohl(*bp++);
591 bp++; /* clone ID */
593 tmp = ntohl(*bp++); /* flags */
594 if (tmp & AFS_VLF_RWEXISTS)
595 entry->vidmask |= AFS_VOL_VTM_RW;
596 if (tmp & AFS_VLF_ROEXISTS)
597 entry->vidmask |= AFS_VOL_VTM_RO;
598 if (tmp & AFS_VLF_BACKEXISTS)
599 entry->vidmask |= AFS_VOL_VTM_BAK;
601 ret = -ENOMEDIUM;
602 if (!entry->vidmask) {
603 rxrpc_call_abort(op->call, ret);
604 goto done;
607 #if 0 /* TODO: remove */
608 entry->nservers = 3;
609 entry->servers[0].s_addr = htonl(0xac101249);
610 entry->servers[1].s_addr = htonl(0xac101243);
611 entry->servers[2].s_addr = htonl(0xac10125b /*0xac10125b*/);
613 entry->srvtmask[0] = AFS_VOL_VTM_RO;
614 entry->srvtmask[1] = AFS_VOL_VTM_RO;
615 entry->srvtmask[2] = AFS_VOL_VTM_RO | AFS_VOL_VTM_RW;
616 #endif
618 /* success */
619 entry->rtime = get_seconds();
620 ret = 0;
621 goto done;
624 if (op->call->app_call_state == RXRPC_CSTATE_ERROR) {
625 /* operation error */
626 ret = op->call->app_errno;
627 goto done;
630 _leave(" = -EAGAIN");
631 return -EAGAIN;
633 done:
634 rxrpc_put_call(op->call);
635 op->call = NULL;
636 _leave(" = %d", ret);
637 return ret;
638 } /* end afs_rxvl_get_entry_by_id_async2() */
640 /*****************************************************************************/
642 * handle attention events on an async get-entry-by-ID op
643 * - called from krxiod
645 static void afs_rxvl_get_entry_by_id_attn(struct rxrpc_call *call)
647 struct afs_async_op *op = call->app_user;
649 _enter("{op=%p cst=%u}", op, call->app_call_state);
651 switch (call->app_call_state) {
652 case RXRPC_CSTATE_COMPLETE:
653 afs_kafsasyncd_attend_op(op);
654 break;
655 case RXRPC_CSTATE_CLNT_RCV_REPLY:
656 if (call->app_async_read)
657 break;
658 case RXRPC_CSTATE_CLNT_GOT_REPLY:
659 if (call->app_read_count == 0)
660 break;
661 printk("kAFS: Reply bigger than expected"
662 " {cst=%u asyn=%d mark=%Zu rdy=%Zu pr=%u%s}",
663 call->app_call_state,
664 call->app_async_read,
665 call->app_mark,
666 call->app_ready_qty,
667 call->pkt_rcv_count,
668 call->app_last_rcv ? " last" : "");
670 rxrpc_call_abort(call, -EBADMSG);
671 break;
672 default:
673 BUG();
676 _leave("");
678 } /* end afs_rxvl_get_entry_by_id_attn() */
680 /*****************************************************************************/
682 * handle error events on an async get-entry-by-ID op
683 * - called from krxiod
685 static void afs_rxvl_get_entry_by_id_error(struct rxrpc_call *call)
687 struct afs_async_op *op = call->app_user;
689 _enter("{op=%p cst=%u}", op, call->app_call_state);
691 afs_kafsasyncd_attend_op(op);
693 _leave("");
695 } /* end afs_rxvl_get_entry_by_id_error() */