nfs-ganesha 1.4

nfs41_op_open.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 
00037 #ifdef HAVE_CONFIG_H
00038 #include "config.h"
00039 #endif
00040 
00041 #ifdef _SOLARIS
00042 #include "solaris_port.h"
00043 #endif
00044 
00045 #include <stdio.h>
00046 #include <string.h>
00047 #include <pthread.h>
00048 #include "HashData.h"
00049 #include "HashTable.h"
00050 #include "log.h"
00051 #include "ganesha_rpc.h"
00052 #include "nfs4.h"
00053 #include "nfs_core.h"
00054 #include "sal_functions.h"
00055 #include "nfs_proto_functions.h"
00056 #include "nfs_proto_tools.h"
00057 #include "cache_inode_lru.h"
00058 
00072 #define arg_OPEN4 op->nfs_argop4_u.opopen
00073 #define res_OPEN4 resp->nfs_resop4_u.opopen
00074 
00075 int nfs41_op_open(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp)
00076 {
00077   cache_entry_t           * pentry_parent = NULL;
00078   cache_entry_t           * pentry_lookup = NULL;
00079   cache_entry_t           * pentry_newfile = NULL;
00080   fsal_handle_t           * pnewfsal_handle = NULL;
00081   fsal_attrib_list_t        attr_parent;
00082   fsal_attrib_list_t        attr;
00083   fsal_attrib_list_t        attr_newfile;
00084   fsal_attrib_list_t        sattr;
00085   fsal_openflags_t          openflags = 0;
00086   cache_inode_status_t      cache_status = CACHE_INODE_SUCCESS;
00087   state_status_t            state_status;
00088   int                       retval;
00089   fsal_name_t               filename;
00090   bool_t                    AttrProvided = FALSE;
00091   bool_t                    ReuseState = FALSE;
00092   fsal_accessmode_t         mode = 0600;
00093   nfs_fh4                   newfh4;
00094   struct alloc_file_handle_v4 new_handle;
00095   state_data_t              candidate_data;
00096   state_type_t              candidate_type;
00097   state_t                 * pfile_state = NULL;
00098   state_t                 * pstate_iterate;
00099   state_nfs4_owner_name_t   owner_name;
00100   state_owner_t           * powner = NULL;
00101   const char              * tag = "OPEN";
00102   const char              * cause = "OOPS";
00103   const char              * cause2 = "";
00104   struct glist_head       * glist;
00105 #ifdef _USE_QUOTA
00106   fsal_status_t            fsal_status ;
00107 #endif
00108 
00109   LogDebug(COMPONENT_STATE,
00110            "Entering NFS v4.1 OPEN handler -----------------------------------------------------");
00111 
00112   newfh4.nfs_fh4_val = (caddr_t) &new_handle;
00113   newfh4.nfs_fh4_len = sizeof(struct alloc_file_handle_v4);
00114 
00115   fsal_accessflags_t write_access = FSAL_WRITE_ACCESS;
00116   fsal_accessflags_t read_access = FSAL_READ_ACCESS;
00117 
00118   resp->resop = NFS4_OP_OPEN;
00119   res_OPEN4.status = NFS4_OK;
00120 
00121   uint32_t tmp_attr[2];
00122 
00123   cache_inode_create_arg_t create_arg = {
00124        .newly_created_dir = FALSE
00125   };
00126 
00127   memset(&create_arg, 0, sizeof(create_arg));
00128 
00129   /*
00130    * Do basic checks on a filehandle
00131    */
00132   res_OPEN4.status = nfs4_sanity_check_FH(data, 0LL);
00133   if(res_OPEN4.status != NFS4_OK)
00134     goto out;
00135 
00136   /* This can't be done on the pseudofs */
00137   if(nfs4_Is_Fh_Pseudo(&(data->currentFH)))
00138     {
00139       res_OPEN4.status = NFS4ERR_ROFS;
00140       LogDebug(COMPONENT_STATE,
00141                "NFS41 OPEN returning NFS4ERR_ROFS");
00142       goto out;
00143     }
00144 
00145   /* If Filehandle points to a xattr object, manage it via the xattrs specific functions */
00146   if(nfs4_Is_Fh_Xattr(&(data->currentFH))) {
00147     res_OPEN4.status = nfs4_op_open_xattr(op, data, resp);
00148     goto out;
00149   }
00150 
00151   /* If data->current_entry is empty, repopulate it */
00152   if(data->current_entry == NULL)
00153     {
00154       if((data->current_entry = nfs_FhandleToCache(NFS_V4,
00155                                                    NULL,
00156                                                    NULL,
00157                                                    &(data->currentFH),
00158                                                    NULL,
00159                                                    NULL,
00160                                                    &(res_OPEN4.status),
00161                                                    &attr,
00162                                                    data->pcontext,
00163                                                    &retval)) == NULL)
00164         {
00165           res_OPEN4.status = NFS4ERR_RESOURCE;
00166           LogDebug(COMPONENT_STATE,
00167                    "NFS41 OPEN returning NFS4ERR_RESOURCE after trying to repopulate cache");
00168           goto out;
00169         }
00170     }
00171 
00172   /* Set parent */
00173   pentry_parent = data->current_entry;
00174 
00175   /* First switch is based upon claim type */
00176   switch (arg_OPEN4.claim.claim)
00177     {
00178     case CLAIM_DELEGATE_CUR:
00179     case CLAIM_DELEGATE_PREV:
00180       /* Check for name length */
00181       if(arg_OPEN4.claim.open_claim4_u.file.utf8string_len > FSAL_MAX_NAME_LEN)
00182         {
00183           res_OPEN4.status = NFS4ERR_NAMETOOLONG;
00184           LogDebug(COMPONENT_STATE,
00185                    "NFS41 OPEN returning NFS4ERR_NAMETOOLONG for CLAIM_DELEGATE");
00186           goto out;
00187         }
00188 
00189       /* get the filename from the argument, it should not be empty */
00190       if(arg_OPEN4.claim.open_claim4_u.file.utf8string_len == 0)
00191         {
00192           res_OPEN4.status = NFS4ERR_INVAL;
00193           LogDebug(COMPONENT_STATE,
00194                    "NFS41 OPEN returning NFS4ERR_INVAL for CLAIM_DELEGATE");
00195           goto out;
00196         }
00197 
00198       res_OPEN4.status = NFS4ERR_NOTSUPP;
00199       LogDebug(COMPONENT_STATE,
00200                "NFS41 OPEN returning NFS4ERR_NOTSUPP for CLAIM_DELEGATE");
00201       goto out;
00202 
00203     case CLAIM_NULL:
00204       cause = "CLAIM_NULL";
00205 
00206       /* Is this open_owner known? If so, get it so we can use replay cache */
00207       convert_nfs4_open_owner(&arg_OPEN4.owner,
00208                               &owner_name,
00209                               data->psession->clientid);
00210 
00211       if(!nfs4_owner_Get_Pointer(&owner_name, &powner))
00212         {
00213           LogFullDebug(COMPONENT_STATE,
00214                        "OPEN new owner");
00215         }
00216       else
00217         {
00218           if(isFullDebug(COMPONENT_STATE))
00219             {
00220               char str[HASHTABLE_DISPLAY_STRLEN];
00221 
00222               display_nfs4_owner(powner, str);
00223 
00224               LogFullDebug(COMPONENT_STATE,
00225                            "A previously known open_owner is used:%p %s arg_OPEN4.seqid=%u",
00226                            powner, str, arg_OPEN4.seqid);
00227             }
00228         }
00229 
00230       /* Check for name length */
00231       if(arg_OPEN4.claim.open_claim4_u.file.utf8string_len > FSAL_MAX_NAME_LEN)
00232         {
00233           res_OPEN4.status = NFS4ERR_NAMETOOLONG;
00234           goto out;
00235         }
00236 
00237       /* get the filename from the argument, it should not be empty */
00238       if(arg_OPEN4.claim.open_claim4_u.file.utf8string_len == 0)
00239         {
00240           res_OPEN4.status = NFS4ERR_INVAL;
00241           cause2 = " (empty filename)";
00242           goto out;
00243         }
00244 
00245       /* Check if asked attributes are correct */
00246       if(arg_OPEN4.openhow.openflag4_u.how.mode == GUARDED4 ||
00247          arg_OPEN4.openhow.openflag4_u.how.mode == UNCHECKED4)
00248         {
00249           if(!nfs4_Fattr_Supported
00250              (&arg_OPEN4.openhow.openflag4_u.how.createhow4_u.createattrs))
00251             {
00252               res_OPEN4.status = NFS4ERR_ATTRNOTSUPP;
00253               goto out;
00254             }
00255 
00256           /* Do not use READ attr, use WRITE attr */
00257           if(!nfs4_Fattr_Check_Access
00258              (&arg_OPEN4.openhow.openflag4_u.how.createhow4_u.createattrs,
00259               FATTR4_ATTR_WRITE))
00260             {
00261               res_OPEN4.status = NFS4ERR_INVAL;
00262               cause2 = " (bad attr)";
00263               goto out;
00264             }
00265         }
00266 
00267       /* Check if filename is correct */
00268       if((cache_status =
00269           cache_inode_error_convert(FSAL_buffdesc2name
00270                                     ((fsal_buffdesc_t *) & arg_OPEN4.claim.open_claim4_u.
00271                                      file, &filename))) != CACHE_INODE_SUCCESS)
00272         {
00273           res_OPEN4.status = nfs4_Errno(cache_status);
00274           cause2 = " FSAL_buffdesc2name";
00275           goto out;
00276         }
00277 
00278       /* Check parent */
00279       pentry_parent = data->current_entry;
00280 
00281       /* Parent must be a directory */
00282       if(pentry_parent->type != DIRECTORY)
00283         {
00284           /* Parent object is not a directory... */
00285           if(pentry_parent->type == SYMBOLIC_LINK)
00286             res_OPEN4.status = NFS4ERR_SYMLINK;
00287           else
00288             res_OPEN4.status = NFS4ERR_NOTDIR;
00289 
00290           cause2 = " (parent not directory)";
00291           goto out;
00292         }
00293 
00294       /* What kind of open is it ? */
00295       LogFullDebug(COMPONENT_STATE,
00296                    "OPEN: Claim type = %d   Open Type = %d  Share Deny = %d   Share Access = %d ",
00297                    arg_OPEN4.claim.claim,
00298                    arg_OPEN4.openhow.opentype,
00299                    arg_OPEN4.share_deny,
00300                    arg_OPEN4.share_access);
00301 
00302       /* It this a known client id ? */
00303       LogDebug(COMPONENT_STATE,
00304                "OPEN Client id = %llx",
00305                (unsigned long long)arg_OPEN4.owner.clientid);
00306 
00307       /* Is this open_owner known ? */
00308       if(powner == NULL)
00309         {
00310           /* This open owner is not known yet, allocated and set up a new one */
00311           powner = create_nfs4_owner(&owner_name,
00312                                      data->psession->pclientid_record,
00313                                      STATE_OPEN_OWNER_NFSV4,
00314                                      NULL,
00315                                      1); /* NFSv4.1 specific, initial seqid is 1 */
00316 
00317           if(powner == NULL)
00318             {
00319               res_OPEN4.status = NFS4ERR_RESOURCE;
00320               LogDebug(COMPONENT_STATE,
00321                        "NFS41 OPEN returning NFS4ERR_RESOURCE for CLAIM_NULL (could not create NFS41 Owner");
00322               goto out;
00323             }
00324         }
00325 
00326       /* Status of parent directory before the operation */
00327       if(cache_inode_getattr(pentry_parent,
00328                              &attr_parent,
00329                              data->pcontext,
00330                              &cache_status) != CACHE_INODE_SUCCESS)
00331         {
00332           res_OPEN4.status = nfs4_Errno(cache_status);
00333           cause2 = " cache_inode_getattr";
00334           goto out;
00335         }
00336 
00337       res_OPEN4.OPEN4res_u.resok4.cinfo.before
00338            = cache_inode_get_changeid4(pentry_parent);
00339 
00340       /* CLient may have provided fattr4 to set attributes at creation time */
00341       if(arg_OPEN4.openhow.openflag4_u.how.mode == GUARDED4 ||
00342          arg_OPEN4.openhow.openflag4_u.how.mode == UNCHECKED4)
00343         {
00344           if(arg_OPEN4.openhow.openflag4_u.how.createhow4_u.createattrs.attrmask.
00345              bitmap4_len != 0)
00346             {
00347               /* Convert fattr4 so nfs4_sattr */
00348               res_OPEN4.status =
00349                   nfs4_Fattr_To_FSAL_attr(&sattr,
00350                                           &(arg_OPEN4.openhow.openflag4_u.how.
00351                                             createhow4_u.createattrs));
00352 
00353               if(res_OPEN4.status != NFS4_OK)
00354                 {
00355                   cause2 = " (nfs4_Fattr_To_FSAL_attr failed)";
00356                   goto out;
00357                 }
00358 
00359               AttrProvided = TRUE;
00360             }
00361         }
00362 
00363       /* Second switch is based upon "openhow" */
00364       switch (arg_OPEN4.openhow.opentype)
00365         {
00366         case OPEN4_CREATE:
00367           /* a new file is to be created */
00368 #ifdef _USE_QUOTA
00369           /* if quota support is active, then we should check is the FSAL allows inode creation or not */
00370           fsal_status = FSAL_check_quota( data->pexport->fullpath, 
00371                                           FSAL_QUOTA_INODES,
00372                                           FSAL_OP_CONTEXT_TO_UID( data->pcontext ) ) ;
00373           if( FSAL_IS_ERROR( fsal_status ) )
00374             {
00375               res_OPEN4.status = NFS4ERR_DQUOT ;
00376               return res_OPEN4.status;
00377             }
00378 #endif /* _USE_QUOTA */
00379 
00380           if(arg_OPEN4.openhow.openflag4_u.how.mode == EXCLUSIVE4)
00381             cause = "OPEN4_CREATE EXCLUSIVE";
00382           else
00383             cause = "OPEN4_CREATE";
00384 
00385           /* Does a file with this name already exist ? */
00386           pentry_lookup = cache_inode_lookup(pentry_parent,
00387                                              &filename,
00388                                              &attr_newfile,
00389                                              data->pcontext,
00390                                              &cache_status);
00391 
00392           if(cache_status != CACHE_INODE_NOT_FOUND)
00393             {
00394               /* if open is UNCHECKED, return NFS4_OK (RFC3530 page 172) */
00395               if(arg_OPEN4.openhow.openflag4_u.how.mode == UNCHECKED4
00396                  && (cache_status == CACHE_INODE_SUCCESS))
00397                 {
00398                   /* If the file is opened for write, OPEN4 while deny share write access,
00399                    * in this case, check caller has write access to the file */
00400                   if(arg_OPEN4.share_deny & OPEN4_SHARE_DENY_WRITE)
00401                     {
00402                       if(cache_inode_access(pentry_lookup,
00403                                             write_access,
00404                                             data->pcontext,
00405                                             &cache_status) != CACHE_INODE_SUCCESS)
00406                         {
00407                           res_OPEN4.status = NFS4ERR_ACCESS;
00408                           goto out;
00409                         }
00410                       openflags = FSAL_O_WRONLY;
00411                     }
00412 
00413                   /* Same check on read: check for readability of a file before opening it for read */
00414                   if(arg_OPEN4.share_access & OPEN4_SHARE_ACCESS_READ)
00415                     {
00416                       if(cache_inode_access(pentry_lookup,
00417                                             read_access,
00418                                             data->pcontext,
00419                                             &cache_status) != CACHE_INODE_SUCCESS)
00420                         {
00421                           res_OPEN4.status = NFS4ERR_ACCESS;
00422                           goto out;
00423                         }
00424                       openflags = FSAL_O_RDONLY;
00425                     }
00426 
00427                   if(AttrProvided == TRUE)      /* Set the attribute if provided */
00428                     {
00429                       if(cache_inode_setattr(pentry_lookup,
00430                                              &sattr,
00431                                              data->pcontext,
00432                                              &cache_status) != CACHE_INODE_SUCCESS)
00433                         {
00434                           res_OPEN4.status = nfs4_Errno(cache_status);
00435                           cause2 = " cache_inode_setattr";
00436                           goto out;
00437                         }
00438 
00439                       res_OPEN4.OPEN4res_u.resok4.attrset =
00440                           arg_OPEN4.openhow.openflag4_u.how.createhow4_u.createattrs.
00441                           attrmask;
00442                     }
00443                   else
00444                     res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_len = 0;
00445 
00446                   /* Same check on write */
00447                   if(arg_OPEN4.share_access & OPEN4_SHARE_ACCESS_WRITE)
00448                     {
00449                       if(cache_inode_access(pentry_lookup,
00450                                             write_access,
00451                                             data->pcontext,
00452                                             &cache_status) != CACHE_INODE_SUCCESS)
00453                         {
00454                           res_OPEN4.status = NFS4ERR_ACCESS;
00455                           cause2 = " cache_inode_access";
00456                           goto out;
00457                         }
00458                       openflags = FSAL_O_RDWR;
00459                     }
00460 
00461                   /* Set the state for the related file */
00462 
00463                   /* Prepare state management structure */
00464                   candidate_type                    = STATE_TYPE_SHARE;
00465                   candidate_data.share.share_deny   = arg_OPEN4.share_deny;
00466                   candidate_data.share.share_access = arg_OPEN4.share_access;
00467 
00468                   if(state_add(pentry_lookup,
00469                                candidate_type,
00470                                &candidate_data,
00471                                powner,
00472                                data->pcontext,
00473                                &pfile_state,
00474                                &state_status) != STATE_SUCCESS)
00475                     {
00476                       res_OPEN4.status = nfs4_Errno_state(state_status);
00477                       cause2 = " (state_add failed)";
00478                       goto out;
00479                     }
00480                   /* Attach this open to an export */
00481                   pfile_state->state_pexport = data->pexport;
00482                   P(data->pexport->exp_state_mutex);
00483                   glist_add_tail(&data->pexport->exp_state_list,
00484                                  &pfile_state->state_export_list);
00485                   V(data->pexport->exp_state_mutex);
00486 
00487                   init_glist(&pfile_state->state_data.share.share_lockstates);
00488 
00489                   /* Attach this open to an export */
00490                   pfile_state->state_pexport = data->pexport;
00491                   P(data->pexport->exp_state_mutex);
00492                   glist_add_tail(&data->pexport->exp_state_list, &pfile_state->state_export_list);
00493                   V(data->pexport->exp_state_mutex);
00494 
00495                   /* Open the file */
00496                   if(cache_inode_open(pentry_lookup,
00497                                       openflags,
00498                                       data->pcontext,
00499                                       0,
00500                                       &cache_status) != CACHE_INODE_SUCCESS)
00501                     {
00502                       // TODO FSF: huh????
00503                       res_OPEN4.status = NFS4ERR_SHARE_DENIED;
00504                       res_OPEN4.status = NFS4ERR_ACCESS;
00505                       cause2 = " cache_inode_open";
00506                       goto out;
00507                     }
00508 
00509                   res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_len = 3;
00510                   if((res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_val =
00511                       gsh_calloc(res_OPEN4.OPEN4res_u.resok4.attrset.
00512                                  bitmap4_len, sizeof(uint32_t))) == NULL)
00513                     {
00514                       res_OPEN4.status = NFS4ERR_RESOURCE;
00515                       res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_len = 0;
00516                       cause2 = " (allocation of bitmap failed)";
00517                       goto out;
00518                     }
00519 
00520                   res_OPEN4.OPEN4res_u.resok4.cinfo.after
00521                        = cache_inode_get_changeid4(pentry_parent);
00522                   res_OPEN4.OPEN4res_u.resok4.cinfo.atomic = FALSE;
00523 
00524                   /* No delegation */
00525                   res_OPEN4.OPEN4res_u.resok4.delegation.delegation_type =
00526                       OPEN_DELEGATE_NONE;
00527 
00528                   res_OPEN4.OPEN4res_u.resok4.rflags = OPEN4_RESULT_LOCKTYPE_POSIX;
00529 
00530                   /* Now produce the filehandle to this file */
00531                   pnewfsal_handle = &pentry_lookup->handle;
00532 
00533                   /* Building a new fh */
00534                   if(!nfs4_FSALToFhandle(&newfh4, pnewfsal_handle, data))
00535                     {
00536                       res_OPEN4.status = NFS4ERR_SERVERFAULT;
00537                       cause2 = " (nfs4_FSALToFhandle failed)";
00538                       goto out;
00539                     }
00540 
00541                   /* This new fh replaces the current FH */
00542                   data->currentFH.nfs_fh4_len = newfh4.nfs_fh4_len;
00543                   memcpy(data->currentFH.nfs_fh4_val, newfh4.nfs_fh4_val,
00544                          newfh4.nfs_fh4_len);
00545 
00546                   data->current_entry = pentry_lookup;
00547                   if (cache_inode_lru_ref(data->current_entry,
00548                                           0)
00549                       != CACHE_INODE_SUCCESS)
00550                     {
00551                       LogFatal(COMPONENT_CACHE_INODE_LRU,
00552                                "Inconsistency found in LRU management.");
00553                     }
00554                   data->current_filetype = REGULAR_FILE;
00555 
00556                   /* regular exit */
00557                   goto out_success;
00558                 }
00559 
00560               /* if open is EXCLUSIVE, but verifier is the same, return NFS4_OK (RFC3530 page 173) */
00561               if(arg_OPEN4.openhow.openflag4_u.how.mode == EXCLUSIVE4)
00562                 {
00563                   if((pentry_lookup != NULL)
00564                      && (pentry_lookup->type == REGULAR_FILE))
00565                     {
00566                       pthread_rwlock_rdlock(&pentry_lookup->state_lock);
00567                       glist_for_each(glist, &pentry_lookup->state_list)
00568                         {
00569                           pstate_iterate = glist_entry(glist, state_t, state_list);
00570 
00571                           /* Check is open_owner is the same */
00572                           if((pstate_iterate->state_type == STATE_TYPE_SHARE)
00573                              && !memcmp(arg_OPEN4.owner.owner.owner_val,
00574                                         pstate_iterate->state_powner->so_owner_val,
00575                                         pstate_iterate->state_powner->so_owner_len)
00576                              && !memcmp(pstate_iterate->state_data.share.
00577                                         share_oexcl_verifier,
00578                                         arg_OPEN4.openhow.openflag4_u.how.
00579                                         createhow4_u.createverf, NFS4_VERIFIER_SIZE))
00580                             {
00581 
00582                               /* A former open EXCLUSIVE with same owner and verifier was found, resend it */
00583                               memset(&(res_OPEN4.OPEN4res_u.resok4.cinfo.after), 0,
00584                                      sizeof(changeid4));
00585                               res_OPEN4.OPEN4res_u.resok4.cinfo.after =
00586                                    cache_inode_get_changeid4(pentry_parent);
00587                               res_OPEN4.OPEN4res_u.resok4.cinfo.atomic = FALSE;
00588 
00589                               /* No delegation */
00590                               res_OPEN4.OPEN4res_u.resok4.delegation.delegation_type =
00591                                   OPEN_DELEGATE_NONE;
00592 
00593                               res_OPEN4.OPEN4res_u.resok4.rflags =
00594                                   OPEN4_RESULT_LOCKTYPE_POSIX;
00595 
00596                               /* Now produce the filehandle to this file */
00597                               pnewfsal_handle = &pentry_lookup->handle;
00598 
00599                               /* Building a new fh */
00600                               if(!nfs4_FSALToFhandle(&newfh4, pnewfsal_handle, data))
00601                                 {
00602                                   res_OPEN4.status = NFS4ERR_SERVERFAULT;
00603                                   cause2 = " nfs4_FSALToFhandle failed";
00604                                   pthread_rwlock_unlock(&pentry_lookup
00605                                                         ->state_lock);
00606                                   goto out;
00607                                 }
00608 
00609                               /* This new fh replaces the current FH */
00610                               data->currentFH.nfs_fh4_len = newfh4.nfs_fh4_len;
00611                               memcpy(data->currentFH.nfs_fh4_val, newfh4.nfs_fh4_val,
00612                                      newfh4.nfs_fh4_len);
00613 
00614                               data->current_entry = pentry_lookup;
00615                               if (cache_inode_lru_ref(data->current_entry, 0)
00616                                   != CACHE_INODE_SUCCESS)
00617                                 {
00618                                   LogFatal(COMPONENT_CACHE_INODE_LRU,
00619                                            "Inconsistency found in LRU "
00620                                            "management.");
00621                                 }
00622                               data->current_filetype = REGULAR_FILE;
00623 
00624                               pthread_rwlock_unlock(&pentry_lookup
00625                                                     ->state_lock);
00626                               /* regular exit */
00627                               goto out_success;
00628                             }
00629                         }
00630                     }
00631                 }
00632 
00633               /* Managing GUARDED4 mode */
00634               if(cache_status != CACHE_INODE_SUCCESS)
00635                 res_OPEN4.status = nfs4_Errno(cache_status);
00636               else
00637                 res_OPEN4.status = NFS4ERR_EXIST;       /* File already exists */
00638 
00639               cause2 = "GUARDED4";
00640               goto out;
00641             }
00642 
00643           /*  if( cache_status != CACHE_INODE_NOT_FOUND ), if file already exists basically */
00644           LogFullDebug(COMPONENT_STATE,
00645                        "    OPEN open.how = %d",
00646                        arg_OPEN4.openhow.openflag4_u.how.mode);
00647 
00648           /* Create the file, if we reach this point, it does not exist, we can create it */
00649           if((pentry_newfile = cache_inode_create(pentry_parent,
00650                                                   &filename,
00651                                                   REGULAR_FILE,
00652                                                   mode,
00653                                                   &create_arg,
00654                                                   &attr_newfile,
00655                                                   data->pcontext, &cache_status)) == NULL)
00656             {
00657               /* If the file already exists, this is not an error if open mode is UNCHECKED */
00658               if(cache_status != CACHE_INODE_ENTRY_EXISTS)
00659                 {
00660                   res_OPEN4.status = nfs4_Errno(cache_status);
00661                   cause2 = " UNCHECKED cache_inode_create";
00662                   goto out;
00663                 }
00664               else
00665                 {
00666                   /* If this point is reached, then the file already
00667                      exists, cache_status == CACHE_INODE_ENTRY_EXISTS
00668                      and pentry_newfile == NULL This probably means
00669                      EXCLUSIVE4 mode is used and verifier
00670                      matches. pentry_newfile is then set to
00671                      pentry_lookup */
00672                   pentry_newfile = pentry_lookup;
00673                 }
00674             }
00675 
00676           /* Prepare state management structure */
00677           candidate_type                    = STATE_TYPE_SHARE;
00678           candidate_data.share.share_deny   = arg_OPEN4.share_deny;
00679           candidate_data.share.share_access = arg_OPEN4.share_access;
00680 
00681           /* If file is opened under mode EXCLUSIVE4, open verifier
00682              should be kept to detect non vicious double open */
00683           if(arg_OPEN4.openhow.openflag4_u.how.mode == EXCLUSIVE4)
00684             {
00685               strncpy(candidate_data.share.share_oexcl_verifier,
00686                       arg_OPEN4.openhow.openflag4_u.how.createhow4_u.createverf,
00687                       NFS4_VERIFIER_SIZE);
00688             }
00689 
00690           if(state_add(pentry_newfile,
00691                        candidate_type,
00692                        &candidate_data,
00693                        powner,
00694                        data->pcontext,
00695                        &pfile_state, &state_status) != STATE_SUCCESS)
00696             {
00697               res_OPEN4.status = nfs4_Errno_state(state_status);
00698               cause2 = " state_add failed";
00699               goto out;
00700             }
00701 
00702           /* Attach this open to an export */
00703           pfile_state->state_pexport = data->pexport;
00704           P(data->pexport->exp_state_mutex);
00705           glist_add_tail(&data->pexport->exp_state_list,
00706                          &pfile_state->state_export_list);
00707           V(data->pexport->exp_state_mutex);
00708 
00709           init_glist(&pfile_state->state_data.share.share_lockstates);
00710 
00711           /* Attach this open to an export */
00712           pfile_state->state_pexport = data->pexport;
00713           P(data->pexport->exp_state_mutex);
00714           glist_add_tail(&data->pexport->exp_state_list, &pfile_state->state_export_list);
00715           V(data->pexport->exp_state_mutex);
00716 
00717           cache_status = CACHE_INODE_SUCCESS;
00718 
00719           if(AttrProvided == TRUE)      /* Set the attribute if provided */
00720             {
00721               if((cache_status = cache_inode_setattr(pentry_newfile,
00722                                                      &sattr,
00723                                                      data->pcontext,
00724                                                      &cache_status)) !=
00725                  CACHE_INODE_SUCCESS)
00726                 {
00727                   res_OPEN4.status = nfs4_Errno(cache_status);
00728                   cause2 = " cache_inode_setattr";
00729                   goto out;
00730                 }
00731 
00732             }
00733 
00734           /* Set the openflags variable */
00735           if(arg_OPEN4.share_deny & OPEN4_SHARE_DENY_WRITE)
00736             openflags |= FSAL_O_RDONLY;
00737           if(arg_OPEN4.share_deny & OPEN4_SHARE_DENY_READ)
00738             openflags |= FSAL_O_WRONLY;
00739           if(arg_OPEN4.share_access & OPEN4_SHARE_ACCESS_WRITE)
00740             openflags = FSAL_O_RDWR;
00741           if(arg_OPEN4.share_access != 0)
00742             openflags = FSAL_O_RDWR;    /* @todo : BUGAZOMEU : Something better later */
00743 
00744           /* Open the file */
00745           if(cache_inode_open(pentry_newfile,
00746                               openflags,
00747                               data->pcontext,
00748                               0,
00749                               &cache_status) != CACHE_INODE_SUCCESS)
00750             {
00751               res_OPEN4.status = NFS4ERR_ACCESS;
00752               cause2 = " cache_inode_open";
00753               goto out;
00754             }
00755 
00756           break;
00757 
00758         case OPEN4_NOCREATE:
00759           /* It was not a creation, but a regular open */
00760           cause = "OPEN4_NOCREATE";
00761 
00762           /* The filehandle to the new file replaces the current filehandle */
00763           if(pentry_newfile == NULL)
00764             {
00765               if((pentry_newfile = cache_inode_lookup(pentry_parent,
00766                                                       &filename,
00767                                                       &attr_newfile,
00768                                                       data->pcontext,
00769                                                       &cache_status)) == NULL)
00770                 {
00771                   res_OPEN4.status = nfs4_Errno(cache_status);
00772                   cause2 = " cache_inode_lookup";
00773                   goto out;
00774                 }
00775             }
00776 
00777           /* OPEN4 is to be done on a file */
00778           if(pentry_newfile->type != REGULAR_FILE)
00779             {
00780               if(pentry_newfile->type == DIRECTORY)
00781                 {
00782                   res_OPEN4.status = NFS4ERR_ISDIR;
00783                   goto out;
00784                 }
00785               else if(pentry_newfile->type == SYMBOLIC_LINK)
00786                 {
00787                   res_OPEN4.status = NFS4ERR_SYMLINK;
00788                   goto out;
00789                 }
00790               else
00791                 {
00792                   res_OPEN4.status = NFS4ERR_INVAL;
00793                   cause2 = " (not REGULAR_FILE)";
00794                   goto out;
00795                 }
00796             }
00797 
00798           /* If the file is opened for write, OPEN4 while deny share write access,
00799            * in this case, check caller has write access to the file */
00800           if(arg_OPEN4.share_deny & OPEN4_SHARE_DENY_WRITE)
00801             {
00802               if(cache_inode_access(pentry_newfile,
00803                                     write_access,
00804                                     data->pcontext, &cache_status) != CACHE_INODE_SUCCESS)
00805                 {
00806                   res_OPEN4.status = NFS4ERR_ACCESS;
00807                   cause2 = " OPEN4_SHARE_DENY_WRITE cache_inode_access";
00808                   goto out;
00809                 }
00810               openflags = FSAL_O_WRONLY;
00811             }
00812 
00813           /* Same check on read: check for readability of a file before opening it for read */
00814           if(arg_OPEN4.share_access & OPEN4_SHARE_ACCESS_READ)
00815             {
00816               if(cache_inode_access(pentry_newfile,
00817                                     read_access,
00818                                     data->pcontext, &cache_status) != CACHE_INODE_SUCCESS)
00819                 {
00820                   res_OPEN4.status = NFS4ERR_ACCESS;
00821                   cause2 = " OPEN4_SHARE_ACCESS_READ cache_inode_access";
00822                   goto out;
00823                 }
00824               openflags = FSAL_O_RDONLY;
00825             }
00826 
00827           /* Same check on write */
00828           if(arg_OPEN4.share_access & OPEN4_SHARE_ACCESS_WRITE)
00829             {
00830               if(cache_inode_access(pentry_newfile,
00831                                     write_access,
00832                                     data->pcontext, &cache_status) != CACHE_INODE_SUCCESS)
00833                 {
00834                   res_OPEN4.status = NFS4ERR_ACCESS;
00835                   cause2 = " OPEN4_SHARE_ACCESS_WRITE cache_inode_access";
00836                   goto out;
00837                 }
00838               openflags = FSAL_O_RDWR;
00839             }
00840 
00841           /* Try to find if the same open_owner already has acquired a
00842              stateid for this file */
00843           pthread_rwlock_wrlock(&pentry_newfile->state_lock);
00844           glist_for_each(glist, &pentry_newfile->state_list)
00845             {
00846               pstate_iterate = glist_entry(glist, state_t, state_list);
00847 
00848               // TODO FSF: currently only care about share types
00849               if(pstate_iterate->state_type != STATE_TYPE_SHARE)
00850                 continue;
00851 
00852               /* Check is open_owner is the same */
00853               if((pstate_iterate->state_powner->so_owner.so_nfs4_owner.so_clientid == arg_OPEN4.owner.clientid) &&
00854                  ((pstate_iterate->state_powner->so_owner_len == arg_OPEN4.owner.owner.owner_len) &&
00855                   (!memcmp(arg_OPEN4.owner.owner.owner_val,
00856                            pstate_iterate->state_powner->so_owner_val,
00857                            pstate_iterate->state_powner->so_owner_len))))
00858                 {
00859                   /* We'll be re-using the found state */
00860                   pfile_state = pstate_iterate;
00861                   ReuseState  = TRUE;
00862                 }
00863               else
00864                 {
00865                   /* This is a different owner, check for possible conflicts */
00866                   if((pstate_iterate->state_data.share.share_access & OPEN4_SHARE_ACCESS_WRITE)
00867                      && (arg_OPEN4.share_deny & OPEN4_SHARE_DENY_WRITE))
00868                     {
00869                       res_OPEN4.status = NFS4ERR_SHARE_DENIED;
00870                       cause2 = " (OPEN4_SHARE_DENY_WRITE)";
00871                       pthread_rwlock_unlock(&pentry_newfile->state_lock);
00872                       goto out;
00873                     }
00874                 }
00875 
00876               /* In all cases opening in read access a read denied file or write access to a write denied file 
00877                * should fail, even if the owner is the same, see discussion in 14.2.16 and 8.9
00878                */
00879 
00880               /* deny read access on read denied file */
00881               if((pstate_iterate->state_data.share.share_deny & OPEN4_SHARE_DENY_READ)
00882                  && (arg_OPEN4.share_access & OPEN4_SHARE_ACCESS_READ))
00883                 {
00884                   res_OPEN4.status = NFS4ERR_SHARE_DENIED;
00885                   cause2 = " (OPEN4_SHARE_ACCESS_READ)";
00886                   pthread_rwlock_unlock(&pentry_newfile->state_lock);
00887                   goto out;
00888                 }
00889 
00890               /* deny write access on write denied file */
00891               if((pstate_iterate->state_data.share.share_deny & OPEN4_SHARE_DENY_WRITE)
00892                  && (arg_OPEN4.share_access & OPEN4_SHARE_ACCESS_WRITE))
00893                 {
00894                   res_OPEN4.status = NFS4ERR_SHARE_DENIED;
00895                   cause2 = " (OPEN4_SHARE_ACCESS_WRITE)";
00896                   pthread_rwlock_unlock(&pentry_newfile->state_lock);
00897                   goto out;
00898                 }
00899             }
00900 
00901           if(pfile_state == NULL)
00902             {
00903               /* Set the state for the related file */
00904               /* Prepare state management structure */
00905               candidate_type                    = STATE_TYPE_SHARE;
00906               candidate_data.share.share_deny   = arg_OPEN4.share_deny;
00907               candidate_data.share.share_access = arg_OPEN4.share_access;
00908 
00909               if(state_add_impl(pentry_newfile,
00910                                 candidate_type,
00911                                 &candidate_data,
00912                                 powner,
00913                                 data->pcontext,
00914                                 &pfile_state,
00915                                 &state_status) != STATE_SUCCESS)
00916                 {
00917                   res_OPEN4.status = nfs4_Errno_state(state_status);
00918                   cause2 = " (state_add failed)";
00919                   pthread_rwlock_unlock(&pentry_newfile->state_lock);
00920                   goto out;
00921                 }
00922 
00923               /* Attach this open to an export */
00924               pfile_state->state_pexport = data->pexport;
00925               P(data->pexport->exp_state_mutex);
00926               glist_add_tail(&data->pexport->exp_state_list,
00927                              &pfile_state->state_export_list);
00928               V(data->pexport->exp_state_mutex);
00929               init_glist(&pfile_state->state_data.share.share_lockstates);
00930 
00931               /* Attach this open to an export */
00932               pfile_state->state_pexport = data->pexport;
00933               P(data->pexport->exp_state_mutex);
00934               glist_add_tail(&data->pexport->exp_state_list, &pfile_state->state_export_list);
00935               V(data->pexport->exp_state_mutex);
00936             }
00937           else 
00938             {
00939               /* Check if open from another export */
00940               if(pfile_state->state_pexport != data->pexport)
00941                 {
00942                   LogEvent(COMPONENT_STATE,
00943                            "Lock Owner Export Conflict, Lock held for export %d (%s), request for export %d (%s)",
00944                            pfile_state->state_pexport->id,
00945                            pfile_state->state_pexport->fullpath,
00946                            data->pexport->id,
00947                            data->pexport->fullpath);
00948                   return STATE_INVALID_ARGUMENT;
00949                 }
00950             }
00951           pthread_rwlock_unlock(&pentry_newfile->state_lock);
00952 
00953           /* Open the file */
00954           if(cache_inode_open(pentry_newfile,
00955                               openflags,
00956                               data->pcontext,
00957                               0,
00958                               &cache_status) != CACHE_INODE_SUCCESS)
00959             {
00960               res_OPEN4.status = NFS4ERR_ACCESS;
00961               cause2 = " cache_inode_open";
00962               goto out;
00963             }
00964           break;
00965 
00966         default:
00967           cause = "INVALID OPEN TYPE";
00968           res_OPEN4.status = NFS4ERR_INVAL;
00969           goto out;
00970         }                       /* switch( arg_OPEN4.openhow.opentype ) */
00971 
00972       break;
00973 
00974     case CLAIM_PREVIOUS:
00975       // TODO FSF: doesn't this need to do something to re-establish state?
00976       cause = "CLAIM_PREVIOUS";
00977       powner = NULL;
00978       break;
00979 
00980     default:
00981       /* Invalid claim type */
00982       cause = "INVALID CLAIM";
00983       res_OPEN4.status = NFS4ERR_INVAL;
00984       goto out;
00985     }                           /*  switch(  arg_OPEN4.claim.claim ) */
00986 
00987   /* Now produce the filehandle to this file */
00988   pnewfsal_handle = &pentry_newfile->handle;
00989 
00990   /* Building a new fh */
00991   if(!nfs4_FSALToFhandle(&newfh4, pnewfsal_handle, data))
00992     {
00993       res_OPEN4.status = NFS4ERR_SERVERFAULT;
00994       cause2 = " (nfs4_FSALToFhandle failed)";
00995       goto out;
00996     }
00997 
00998   /* This new fh replaces the current FH */
00999   data->currentFH.nfs_fh4_len = newfh4.nfs_fh4_len;
01000   memcpy(data->currentFH.nfs_fh4_val, newfh4.nfs_fh4_val, newfh4.nfs_fh4_len);
01001 
01002   data->current_entry = pentry_newfile;
01003   if (cache_inode_lru_ref(data->current_entry, 0)
01004       != CACHE_INODE_SUCCESS)
01005     {
01006       LogFatal(COMPONENT_CACHE_INODE_LRU,
01007                "Inconsistency found in LRU management.");
01008     }
01009   data->current_filetype = REGULAR_FILE;
01010 
01011   /* Status of parent directory after the operation */
01012   if((cache_status = cache_inode_getattr(pentry_parent,
01013                                          &attr_parent,
01014                                          data->pcontext,
01015                                          &cache_status)) != CACHE_INODE_SUCCESS)
01016     {
01017       res_OPEN4.status = nfs4_Errno(cache_status);
01018       cause2 = " cache_inode_getattr";
01019       goto out;
01020     }
01021 
01022   res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_len = 3;
01023   if((res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_val =
01024       gsh_calloc(res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_len,
01025                  sizeof(uint32_t))) == NULL)
01026     {
01027       res_OPEN4.status = NFS4ERR_SERVERFAULT;
01028       res_OPEN4.OPEN4res_u.resok4.attrset.bitmap4_len = 0;
01029       cause2 = " (allocation of attr failed)";
01030       goto out;
01031     }
01032 
01033   if(arg_OPEN4.openhow.opentype == OPEN4_CREATE)
01034     {
01035       tmp_attr[0] = FATTR4_SIZE;
01036       tmp_attr[1] = FATTR4_MODE;
01037       nfs4_list_to_bitmap4(&(res_OPEN4.OPEN4res_u.resok4.attrset), 2, tmp_attr);
01038     }
01039 
01040   res_OPEN4.OPEN4res_u.resok4.cinfo.after
01041        = cache_inode_get_changeid4(pentry_parent);
01042   res_OPEN4.OPEN4res_u.resok4.cinfo.atomic = FALSE;
01043 
01044   /* No delegation */
01045   res_OPEN4.OPEN4res_u.resok4.delegation.delegation_type = OPEN_DELEGATE_NONE;
01046 
01047   res_OPEN4.OPEN4res_u.resok4.rflags = OPEN4_RESULT_LOCKTYPE_POSIX;
01048 
01049  out_success:
01050 
01051   LogFullDebug(COMPONENT_STATE, "NFS41 OPEN returning NFS4_OK");
01052 
01053   /* regular exit */
01054   res_OPEN4.status = NFS4_OK;
01055 
01056   /* Handle stateid/seqid for success */
01057   update_stateid(pfile_state,
01058                  &res_OPEN4.OPEN4res_u.resok4.stateid,
01059                  data,
01060                  tag);
01061 
01062   /* If we are re-using stateid, then release extra reference to open owner */
01063   if(ReuseState)
01064     dec_state_owner_ref(powner);
01065 
01066  out:
01067 
01068   if(res_OPEN4.status != NFS4_OK)
01069     {
01070       const char *cause3 = "", *cause4 = "";
01071 
01072       if(cache_status != CACHE_INODE_SUCCESS)
01073         {
01074           cause3 = " returned ";
01075           cause4 = cache_inode_err_str(cache_status);
01076         }
01077 
01078       LogDebug(COMPONENT_STATE,
01079                "NFS41 OPEN returning %s for %s%s%s%s",
01080                nfsstat4_to_str(res_OPEN4.status),
01081                cause, cause2, cause3, cause4);
01082 
01083       /* Clean up if we have an error exit */
01084       if(pfile_state != NULL && !ReuseState)
01085         {
01086           /* Need to destroy open owner and state */
01087           if(state_del(pfile_state,
01088                        &state_status) != STATE_SUCCESS)
01089             LogDebug(COMPONENT_NFS_V4_LOCK,
01090                      "state_del failed with status %s",
01091                      state_err_str(state_status));
01092         }
01093       else if(powner != NULL)
01094         {
01095           /* Need to release the open owner */
01096           dec_state_owner_ref(powner);
01097         }
01098     }
01099 
01100   /* return cache entry references */
01101   if (pentry_parent)
01102       cache_inode_put(pentry_parent);
01103 
01104   if (pentry_lookup)
01105       cache_inode_put(pentry_lookup);
01106 
01107   if (pentry_newfile)
01108       cache_inode_put(pentry_newfile);
01109 
01110   return res_OPEN4.status;
01111 }                               /* nfs41_op_open */
01112 
01123 void nfs41_op_open_Free(OPEN4res * resp)
01124 {
01125   gsh_free(resp->OPEN4res_u.resok4.attrset.bitmap4_val);
01126   resp->OPEN4res_u.resok4.attrset.bitmap4_len = 0;
01127 
01128   return;
01129 }                               /* nfs41_op_open_Free */