nfs-ganesha 1.4

nfs4_state.c

Go to the documentation of this file.
00001 /* vim:expandtab:shiftwidth=8:tabstop=8:
00002  *
00003  * Copyright CEA/DAM/DIF  (2008)
00004  * contributeur : Philippe DENIEL   philippe.deniel@cea.fr
00005  *                Thomas LEIBOVICI  thomas.leibovici@cea.fr
00006  *
00007  *
00008  * This program is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public License
00010  * as published by the Free Software Foundation; either version 3 of
00011  * the License, or (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with this library; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00021  * 02110-1301 USA
00022  *
00023  * ---------------------------------------
00024  */
00025 
00034 #ifdef HAVE_CONFIG_H
00035 #include "config.h"
00036 #endif
00037 
00038 #ifdef _SOLARIS
00039 #include "solaris_port.h"
00040 #endif                          /* _SOLARIS */
00041 
00042 #include <unistd.h>
00043 #include <sys/types.h>
00044 #include <sys/param.h>
00045 #include <time.h>
00046 #include <pthread.h>
00047 #include <string.h>
00048 
00049 #include "LRU_List.h"
00050 #include "log.h"
00051 #include "HashData.h"
00052 #include "HashTable.h"
00053 #include "nfs_core.h"
00054 #include "nfs4.h"
00055 #include "fsal.h"
00056 #include "sal_functions.h"
00057 #include "cache_inode_lru.h"
00058 
00072 int state_conflict(state_t      * pstate,
00073                    state_type_t   state_type,
00074                    state_data_t * pstate_data)
00075 {
00076   if(pstate == NULL || pstate_data == NULL)
00077     return TRUE;
00078 
00079   switch (state_type)
00080     {
00081     case STATE_TYPE_NONE:
00082       return FALSE;               /* STATE_NONE conflicts with nobody */
00083 
00084     case STATE_TYPE_SHARE:
00085       if(pstate->state_type == STATE_TYPE_SHARE)
00086         {
00087           if((pstate->state_data.share.share_access & pstate_data->share.share_deny) ||
00088              (pstate->state_data.share.share_deny & pstate_data->share.share_access))
00089             return TRUE;
00090         }
00091       return FALSE;
00092 
00093     case STATE_TYPE_LOCK:
00094       return FALSE;              /* lock conflict is managed in the NFS request */
00095 
00096     case STATE_TYPE_LAYOUT:
00097       return FALSE;              
00099     case STATE_TYPE_DELEG:
00100       /* Not yet implemented for now, answer TRUE to avoid weird behavior */
00101       return TRUE;
00102     }
00103 
00104   return TRUE;
00105 }                               /* state_conflict */
00106 
00126 state_status_t state_add_impl(cache_entry_t         * pentry,
00127                               state_type_t            state_type,
00128                               state_data_t          * pstate_data,
00129                               state_owner_t         * powner_input,
00130                               fsal_op_context_t     * pcontext,
00131                               state_t              ** ppstate,
00132                               state_status_t        * pstatus)
00133 {
00134   state_t              * pnew_state  = NULL;
00135   state_t              * piter_state = NULL;
00136   char                   debug_str[OTHERSIZE * 2 + 1];
00137   struct glist_head    * glist;
00138   cache_inode_status_t   cache_status;
00139   bool_t                 got_pinned = FALSE;
00140 
00141   if(glist_empty(&pentry->state_list))
00142     {
00143       cache_status = cache_inode_inc_pin_ref(pentry);
00144 
00145       if(cache_status != CACHE_INODE_SUCCESS)
00146         {
00147           *pstatus = cache_inode_status_to_state_status(cache_status);
00148           LogDebug(COMPONENT_STATE,
00149                    "Could not pin file");
00150           return *pstatus;
00151         }
00152 
00153       got_pinned = TRUE;
00154     }
00155 
00156   pnew_state = pool_alloc(state_v4_pool, NULL);
00157 
00158   if(pnew_state == NULL)
00159     {
00160       LogDebug(COMPONENT_STATE,
00161                "Can't allocate a new file state from cache pool");
00162 
00163       /* stat */
00164       *pstatus = STATE_MALLOC_ERROR;
00165 
00166       if(got_pinned)
00167         cache_inode_dec_pin_ref(pentry);
00168 
00169       return *pstatus;
00170     }
00171 
00172   memset(pnew_state, 0, sizeof(*pnew_state));
00173 
00174   /* Browse the state's list */
00175   glist_for_each(glist, &pentry->state_list)
00176     {
00177       piter_state = glist_entry(glist, state_t, state_list);
00178 
00179       if(state_conflict(piter_state, state_type, pstate_data))
00180         {
00181           LogDebug(COMPONENT_STATE,
00182                    "new state conflicts with another state for pentry %p",
00183                    pentry);
00184 
00185           /* stat */
00186           pool_free(state_v4_pool, pnew_state);
00187 
00188           *pstatus = STATE_STATE_CONFLICT;
00189 
00190           if(got_pinned)
00191             cache_inode_dec_pin_ref(pentry);
00192 
00193           return *pstatus;
00194         }
00195     }
00196 
00197   /* Add the stateid.other, this will increment state_id_counter */
00198   nfs4_BuildStateId_Other(pnew_state->stateid_other);
00199 
00200   /* Set the type and data for this state */
00201   memcpy(&(pnew_state->state_data), pstate_data, sizeof(state_data_t));
00202   pnew_state->state_type   = state_type;
00203   pnew_state->state_seqid  = 0; /* will be incremented to 1 later */
00204   pnew_state->state_pentry = pentry;
00205   pnew_state->state_powner = powner_input;
00206 
00207   if (isDebug(COMPONENT_STATE))
00208     sprint_mem(debug_str, (char *)pnew_state->stateid_other, OTHERSIZE);
00209 
00210   init_glist(&pnew_state->state_list);
00211   init_glist(&pnew_state->state_owner_list);
00212 
00213   /* Add the state to the related hashtable */
00214   if(!nfs4_State_Set(pnew_state->stateid_other, pnew_state))
00215     {
00216       LogDebug(COMPONENT_STATE,
00217                "Can't create a new state id %s for the pentry %p (F)",
00218                debug_str, pentry);
00219 
00220       pool_free(state_v4_pool, pnew_state);
00221 
00222       /* Return STATE_MALLOC_ERROR since most likely the nfs4_State_Set failed
00223        * to allocate memory.
00224        */
00225       *pstatus = STATE_MALLOC_ERROR;
00226 
00227       if(got_pinned)
00228         cache_inode_dec_pin_ref(pentry);
00229 
00230       return *pstatus;
00231     }
00232 
00233   /* Add state to list for cache entry */
00234   glist_add_tail(&pentry->state_list, &pnew_state->state_list);
00235 
00236   P(powner_input->so_mutex);
00237   glist_add_tail(&powner_input->so_owner.so_nfs4_owner.so_state_list,
00238                  &pnew_state->state_owner_list);
00239   V(powner_input->so_mutex);
00240 
00241   /* Copy the result */
00242   *ppstate = pnew_state;
00243 
00244   LogFullDebug(COMPONENT_STATE,
00245                "Add State: %s", debug_str);
00246 
00247   /* Regular exit */
00248   *pstatus = STATE_SUCCESS;
00249   return *pstatus;
00250 }                               /* state_add */
00251 
00252 
00270 state_status_t state_add(cache_entry_t         * pentry,
00271                          state_type_t            state_type,
00272                          state_data_t          * pstate_data,
00273                          state_owner_t         * powner_input,
00274                          fsal_op_context_t     * pcontext,
00275                          state_t              ** ppstate,
00276                          state_status_t        * pstatus)
00277 {
00278   /* Ensure that states are are associated only with the appropriate
00279      owners */
00280 
00281   if (((state_type == STATE_TYPE_SHARE) &&
00282        (powner_input->so_type != STATE_OPEN_OWNER_NFSV4)) ||
00283       ((state_type == STATE_TYPE_LOCK) &&
00284        (powner_input->so_type != STATE_LOCK_OWNER_NFSV4)) ||
00285       (((state_type == STATE_TYPE_DELEG) ||
00286         (state_type == STATE_TYPE_LAYOUT)) &&
00287        (powner_input->so_type != STATE_CLIENTID_OWNER_NFSV4)))
00288     {
00289       return (*pstatus = STATE_BAD_TYPE);
00290     }
00291 
00292   pthread_rwlock_wrlock(&pentry->state_lock);
00293   state_add_impl(pentry, state_type, pstate_data, powner_input,
00294                  pcontext, ppstate, pstatus);
00295   pthread_rwlock_unlock(&pentry->state_lock);
00296 
00297   return *pstatus;
00298 }                               /* state_add */
00299 
00300 state_status_t state_del_locked(state_t              * pstate,
00301                                 cache_entry_t        * pentry)
00302 {
00303   char            debug_str[OTHERSIZE * 2 + 1];
00304 
00305   if (isDebug(COMPONENT_STATE))
00306     sprint_mem(debug_str, (char *)pstate->stateid_other, OTHERSIZE);
00307 
00308   LogFullDebug(COMPONENT_STATE, "Deleting state %s", debug_str);
00309 
00310   /* Remove the entry from the HashTable */
00311   if(!nfs4_State_Del(pstate->stateid_other))
00312     {
00313       LogDebug(COMPONENT_STATE, "Could not delete state %s", debug_str);
00314 
00315       return STATE_STATE_ERROR;
00316     }
00317 
00318   /* Remove from list of states owned by owner */
00319 
00320   /* Release the state owner reference */
00321   if(pstate->state_powner != NULL)
00322     {
00323       P(pstate->state_powner->so_mutex);
00324       glist_del(&pstate->state_owner_list);
00325       V(pstate->state_powner->so_mutex);
00326       dec_state_owner_ref(pstate->state_powner);
00327     }
00328 
00329   /* Remove from the list of states for a particular cache entry */
00330   glist_del(&pstate->state_list);
00331 
00332   /* Remove from the list of lock states for a particular open state */
00333   if(pstate->state_type == STATE_TYPE_LOCK)
00334     glist_del(&pstate->state_data.lock.state_sharelist);
00335 
00336   /* Remove from list of states for a particular export */
00337   P(pstate->state_pexport->exp_state_mutex);
00338   glist_del(&pstate->state_export_list);
00339   V(pstate->state_pexport->exp_state_mutex);
00340 
00341   pool_free(state_v4_pool, pstate);
00342 
00343   LogFullDebug(COMPONENT_STATE, "Deleted state %s", debug_str);
00344 
00345   if(glist_empty(&pentry->state_list))
00346     cache_inode_dec_pin_ref(pentry);
00347 
00348   return STATE_SUCCESS;
00349 }
00350 
00363 state_status_t state_del(state_t              * pstate,
00364                          state_status_t       * pstatus)
00365 {
00366   cache_entry_t *entry = pstate->state_pentry;
00367 
00368   pthread_rwlock_wrlock(&entry->state_lock);
00369 
00370   *pstatus = state_del_locked(pstate, pstate->state_pentry);
00371 
00372   pthread_rwlock_unlock(&entry->state_lock);
00373 
00374   return *pstatus;
00375 }                               /* state_del */
00376 
00377 void state_nfs4_state_wipe(cache_entry_t        * pentry)
00378 {
00379   struct glist_head * glist, *glistn;
00380   state_t           * pstate = NULL;
00381 
00382   if(glist_empty(&pentry->state_list))
00383     return;
00384 
00385   glist_for_each_safe(glist, glistn, &pentry->state_list)
00386     {
00387       pstate = glist_entry(glist, state_t, state_list);
00388       state_del_locked(pstate, pentry);
00389     }
00390 
00391   return;
00392 }
00393 
00402 void release_lockstate(state_owner_t * plock_owner)
00403 {
00404   state_status_t         state_status;
00405   struct glist_head    * glist, * glistn;
00406 
00407   glist_for_each_safe(glist, glistn, &plock_owner->so_owner.so_nfs4_owner.so_state_list)
00408     {
00409       state_t * pstate_found = glist_entry(glist,
00410                                            state_t,
00411                                            state_owner_list);
00412 
00413       /* Make sure we hold an lru ref to the cache inode while calling state_del */
00414       if(cache_inode_lru_ref(pstate_found->state_pentry,
00415                              0) != CACHE_INODE_SUCCESS)
00416         LogCrit(COMPONENT_CLIENTID,
00417                 "Ugliness - cache_inode_lru_ref has returned non-success");
00418 
00419       if(state_del(pstate_found,
00420                    &state_status) != STATE_SUCCESS)
00421       {
00422         LogDebug(COMPONENT_CLIENTID,
00423                "release_lockstate failed to release stateid error %s",
00424                 state_err_str(state_status));
00425       }
00426 
00427       /* Release the lru ref to the cache inode we held while calling state_del */
00428       cache_inode_lru_unref(pstate_found->state_pentry,
00429                             0);
00430     }
00431 
00432   /* Release the reference to the lock owner that keeps it in the hash table */
00433   dec_state_owner_ref(plock_owner);
00434 }
00435 
00444 void release_openstate(state_owner_t * popen_owner)
00445 {
00446   state_status_t         state_status;
00447   struct glist_head    * glist, * glistn;
00448 
00449   glist_for_each_safe(glist, glistn, &popen_owner->so_owner.so_nfs4_owner.so_state_list)
00450     {
00451       fsal_op_context_t        fsal_context;
00452       fsal_status_t            fsal_status;
00453 
00454       state_t * pstate_found = glist_entry(glist,
00455                                            state_t,
00456                                            state_owner_list);
00457 
00458       cache_entry_t        * pentry = pstate_found->state_pentry;
00459       cache_inode_status_t   cache_status;
00460 
00461       /* Make sure we hold an lru ref to the cache inode while calling state_del */
00462       if(cache_inode_lru_ref(pentry,
00463                              0) != CACHE_INODE_SUCCESS)
00464         LogCrit(COMPONENT_CLIENTID,
00465                 "Ugliness - cache_inode_lru_ref has returned non-success");
00466 
00467       pthread_rwlock_wrlock(&pentry->state_lock);
00468       /* Construct the fsal context based on the export and root credential */
00469       fsal_status = FSAL_GetClientContext(&fsal_context,
00470                                           &pstate_found->state_pexport->FS_export_context,
00471                                           0,
00472                                           0,
00473                                           NULL,
00474                                           0);
00475 
00476       if(FSAL_IS_ERROR(fsal_status))
00477         {
00478           /* log error here , and continue? */
00479           LogEvent(COMPONENT_CLIENTID,
00480                    "FSAL_GetClientConext failed");
00481         }
00482       else if(pstate_found->state_type == STATE_TYPE_SHARE)
00483         {
00484           if(state_share_remove(pstate_found->state_pentry,
00485                                 &fsal_context,
00486                                 popen_owner,
00487                                 pstate_found,
00488                                 &state_status) != STATE_SUCCESS)
00489             {
00490               LogEvent(COMPONENT_CLIENTID,
00491                        "EXPIRY failed to release share stateid error %s",
00492                        state_err_str(state_status));
00493             }
00494         }
00495 
00496       if((state_status
00497           = state_del_locked(pstate_found,
00498                              pentry)) != STATE_SUCCESS)
00499         {
00500           LogDebug(COMPONENT_CLIENTID,
00501                    "EXPIRY failed to release stateid error %s",
00502                    state_err_str(state_status));
00503         }
00504 
00505       /* Close the file in FSAL through the cache inode */
00506       cache_inode_close(pentry,
00507                         0,
00508                         &cache_status);
00509 
00510       pthread_rwlock_unlock(&pentry->state_lock);
00511 
00512       /* Release the lru ref to the cache inode we held while calling state_del */
00513       cache_inode_lru_unref(pentry,
00514                             0);
00515     }
00516 
00517   /* Release the reference to the open owner that keeps it in the hash table */
00518   dec_state_owner_ref(popen_owner);
00519 }