vmod/vmodttl: fixed bug related to luns not ordered and/or not starting from zero.
[ht-drivers.git] / xmem / lib / daemon / XmemDaemon.c
blob0a60f6e73bc91a3871a5d317a1318def12b6da6b
1 /**
2 * @file XmemDaemon.c
4 * @brief Daemon for Xmem. Built on top of libxmem.
6 * @author Julian Lewis
8 * @date Created on 11/03/2005
10 * @version 1.1 Emilio G. Cota 23/01/2009
12 * @version 1.0 Julian Lewis
14 #include <ipc.h>
15 #include <shm.h>
16 #include <unistd.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <fcntl.h>
21 #include <sys/ioctl.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <errno.h>
25 #include <sys/file.h>
26 #include <a.out.h>
27 #include <ctype.h>
28 #include <time.h>
30 #include <libxmem.h>
31 #include <XmemDaemon.h>
34 extern int symp;
36 /* Event logging */
37 static XmemEventMask log_mask = XmemEventMaskMASK; /* Events to be logged */
38 static XdEventLogEntries *event_log = NULL;
39 static XdEventLogEntries *result = NULL;
41 int VmicDaemonWait(int timeout);
42 void VmicDaemonCall();
45 /**
46 * TimeToStr - Convert time to a standard string
48 * @param tod: time to convert
50 * The format is:
52 * Thu-18/Jan/2001 08:25:14
54 * day-dd/mon/yyyy hh:mm:ss
56 * @return pointer to a static string
58 char *TimeToStr(time_t tod)
60 static char tbuf[128];
62 char tmp[128];
63 char *yr, *ti, *md, *mn, *dy;
65 bzero((void *)tbuf, 128);
66 bzero((void *)tmp, 128);
68 if (tod) {
69 ctime_r(&tod, tmp);
71 tmp[ 3] = 0;
72 dy = &(tmp[0]);
74 tmp[ 7] = 0;
75 mn = &(tmp[4]);
77 tmp[10] = 0;
78 md = &(tmp[8]);
79 if (md[0] == ' ')
80 md[0] = '0';
82 tmp[19] = 0;
83 ti = &(tmp[11]);
85 tmp[24] = 0;
86 yr = &(tmp[20]);
88 sprintf (tbuf, "%s-%s/%s/%s %s", dy, md, mn, yr, ti);
89 } else
90 sprintf(tbuf, "--- Zero ---");
92 return tbuf;
96 /**
97 * GetEventLogTable - Get the event log table in shared memory
99 * @param : none
101 * @return a pointer to the acquired shared memory segment
103 XdEventLogEntries *GetEventLogTable()
105 key_t smemky;
106 unsigned smemid;
108 if (result)
109 return result;
111 smemky = XmemGetKey(EVENT_LOG_NAME);
112 smemid = shmget(smemky, sizeof(XdEventLogEntries), 0666);
114 if (smemid != -1) {
115 result = (XdEventLogEntries *)shmat(smemid, (char *)0, 0);
117 if ((int)result != -1)
118 return result;
119 else
120 goto errsys;
123 if (errno == ENOENT) {
124 /* a shared memory identifier does not exist; create it */
125 smemid = shmget(smemky, sizeof(XdEventLogEntries),
126 IPC_CREAT | 0666);
128 if (smemid == -1)
129 goto errsys;
131 result = (XdEventLogEntries *)shmat(smemid, (char *)0, 0);
133 if ((int)result == -1)
134 goto errsys;
136 /* clear the acquired segment and return */
137 bzero((void *)result, sizeof(XdEventLogEntries));
138 return result;
141 errsys:
142 XmemErrorCallback(XmemErrorSYSTEM, errno);
143 return NULL;
148 * CallbackToStr - Print out a callback structure
150 * @param cbs: Callback structure to be printed out
152 * @return pointer to the static string @str
154 char *CallbackToStr(XmemCallbackStruct *cbs)
156 static char str[128];
158 if (! cbs)
159 return NULL;
161 bzero((void *)str, 128);
163 switch (cbs->Mask) {
165 case XmemEventMaskTIMEOUT:
166 sprintf(str, "Timeout");
167 break;
169 case XmemEventMaskUSER:
170 sprintf(str, "User event:%d From node:%s",
171 (int)cbs->Data, XmemGetNodeName(cbs->Node));
172 break;
174 case XmemEventMaskSEND_TABLE:
175 sprintf(str, "Send table:%s From node:%s",
176 XmemGetTableName(cbs->Table),
177 XmemGetNodeName(cbs->Node));
178 break;
180 case XmemEventMaskTABLE_UPDATE:
181 sprintf(str, "Update table:%s From node:%s",
182 XmemGetTableName(cbs->Table),
183 XmemGetNodeName(cbs->Node));
184 break;
186 case XmemEventMaskINITIALIZED:
187 sprintf(str, "Initialized:%d From node:%s",
188 (int)cbs->Data, XmemGetNodeName(cbs->Node));
189 break;
191 case XmemEventMaskKILL:
192 sprintf(str, "Kill daemon received");
193 break;
195 case XmemEventMaskIO:
196 sprintf(str, "IO error:%s", XmemErrorToString(cbs->Data));
197 break;
199 case XmemEventMaskSYSTEM:
200 sprintf(str, "System error:%d", (int)cbs->Data);
201 break;
203 case XmemEventMaskSOFTWARE:
204 if (cbs->Data == XmemErrorSUCCESS)
205 sprintf(str, "Information:");
206 else
207 sprintf(str, "Software error:%s",
208 XmemErrorToString(cbs->Data));
209 break;
211 default:
212 break;
215 return str;
220 * LogEvent - Log an event in the log file
222 * @param cbs: callback struct with the information to log
223 * @param text: text to log
225 * This routine writes EVENT_LOG_ENTRIES events into a log file each time it
226 * has collected enough events.
228 * @return 1 on success; 0 otherwise
230 int LogEvent(XmemCallbackStruct *cbs, char *text)
232 int idx, cnt, logit;
233 time_t tod;
234 FILE *fp;
235 char *elog;
236 XdEventLogEntry *evp;
238 if (event_log == NULL)
239 return 0;
241 idx = event_log->NextEntry;
242 evp = &event_log->Entries[idx];
244 tod = time(NULL);
245 evp->Time = tod;
247 logit = 0;
249 if (text) {
250 strncpy(evp->Text, text, EVENT_MESSAGE_SIZE - 1);
251 fprintf(stderr, "%s XmemDaemon: %s\n", TimeToStr(tod), text);
252 logit++;
255 if (cbs && log_mask & cbs->Mask) {
256 evp->CbEvent = *cbs;
257 // fprintf(stderr, "XmemDaemon: %s %s\n",
258 // TimeToStr(tod),CallbackToStr(cbs));
259 logit++;
262 if (!logit)
263 return 1;
265 if (++idx >= EVENT_LOG_ENTRIES) {
266 /* event_log filled up; write to the file */
267 umask(0);
268 elog = XmemGetFile(EVENT_LOG);
269 fp = fopen(elog, "w");
271 if (!fp) {
272 perror("XmemDaemon");
273 fprintf(stderr,
274 "XmemDaemon: Error: Can't OPEN:%s for WRITE\n",
275 elog);
276 bzero((void *)event_log, sizeof(XdEventLogEntries));
277 return 0;
280 evp = &event_log->Entries[idx];
281 cnt = fwrite(event_log, sizeof(XdEventLogEntries), 1, fp);
283 if (cnt <= 0) {
284 perror("XmemDaemon");
285 fprintf(stderr, "XmemDaemon: Error: Can't WRITE:%s\n",
286 elog);
287 fclose(fp);
289 bzero((void *) event_log, sizeof(XdEventLogEntries));
290 return 0;
293 fclose(fp);
294 bzero((void *) event_log, sizeof(XdEventLogEntries));
296 return 1;
298 else
299 event_log->NextEntry = idx;
301 return 1;
305 * __flush_startup is only called by the callback handler when handling a
306 * pending initialisation; it alleviates an already bloated callback handler.
308 void __flush_startup(unsigned long *longs, XmemNodeId *nodes,
309 unsigned long *user, XmemNodeId me, XmemNodeId init_node)
311 #ifdef FLUSH_ON_STARTUP
312 int i;
313 unsigned long msk;
314 XmemTableId atids;
315 XmemNodeId acnds;
316 char txt[80];
318 atids = XmemGetAllTableIds();
320 for (i = 0; i < XmemMAX_TABLES; i++) {
321 msk = 1 << i;
322 if (! (msk & atids))
323 continue;
325 XmemGetTableDesc(msk, longs, nodes, user);
326 if (! (*nodes & me))
327 continue;
329 acnds = XmemGetAllNodeIds() & *nodes;
330 /* only the highest node ID issues the write */
331 if ((~me & acnds) > me)
332 continue;
334 XmemSendTable(msk, NULL, 0, 0, 1);
336 sprintf(txt, "Flushed table: %s For initialized node: %s",
337 XmemGetTableName(msk),
338 XmemGetNodeName(init_node));
339 LogEvent(NULL, txt);
341 #endif
342 return ;
346 * callback - callback handler
348 * @param cbs: callback struct delivered to the callback
351 void callback(XmemCallbackStruct *cbs)
353 int i;
354 unsigned long msk, user, longs;
356 XmemError err;
357 XmemNodeId me;
358 XmemNodeId nodes, acnds;
359 XmemTableId tid;
360 XmemMessage mess;
362 char txt[80];
363 unsigned long *smemad;
365 if (cbs == NULL)
366 return;
368 me = XmemWhoAmI();
370 tid = cbs->Table;
372 if (tid) {
373 err = XmemGetTableDesc(tid, &longs, &nodes, &user);
374 if (err != XmemErrorSUCCESS)
375 return;
377 else {
378 tid = 0;
379 longs = 0;
380 nodes = 0;
381 user = 0;
384 for (i = 0; i < XmemEventMASKS; i++) {
385 msk = 1 << i;
386 if (! (cbs->Mask & msk))
387 continue;
389 switch ((XmemEventMask) msk) {
391 case XmemEventMaskSEND_TABLE:
393 if ((!tid || cbs->Node == me) && !symp)
394 return;
395 if (! (me & nodes))
396 break;
398 if (user & IN_SHMEM) {
399 smemad = XmemGetSharedMemory(tid);
400 if (!smemad)
401 break;
403 XmemSendTable(tid, smemad, longs, 0, 1);
404 sprintf(txt,
405 "Written table: %s For requesting node: %s",
406 XmemGetTableName(tid),
407 XmemGetNodeName(cbs->Node));
408 LogEvent(NULL, txt);
410 else {
411 XmemSendTable(tid, NULL, 0, 0, 1);
412 sprintf(txt,
413 "Flushed table: %s For requesting node: %s",
414 XmemGetTableName(tid),
415 XmemGetNodeName(cbs->Node));
416 LogEvent(NULL, txt);
418 break;
420 case XmemEventMaskTABLE_UPDATE:
421 if ((!tid || cbs->Node == me) && !symp)
422 return;
423 if (! (user & IN_SHMEM))
424 break;
426 smemad = XmemGetSharedMemory(tid);
427 if (smemad) {
428 /* read from reflective memory */
429 XmemRecvTable(tid, smemad, longs, 0);
431 sprintf(txt,
432 "Received table: %s From updating node: %s",
433 XmemGetTableName(tid),
434 XmemGetNodeName(cbs->Node));
435 LogEvent(NULL, txt);
437 if (user & ON_DISC && nodes & me) {
438 acnds = XmemGetAllNodeIds() & nodes;
439 /* only the highest node ID issues the write */
440 if ((~me & acnds) > me)
441 break;
443 XmemWriteTableFile(tid);
444 sprintf(txt,
445 "Disc file updated for table: %s For requesting node: %s",
446 XmemGetTableName(tid),
447 XmemGetNodeName(cbs->Node));
448 LogEvent(NULL, txt);
450 break;
452 case XmemEventMaskINITIALIZED:
453 if (cbs->Data == XmemInitMessageRESET) {
454 /* Acknowledge Init and send tables */
455 mess.MessageType = XmemMessageTypeINITIALIZE_ME;
456 mess.Data = XmemInitMessageSEEN_BY;
457 XmemSendMessage(XmemALL_NODES, &mess);
459 __flush_startup(&longs, &nodes, &user,
460 me, cbs->Node);
462 if (cbs->Data != XmemInitMessageSEEN_BY)
463 LogEvent(cbs, NULL);
464 break;
466 case XmemEventMaskKILL:
467 sprintf(txt, "Received a Kill, EXIT: Deamon is DEAD");
468 LogEvent(cbs, txt);
469 exit(1);
470 break;
472 case XmemEventMaskUSER:
473 sprintf(txt, "User message received");
474 LogEvent(cbs, txt);
475 break;
477 case XmemEventMaskTIMEOUT:
478 case XmemEventMaskIO:
479 case XmemEventMaskSYSTEM:
480 case XmemEventMaskSOFTWARE:
481 break;
483 default:
484 break;
491 * __init_coldstart() reads the tables for the node from memory.
493 void __init_coldstart()
495 int i;
496 unsigned long msk, longs, user;
497 XmemError err;
498 XmemNodeId me, nodes;
499 XmemTableId tid;
501 char txt[80];
504 me = XmemWhoAmI();
506 tid = XmemGetAllTableIds();
508 for (i = 0; i < XmemMAX_TABLES; i++) {
509 msk = 1 << i;
510 if (! (tid & msk))
511 continue;
513 XmemGetTableDesc(msk, &longs, &nodes, &user);
514 if (! (nodes & me))
515 continue;
516 if (! (user & IN_SHMEM && user & ON_DISC))
517 continue;
519 sprintf(txt, "Reading table:%s id:%d from disc",
520 XmemGetTableName((XmemTableId)msk), (int)msk);
521 LogEvent(NULL, txt);
523 err = XmemReadTableFile(msk);
524 if (err == XmemErrorSUCCESS)
525 continue;
527 LogEvent(NULL, "WARNING: Failed to read table from disc");
533 * main - Xmem Daemon
535 * @param argc: argument counter
536 * @param char *argv[]: arguments' values
538 * The daemon initialises the segments (it can be a warm/cold start), then
539 * registers the callback handler, and waits in an infinite loop.
541 * @return if there's an error, main will exit with an appropriate error code.
543 int main(int argc, char *argv[])
545 XmemEventMask emsk;
546 XmemError err;
547 XmemMessage mes;
548 int warmst;
550 event_log = GetEventLogTable();
552 err = XmemInitialize(XmemDeviceANY);
553 if (err != XmemErrorSUCCESS) {
554 LogEvent(NULL, "Can't initialize library");
555 goto fatal;
558 XmemUnBlockCallbacks();
560 if (!event_log) {
561 LogEvent(NULL, "Can't get: EVENT_LOG shared memory segment");
562 goto fatal;
565 emsk = XmemEventMaskMASK;
566 /* subscribe the daemon to XmemEventMaskMASK */
567 err = XmemRegisterCallback(callback, emsk);
568 if (err != XmemErrorSUCCESS) {
569 LogEvent(NULL, "Can't register callback");
570 goto fatal;
573 warmst = XmemCheckForWarmStart();
574 if (warmst) {
575 LogEvent(NULL,"Warm Start: Begin ...");
576 /* Tell the world I exist */
577 mes.MessageType = XmemMessageTypeINITIALIZE_ME;
578 mes.Data = XmemInitMessageSEEN_BY;
579 XmemSendMessage(XmemALL_NODES, &mes);
580 /* ...it might be interesting to do this in a loop */
582 else {
583 LogEvent(NULL, "Cold Start: Initialize Tables: Begin ...");
584 /* For cold starts, read tables from disc */
585 __init_coldstart();
586 /*Tell the world to send me their tables and that I exist */
587 mes.MessageType = XmemMessageTypeINITIALIZE_ME;
588 mes.Data = XmemInitMessageRESET;
589 XmemSendMessage(XmemALL_NODES, &mes);
593 * ...start-up finished.
595 LogEvent(NULL, "XmemDaemon: Running OK");
598 * This is the infinite wait-loop of the daemon
600 while(1) {
601 if (VmicDaemonWait(1000)) {
602 XmemBlockCallbacks();
603 VmicDaemonCall();
605 XmemUnBlockCallbacks();
608 fatal:
609 LogEvent(NULL, "Fatal Error: Daemon Teminated");
610 exit((int)err);