blob: 7b0e3192ee390a46a20e7e2639f4a3fa57cc06c3 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* vlclient.c: AFS Volume Location Service client
2 *
3 * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
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.
10 */
11
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"
25
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 */
29
30static void afs_rxvl_get_entry_by_id_attn(struct rxrpc_call *call);
31static void afs_rxvl_get_entry_by_id_error(struct rxrpc_call *call);
32
33/*****************************************************************************/
34/*
35 * map afs VL abort codes to/from Linux error codes
36 * - called with call->lock held
37 */
38static void afs_rxvl_aemap(struct rxrpc_call *call)
39{
40 int err;
41
42 _enter("{%u,%u,%d}",
43 call->app_err_state, call->app_abort_code, call->app_errno);
44
45 switch (call->app_err_state) {
46 case RXRPC_ESTATE_LOCAL_ABORT:
47 call->app_abort_code = -call->app_errno;
48 return;
49
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;
83 }
84 call->app_errno = err;
85 return;
86
87 default:
88 return;
89 }
90} /* end afs_rxvl_aemap() */
91
92#if 0
93/*****************************************************************************/
94/*
95 * probe a volume location server to see if it is still alive -- unused
96 */
97static int afs_rxvl_probe(struct afs_server *server, int alloc_flags)
98{
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];
105
106 DECLARE_WAITQUEUE(myself, current);
107
108 /* get hold of the vlserver connection */
109 ret = afs_server_get_vlconn(server, &conn);
110 if (ret < 0)
111 goto out;
112
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;
118 }
119 call->app_opcode = VLPROBE;
120
121 /* we want to get event notifications from the call */
122 add_wait_queue(&call->waitq, &myself);
123
124 /* marshall the parameters */
125 param[0] = htonl(VLPROBE);
126 piov[0].iov_len = sizeof(param);
127 piov[0].iov_base = param;
128
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;
134
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();
142 }
143 set_current_state(TASK_RUNNING);
144
145 ret = -EINTR;
146 if (signal_pending(current))
147 goto abort;
148
149 switch (call->app_call_state) {
150 case RXRPC_CSTATE_ERROR:
151 ret = call->app_errno;
152 goto out_unwait;
153
154 case RXRPC_CSTATE_CLNT_GOT_REPLY:
155 ret = 0;
156 goto out_unwait;
157
158 default:
159 BUG();
160 }
161
162 abort:
163 set_current_state(TASK_UNINTERRUPTIBLE);
164 rxrpc_call_abort(call, ret);
165 schedule();
166
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;
175
176} /* end afs_rxvl_probe() */
177#endif
178
179/*****************************************************************************/
180/*
181 * look up a volume location database entry by name
182 */
183int afs_rxvl_get_entry_by_name(struct afs_server *server,
184 const char *volname,
185 unsigned volnamesz,
186 struct afs_cache_vlocation *entry)
187{
188 DECLARE_WAITQUEUE(myself, current);
189
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;
197
198 _enter(",%*.*s,%u,", volnamesz, volnamesz, volname, volnamesz);
199
200 memset(entry, 0, sizeof(*entry));
201
202 /* get hold of the vlserver connection */
203 ret = afs_server_get_vlconn(server, &conn);
204 if (ret < 0)
205 goto out;
206
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;
212 }
213 call->app_opcode = VLGETENTRYBYNAME;
214
215 /* we want to get event notifications from the call */
216 add_wait_queue(&call->waitq, &myself);
217
218 /* marshall the parameters */
219 piov[1].iov_len = volnamesz;
220 piov[1].iov_base = (char *) volname;
221
222 zero = 0;
223 piov[2].iov_len = (4 - (piov[1].iov_len & 3)) & 3;
224 piov[2].iov_base = &zero;
225
226 param[0] = htonl(VLGETENTRYBYNAME);
227 param[1] = htonl(piov[1].iov_len);
228
229 piov[0].iov_len = sizeof(param);
230 piov[0].iov_base = param;
231
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;
237
238 /* wait for the reply to completely arrive */
239 bp = rxrpc_call_alloc_scratch(call, 384);
240
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;
248 }
249 goto abort;
250 }
251
252 /* unmarshall the reply */
253 for (loop = 0; loop < 64; loop++)
254 entry->name[loop] = ntohl(*bp++);
255 bp++; /* final NUL */
256
257 bp++; /* type */
258 entry->nservers = ntohl(*bp++);
259
260 for (loop = 0; loop < 8; loop++)
261 entry->servers[loop].s_addr = *bp++;
262
263 bp += 8; /* partition IDs */
264
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;
273 }
274
275 entry->vid[0] = ntohl(*bp++);
276 entry->vid[1] = ntohl(*bp++);
277 entry->vid[2] = ntohl(*bp++);
278
279 bp++; /* clone ID */
280
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;
288
289 ret = -ENOMEDIUM;
290 if (!entry->vidmask)
291 goto abort;
292
293 /* success */
294 entry->rtime = get_seconds();
295 ret = 0;
296
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;
306
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() */
313
314/*****************************************************************************/
315/*
316 * look up a volume location database entry by ID
317 */
318int 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)
322{
323 DECLARE_WAITQUEUE(myself, current);
324
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];
332
333 _enter(",%x,%d,", volid, voltype);
334
335 memset(entry, 0, sizeof(*entry));
336
337 /* get hold of the vlserver connection */
338 ret = afs_server_get_vlconn(server, &conn);
339 if (ret < 0)
340 goto out;
341
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;
347 }
348 call->app_opcode = VLGETENTRYBYID;
349
350 /* we want to get event notifications from the call */
351 add_wait_queue(&call->waitq, &myself);
352
353 /* marshall the parameters */
354 param[0] = htonl(VLGETENTRYBYID);
355 param[1] = htonl(volid);
356 param[2] = htonl(voltype);
357
358 piov[0].iov_len = sizeof(param);
359 piov[0].iov_base = param;
360
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;
366
367 /* wait for the reply to completely arrive */
368 bp = rxrpc_call_alloc_scratch(call, 384);
369
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;
377 }
378 goto abort;
379 }
380
381 /* unmarshall the reply */
382 for (loop = 0; loop < 64; loop++)
383 entry->name[loop] = ntohl(*bp++);
384 bp++; /* final NUL */
385
386 bp++; /* type */
387 entry->nservers = ntohl(*bp++);
388
389 for (loop = 0; loop < 8; loop++)
390 entry->servers[loop].s_addr = *bp++;
391
392 bp += 8; /* partition IDs */
393
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;
402 }
403
404 entry->vid[0] = ntohl(*bp++);
405 entry->vid[1] = ntohl(*bp++);
406 entry->vid[2] = ntohl(*bp++);
407
408 bp++; /* clone ID */
409
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;
417
418 ret = -ENOMEDIUM;
419 if (!entry->vidmask)
420 goto abort;
421
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*/);
427
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
432
433 /* success */
434 entry->rtime = get_seconds();
435 ret = 0;
436
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;
446
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() */
453
454/*****************************************************************************/
455/*
456 * look up a volume location database entry by ID asynchronously
457 */
458int afs_rxvl_get_entry_by_id_async(struct afs_async_op *op,
459 afs_volid_t volid,
460 afs_voltype_t voltype)
461{
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];
468
469 _enter(",%x,%d,", volid, voltype);
470
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;
476 }
477
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);
485
486 if (ret < 0) {
487 printk("kAFS: Unable to create call: %d\n", ret);
488 _leave(" = %d", ret);
489 return ret;
490 }
491
492 op->call->app_opcode = VLGETENTRYBYID;
493 op->call->app_user = op;
494
495 call = op->call;
496 rxrpc_get_call(call);
497
498 /* send event notifications from the call to kafsasyncd */
499 afs_kafsasyncd_begin_op(op);
500
501 /* marshall the parameters */
502 param[0] = htonl(VLGETENTRYBYID);
503 param[1] = htonl(volid);
504 param[2] = htonl(voltype);
505
506 piov[0].iov_len = sizeof(param);
507 piov[0].iov_base = param;
508
509 /* allocate result read buffer in scratch space */
510 call->app_scr_ptr = rxrpc_call_alloc_scratch(op->call, 384);
511
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;
519 }
520
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 */
529
530 default:
531 rxrpc_call_abort(call, ret); /* make kafsasyncd handle it */
532 ret = 0;
533 break;
534 }
535
536 out:
537 rxrpc_put_call(call);
538 _leave(" = %d", ret);
539 return ret;
540
541} /* end afs_rxvl_get_entry_by_id_async() */
542
543/*****************************************************************************/
544/*
545 * attend to the asynchronous get VLDB entry by ID
546 */
547int afs_rxvl_get_entry_by_id_async2(struct afs_async_op *op,
548 struct afs_cache_vlocation *entry)
549{
550 __be32 *bp;
551 __u32 tmp;
552 int loop, ret;
553
554 _enter("{op=%p cst=%u}", op, op->call->app_call_state);
555
556 memset(entry, 0, sizeof(*entry));
557
558 if (op->call->app_call_state == RXRPC_CSTATE_COMPLETE) {
559 /* operation finished */
560 afs_kafsasyncd_terminate_op(op);
561
562 bp = op->call->app_scr_ptr;
563
564 /* unmarshall the reply */
565 for (loop = 0; loop < 64; loop++)
566 entry->name[loop] = ntohl(*bp++);
567 bp++; /* final NUL */
568
569 bp++; /* type */
570 entry->nservers = ntohl(*bp++);
571
572 for (loop = 0; loop < 8; loop++)
573 entry->servers[loop].s_addr = *bp++;
574
575 bp += 8; /* partition IDs */
576
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;
585 }
586
587 entry->vid[0] = ntohl(*bp++);
588 entry->vid[1] = ntohl(*bp++);
589 entry->vid[2] = ntohl(*bp++);
590
591 bp++; /* clone ID */
592
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;
600
601 ret = -ENOMEDIUM;
602 if (!entry->vidmask) {
603 rxrpc_call_abort(op->call, ret);
604 goto done;
605 }
606
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*/);
612
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
617
618 /* success */
619 entry->rtime = get_seconds();
620 ret = 0;
621 goto done;
622 }
623
624 if (op->call->app_call_state == RXRPC_CSTATE_ERROR) {
625 /* operation error */
626 ret = op->call->app_errno;
627 goto done;
628 }
629
630 _leave(" = -EAGAIN");
631 return -EAGAIN;
632
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() */
639
640/*****************************************************************************/
641/*
642 * handle attention events on an async get-entry-by-ID op
643 * - called from krxiod
644 */
645static void afs_rxvl_get_entry_by_id_attn(struct rxrpc_call *call)
646{
647 struct afs_async_op *op = call->app_user;
648
649 _enter("{op=%p cst=%u}", op, call->app_call_state);
650
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" : "");
669
670 rxrpc_call_abort(call, -EBADMSG);
671 break;
672 default:
673 BUG();
674 }
675
676 _leave("");
677
678} /* end afs_rxvl_get_entry_by_id_attn() */
679
680/*****************************************************************************/
681/*
682 * handle error events on an async get-entry-by-ID op
683 * - called from krxiod
684 */
685static void afs_rxvl_get_entry_by_id_error(struct rxrpc_call *call)
686{
687 struct afs_async_op *op = call->app_user;
688
689 _enter("{op=%p cst=%u}", op, call->app_call_state);
690
691 afs_kafsasyncd_attend_op(op);
692
693 _leave("");
694
695} /* end afs_rxvl_get_entry_by_id_error() */