nfs-ganesha 1.4

nfs_dupreq.c

Go to the documentation of this file.
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 License
00010  * as published by the Free Software Foundation; either version 3 of
00011  * the License, or (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful, but
00014  * 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
00021  * 02110-1301 USA
00022  *
00023  * ---------------------------------------
00024  */
00025 
00034 #ifdef HAVE_CONFIG_H
00035 #include "config.h"
00036 #endif
00037 
00038 #ifdef _SOLARIS
00039 #include "solaris_port.h"
00040 #endif
00041 
00042 #include <stdio.h>
00043 #include <sys/types.h>
00044 #include <ctype.h>              /* for having isalnum */
00045 #include <stdlib.h>             /* for having atoi */
00046 #include <dirent.h>             /* for having MAXNAMLEN */
00047 #include <netdb.h>
00048 #include <netinet/in.h>
00049 #include <arpa/inet.h>
00050 #include <string.h>
00051 #include <pthread.h>
00052 #include <fcntl.h>
00053 #include <sys/file.h>           /* for having FNDELAY */
00054 #include <pwd.h>
00055 #include <grp.h>
00056 
00057 #include "rpcal.h"
00058 #include "LRU_List.h"
00059 #include "HashData.h"
00060 #include "HashTable.h"
00061 #include "log.h"
00062 #include "nfs_core.h"
00063 #include "nfs23.h"
00064 #include "nfs4.h"
00065 #include "fsal.h"
00066 #include "nfs_tools.h"
00067 #include "nfs_exports.h"
00068 #include "nfs_file_handle.h"
00069 #include "nfs_dupreq.h"
00070 
00071 extern nfs_function_desc_t nfs2_func_desc[];
00072 extern nfs_function_desc_t nfs3_func_desc[];
00073 extern nfs_function_desc_t nfs4_func_desc[];
00074 extern nfs_function_desc_t mnt1_func_desc[];
00075 extern nfs_function_desc_t mnt3_func_desc[];
00076 #ifdef _USE_NLM
00077 extern nfs_function_desc_t nlm4_func_desc[];
00078 #endif                          /* _USE_NLM */
00079 #ifdef _USE_RQUOTA
00080 extern nfs_function_desc_t rquota1_func_desc[];
00081 extern nfs_function_desc_t rquota2_func_desc[];
00082 #endif                          /* _USE_QUOTA */
00083 /* Structure used for duplicated request cache */
00084 hash_table_t *ht_dupreq_udp;
00085 hash_table_t *ht_dupreq_tcp;
00086 
00087 void LogDupReq(const char *label, sockaddr_t *addr, long xid, u_long rq_prog)
00088 {
00089   char namebuf[SOCK_NAME_MAX];
00090 
00091   sprint_sockaddr(addr, namebuf, sizeof(namebuf));
00092 
00093   LogFullDebug(COMPONENT_DUPREQ,
00094                "%s addr=%s xid=%ld rq_prog=%ld",
00095                label, namebuf, xid, rq_prog);
00096 }
00097 
00098 static unsigned int get_ipproto_by_xprt( SVCXPRT * xprt )
00099 {
00100    if( xprt->xp_p2 != NULL )
00101      return IPPROTO_UDP ;
00102    else if ( xprt->xp_p1 != NULL )
00103      return IPPROTO_TCP;
00104    else
00105      return IPPROTO_IP ; /* Dummy output */
00106 }
00107 
00108 
00109 static hash_table_t * get_ht_by_xprt( SVCXPRT * xprt )
00110 {
00111    return (get_ipproto_by_xprt( xprt )==IPPROTO_UDP)?ht_dupreq_udp:ht_dupreq_tcp ;
00112 }
00113 
00114 
00127 int print_entry_dupreq(LRU_data_t data, char *str)
00128 {
00129   strcpy(str, "");
00130   return 0;
00131 }
00132 
00133 static int _remove_dupreq(hash_table_t *ht_dupreq, hash_buffer_t *buffkey,
00134                           dupreq_entry_t *pdupreq, int nfs_req_status)
00135 {
00136   int rc;
00137   nfs_function_desc_t funcdesc = nfs2_func_desc[0];
00138   hash_buffer_t usedbuffkey;
00139 
00140   rc = HashTable_Del(ht_dupreq, buffkey, &usedbuffkey, NULL);
00141 
00142   /* if hashtable no such key => dupreq garbaged by another thread */
00143   if(rc != HASHTABLE_SUCCESS && rc != HASHTABLE_ERROR_NO_SUCH_KEY)
00144     return 1;                   /* Error while cleaning */
00145   else if(rc == HASHTABLE_ERROR_NO_SUCH_KEY)
00146     return 0;                   /* don't free the dupreq twice */
00147 
00148   /* Locate the function descriptor associated with this cached request */
00149   if(pdupreq->rq_prog == nfs_param.core_param.program[P_NFS])
00150     {
00151       switch (pdupreq->rq_vers)
00152         {
00153         case NFS_V2:
00154           funcdesc = nfs2_func_desc[pdupreq->rq_proc];
00155           break;
00156 
00157         case NFS_V3:
00158           funcdesc = nfs3_func_desc[pdupreq->rq_proc];
00159           break;
00160 
00161         case NFS_V4:
00162           funcdesc = nfs4_func_desc[pdupreq->rq_proc];
00163           break;
00164 
00165         default:
00166           /* We should never go there (this situation is filtered in nfs_rpc_getreq) */
00167           LogMajor(COMPONENT_DUPREQ,
00168                    "NFS Protocol version %d unknown in dupreq_gc",
00169                    (int)pdupreq->rq_vers);
00170         }
00171     }
00172   else if(pdupreq->rq_prog == nfs_param.core_param.program[P_MNT])
00173     {
00174       switch (pdupreq->rq_vers)
00175         {
00176         case MOUNT_V1:
00177           funcdesc = mnt1_func_desc[pdupreq->rq_proc];
00178           break;
00179 
00180         case MOUNT_V3:
00181           funcdesc = mnt3_func_desc[pdupreq->rq_proc];
00182           break;
00183 
00184         default:
00185           /* We should never go there (this situation is filtered in nfs_rpc_getreq) */
00186           LogMajor(COMPONENT_DUPREQ,
00187                    "MOUNT Protocol version %d unknown in dupreq_gc",
00188                    (int)pdupreq->rq_vers);
00189           break;
00190         }                       /* switch( pdupreq->vers ) */
00191     }
00192 #ifdef _USE_NLM
00193   else if(pdupreq->rq_prog == nfs_param.core_param.program[P_NLM])
00194     {
00195 
00196       switch (pdupreq->rq_vers)
00197         {
00198         case NLM4_VERS:
00199           funcdesc = nlm4_func_desc[pdupreq->rq_proc];
00200           break;
00201         }                       /* switch( pdupreq->vers ) */
00202     }
00203 #endif                          /* _USE_NLM */
00204 #ifdef _USE_RQUOTA
00205   else if(pdupreq->rq_prog == nfs_param.core_param.program[P_RQUOTA])
00206     {
00207 
00208       switch (pdupreq->rq_vers)
00209         {
00210         case RQUOTAVERS:
00211           funcdesc = rquota1_func_desc[pdupreq->rq_proc];
00212           break;
00213 
00214         case EXT_RQUOTAVERS:
00215           funcdesc = rquota2_func_desc[pdupreq->rq_proc];
00216           break;
00217         }                       /* switch( pdupreq->vers ) */
00218     }
00219 #endif
00220   else
00221     {
00222       /* We should never go there (this situation is filtered in nfs_rpc_getreq) */
00223       LogMajor(COMPONENT_DUPREQ,
00224                "protocol %d is not managed",
00225                (int)pdupreq->rq_prog);
00226     }
00227 
00228   /* Call the free function */
00229   if (nfs_req_status == NFS_REQ_OK)
00230     funcdesc.free_function(&(pdupreq->res_nfs));
00231 
00232   /* Send the entry back to the pool */
00233   pool_free(dupreq_pool, pdupreq);
00234   gsh_free(usedbuffkey.pdata);
00235 
00236   return DUPREQ_SUCCESS;
00237 }
00238 
00239 int nfs_dupreq_delete(struct svc_req *req)
00240 {
00241   int status;
00242 
00243   hash_buffer_t buffkey;
00244   hash_buffer_t buffval;
00245   dupreq_key_t dupkey;
00246   dupreq_entry_t *pdupreq;
00247   hash_table_t * ht_dupreq = NULL;
00248 
00249   /* Get correct HT depending on proto used */
00250   ht_dupreq = get_ht_by_xprt(req->rq_xprt) ;
00251 
00252   /* Get the socket address for the key */
00253   if(copy_xprt_addr(&dupkey.addr, req->rq_xprt) == 0)
00254     return DUPREQ_NOT_FOUND;
00255 
00256   dupkey.xid = req->rq_xid;
00257   dupkey.checksum = 0;
00258 
00259   /* I have to keep an integer as key, I wil use the pointer buffkey->pdata for this,
00260    * this also means that buffkey->len will be 0 */
00261   buffkey.pdata = (caddr_t) &dupkey;
00262   buffkey.len = sizeof(dupreq_key_t);
00263 
00264   if(HashTable_Get(ht_dupreq, &buffkey, &buffval) == HASHTABLE_SUCCESS)
00265     {
00266       pdupreq = (dupreq_entry_t *) buffval.pdata;
00267 
00268       /* reset timestamp */
00269       pdupreq->timestamp = time(NULL);
00270 
00271       status = DUPREQ_SUCCESS;
00272     }
00273   else {
00274     return DUPREQ_NOT_FOUND;
00275   }
00276 
00277   LogDupReq("REMOVING", &pdupreq->addr, pdupreq->xid, pdupreq->rq_prog);
00278 
00279   status = _remove_dupreq( ht_dupreq, &buffkey, pdupreq, !NFS_REQ_OK);
00280   return status;
00281 }
00282 
00295 int clean_entry_dupreq(LRU_entry_t *pentry, void *addparam)
00296 {
00297   hash_buffer_t buffkey;
00298   dupreq_entry_t *pdupreq = (dupreq_entry_t *) (pentry->buffdata.pdata);
00299   dupreq_key_t dupkey;
00300   hash_table_t * ht_dupreq = NULL ;
00301 
00302   /* Get the socket address for the key */
00303   memcpy((char *)&dupkey.addr, (char *)&pdupreq->addr, sizeof(dupkey.addr));
00304   dupkey.xid = pdupreq->xid;
00305   dupkey.checksum = pdupreq->checksum;
00306 
00307   /* I have to keep an integer as key, I wil use the pointer buffkey->pdata for this,
00308    * this also means that buffkey->len will be 0 */
00309   buffkey.pdata = (caddr_t) &dupkey;
00310   buffkey.len = sizeof(dupreq_key_t);
00311 
00312   /* Get correct HT depending on proto used */
00313   if( pdupreq->ipproto == IPPROTO_TCP )
00314      ht_dupreq = ht_dupreq_tcp ;
00315   else
00316      ht_dupreq = ht_dupreq_udp ;
00317 
00318   LogDupReq("Garbage collection on", &pdupreq->addr, pdupreq->xid, pdupreq->rq_prog);
00319 
00320   return _remove_dupreq(ht_dupreq, &buffkey, pdupreq, NFS_REQ_OK);
00321 }                               /* clean_entry_dupreq */
00322 
00340 uint32_t dupreq_value_hash_func(hash_parameter_t * p_hparam,
00341                                 hash_buffer_t * buffclef)
00342 {
00343   dupreq_key_t *pdupkey = (dupreq_key_t *)(buffclef->pdata);
00344   unsigned long addr_hash = hash_sockaddr((sockaddr_t *) &pdupkey->addr, CHECK_PORT);
00345 
00346   return (((unsigned long)pdupkey->xid + addr_hash)^(pdupkey->checksum)) % p_hparam->index_size;
00347 }                               /*  dupreq_value_hash_func */
00348 
00365 uint64_t dupreq_rbt_hash_func(hash_parameter_t * p_hparam, hash_buffer_t * buffclef)
00366 {
00367   dupreq_key_t *pdupkey = (dupreq_key_t *)(buffclef->pdata);
00368 
00369   unsigned long addr_hash = hash_sockaddr((sockaddr_t *) &pdupkey->addr, CHECK_PORT);
00370 
00371   return (((unsigned long)pdupkey->xid + addr_hash)^(pdupkey->checksum));
00372 }                               /* dupreq_rbt_hash_func */
00373 
00390 int compare_req(hash_buffer_t * buff1, hash_buffer_t * buff2)
00391 {
00392   dupreq_key_t *key1 = (dupreq_key_t *)(buff1->pdata);
00393   dupreq_key_t *key2 = (dupreq_key_t *)(buff2->pdata);
00394 
00395   if (key1->xid != key2->xid)
00396     return 1;
00397   if (cmp_sockaddr(&key1->addr, &key2->addr, CHECK_PORT) == 0)
00398     return 1;
00399   if (key1->checksum != key2->checksum)
00400     return 1;
00401   return 0;
00402 }                               /* compare_xid */
00403 
00417 int display_req_key(hash_buffer_t * pbuff, char *str)
00418 {
00419   dupreq_key_t *pdupkey = (dupreq_key_t *)(pbuff->pdata);
00420   char namebuf[SOCK_NAME_MAX];
00421 
00422   sprint_sockaddr(&pdupkey->addr, namebuf, sizeof(namebuf));
00423 
00424   return sprintf(str, "addr=%s xid=%ld checksum=%d",
00425                  namebuf, pdupkey->xid, pdupkey->checksum);
00426 
00427 }
00428 
00442 int display_req_val(hash_buffer_t *pbuff, char *str)
00443 {
00444   dupreq_entry_t *pdupreq = (dupreq_entry_t *)(pbuff->pdata);
00445   char namebuf[SOCK_NAME_MAX];
00446 
00447   sprint_sockaddr(&pdupreq->addr, namebuf, sizeof(namebuf));
00448 
00449   return sprintf(str, "addr=%s xid=%ld checksum=%d rq_prog=%lu rq_vers=%lu rq_proc=%lu",
00450                  namebuf, pdupreq->xid, pdupreq->checksum,
00451                  pdupreq->rq_prog, pdupreq->rq_vers, pdupreq->rq_proc);
00452 }
00453 
00465 int nfs_Init_dupreq(nfs_rpc_dupreq_parameter_t param)
00466 {
00467   if((ht_dupreq_udp = HashTable_Init(&param.hash_param)) == NULL)
00468     {
00469       LogCrit(COMPONENT_DUPREQ,
00470               "Cannot init the duplicate request hash table");
00471       return -1;
00472     }
00473 
00474   if((ht_dupreq_tcp = HashTable_Init(&param.hash_param)) == NULL)
00475     {
00476       LogCrit(COMPONENT_DUPREQ,
00477               "Cannot init the duplicate request hash table");
00478       return -1;
00479     }
00480 
00481 
00482   return DUPREQ_SUCCESS;
00483 }                               /* nfs_Init_dupreq */
00484 
00499 int nfs_dupreq_add_not_finished(struct svc_req *req,
00500                                 nfs_res_t *res_nfs)
00501 {
00502   hash_buffer_t buffkey;
00503   hash_buffer_t buffval;
00504   hash_buffer_t buffdata;
00505   dupreq_entry_t *pdupreq = NULL;
00506   int status = 0;
00507   dupreq_key_t *pdupkey = NULL;
00508   hash_table_t * ht_dupreq = NULL ;
00509 
00510   /* Get correct HT depending on proto used */
00511   ht_dupreq = get_ht_by_xprt(req->rq_xprt);
00512   /* Entry to be cached */
00513   pdupreq = pool_alloc(dupreq_pool, NULL);
00514   if(pdupreq == NULL)
00515     return DUPREQ_INSERT_MALLOC_ERROR;
00516 
00517   if(pthread_mutex_init(&pdupreq->dupreq_mutex, NULL) == -1)
00518     {
00519       pool_free(dupreq_pool, pdupreq);
00520       return DUPREQ_INSERT_MALLOC_ERROR;
00521     }
00522 
00523   if((pdupkey = gsh_malloc(sizeof(dupreq_key_t))) == NULL)
00524     {
00525       pool_free(dupreq_pool, pdupreq);
00526       return DUPREQ_INSERT_MALLOC_ERROR;
00527     }
00528 
00529   /* Get the socket address for the key and the request */
00530   if(copy_xprt_addr(&pdupkey->addr, req->rq_xprt) == 0 ||
00531      copy_xprt_addr(&pdupreq->addr, req->rq_xprt) == 0)
00532     {
00533       gsh_free(pdupkey);
00534       pool_free(dupreq_pool, pdupreq);
00535       return DUPREQ_INSERT_MALLOC_ERROR;
00536     }
00537 
00538   pdupkey->xid = req->rq_xid;
00539   pdupreq->xid = req->rq_xid;
00540 
00541   /* Checksum the request */
00542   pdupkey->checksum = 0;
00543   pdupreq->checksum = 0;
00544 
00545   /* I have to keep an integer as key, I wil use the pointer buffkey->pdata for this,
00546    * this also means that buffkey->len will be 0 */
00547   buffkey.pdata = (caddr_t) pdupkey;
00548   buffkey.len = sizeof(dupreq_key_t);
00549 
00550   /* I build the data with the request pointer that should be in state 'IN USE' */
00551   pdupreq->rq_prog = req->rq_prog;
00552   pdupreq->rq_vers = req->rq_vers;
00553   pdupreq->rq_proc = req->rq_proc;
00554   pdupreq->timestamp = time(NULL);
00555   pdupreq->processing = 1;
00556   pdupreq->ipproto = get_ipproto_by_xprt(req->rq_xprt) ;
00557   buffdata.pdata = (caddr_t) pdupreq;
00558   buffdata.len = sizeof(dupreq_entry_t);
00559 
00560   LogDupReq("Add Not Finished", &pdupreq->addr, pdupreq->xid, pdupreq->rq_prog);
00561 
00562   status = HashTable_Test_And_Set(ht_dupreq, &buffkey, &buffdata,
00563                                   HASHTABLE_SET_HOW_SET_NO_OVERWRITE);
00564 
00565   if (status == HASHTABLE_ERROR_KEY_ALREADY_EXISTS)
00566     {
00567       if(HashTable_Get(ht_dupreq, &buffkey, &buffval) == HASHTABLE_SUCCESS)
00568         {
00569           P(((dupreq_entry_t *)buffval.pdata)->dupreq_mutex);
00570           if ( ((dupreq_entry_t *)buffval.pdata)->processing == 1)
00571             {
00572               status = DUPREQ_BEING_PROCESSED;
00573             }
00574           else
00575             {
00576               *res_nfs = ((dupreq_entry_t *) buffval.pdata)->res_nfs;
00577               status = DUPREQ_ALREADY_EXISTS;
00578             }
00579           V(((dupreq_entry_t *)buffval.pdata)->dupreq_mutex);
00580         }
00581       else
00582         status = DUPREQ_NOT_FOUND;
00583     }
00584   else if (status == HASHTABLE_INSERT_MALLOC_ERROR)
00585       status = DUPREQ_INSERT_MALLOC_ERROR;
00586   else
00587     status = DUPREQ_SUCCESS;
00588   if (status != DUPREQ_SUCCESS) {
00589     pool_free(dupreq_pool, pdupreq);
00590     gsh_free(pdupkey);
00591   }
00592   return status;
00593 }                               /* nfs_dupreq_add_not_finished */
00594 
00612 int nfs_dupreq_finish(struct svc_req *req, nfs_res_t *p_res_nfs,
00613                       LRU_list_t *lru_dupreq)
00614 {
00615   hash_buffer_t buffkey;
00616   hash_buffer_t buffval;
00617   LRU_entry_t *pentry = NULL;
00618   LRU_status_t lru_status;
00619   dupreq_key_t dupkey;
00620   dupreq_entry_t *pdupreq;
00621   hash_table_t *ht_dupreq = NULL ;
00622 
00623   /* Get correct HT depending on proto used */
00624   ht_dupreq = get_ht_by_xprt(req->rq_xprt) ;
00625  
00626 
00627   /* Get the socket address for the key */
00628   if(copy_xprt_addr(&dupkey.addr, req->rq_xprt) == 0)
00629     return DUPREQ_NOT_FOUND;
00630 
00631   dupkey.xid = req->rq_xid;
00632   dupkey.checksum = 0;
00633 
00634   /* I have to keep an integer as key, I wil use the pointer buffkey->pdata for this,
00635    * this also means that buffkey->len will be 0 */
00636   buffkey.pdata = (caddr_t) &dupkey;
00637   buffkey.len = sizeof(dupreq_key_t);
00638   if(HashTable_Get(ht_dupreq, &buffkey, &buffval) != HASHTABLE_SUCCESS)
00639     return DUPREQ_NOT_FOUND;
00640 
00641   pdupreq = (dupreq_entry_t *)buffval.pdata;
00642 
00643   LogDupReq("Finish", &pdupreq->addr, pdupreq->xid, pdupreq->rq_prog);
00644 
00645   P(pdupreq->dupreq_mutex);
00646 
00647   pdupreq->res_nfs = *p_res_nfs;
00648   pdupreq->timestamp = time(NULL);
00649   pdupreq->processing = 0;
00650 
00651   V(pdupreq->dupreq_mutex);
00652 
00653   /* Add it to lru list */
00654   if((pentry = LRU_new_entry(lru_dupreq, &lru_status)) == NULL)
00655     return DUPREQ_INSERT_MALLOC_ERROR;
00656   pentry->buffdata.pdata = buffval.pdata;
00657   pentry->buffdata.len = buffval.len;
00658 
00659   return DUPREQ_SUCCESS;
00660 }                               /* nfs_dupreq_finish */
00661 
00675 nfs_res_t nfs_dupreq_get(struct svc_req *req, int *pstatus)
00676 {
00677   hash_buffer_t buffkey;
00678   hash_buffer_t buffval;
00679   nfs_res_t res_nfs;
00680   dupreq_key_t dupkey;
00681   hash_table_t * ht_dupreq = NULL ;
00682 
00683   /* Get correct HT depending on proto used */
00684   ht_dupreq = get_ht_by_xprt(req->rq_xprt) ;
00685  
00686 
00687   memset(&res_nfs, 0, sizeof(res_nfs));
00688 
00689   /* Get the socket address for the key */
00690   if(copy_xprt_addr(&dupkey.addr, req->rq_xprt) == 0)
00691     {
00692       *pstatus = DUPREQ_NOT_FOUND;
00693       return res_nfs;
00694     }
00695 
00696   dupkey.xid = req->rq_xid;
00697   dupkey.checksum = 0;
00698 
00699   /* I have to keep an integer as key, I wil use the pointer buffkey->pdata for this,
00700    * this also means that buffkey->len will be 0 */
00701   buffkey.pdata = (caddr_t) &dupkey;
00702   buffkey.len = sizeof(dupreq_key_t);
00703   if(HashTable_Get(ht_dupreq, &buffkey, &buffval) == HASHTABLE_SUCCESS)
00704     {
00705       dupreq_entry_t *pdupreq = (dupreq_entry_t *)buffval.pdata;
00706       /* reset timestamp */
00707       pdupreq->timestamp = time(NULL);
00708 
00709       *pstatus = DUPREQ_SUCCESS;
00710       res_nfs = pdupreq->res_nfs;
00711       LogDupReq(" dupreq_get: Hit in the dupreq cache for", &pdupreq->addr,
00712                 pdupreq->xid, pdupreq->rq_prog);
00713     }
00714   else
00715     {
00716       LogDupReq("Failed to get dupreq entry", &dupkey.addr, dupkey.xid, req->rq_prog);
00717       *pstatus = DUPREQ_NOT_FOUND;
00718     }
00719   return res_nfs;
00720 }                               /* nfs_dupreq_get */
00721 
00736 int nfs_dupreq_gc_function(LRU_entry_t * pentry, void *addparam)
00737 {
00738   dupreq_entry_t *pdupreq = NULL;
00739 
00740   pdupreq = (dupreq_entry_t *) (pentry->buffdata.pdata);
00741 
00742   /* Test if entry is expired */
00743   if(time(NULL) - pdupreq->timestamp > nfs_param.core_param.expiration_dupreq)
00744     return LRU_LIST_SET_INVALID;
00745 
00746   return LRU_LIST_DO_NOT_SET_INVALID;
00747 }                               /* nfs_dupreq_fc_function */
00748 
00762 void nfs_dupreq_get_stats(hash_stat_t * phstat_udp, hash_stat_t * phstat_tcp )
00763 {
00764   HashTable_GetStats(ht_dupreq_udp, phstat_udp);
00765   HashTable_GetStats(ht_dupreq_tcp, phstat_tcp);
00766 }                               /* nfs_dupreq_get_stats */