nfs-ganesha 1.4
|
00001 /* 00002 * vim:set expandtab:shiftwidth=2:tabstop=8: 00003 */ 00004 00013 #ifdef HAVE_CONFIG_H 00014 #include "config.h" 00015 #endif 00016 00017 #ifdef _SOLARIS 00018 #include "solaris_port.h" 00019 #endif /* _SOLARIS */ 00020 00021 #include <ctype.h> /* for isalpha */ 00022 #include <netdb.h> /* for gethostbyname */ 00023 #include <sys/socket.h> 00024 #include <netinet/in.h> 00025 #include <arpa/inet.h> 00026 00027 #include "fsal.h" 00028 #include "fsal_internal.h" 00029 #include "fsal_common.h" 00030 #include "fsal_convert.h" 00031 #include "config_parsing.h" 00032 #include "fsal_common.h" 00033 #include <string.h> 00034 00035 #ifdef _HANDLE_MAPPING 00036 #include "handle_mapping/handle_mapping.h" 00037 #endif 00038 00039 extern proxyfs_specific_initinfo_t global_fsal_proxy_specific_info; 00040 00041 /* case unsensitivity */ 00042 #define STRCMP strcasecmp 00043 00044 char *PROXYFSAL_GetFSName() 00045 { 00046 return "NFSv4 PROXY"; 00047 } 00048 00065 int PROXYFSAL_handlecmp(fsal_handle_t * handle_1, fsal_handle_t * handle_2, 00066 fsal_status_t * status) 00067 { 00068 *status = FSAL_STATUS_NO_ERROR; 00069 proxyfsal_handle_t * handle1 = (proxyfsal_handle_t *)handle_1; 00070 proxyfsal_handle_t * handle2 = (proxyfsal_handle_t *)handle_2; 00071 00072 if(!handle1 || !handle2) 00073 { 00074 status->major = ERR_FSAL_FAULT; 00075 return -1; 00076 } 00077 00078 /* Check if size are the same for underlying's server FH */ 00079 if(handle1->data.srv_handle_len != handle2->data.srv_handle_len) 00080 return -1; 00081 00082 /* At last, check underlying FH value. We use the fact that srv_handle_len is the same */ 00083 if(memcmp(handle1->data.srv_handle_val, handle2->data.srv_handle_val, handle1->data.srv_handle_len)) 00084 return -1; 00085 00086 /* If this point is reached, then the FH are the same */ 00087 return 0; 00088 } /* FSAL_handlecmp */ 00089 00104 unsigned int PROXYFSAL_Handle_to_HashIndex(fsal_handle_t *handle, 00105 unsigned int cookie, 00106 unsigned int alphabet_len, 00107 unsigned int index_size) 00108 { 00109 unsigned int cpt = 0; 00110 unsigned int sum = 0; 00111 unsigned int extract = 0; 00112 unsigned int mod; 00113 proxyfsal_handle_t * p_handle = (proxyfsal_handle_t *)handle; 00114 00115 /* XXX If the handle is not 32 bits-aligned, the last loop will get uninitialized 00116 * chars after the end of the handle. We must avoid this by skipping the last loop 00117 * and doing a special processing for the last bytes */ 00118 00119 mod = p_handle->data.srv_handle_len % sizeof(unsigned int); 00120 00121 sum = cookie; 00122 for(cpt = 0; cpt < p_handle->data.srv_handle_len - mod; cpt += sizeof(unsigned int)) 00123 { 00124 memcpy(&extract, &(p_handle->data.srv_handle_val[cpt]), sizeof(unsigned int)); 00125 sum = (3 * sum + 5 * extract + 1999) % index_size; 00126 } 00127 00128 if(mod) 00129 { 00130 extract = 0; 00131 for(cpt = p_handle->data.srv_handle_len - mod; cpt < p_handle->data.srv_handle_len; cpt++) 00132 { 00133 /* shift of 1 byte */ 00134 extract <<= 8; 00135 extract |= (unsigned int)p_handle->data.srv_handle_val[cpt]; 00136 } 00137 sum = (3 * sum + 5 * extract + 1999) % index_size; 00138 } 00139 00140 return sum; 00141 } 00142 00143 /* 00144 * FSAL_Handle_to_RBTIndex 00145 * This function is used for generating a RBT node ID 00146 * in order to identify entries into the RBT. 00147 * 00148 * \param p_handle The handle to be hashed 00149 * \param cookie Makes it possible to have different hash value for the 00150 * same handle, when cookie changes. 00151 * 00152 * \return The hash value 00153 */ 00154 00155 unsigned int PROXYFSAL_Handle_to_RBTIndex(fsal_handle_t *handle, 00156 unsigned int cookie) 00157 { 00158 unsigned int h = 0; 00159 unsigned int cpt = 0; 00160 unsigned int extract = 0; 00161 unsigned int mod; 00162 proxyfsal_handle_t * p_handle = (proxyfsal_handle_t *)handle; 00163 00164 h = cookie; 00165 00166 /* XXX If the handle is not 32 bits-aligned, the last loop will get uninitialized 00167 * chars after the end of the handle. We must avoid this by skipping the last loop 00168 * and doing a special processing for the last bytes */ 00169 00170 mod = p_handle->data.srv_handle_len % sizeof(unsigned int); 00171 00172 for(cpt = 0; cpt < p_handle->data.srv_handle_len - mod; cpt += sizeof(unsigned int)) 00173 { 00174 memcpy(&extract, &(p_handle->data.srv_handle_val[cpt]), sizeof(unsigned int)); 00175 h = (857 * h ^ extract) % 715827883; 00176 } 00177 00178 if(mod) 00179 { 00180 extract = 0; 00181 for(cpt = p_handle->data.srv_handle_len - mod; cpt < p_handle->data.srv_handle_len; cpt++) 00182 { 00183 /* shift of 1 byte */ 00184 extract <<= 8; 00185 extract |= (unsigned int)p_handle->data.srv_handle_val[cpt]; 00186 } 00187 h = (857 * h ^ extract) % 715827883; 00188 } 00189 00190 return h; 00191 } 00192 00193 static ssize_t proxy_sizeof_handle(const proxyfsal_handle_t *pxh) 00194 { 00195 if(pxh->data.srv_handle_len > sizeof(pxh->data.srv_handle_val)) 00196 return -1; 00197 return offsetof(proxyfsal_handle_t, data.srv_handle_val) + 00198 pxh->data.srv_handle_len; 00199 } 00200 00217 fsal_status_t PROXYFSAL_DigestHandle(fsal_export_context_t * exp_context, /* IN */ 00218 fsal_digesttype_t output_type, /* IN */ 00219 fsal_handle_t * in_handle, /* IN */ 00220 struct fsal_handle_desc * fh_desc) 00221 { 00222 #ifdef _HANDLE_MAPPING 00223 nfs23_map_handle_t map_hdl; 00224 #endif 00225 proxyfsal_export_context_t * p_expcontext = (proxyfsal_export_context_t *)exp_context; 00226 proxyfsal_handle_t * in_fsal_handle = (proxyfsal_handle_t *)in_handle; 00227 ssize_t sz; 00228 const void *data; 00229 uint32_t fid2; 00230 00231 /* sanity checks */ 00232 if(!in_handle || !fh_desc || !fh_desc->start || !p_expcontext) 00233 ReturnCode(ERR_FSAL_FAULT, 0); 00234 00235 switch (output_type) 00236 { 00237 case FSAL_DIGEST_NFSV2: 00238 case FSAL_DIGEST_NFSV3: 00239 if(!global_fsal_proxy_specific_info.enable_handle_mapping) 00240 ReturnCode(ERR_FSAL_NOTSUPP, 0); 00241 00242 #ifdef _HANDLE_MAPPING 00243 if(fh_desc->len < sizeof(map_hdl)) 00244 ReturnCode(ERR_FSAL_TOOSMALL, 0); 00245 00246 /* returns a digest and register it to handle map 00247 * (use the same checksum as cache inode's RBT index) 00248 */ 00249 map_hdl.object_id = in_fsal_handle->data.fileid4; 00250 map_hdl.handle_hash = FSAL_Handle_to_RBTIndex(in_fsal_handle, 0); 00251 00252 HandleMap_SetFH(&map_hdl, in_fsal_handle); 00253 00254 /* Do no set length - use as much of opaque handle as allowed, 00255 * it could help when converting handles back in ExpandHandle */ 00256 memset(fh_desc->start, 0, fh_desc->len); 00257 memcpy(fh_desc->start, &map_hdl, sizeof(map_hdl)); 00258 ReturnCode(ERR_FSAL_NO_ERROR, 0); 00259 #endif 00260 /* fallthru */ 00261 case FSAL_DIGEST_NFSV4: 00262 sz = proxy_sizeof_handle(in_fsal_handle); 00263 data = in_fsal_handle; 00264 break; 00265 00266 case FSAL_DIGEST_FILEID2: 00267 fid2 = in_fsal_handle->data.fileid4; 00268 if(fid2 != in_fsal_handle->data.fileid4) 00269 ReturnCode(ERR_FSAL_OVERFLOW, 0); 00270 data = &fid2; 00271 sz = sizeof(fid2); 00272 break; 00273 00274 case FSAL_DIGEST_FILEID3: 00275 case FSAL_DIGEST_FILEID4: 00276 sz = sizeof(in_fsal_handle->data.fileid4); 00277 data = &(in_fsal_handle->data.fileid4); 00278 break; 00279 00280 default: 00281 ReturnCode(ERR_FSAL_SERVERFAULT, 0); 00282 } 00283 00284 if(fh_desc->len < sz) 00285 { 00286 LogDebug(COMPONENT_FSAL, "Cannot fit %zd bytes into %zd", 00287 sz, fh_desc->len); 00288 ReturnCode(ERR_FSAL_TOOSMALL, 0); 00289 } 00290 00291 fh_desc->len = sz; 00292 memcpy(fh_desc->start, data, sz); 00293 ReturnCode(ERR_FSAL_NO_ERROR, 0); 00294 00295 } /* FSAL_DigestHandle */ 00296 00310 fsal_status_t PROXYFSAL_ExpandHandle(fsal_export_context_t * p_expcontext, /* IN */ 00311 fsal_digesttype_t in_type, /* IN */ 00312 struct fsal_handle_desc *fh_desc) 00313 { 00314 #ifdef _HANDLE_MAPPING 00315 nfs23_map_handle_t *map_hdl; 00316 proxyfsal_handle_t tmp_hdl; 00317 int rc; 00318 #endif 00319 ssize_t sz; 00320 00321 /* sanity checks */ 00322 if(!fh_desc || !fh_desc->start) 00323 ReturnCode(ERR_FSAL_FAULT, 0); 00324 00325 switch (in_type) 00326 { 00327 case FSAL_DIGEST_NFSV2: 00328 case FSAL_DIGEST_NFSV3: 00329 if(!global_fsal_proxy_specific_info.enable_handle_mapping) 00330 ReturnCode(ERR_FSAL_NOTSUPP, 0); 00331 00332 #ifdef _HANDLE_MAPPING 00333 if(fh_desc->len < sizeof(*map_hdl)) 00334 ReturnCode(ERR_FSAL_TOOSMALL, 0); 00335 00336 map_hdl = (nfs23_map_handle_t *)fh_desc->start; 00337 rc = HandleMap_GetFH(map_hdl, &tmp_hdl); 00338 00339 if(isFullDebug(COMPONENT_FSAL)) 00340 { 00341 if(rc == HANDLEMAP_STALE) 00342 LogFullDebug(COMPONENT_FSAL, "File id=%llu : HandleMap_GetFH returns HANDLEMAP_STALE\n", 00343 (unsigned long long)map_hdl->object_id); 00344 else if(rc == 0) 00345 LogFullDebug(COMPONENT_FSAL, "File id=%llu : HandleMap_GetFH returns HANDLEMAP_SUCCESS\n", 00346 (unsigned long long)map_hdl->object_id); 00347 else 00348 LogFullDebug(COMPONENT_FSAL, "File id=%llu : HandleMap_GetFH returns error %d\n", 00349 (unsigned long long)map_hdl->object_id, rc); 00350 } 00351 00352 if(rc == HANDLEMAP_STALE) 00353 ReturnCode(ERR_FSAL_STALE, rc); 00354 else if(rc != 0) 00355 ReturnCode(ERR_FSAL_SERVERFAULT, rc); 00356 00357 sz = proxy_sizeof_handle(&tmp_hdl); 00358 if(fh_desc->len < sz) 00359 ReturnCode(ERR_FSAL_TOOSMALL, 0); 00360 memcpy(fh_desc->start, &tmp_hdl, sz); 00361 break; 00362 #endif 00363 /* fallthru */ 00364 case FSAL_DIGEST_NFSV4: 00365 sz = proxy_sizeof_handle((proxyfsal_handle_t *)fh_desc->start); 00366 if(sz < 0) 00367 ReturnCode(ERR_FSAL_BADHANDLE, 0); 00368 if(fh_desc->len != sz) 00369 { 00370 LogMajor(COMPONENT_FSAL, 00371 "size mismatch for handle. should be %zd, got %zd", 00372 sz, fh_desc->len); 00373 ReturnCode(ERR_FSAL_BADHANDLE, 0); 00374 } 00375 break; 00376 case FSAL_DIGEST_SIZEOF: 00377 sz = proxy_sizeof_handle((proxyfsal_handle_t *)fh_desc->start); 00378 break; 00379 default: /* Catch FILEID2, FILEID3, FILEID4 */ 00380 ReturnCode(ERR_FSAL_SERVERFAULT, 0); 00381 } 00382 fh_desc->len = sz; /* pass back the actual size */ 00383 ReturnCode(ERR_FSAL_NO_ERROR, 0); 00384 } 00385 00394 fsal_status_t PROXYFSAL_SetDefault_FS_specific_parameter(fsal_parameter_t * out_parameter) 00395 { 00396 proxyfs_specific_initinfo_t *init_info; 00397 00398 /* defensive programming... */ 00399 if(out_parameter == NULL) 00400 ReturnCode(ERR_FSAL_FAULT, 0); 00401 00402 /* >> set your default FS configuration into the 00403 out_parameter->fs_specific_info structure << */ 00404 00405 init_info = (proxyfs_specific_initinfo_t *) &(out_parameter->fs_specific_info); 00406 00407 init_info->retry_sleeptime = FSAL_PROXY_RETRY_SLEEPTIME; /* Time to sleep when retrying */ 00408 init_info->srv_addr = htonl(0x7F000001); /* 127.0.0.1 aka localhost */ 00409 init_info->srv_prognum = 100003; /* Default NFS prognum */ 00410 init_info->srv_port = htons(2049); /* Default NFS port */ 00411 init_info->srv_timeout = 2; /* RPC Client timeout */ 00412 init_info->srv_sendsize = FSAL_PROXY_SEND_BUFFER_SIZE; /* Default Buffer Send Size */ 00413 init_info->srv_recvsize = FSAL_PROXY_RECV_BUFFER_SIZE; /* Default Buffer Send Size */ 00414 init_info->use_privileged_client_port = FALSE; /* No privileged port by default */ 00415 00416 init_info->active_krb5 = FALSE; /* No RPCSEC_GSS by default */ 00417 strncpy(init_info->local_principal, "(no principal set)", MAXNAMLEN); /* Principal is nfs@<host> */ 00418 strncpy(init_info->remote_principal, "(no principal set)", MAXNAMLEN); /* Principal is nfs@<host> */ 00419 strncpy(init_info->keytab, "etc/krb5.keytab", MAXPATHLEN); /* Path to krb5 keytab file */ 00420 init_info->cred_lifetime = 86400; /* 24h is a good default */ 00421 init_info->sec_type = 0; 00422 00423 strcpy(init_info->srv_proto, "tcp"); 00424 00425 #ifdef _HANDLE_MAPPING 00426 init_info->enable_handle_mapping = FALSE; 00427 strcpy(init_info->hdlmap_dbdir, "/var/ganesha/handlemap"); 00428 strcpy(init_info->hdlmap_tmpdir, "/var/ganesha/tmp"); 00429 init_info->hdlmap_dbcount = 8; 00430 init_info->hdlmap_hashsize = 103; 00431 init_info->hdlmap_nb_entry_prealloc = 16384; 00432 init_info->hdlmap_nb_db_op_prealloc = 1024; 00433 #endif 00434 00435 ReturnCode(ERR_FSAL_NO_ERROR, 0); 00436 00437 } 00438 00460 /* load specific filesystem configuration options */ 00461 00462 fsal_status_t PROXYFSAL_load_FS_specific_parameter_from_conf(config_file_t in_config, 00463 fsal_parameter_t * 00464 out_parameter) 00465 { 00466 int err; 00467 int var_max, var_index; 00468 char *key_name; 00469 char *key_value; 00470 struct hostent *hp = NULL; 00471 config_item_t block; 00472 proxyfs_specific_initinfo_t *init_info; 00473 00474 /* defensive programming... */ 00475 if(out_parameter == NULL) 00476 ReturnCode(ERR_FSAL_FAULT, 0); 00477 00478 /* >> set your default FS configuration into the 00479 out_parameter->fs_specific_info structure << */ 00480 00481 init_info = (proxyfs_specific_initinfo_t *) &(out_parameter->fs_specific_info); 00482 00483 block = config_FindItemByName(in_config, CONF_LABEL_FS_SPECIFIC); 00484 00485 /* cannot read item */ 00486 if(block == NULL) 00487 { 00488 LogCrit(COMPONENT_CONFIG, "FSAL LOAD PARAMETER: Cannot read item \"%s\" from configuration file", 00489 CONF_LABEL_FS_SPECIFIC); 00490 ReturnCode(ERR_FSAL_NOENT, 0); 00491 } 00492 else if(config_ItemType(block) != CONFIG_ITEM_BLOCK) 00493 { 00494 LogCrit(COMPONENT_CONFIG, "FSAL LOAD PARAMETER: Item \"%s\" is expected to be a block", 00495 CONF_LABEL_FS_SPECIFIC); 00496 ReturnCode(ERR_FSAL_INVAL, 0); 00497 } 00498 00499 /* makes an iteration on the (key, value) couplets */ 00500 00501 var_max = config_GetNbItems(block); 00502 00503 for(var_index = 0; var_index < var_max; var_index++) 00504 { 00505 config_item_t item; 00506 00507 item = config_GetItemByIndex(block, var_index); 00508 00509 err = config_GetKeyValue(item, &key_name, &key_value); 00510 if(err) 00511 { 00512 LogCrit(COMPONENT_CONFIG, 00513 "FSAL LOAD PARAMETER: ERROR reading key[%d] from section \"%s\" of configuration file.", 00514 var_index, CONF_LABEL_FS_SPECIFIC); 00515 ReturnCode(ERR_FSAL_SERVERFAULT, err); 00516 } 00517 00518 /* what parameter is it ? */ 00519 00520 if(!STRCMP(key_name, "Srv_Addr")) 00521 { 00522 if(isdigit(key_value[0])) 00523 { 00524 /* Address begin with a digit, it is a address in the dotted form, translate it */ 00525 init_info->srv_addr = inet_addr(key_value); 00526 } 00527 else 00528 { 00529 /* This is a serveur name that is to be resolved. Use gethostbyname */ 00530 if((hp = gethostbyname(key_value)) == NULL) 00531 { 00532 LogCrit(COMPONENT_CONFIG, "FSAL LOAD PARAMETER: ERROR: Unexpected value for %s", 00533 key_name); 00534 ReturnCode(ERR_FSAL_INVAL, 0); 00535 } 00536 memcpy(&init_info->srv_addr, hp->h_addr, hp->h_length); 00537 } 00538 } 00539 else if(!STRCMP(key_name, "NFS_Port")) 00540 { 00541 init_info->srv_port = 00542 htons((unsigned short)atoi(key_value)); 00543 } 00544 else if(!STRCMP(key_name, "NFS_Service")) 00545 { 00546 init_info->srv_prognum = (unsigned int)atoi(key_value); 00547 } 00548 else if(!STRCMP(key_name, "NFS_SendSize")) 00549 { 00550 init_info->srv_sendsize = (unsigned int)atoi(key_value); 00551 } 00552 else if(!STRCMP(key_name, "NFS_RecvSize")) 00553 { 00554 init_info->srv_recvsize = (unsigned int)atoi(key_value); 00555 } 00556 else if(!STRCMP(key_name, "Use_Privileged_Client_Port")) 00557 { 00558 init_info->use_privileged_client_port = StrToBoolean( key_value ) ; 00559 } 00560 else if(!STRCMP(key_name, "Retry_SleepTime")) 00561 { 00562 init_info->retry_sleeptime = (unsigned int)atoi(key_value); 00563 } 00565 else if(!STRCMP(key_name, "NFS_Proto")) 00566 { 00567 /* key_value should be either "udp" or "tcp" */ 00568 if(strncasecmp(key_value, "udp", MAXNAMLEN) 00569 && strncasecmp(key_value, "tcp", MAXNAMLEN)) 00570 { 00571 LogCrit(COMPONENT_CONFIG, "FSAL LOAD PARAMETER: ERROR: Unexpected value for %s --> %s", 00572 key_name, key_value); 00573 ReturnCode(ERR_FSAL_INVAL, 0); 00574 } 00575 strncpy(init_info->srv_proto, key_value, MAXNAMLEN); 00576 } 00578 else if(!STRCMP(key_name, "Active_krb5")) 00579 { 00580 init_info->active_krb5 = StrToBoolean(key_value); 00581 } 00582 else if(!STRCMP(key_name, "Local_PrincipalName")) 00583 { 00584 strncpy(init_info->local_principal, key_value, MAXNAMLEN); 00585 } 00586 else if(!STRCMP(key_name, "Remote_PrincipalName")) 00587 { 00588 strncpy(init_info->remote_principal, key_value, MAXNAMLEN); 00589 } 00590 else if(!STRCMP(key_name, "KeytabPath")) 00591 { 00592 strncpy(init_info->keytab, key_value, MAXPATHLEN); 00593 } 00594 else if(!STRCMP(key_name, "Credential_LifeTime")) 00595 { 00596 init_info->cred_lifetime = (unsigned int)atoi(key_value); 00597 } 00598 else if(!STRCMP(key_name, "Sec_Type")) 00599 { 00600 #ifdef _USE_GSSRPC 00601 if(!STRCMP(key_value, "krb5")) 00602 init_info->sec_type = RPCSEC_GSS_SVC_NONE; 00603 else if(!STRCMP(key_value, "krb5i")) 00604 init_info->sec_type = RPCSEC_GSS_SVC_INTEGRITY; 00605 else if(!STRCMP(key_value, "krb5p")) 00606 init_info->sec_type = RPCSEC_GSS_SVC_PRIVACY; 00607 else 00608 { 00609 LogCrit(COMPONENT_CONFIG, "FSAL LOAD PARAMETER: bad value %s for parameter %s", key_value, 00610 key_name); 00611 ReturnCode(ERR_FSAL_INVAL, 0); 00612 } 00613 #endif 00614 } 00615 else if(!STRCMP(key_name, "Enable_Handle_Mapping")) 00616 { 00617 init_info->enable_handle_mapping = StrToBoolean(key_value); 00618 00619 if(init_info->enable_handle_mapping == -1) 00620 { 00621 LogCrit(COMPONENT_CONFIG, 00622 "FSAL LOAD PARAMETER: ERROR: Unexpected value for %s --> %s (boolean expected)", 00623 key_name, key_value); 00624 ReturnCode(ERR_FSAL_INVAL, 0); 00625 } 00626 } 00627 else if(!STRCMP(key_name, "HandleMap_DB_Dir")) 00628 { 00629 strncpy(init_info->hdlmap_dbdir, key_value, MAXPATHLEN); 00630 } 00631 else if(!STRCMP(key_name, "HandleMap_Tmp_Dir")) 00632 { 00633 strncpy(init_info->hdlmap_tmpdir, key_value, MAXPATHLEN); 00634 } 00635 else if(!STRCMP(key_name, "HandleMap_DB_Count")) 00636 { 00637 init_info->hdlmap_dbcount = (unsigned int)atoi(key_value); 00638 } 00639 else if(!STRCMP(key_name, "HandleMap_HashTable_Size")) 00640 { 00641 init_info->hdlmap_hashsize = (unsigned int)atoi(key_value); 00642 } 00643 else if(!STRCMP(key_name, "HandleMap_Nb_Entries_Prealloc")) 00644 { 00645 init_info->hdlmap_nb_entry_prealloc = 00646 (unsigned int)atoi(key_value); 00647 } 00648 else if(!STRCMP(key_name, "HandleMap_Nb_DB_Operations_Prealloc")) 00649 { 00650 init_info->hdlmap_nb_db_op_prealloc = 00651 (unsigned int)atoi(key_value); 00652 } 00653 00654 else 00655 { 00656 LogCrit(COMPONENT_CONFIG, 00657 "FSAL LOAD PARAMETER: ERROR: Unknown or unsettable key: %s (item %s)", 00658 key_name, CONF_LABEL_FS_SPECIFIC); 00659 ReturnCode(ERR_FSAL_INVAL, 0); 00660 } 00661 00662 } 00663 00664 ReturnCode(ERR_FSAL_NO_ERROR, 0); 00665 00666 } /* FSAL_load_FS_specific_parameter_from_conf */