nfs-ganesha 1.4

fsal_tools.c

Go to the documentation of this file.
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 */