nfs-ganesha 1.4
|
00001 /* 00002 * vim:expandtab:shiftwidth=8:tabstop=8: 00003 * 00004 * Copyright CEA/DAM/DIF (2008) 00005 * contributeur : Philippe DENIEL philippe.deniel@cea.fr 00006 * Thomas LEIBOVICI thomas.leibovici@cea.fr 00007 * 00008 * This program is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Lesser General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 3 of the License, or (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Lesser General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License along with this library; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 * 00022 * --------------------------------------- 00023 */ 00024 00036 #ifdef HAVE_CONFIG_H 00037 #include "config.h" 00038 #endif 00039 00040 #ifdef _SOLARIS 00041 #include "solaris_port.h" 00042 #endif 00043 00044 #include <stdio.h> 00045 #include <string.h> 00046 #include <pthread.h> 00047 #include <sys/stat.h> 00048 #include <time.h> 00049 #include <stdlib.h> 00050 #include <unistd.h> 00051 #include <errno.h> 00052 #include <sys/types.h> 00053 #include <sys/socket.h> 00054 #include <netinet/in.h> 00055 #include <netdb.h> 00056 #include <arpa/inet.h> 00057 #include <sys/wait.h> 00058 #include <signal.h> 00059 #include "nfs_core.h" 00060 #include "nfs_stat.h" 00061 #include "nfs_exports.h" 00062 #include "nodelist.h" 00063 #include "fsal.h" 00064 #include "ganesha_rpc.h" 00065 #include "abstract_mem.h" 00066 00067 #define DEFAULT_PORT "10401" 00068 00069 #define BACKLOG 10 00070 00071 #define CONF_STAT_EXPORTER_LABEL "STAT_EXPORTER" 00072 #define STRCMP strcasecmp 00073 00074 /* Make sure this is <= the same macro in support/exports.c */ 00075 #define EXPORT_MAX_CLIENTS 20 00076 #define EXPORT_MAX_CLIENTLEN 256 /* client name len */ 00077 00078 int stat_export_check_access(struct sockaddr_storage *pssaddr, 00079 exportlist_client_t *clients, 00080 exportlist_client_entry_t * pclient_found) 00081 { 00082 sockaddr_t *psockaddr_in; 00083 #ifdef _USE_TIRPC_IPV6 00084 struct sockaddr_in6 *psockaddr_in6; 00085 static char ten_bytes_all_0[10]; 00086 static unsigned two_bytes_all_1 = 0xFFFF; 00087 char ip6string[MAXHOSTNAMELEN]; 00088 memset(ten_bytes_all_0, 0, 10); 00089 #endif 00090 char ipstring[SOCK_NAME_MAX]; 00091 00092 psockaddr_in = (sockaddr_t *)pssaddr; 00093 00094 /* For now, no matching client is found */ 00095 memset(pclient_found, 0, sizeof(exportlist_client_entry_t)); 00096 00097 #ifdef _USE_TIPRC_IPV6 00098 if(psockaddr_in->sin_family == AF_INET) 00099 { 00100 #endif /* _USE_TIRPC_IPV6 */ 00101 /* Convert IP address into a string for wild character access checks. */ 00102 sprint_sockip(psockaddr_in, ipstring, sizeof(ipstring)); 00103 if(ipstring == NULL) 00104 { 00105 LogCrit(COMPONENT_MAIN, 00106 "Stat Export Check Access: Could not convert the IPv4 address to a character string."); 00107 return FALSE; 00108 } 00109 if(export_client_match 00110 (psockaddr_in, ipstring, clients, pclient_found, EXPORT_OPTION_READ_ACCESS | EXPORT_OPTION_WRITE_ACCESS)) 00111 return TRUE; 00112 #ifdef _USE_TIRPC_IPV6 00113 } 00114 else 00115 { 00116 psockaddr_in6 = (struct sockaddr_in6 *)pssaddr; 00117 if(isFulldebug(COMPONENT_MAIN)) 00118 { 00119 char txtaddrv6[100]; 00120 00121 inet_ntop(psockaddr_in6->sin6_family, 00122 psockaddr_in6->sin6_addr.s6_addr, txtaddrv6, 100); 00123 LogFullDebug(COMPONENT_MAIN, 00124 "Client has IPv6 adress = %s", txtaddrv6); 00125 } 00126 /* If the client socket is IPv4, then it is wrapped into a ::ffff:a.b.c.d IPv6 address. We check this here 00127 * This kind of adress is shaped like this: 00128 * |---------------------------------------------------------------| 00129 * | 80 bits = 10 bytes | 16 bits = 2 bytes | 32 bits = 4 bytes | 00130 * |---------------------------------------------------------------| 00131 * | 0 | FFFF | IPv4 address | 00132 * |---------------------------------------------------------------| */ 00133 if(!memcmp(psockaddr_in6->sin6_addr.s6_addr, ten_bytes_all_0, 10) && 00134 !memcmp((char *)(psockaddr_in6->sin6_addr.s6_addr + 10), 00135 (char *)&two_bytes_all_1, 2)) 00136 { 00137 /* Convert IP address into a string for wild character access checks. */ 00138 inet_ntop(psockaddr_in->sin6_family, &psockaddr_in->sin6_addr, 00139 ip6string, INET6_ADDRSTRLEN); 00140 if(ip6string == NULL) 00141 { 00142 LogCrit(COMPONENT_MAIN, 00143 "Error: Could not convert the IPv6 address to a character string."); 00144 return FALSE; 00145 } 00146 /* This is an IPv4 address mapped to an IPv6 one. Extract the IPv4 address and proceed with IPv4 autentication */ 00147 memcpy((char *)&addr, (char *)(psockaddr_in6->sin6_addr.s6_addr + 12), 4); 00148 00149 /* Proceed with IPv4 dedicated function */ 00150 /* else, check if any access only export matches this client */ 00151 if(export_client_match 00152 (addr, ip6string, clients, pclient_found, EXPORT_OPTION_READ_ACCESS | EXPORT_OPTION_WRITE_ACCESS)) 00153 return TRUE; 00154 } 00155 if(export_client_matchv6 00156 (&(psockaddr_in6->sin6_addr), clients, pclient_found, EXPORT_OPTION_READ_ACCESS | EXPORT_OPTION_WRITE_ACCESS)) 00157 return TRUE; 00158 } 00159 #endif /* _USE_TIRPC_IPV6 */ 00160 /* If this point is reached, no matching entry was found */ 00161 return FALSE; 00162 00163 } /* stat_export_check_access */ 00164 00165 static int parseAccessParam_for_statexporter(char *var_name, char *var_value, 00166 exportlist_client_t *clients) 00167 { 00168 int rc = 0, err_flag __attribute__((unused)) = FALSE; 00169 char *expended_node_list; 00170 00171 /* temp array of clients */ 00172 char *client_list[EXPORT_MAX_CLIENTS]; 00173 int idx; 00174 int count; 00175 00176 /* expends host[n-m] notations */ 00177 count = 00178 nodelist_common_condensed2extended_nodelist(var_value, &expended_node_list); 00179 00180 if(count <= 0) 00181 { 00182 err_flag = TRUE; 00183 LogCrit(COMPONENT_CONFIG, 00184 "STAT_EXPORT_ACCESS: ERROR: Invalid format for client list in EXPORT::%s definition", 00185 var_name); 00186 00187 return -1; 00188 } 00189 else if(count > EXPORT_MAX_CLIENTS) 00190 { 00191 err_flag = TRUE; 00192 LogCrit(COMPONENT_CONFIG, 00193 "STAT_EXPORT_ACCESS: ERROR: Client list too long (%d>%d)", 00194 count, EXPORT_MAX_CLIENTS); 00195 return -1; 00196 } 00197 00198 /* allocate clients strings */ 00199 for(idx = 0; idx < count; idx++) 00200 { 00201 client_list[idx] = gsh_malloc(EXPORT_MAX_CLIENTLEN); 00202 client_list[idx][0] = '\0'; 00203 } 00204 00205 /* 00206 * Search for coma-separated list of hosts, networks and netgroups 00207 */ 00208 rc = nfs_ParseConfLine(client_list, count, 00209 expended_node_list, find_comma, find_endLine); 00210 00211 /* free the buffer the nodelist module has allocated */ 00212 free(expended_node_list); 00213 00214 if(rc < 0) 00215 { 00216 err_flag = TRUE; 00217 LogCrit(COMPONENT_CONFIG, 00218 "STAT_EXPORT_ACCESS: ERROR: Client list too long (>%d)", count); 00219 00220 /* free client strings */ 00221 for(idx = 0; idx < count; idx++) 00222 gsh_free(client_list[idx]); 00223 00224 return rc; 00225 } 00226 00227 rc = nfs_AddClientsToClientArray( clients, rc, 00228 (char **)client_list, EXPORT_OPTION_READ_ACCESS | EXPORT_OPTION_WRITE_ACCESS); 00229 if(rc != 0) 00230 { 00231 err_flag = TRUE; 00232 LogCrit(COMPONENT_CONFIG, 00233 "STAT_EXPORT_ACCESS: ERROR: Invalid client found in \"%s\"", 00234 var_value); 00235 00236 /* free client strings */ 00237 for(idx = 0; idx < count; idx++) 00238 gsh_free(client_list[idx]); 00239 00240 return rc; 00241 } 00242 00243 /* everything is OK */ 00244 00245 /* free client strings */ 00246 for(idx = 0; idx < count; idx++) 00247 gsh_free(client_list[idx]); 00248 00249 return rc; 00250 } 00251 00252 00253 int get_stat_exporter_conf(config_file_t in_config, external_tools_parameter_t * out_parameter) 00254 { 00255 int err; 00256 int var_max, var_index; 00257 char *key_name; 00258 char *key_value; 00259 config_item_t block; 00260 config_item_t item; 00261 00262 strncpy(out_parameter->stat_export.export_stat_port, DEFAULT_PORT, MAXPORTLEN); 00263 00264 /* Get the config BLOCK */ 00265 if((block = config_FindItemByName(in_config, CONF_STAT_EXPORTER_LABEL)) == NULL) 00266 { 00267 /* cannot read item */ 00268 LogCrit(COMPONENT_CONFIG, 00269 "STAT_EXPORTER: Cannot read item \"%s\" from configuration file", 00270 CONF_STAT_EXPORTER_LABEL); 00271 /* Expected to be a block */ 00272 return ENOENT; 00273 } 00274 else if(config_ItemType(block) != CONFIG_ITEM_BLOCK) 00275 { 00276 LogCrit(COMPONENT_CONFIG, 00277 "STAT_EXPORTER: Cannot read item \"%s\" from configuration file", 00278 CONF_STAT_EXPORTER_LABEL); 00279 /* Expected to be a block */ 00280 return ENOENT; 00281 } 00282 00283 /* makes an iteration on the (key, value) couplets */ 00284 var_max = config_GetNbItems(block); 00285 00286 for(var_index = 0; var_index < var_max; var_index++) 00287 { 00288 /* retrieve key's name */ 00289 item = config_GetItemByIndex(block, var_index); 00290 err = config_GetKeyValue(item, &key_name, &key_value); 00291 00292 if(err) 00293 { 00294 LogCrit(COMPONENT_CONFIG, 00295 "STAT_EXPORTER: ERROR reading key[%d] from section \"%s\" of configuration file.", 00296 var_index, CONF_LABEL_FS_SPECIFIC); 00297 return err; 00298 } 00299 00300 if(!STRCMP(key_name, "Access")) 00301 { 00302 parseAccessParam_for_statexporter(key_name, key_value, 00303 &(out_parameter->stat_export.allowed_clients)); 00304 } 00305 else if(!STRCMP(key_name, "Port")) 00306 { 00307 strncpy(out_parameter->stat_export.export_stat_port, key_value, MAXPORTLEN); 00308 } 00309 else 00310 { 00311 LogCrit(COMPONENT_CONFIG, 00312 "STAT_EXPORTER LOAD PARAMETER: ERROR: Unknown or unsettable key: %s (item %s)", 00313 key_name, CONF_LABEL_FS_SPECIFIC); 00314 return EINVAL; 00315 } 00316 } 00317 return 0; 00318 } 00319 00320 int merge_stats(nfs_request_stat_item_t *global_stat_items, 00321 nfs_request_stat_item_t **workers_stat_items, int function_index, int detail_flag) 00322 { 00323 int rc = ERR_STAT_NO_ERROR; 00324 unsigned int i = 0; 00325 00326 for(i = 0; i < nfs_param.core_param.nb_worker; i++) 00327 { 00328 if(i == 0) 00329 { 00330 global_stat_items[function_index].total = 00331 workers_stat_items[i][function_index].total; 00332 global_stat_items[function_index].success = 00333 workers_stat_items[i][function_index].success; 00334 global_stat_items[function_index].dropped = 00335 workers_stat_items[i][function_index].dropped; 00336 global_stat_items[function_index].tot_latency = 00337 workers_stat_items[i][function_index].tot_latency; 00338 global_stat_items[function_index].min_latency = 00339 workers_stat_items[i][function_index].min_latency; 00340 global_stat_items[function_index].max_latency = 00341 workers_stat_items[i][function_index].max_latency; 00342 if(detail_flag) 00343 { 00344 global_stat_items[function_index].tot_await_time = 00345 workers_stat_items[i][function_index].tot_await_time; 00346 } 00347 } 00348 else 00349 { 00350 global_stat_items[function_index].total += 00351 workers_stat_items[i][function_index].total; 00352 global_stat_items[function_index].success += 00353 workers_stat_items[i][function_index].success; 00354 global_stat_items[function_index].dropped += 00355 workers_stat_items[i][function_index].dropped; 00356 global_stat_items[function_index].tot_latency += 00357 workers_stat_items[i][function_index].tot_latency; 00358 set_min_latency(&(global_stat_items[function_index]), 00359 workers_stat_items[i][function_index].min_latency); 00360 set_max_latency(&(global_stat_items[function_index]), 00361 workers_stat_items[i][function_index].max_latency); 00362 if(detail_flag) 00363 { 00364 global_stat_items[function_index].tot_await_time += 00365 workers_stat_items[i][function_index].tot_await_time; 00366 } 00367 } 00368 } 00369 00370 return rc; 00371 } 00372 00373 int write_stats(char *stat_buf, int num_cmds, char **function_names, nfs_request_stat_item_t *global_stat_items, int detail_flag) 00374 { 00375 int rc = ERR_STAT_NO_ERROR; 00376 00377 char *offset = NULL; 00378 unsigned int i = 0; 00379 unsigned int tot_calls =0, tot_latency = 0; 00380 unsigned int tot_await_time = 0; 00381 float tot_latency_ms = 0; 00382 float tot_await_time_ms = 0; 00383 char *name = NULL; 00384 char *ver __attribute__((unused)) = NULL; 00385 char *call = NULL; 00386 char *saveptr = NULL; 00387 00388 offset = stat_buf; 00389 for(i = 0; i < num_cmds; i++) 00390 { 00391 tot_calls = global_stat_items[i].total; 00392 tot_latency = global_stat_items[i].tot_latency; 00393 tot_latency_ms = (float)((float)tot_latency / (float)1000); 00394 if(detail_flag) 00395 { 00396 tot_await_time = global_stat_items[i].tot_await_time; 00397 tot_await_time_ms = (float)((float)tot_await_time / (float)1000); 00398 } 00399 00400 /* Extract call name from function name. */ 00401 name = strdup(function_names[i]); 00402 ver = strtok_r(name, "_", &saveptr); 00403 call = strtok_r(NULL, "_", &saveptr); 00404 00405 if(detail_flag) 00406 sprintf(offset, "_%s_ %u %.2f %.2f", call, tot_calls, tot_latency_ms, tot_await_time_ms); 00407 else 00408 sprintf(offset, "_%s_ %u %.2f", call, tot_calls, tot_latency_ms); 00409 offset += strlen(stat_buf); 00410 if(i != num_cmds - 1) 00411 { 00412 sprintf(offset, "%s", " "); 00413 offset += 1; 00414 } 00415 00416 free(name); 00417 } 00418 00419 return rc; 00420 } 00421 00422 int merge_nfs_stats_by_share(char *stat_buf, nfs_stat_client_req_t *stat_client_req, 00423 nfs_worker_stat_t *global_data, 00424 nfs_worker_stat_t *workers_stat) 00425 { 00426 int rc = ERR_STAT_NO_ERROR; 00427 00428 unsigned int i = 0; 00429 unsigned int num_cmds = 0; 00430 nfs_request_stat_item_t *global_stat_items = NULL; 00431 nfs_request_stat_item_t *workers_stat_items[nfs_param.core_param.nb_worker]; 00432 char **function_names = NULL; 00433 00434 switch(stat_client_req->nfs_version) 00435 { 00436 case 2: 00437 num_cmds = NFS_V2_NB_COMMAND; 00438 global_stat_items = (global_data->stat_req.stat_req_nfs2); 00439 for(i = 0; i < nfs_param.core_param.nb_worker; i++) 00440 { 00441 workers_stat_items[i] = (workers_stat[i].stat_req.stat_req_nfs2); 00442 } 00443 function_names = nfsv2_function_names; 00444 break; 00445 00446 case 3: 00447 num_cmds = NFS_V3_NB_COMMAND; 00448 global_stat_items = (global_data->stat_req.stat_req_nfs3); 00449 for(i = 0; i < nfs_param.core_param.nb_worker; i++) 00450 { 00451 workers_stat_items[i] = (workers_stat[i].stat_req.stat_req_nfs3); 00452 } 00453 function_names = nfsv3_function_names; 00454 break; 00455 00456 case 4: 00457 num_cmds = NFS_V4_NB_COMMAND; 00458 global_stat_items = (global_data->stat_req.stat_req_nfs4); 00459 for(i = 0; i < nfs_param.core_param.nb_worker; i++) 00460 { 00461 workers_stat_items[i] = (workers_stat[i].stat_req.stat_req_nfs4); 00462 } 00463 function_names = nfsv4_function_names; 00464 break; 00465 00466 default: 00467 // TODO: Invalid NFS version handling 00468 LogCrit(COMPONENT_MAIN, "Error: Invalid NFS version."); 00469 break; 00470 } 00471 00472 switch(stat_client_req->stat_type) 00473 { 00474 case PER_SERVER: 00475 case PER_SHARE: 00476 for(i = 0; i < num_cmds; i++) 00477 { 00478 rc = merge_stats(global_stat_items, workers_stat_items, i, 0); 00479 } 00480 rc = write_stats(stat_buf, num_cmds, function_names, global_stat_items, 0); 00481 break; 00482 00483 case PER_SERVER_DETAIL: 00484 case PER_SHARE_DETAIL: 00485 for(i = 0; i < num_cmds; i++) 00486 { 00487 rc = merge_stats(global_stat_items, workers_stat_items, i, 1); 00488 } 00489 rc = write_stats(stat_buf, num_cmds, function_names, global_stat_items, 1); 00490 break; 00491 00492 case PER_CLIENT: 00493 break; 00494 00495 case PER_CLIENTSHARE: 00496 break; 00497 00498 default: 00499 // TODO: Invalid stat type handling 00500 LogCrit(COMPONENT_MAIN, "Error: Invalid stat type."); 00501 break; 00502 } 00503 00504 return rc; 00505 } 00506 00507 00508 int merge_nfs_stats(char *stat_buf, nfs_stat_client_req_t *stat_client_req, 00509 nfs_worker_stat_t *global_data, nfs_worker_data_t *workers_data) 00510 { 00511 int rc = ERR_STAT_NO_ERROR; 00512 00513 unsigned int i = 0; 00514 unsigned int num_cmds = 0; 00515 nfs_request_stat_item_t *global_stat_items = NULL; 00516 nfs_request_stat_item_t *workers_stat_items[nfs_param.core_param.nb_worker]; 00517 char **function_names = NULL; 00518 00519 switch(stat_client_req->nfs_version) 00520 { 00521 case 2: 00522 num_cmds = NFS_V2_NB_COMMAND; 00523 global_stat_items = (global_data->stat_req.stat_req_nfs2); 00524 for(i = 0; i < nfs_param.core_param.nb_worker; i++) 00525 { 00526 workers_stat_items[i] = (workers_data[i].stats.stat_req.stat_req_nfs2); 00527 } 00528 function_names = nfsv2_function_names; 00529 break; 00530 00531 case 3: 00532 num_cmds = NFS_V3_NB_COMMAND; 00533 global_stat_items = (global_data->stat_req.stat_req_nfs3); 00534 for(i = 0; i < nfs_param.core_param.nb_worker; i++) 00535 { 00536 workers_stat_items[i] = (workers_data[i].stats.stat_req.stat_req_nfs3); 00537 } 00538 function_names = nfsv3_function_names; 00539 break; 00540 00541 case 4: 00542 num_cmds = NFS_V4_NB_COMMAND; 00543 global_stat_items = (global_data->stat_req.stat_req_nfs4); 00544 for(i = 0; i < nfs_param.core_param.nb_worker; i++) 00545 { 00546 workers_stat_items[i] = (workers_data[i].stats.stat_req.stat_req_nfs4); 00547 } 00548 function_names = nfsv4_function_names; 00549 break; 00550 00551 default: 00552 // TODO: Invalid NFS version handling 00553 LogCrit(COMPONENT_MAIN, "Error: Invalid NFS version."); 00554 break; 00555 } 00556 00557 switch(stat_client_req->stat_type) 00558 { 00559 case PER_SERVER: 00560 case PER_SHARE: 00561 for(i = 0; i < num_cmds; i++) 00562 { 00563 rc = merge_stats(global_stat_items, workers_stat_items, i, 0); 00564 } 00565 rc = write_stats(stat_buf, num_cmds, function_names, global_stat_items, 0); 00566 break; 00567 00568 case PER_SERVER_DETAIL: 00569 case PER_SHARE_DETAIL: 00570 for(i = 0; i < num_cmds; i++) 00571 { 00572 rc = merge_stats(global_stat_items, workers_stat_items, i, 1); 00573 } 00574 rc = write_stats(stat_buf, num_cmds, function_names, global_stat_items, 1); 00575 break; 00576 00577 case PER_CLIENT: 00578 break; 00579 00580 case PER_CLIENTSHARE: 00581 break; 00582 00583 default: 00584 // TODO: Invalid stat type handling 00585 LogCrit(COMPONENT_MAIN, "Error: Invalid stat type."); 00586 break; 00587 } 00588 00589 return rc; 00590 } 00591 00592 int process_stat_request(int new_fd) 00593 { 00594 int rc = ERR_STAT_NO_ERROR; 00595 00596 char cmd_buf[4096]; 00597 00598 char stat_buf[4096]; 00599 char *token = NULL; 00600 char *key = NULL; 00601 char *value = NULL; 00602 char *saveptr1 = NULL; 00603 char *saveptr2 = NULL; 00604 00605 exportlist_t *pexport = NULL; 00606 00607 nfs_worker_stat_t global_worker_stat; 00608 nfs_stat_client_req_t stat_client_req; 00609 memset(&stat_client_req, 0, sizeof(nfs_stat_client_req_t)); 00610 memset(cmd_buf, 0, 4096); 00611 00612 if((rc = recv(new_fd, cmd_buf, 4096, 0)) == -1) 00613 LogError(COMPONENT_MAIN, ERR_SYS, errno, rc); 00614 00615 /* Parse command options. */ 00616 token = strtok_r(cmd_buf, ",", &saveptr1); 00617 while(token != NULL) 00618 { 00619 key = strtok_r(token, "=", &saveptr2); 00620 value = strtok_r(NULL, "=", &saveptr2); 00621 00622 if(key != NULL && value != NULL) 00623 { 00624 if(strcmp(key, "version") == 0) 00625 { 00626 stat_client_req.nfs_version = atoi(value); 00627 } 00628 else if(strcmp(key, "type") == 0) 00629 { 00630 if(strcmp(value, "all") == 0) 00631 { 00632 stat_client_req.stat_type = PER_SERVER; 00633 } 00634 else if(strcmp(value, "all_detail") == 0) 00635 { 00636 stat_client_req.stat_type = PER_SERVER_DETAIL; 00637 } 00638 else if(strcmp(value, "share") == 0) 00639 { 00640 stat_client_req.stat_type = PER_SHARE; 00641 } 00642 else if(strcmp(value, "share_detail") == 0) 00643 { 00644 stat_client_req.stat_type = PER_SHARE_DETAIL; 00645 } 00646 } 00647 else if(strcmp(key, "path") == 0) 00648 { 00649 strcpy(stat_client_req.share_path, value); 00650 } 00651 } 00652 00653 token = strtok_r(NULL, ",", &saveptr1); 00654 } 00655 00656 memset(stat_buf, 0, 4096); 00657 00658 if(stat_client_req.stat_type == PER_SHARE || 00659 stat_client_req.stat_type == PER_SHARE_DETAIL) 00660 { 00661 LogDebug(COMPONENT_MAIN, "share path %s", 00662 stat_client_req.share_path); 00663 00664 // Get export entry 00665 pexport = GetExportEntry(stat_client_req.share_path); 00666 if(!pexport) 00667 { 00668 LogEvent(COMPONENT_MAIN, "Invalid export, discard stat request"); 00669 goto exit; 00670 } 00671 else 00672 LogDebug(COMPONENT_MAIN, "Got export entry, pexport %p", pexport); 00673 00674 merge_nfs_stats_by_share(stat_buf, &stat_client_req, &global_worker_stat, 00675 pexport->worker_stats); 00676 } 00677 else 00678 { 00679 merge_nfs_stats(stat_buf, &stat_client_req, &global_worker_stat, 00680 workers_data); 00681 } 00682 00683 if((rc = send(new_fd, stat_buf, 4096, 0)) == -1) 00684 LogError(COMPONENT_MAIN, ERR_SYS, errno, rc); 00685 00686 exit: 00687 close(new_fd); 00688 00689 return rc; 00690 } 00691 00692 int check_permissions() { 00693 return 0; 00694 } 00695 00696 void *stat_exporter_thread(void *UnusedArg) 00697 { 00698 int sockfd, new_fd; 00699 struct addrinfo hints, *servinfo, *p; 00700 struct sockaddr_storage their_addr; 00701 socklen_t sin_size; 00702 int yes = 1; 00703 char s[INET6_ADDRSTRLEN]; 00704 int rc; 00705 exportlist_client_entry_t pclient_found; 00706 00707 SetNameFunction("statistics_exporter"); 00708 00709 memset(&hints, 0, sizeof hints); 00710 00711 #ifndef _USE_TIRPC_IPV6 00712 hints.ai_family = AF_INET; 00713 #else 00714 hints.ai_family = AF_INET6; 00715 #endif 00716 hints.ai_socktype = SOCK_STREAM; 00717 hints.ai_flags = AI_PASSIVE; 00718 00719 if((rc = getaddrinfo(NULL, nfs_param.extern_param.stat_export.export_stat_port, &hints, &servinfo)) != 0) 00720 { 00721 LogCrit(COMPONENT_MAIN, "getaddrinfo: %s", gai_strerror(rc)); 00722 return NULL; 00723 } 00724 for(p = servinfo; p != NULL; p = p->ai_next) 00725 { 00726 if((sockfd = socket(p->ai_family, p->ai_socktype, 00727 p->ai_protocol)) == -1) 00728 { 00729 LogError(COMPONENT_MAIN, ERR_SYS, errno, sockfd); 00730 continue; 00731 } 00732 00733 if((rc = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, 00734 sizeof(int))) == -1) 00735 { 00736 LogError(COMPONENT_MAIN, ERR_SYS, errno, rc); 00737 freeaddrinfo(servinfo); 00738 return NULL; 00739 } 00740 00741 if((rc = bind(sockfd, p->ai_addr, p->ai_addrlen)) == -1) 00742 { 00743 close(sockfd); 00744 LogError(COMPONENT_MAIN, ERR_SYS, errno, rc); 00745 continue; 00746 } 00747 00748 break; 00749 } 00750 00751 if(p == NULL) 00752 { 00753 LogCrit(COMPONENT_MAIN, "server: failed to bind"); 00754 freeaddrinfo(servinfo); 00755 return NULL; 00756 } 00757 00758 freeaddrinfo(servinfo); 00759 if((rc = listen(sockfd, BACKLOG)) == -1) 00760 { 00761 LogError(COMPONENT_MAIN, ERR_SYS, errno, rc); 00762 return NULL; 00763 } 00764 LogInfo(COMPONENT_MAIN, "Stat export server: Waiting for connections..."); 00765 00766 while(1) 00767 { 00768 sin_size = sizeof their_addr; 00769 new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size); 00770 if(new_fd == -1) 00771 { 00772 LogError(COMPONENT_MAIN, ERR_SYS, errno, new_fd); 00773 continue; 00774 } 00775 00776 sprint_sockip((sockaddr_t *)&their_addr, s, sizeof s); 00777 00778 if (stat_export_check_access(&their_addr, 00779 &(nfs_param.extern_param.stat_export.allowed_clients), 00780 &pclient_found)) { 00781 LogDebug(COMPONENT_MAIN, "Stat export server: Access granted to %s", s); 00782 process_stat_request(new_fd); 00783 } else { 00784 LogWarn(COMPONENT_MAIN, "Stat export server: Access denied to %s", s); 00785 } 00786 } /* while ( 1 ) */ 00787 00788 return NULL; 00789 } /* stat_exporter_thread */ 00790 00791 void *long_processing_thread(void *UnusedArg) 00792 { 00793 struct timeval timer_end; 00794 struct timeval timer_diff; 00795 int i; 00796 00797 SetNameFunction("long_processing"); 00798 00799 while(1) 00800 { 00801 sleep(1); 00802 gettimeofday(&timer_end, NULL); 00803 00804 for(i = 0; i < nfs_param.core_param.nb_worker; i++) 00805 { 00806 P(workers_data[i].request_pool_mutex); 00807 if(workers_data[i].timer_start.tv_sec == 0) 00808 { 00809 V(workers_data[i].request_pool_mutex); 00810 continue; 00811 } 00812 timer_diff = time_diff(workers_data[i].timer_start, timer_end); 00813 V(workers_data[i].request_pool_mutex); 00814 if(timer_diff.tv_sec == nfs_param.core_param.long_processing_threshold || 00815 timer_diff.tv_sec == nfs_param.core_param.long_processing_threshold * 10) 00816 LogEvent(COMPONENT_DISPATCH, 00817 "Worker#%d: Function %s has been running for %llu.%.6llu seconds", 00818 i, workers_data[i].pfuncdesc->funcname, 00819 (unsigned long long)timer_diff.tv_sec, 00820 (unsigned long long)timer_diff.tv_usec); 00821 } 00822 } 00823 00824 return NULL; 00825 } /* long_processing_thread */