nfs-ganesha 1.4

nfs4_Compound.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 
00036 #ifdef HAVE_CONFIG_H
00037 #include "config.h"
00038 #endif
00039 
00040 #ifdef _SOLARIS
00041 #include "solaris_port.h"
00042 #endif
00043 
00044 #include "sal_functions.h"
00045 #include "nfs_tools.h"
00046 
00047 typedef struct nfs4_op_desc__
00048 {
00049   char *name;
00050   unsigned int val;
00051   int (*funct) (struct nfs_argop4 *, compound_data_t *, struct nfs_resop4 *);
00052 } nfs4_op_desc_t;
00053 
00054 /* This array maps the operation number to the related position in array optab4 */
00055 #ifndef _USE_NFS4_1
00056 const int optab4index[] =
00057     { 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
00058   21, 22, 23,
00059   24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39
00060 };
00061 
00062 #else
00063 const int optab4index[] =
00064     { 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
00065   21, 22, 23,
00066   24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
00067   46,
00068   47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58
00069 };
00070 
00071 #endif
00072 
00073 #define POS_ILLEGAL_V40 40
00074 #define POS_ILLEGAL_V41 59
00075 
00076 static const nfs4_op_desc_t optab4v0[] = {
00077   {"OP_ACCESS", NFS4_OP_ACCESS, nfs4_op_access},
00078   {"OP_CLOSE", NFS4_OP_CLOSE, nfs4_op_close},
00079   {"OP_COMMIT", NFS4_OP_COMMIT, nfs4_op_commit},
00080   {"OP_CREATE", NFS4_OP_CREATE, nfs4_op_create},
00081   {"OP_DELEGPURGE", NFS4_OP_DELEGPURGE, nfs4_op_delegpurge},
00082   {"OP_DELEGRETURN", NFS4_OP_DELEGRETURN, nfs4_op_delegreturn},
00083   {"OP_GETATTR", NFS4_OP_GETATTR, nfs4_op_getattr},
00084   {"OP_GETFH", NFS4_OP_GETFH, nfs4_op_getfh},
00085   {"OP_LINK", NFS4_OP_LINK, nfs4_op_link},
00086   {"OP_LOCK", NFS4_OP_LOCK, nfs4_op_lock},
00087   {"OP_LOCKT", NFS4_OP_LOCKT, nfs4_op_lockt},
00088   {"OP_LOCKU", NFS4_OP_LOCKU, nfs4_op_locku},
00089   {"OP_LOOKUP", NFS4_OP_LOOKUP, nfs4_op_lookup},
00090   {"OP_LOOKUPP", NFS4_OP_LOOKUPP, nfs4_op_lookupp},
00091   {"OP_NVERIFY", NFS4_OP_NVERIFY, nfs4_op_nverify},
00092   {"OP_OPEN", NFS4_OP_OPEN, nfs4_op_open},
00093   {"OP_OPENATTR", NFS4_OP_OPENATTR, nfs4_op_openattr},
00094   {"OP_OPEN_CONFIRM", NFS4_OP_OPEN_CONFIRM, nfs4_op_open_confirm},
00095   {"OP_OPEN_DOWNGRADE", NFS4_OP_OPEN_DOWNGRADE, nfs4_op_open_downgrade},
00096   {"OP_PUTFH", NFS4_OP_PUTFH, nfs4_op_putfh},
00097   {"OP_PUTPUBFH", NFS4_OP_PUTPUBFH, nfs4_op_putpubfh},
00098   {"OP_PUTROOTFH", NFS4_OP_PUTROOTFH, nfs4_op_putrootfh},
00099   {"OP_READ", NFS4_OP_READ, nfs4_op_read},
00100   {"OP_READDIR", NFS4_OP_READDIR, nfs4_op_readdir},
00101   {"OP_READLINK", NFS4_OP_READLINK, nfs4_op_readlink},
00102   {"OP_REMOVE", NFS4_OP_REMOVE, nfs4_op_remove},
00103   {"OP_RENAME", NFS4_OP_RENAME, nfs4_op_rename},
00104   {"OP_RENEW", NFS4_OP_RENEW, nfs4_op_renew},
00105   {"OP_RESTOREFH", NFS4_OP_RESTOREFH, nfs4_op_restorefh},
00106   {"OP_SAVEFH", NFS4_OP_SAVEFH, nfs4_op_savefh},
00107   {"OP_SECINFO", NFS4_OP_SECINFO, nfs4_op_secinfo},
00108   {"OP_SETATTR", NFS4_OP_SETATTR, nfs4_op_setattr},
00109   {"OP_SETCLIENTID", NFS4_OP_SETCLIENTID, nfs4_op_setclientid},
00110   {"OP_SETCLIENTID_CONFIRM", NFS4_OP_SETCLIENTID_CONFIRM, nfs4_op_setclientid_confirm},
00111   {"OP_VERIFY", NFS4_OP_VERIFY, nfs4_op_verify},
00112   {"OP_WRITE", NFS4_OP_WRITE, nfs4_op_write},
00113   {"OP_RELEASE_LOCKOWNER", NFS4_OP_RELEASE_LOCKOWNER, nfs4_op_release_lockowner},
00114   {"OP_ILLEGAL", NFS4_OP_ILLEGAL, nfs4_op_illegal}
00115 };
00116 
00117 #ifdef _USE_NFS4_1
00118 static const nfs4_op_desc_t optab4v1[] = {
00119   {"OP_ACCESS", NFS4_OP_ACCESS, nfs4_op_access},
00120   {"OP_CLOSE", NFS4_OP_CLOSE, nfs41_op_close},
00121   {"OP_COMMIT", NFS4_OP_COMMIT, nfs4_op_commit},
00122   {"OP_CREATE", NFS4_OP_CREATE, nfs4_op_create},
00123   {"OP_DELEGPURGE", NFS4_OP_DELEGPURGE, nfs4_op_delegpurge},
00124   {"OP_DELEGRETURN", NFS4_OP_DELEGRETURN, nfs4_op_delegreturn},
00125   {"OP_GETATTR", NFS4_OP_GETATTR, nfs4_op_getattr},
00126   {"OP_GETFH", NFS4_OP_GETFH, nfs4_op_getfh},
00127   {"OP_LINK", NFS4_OP_LINK, nfs4_op_link},
00128   {"OP_LOCK", NFS4_OP_LOCK, nfs41_op_lock},
00129   {"OP_LOCKT", NFS4_OP_LOCKT, nfs41_op_lockt},
00130   {"OP_LOCKU", NFS4_OP_LOCKU, nfs41_op_locku},
00131   {"OP_LOOKUP", NFS4_OP_LOOKUP, nfs4_op_lookup},
00132   {"OP_LOOKUPP", NFS4_OP_LOOKUPP, nfs4_op_lookupp},
00133   {"OP_NVERIFY", NFS4_OP_NVERIFY, nfs4_op_nverify},
00134   {"OP_OPEN", NFS4_OP_OPEN, nfs41_op_open},
00135   {"OP_OPENATTR", NFS4_OP_OPENATTR, nfs4_op_openattr},
00136   {"OP_OPEN_CONFIRM", NFS4_OP_OPEN_CONFIRM, nfs4_op_illegal},   /* OP_OPEN_CONFIRM is deprecated in NFSv4.1 */
00137   {"OP_OPEN_DOWNGRADE", NFS4_OP_OPEN_DOWNGRADE, nfs4_op_open_downgrade},
00138   {"OP_PUTFH", NFS4_OP_PUTFH, nfs4_op_putfh},
00139   {"OP_PUTPUBFH", NFS4_OP_PUTPUBFH, nfs4_op_putpubfh},
00140   {"OP_PUTROOTFH", NFS4_OP_PUTROOTFH, nfs4_op_putrootfh},
00141   {"OP_READ", NFS4_OP_READ, nfs4_op_read},
00142   {"OP_READDIR", NFS4_OP_READDIR, nfs4_op_readdir},
00143   {"OP_READLINK", NFS4_OP_READLINK, nfs4_op_readlink},
00144   {"OP_REMOVE", NFS4_OP_REMOVE, nfs4_op_remove},
00145   {"OP_RENAME", NFS4_OP_RENAME, nfs4_op_rename},
00146   {"OP_RENEW", NFS4_OP_RENEW, nfs4_op_renew},
00147   {"OP_RESTOREFH", NFS4_OP_RESTOREFH, nfs4_op_restorefh},
00148   {"OP_SAVEFH", NFS4_OP_SAVEFH, nfs4_op_savefh},
00149   {"OP_SECINFO", NFS4_OP_SECINFO, nfs4_op_secinfo},
00150   {"OP_SETATTR", NFS4_OP_SETATTR, nfs4_op_setattr},
00151   {"OP_SETCLIENTID", NFS4_OP_SETCLIENTID, nfs4_op_setclientid},
00152   {"OP_SETCLIENTID_CONFIRM", NFS4_OP_SETCLIENTID_CONFIRM, nfs4_op_setclientid_confirm},
00153   {"OP_VERIFY", NFS4_OP_VERIFY, nfs4_op_verify},
00154   {"OP_WRITE", NFS4_OP_WRITE, nfs4_op_write},
00155   {"OP_RELEASE_LOCKOWNER", NFS4_OP_RELEASE_LOCKOWNER, nfs4_op_release_lockowner},
00156   {"OP_BACKCHANNEL_CTL", NFS4_OP_BACKCHANNEL_CTL, nfs4_op_illegal},     /* tbd */
00157   {"OP_BIND_CONN_TO_SESSION", NFS4_OP_BIND_CONN_TO_SESSION, nfs4_op_illegal},   /* tbd */
00158   {"OP_EXCHANGE_ID", NFS4_OP_EXCHANGE_ID, nfs41_op_exchange_id},
00159   {"OP_CREATE_SESSION", NFS4_OP_CREATE_SESSION, nfs41_op_create_session},
00160   {"OP_DESTROY_SESSION", NFS4_OP_DESTROY_SESSION, nfs41_op_destroy_session},
00161   {"OP_FREE_STATEID", NFS4_OP_FREE_STATEID, nfs41_op_free_stateid},   
00162   {"OP_GET_DIR_DELEGATION", NFS4_OP_GET_DIR_DELEGATION, nfs4_op_illegal},       /* tbd */
00163   {"OP_GETDEVICEINFO", NFS4_OP_GETDEVICEINFO, nfs41_op_getdeviceinfo},
00164   {"OP_GETDEVICELIST", NFS4_OP_GETDEVICELIST, nfs41_op_getdevicelist},
00165   {"OP_LAYOUTCOMMIT", NFS4_OP_LAYOUTCOMMIT, nfs41_op_layoutcommit},
00166   {"OP_LAYOUTGET", NFS4_OP_LAYOUTGET, nfs41_op_layoutget},
00167   {"OP_LAYOUTRETURN", NFS4_OP_LAYOUTRETURN, nfs41_op_layoutreturn},
00168   {"OP_SECINFO_NO_NAME", NFS4_OP_SECINFO_NO_NAME, nfs4_op_illegal},     /* tbd */
00169   {"OP_SEQUENCE", NFS4_OP_SEQUENCE, nfs41_op_sequence},
00170   {"OP_SET_SSV", NFS4_OP_SET_SSV, nfs41_op_set_ssv},
00171   {"OP_TEST_STATEID", NFS4_OP_TEST_STATEID, nfs41_op_test_stateid}, 
00172   {"OP_WANT_DELEGATION", NFS4_OP_WANT_DELEGATION, nfs4_op_illegal},     /* tbd */
00173   {"OP_DESTROY_CLIENTID", NFS4_OP_DESTROY_CLIENTID, nfs4_op_illegal},   /* tbd */
00174   {"OP_RECLAIM_COMPLETE", NFS4_OP_RECLAIM_COMPLETE, nfs41_op_reclaim_complete},
00175   {"OP_ILLEGAL", NFS4_OP_ILLEGAL, nfs4_op_illegal}
00176 };
00177 #endif                          /* _USE_NFS4_1 */
00178 
00179 #ifdef _USE_NFS4_1
00180 nfs4_op_desc_t *optabvers[] =
00181     { (nfs4_op_desc_t *) optab4v0, (nfs4_op_desc_t *) optab4v1 };
00182 #else
00183 nfs4_op_desc_t *optabvers[] = { (nfs4_op_desc_t *) optab4v0 };
00184 #endif
00185 
00207 int nfs4_Compound(nfs_arg_t *parg,
00208                   exportlist_t *pexport,
00209                   fsal_op_context_t *pcontext,
00210                   nfs_worker_data_t *pworker,
00211                   struct svc_req *preq,
00212                   nfs_res_t * pres)
00213 {
00214   unsigned int i = 0;
00215   int status = NFS4_OK;
00216   struct nfs_resop4 res;
00217   char __attribute__ ((__unused__)) funcname[] = "nfs4_Compound";
00218   compound_data_t data;
00219   int opindex;
00220   #define TAGLEN 64
00221   char tagstr[TAGLEN + 1 + 5];
00222 
00223   /* A "local" #define to avoid typo with nfs (too) long structure names */
00224 #define COMPOUND4_ARRAY parg->arg_compound4.argarray
00225 #define COMPOUND4_MINOR parg->arg_compound4.minorversion
00226 
00227 #ifdef _USE_NFS4_1
00228   if(COMPOUND4_MINOR > 1)
00229 #else
00230   if(COMPOUND4_MINOR != 0)
00231 #endif
00232     {
00233       LogCrit(COMPONENT_NFS_V4,
00234               "Bad Minor Version %d",
00235               COMPOUND4_MINOR);
00236 
00237       pres->res_compound4.status = NFS4ERR_MINOR_VERS_MISMATCH;
00238       pres->res_compound4.resarray.resarray_len = 0;
00239       return NFS_REQ_OK;
00240     }
00241 
00242   /* Check for empty COMPOUND request */
00243   if(COMPOUND4_ARRAY.argarray_len == 0)
00244     {
00245       LogMajor(COMPONENT_NFS_V4,
00246                "An empty COMPOUND (no operation in it) was received");
00247 
00248       pres->res_compound4.status = NFS4_OK;
00249       pres->res_compound4.resarray.resarray_len = 0;
00250       return NFS_REQ_OK;
00251     }
00252 
00253   /* Check if this export supports NFSv4 */
00254   if( ( pexport->options & EXPORT_OPTION_NFSV4 ) == 0 )
00255    {
00256       LogMajor( COMPONENT_NFS_V4,
00257                 "The export(id=%u) does not support NFSv4... rejecting it", pexport->id ) ;
00258       pres->res_compound4.status = NFS4ERR_PERM ;
00259       pres->res_compound4.resarray.resarray_len = 0;
00260       return NFS_REQ_OK ;
00261    }
00262 
00263   /* Check for too long request */
00264   if(COMPOUND4_ARRAY.argarray_len > 30)
00265     {
00266       LogMajor(COMPONENT_NFS_V4,
00267                "A COMPOUND with too many operations (%d) was received",
00268                COMPOUND4_ARRAY.argarray_len);
00269 
00270       pres->res_compound4.status = NFS4ERR_RESOURCE;
00271       pres->res_compound4.resarray.resarray_len = 0;
00272       return NFS_REQ_OK;
00273     }
00274 
00275   /* Initialisation of the compound request internal's data */
00276   memset(&data, 0, sizeof(data));
00277 
00278   /* Minor version related stuff */
00279   data.minorversion = COMPOUND4_MINOR;
00282   data.pfullexportlist = pexport;       /* Full export list is
00283                                            provided in input */
00284   data.pcontext = pcontext; /* Get the fsal credentials from the
00285                                worker thread */
00286   data.pworker = pworker;
00287   data.pseudofs = nfs4_GetPseudoFs();
00288   data.reqp = preq;
00289 
00290   strcpy(data.MntPath, "/");
00291 
00292   /* Building the client credential field */
00293   if(nfs_rpc_req2client_cred(preq, &(data.credential)) == -1)
00294     return NFS_REQ_DROP;        /* Malformed credential */
00295 
00296   /* Keeping the same tag as in the arguments */
00297   memcpy(&(pres->res_compound4.tag), &(parg->arg_compound4.tag),
00298          sizeof(parg->arg_compound4.tag));
00299 
00300   if(utf8dup(&(pres->res_compound4.tag), &(parg->arg_compound4.tag)) == -1)
00301     {
00302       LogCrit(COMPONENT_NFS_V4, "Unable to duplicate tag into response");
00303       return NFS_REQ_DROP;
00304     }
00305 
00306   /* Allocating the reply nfs_resop4 */
00307   if((pres->res_compound4.resarray.resarray_val =
00308       gsh_calloc((COMPOUND4_ARRAY.argarray_len),
00309                  sizeof(struct nfs_resop4))) == NULL)
00310     {
00311       return NFS_REQ_DROP;
00312     }
00313 
00314   if(isDebug(COMPONENT_NFS_V4) && pres->res_compound4.tag.utf8string_len > 0)
00315     {
00316       sprintf(tagstr, " TAG=");
00317       utf82str(tagstr+5, TAGLEN, &(pres->res_compound4.tag));
00318     }
00319   else
00320     {
00321       tagstr[0] = '\0';
00322     }
00323 
00324   /* Managing the operation list */
00325   LogDebug(COMPONENT_NFS_V4,
00326            "COMPOUND: There are %d operations%s",
00327            COMPOUND4_ARRAY.argarray_len, tagstr);
00328 
00329 #ifdef _USE_NFS4_1
00330   /* Manage error NFS4ERR_NOT_ONLY_OP */
00331   if(COMPOUND4_ARRAY.argarray_len > 1)
00332     {
00333       /* If not prepended ny OP4_SEQUENCE, OP4_EXCHANGE_ID should be the only request in the compound
00334        * see 18.35.3. and test EID8 for details */
00335       if(optabvers[1][optab4index[COMPOUND4_ARRAY.argarray_val[0].argop]].val ==
00336          NFS4_OP_EXCHANGE_ID)
00337         {
00338           status = NFS4ERR_NOT_ONLY_OP;
00339           pres->res_compound4.resarray.resarray_val[0].nfs_resop4_u.opexchange_id.
00340               eir_status = status;
00341           pres->res_compound4.status = status;
00342 
00343           return NFS_REQ_OK;
00344         }
00345     }
00346 #endif
00347 
00348   pres->res_compound4.resarray.resarray_len = COMPOUND4_ARRAY.argarray_len;
00349   for(i = 0; i < COMPOUND4_ARRAY.argarray_len; i++)
00350     {
00351       /* Use optab4index to reference the operation */
00352 #ifdef _USE_NFS4_1
00353       data.oppos = i;           /* Useful to check if OP_SEQUENCE is used as the first operation */
00354 
00355       if(COMPOUND4_MINOR == 1)
00356         {
00357           if(data.psession != NULL)
00358             {
00359               if(data.psession->fore_channel_attrs.ca_maxoperations == i)
00360                 {
00361                   status = NFS4ERR_TOO_MANY_OPS;
00362                   pres->res_compound4.resarray.resarray_val[i].nfs_resop4_u.opaccess.
00363                       status = status;
00364                   pres->res_compound4.resarray.resarray_val[i].resop =
00365                       COMPOUND4_ARRAY.argarray_val[i].argop;
00366                   pres->res_compound4.status = status;
00367                   break;        /* stop loop */
00368                 }
00369             }
00370         }
00371 
00372       /* if( COMPOUND4_MINOR == 1 ) */
00373       if((COMPOUND4_ARRAY.argarray_val[i].argop <= NFS4_OP_RELEASE_LOCKOWNER
00374           && COMPOUND4_MINOR == 0)
00375          || (COMPOUND4_ARRAY.argarray_val[i].argop <= NFS4_OP_RECLAIM_COMPLETE
00376              && COMPOUND4_MINOR == 1))
00377 #else
00378       if(COMPOUND4_ARRAY.argarray_val[i].argop <= NFS4_OP_RELEASE_LOCKOWNER)
00379 #endif
00380         opindex = optab4index[COMPOUND4_ARRAY.argarray_val[i].argop];
00381       else
00382        {
00383          /* Set optindex to op_illegal */
00384 #ifdef _USE_NFS4_1
00385          opindex = (COMPOUND4_MINOR==0)?optab4index[POS_ILLEGAL_V40]:optab4index[POS_ILLEGAL_V41];  
00386 #else
00387          opindex = optab4index[POS_ILLEGAL_V40];
00388 #endif
00389          LogMajor( COMPONENT_NFS_V4, "Client is using Illegal operation #%u", COMPOUND4_ARRAY.argarray_val[i].argop ) ;
00390        }
00391 
00392       LogDebug(COMPONENT_NFS_V4,
00393                "Request %d is %d = %s, entry %d in the op array%s",
00394                i,
00395                optabvers[COMPOUND4_MINOR][opindex].val,
00396                optabvers[COMPOUND4_MINOR][opindex].name,
00397                opindex,
00398                tagstr);
00399 
00400       memset(&res, 0, sizeof(res));
00401       status = (optabvers[COMPOUND4_MINOR][opindex].funct) (&(COMPOUND4_ARRAY.argarray_val[i]),
00402                                                             &data,
00403                                                             &res);
00404 
00405       memcpy(&(pres->res_compound4.resarray.resarray_val[i]), &res, sizeof(res));
00406 
00407       LogCompoundFH(&data);
00408 
00409       /* All the operation, like NFS4_OP_ACESS, have a first replyied field called .status */
00410       pres->res_compound4.resarray.resarray_val[i].nfs_resop4_u.opaccess.status = status;
00411 
00412       if(status != NFS4_OK)
00413         {
00414           /* An error occured, we do not manage the other requests in the COMPOUND, this may be a regular behaviour */
00415           LogDebug(COMPONENT_NFS_V4,
00416                    "Status of %s in position %d = %s%s",
00417                    optabvers[COMPOUND4_MINOR][opindex].name,
00418                    i,
00419                    nfsstat4_to_str(status),
00420                    tagstr);
00421 
00422           pres->res_compound4.resarray.resarray_len = i + 1;
00423 
00424           break;
00425         }
00426 #ifdef _USE_NFS4_1
00427       /* Check Req size */
00428 
00429       /* NFS_V4.1 specific stuff */
00430       if(data.use_drc)
00431         {
00432           /* Replay cache, only true for SEQUENCE or CREATE_SESSION w/o SEQUENCE.
00433            * Since will only be set in those cases, no need to check operation or anything.
00434            */
00435           LogFullDebug(COMPONENT_SESSIONS,
00436                        "Use session replay cache %p",
00437                        data.pcached_res);
00438 
00439           /* Free the reply allocated above */
00440           gsh_free(pres->res_compound4.resarray.resarray_val);
00441 
00442           /* Copy the reply from the cache */
00443           pres->res_compound4_extended = *data.pcached_res;
00444           status = ((COMPOUND4res *) data.pcached_res)->status;
00445           break;    /* Exit the for loop */
00446         }
00447 #endif
00448     }                           /* for */
00449 
00450   /* Complete the reply, in particular, tell where you stopped if unsuccessfull COMPOUD */
00451   pres->res_compound4.status = status;
00452 
00453 #ifdef _USE_NFS4_1
00454   /* Manage session's DRC: keep NFS4.1 replay for later use, but don't save a
00455    * replayed result again.
00456    */
00457   if(data.pcached_res != NULL && !data.use_drc)
00458     {
00459       /* Pointer has been set by nfs41_op_sequence and points to slot to cache
00460        * result in.
00461        */
00462       LogFullDebug(COMPONENT_SESSIONS,
00463                    "Save result in session replay cache %p sizeof nfs_res_t=%d",
00464                    data.pcached_res,
00465                    (int) sizeof(nfs_res_t));
00466 
00467       /* Indicate to nfs4_Compound_Free that this reply is cached. */
00468       pres->res_compound4_extended.res_cached = TRUE;
00469 
00470       /* If the cache is already in use, free it. */
00471       if(data.pcached_res->res_cached)
00472         {
00473           data.pcached_res->res_cached = FALSE;
00474           nfs4_Compound_Free((nfs_res_t *)data.pcached_res);
00475         }
00476 
00477       /* Save the result in the cache. */
00478       *data.pcached_res = pres->res_compound4_extended;
00479     }
00480 
00481   /* If we have reserved a lease, update it and release it */
00482   if(data.preserved_clientid != NULL)
00483     {
00484       /* Update and release lease */
00485       P(data.preserved_clientid->cid_mutex);
00486 
00487       update_lease(data.preserved_clientid);
00488 
00489       V(data.preserved_clientid->cid_mutex);
00490     }
00491 #endif
00492 
00493   if(status != NFS4_OK)
00494     LogDebug(COMPONENT_NFS_V4,
00495              "End status = %s lastindex = %d%s",
00496              nfsstat4_to_str(status), i, tagstr);
00497 
00498   compound_data_Free(&data);
00499 
00500   return NFS_REQ_OK;
00501 }                               /* nfs4_Compound */
00502 
00514 void nfs4_Compound_FreeOne(nfs_resop4 *pres)
00515 {
00516   switch (pres->resop)
00517     {
00518       case NFS4_OP_ACCESS:
00519         nfs4_op_access_Free(&(pres->nfs_resop4_u.opaccess));
00520         break;
00521 
00522       case NFS4_OP_CLOSE:
00523         nfs4_op_close_Free(&(pres->nfs_resop4_u.opclose));
00524         break;
00525 
00526       case NFS4_OP_COMMIT:
00527         nfs4_op_commit_Free(&(pres->nfs_resop4_u.opcommit));
00528         break;
00529 
00530       case NFS4_OP_CREATE:
00531         nfs4_op_create_Free(&(pres->nfs_resop4_u.opcreate));
00532         break;
00533 
00534       case NFS4_OP_DELEGPURGE:
00535         nfs4_op_delegpurge_Free(&(pres->nfs_resop4_u.opdelegpurge));
00536         break;
00537 
00538       case NFS4_OP_DELEGRETURN:
00539         nfs4_op_delegreturn_Free(&(pres->nfs_resop4_u.opdelegreturn));
00540         break;
00541 
00542       case NFS4_OP_GETATTR:
00543         nfs4_op_getattr_Free(&(pres->nfs_resop4_u.opgetattr));
00544         break;
00545 
00546       case NFS4_OP_GETFH:
00547         nfs4_op_getfh_Free(&(pres->nfs_resop4_u.opgetfh));
00548         break;
00549 
00550       case NFS4_OP_LINK:
00551         nfs4_op_link_Free(&(pres->nfs_resop4_u.oplink));
00552         break;
00553 
00554       case NFS4_OP_LOCK:
00555         nfs4_op_lock_Free(&(pres->nfs_resop4_u.oplock));
00556         break;
00557 
00558       case NFS4_OP_LOCKT:
00559         nfs4_op_lockt_Free(&(pres->nfs_resop4_u.oplockt));
00560         break;
00561 
00562       case NFS4_OP_LOCKU:
00563         nfs4_op_locku_Free(&(pres->nfs_resop4_u.oplocku));
00564         break;
00565 
00566       case NFS4_OP_LOOKUP:
00567         nfs4_op_lookup_Free(&(pres->nfs_resop4_u.oplookup));
00568         break;
00569 
00570       case NFS4_OP_LOOKUPP:
00571         nfs4_op_lookupp_Free(&(pres->nfs_resop4_u.oplookupp));
00572         break;
00573 
00574       case NFS4_OP_NVERIFY:
00575         nfs4_op_nverify_Free(&(pres->nfs_resop4_u.opnverify));
00576         break;
00577 
00578       case NFS4_OP_OPEN:
00579         nfs4_op_open_Free(&(pres->nfs_resop4_u.opopen));
00580         break;
00581 
00582       case NFS4_OP_OPENATTR:
00583         nfs4_op_openattr_Free(&(pres->nfs_resop4_u.opopenattr));
00584         break;
00585 
00586       case NFS4_OP_OPEN_CONFIRM:
00587         nfs4_op_open_confirm_Free(&(pres->nfs_resop4_u.opopen_confirm));
00588         break;
00589 
00590       case NFS4_OP_OPEN_DOWNGRADE:
00591         nfs4_op_open_downgrade_Free(&(pres->nfs_resop4_u.opopen_downgrade));
00592         break;
00593 
00594       case NFS4_OP_PUTFH:
00595         nfs4_op_putfh_Free(&(pres->nfs_resop4_u.opputfh));
00596         break;
00597 
00598       case NFS4_OP_PUTPUBFH:
00599         nfs4_op_putpubfh_Free(&(pres->nfs_resop4_u.opputpubfh));
00600         break;
00601 
00602       case NFS4_OP_PUTROOTFH:
00603         nfs4_op_putrootfh_Free(&(pres->nfs_resop4_u.opputrootfh));
00604         break;
00605 
00606       case NFS4_OP_READ:
00607         nfs4_op_read_Free(&(pres->nfs_resop4_u.opread));
00608         break;
00609 
00610       case NFS4_OP_READDIR:
00611         nfs4_op_readdir_Free(&(pres->nfs_resop4_u.opreaddir));
00612         break;
00613 
00614       case NFS4_OP_READLINK:
00615         nfs4_op_readlink_Free(&(pres->nfs_resop4_u.opreadlink));
00616         break;
00617 
00618       case NFS4_OP_REMOVE:
00619         nfs4_op_remove_Free(&(pres->nfs_resop4_u.opremove));
00620         break;
00621 
00622       case NFS4_OP_RENAME:
00623         nfs4_op_rename_Free(&(pres->nfs_resop4_u.oprename));
00624         break;
00625 
00626       case NFS4_OP_RENEW:
00627         nfs4_op_renew_Free(&(pres->nfs_resop4_u.oprenew));
00628         break;
00629 
00630       case NFS4_OP_RESTOREFH:
00631         nfs4_op_restorefh_Free(&(pres->nfs_resop4_u.oprestorefh));
00632         break;
00633 
00634       case NFS4_OP_SAVEFH:
00635         nfs4_op_savefh_Free(&(pres->nfs_resop4_u.opsavefh));
00636         break;
00637 
00638       case NFS4_OP_SECINFO:
00639         nfs4_op_secinfo_Free(&(pres->nfs_resop4_u.opsecinfo));
00640         break;
00641 
00642       case NFS4_OP_SETATTR:
00643         nfs4_op_setattr_Free(&(pres->nfs_resop4_u.opsetattr));
00644         break;
00645 
00646       case NFS4_OP_SETCLIENTID:
00647         nfs4_op_setclientid_Free(&(pres->nfs_resop4_u.opsetclientid));
00648         break;
00649 
00650       case NFS4_OP_SETCLIENTID_CONFIRM:
00651         nfs4_op_setclientid_confirm_Free(&(pres->nfs_resop4_u.opsetclientid_confirm));
00652         break;
00653 
00654       case NFS4_OP_VERIFY:
00655         nfs4_op_verify_Free(&(pres->nfs_resop4_u.opverify));
00656         break;
00657 
00658       case NFS4_OP_WRITE:
00659         nfs4_op_write_Free(&(pres->nfs_resop4_u.opwrite));
00660         break;
00661 
00662       case NFS4_OP_RELEASE_LOCKOWNER:
00663         nfs4_op_release_lockowner_Free(&(pres->nfs_resop4_u.oprelease_lockowner));
00664         break;
00665 
00666 #ifdef _USE_NFS4_1
00667       case NFS4_OP_EXCHANGE_ID:
00668         nfs41_op_exchange_id_Free(&(pres->nfs_resop4_u.opexchange_id));
00669         break;
00670 
00671       case NFS4_OP_CREATE_SESSION:
00672         nfs41_op_create_session_Free(&(pres->nfs_resop4_u.opcreate_session));
00673         break;
00674 
00675       case NFS4_OP_SEQUENCE:
00676         nfs41_op_sequence_Free(&(pres->nfs_resop4_u.opsequence));
00677         break;
00678 
00679       case NFS4_OP_GETDEVICEINFO:
00680         nfs41_op_getdeviceinfo_Free(&(pres->nfs_resop4_u.opgetdeviceinfo));
00681         break;
00682 
00683       case NFS4_OP_GETDEVICELIST:
00684         nfs41_op_getdevicelist_Free(&(pres->nfs_resop4_u.opgetdevicelist));
00685         break;
00686 
00687       case NFS4_OP_TEST_STATEID:
00688         nfs41_op_test_stateid_Free(&(pres->nfs_resop4_u.optest_stateid));
00689         break;
00690 
00691       case NFS4_OP_FREE_STATEID:
00692         nfs41_op_free_stateid_Free(&(pres->nfs_resop4_u.opfree_stateid));
00693         break;
00694 
00695       case NFS4_OP_BACKCHANNEL_CTL:
00696       case NFS4_OP_BIND_CONN_TO_SESSION:
00697       case NFS4_OP_DESTROY_SESSION:
00698       case NFS4_OP_GET_DIR_DELEGATION:
00699       case NFS4_OP_LAYOUTCOMMIT:
00700       case NFS4_OP_LAYOUTGET:
00701       case NFS4_OP_LAYOUTRETURN:
00702       case NFS4_OP_SECINFO_NO_NAME:
00703       case NFS4_OP_SET_SSV:
00704       case NFS4_OP_WANT_DELEGATION:
00705       case NFS4_OP_DESTROY_CLIENTID:
00706       case NFS4_OP_RECLAIM_COMPLETE:
00707         nfs41_op_reclaim_complete_Free(&(pres->nfs_resop4_u.opreclaim_complete));
00708         break;
00709 #endif
00710 
00711       case NFS4_OP_ILLEGAL:
00712         nfs4_op_illegal_Free(&(pres->nfs_resop4_u.opillegal));
00713         break;
00714     }                       /* switch */
00715 }
00716 
00730 void nfs4_Compound_Free(nfs_res_t *pres)
00731 {
00732   unsigned int     i = 0;
00733   log_components_t component = COMPONENT_NFS_V4;
00734 
00735   if(isFullDebug(COMPONENT_SESSIONS))
00736     component = COMPONENT_SESSIONS;
00737 
00738   if(pres->res_compound4_extended.res_cached)
00739     {
00740       LogFullDebug(component,
00741                    "Skipping free of NFS4 result %p",
00742                    pres);
00743       return;
00744     }
00745 
00746   LogFullDebug(component,
00747                "nfs4_Compound_Free %p (resarraylen=%i)",
00748                pres,
00749                pres->res_compound4.resarray.resarray_len);
00750 
00751   for(i = 0; i < pres->res_compound4.resarray.resarray_len; i++) {
00752       nfs_resop4 *val = &pres->res_compound4.resarray.resarray_val[i];
00753       if (val) {
00754           /* !val is an error case, but it can occur, so avoid
00755            * indirect on NULL */
00756           nfs4_Compound_FreeOne(val);
00757       }
00758   }
00759 
00760   gsh_free(pres->res_compound4.resarray.resarray_val);
00761   free_utf8(&pres->res_compound4.tag);
00762 
00763   return;
00764 }                               /* nfs4_Compound_Free */
00765 
00779 void compound_data_Free(compound_data_t * data)
00780 {
00781   /* Release refcounted cache entries */
00782   if (data->current_entry)
00783       cache_inode_put(data->current_entry);
00784 
00785   if (data->saved_entry)
00786       cache_inode_put(data->saved_entry);
00787 
00788   if(data->currentFH.nfs_fh4_val != NULL)
00789     gsh_free(data->currentFH.nfs_fh4_val);
00790 
00791   if(data->rootFH.nfs_fh4_val != NULL)
00792     gsh_free(data->rootFH.nfs_fh4_val);
00793 
00794   if(data->publicFH.nfs_fh4_val != NULL)
00795     gsh_free(data->publicFH.nfs_fh4_val);
00796 
00797   if(data->savedFH.nfs_fh4_val != NULL)
00798     gsh_free(data->savedFH.nfs_fh4_val);
00799 
00800   if(data->mounted_on_FH.nfs_fh4_val != NULL)
00801     gsh_free(data->mounted_on_FH.nfs_fh4_val);
00802 
00803 }                               /* compound_data_Free */
00804 
00810 void nfs4_Compound_CopyResOne(nfs_resop4 * pres_dst, nfs_resop4 * pres_src)
00811 {
00812   /* Copy base data structure */
00813   memcpy(pres_dst, pres_src, sizeof(*pres_dst));
00814 
00815   /* Do deep copy where necessary */
00816   switch (pres_src->resop)
00817     {
00818       case NFS4_OP_ACCESS:
00819         break;
00820 
00821       case NFS4_OP_CLOSE:
00822         nfs4_op_close_CopyRes(&(pres_dst->nfs_resop4_u.opclose),
00823                               &(pres_src->nfs_resop4_u.opclose));
00824         return;
00825 
00826       case NFS4_OP_COMMIT:
00827       case NFS4_OP_CREATE:
00828       case NFS4_OP_DELEGPURGE:
00829       case NFS4_OP_DELEGRETURN:
00830       case NFS4_OP_GETATTR:
00831       case NFS4_OP_GETFH:
00832       case NFS4_OP_LINK:
00833         break;
00834 
00835       case NFS4_OP_LOCK:
00836         nfs4_op_lock_CopyRes(&(pres_dst->nfs_resop4_u.oplock),
00837                              &(pres_src->nfs_resop4_u.oplock));
00838         return;
00839 
00840       case NFS4_OP_LOCKT:
00841         break;
00842 
00843       case NFS4_OP_LOCKU:
00844         nfs4_op_locku_CopyRes(&(pres_dst->nfs_resop4_u.oplocku),
00845                               &(pres_src->nfs_resop4_u.oplocku));
00846         return;
00847 
00848       case NFS4_OP_LOOKUP:
00849       case NFS4_OP_LOOKUPP:
00850       case NFS4_OP_NVERIFY:
00851         break;
00852 
00853       case NFS4_OP_OPEN:
00854         nfs4_op_open_CopyRes(&(pres_dst->nfs_resop4_u.opopen),
00855                              &(pres_src->nfs_resop4_u.opopen));
00856         return;
00857 
00858       case NFS4_OP_OPENATTR:
00859         break;
00860 
00861       case NFS4_OP_OPEN_CONFIRM:
00862         nfs4_op_open_confirm_CopyRes(&(pres_dst->nfs_resop4_u.opopen_confirm),
00863                                      &(pres_src->nfs_resop4_u.opopen_confirm));
00864         return;
00865 
00866       case NFS4_OP_OPEN_DOWNGRADE:
00867         nfs4_op_open_downgrade_CopyRes(&(pres_dst->nfs_resop4_u.opopen_downgrade),
00868                                        &(pres_src->nfs_resop4_u.opopen_downgrade));
00869         return;
00870 
00871       case NFS4_OP_PUTFH:
00872       case NFS4_OP_PUTPUBFH:
00873       case NFS4_OP_PUTROOTFH:
00874       case NFS4_OP_READ:
00875       case NFS4_OP_READDIR:
00876       case NFS4_OP_READLINK:
00877       case NFS4_OP_REMOVE:
00878       case NFS4_OP_RENAME:
00879       case NFS4_OP_RENEW:
00880       case NFS4_OP_RESTOREFH:
00881       case NFS4_OP_SAVEFH:
00882       case NFS4_OP_SECINFO:
00883       case NFS4_OP_SETATTR:
00884       case NFS4_OP_SETCLIENTID:
00885       case NFS4_OP_SETCLIENTID_CONFIRM:
00886       case NFS4_OP_VERIFY:
00887       case NFS4_OP_WRITE:
00888       case NFS4_OP_RELEASE_LOCKOWNER:
00889         break;
00890 
00891 #ifdef _USE_NFS4_1
00892       case NFS4_OP_EXCHANGE_ID:
00893       case NFS4_OP_CREATE_SESSION:
00894       case NFS4_OP_SEQUENCE:
00895       case NFS4_OP_GETDEVICEINFO:
00896       case NFS4_OP_GETDEVICELIST:
00897       case NFS4_OP_BACKCHANNEL_CTL:
00898       case NFS4_OP_BIND_CONN_TO_SESSION:
00899       case NFS4_OP_DESTROY_SESSION:
00900       case NFS4_OP_FREE_STATEID:
00901       case NFS4_OP_GET_DIR_DELEGATION:
00902       case NFS4_OP_LAYOUTCOMMIT:
00903       case NFS4_OP_LAYOUTGET:
00904       case NFS4_OP_LAYOUTRETURN:
00905       case NFS4_OP_SECINFO_NO_NAME:
00906       case NFS4_OP_SET_SSV:
00907       case NFS4_OP_TEST_STATEID:
00908       case NFS4_OP_WANT_DELEGATION:
00909       case NFS4_OP_DESTROY_CLIENTID:
00910       case NFS4_OP_RECLAIM_COMPLETE:
00911         break;
00912 #endif
00913 
00914       case NFS4_OP_ILLEGAL:
00915         break;
00916     }                       /* switch */
00917 
00918   LogFatal(COMPONENT_NFS_V4,
00919            "nfs4_Compound_CopyResOne not implemented for %d",
00920            pres_src->resop);
00921 }
00922 
00936 void nfs4_Compound_CopyRes(nfs_res_t * pres_dst, nfs_res_t * pres_src)
00937 {
00938   unsigned int i = 0;
00939 
00940   LogFullDebug(COMPONENT_NFS_V4,
00941                "nfs4_Compound_CopyRes of %p to %p (resarraylen : %i)",
00942                pres_src, pres_dst,
00943                pres_src->res_compound4.resarray.resarray_len);
00944 
00945   for(i = 0; i < pres_src->res_compound4.resarray.resarray_len; i++)
00946     nfs4_Compound_CopyResOne(&pres_dst->res_compound4.resarray.resarray_val[i],
00947                              &pres_src->res_compound4.resarray.resarray_val[i]);
00948 }
00949 
00964 int nfs4_op_stat_update(nfs_arg_t * parg /* IN     */ ,
00965                         nfs_res_t * pres /* IN    */ ,
00966                         nfs_request_stat_t * pstat_req /* OUT */ )
00967 {
00968   int i = 0;
00969 
00970   switch (COMPOUND4_MINOR)
00971     {
00972     case 0:
00973       for(i = 0; i < pres->res_compound4.resarray.resarray_len; i++)
00974         {
00975           pstat_req->nb_nfs40_op += 1;
00976           pstat_req->stat_op_nfs40[pres->res_compound4.resarray.resarray_val[i].resop].
00977               total += 1;
00978 
00979           /* All operations's reply structures start with their status, whatever the name of this field */
00980           if(pres->res_compound4.resarray.resarray_val[i].nfs_resop4_u.opaccess.status ==
00981              NFS4_OK)
00982             pstat_req->stat_op_nfs40[pres->res_compound4.resarray.resarray_val[i].resop].
00983                 success += 1;
00984           else
00985             pstat_req->stat_op_nfs40[pres->res_compound4.resarray.resarray_val[i].resop].
00986                 failed += 1;
00987         }
00988       break;
00989 
00990 #ifdef _USE_NFS4_1
00991     case 1:
00992       for(i = 0; i < pres->res_compound4.resarray.resarray_len; i++)
00993         {
00994           pstat_req->nb_nfs41_op += 1;
00995           pstat_req->stat_op_nfs41[pres->res_compound4.resarray.resarray_val[i].resop].
00996               total += 1;
00997 
00998           /* All operations's reply structures start with their status, whatever the name of this field */
00999           if(pres->res_compound4.resarray.resarray_val[i].nfs_resop4_u.opaccess.status ==
01000              NFS4_OK)
01001             pstat_req->stat_op_nfs41[pres->res_compound4.resarray.resarray_val[i].resop].
01002                 success += 1;
01003           else
01004             pstat_req->stat_op_nfs41[pres->res_compound4.resarray.resarray_val[i].resop].
01005                 failed += 1;
01006         }
01007 
01008       break;
01009 #endif
01010 
01011     default:
01012       /* Bad parameter */
01013       return -1;
01014     }
01015   return 0;
01016 }                               /* nfs4_op_stat_update */