nfs-ganesha 1.4

nfs_worker_thread.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  *
00009  * This program is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public
00011  * License as published by the Free Software Foundation; either
00012  * version 3 of the License, or (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * Lesser General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU Lesser General Public
00020  * License along with this library; if not, write to the Free Software
00021  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00022  *
00023  * ---------------------------------------
00024  */
00025 
00038 #ifdef HAVE_CONFIG_H
00039 #include "config.h"
00040 #endif
00041 
00042 #ifdef _SOLARIS
00043 #include "solaris_port.h"
00044 #endif
00045 
00046 #include <assert.h>
00047 #include <stdio.h>
00048 #include <stdbool.h>
00049 #include <string.h>
00050 #include <pthread.h>
00051 #include <fcntl.h>
00052 #include <sys/file.h>           /* for having FNDELAY */
00053 #include <sys/signal.h>
00054 #include <poll.h>
00055 #include "HashData.h"
00056 #include "HashTable.h"
00057 #include "log.h"
00058 #include "ganesha_rpc.h"
00059 #include "nfs23.h"
00060 #include "nfs4.h"
00061 #include "mount.h"
00062 #include "nlm4.h"
00063 #include "rquota.h"
00064 #include "nfs_core.h"
00065 #include "cache_inode.h"
00066 #include "nfs_exports.h"
00067 #include "nfs_creds.h"
00068 #include "nfs_proto_functions.h"
00069 #include "nfs_dupreq.h"
00070 #include "nfs_file_handle.h"
00071 #include "nfs_stat.h"
00072 #include "nfs_tcb.h"
00073 #include "SemN.h"
00074 
00075 extern nfs_worker_data_t *workers_data;
00076 
00077 pool_t *request_pool;
00078 pool_t *request_data_pool;
00079 pool_t *dupreq_pool;
00080 pool_t *ip_stats_pool;
00081 
00082 /* These two variables keep state of the thread that gc at this time */
00083 unsigned int nb_current_gc_workers;
00084 pthread_mutex_t lock_nb_current_gc_workers;
00085 
00086 const nfs_function_desc_t invalid_funcdesc =
00087   {nfs_Null, nfs_Null_Free, (xdrproc_t) xdr_void, (xdrproc_t) xdr_void,
00088    "invalid_function", NOTHING_SPECIAL};
00089 
00090   const nfs_function_desc_t *INVALID_FUNCDESC = &invalid_funcdesc;
00091 
00092 /* Static array : all the function pointer per nfs v2 functions */
00093 const nfs_function_desc_t nfs2_func_desc[] = {
00094   {nfs_Null, nfs_Null_Free, (xdrproc_t) xdr_void,
00095    (xdrproc_t) xdr_void, "nfs_Null",
00096    NOTHING_SPECIAL},
00097   {nfs_Getattr, nfs_Getattr_Free, (xdrproc_t) xdr_fhandle2,
00098    (xdrproc_t) xdr_ATTR2res, "nfs_Getattr",
00099    NEEDS_CRED | SUPPORTS_GSS},
00100   {nfs_Setattr, nfs_Setattr_Free, (xdrproc_t) xdr_SETATTR2args,
00101    (xdrproc_t) xdr_ATTR2res, "nfs_Setattr",
00102    MAKES_WRITE | NEEDS_CRED | CAN_BE_DUP | SUPPORTS_GSS},
00103   {nfs2_Root, nfs2_Root_Free, (xdrproc_t) xdr_void,
00104    (xdrproc_t) xdr_void, "nfs2_Root",
00105    NOTHING_SPECIAL},
00106   {nfs_Lookup, nfs2_Lookup_Free, (xdrproc_t) xdr_diropargs2,
00107    (xdrproc_t) xdr_DIROP2res, "nfs_Lookup",
00108    NEEDS_CRED | SUPPORTS_GSS},
00109   {nfs_Readlink, nfs2_Readlink_Free, (xdrproc_t) xdr_fhandle2,
00110    (xdrproc_t) xdr_READLINK2res, "nfs_Readlink",
00111    NEEDS_CRED | SUPPORTS_GSS},
00112   {nfs_Read, nfs2_Read_Free, (xdrproc_t) xdr_READ2args,
00113    (xdrproc_t) xdr_READ2res, "nfs_Read",
00114    NEEDS_CRED | SUPPORTS_GSS},
00115   {nfs2_Writecache, nfs2_Writecache_Free, (xdrproc_t) xdr_void,
00116    (xdrproc_t) xdr_void, "nfs_Writecache",
00117    NOTHING_SPECIAL},
00118   {nfs_Write, nfs_Write_Free, (xdrproc_t) xdr_WRITE2args,
00119    (xdrproc_t) xdr_ATTR2res, "nfs_Write",
00120    MAKES_WRITE | NEEDS_CRED | CAN_BE_DUP | SUPPORTS_GSS},
00121   {nfs_Create, nfs_Create_Free, (xdrproc_t) xdr_CREATE2args,
00122    (xdrproc_t) xdr_DIROP2res, "nfs_Create",
00123    MAKES_WRITE | NEEDS_CRED | CAN_BE_DUP | SUPPORTS_GSS},
00124   {nfs_Remove, nfs_Remove_Free, (xdrproc_t) xdr_diropargs2,
00125    (xdrproc_t) xdr_nfsstat2, "nfs_Remove",
00126    MAKES_WRITE | NEEDS_CRED | CAN_BE_DUP | SUPPORTS_GSS},
00127   {nfs_Rename, nfs_Rename_Free, (xdrproc_t) xdr_RENAME2args,
00128    (xdrproc_t) xdr_nfsstat2, "nfs_Rename",
00129    MAKES_WRITE | NEEDS_CRED | CAN_BE_DUP | SUPPORTS_GSS},
00130   {nfs_Link, nfs_Link_Free, (xdrproc_t) xdr_LINK2args,
00131    (xdrproc_t) xdr_nfsstat2, "nfs_Link",
00132    MAKES_WRITE | NEEDS_CRED | CAN_BE_DUP | SUPPORTS_GSS},
00133   {nfs_Symlink, nfs_Symlink_Free, (xdrproc_t) xdr_SYMLINK2args,
00134    (xdrproc_t) xdr_nfsstat2, "nfs_Symlink",
00135    MAKES_WRITE | NEEDS_CRED | CAN_BE_DUP | SUPPORTS_GSS},
00136   {nfs_Mkdir, nfs_Mkdir_Free, (xdrproc_t) xdr_CREATE2args,
00137    (xdrproc_t) xdr_DIROP2res, "nfs_Mkdir",
00138    MAKES_WRITE | NEEDS_CRED | CAN_BE_DUP | SUPPORTS_GSS},
00139   {nfs_Rmdir, nfs_Rmdir_Free, (xdrproc_t) xdr_diropargs2,
00140    (xdrproc_t) xdr_nfsstat2, "nfs_Rmdir",
00141    MAKES_WRITE | NEEDS_CRED | CAN_BE_DUP | SUPPORTS_GSS},
00142   {nfs_Readdir, nfs2_Readdir_Free, (xdrproc_t) xdr_READDIR2args,
00143    (xdrproc_t) xdr_READDIR2res, "nfs_Readdir",
00144    NEEDS_CRED | SUPPORTS_GSS},
00145   {nfs_Fsstat, nfs_Fsstat_Free, (xdrproc_t) xdr_fhandle2,
00146    (xdrproc_t) xdr_STATFS2res, "nfs_Fsstat",
00147    NEEDS_CRED | SUPPORTS_GSS}
00148 };
00149 
00150 const nfs_function_desc_t nfs3_func_desc[] = {
00151   {nfs_Null, nfs_Null_Free, (xdrproc_t) xdr_void,
00152    (xdrproc_t) xdr_void,
00153    "nfs_Null",
00154    NOTHING_SPECIAL},
00155   {nfs_Getattr, nfs_Getattr_Free, (xdrproc_t) xdr_GETATTR3args,
00156    (xdrproc_t) xdr_GETATTR3res, "nfs_Getattr", NEEDS_CRED | SUPPORTS_GSS},
00157   {nfs_Setattr, nfs_Setattr_Free, (xdrproc_t) xdr_SETATTR3args,
00158    (xdrproc_t) xdr_SETATTR3res, "nfs_Setattr",
00159    MAKES_WRITE | NEEDS_CRED | CAN_BE_DUP | SUPPORTS_GSS},
00160   {nfs_Lookup, nfs3_Lookup_Free, (xdrproc_t) xdr_LOOKUP3args,
00161    (xdrproc_t) xdr_LOOKUP3res, "nfs_Lookup",
00162    NEEDS_CRED | SUPPORTS_GSS},
00163   {nfs3_Access, nfs3_Access_Free, (xdrproc_t) xdr_ACCESS3args,
00164    (xdrproc_t) xdr_ACCESS3res, "nfs3_Access",
00165    NEEDS_CRED | SUPPORTS_GSS},
00166   {nfs_Readlink, nfs3_Readlink_Free, (xdrproc_t) xdr_READLINK3args,
00167    (xdrproc_t) xdr_READLINK3res, "nfs_Readlink",
00168    NEEDS_CRED | SUPPORTS_GSS},
00169   {nfs_Read, nfs3_Read_Free, (xdrproc_t) xdr_READ3args,
00170    (xdrproc_t) xdr_READ3res, "nfs_Read",
00171    NEEDS_CRED | SUPPORTS_GSS},
00172   {nfs_Write, nfs_Write_Free, (xdrproc_t) xdr_WRITE3args,
00173    (xdrproc_t) xdr_WRITE3res, "nfs_Write",
00174    MAKES_WRITE | NEEDS_CRED | CAN_BE_DUP | SUPPORTS_GSS},
00175   {nfs_Create, nfs_Create_Free, (xdrproc_t) xdr_CREATE3args,
00176    (xdrproc_t) xdr_CREATE3res, "nfs_Create",
00177    MAKES_WRITE | NEEDS_CRED | CAN_BE_DUP | SUPPORTS_GSS},
00178   {nfs_Mkdir, nfs_Mkdir_Free, (xdrproc_t) xdr_MKDIR3args,
00179    (xdrproc_t) xdr_MKDIR3res, "nfs_Mkdir",
00180    MAKES_WRITE | NEEDS_CRED | CAN_BE_DUP | SUPPORTS_GSS},
00181   {nfs_Symlink, nfs_Symlink_Free, (xdrproc_t) xdr_SYMLINK3args,
00182    (xdrproc_t) xdr_SYMLINK3res, "nfs_Symlink",
00183    MAKES_WRITE | NEEDS_CRED | CAN_BE_DUP | SUPPORTS_GSS},
00184   {nfs3_Mknod, nfs3_Mknod_Free, (xdrproc_t) xdr_MKNOD3args,
00185    (xdrproc_t) xdr_MKNOD3res, "nfs3_Mknod",
00186    MAKES_WRITE | NEEDS_CRED | CAN_BE_DUP | SUPPORTS_GSS},
00187   {nfs_Remove, nfs_Remove_Free, (xdrproc_t) xdr_REMOVE3args,
00188    (xdrproc_t) xdr_REMOVE3res, "nfs_Remove",
00189    MAKES_WRITE | NEEDS_CRED | CAN_BE_DUP | SUPPORTS_GSS},
00190   {nfs_Rmdir, nfs_Rmdir_Free, (xdrproc_t) xdr_RMDIR3args,
00191    (xdrproc_t) xdr_RMDIR3res, "nfs_Rmdir",
00192    MAKES_WRITE | NEEDS_CRED | CAN_BE_DUP | SUPPORTS_GSS},
00193   {nfs_Rename, nfs_Rename_Free, (xdrproc_t) xdr_RENAME3args,
00194    (xdrproc_t) xdr_RENAME3res, "nfs_Rename",
00195    MAKES_WRITE | NEEDS_CRED | CAN_BE_DUP | SUPPORTS_GSS},
00196   {nfs_Link, nfs_Link_Free, (xdrproc_t) xdr_LINK3args,
00197    (xdrproc_t) xdr_LINK3res, "nfs_Link",
00198    MAKES_WRITE | NEEDS_CRED | CAN_BE_DUP | SUPPORTS_GSS},
00199   {nfs_Readdir, nfs3_Readdir_Free, (xdrproc_t) xdr_READDIR3args,
00200    (xdrproc_t) xdr_READDIR3res, "nfs_Readdir",
00201    NEEDS_CRED | SUPPORTS_GSS},
00202   {nfs3_Readdirplus, nfs3_Readdirplus_Free, (xdrproc_t) xdr_READDIRPLUS3args,
00203    (xdrproc_t) xdr_READDIRPLUS3res, "nfs3_Readdirplus",
00204    NEEDS_CRED | SUPPORTS_GSS},
00205   {nfs_Fsstat, nfs_Fsstat_Free, (xdrproc_t) xdr_FSSTAT3args,
00206    (xdrproc_t) xdr_FSSTAT3res, "nfs_Fsstat",
00207    NEEDS_CRED | SUPPORTS_GSS},
00208   {nfs3_Fsinfo, nfs3_Fsinfo_Free, (xdrproc_t) xdr_FSINFO3args,
00209    (xdrproc_t) xdr_FSINFO3res, "nfs3_Fsinfo",
00210    NEEDS_CRED},
00211   {nfs3_Pathconf, nfs3_Pathconf_Free, (xdrproc_t) xdr_PATHCONF3args,
00212    (xdrproc_t) xdr_PATHCONF3res, "nfs3_Pathconf",
00213    NEEDS_CRED | SUPPORTS_GSS},
00214   {nfs3_Commit, nfs3_Commit_Free, (xdrproc_t) xdr_COMMIT3args,
00215    (xdrproc_t) xdr_COMMIT3res, "nfs3_Commit",
00216    MAKES_WRITE | NEEDS_CRED | SUPPORTS_GSS}
00217 };
00218 
00219 /* Remeber that NFSv4 manages authentication though junction crossing, and
00220  * so does it for RO FS management (for each operation) */
00221 const nfs_function_desc_t nfs4_func_desc[] = {
00222   {nfs_Null, nfs_Null_Free, (xdrproc_t) xdr_void,
00223    (xdrproc_t) xdr_void, "nfs_Null",
00224    NOTHING_SPECIAL},
00225   {nfs4_Compound, nfs4_Compound_Free, (xdrproc_t) xdr_COMPOUND4args,
00226    (xdrproc_t) xdr_COMPOUND4res, "nfs4_Compound", NEEDS_CRED}
00227 };
00228 
00229 const nfs_function_desc_t mnt1_func_desc[] = {
00230   {mnt_Null, mnt_Null_Free, (xdrproc_t) xdr_void,
00231    (xdrproc_t) xdr_void, "mnt_Null",
00232    NOTHING_SPECIAL},
00233   {mnt_Mnt, mnt1_Mnt_Free, (xdrproc_t) xdr_dirpath,
00234    (xdrproc_t) xdr_fhstatus2, "mnt_Mnt",
00235    NEEDS_CRED},
00236   {mnt_Dump, mnt_Dump_Free, (xdrproc_t) xdr_void,
00237    (xdrproc_t) xdr_mountlist, "mnt_Dump",
00238    NOTHING_SPECIAL},
00239   {mnt_Umnt, mnt_Umnt_Free, (xdrproc_t) xdr_dirpath,
00240    (xdrproc_t) xdr_void, "mnt_Umnt",
00241    NOTHING_SPECIAL},
00242   {mnt_UmntAll, mnt_UmntAll_Free, (xdrproc_t) xdr_void,
00243    (xdrproc_t) xdr_void, "mnt_UmntAll",
00244    NOTHING_SPECIAL},
00245   {mnt_Export, mnt_Export_Free, (xdrproc_t) xdr_void,
00246    (xdrproc_t) xdr_exports, "mnt_Export",
00247    NOTHING_SPECIAL}
00248 };
00249 
00250 const nfs_function_desc_t mnt3_func_desc[] = {
00251   {mnt_Null, mnt_Null_Free, (xdrproc_t) xdr_void,
00252    (xdrproc_t) xdr_void, "mnt_Null",
00253    NOTHING_SPECIAL},
00254   {mnt_Mnt, mnt3_Mnt_Free, (xdrproc_t) xdr_dirpath,
00255    (xdrproc_t) xdr_mountres3, "mnt_Mnt",
00256    NEEDS_CRED},
00257   {mnt_Dump, mnt_Dump_Free, (xdrproc_t) xdr_void,
00258    (xdrproc_t) xdr_mountlist, "mnt_Dump",
00259    NOTHING_SPECIAL},
00260   {mnt_Umnt, mnt_Umnt_Free, (xdrproc_t) xdr_dirpath,
00261    (xdrproc_t) xdr_void, "mnt_Umnt",
00262    NOTHING_SPECIAL},
00263   {mnt_UmntAll, mnt_UmntAll_Free, (xdrproc_t) xdr_void,
00264    (xdrproc_t) xdr_void, "mnt_UmntAll",
00265    NOTHING_SPECIAL},
00266   {mnt_Export, mnt_Export_Free, (xdrproc_t) xdr_void,
00267    (xdrproc_t) xdr_exports, "mnt_Export",
00268    NOTHING_SPECIAL}
00269 };
00270 
00271 #define nlm4_Unsupported nlm_Null
00272 #define nlm4_Unsupported_Free nlm_Null_Free
00273 
00274 #ifdef _USE_NLM
00275 const nfs_function_desc_t nlm4_func_desc[] = {
00276   [NLMPROC4_NULL] = {
00277       nlm_Null, nlm_Null_Free, (xdrproc_t) xdr_void,
00278       (xdrproc_t) xdr_void, "nlm_Null",
00279       NOTHING_SPECIAL},
00280   [NLMPROC4_TEST] = {
00281       nlm4_Test, nlm4_Test_Free, (xdrproc_t) xdr_nlm4_testargs,
00282       (xdrproc_t) xdr_nlm4_testres, "nlm4_Test",
00283       NEEDS_CRED},
00284   [NLMPROC4_LOCK] = {
00285       nlm4_Lock, nlm4_Lock_Free, (xdrproc_t) xdr_nlm4_lockargs,
00286       (xdrproc_t) xdr_nlm4_res, "nlm4_Lock",
00287       NEEDS_CRED},
00288   [NLMPROC4_CANCEL] = {
00289       nlm4_Cancel, nlm4_Cancel_Free, (xdrproc_t) xdr_nlm4_cancargs,
00290       (xdrproc_t) xdr_nlm4_res, "nlm4_Cancel",
00291       NEEDS_CRED},
00292   [NLMPROC4_UNLOCK] = {
00293       nlm4_Unlock, nlm4_Unlock_Free, (xdrproc_t) xdr_nlm4_unlockargs,
00294       (xdrproc_t) xdr_nlm4_res, "nlm4_Unlock",
00295       NEEDS_CRED},
00296   [NLMPROC4_GRANTED] = {
00297       nlm4_Unsupported, nlm4_Unsupported_Free, (xdrproc_t) xdr_void,
00298       (xdrproc_t) xdr_void, "nlm4_Granted",
00299       NOTHING_SPECIAL},
00300   [NLMPROC4_TEST_MSG] = {
00301       nlm4_Test_Message, nlm4_Test_Free,
00302       (xdrproc_t) xdr_nlm4_testargs,
00303       (xdrproc_t) xdr_void, "nlm4_Test_msg",
00304       NEEDS_CRED},
00305   [NLMPROC4_LOCK_MSG] = {
00306       nlm4_Lock_Message, nlm4_Lock_Free,
00307       (xdrproc_t) xdr_nlm4_lockargs,
00308       (xdrproc_t) xdr_void, "nlm4_Lock_msg",
00309       NEEDS_CRED},
00310   [NLMPROC4_CANCEL_MSG] = {
00311       nlm4_Cancel_Message, nlm4_Cancel_Free,
00312       (xdrproc_t) xdr_nlm4_cancargs,
00313       (xdrproc_t) xdr_void, "nlm4_Cancel_msg",
00314       NEEDS_CRED},
00315   [NLMPROC4_UNLOCK_MSG] = {
00316       nlm4_Unlock_Message, nlm4_Unlock_Free,
00317       (xdrproc_t) xdr_nlm4_unlockargs,
00318       (xdrproc_t) xdr_void, "nlm4_Unlock_msg",
00319       NEEDS_CRED},
00320   [NLMPROC4_GRANTED_MSG] = {
00321       nlm4_Unsupported, nlm4_Unsupported_Free, (xdrproc_t) xdr_void,
00322       (xdrproc_t) xdr_void, "nlm4_Granted_msg",
00323       NOTHING_SPECIAL},
00324   [NLMPROC4_TEST_RES] = {
00325       nlm4_Unsupported, nlm4_Unsupported_Free, (xdrproc_t) xdr_void,
00326       (xdrproc_t) xdr_void, "nlm4_Test_res",
00327       NOTHING_SPECIAL},
00328   [NLMPROC4_LOCK_RES] = {
00329       nlm4_Unsupported, nlm4_Unsupported_Free, (xdrproc_t) xdr_void,
00330       (xdrproc_t) xdr_void, "nlm4_Lock_res",
00331       NOTHING_SPECIAL},
00332   [NLMPROC4_CANCEL_RES] = {
00333       nlm4_Unsupported, nlm4_Unsupported_Free, (xdrproc_t) xdr_void,
00334       (xdrproc_t) xdr_void, "nlm4_Cancel_res",
00335       NOTHING_SPECIAL},
00336   [NLMPROC4_UNLOCK_RES] = {
00337       nlm4_Unsupported, nlm4_Unsupported_Free, (xdrproc_t) xdr_void,
00338       (xdrproc_t) xdr_void, "nlm4_Unlock_res",
00339       NOTHING_SPECIAL},
00340   [NLMPROC4_GRANTED_RES] = {
00341       nlm4_Granted_Res, nlm4_Granted_Res_Free, (xdrproc_t) xdr_nlm4_res,
00342       (xdrproc_t) xdr_void, "nlm4_Granted_res",
00343       NEEDS_CRED},
00344   [NLMPROC4_SM_NOTIFY] = {
00345       nlm4_Sm_Notify, nlm4_Sm_Notify_Free,
00346       (xdrproc_t) xdr_nlm4_sm_notifyargs, (xdrproc_t) xdr_void,
00347       "nlm4_sm_notify",
00348       NOTHING_SPECIAL},
00349   [17] = {
00350       nlm4_Unsupported, nlm4_Unsupported_Free,
00351       (xdrproc_t) xdr_void, (xdrproc_t) xdr_void,
00352       "nlm4_Granted_res",
00353       NOTHING_SPECIAL},
00354   [18] = {
00355       nlm4_Unsupported, nlm4_Unsupported_Free,
00356       (xdrproc_t) xdr_void, (xdrproc_t) xdr_void,
00357       "nlm4_Granted_res",
00358       NOTHING_SPECIAL},
00359   [19] = {
00360       nlm4_Unsupported, nlm4_Unsupported_Free,
00361       (xdrproc_t) xdr_void, (xdrproc_t) xdr_void,
00362       "nlm4_Granted_res",
00363       NOTHING_SPECIAL},
00364   [NLMPROC4_SHARE] {nlm4_Share, nlm4_Share_Free,
00365                     (xdrproc_t) xdr_nlm4_shareargs, (xdrproc_t) xdr_nlm4_shareres,
00366                     "nlm4_Share",
00367                     NEEDS_CRED},
00368   [NLMPROC4_UNSHARE] = {nlm4_Unshare, nlm4_Unshare_Free,
00369                         (xdrproc_t) xdr_nlm4_shareargs, (xdrproc_t) xdr_nlm4_shareres,
00370                         "nlm4_Unshare",
00371                         NEEDS_CRED},
00372   [NLMPROC4_NM_LOCK] = {
00373                         /* NLM_NM_LOCK uses the same handling as NLM_LOCK except for
00374                          * monitoring, nlm4_Lock will make that determination.
00375                          */
00376                         nlm4_Lock, nlm4_Lock_Free,
00377                         (xdrproc_t) xdr_nlm4_lockargs, (xdrproc_t) xdr_nlm4_res,
00378                         "nlm4_Nm_lock",
00379                         NEEDS_CRED},
00380   [NLMPROC4_FREE_ALL] = {nlm4_Free_All, nlm4_Free_All_Free,
00381                          (xdrproc_t) xdr_nlm4_free_allargs, (xdrproc_t) xdr_void,
00382                          "nlm4_Free_all",
00383                          NOTHING_SPECIAL},
00384 };
00385 #endif                          /* _USE_NLM */
00386 
00387 #ifdef _USE_RQUOTA
00388 const nfs_function_desc_t rquota1_func_desc[] = {
00389   [0] = {
00390          rquota_Null, rquota_Null_Free, (xdrproc_t) xdr_void,
00391          (xdrproc_t) xdr_void, "rquota_Null",
00392          NOTHING_SPECIAL},
00393   [RQUOTAPROC_GETQUOTA] = {
00394       rquota_getquota, rquota_getquota_Free,
00395       (xdrproc_t) xdr_getquota_args,
00396       (xdrproc_t) xdr_getquota_rslt, "rquota_Getquota",
00397       NEEDS_CRED},
00398   [RQUOTAPROC_GETACTIVEQUOTA] = {
00399       rquota_getactivequota, rquota_getactivequota_Free,
00400       (xdrproc_t) xdr_getquota_args,
00401       (xdrproc_t) xdr_getquota_rslt, "rquota_Getactivequota",
00402       NEEDS_CRED},
00403   [RQUOTAPROC_SETQUOTA] = {
00404       rquota_setquota, rquota_setquota_Free,
00405       (xdrproc_t) xdr_setquota_args,
00406       (xdrproc_t) xdr_setquota_rslt, "rquota_Setactivequota",
00407       NEEDS_CRED},
00408   [RQUOTAPROC_SETACTIVEQUOTA] = {
00409       rquota_setactivequota, rquota_setactivequota_Free,
00410       (xdrproc_t) xdr_setquota_args,
00411       (xdrproc_t) xdr_setquota_rslt, "rquota_Getactivequota",
00412       NEEDS_CRED}
00413 };
00414 
00415 const nfs_function_desc_t rquota2_func_desc[] = {
00416     [0] = {
00417         rquota_Null, rquota_Null_Free, (xdrproc_t) xdr_void,
00418         (xdrproc_t) xdr_void, "rquota_Null",
00419         NOTHING_SPECIAL},
00420     [RQUOTAPROC_GETQUOTA] = {
00421         rquota_getquota, rquota_getquota_Free,
00422         (xdrproc_t) xdr_ext_getquota_args,
00423         (xdrproc_t) xdr_getquota_rslt, "rquota_Ext_Getquota",
00424         NEEDS_CRED},
00425   [RQUOTAPROC_GETACTIVEQUOTA] = {
00426       rquota_getactivequota, rquota_getactivequota_Free,
00427       (xdrproc_t) xdr_ext_getquota_args,
00428       (xdrproc_t) xdr_getquota_rslt,
00429       "rquota_Ext_Getactivequota",
00430       NEEDS_CRED},
00431     [RQUOTAPROC_SETQUOTA] = {
00432         rquota_setquota, rquota_setquota_Free,
00433         (xdrproc_t) xdr_ext_setquota_args,
00434         (xdrproc_t) xdr_setquota_rslt, "rquota_Ext_Setactivequota",
00435         NEEDS_CRED},
00436     [RQUOTAPROC_SETACTIVEQUOTA] = {
00437         rquota_setactivequota, rquota_setactivequota_Free,
00438         (xdrproc_t) xdr_ext_setquota_args,
00439         (xdrproc_t) xdr_setquota_rslt,
00440         "rquota_Ext_Getactivequota",
00441         NEEDS_CRED}
00442 };
00443 
00444 #endif                          /* _USE_RQUOTA */
00445 
00446 extern const char *pause_state_str[];
00447 
00461 int nfs_Init_gc_counter(void)
00462 {
00463   pthread_mutexattr_t mutexattr;
00464 
00465   if(pthread_mutexattr_init(&mutexattr) != 0)
00466     return -1;
00467 
00468   if(pthread_mutex_init(&lock_nb_current_gc_workers, &mutexattr) != 0)
00469     return -1;
00470 
00471   nb_current_gc_workers = 0;
00472 
00473   return 0;                     /* Success */
00474 }                               /* nfs_Init_gc_counter */
00475 
00476 struct timeval time_diff(struct timeval time_from, struct timeval time_to)
00477 {
00478 
00479   struct timeval result;
00480 
00481   if(time_to.tv_usec < time_from.tv_usec)
00482     {
00483       result.tv_sec = time_to.tv_sec - time_from.tv_sec - 1;
00484       result.tv_usec = 1000000 + time_to.tv_usec - time_from.tv_usec;
00485     }
00486   else
00487     {
00488       result.tv_sec = time_to.tv_sec - time_from.tv_sec;
00489       result.tv_usec = time_to.tv_usec - time_from.tv_usec;
00490     }
00491 
00492   return result;
00493 }
00494 
00499 int is_rpc_call_valid(SVCXPRT *xprt, struct svc_req *preq)
00500 {
00501   int lo_vers, hi_vers;
00502 
00503   if(preq->rq_prog == nfs_param.core_param.program[P_NFS])
00504     {
00505       /* If we go there, preq->rq_prog ==  nfs_param.core_param.program[P_NFS] */
00506       if(((preq->rq_vers != NFS_V2) || ((nfs_param.core_param.core_options & CORE_OPTION_NFSV2) == 0)) &&
00507          ((preq->rq_vers != NFS_V3) || ((nfs_param.core_param.core_options & CORE_OPTION_NFSV3) == 0)) &&
00508          ((preq->rq_vers != NFS_V4) || ((nfs_param.core_param.core_options & CORE_OPTION_NFSV4) == 0)))
00509         {
00510           if(xprt != NULL)
00511             {
00512               LogFullDebug(COMPONENT_DISPATCH,
00513                            "Invalid NFS Version #%d",
00514                            (int)preq->rq_vers);
00515               lo_vers = NFS_V4;
00516               hi_vers = NFS_V2;
00517               if((nfs_param.core_param.core_options & CORE_OPTION_NFSV2) != 0)
00518                 lo_vers = NFS_V2;
00519               if((nfs_param.core_param.core_options & CORE_OPTION_NFSV3) != 0)
00520                 {
00521                   if(lo_vers == NFS_V4)
00522                     lo_vers = NFS_V3;
00523                   hi_vers = NFS_V3;
00524                 }
00525               if((nfs_param.core_param.core_options & CORE_OPTION_NFSV4) != 0)
00526                 hi_vers = NFS_V4;
00527               svcerr_progvers2(xprt, preq, lo_vers, hi_vers);  /* Bad NFS version */
00528             }
00529           return FALSE;
00530         }
00531       else if(((preq->rq_vers == NFS_V2) && (preq->rq_proc > NFSPROC_STATFS)) ||
00532               ((preq->rq_vers == NFS_V3) && (preq->rq_proc > NFSPROC3_COMMIT)) ||
00533               ((preq->rq_vers == NFS_V4) && (preq->rq_proc > NFSPROC4_COMPOUND)))
00534         {
00535           if(xprt != NULL)
00536             svcerr_noproc2(xprt, preq);
00537           return FALSE;
00538         }
00539       return TRUE;
00540     }
00541 
00542   if(preq->rq_prog == nfs_param.core_param.program[P_MNT] &&
00543      ((nfs_param.core_param.core_options & (CORE_OPTION_NFSV2 | CORE_OPTION_NFSV3)) != 0))
00544     {
00545       /* Call is with MOUNTPROG */
00546       /* Verify mount version and report error if invalid */
00547       lo_vers = MOUNT_V1;
00548       hi_vers = MOUNT_V3;
00549 
00550       /* Some clients may use the wrong mount version to umount, so always allow umount,
00551        * otherwise only allow request if the appropriate mount version is enabled.
00552        * also need to allow dump and export, so just disallow mount if version not supported
00553        */
00554       if((preq->rq_vers == MOUNT_V1) &&
00555          (((nfs_param.core_param.core_options & CORE_OPTION_NFSV2) != 0) ||
00556           (preq->rq_proc != MOUNTPROC2_MNT)))
00557         {
00558           if(preq->rq_proc > MOUNTPROC2_EXPORT)
00559             {
00560               if(xprt != NULL)
00561                 svcerr_noproc2(xprt, preq);
00562               return FALSE;
00563             }
00564           return TRUE;
00565         }
00566       else if((preq->rq_vers == MOUNT_V3) &&
00567               (((nfs_param.core_param.core_options & CORE_OPTION_NFSV3) != 0) ||
00568                (preq->rq_proc != MOUNTPROC2_MNT)))
00569         {
00570           if(preq->rq_proc > MOUNTPROC3_EXPORT)
00571             {
00572               if(xprt != NULL)
00573                   svcerr_noproc2(xprt, preq);
00574               return FALSE;
00575             }
00576           return TRUE;
00577         }
00578 
00579       if(xprt != NULL)
00580         {
00581           /* Bad MOUNT version - set the hi and lo versions and report error */
00582           if((nfs_param.core_param.core_options & CORE_OPTION_NFSV2) == 0)
00583             lo_vers = MOUNT_V3;
00584           if((nfs_param.core_param.core_options & CORE_OPTION_NFSV3) == 0)
00585             hi_vers = MOUNT_V1;
00586 
00587           LogFullDebug(COMPONENT_DISPATCH,
00588                        "Invalid Mount Version #%d",
00589                        (int)preq->rq_vers);
00590           svcerr_progvers2(xprt, preq, lo_vers, hi_vers);
00591         }
00592       return FALSE;
00593     }
00594 
00595 #ifdef _USE_NLM
00596   if(preq->rq_prog == nfs_param.core_param.program[P_NLM] &&
00597           ((nfs_param.core_param.core_options & CORE_OPTION_NFSV3) != 0))
00598     {
00599       /* Call is with NLMPROG */
00600       if(preq->rq_vers != NLM4_VERS)
00601         {
00602           /* Bad NLM version */
00603           LogFullDebug(COMPONENT_DISPATCH,
00604                        "Invalid NLM Version #%d",
00605                        (int)preq->rq_vers);
00606           if(xprt != NULL)
00607             svcerr_progvers2(xprt, preq, NLM4_VERS, NLM4_VERS);
00608           return FALSE;
00609         }
00610       if(preq->rq_proc > NLMPROC4_FREE_ALL)
00611         {
00612           if(xprt != NULL)
00613              svcerr_noproc2(xprt, preq);
00614           return FALSE;
00615         }
00616       return TRUE;
00617     }
00618 #endif                          /* _USE_NLM */
00619 
00620 #ifdef _USE_RQUOTA
00621    if(preq->rq_prog == nfs_param.core_param.program[P_RQUOTA])
00622      {
00623        /* Call is with NLMPROG */
00624        if((preq->rq_vers != RQUOTAVERS) &&
00625           (preq->rq_vers != EXT_RQUOTAVERS))
00626          {
00627            /* Bad NLM version */
00628            if(xprt != NULL)
00629              {
00630                LogFullDebug(COMPONENT_DISPATCH,
00631                             "Invalid RQUOTA Version #%d",
00632                             (int)preq->rq_vers);
00633                svcerr_progvers2(xprt, preq, RQUOTAVERS, EXT_RQUOTAVERS);
00634              }
00635            return FALSE;
00636          }
00637        if (((preq->rq_vers == RQUOTAVERS) &&
00638             (preq->rq_proc > RQUOTAPROC_SETACTIVEQUOTA)) ||
00639            ((preq->rq_vers == EXT_RQUOTAVERS) &&
00640             (preq->rq_proc > RQUOTAPROC_SETACTIVEQUOTA)))
00641         {
00642           if(xprt != NULL)
00643             svcerr_noproc2(xprt, preq);
00644           return FALSE;
00645         }
00646       return TRUE;
00647      }
00648 #endif                          /* _USE_QUOTA */
00649 
00650   /* No such program */
00651   if(xprt != NULL)
00652     {
00653       LogFullDebug(COMPONENT_DISPATCH,
00654                    "Invalid Program number #%d",
00655                    (int)preq->rq_prog);
00656       svcerr_noprog2(xprt, preq);        /* This is no NFS, MOUNT program, exit... */
00657     }
00658   return FALSE;
00659 }
00660 
00661 /*
00662  * Extract nfs function descriptor from nfs request.
00663  */
00664 const nfs_function_desc_t *nfs_rpc_get_funcdesc(nfs_request_data_t *preqnfs)
00665 {
00666   struct svc_req *req = &preqnfs->req;
00667 
00668   /* Validate rpc call, but don't report any errors here */
00669   if(is_rpc_call_valid(preqnfs->xprt, req) == FALSE)
00670     {
00671       LogFullDebug(COMPONENT_DISPATCH,
00672                    "INVALID_FUNCDESC for Program %d, Version %d, "
00673                    "Function %d after is_rpc_call_valid",
00674                    (int)req->rq_prog, (int)req->rq_vers, (int)req->rq_proc);
00675       return INVALID_FUNCDESC;
00676     }
00677 
00678   if(req->rq_prog == nfs_param.core_param.program[P_NFS])
00679     {
00680       if(req->rq_vers == NFS_V2)
00681         return &nfs2_func_desc[req->rq_proc];
00682       else if(req->rq_vers == NFS_V3)
00683         return &nfs3_func_desc[req->rq_proc];
00684       else
00685         return &nfs4_func_desc[req->rq_proc];
00686     }
00687 
00688   if(req->rq_prog == nfs_param.core_param.program[P_MNT])
00689     {
00690       if(req->rq_vers == MOUNT_V1)
00691         return &mnt1_func_desc[req->rq_proc];
00692       else
00693         return &mnt3_func_desc[req->rq_proc];
00694     }
00695 
00696 #ifdef _USE_NLM
00697   if(req->rq_prog == nfs_param.core_param.program[P_NLM])
00698     {
00699       return &nlm4_func_desc[req->rq_proc];
00700     }
00701 #endif                          /* _USE_NLM */
00702 
00703 #ifdef _USE_RQUOTA
00704   if(req->rq_prog == nfs_param.core_param.program[P_RQUOTA])
00705     {
00706       if(req->rq_vers == RQUOTAVERS)
00707         return &rquota1_func_desc[req->rq_proc];
00708       else
00709         return &rquota2_func_desc[req->rq_proc];
00710     }
00711 #endif                          /* _USE_RQUOTA */
00712 
00713   /* Oops, should never get here! */
00714   svcerr_noprog2(preqnfs->xprt, req);
00715   LogFullDebug(COMPONENT_DISPATCH,
00716                "INVALID_FUNCDESC for Program %d, Version %d, Function %d",
00717                (int)req->rq_prog, (int)req->rq_vers, (int)req->rq_proc);
00718   return INVALID_FUNCDESC;
00719 }
00720 
00721 /*
00722  * Extract RPC argument.
00723  */
00724 int nfs_rpc_get_args(nfs_request_data_t *preqnfs, const nfs_function_desc_t *pfuncdesc)
00725 {
00726   SVCXPRT *xprt = preqnfs->xprt;
00727   nfs_arg_t *parg_nfs = &preqnfs->arg_nfs;
00728 
00729   memset(parg_nfs, 0, sizeof(nfs_arg_t));
00730 
00731   LogFullDebug(COMPONENT_DISPATCH,
00732                "Before svc_getargs on socket %d, xprt=%p",
00733                xprt->xp_fd, xprt);
00734 
00735   if(svc_getargs(xprt, pfuncdesc->xdr_decode_func, (caddr_t) parg_nfs) == FALSE)
00736     {
00737       struct svc_req *req = &preqnfs->req;
00738       LogMajor(COMPONENT_DISPATCH,
00739                    "svc_getargs failed for Program %d, Version %d, Function %d xid=%u",
00740                (int)req->rq_prog, (int)req->rq_vers, (int)req->rq_proc,
00741                req->rq_xid);
00742       svcerr_decode2(xprt, req);
00743       return FALSE;
00744     }
00745 
00746   return TRUE;
00747 }
00748 
00757 static void nfs_rpc_execute(request_data_t *preq,
00758                             nfs_worker_data_t *pworker_data)
00759 {
00760   unsigned int export_check_result;
00761   exportlist_t *pexport = NULL;
00762   nfs_request_data_t *preqnfs = preq->r_u.nfs;
00763   nfs_arg_t *parg_nfs = &preqnfs->arg_nfs;
00764   nfs_res_t res_nfs;
00765   short exportid;
00766   LRU_list_t *lru_dupreq = NULL;
00767   struct svc_req *req = &preqnfs->req;
00768   SVCXPRT *xprt = preqnfs->xprt;
00769   nfs_stat_type_t stat_type;
00770   sockaddr_t hostaddr;
00771   int port;
00772   int rc;
00773   int do_dupreq_cache;
00774   dupreq_status_t dpq_status;
00775   exportlist_client_entry_t related_client;
00776   struct user_cred user_credentials;
00777   int   update_per_share_stats;
00778   fsal_op_context_t * pfsal_op_ctx = NULL ;
00779 
00780   struct timeval *timer_start = &pworker_data->timer_start;
00781   struct timeval timer_end;
00782   struct timeval timer_diff;
00783   struct timeval queue_timer_diff;
00784   nfs_request_latency_stat_t latency_stat;
00785 
00786   memset(&related_client, 0, sizeof(exportlist_client_entry_t));
00787 
00788   /* Get the value from the worker data */
00789   lru_dupreq = pworker_data->duplicate_request;
00790 
00791   /* initializing RPC structure */
00792   memset(&res_nfs, 0, sizeof(res_nfs));
00793 
00794   /* If we reach this point, there was no dupreq cache hit or no dup req cache
00795    * was necessary.  Get NFS function descriptor. */
00796   pworker_data->pfuncdesc = nfs_rpc_get_funcdesc(preqnfs);
00797   if(pworker_data->pfuncdesc == INVALID_FUNCDESC)
00798     return;
00799 
00800   /* XXX must hold lock when calling any TI-RPC channel function,
00801    * including svc_sendreply2 and the svcerr_* calls */
00802 
00803   if(copy_xprt_addr(&hostaddr, xprt) == 0)
00804     {
00805       LogFullDebug(COMPONENT_DISPATCH,
00806                    "copy_xprt_addr failed for Program %d, Version %d, "
00807                    "Function %d",
00808                    (int)req->rq_prog, (int)req->rq_vers,
00809                    (int)req->rq_proc);
00810       /* XXX move lock wrapper into RPC API */
00811       svc_dplx_lock_x(xprt, &pworker_data->sigmask);
00812       svcerr_systemerr2(xprt, req);
00813       svc_dplx_unlock_x(xprt, &pworker_data->sigmask);
00814       return;
00815     }
00816 
00817   port = get_port(&hostaddr);
00818 
00819   if(isDebug(COMPONENT_DISPATCH))
00820     {
00821       char addrbuf[SOCK_NAME_MAX];
00822       sprint_sockaddr(&hostaddr, addrbuf, sizeof(addrbuf));
00823       LogDebug(COMPONENT_DISPATCH,
00824                "Request from %s for Program %d, Version %d, Function %d "
00825                "has xid=%u",
00826                addrbuf,
00827                (int)req->rq_prog, (int)req->rq_vers, (int)req->rq_proc,
00828                req->rq_xid);
00829     }
00830 
00831   do_dupreq_cache = pworker_data->pfuncdesc->dispatch_behaviour & CAN_BE_DUP;
00832   LogFullDebug(COMPONENT_DISPATCH, "do_dupreq_cache = %d", do_dupreq_cache);
00833   dpq_status = nfs_dupreq_add_not_finished(req, &res_nfs);
00834   switch(dpq_status)
00835     {
00836       /* a new request, continue processing it */
00837     case DUPREQ_SUCCESS:
00838       LogFullDebug(COMPONENT_DISPATCH, "Current request is not duplicate.");
00839       break;
00840       /* Found the reuqest in the dupreq cache. It's an old request so resend
00841        * old reply. */
00842     case DUPREQ_ALREADY_EXISTS:
00843       if(do_dupreq_cache)
00844         {
00845           /* Request was known, use the previous reply */
00846           LogFullDebug(COMPONENT_DISPATCH,
00847                        "NFS DISPATCHER: DupReq Cache Hit: using previous "
00848                        "reply, rpcxid=%u",
00849                        req->rq_xid);
00850 
00851           LogFullDebug(COMPONENT_DISPATCH,
00852                        "Before svc_sendreply on socket %d (dup req)",
00853                        xprt->xp_fd);
00854 
00855           svc_dplx_lock_x(xprt, &pworker_data->sigmask);
00856           if(svc_sendreply2
00857              (xprt, req, pworker_data->pfuncdesc->xdr_encode_func,
00858               (caddr_t) &res_nfs) == FALSE)
00859             {
00860               LogDebug(COMPONENT_DISPATCH,
00861                        "NFS DISPATCHER: FAILURE: Error while calling "
00862                        "svc_sendreply");
00863               svcerr_systemerr2(xprt, req);
00864             }
00865           svc_dplx_unlock_x(xprt, &pworker_data->sigmask);
00866 
00867           LogFullDebug(COMPONENT_DISPATCH,
00868                        "After svc_sendreply on socket %d (dup req)",
00869                        xprt->xp_fd);
00870           return;
00871         }
00872       else
00873         {
00874           LogCrit(COMPONENT_DISPATCH,
00875                   "Error: Duplicate request rejected because it was found "
00876                   "in the cache but is not allowed to be cached.");
00877           svc_dplx_lock_x(xprt, &pworker_data->sigmask);
00878           svcerr_systemerr2(xprt, req);
00879           svc_dplx_unlock_x(xprt, &pworker_data->sigmask);
00880           return;
00881         }
00882       break;
00883 
00884       /* Another thread owns the request */
00885     case DUPREQ_BEING_PROCESSED:
00886       LogFullDebug(COMPONENT_DISPATCH,
00887                    "Dupreq xid=%u was asked for process since another thread "
00888                    "manage it, reject for avoiding threads starvation...",
00889                    req->rq_xid);
00890       /* Free the arguments */
00891       svc_dplx_lock_x(xprt, &pworker_data->sigmask);
00892       if((preqnfs->req.rq_vers == 2) ||
00893          (preqnfs->req.rq_vers == 3) ||
00894          (preqnfs->req.rq_vers == 4)) 
00895         if(!SVC_FREEARGS(xprt, pworker_data->pfuncdesc->xdr_decode_func,
00896                          (caddr_t) parg_nfs))
00897           {
00898             LogCrit(COMPONENT_DISPATCH,
00899                     "NFS DISPATCHER: FAILURE: Bad SVC_FREEARGS for %s",
00900                     pworker_data->pfuncdesc->funcname);
00901           }
00902       svc_dplx_unlock_x(xprt, &pworker_data->sigmask);
00903       /* Ignore the request, send no error */
00904       return;
00905 
00906       /* something is very wrong with the duplicate request cache */
00907     case DUPREQ_NOT_FOUND:
00908       LogCrit(COMPONENT_DISPATCH,
00909               "Did not find the request in the duplicate request cache and "
00910               "couldn't add the request.");
00911       svc_dplx_lock_x(xprt, &pworker_data->sigmask);
00912       svcerr_systemerr2(xprt, req);
00913       svc_dplx_unlock_x(xprt, &pworker_data->sigmask);
00914       return;
00915 
00916       /* oom */
00917     case DUPREQ_INSERT_MALLOC_ERROR:
00918       LogCrit(COMPONENT_DISPATCH,
00919               "Cannot process request, not enough memory available!");
00920       svc_dplx_lock_x(xprt, &pworker_data->sigmask);
00921       svcerr_systemerr2(xprt, req);
00922       svc_dplx_unlock_x(xprt, &pworker_data->sigmask);
00923       return;
00924 
00925     default:
00926       LogCrit(COMPONENT_DISPATCH,
00927               "Unknown duplicate request cache status. This should never be "
00928               "reached!");
00929       svc_dplx_lock_x(xprt, &pworker_data->sigmask);
00930       svcerr_systemerr2(xprt, req);
00931       svc_dplx_unlock_x(xprt, &pworker_data->sigmask);
00932       return;
00933     }
00934 
00935   /* Get the export entry */
00936   if(req->rq_prog == nfs_param.core_param.program[P_NFS])
00937     {
00938       /* The NFSv2 and NFSv3 functions'arguments always begin with the file
00939        * handle (but not the NULL function).  This hook is used to get the
00940        * fhandle with the arguments and so determine the export entry to be
00941        * used.  In NFSv4, junction traversal is managed by the protocol itself
00942        * so the whole export list is provided to NFSv4 request. */
00943 
00944       switch (req->rq_vers)
00945         {
00946         case NFS_V2:
00947           if(req->rq_proc != NFSPROC_NULL)
00948             {
00949               exportid = nfs2_FhandleToExportId((fhandle2 *) parg_nfs);
00950 
00951               if(exportid < 0 ||
00952                  (pexport = nfs_Get_export_by_id(nfs_param.pexportlist,
00953                                                  exportid)) == NULL ||
00954                  (pexport->options & EXPORT_OPTION_NFSV2) == 0)
00955                 {
00956                   /* Reject the request for authentication reason (incompatible
00957                    * file handle) */
00958                   if(isInfo(COMPONENT_DISPATCH))
00959                     {
00960                       char dumpfh[1024];
00961                       char *reason;
00962                       char addrbuf[SOCK_NAME_MAX];
00963                       sprint_sockaddr(&hostaddr, addrbuf, sizeof(addrbuf));
00964                       if(exportid < 0)
00965                         reason = "has badly formed handle";
00966                       else if(pexport == NULL)
00967                         reason = "has invalid export";
00968                       else
00969                         reason = "V2 not allowed on this export";
00970                       sprint_fhandle2(dumpfh, (fhandle2 *) parg_nfs);
00971                       LogMajor(COMPONENT_DISPATCH,
00972                                "NFS2 Request from host %s %s, proc=%d, FH=%s",
00973                                addrbuf, reason,
00974                                (int)req->rq_proc, dumpfh);
00975                     }
00976                   /* Bad argument */
00977                   svc_dplx_lock_x(xprt, &pworker_data->sigmask);
00978                   svcerr_auth2(xprt, req, AUTH_FAILED);
00979                   svc_dplx_unlock_x(xprt, &pworker_data->sigmask);
00980                   if (nfs_dupreq_delete(req) != DUPREQ_SUCCESS)
00981                     {
00982                       LogCrit(COMPONENT_DISPATCH,
00983                               "Attempt to delete duplicate request failed on "
00984                               "line %d", __LINE__);
00985                     }
00986                   return;
00987                 }
00988 
00989               LogFullDebug(COMPONENT_DISPATCH,
00990                            "Found export entry for dirname=%s as exportid=%d",
00991                            pexport->dirname, pexport->id);
00992             }
00993           else
00994             pexport = nfs_param.pexportlist;
00995 
00996           break;
00997 
00998         case NFS_V3:
00999           if(req->rq_proc != NFSPROC_NULL)
01000             {
01001               exportid = nfs3_FhandleToExportId((nfs_fh3 *) parg_nfs);
01002 
01003               if(exportid < 0 ||
01004                  (pexport = nfs_Get_export_by_id(nfs_param.pexportlist,
01005                                                  exportid)) == NULL ||
01006                  (pexport->options & EXPORT_OPTION_NFSV3) == 0)
01007                 {
01008                   /* Reject the request for authentication reason (incompatible
01009                    * file handle) */
01010                   if(isInfo(COMPONENT_DISPATCH))
01011                     {
01012                       char dumpfh[1024];
01013                       char *reason;
01014                       char addrbuf[SOCK_NAME_MAX];
01015                       sprint_sockaddr(&hostaddr, addrbuf, sizeof(addrbuf));
01016                       if(exportid < 0)
01017                         reason = "has badly formed handle";
01018                       else if(pexport == NULL)
01019                         reason = "has invalid export";
01020                       else
01021                         reason = "V3 not allowed on this export";
01022                       sprint_fhandle3(dumpfh, (nfs_fh3 *) parg_nfs);
01023                       LogMajor(COMPONENT_DISPATCH,
01024                                "NFS3 Request from host %s %s, proc=%d, FH=%s",
01025                                addrbuf, reason,
01026                                (int)req->rq_proc, dumpfh);
01027                     }
01028                   /* Bad argument */
01029                   svc_dplx_lock_x(xprt, &pworker_data->sigmask);
01030                   svcerr_auth2(xprt, req, AUTH_FAILED);
01031                   svc_dplx_unlock_x(xprt, &pworker_data->sigmask);
01032                   if (nfs_dupreq_delete(req) != DUPREQ_SUCCESS)
01033                     {
01034                       LogCrit(COMPONENT_DISPATCH,
01035                               "Attempt to delete duplicate request failed on "
01036                               "line %d", __LINE__);
01037                     }
01038                   return;
01039                 }
01040 
01041               LogFullDebug(COMPONENT_DISPATCH,
01042                            "Found export entry for dirname=%s as exportid=%d",
01043                            pexport->dirname, pexport->id);
01044             }
01045           else
01046             pexport = nfs_param.pexportlist;
01047 
01048           break;
01049 
01050         case NFS_V4:
01051           /* NFSv4 requires entire export list */
01052           pexport = nfs_param.pexportlist;
01053           break;
01054 
01055         default:
01056           /* NFSv4 or invalid version (which should never get here) */
01057           pexport = nfs_param.pexportlist;
01058           break;
01059         }                       /* switch( ptr_req->rq_vers ) */
01060     }
01061 #ifdef _USE_NLM
01062   else if(req->rq_prog == nfs_param.core_param.program[P_NLM])
01063     {
01064       netobj *pfh3 = NULL;
01065 
01066       switch(req->rq_proc)
01067         {
01068           case NLMPROC4_NULL:
01069           case NLMPROC4_TEST_RES:
01070           case NLMPROC4_LOCK_RES:
01071           case NLMPROC4_CANCEL_RES:
01072           case NLMPROC4_UNLOCK_RES:
01073           case NLMPROC4_GRANTED_RES:
01074           case NLMPROC4_SM_NOTIFY:
01075           case NLMPROC4_FREE_ALL:
01076             break;
01077 
01078           case NLMPROC4_TEST:
01079           case NLMPROC4_TEST_MSG:
01080           case NLMPROC4_GRANTED:
01081           case NLMPROC4_GRANTED_MSG:
01082             pfh3 = &parg_nfs->arg_nlm4_test.alock.fh;
01083             break;
01084 
01085           case NLMPROC4_LOCK:
01086           case NLMPROC4_LOCK_MSG:
01087           case NLMPROC4_NM_LOCK:
01088             pfh3 = &parg_nfs->arg_nlm4_lock.alock.fh;
01089             break;
01090 
01091           case NLMPROC4_CANCEL:
01092           case NLMPROC4_CANCEL_MSG:
01093             pfh3 = &parg_nfs->arg_nlm4_cancel.alock.fh;
01094             break;
01095 
01096           case NLMPROC4_UNLOCK:
01097           case NLMPROC4_UNLOCK_MSG:
01098             pfh3 = &parg_nfs->arg_nlm4_unlock.alock.fh;
01099             break;
01100 
01101           case NLMPROC4_SHARE:
01102           case NLMPROC4_UNSHARE:
01103             pfh3 = &parg_nfs->arg_nlm4_share.share.fh;
01104             break;
01105         }
01106       if(pfh3 != NULL)
01107         {
01108           exportid = nlm4_FhandleToExportId(pfh3);
01109 
01110           if(exportid < 0 ||
01111              (pexport = nfs_Get_export_by_id(nfs_param.pexportlist,
01112                                              exportid)) == NULL ||
01113              (pexport->options & EXPORT_OPTION_NFSV3) == 0)
01114             {
01115               /* Reject the request for authentication reason (incompatible 
01116                * file handle) */
01117               if(isInfo(COMPONENT_DISPATCH))
01118                 {
01119                   char dumpfh[1024];
01120                   char *reason;
01121                   char addrbuf[SOCK_NAME_MAX];
01122                   sprint_sockaddr(&hostaddr, addrbuf, sizeof(addrbuf));
01123                   if(exportid < 0)
01124                     reason = "has badly formed handle";
01125                   else if(pexport == NULL)
01126                     reason = "has invalid export";
01127                   else
01128                     reason = "V3 not allowed on this export";
01129                   sprint_fhandle_nlm(dumpfh, pfh3);
01130                   LogMajor(COMPONENT_DISPATCH,
01131                            "NLM4 Request from host %s %s, proc=%d, FH=%s",
01132                            addrbuf, reason,
01133                            (int)req->rq_proc, dumpfh);
01134                 }
01135               /* Bad argument */
01136               svc_dplx_lock_x(xprt, &pworker_data->sigmask);
01137               svcerr_auth2(xprt, req, AUTH_FAILED);
01138               svc_dplx_unlock_x(xprt, &pworker_data->sigmask);
01139               if (nfs_dupreq_delete(req) != DUPREQ_SUCCESS)
01140                 {
01141                   LogCrit(COMPONENT_DISPATCH,
01142                           "Attempt to delete duplicate request failed on line "
01143                           "%d", __LINE__);
01144                 }
01145               return;
01146             }
01147 
01148           LogFullDebug(COMPONENT_DISPATCH,
01149                        "Found export entry for dirname=%s as exportid=%d",
01150                        pexport->dirname, pexport->id);
01151         }
01152       else
01153         pexport = nfs_param.pexportlist;
01154     }
01155 #endif                          /* _USE_NLM */
01156   else
01157     {
01158       /* All other protocols use the whole export list */
01159       pexport = nfs_param.pexportlist;
01160     }
01161 
01162   if(pworker_data->pfuncdesc->dispatch_behaviour & SUPPORTS_GSS)
01163     {
01164       /* Test if export allows the authentication provided */
01165       if (nfs_export_check_security(req, pexport) == FALSE)
01166         {
01167           svc_dplx_lock_x(xprt, &pworker_data->sigmask);
01168           svcerr_auth2(xprt, req, AUTH_TOOWEAK);
01169           svc_dplx_unlock_x(xprt, &pworker_data->sigmask);
01170           if (nfs_dupreq_delete(req) != DUPREQ_SUCCESS)
01171             {
01172               LogCrit(COMPONENT_DISPATCH,
01173                       "Attempt to delete duplicate request failed on "
01174                       "line %d", __LINE__);
01175             }
01176           return;
01177         }
01178     }
01179 
01180   /* Zero out timers prior to starting processing */
01181   memset(&timer_end, 0, sizeof(struct timeval));
01182   memset(&timer_diff, 0, sizeof(struct timeval));
01183   memset(&queue_timer_diff, 0, sizeof(struct timeval));
01184 
01185   /*
01186    * It is now time for checking if export list allows the machine to perform
01187    * the request
01188    */
01189   pworker_data->hostaddr = hostaddr;
01190 
01191   /* Check if client is using a privileged port, but only for NFS protocol */
01192   if ((req->rq_prog == nfs_param.core_param.program[P_NFS]) &&
01193       (req->rq_proc != 0))
01194     {
01195       if ((pexport->options & EXPORT_OPTION_PRIVILEGED_PORT) &&
01196          (port >= IPPORT_RESERVED))
01197         {
01198           LogInfo(COMPONENT_DISPATCH,
01199                   "Port %d is too high for this export entry, rejecting client",
01200                   port);
01201           svc_dplx_lock_x(xprt, &pworker_data->sigmask);
01202           svcerr_auth2(xprt, req, AUTH_TOOWEAK);
01203           svc_dplx_unlock_x(xprt, &pworker_data->sigmask);
01204           /* XXX */
01205           pworker_data->current_xid = 0;    /* No more xid managed */
01206 
01207           if (nfs_dupreq_delete(req) != DUPREQ_SUCCESS)
01208             {
01209               LogCrit(COMPONENT_DISPATCH,
01210                       "Attempt to delete duplicate request failed on line %d",
01211                       __LINE__);
01212             }
01213           return;
01214         }
01215     }
01216 
01217   if (pworker_data->pfuncdesc->dispatch_behaviour & NEEDS_CRED)
01218     {
01219       if (get_req_uid_gid(req, pexport, &user_credentials) == FALSE)
01220         {
01221           LogInfo(COMPONENT_DISPATCH,
01222                   "could not get uid and gid, rejecting client");
01223           svc_dplx_lock_x(xprt, &pworker_data->sigmask);
01224           svcerr_auth2(xprt, req, AUTH_TOOWEAK);
01225           svc_dplx_unlock_x(xprt, &pworker_data->sigmask);
01226           /* XXX */
01227           pworker_data->current_xid = 0;    /* No more xid managed */
01228 
01229           if (nfs_dupreq_delete(req) != DUPREQ_SUCCESS)
01230             {
01231               LogCrit(COMPONENT_DISPATCH,
01232                       "Attempt to delete duplicate request failed on line %d",
01233                       __LINE__);
01234             }
01235           return;
01236         }
01237     }
01238 
01239   /* Be careful (Issue #66) : it makes no sense to check access for
01240    * a MOUNT request */
01241   if(req->rq_prog != nfs_param.core_param.program[P_MNT])
01242    {
01243      LogFullDebug(COMPONENT_DISPATCH,
01244                   "nfs_rpc_execute about to call nfs_export_check_access");
01245      export_check_result = nfs_export_check_access(&pworker_data->hostaddr,
01246                                                    req,
01247                                                    pexport,
01248                                                    nfs_param.core_param.program[P_NFS],
01249                                                    nfs_param.core_param.program[P_MNT],
01250                                                    pworker_data->ht_ip_stats,
01251                                                    ip_stats_pool,
01252                                                    &related_client,
01253                                                    &user_credentials,
01254                                                    (pworker_data->pfuncdesc->dispatch_behaviour & MAKES_WRITE) == MAKES_WRITE);
01255    }
01256   else
01257    {
01258       LogFullDebug(COMPONENT_DISPATCH,
01259                    "Call to a function from the MOUNT protocol, no call to nfs_export_check_access() required" ) ;
01260       export_check_result = EXPORT_PERMISSION_GRANTED ;
01261    }
01262 
01263   if (export_check_result == EXPORT_PERMISSION_DENIED)
01264     {
01265       char addrbuf[SOCK_NAME_MAX];
01266       sprint_sockaddr(&hostaddr, addrbuf, sizeof(addrbuf));
01267       LogInfo(COMPONENT_DISPATCH,
01268               "Host %s is not allowed to access this export entry, vers=%d, proc=%d",
01269               addrbuf,
01270               (int)req->rq_vers, (int)req->rq_proc);
01271       svc_dplx_lock_x(xprt, &pworker_data->sigmask);
01272       svcerr_auth2(xprt, req, AUTH_TOOWEAK);
01273       svc_dplx_unlock_x(xprt, &pworker_data->sigmask);
01274       /* XXX */
01275       pworker_data->current_xid = 0;        /* No more xid managed */
01276 
01277       if (nfs_dupreq_delete(req) != DUPREQ_SUCCESS)
01278         {
01279           LogCrit(COMPONENT_DISPATCH,
01280                   "Attempt to delete duplicate request failed on line %d",
01281                   __LINE__);
01282         }
01283       return;
01284     }
01285   else if ((export_check_result == EXPORT_WRITE_ATTEMPT_WHEN_RO) ||
01286            (export_check_result == EXPORT_WRITE_ATTEMPT_WHEN_MDONLY_RO))
01287     {
01288       LogDebug(COMPONENT_DISPATCH,
01289                "Dropping request because nfs_export_check_access() reported this is a RO filesystem.");
01290       if(req->rq_prog == nfs_param.core_param.program[P_NFS])
01291         {
01292           if(req->rq_vers == NFS_V2)
01293             {
01294               /* All the nfs_res structure in V2 have the status at the same place (because it is an union) */
01295               res_nfs.res_attr2.status = NFSERR_ROFS;
01296               rc = NFS_REQ_OK;  /* Processing of the request is done */
01297             }
01298           else
01299             {
01300               /* V3 request */
01301               /* All the nfs_res structure in V2 have the status at the same place, and so does V3 ones */
01302               res_nfs.res_attr2.status = (nfsstat2) NFS3ERR_ROFS;
01303               rc = NFS_REQ_OK;  /* Processing of the request is done */
01304             }
01305         }
01306       else                      /* unexpected protocol (mount doesn't make write) */
01307         rc = NFS_REQ_DROP;
01308     }
01309   else if ((export_check_result != EXPORT_PERMISSION_GRANTED) &&
01310            (export_check_result != EXPORT_MDONLY_GRANTED))
01311     {
01312       /* If not EXPORT_PERMISSION_GRANTED, then we are all out of options! */
01313       LogMajor(COMPONENT_DISPATCH,
01314                "nfs_export_check_access() returned none of the expected flags. This is an unexpected state!");
01315       rc = NFS_REQ_DROP;
01316     }
01317   else  /* export_check_result == EXPORT_PERMISSION_GRANTED is TRUE */
01318     {
01319       LogFullDebug(COMPONENT_DISPATCH,
01320                    "nfs_export_check_access() reported PERMISSION GRANTED.");
01321 
01322       /* Do the authentication stuff, if needed */
01323       if(pworker_data->pfuncdesc->dispatch_behaviour & NEEDS_CRED)
01324         {
01325           /* Swap the anonymous uid/gid if the user should be anonymous */
01326           if(nfs_check_anon(&related_client, pexport, &user_credentials) == FALSE
01327              || nfs_build_fsal_context(req,
01328                                        pexport,
01329                                        &pworker_data->thread_fsal_context,
01330                                        &user_credentials) == FALSE)
01331             {
01332               LogInfo(COMPONENT_DISPATCH,
01333                       "authentication failed, rejecting client");
01334               svc_dplx_lock_x(xprt, &pworker_data->sigmask);
01335               svcerr_auth2(xprt, req, AUTH_TOOWEAK);
01336               svc_dplx_unlock_x(xprt, &pworker_data->sigmask);
01337               /* XXX */
01338               pworker_data->current_xid = 0;    /* No more xid managed */
01339 
01340               if (nfs_dupreq_delete(req) != DUPREQ_SUCCESS)
01341                 {
01342                   LogCrit(COMPONENT_DISPATCH,
01343                          "Attempt to delete duplicate request failed on line %d",
01344                          __LINE__);
01345                 }
01346               return;
01347             }
01348         }
01349 
01350       /* processing */
01351       P(pworker_data->request_pool_mutex);
01352       gettimeofday(timer_start, NULL);
01353 
01354       LogDebug(COMPONENT_DISPATCH,
01355                "NFS DISPATCHER: Calling service function %s start_time %llu.%.6llu",
01356                pworker_data->pfuncdesc->funcname,
01357                (unsigned long long)timer_start->tv_sec,
01358                (unsigned long long)timer_start->tv_usec);
01359 
01360       V(pworker_data->request_pool_mutex);
01361 
01362 #ifdef _ERROR_INJECTION
01363       if(worker_delay_time != 0)
01364         sleep(worker_delay_time);
01365       else if(next_worker_delay_time != 0)
01366         {
01367           sleep(next_worker_delay_time);
01368           next_worker_delay_time = 0;
01369         }
01370 #endif
01371 
01372       pfsal_op_ctx =  &pworker_data->thread_fsal_context ;
01373 
01374       rc = pworker_data->pfuncdesc->service_function(parg_nfs,
01375                                                      pexport,
01376                                                      pfsal_op_ctx,
01377                                                      pworker_data,
01378                                                      req,
01379                                                      &res_nfs);
01380     }
01381 
01382   /* Perform statistics here */
01383   gettimeofday(&timer_end, NULL);
01384 
01385   /* process time */
01386   stat_type = (rc == NFS_REQ_OK) ? GANESHA_STAT_SUCCESS : GANESHA_STAT_DROP;
01387   P(pworker_data->request_pool_mutex);
01388   timer_diff = time_diff(*timer_start, timer_end);
01389 
01390   /* this thread is done, reset the timer start to avoid long processing */
01391   memset(timer_start, 0, sizeof(struct timeval));
01392   V(pworker_data->request_pool_mutex);
01393   latency_stat.type = SVC_TIME;
01394   latency_stat.latency = timer_diff.tv_sec * 1000000
01395     + timer_diff.tv_usec; /* microseconds */
01396   nfs_stat_update(stat_type, &(pworker_data->stats.stat_req), req,
01397                   &latency_stat);
01398 
01399   if ((req->rq_prog == nfs_param.core_param.program[P_MNT]) ||
01400       ((req->rq_prog == nfs_param.core_param.program[P_NFS]) &&
01401        (req->rq_proc == 0 /*NULL RPC*/ ))) {
01402       update_per_share_stats = FALSE;
01403   } else {
01404       update_per_share_stats = TRUE;
01405   }
01406   /* Update per-share counter and process time */
01407   if (update_per_share_stats) {
01408       nfs_stat_update(stat_type,
01409                       &(pexport->worker_stats[pworker_data->worker_index].stat_req),
01410                       req, &latency_stat);
01411   }
01412 
01413   /* process time + queue time */
01414   queue_timer_diff = time_diff(preqnfs->time_queued, timer_end);
01415   latency_stat.type = AWAIT_TIME;
01416   latency_stat.latency = queue_timer_diff.tv_sec * 1000000
01417     + queue_timer_diff.tv_usec; /* microseconds */
01418   nfs_stat_update(GANESHA_STAT_SUCCESS, &(pworker_data->stats.stat_req), req,
01419                   &latency_stat);
01420 
01421   /* Update per-share process time + queue time */
01422   if (update_per_share_stats) {
01423       nfs_stat_update(GANESHA_STAT_SUCCESS,
01424                       &(pexport->worker_stats[pworker_data->worker_index].stat_req),
01425                       req, &latency_stat);
01426 
01427       /* Update per-share total counters */
01428       pexport->worker_stats[pworker_data->worker_index].nb_total_req += 1;
01429   }
01430 
01431   /* Update total counters */
01432   pworker_data->stats.nb_total_req += 1;
01433 
01434   if(timer_diff.tv_sec >= nfs_param.core_param.long_processing_threshold)
01435     LogEvent(COMPONENT_DISPATCH,
01436              "Function %s xid=%u exited with status %d taking %llu.%.6llu seconds to process",
01437              pworker_data->pfuncdesc->funcname, req->rq_xid, rc,
01438              (unsigned long long)timer_diff.tv_sec,
01439              (unsigned long long)timer_diff.tv_usec);
01440   else
01441     LogDebug(COMPONENT_DISPATCH,
01442              "Function %s xid=%u exited with status %d taking %llu.%.6llu seconds to process",
01443              pworker_data->pfuncdesc->funcname, req->rq_xid, rc,
01444              (unsigned long long)timer_diff.tv_sec,
01445              (unsigned long long)timer_diff.tv_usec);
01446 
01447   LogFullDebug(COMPONENT_DISPATCH,
01448                "Function %s xid=%u: process %llu.%.6llu await %llu.%.6llu",
01449                pworker_data->pfuncdesc->funcname, req->rq_xid,
01450                (unsigned long long int)timer_diff.tv_sec,
01451                (unsigned long long int)timer_diff.tv_usec,
01452                (unsigned long long int)queue_timer_diff.tv_sec,
01453                (unsigned long long int)queue_timer_diff.tv_usec);
01454   
01455   /* Perform NFSv4 operations statistics if required */
01456   if(req->rq_vers == NFS_V4)
01457       if(req->rq_proc == NFSPROC4_COMPOUND)
01458           nfs4_op_stat_update(parg_nfs, &res_nfs,
01459                               &(pworker_data->stats.stat_req));
01460 
01461   /* XXX */
01462   pworker_data->current_xid = 0;        /* No more xid managed */
01463 
01464   /* If request is dropped, no return to the client */
01465   if(rc == NFS_REQ_DROP)
01466     {
01467       /* The request was dropped */
01468       LogDebug(COMPONENT_DISPATCH,
01469                "Drop request rpc_xid=%u, program %u, version %u, function %u",
01470                req->rq_xid, (int)req->rq_prog,
01471                (int)req->rq_vers, (int)req->rq_proc);
01472 
01473       /* If the request is not normally cached, then the entry will be removed
01474        * later. We only remove a reply that is normally cached that has been
01475        * dropped. */
01476       if(do_dupreq_cache)
01477         if (nfs_dupreq_delete(req) != DUPREQ_SUCCESS)
01478           {
01479             LogCrit(COMPONENT_DISPATCH,
01480                     "Attempt to delete duplicate request failed on line %d",
01481                     __LINE__);
01482           }
01483     }
01484   else
01485     {
01486       LogFullDebug(COMPONENT_DISPATCH,
01487                    "Before svc_sendreply on socket %d",
01488                    xprt->xp_fd);
01489 
01490       svc_dplx_lock_x(xprt, &pworker_data->sigmask);
01491 
01492       /* encoding the result on xdr output */
01493       if(svc_sendreply2(xprt, req, pworker_data->pfuncdesc->xdr_encode_func,
01494                         (caddr_t) &res_nfs) == FALSE)
01495         {
01496           LogDebug(COMPONENT_DISPATCH,
01497                    "NFS DISPATCHER: FAILURE: Error while calling svc_sendreply");
01498           svcerr_systemerr2(xprt, req);
01499 
01500           if (nfs_dupreq_delete(req) != DUPREQ_SUCCESS)
01501             {
01502               LogCrit(COMPONENT_DISPATCH,
01503                       "Attempt to delete duplicate request failed on line %d",
01504                       __LINE__);
01505             }
01506           svc_dplx_unlock_x(xprt, &pworker_data->sigmask);
01507           return;
01508         }
01509 
01510       LogFullDebug(COMPONENT_DISPATCH,
01511                    "After svc_sendreply on socket %d",
01512                    xprt->xp_fd);
01513 
01514       /* Mark request as finished */
01515       LogFullDebug(COMPONENT_DUPREQ, "YES?: %d", do_dupreq_cache);
01516       if(do_dupreq_cache)
01517         {
01518           dpq_status = nfs_dupreq_finish(req, &res_nfs, lru_dupreq);
01519         }
01520     } /* rc == NFS_REQ_DROP */
01521 
01522   /* Free the allocated resources once the work is done */
01523   /* Free the arguments */
01524   if((preqnfs->req.rq_vers == 2) ||
01525      (preqnfs->req.rq_vers == 3) ||
01526      (preqnfs->req.rq_vers == 4))
01527       if(!SVC_FREEARGS(xprt, pworker_data->pfuncdesc->xdr_decode_func,
01528                        (caddr_t) parg_nfs))
01529       {
01530         LogCrit(COMPONENT_DISPATCH,
01531                 "NFS DISPATCHER: FAILURE: Bad SVC_FREEARGS for %s",
01532                 pworker_data->pfuncdesc->funcname);
01533       }
01534 
01535   /* XXX we must hold xprt lock across SVC_FREEARGS */
01536   svc_dplx_unlock_x(xprt, &pworker_data->sigmask);
01537     
01538   /* Free the reply.
01539    * This should not be done if the request is dupreq cached because this will
01540    * mark the dupreq cached info eligible for being reuse by other requests */
01541   if(!do_dupreq_cache)
01542     {
01543       if (nfs_dupreq_delete(req) != DUPREQ_SUCCESS)
01544         {
01545           LogCrit(COMPONENT_DISPATCH,
01546                   "Attempt to delete duplicate request failed on line %d",
01547                   __LINE__);
01548         }
01549       /* Free only the non dropped requests */
01550       if(rc == NFS_REQ_OK) {
01551           pworker_data->pfuncdesc->free_function(&res_nfs);
01552       }
01553     }
01554 
01555   /* By now the dupreq cache entry should have been completed w/ a request
01556    * that is reusable or the dupreq cache entry should have been removed. */
01557   return;
01558 }                               /* nfs_rpc_execute */
01559 
01573 int nfs_Init_worker_data(nfs_worker_data_t * pdata)
01574 {
01575   LRU_status_t status = LRU_LIST_SUCCESS;
01576   char name[256];
01577 
01578   if(pthread_mutex_init(&(pdata->request_pool_mutex), NULL) != 0)
01579     return -1;
01580 
01581   sprintf(name, "Worker Thread #%u", (int)pdata->worker_index);
01582   if(tcb_new(&(pdata->wcb), name) != 0)
01583     return -1;
01584 
01585   init_glist(&pdata->pending_request);
01586   pdata->pending_request_len = 0;
01587 
01588   sprintf(name, "Worker Thread #%u Duplicate Request", pdata->worker_index);
01589   nfs_param.worker_param.lru_dupreq.lp_name = name;
01590 
01591   if((pdata->duplicate_request =
01592       LRU_Init(nfs_param.worker_param.lru_dupreq, &status)) == NULL)
01593     {
01594       LogError(COMPONENT_DISPATCH, ERR_LRU, ERR_LRU_LIST_INIT, status);
01595       return -1;
01596     }
01597 
01598   pdata->passcounter = 0;
01599   pdata->wcb.tcb_ready = FALSE;
01600   pdata->gc_in_progress = FALSE;
01601   pdata->pfuncdesc = INVALID_FUNCDESC;
01602 
01603   return 0;
01604 }                               /* nfs_Init_worker_data */
01605 
01606 void DispatchWorkNFS(request_data_t *nfsreq, unsigned int worker_index)
01607 {
01608   struct svc_req *req = NULL;
01609   uint32_t rpcxid = 0;
01610 
01611   switch (nfsreq->rtype) {
01612   case NFS_CALL:
01613       break;
01614   default:
01615       req = &nfsreq->r_u.nfs->req;
01616       rpcxid = req->rq_xid;
01617   }
01618 
01619   LogDebug(COMPONENT_DISPATCH,
01620            "Awaking Worker Thread #%u for request %p, rtype=%d xid=%u",
01621            worker_index, nfsreq, nfsreq->rtype, rpcxid);
01622 
01623   P(workers_data[worker_index].wcb.tcb_mutex);
01624   P(workers_data[worker_index].request_pool_mutex);
01625 
01626   glist_add_tail(&workers_data[worker_index].pending_request, &nfsreq->pending_req_queue);
01627   workers_data[worker_index].pending_request_len++;
01628 
01629   if(pthread_cond_signal(&(workers_data[worker_index].wcb.tcb_condvar)) == -1)
01630     {
01631       V(workers_data[worker_index].request_pool_mutex);
01632       V(workers_data[worker_index].wcb.tcb_mutex);
01633       LogMajor(COMPONENT_THREAD,
01634                "Error %d (%s) while signalling Worker Thread #%u... Exiting",
01635                errno, strerror(errno), worker_index);
01636       Fatal();
01637     }
01638   V(workers_data[worker_index].request_pool_mutex);
01639   V(workers_data[worker_index].wcb.tcb_mutex);
01640 }
01641 
01642 enum auth_stat AuthenticateRequest(nfs_request_data_t *nfsreq,
01643                                    bool_t *no_dispatch)
01644 {
01645   struct rpc_msg *msg;
01646   struct svc_req *req;
01647   SVCXPRT *xprt;
01648   enum auth_stat why;
01649 
01650   /* A few words of explanation are required here:
01651    * In authentication is AUTH_NONE or AUTH_UNIX, then the value of no_dispatch
01652    * remains FALSE and the request is proceeded normally.
01653    * If authentication is RPCSEC_GSS, no_dispatch may have value TRUE, this
01654    * means that gc->gc_proc != RPCSEC_GSS_DATA and that the message is in fact
01655    * an internal negociation message from RPCSEC_GSS using GSSAPI. It then
01656    * should not be proceed by the worker and SVC_STAT should be returned to
01657    * the dispatcher.
01658    */
01659 
01660   *no_dispatch = FALSE;
01661 
01662   /* Set pointers */
01663   msg = &(nfsreq->msg);
01664   req = &(nfsreq->req);
01665   xprt = nfsreq->xprt;
01666 
01667   req->rq_xprt = nfsreq->xprt;
01668   req->rq_prog = msg->rm_call.cb_prog;
01669   req->rq_vers = msg->rm_call.cb_vers;
01670   req->rq_proc = msg->rm_call.cb_proc;
01671   req->rq_xid = msg->rm_xid;
01672 
01673   LogFullDebug(COMPONENT_DISPATCH,
01674                "About to authenticate Prog=%d, vers=%d, proc=%d xid=%u xprt=%p",
01675                (int)req->rq_prog, (int)req->rq_vers,
01676                (int)req->rq_proc, req->rq_xid, req->rq_xprt);
01677 
01678   /* XXX Restore previously saved GssData.
01679    * I'm not clear what we're restoring here.  Operating on xprt means that
01680    * we do (did) not share buffers with xprt_copy.
01681    */
01682 #ifdef _HAVE_GSSAPI
01683   if((why = Rpcsecgss__authenticate(req, msg, no_dispatch)) != AUTH_OK)
01684 #else
01685   if((why = _authenticate(req, msg)) != AUTH_OK)
01686 #endif
01687     {
01688       char auth_str[AUTH_STR_LEN];
01689       auth_stat2str(why, auth_str);
01690       LogInfo(COMPONENT_DISPATCH,
01691               "Could not authenticate request... rejecting with AUTH_STAT=%s",
01692               auth_str);
01693       svcerr_auth2(xprt, req, why);
01694       *no_dispatch = TRUE;
01695       return why;
01696     }
01697   else
01698     {
01699 #ifdef _HAVE_GSSAPI
01700       struct rpc_gss_cred *gc;
01701 
01702       if(req->rq_xprt->xp_verf.oa_flavor == RPCSEC_GSS)
01703         {
01704           gc = (struct rpc_gss_cred *) req->rq_clntcred;
01705           LogFullDebug(COMPONENT_DISPATCH,
01706                        "AuthenticateRequest no_dispatch=%d gc->gc_proc=(%u) %s",
01707                        *no_dispatch, gc->gc_proc, str_gc_proc(gc->gc_proc));
01708         }
01709 #endif
01710     }             /* else from if( ( why = _authenticate( preq, pmsg) ) != AUTH_OK) */
01711   return AUTH_OK;
01712 }
01713 
01714 #ifdef _USE_9P
01715 
01726 static void _9p_execute( _9p_request_data_t * preq9p, 
01727                           nfs_worker_data_t * pworker_data)
01728 {
01729   _9p_process_request( preq9p, pworker_data ) ;
01730   return ;
01731 } /* _9p_execute */
01732 #endif
01733 
01734 static inline enum xprt_stat
01735 cond_multi_dispatch(nfs_worker_data_t *pmydata, request_data_t *nfsreq,
01736                     bool *locked)
01737 {
01738     enum xprt_stat stat;
01739     bool_t try_multi = FALSE, dispatched = FALSE;
01740     SVCXPRT *xprt = nfsreq->r_u.nfs->xprt;
01741 
01742     stat = SVC_STAT(xprt);
01743     svc_dplx_unlock_x(xprt, &pmydata->sigmask);
01744     *locked = FALSE;
01745 
01746     if (stat == XPRT_MOREREQS)
01747         try_multi = TRUE;
01748 
01749 #if 0 /* XXX */
01750     try_multi = FALSE;
01751 #endif
01752 
01753     if (try_multi) {
01754         process_status_t rc_multi __attribute__((unused));
01755         gsh_xprt_private_t *xu;
01756         pthread_rwlock_wrlock(&xprt->lock);
01757         xu = (gsh_xprt_private_t *) xprt->xp_u1;
01758 
01759         LogDebug(COMPONENT_DISPATCH, "xprt=%p try_multi=TRUE multi_cnt=%u "
01760                 "refcnt=%u",
01761                 xprt,
01762                 xu->multi_cnt,
01763                 xu->refcnt);
01764 
01765         /* we need an atomic total-outstanding counter, check against hiwat */
01766         if (xu->multi_cnt < nfs_param.core_param.dispatch_multi_xprt_max) {
01767             ++(xu->multi_cnt);
01768             /* dispatch it */
01769             rc_multi = dispatch_rpc_subrequest(pmydata, nfsreq);
01770             dispatched = TRUE;
01771         }
01772         pthread_rwlock_unlock(&xprt->lock);
01773     }
01774 
01775     if (! dispatched) {
01776         /* Execute it */
01777         nfs_rpc_execute(nfsreq, pmydata);
01778     }
01779 
01780     return (stat);
01781 }
01782 
01788 #define DISP_LOCK(x) do { \
01789     if (! locked) { \
01790         svc_dplx_lock_x(xprt, &pmydata->sigmask); \
01791         locked = TRUE; \
01792       }\
01793     } while (0);
01794 
01795 #define DISP_UNLOCK(x) do { \
01796     if (locked) { \
01797         svc_dplx_unlock_x(xprt, &pmydata->sigmask); \
01798         locked = FALSE; \
01799       }\
01800     } while (0);
01801 
01802 process_status_t
01803 nfs_worker_process_rpc_requests(nfs_worker_data_t *pmydata,
01804                                 request_data_t *nfsreq)
01805 {
01806   enum xprt_stat stat = XPRT_IDLE;
01807   struct rpc_msg *pmsg;
01808   struct svc_req *preq;
01809   const nfs_function_desc_t *pfuncdesc;
01810   bool_t no_dispatch = TRUE, recv_status;
01811   process_status_t rc = PROCESS_DONE;
01812   SVCXPRT *xprt;
01813   bool locked = FALSE;
01814 again:
01815   /*
01816    * Receive from socket.
01817    * Will block until the client operates on the socket
01818    */
01819   xprt = nfsreq->r_u.nfs->xprt;
01820 
01821   LogFullDebug(COMPONENT_DISPATCH,
01822                "Before calling SVC_RECV on socket %d",
01823                xprt->xp_fd);
01824 
01825   rc = PROCESS_DONE;
01826 
01827   preq = &nfsreq->r_u.nfs->req;
01828   pmsg = &nfsreq->r_u.nfs->msg;
01829 
01830   DISP_LOCK(xprt);
01831   recv_status = SVC_RECV(xprt, pmsg);
01832 
01833   LogFullDebug(COMPONENT_DISPATCH,
01834                "Status for SVC_RECV on socket %d is %d, xid=%lu",
01835                xprt->xp_fd,
01836                recv_status,
01837                (unsigned long)pmsg->rm_xid);
01838 
01839   /* If status is ok, the request will be processed by the related
01840    * worker, otherwise, it should be released by being tagged as invalid. */
01841   if (!recv_status)
01842     {
01843       /* RPC over TCP specific: RPC/UDP's xprt know only one state: XPRT_IDLE,
01844        * because UDP is mostly a stateless protocol.  With RPC/TCP, they can be
01845        * XPRT_DIED especially when the client closes the peer's socket. We
01846        * have to cope with this aspect in the next lines.  Finally, xdrrec
01847        * uses XPRT_MOREREQS to indicate that additional records are ready to
01848        * be consumed immediately. */
01849 
01850         /* XXXX */
01851       sockaddr_t addr;
01852       char addrbuf[SOCK_NAME_MAX];
01853 
01854       if(copy_xprt_addr(&addr, xprt) == 1)
01855         sprint_sockaddr(&addr, addrbuf, sizeof(addrbuf));
01856       else
01857         sprintf(addrbuf, "<unresolved>");
01858 
01859       stat = SVC_STAT(xprt);
01860       DISP_UNLOCK(xprt);
01861 
01862       if(stat == XPRT_DIED)
01863         {
01864 
01865           LogDebug(COMPONENT_DISPATCH,
01866                    "Client on socket=%d, addr=%s disappeared...",
01867                    xprt->xp_fd, addrbuf);
01868           DISP_LOCK(xprt);
01869           gsh_xprt_destroy(xprt);
01870           rc = PROCESS_LOST_CONN;
01871         }
01872       else if(stat == XPRT_MOREREQS)
01873         {
01874           /* unexpected case */
01875           LogDebug(COMPONENT_DISPATCH,
01876                    "Client on socket=%d, addr=%s has status XPRT_MOREREQS",
01877                    xprt->xp_fd, addrbuf);
01878         }
01879       else if(stat == XPRT_IDLE)
01880         {
01881           LogDebug(COMPONENT_DISPATCH,
01882                    "Client on socket=%d, addr=%s has status XPRT_IDLE",
01883                    xprt->xp_fd, addrbuf);
01884         }
01885       else
01886         {
01887           LogDebug(COMPONENT_DISPATCH,
01888                    "Client on socket=%d, addr=%s has status unknown (%d)",
01889                    xprt->xp_fd, addrbuf, (int)stat);
01890         }
01891       goto unblock;
01892     }
01893   else
01894     {
01895       nfsreq->r_u.nfs->req.rq_prog = pmsg->rm_call.cb_prog;
01896       nfsreq->r_u.nfs->req.rq_vers = pmsg->rm_call.cb_vers;
01897       nfsreq->r_u.nfs->req.rq_proc = pmsg->rm_call.cb_proc;
01898       nfsreq->r_u.nfs->req.rq_xid = pmsg->rm_xid;
01899 
01900       pfuncdesc = nfs_rpc_get_funcdesc(nfsreq->r_u.nfs);
01901       if(pfuncdesc == INVALID_FUNCDESC)
01902           goto unblock;
01903 
01904       DISP_LOCK(xprt);
01905       if(AuthenticateRequest(nfsreq->r_u.nfs,
01906                              &no_dispatch) != AUTH_OK || no_dispatch) {
01907           goto unblock;
01908       }
01909 
01910       if(!nfs_rpc_get_args(nfsreq->r_u.nfs, pfuncdesc))
01911           goto unblock;
01912 
01913       preq->rq_xprt = xprt;
01914 
01915       /* Validate the rpc request as being a valid program, version,
01916        * and proc. If not, report the error. Otherwise, execute the
01917        * funtion. */
01918       if(is_rpc_call_valid(preq->rq_xprt, preq) == TRUE)
01919           stat = cond_multi_dispatch(pmydata, nfsreq, &locked);
01920 
01921       rc = PROCESS_DISPATCHED;
01922     }
01923 
01924 unblock:
01925   /* continue receiving if data is available--this isn't optional, because
01926    * irrespective of TI-RPC "nonblock" mode, we will frequently have consumed
01927    * additional RPC records (TCP).  Also, we expect to move the SVC_RECV
01928    * into the worker thread, so this will asynchronous wrt to the shared
01929    * event loop */
01930   if (rc == PROCESS_DISPATCHED) {
01931       if (stat == XPRT_MOREREQS)
01932           goto again;
01933       else {
01934           /* XXX dont bother re-arming epoll for xprt if there is data 
01935            * waiting */
01936           struct pollfd fd;
01937           fd.fd = xprt->xp_fd;
01938           fd.events = POLLIN;
01939           if (poll(&fd, 1, 0 /* ms, ie, now */) > 0)
01940               goto again;
01941       }
01942   }
01943 
01944   DISP_UNLOCK(xprt);
01945 
01946   if (rc != PROCESS_LOST_CONN)
01947       (void) svc_rqst_unblock_events(nfsreq->r_u.nfs->xprt,
01948                                      SVC_RQST_FLAG_NONE);
01949 
01950   return (rc);
01951 }
01952 
01966 void *worker_thread(void *IndexArg)
01967 {
01968   request_data_t *nfsreq;
01969   int rc = 0;
01970   unsigned int gc_allowed = FALSE;
01971   unsigned long worker_index = (unsigned long) IndexArg;
01972   nfs_worker_data_t *pmydata = &(workers_data[worker_index]);
01973   char thr_name[32];
01974   gsh_xprt_private_t *xu = NULL;
01975 
01976 #ifdef _USE_SHARED_FSAL
01977   unsigned int i = 0 ;
01978   unsigned int fsalid = 0 ;
01979 #endif
01980 
01981   snprintf(thr_name, sizeof(thr_name), "Worker Thread #%lu", worker_index);
01982   SetNameFunction(thr_name);
01983 
01984   /* save current signal mask */
01985   rc = pthread_sigmask(SIG_SETMASK, (sigset_t *) 0, &pmydata->sigmask);
01986   if (rc) {
01987       LogFatal(COMPONENT_DISPATCH,
01988                "pthread_sigmask returned %d", rc);
01989   }
01990 
01991   if(mark_thread_existing(&(pmydata->wcb)) == PAUSE_EXIT)
01992     {
01993       /* Oops, that didn't last long... exit. */
01994       mark_thread_done(&(pmydata->wcb));
01995       LogDebug(COMPONENT_DISPATCH,
01996                "Worker exiting before initialization");
01997       return NULL;
01998     }
01999 
02000   LogFullDebug(COMPONENT_DISPATCH,
02001                "Starting, pending=%d", pmydata->pending_request_len);
02002 
02003   LogDebug(COMPONENT_DISPATCH, "NFS WORKER #%lu: my pthread id is %p",
02004            worker_index, (caddr_t) pthread_self());
02005 
02006   /* Initialisation of credential for current thread */
02007   LogFullDebug(COMPONENT_DISPATCH,
02008                "NFS WORKER #%lu: Initialization of thread's credential",
02009                worker_index);
02010 
02011   if(FSAL_IS_ERROR(FSAL_InitClientContext(&pmydata->thread_fsal_context)))
02012     {
02013       /* Failed init */
02014       LogFatal(COMPONENT_DISPATCH,
02015                "Error initializing thread's credential");
02016     }
02017 
02018   LogInfo(COMPONENT_DISPATCH, "Worker successfully initialized");
02019 
02020   /* Worker's infinite loop */
02021   while(1)
02022     {
02023       /* update memory and FSAL stats,
02024        * twice often than stats display.
02025        */
02026       if(time(NULL) - pmydata->stats.last_stat_update >
02027          (int)nfs_param.core_param.stats_update_delay / 2)
02028         {
02029 
02030           FSAL_get_stats(&pmydata->stats.fsal_stats, FALSE);
02031 
02032           /* reset last stat */
02033           pmydata->stats.last_stat_update = time(NULL);
02034         }
02035 
02036       /* Wait on condition variable for work to be done */
02037       LogFullDebug(COMPONENT_DISPATCH,
02038                    "waiting for requests to process, pending=%d",
02039                    pmydata->pending_request_len);
02040 
02041       /* Get the state without lock first, if things are fine
02042        * don't bother to check under lock.
02043        */
02044       if((pmydata->wcb.tcb_state != STATE_AWAKE) ||
02045           (pmydata->pending_request_len == 0)) {
02046           while(1)
02047             {
02048               P(pmydata->wcb.tcb_mutex);
02049               if(pmydata->wcb.tcb_state == STATE_AWAKE &&
02050                  (pmydata->pending_request_len != 0)) {
02051                   V(pmydata->wcb.tcb_mutex);
02052                   break;
02053                 }
02054               switch(thread_sm_locked(&pmydata->wcb))
02055                 {
02056                   case THREAD_SM_RECHECK:
02057                     V(pmydata->wcb.tcb_mutex);
02058                     continue;
02059 
02060                   case THREAD_SM_BREAK:
02061                     if(pmydata->pending_request_len == 0) {
02062                         /* No work; wait */
02063                         pthread_cond_wait(&(pmydata->wcb.tcb_condvar),
02064                                           &(pmydata->wcb.tcb_mutex));
02065                         V(pmydata->wcb.tcb_mutex);
02066                         continue;
02067                       }
02068 
02069                   case THREAD_SM_EXIT:
02070                     LogDebug(COMPONENT_DISPATCH, "Worker exiting as requested");
02071                     V(pmydata->wcb.tcb_mutex);
02072                     return NULL;
02073                 }
02074             }
02075         }
02076 
02077       LogFullDebug(COMPONENT_DISPATCH,
02078                    "Processing a new request, pause_state: %s, pending=%u",
02079                    pause_state_str[pmydata->wcb.tcb_state],
02080                    pmydata->pending_request_len);
02081 
02082       P(pmydata->request_pool_mutex);
02083       nfsreq = glist_first_entry(&pmydata->pending_request, request_data_t,
02084                                   pending_req_queue);
02085       if (nfsreq == NULL) {
02086         V(pmydata->request_pool_mutex);
02087         LogMajor(COMPONENT_DISPATCH, "No pending request available");
02088         continue;             /* return to main loop */
02089       }
02090       glist_del(&nfsreq->pending_req_queue);
02091       pmydata->pending_request_len--;
02092       V(pmydata->request_pool_mutex);
02093 
02094       /* Check for destroyed xprts */
02095       switch(nfsreq->rtype) {
02096       case NFS_REQUEST_LEADER:
02097       case NFS_REQUEST:
02098           xu = (gsh_xprt_private_t *) nfsreq->r_u.nfs->xprt->xp_u1;
02099           pthread_rwlock_rdlock(&nfsreq->r_u.nfs->xprt->lock);
02100           if (xu->flags & XPRT_PRIVATE_FLAG_DESTROYED) {
02101               pthread_rwlock_unlock(&nfsreq->r_u.nfs->xprt->lock);
02102               goto finalize_req;
02103           }
02104           pthread_rwlock_unlock(&nfsreq->r_u.nfs->xprt->lock);
02105           break;
02106       default:
02107           break;
02108       }
02109 
02110       switch(nfsreq->rtype)
02111        {
02112           case NFS_REQUEST_LEADER:
02113               LogDebug(COMPONENT_DISPATCH,
02114                        "Multi-dispatch leader, nfsreq=%p, pending=%d, "
02115                        "xid=%u xprt=%p refcnt=%u",
02116                        nfsreq,
02117                        pmydata->pending_request_len,
02118                        nfsreq->r_u.nfs->msg.rm_xid,
02119                        nfsreq->r_u.nfs->xprt,
02120                        xu->refcnt);
02121 
02122            if(nfsreq->r_u.nfs->xprt->xp_fd == 0)
02123              {
02124                LogFullDebug(COMPONENT_DISPATCH,
02125                             "RPC dispatch error:  nfsreq=%p, xp_fd==0",
02126                             nfsreq);
02127              }
02128            else
02129              {
02130                /* Process the sequence */
02131                (void) nfs_worker_process_rpc_requests(pmydata, nfsreq);
02132              }
02133            break;
02134 
02135        case NFS_REQUEST:
02136            LogDebug(COMPONENT_DISPATCH,
02137                     "Multi-dispatch subrequest, nfsreq=%p, pending=%d, "
02138                     "xid=%u xprt=%p refcnt=%u",
02139                     nfsreq,
02140                     pmydata->pending_request_len,
02141                     nfsreq->r_u.nfs->msg.rm_xid,
02142                     nfsreq->r_u.nfs->xprt,
02143                     xu->refcnt);
02144            nfs_rpc_execute(nfsreq, pmydata);
02145            break;
02146 
02147        case NFS_CALL:
02148            /* NFSv4 rpc call (callback) */
02149            nfs_rpc_dispatch_call(nfsreq->r_u.call, 0 /* XXX flags */);
02150            break;
02151 
02152        case _9P_REQUEST:
02153 #ifdef _USE_9P
02154            _9p_execute(&nfsreq->r_u._9p, pmydata);
02155 #else
02156            LogCrit(COMPONENT_DISPATCH, "Implementation error, 9P message "
02157                      "when 9P support is disabled" ) ;
02158 #endif
02159            break;
02160          }
02161 
02162     finalize_req:
02163       /* XXX Signal the request processing has completed, though at
02164        * present there may be no effect. */
02165       LogInfo(COMPONENT_DISPATCH, "Signaling completion of request");
02166 
02167       /* Drop multi_cnt and xprt refcnt, if appropriate */
02168       switch(nfsreq->rtype) {
02169        case NFS_REQUEST_LEADER:
02170            gsh_xprt_unref(
02171                nfsreq->r_u.nfs->xprt, XPRT_PRIVATE_FLAG_NONE);
02172            break;
02173        case NFS_REQUEST:
02174            pthread_rwlock_wrlock(&nfsreq->r_u.nfs->xprt->lock);
02175            --(xu->multi_cnt);
02176            gsh_xprt_unref(
02177                nfsreq->r_u.nfs->xprt, XPRT_PRIVATE_FLAG_LOCKED);
02178            break;
02179        case NFS_CALL:
02180            break;
02181        default:
02182            break;
02183        }
02184 
02185       /* Free the req by releasing the entry */
02186       LogFullDebug(COMPONENT_DISPATCH,
02187                    "Invalidating processed entry");
02188       if( nfsreq->rtype != _9P_REQUEST && nfsreq->r_u.nfs ) 
02189         pool_free(request_data_pool, nfsreq->r_u.nfs);
02190       pool_free(request_pool, nfsreq);
02191 
02192       if(pmydata->passcounter > nfs_param.worker_param.nb_before_gc)
02193         {
02194           /* Garbage collection on dup req cache */
02195           LogFullDebug(COMPONENT_DISPATCH,
02196                        "before dupreq invalidation nb_entry=%d nb_invalid=%d",
02197                        pmydata->duplicate_request->nb_entry,
02198                        pmydata->duplicate_request->nb_invalid);
02199           if((rc =
02200               LRU_invalidate_by_function(pmydata->duplicate_request,
02201                                          nfs_dupreq_gc_function,
02202                                          NULL)) != LRU_LIST_SUCCESS)
02203             {
02204               LogCrit(COMPONENT_DISPATCH,
02205                       "FAILURE: Impossible to invalidate entries for duplicate "
02206                       "request cache (error %d)",
02207                       rc);
02208             }
02209           LogFullDebug(COMPONENT_DISPATCH,
02210                        "after dupreq invalidation nb_entry=%d nb_invalid=%d",
02211                        pmydata->duplicate_request->nb_entry,
02212                        pmydata->duplicate_request->nb_invalid);
02213           if((rc =
02214               LRU_gc_invalid(pmydata->duplicate_request, NULL)
02215               != LRU_LIST_SUCCESS))
02216             LogCrit(COMPONENT_DISPATCH,
02217                     "FAILURE: Impossible to gc entries for duplicate request "
02218                     "cache (error %d)",
02219                     rc);
02220           else
02221             LogFullDebug(COMPONENT_DISPATCH,
02222                          "gc entries for duplicate request cache OK");
02223 
02224           LogFullDebug(COMPONENT_DISPATCH,
02225                        "after dupreq gc nb_entry=%d nb_invalid=%d",
02226                        pmydata->duplicate_request->nb_entry,
02227                        pmydata->duplicate_request->nb_invalid);
02228 
02229           /* Performing garbabbge collection */
02230           LogFullDebug(COMPONENT_DISPATCH,
02231                        "Garbage collecting on pending request list");
02232           pmydata->passcounter = 0;
02233         }
02234       else
02235         LogFullDebug(COMPONENT_DISPATCH,
02236                      "garbage collection isn't necessary count=%d, max=%d",
02237                      pmydata->passcounter,
02238                      nfs_param.worker_param.nb_before_gc);
02239       pmydata->passcounter += 1;
02240 
02241       /* If needed, perform garbage collection on cache_inode layer */
02242       P(lock_nb_current_gc_workers);
02243       if(nb_current_gc_workers < nfs_param.core_param.nb_max_concurrent_gc)
02244         {
02245           nb_current_gc_workers += 1;
02246           gc_allowed = TRUE;
02247         }
02248       else
02249         gc_allowed = FALSE;
02250       V(lock_nb_current_gc_workers);
02251 
02252       P(pmydata->wcb.tcb_mutex);
02253       if(gc_allowed == TRUE && pmydata->wcb.tcb_state == STATE_AWAKE)
02254         {
02255           pmydata->gc_in_progress = TRUE;
02256           V(pmydata->wcb.tcb_mutex);
02257           LogFullDebug(COMPONENT_DISPATCH,
02258                        "There are %d concurrent garbage collection",
02259                        nb_current_gc_workers);
02260 
02261           P(lock_nb_current_gc_workers);
02262           nb_current_gc_workers -= 1;
02263           V(lock_nb_current_gc_workers);
02264 
02265           P(pmydata->wcb.tcb_mutex);
02266           pmydata->gc_in_progress = FALSE;
02267         }
02268       V(pmydata->wcb.tcb_mutex);
02269 
02270     }                           /* while( 1 ) */
02271   tcb_remove(&pmydata->wcb);
02272   return NULL;
02273 }                               /* worker_thread */