pthreaded servers: set thread names
[openafs.git] / src / volser / volmain.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 #include <roken.h>
14
15 #ifdef AFS_NT40_ENV
16 #include <windows.h>
17 #include <WINNT/afsevent.h>
18 #endif
19
20 #include <rx/xdr.h>
21 #include <afs/afsint.h>
22 #include <afs/afs_assert.h>
23 #include <afs/prs_fs.h>
24 #include <afs/nfs.h>
25 #include <lwp.h>
26 #include <lock.h>
27 #include <afs/afssyscalls.h>
28 #include <afs/ihandle.h>
29 #ifdef AFS_NT40_ENV
30 #include <afs/ntops.h>
31 #endif
32 #include <afs/vnode.h>
33 #include <afs/volume.h>
34 #include <afs/partition.h>
35 #include <rx/rx.h>
36 #include <rx/rxstat.h>
37 #include <rx/rx_globals.h>
38 #include <afs/auth.h>
39 #include <afs/cellconfig.h>
40 #include <afs/keys.h>
41 #include <afs/dir.h>
42 #include <ubik.h>
43 #include <afs/audit.h>
44 #include <afs/afsutil.h>
45 #include <lwp.h>
46
47 #include "volser.h"
48 #include "volint.h"
49 #include "volser_internal.h"
50
51 /*@printflike@*/ extern void Log(const char *format, ...);
52 /*@printflike@*/ extern void Abort(const char *format, ...);
53
54 #define VolserVersion "2.0"
55 #define N_SECURITY_OBJECTS 3
56
57 extern struct Lock localLock;
58 char *GlobalNameHack = NULL;
59 int hackIsIn = 0;
60 afs_int32 GlobalVolCloneId, GlobalVolParentId;
61 int GlobalVolType;
62 int VolumeChanged;              /* XXXX */
63 static char busyFlags[MAXHELPERS];
64 struct volser_trans *QI_GlobalWriteTrans = 0;
65 struct afsconf_dir *tdir;
66 static afs_int32 runningCalls = 0;
67 int DoLogging = 0;
68 int debuglevel = 0;
69 #define MAXLWP 128
70 int lwps = 9;
71 int udpBufSize = 0;             /* UDP buffer size for receive */
72
73 int rxBind = 0;
74 int rxkadDisableDotCheck = 0;
75
76 #define ADDRSPERSITE 16         /* Same global is in rx/rx_user.c */
77 afs_uint32 SHostAddrs[ADDRSPERSITE];
78
79 #define VS_EXIT(code)  {                                          \
80                           osi_audit(VS_ExitEvent, code, AUD_END); \
81                           exit(code);                             \
82                        }
83
84 static void
85 MyBeforeProc(struct rx_call *acall)
86 {
87     VTRANS_LOCK;
88     runningCalls++;
89     VTRANS_UNLOCK;
90     return;
91 }
92
93 static void
94 MyAfterProc(struct rx_call *acall, afs_int32 code)
95 {
96     VTRANS_LOCK;
97     runningCalls--;
98     VTRANS_UNLOCK;
99     return;
100 }
101
102 /* Called every GCWAKEUP seconds to try to unlock all our partitions,
103  * if we're idle and there are no active transactions
104  */
105 static void
106 TryUnlock(void)
107 {
108     /* if there are no running calls, and there are no active transactions, then
109      * it should be safe to release any partition locks we've accumulated */
110     VTRANS_LOCK;
111     if (runningCalls == 0 && TransList() == (struct volser_trans *)0) {
112         VTRANS_UNLOCK;
113         VPFullUnlock();         /* in volprocs.c */
114     } else
115         VTRANS_UNLOCK;
116 }
117
118 /* background daemon for timing out transactions */
119 static void*
120 BKGLoop(void *unused)
121 {
122     struct timeval tv;
123     int loop = 0;
124
125     afs_pthread_setname_self("vol bkg");
126     while (1) {
127         tv.tv_sec = GCWAKEUP;
128         tv.tv_usec = 0;
129 #ifdef AFS_PTHREAD_ENV
130 #ifdef AFS_NT40_ENV
131         Sleep(GCWAKEUP * 1000);
132 #else
133         select(0, 0, 0, 0, &tv);
134 #endif
135 #else
136         (void)IOMGR_Select(0, 0, 0, 0, &tv);
137 #endif
138         GCTrans();
139         TryUnlock();
140         loop++;
141         if (loop == 10) {       /* reopen log every 5 minutes */
142             loop = 0;
143             ReOpenLog(AFSDIR_SERVER_VOLSERLOG_FILEPATH);
144         }
145     }
146
147     return NULL;
148 }
149
150 /* Background daemon for sleeping so the volserver does not become I/O bound */
151 afs_int32 TTsleep, TTrun;
152 #ifndef AFS_PTHREAD_ENV
153 static void *
154 BKGSleep(void *unused)
155 {
156     struct volser_trans *tt;
157
158     if (TTsleep) {
159         while (1) {
160 #ifdef AFS_PTHREAD_ENV
161             sleep(TTrun);
162 #else /* AFS_PTHREAD_ENV */
163             IOMGR_Sleep(TTrun);
164 #endif
165             VTRANS_LOCK;
166             for (tt = TransList(); tt; tt = tt->next) {
167                 VTRANS_OBJ_LOCK(tt);
168                 if ((strcmp(tt->lastProcName, "DeleteVolume") == 0)
169                     || (strcmp(tt->lastProcName, "Clone") == 0)
170                     || (strcmp(tt->lastProcName, "ReClone") == 0)
171                     || (strcmp(tt->lastProcName, "Forward") == 0)
172                     || (strcmp(tt->lastProcName, "Restore") == 0)
173                     || (strcmp(tt->lastProcName, "ForwardMulti") == 0)) {
174                     VTRANS_OBJ_UNLOCK(tt);
175                     break;
176                 }
177                 VTRANS_OBJ_UNLOCK(tt);
178             }
179             if (tt) {
180                 VTRANS_UNLOCK;
181                 sleep(TTsleep);
182             } else
183                 VTRANS_UNLOCK;
184         }
185     }
186     return NULL;
187 }
188 #endif
189
190 #ifdef AFS_NT40_ENV
191 /* no volser_syscall */
192 #elif defined(AFS_SUN511_ENV)
193 int
194 volser_syscall(afs_uint32 a3, afs_uint32 a4, void *a5)
195 {
196     int err, code;
197     code = ioctl_sun_afs_syscall(28 /* AFSCALL_CALL */, a3, a4, a5, 0, 0, 0,
198                                  &err);
199     if (code) {
200         err = code;
201     }
202     return err;
203 }
204 #else
205 int
206 volser_syscall(afs_uint32 a3, afs_uint32 a4, void *a5)
207 {
208     afs_uint32 rcode;
209 #ifndef AFS_LINUX20_ENV
210     void (*old) (int);
211
212     old = signal(SIGSYS, SIG_IGN);
213 #endif
214     rcode =
215         syscall(AFS_SYSCALL /* AFS_SYSCALL */ , 28 /* AFSCALL_CALL */ , a3,
216                 a4, a5);
217 #ifndef AFS_LINUX20_ENV
218     signal(SIGSYS, old);
219 #endif
220
221     return rcode;
222 }
223 #endif
224
225
226 /* check whether caller is authorized to manage RX statistics */
227 int
228 vol_rxstat_userok(struct rx_call *call)
229 {
230     return afsconf_SuperUser(tdir, call, NULL);
231 }
232
233 #include "AFS_component_version_number.c"
234 int
235 main(int argc, char **argv)
236 {
237     afs_int32 code;
238     struct rx_securityClass **securityClasses;
239     afs_int32 numClasses;
240     struct rx_service *service;
241     struct ktc_encryptionKey tkey;
242     int rxpackets = 100;
243     int rxJumbograms = 0;       /* default is to send and receive jumbograms. */
244     int rxMaxMTU = -1;
245     int bufSize = 0;            /* temp variable to read in udp socket buf size */
246     afs_uint32 host = ntohl(INADDR_ANY);
247     char *auditFileName = NULL;
248     VolumePackageOptions opts;
249
250 #ifdef  AFS_AIX32_ENV
251     /*
252      * The following signal action for AIX is necessary so that in case of a
253      * crash (i.e. core is generated) we can include the user's data section
254      * in the core dump. Unfortunately, by default, only a partial core is
255      * generated which, in many cases, isn't too useful.
256      */
257     struct sigaction nsa;
258
259     sigemptyset(&nsa.sa_mask);
260     nsa.sa_handler = SIG_DFL;
261     nsa.sa_flags = SA_FULLDUMP;
262     sigaction(SIGABRT, &nsa, NULL);
263     sigaction(SIGSEGV, &nsa, NULL);
264 #endif
265     osi_audit_init();
266     osi_audit(VS_StartEvent, 0, AUD_END);
267
268     /* Initialize dirpaths */
269     if (!(initAFSDirPath() & AFSDIR_SERVER_PATHS_OK)) {
270 #ifdef AFS_NT40_ENV
271         ReportErrorEventAlt(AFSEVT_SVR_NO_INSTALL_DIR, 0, argv[0], 0);
272 #endif
273         fprintf(stderr, "%s: Unable to obtain AFS server directory.\n",
274                 argv[0]);
275         exit(2);
276     }
277
278     TTsleep = TTrun = 0;
279
280     /* parse cmd line */
281     for (code = 1; code < argc; code++) {
282         if (strcmp(argv[code], "-log") == 0) {
283             /* set extra logging flag */
284             DoLogging = 1;
285         } else if (strcmp(argv[code], "-help") == 0) {
286             goto usage;
287         } else if (strcmp(argv[code], "-rxbind") == 0) {
288             rxBind = 1;
289         } else if (strcmp(argv[code], "-allow-dotted-principals") == 0) {
290             rxkadDisableDotCheck = 1;
291         } else if (strcmp(argv[code], "-d") == 0) {
292             if ((code + 1) >= argc) {
293                 fprintf(stderr, "missing argument for -d\n");
294                 return -1;
295             }
296             debuglevel = atoi(argv[++code]);
297             LogLevel = debuglevel;
298         } else if (strcmp(argv[code], "-p") == 0) {
299             lwps = atoi(argv[++code]);
300             if (lwps > MAXLWP) {
301                 printf("Warning: '-p %d' is too big; using %d instead\n",
302                        lwps, MAXLWP);
303                 lwps = MAXLWP;
304             }
305         } else if (strcmp(argv[code], "-auditlog") == 0) {
306             auditFileName = argv[++code];
307
308         } else if (strcmp(argv[code], "-audit-interface") == 0) {
309             char *interface = argv[++code];
310
311             if (osi_audit_interface(interface)) {
312                 printf("Invalid audit interface '%s'\n", interface);
313                 return -1;
314             }
315         } else if (strcmp(argv[code], "-nojumbo") == 0) {
316             rxJumbograms = 0;
317         } else if (strcmp(argv[code], "-jumbo") == 0) {
318             rxJumbograms = 1;
319         } else if (!strcmp(argv[code], "-rxmaxmtu")) {
320             if ((code + 1) >= argc) {
321                 fprintf(stderr, "missing argument for -rxmaxmtu\n");
322                 exit(1);
323             }
324             rxMaxMTU = atoi(argv[++code]);
325             if ((rxMaxMTU < RX_MIN_PACKET_SIZE) ||
326                 (rxMaxMTU > RX_MAX_PACKET_DATA_SIZE)) {
327                 printf("rxMaxMTU %d invalid; must be between %d-%" AFS_SIZET_FMT "\n",
328                        rxMaxMTU, RX_MIN_PACKET_SIZE,
329                        RX_MAX_PACKET_DATA_SIZE);
330                 exit(1);
331             }
332         } else if (strcmp(argv[code], "-sleep") == 0) {
333             sscanf(argv[++code], "%d/%d", &TTsleep, &TTrun);
334             if ((TTsleep < 0) || (TTrun <= 0)) {
335                 printf("Warning: '-sleep %d/%d' is incorrect; ignoring\n",
336                        TTsleep, TTrun);
337                 TTsleep = TTrun = 0;
338             }
339         } else if (strcmp(argv[code], "-udpsize") == 0) {
340             if ((code + 1) >= argc) {
341                 printf("You have to specify -udpsize <integer value>\n");
342                 exit(1);
343             }
344             sscanf(argv[++code], "%d", &bufSize);
345             if (bufSize < rx_GetMinUdpBufSize())
346                 printf
347                     ("Warning:udpsize %d is less than minimum %d; ignoring\n",
348                      bufSize, rx_GetMinUdpBufSize());
349             else
350                 udpBufSize = bufSize;
351         } else if (strcmp(argv[code], "-enable_peer_stats") == 0) {
352             rx_enablePeerRPCStats();
353         } else if (strcmp(argv[code], "-enable_process_stats") == 0) {
354             rx_enableProcessRPCStats();
355         }
356 #ifndef AFS_NT40_ENV
357         else if (strcmp(argv[code], "-syslog") == 0) {
358             /* set syslog logging flag */
359             serverLogSyslog = 1;
360         } else if (strncmp(argv[code], "-syslog=", 8) == 0) {
361             serverLogSyslog = 1;
362             serverLogSyslogFacility = atoi(argv[code] + 8);
363         }
364 #endif
365         else {
366             printf("volserver: unrecognized flag '%s'\n", argv[code]);
367           usage:
368 #ifndef AFS_NT40_ENV
369             printf("Usage: volserver [-log] [-p <number of processes>] "
370                    "[-auditlog <log path>] [-d <debug level>] "
371                    "[-nojumbo] [-jumbo] [-rxmaxmtu <bytes>] [-rxbind] [-allow-dotted-principals] "
372                    "[-udpsize <size of socket buffer in bytes>] "
373                    "[-syslog[=FACILITY]] "
374                    "[-enable_peer_stats] [-enable_process_stats] "
375                    "[-help]\n");
376 #else
377             printf("Usage: volserver [-log] [-p <number of processes>] "
378                    "[-auditlog <log path>] [-d <debug level>] "
379                    "[-nojumbo] [-jumbo] [-rxmaxmtu <bytes>] [-rxbind] [-allow-dotted-principals] "
380                    "[-udpsize <size of socket buffer in bytes>] "
381                    "[-enable_peer_stats] [-enable_process_stats] "
382                    "[-help]\n");
383 #endif
384             VS_EXIT(1);
385         }
386     }
387
388     if (auditFileName) {
389         osi_audit_file(auditFileName);
390         osi_audit(VS_StartEvent, 0, AUD_END);
391     }
392 #ifdef AFS_SGI_VNODE_GLUE
393     if (afs_init_kernel_config(-1) < 0) {
394         printf
395             ("Can't determine NUMA configuration, not starting volserver.\n");
396         exit(1);
397     }
398 #endif
399     InitErrTabs();
400
401 #ifdef AFS_PTHREAD_ENV
402     SetLogThreadNumProgram( rx_GetThreadNum );
403 #endif
404
405 #ifdef AFS_NT40_ENV
406     if (afs_winsockInit() < 0) {
407         ReportErrorEventAlt(AFSEVT_SVR_WINSOCK_INIT_FAILED, 0, argv[0], 0);
408         printf("Volume server unable to start winsock, exiting.\n");
409         exit(1);
410     }
411 #endif
412     /* Open VolserLog and map stdout, stderr into it; VInitVolumePackage2 can
413        log, so we need to do this here */
414     OpenLog(AFSDIR_SERVER_VOLSERLOG_FILEPATH);
415
416     VOptDefaults(volumeServer, &opts);
417     if (VInitVolumePackage2(volumeServer, &opts)) {
418         Log("Shutting down: errors encountered initializing volume package\n");
419         exit(1);
420     }
421     /* For nuke() */
422     Lock_Init(&localLock);
423     DInit(40);
424 #ifndef AFS_PTHREAD_ENV
425     vol_PollProc = IOMGR_Poll;  /* tell vol pkg to poll io system periodically */
426 #endif
427 #ifndef AFS_NT40_ENV
428     rxi_syscallp = volser_syscall;
429 #endif
430     rx_nPackets = rxpackets;    /* set the max number of packets */
431     if (udpBufSize)
432         rx_SetUdpBufSize(udpBufSize);   /* set the UDP buffer size for receive */
433     if (rxBind) {
434         afs_int32 ccode;
435         if (AFSDIR_SERVER_NETRESTRICT_FILEPATH ||
436             AFSDIR_SERVER_NETINFO_FILEPATH) {
437             char reason[1024];
438             ccode = parseNetFiles(SHostAddrs, NULL, NULL,
439                                            ADDRSPERSITE, reason,
440                                            AFSDIR_SERVER_NETINFO_FILEPATH,
441                                            AFSDIR_SERVER_NETRESTRICT_FILEPATH);
442         } else
443         {
444             ccode = rx_getAllAddr(SHostAddrs, ADDRSPERSITE);
445         }
446         if (ccode == 1)
447             host = SHostAddrs[0];
448     }
449
450     code = rx_InitHost(host, (int)htons(AFSCONF_VOLUMEPORT));
451     if (code) {
452         fprintf(stderr, "rx init failed on socket AFSCONF_VOLUMEPORT %u\n",
453                 AFSCONF_VOLUMEPORT);
454         VS_EXIT(1);
455     }
456     if (!rxJumbograms) {
457         /* Don't allow 3.4 vos clients to send jumbograms and we don't send. */
458         rx_SetNoJumbo();
459     }
460     if (rxMaxMTU != -1) {
461         rx_SetMaxMTU(rxMaxMTU);
462     }
463     rx_GetIFInfo();
464     rx_SetRxDeadTime(420);
465     memset(busyFlags, 0, sizeof(busyFlags));
466
467     SetupLogSignals();
468
469     {
470 #ifdef AFS_PTHREAD_ENV
471         pthread_t tid;
472         pthread_attr_t tattr;
473         osi_Assert(pthread_attr_init(&tattr) == 0);
474         osi_Assert(pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED) == 0);
475
476         osi_Assert(pthread_create(&tid, &tattr, BKGLoop, NULL) == 0);
477 #else
478         PROCESS pid;
479         LWP_CreateProcess(BKGLoop, 16*1024, 3, 0, "vol bkg daemon", &pid);
480         LWP_CreateProcess(BKGSleep,16*1024, 3, 0, "vol slp daemon", &pid);
481 #endif
482     }
483
484     /* Create a single security object, in this case the null security object, for unauthenticated connections, which will be used to control security on connections made to this server */
485
486     tdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
487     if (!tdir) {
488         Abort("volser: could not open conf files in %s\n",
489               AFSDIR_SERVER_ETC_DIRPATH);
490         VS_EXIT(1);
491     }
492     afsconf_GetKey(tdir, 999, &tkey);
493     afsconf_BuildServerSecurityObjects(tdir, &securityClasses, &numClasses);
494     if (securityClasses[0] == NULL)
495         Abort("rxnull_NewServerSecurityObject");
496     service =
497         rx_NewServiceHost(host, 0, VOLSERVICE_ID, "VOLSER", securityClasses,
498                           numClasses, AFSVolExecuteRequest);
499     if (service == (struct rx_service *)0)
500         Abort("rx_NewService");
501     rx_SetBeforeProc(service, MyBeforeProc);
502     rx_SetAfterProc(service, MyAfterProc);
503     rx_SetIdleDeadTime(service, 0);     /* never timeout */
504     if (lwps < 4)
505         lwps = 4;
506     rx_SetMaxProcs(service, lwps);
507 #if defined(AFS_XBSD_ENV)
508     rx_SetStackSize(service, (128 * 1024));
509 #elif defined(AFS_SGI_ENV)
510     rx_SetStackSize(service, (48 * 1024));
511 #else
512     rx_SetStackSize(service, (32 * 1024));
513 #endif
514
515     if (rxkadDisableDotCheck) {
516         rx_SetSecurityConfiguration(service, RXS_CONFIG_FLAGS,
517                                     (void *)RXS_CONFIG_FLAGS_DISABLE_DOTCHECK);
518     }
519
520     service =
521         rx_NewService(0, RX_STATS_SERVICE_ID, "rpcstats", securityClasses,
522                       numClasses, RXSTATS_ExecuteRequest);
523     if (service == (struct rx_service *)0)
524         Abort("rx_NewService");
525     rx_SetMinProcs(service, 2);
526     rx_SetMaxProcs(service, 4);
527
528     LogCommandLine(argc, argv, "Volserver", VolserVersion, "Starting AFS",
529                    Log);
530     if (TTsleep) {
531         Log("Will sleep %d second%s every %d second%s\n", TTsleep,
532             (TTsleep > 1) ? "s" : "", TTrun + TTsleep,
533             (TTrun + TTsleep > 1) ? "s" : "");
534     }
535
536     /* allow super users to manage RX statistics */
537     rx_SetRxStatUserOk(vol_rxstat_userok);
538
539     rx_StartServer(1);          /* Donate this process to the server process pool */
540
541     osi_audit(VS_FinishEvent, (-1), AUD_END);
542     Abort("StartServer returned?");
543     return 0; /* not reached */
544 }