nfs-ganesha 1.4

state_lock.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 License
00011  * as published by the Free Software Foundation; either version 3 of
00012  * the License, or (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful, but
00015  * 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
00022  * 02110-1301 USA
00023  *
00024  * ---------------------------------------
00025  */
00026 
00035 #ifdef HAVE_CONFIG_H
00036 #include "config.h"
00037 #endif
00038 
00039 #ifdef _SOLARIS
00040 #include "solaris_port.h"
00041 #endif                          /* _SOLARIS */
00042 
00043 #include <unistd.h>
00044 #include <sys/types.h>
00045 #include <sys/param.h>
00046 #include <time.h>
00047 #include <pthread.h>
00048 #include <string.h>
00049 
00050 #include "log.h"
00051 #include "HashData.h"
00052 #include "HashTable.h"
00053 #include "fsal.h"
00054 #include "nfs_core.h"
00055 #include "nfs4.h"
00056 #include "sal_functions.h"
00057 #ifdef _USE_NLM
00058 #include "nlm_util.h"
00059 #endif
00060 #include "cache_inode_lru.h"
00061 
00062 /*
00063  * state_lock_entry_t locking rule:
00064  * The value is always updated/read with nlm_lock_entry->lock held
00065  * If we have nlm_lock_list mutex held we can read it safely, because the
00066  * value is always updated while walking the list with pentry->state_lock held.
00067  * The updation happens as below:
00068  *  pthread_rwlock_wrlock(&pentry->state_mutex)
00069  *  pthread_mutex_lock(lock_entry->sle_mutex)
00070  *    update the lock_entry value
00071  *  ........
00072  * The value is ref counted with nlm_lock_entry->sle_ref_count so that a
00073  * parallel cancel/unlock won't endup freeing the datastructure. The last
00074  * release on the data structure ensure that it is freed.
00075  */
00076 
00077 /* The following constant defines the number of errors we will accept
00078  * before giving up in state recovery routines. These routines need to
00079  * terminate at some point.
00080  */
00081 #define STATE_ERR_MAX 100
00082 
00083 #ifdef _DEBUG_MEMLEAKS
00084 static struct glist_head state_all_locks;
00085 pthread_mutex_t all_locks_mutex = PTHREAD_MUTEX_INITIALIZER;
00086 #endif
00087 
00088 #ifdef _USE_BLOCKING_LOCKS
00089 
00090 /* List of all locks blocked in FSAL */
00091 struct glist_head state_blocked_locks;
00092 
00093 /* List of all async blocking locks notified by FSAL but not processed */
00094 struct glist_head state_notified_locks;
00095 
00096 /* Mutex to protect above lists */
00097 pthread_mutex_t blocked_locks_mutex = PTHREAD_MUTEX_INITIALIZER;
00098 
00099 #endif
00100 
00101 state_owner_t unknown_owner;
00102 
00103 #ifdef _USE_BLOCKING_LOCKS
00104 hash_table_t *ht_lock_cookies;
00105 
00106 state_status_t state_lock_init(state_status_t   * pstatus,
00107                                hash_parameter_t   cookie_param)
00108 #else
00109 state_status_t state_lock_init(state_status_t * pstatus)
00110 #endif
00111 {
00112   *pstatus = STATE_SUCCESS;
00113 
00114   memset(&unknown_owner, 0, sizeof(unknown_owner));
00115   strcpy(unknown_owner.so_owner_val, "ganesha_unknown_owner");
00116   unknown_owner.so_type      = STATE_LOCK_OWNER_UNKNOWN;
00117   unknown_owner.so_refcount  = 1;
00118   unknown_owner.so_owner_len = strlen(unknown_owner.so_owner_val);
00119 
00120   init_glist(&unknown_owner.so_lock_list);
00121 
00122   if(pthread_mutex_init(&unknown_owner.so_mutex, NULL) == -1)
00123     {
00124       *pstatus = STATE_INIT_ENTRY_FAILED;
00125       return *pstatus;
00126     }
00127 
00128 #ifdef _USE_BLOCKING_LOCKS
00129   ht_lock_cookies = HashTable_Init(&cookie_param);
00130   if(ht_lock_cookies == NULL)
00131     {
00132       LogCrit(COMPONENT_STATE,
00133               "Cannot init NLM Client cache");
00134       *pstatus = STATE_INIT_ENTRY_FAILED;
00135       return *pstatus;
00136     }
00137 #endif
00138 
00139 #ifdef _DEBUG_MEMLEAKS
00140   init_glist(&state_all_locks);
00141 #endif
00142  
00143 #ifdef _USE_BLOCKING_LOCKS
00144   init_glist(&state_blocked_locks);
00145   init_glist(&state_notified_locks);
00146 
00147   *pstatus = state_async_init();
00148 #endif
00149 
00150   state_owner_pool = pool_init("NFSv4 state owners",
00151                                sizeof(state_owner_t),
00152                                pool_basic_substrate,
00153                                NULL, NULL, NULL);
00154   state_nfs4_owner_name_pool = pool_init("Owner names",
00155                                          sizeof(state_nfs4_owner_name_t),
00156                                          pool_basic_substrate,
00157                                          NULL, NULL, NULL);
00158   state_v4_pool = pool_init("NFSv4 files states",
00159                             sizeof(state_t),
00160                             pool_basic_substrate,
00161                             NULL, NULL, NULL);
00162   return *pstatus;
00163 }
00164 
00165 bool_t lock_owner_is_nlm(state_lock_entry_t * lock_entry)
00166 {
00167 #ifdef _USE_NLM
00168   return lock_entry->sle_owner->so_type == STATE_LOCK_OWNER_NLM;
00169 #else
00170   return FALSE;
00171 #endif
00172 }
00173 
00174 state_status_t do_lock_op(cache_entry_t        * pentry,
00175                           fsal_op_context_t    * pcontext,
00176                           exportlist_t         * pexport,
00177                           fsal_lock_op_t         lock_op,
00178                           state_owner_t        * powner,
00179                           fsal_lock_param_t    * plock,
00180                           state_owner_t       ** holder,   /* owner that holds conflicting lock */
00181                           fsal_lock_param_t    * conflict, /* description of conflicting lock */
00182                           bool_t                 overlap);  /* hint that lock overlaps */
00183 
00184 /******************************************************************************
00185  *
00186  * Functions to display various aspects of a lock
00187  *
00188  ******************************************************************************/
00189 static inline uint64_t lock_end(fsal_lock_param_t *plock)
00190 {
00191   if(plock->lock_length == 0)
00192     return UINT64_MAX;
00193   else
00194     return plock->lock_start + plock->lock_length - 1;
00195 }
00196 
00197 const char *str_lockt(fsal_lock_t ltype)
00198 {
00199   switch(ltype)
00200     {
00201       case FSAL_LOCK_R:  return "READ ";
00202       case FSAL_LOCK_W:  return "WRITE";
00203       case FSAL_NO_LOCK: return "NO LOCK";
00204       default:           return "?????";
00205     }
00206   return "????";
00207 }
00208 
00209 const char *str_blocking(state_blocking_t blocking)
00210 {
00211   switch(blocking)
00212     {
00213       case STATE_NON_BLOCKING:   return "NON_BLOCKING  ";
00214       case STATE_NLM_BLOCKING:   return "NLM_BLOCKING  ";
00215       case STATE_NFSV4_BLOCKING: return "NFSV4_BLOCKING";
00216       case STATE_GRANTING:       return "GRANTING      ";
00217       case STATE_CANCELED:       return "CANCELED      ";
00218     }
00219   return "unknown       ";
00220 }
00221 
00222 const char *str_blocked(state_blocking_t blocked)
00223 {
00224   switch(blocked)
00225     {
00226       case STATE_NON_BLOCKING:   return "GRANTED       ";
00227       case STATE_NLM_BLOCKING:   return "NLM_BLOCKING  ";
00228       case STATE_NFSV4_BLOCKING: return "NFSV4_BLOCKING";
00229       case STATE_GRANTING:       return "GRANTING      ";
00230       case STATE_CANCELED:       return "CANCELED      ";
00231     }
00232   return "unknown       ";
00233 }
00234 
00235 /******************************************************************************
00236  *
00237  * Function to compare lock parameters
00238  *
00239  ******************************************************************************/
00240 
00241 /* This is not complete, it doesn't check the owner's IP address...*/
00242 static inline int different_lock(fsal_lock_param_t *lock1, fsal_lock_param_t *lock2)
00243 {
00244   return (lock1->lock_type   != lock2->lock_type)  ||
00245          (lock1->lock_start  != lock2->lock_start) ||
00246          (lock1->lock_length != lock2->lock_length);
00247 }
00248 
00249 /******************************************************************************
00250  *
00251  * Functions to log locks in various ways
00252  *
00253  ******************************************************************************/
00254 static void LogEntry(const char         *reason,
00255                      state_lock_entry_t *ple)
00256 {
00257   if(isFullDebug(COMPONENT_STATE))
00258     {
00259       char owner[HASHTABLE_DISPLAY_STRLEN];
00260 
00261       DisplayOwner(ple->sle_owner, owner);
00262 
00263       LogFullDebug(COMPONENT_STATE,
00264                    "%s Entry: %p pentry=%p, fileid=%"PRIu64", export=%u, type=%s, start=0x%llx, end=0x%llx, blocked=%s/%p, state=%p, refcount=%d, owner={%s}",
00265                    reason, ple,
00266                    ple->sle_pentry, (uint64_t)ple->sle_pentry->attributes.fileid,
00267                    (unsigned int) ple->sle_pexport->id,
00268                    str_lockt(ple->sle_lock.lock_type),
00269                    (unsigned long long) ple->sle_lock.lock_start,
00270                    (unsigned long long) lock_end(&ple->sle_lock),
00271                    str_blocked(ple->sle_blocked),
00272                    ple->sle_block_data,
00273                    ple->sle_state,
00274                    ple->sle_ref_count,
00275                    owner);
00276     }
00277 }
00278 
00279 static bool_t LogList(const char        * reason,
00280                       cache_entry_t     * pentry,
00281                       struct glist_head * list)
00282 {
00283   if(isFullDebug(COMPONENT_STATE))
00284     {
00285       struct glist_head  * glist;
00286       state_lock_entry_t * found_entry;
00287 
00288       if(glist_empty(list))
00289         {
00290           if(pentry != NULL)
00291             LogFullDebug(COMPONENT_STATE,
00292                          "%s for %p is empty",
00293                          reason, pentry);
00294           else
00295             LogFullDebug(COMPONENT_STATE,
00296                          "%s is empty",
00297                          reason);
00298           return TRUE;
00299         }
00300 
00301 
00302       glist_for_each(glist, list)
00303         {
00304           found_entry = glist_entry(glist, state_lock_entry_t, sle_list);
00305           LogEntry(reason, found_entry);
00306           if(found_entry->sle_pentry == NULL)
00307             break;
00308         }
00309     }
00310 
00311   return FALSE;
00312 }
00313 
00314 #ifdef _USE_BLOCKING_LOCKS
00315 static bool_t LogBlockedList(const char        * reason,
00316                              cache_entry_t     * pentry,
00317                              struct glist_head * list)
00318 {
00319   if(isFullDebug(COMPONENT_STATE))
00320     {
00321       struct glist_head  * glist;
00322       state_lock_entry_t * found_entry;
00323       state_block_data_t * block_entry;
00324 
00325       if(glist_empty(list))
00326         {
00327           if(pentry != NULL)
00328             LogFullDebug(COMPONENT_STATE,
00329                          "%s for %p is empty",
00330                          reason, pentry);
00331           else
00332             LogFullDebug(COMPONENT_STATE,
00333                          "%s is empty",
00334                          reason);
00335           return TRUE;
00336         }
00337 
00338 
00339       glist_for_each(glist, list)
00340         {
00341           block_entry = glist_entry(glist, state_block_data_t, sbd_list);
00342           found_entry = block_entry->sbd_lock_entry;
00343           LogEntry(reason, found_entry);
00344           if(found_entry->sle_pentry == NULL)
00345             break;
00346         }
00347     }
00348 
00349   return FALSE;
00350 }
00351 #endif /* _USE_BLOCKING_LOCKS */
00352 
00353 void LogLock(log_components_t     component,
00354              log_levels_t         debug,
00355              const char         * reason,
00356              cache_entry_t      * pentry,
00357              fsal_op_context_t  * pcontext,
00358              state_owner_t      * powner,
00359              fsal_lock_param_t  * plock)
00360 {
00361   if(isLevel(component, debug))
00362     {
00363       char owner[HASHTABLE_DISPLAY_STRLEN];
00364 
00365       if(powner != NULL)
00366         DisplayOwner(powner, owner);
00367       else
00368         sprintf(owner, "NONE");
00369 
00370       LogAtLevel(component, debug,
00371                  "%s Lock: pentry=%p, fileid=%"PRIu64", type=%s, start=0x%llx, end=0x%llx, owner={%s}",
00372                  reason, pentry, (uint64_t)pentry->attributes.fileid,
00373                  str_lockt(plock->lock_type),
00374                  (unsigned long long) plock->lock_start,
00375                  (unsigned long long) lock_end(plock),
00376                  owner);
00377     }
00378 }
00379 
00380 void LogLockDesc(log_components_t     component,
00381                  log_levels_t         debug,
00382                  const char         * reason,
00383                  cache_entry_t      * pentry,
00384                  void               * powner,
00385                  fsal_lock_param_t  * plock)
00386 {
00387   LogAtLevel(component, debug,
00388              "%s Lock: pentry=%p, powner=%p, type=%s, start=0x%llx, end=0x%llx",
00389              reason,
00390              pentry,
00391              powner,
00392              str_lockt(plock->lock_type),
00393              (unsigned long long) plock->lock_start,
00394              (unsigned long long) lock_end(plock));
00395 }
00396 
00397 void dump_all_locks(const char * label)
00398 {
00399 #ifdef _DEBUG_MEMLEAKS
00400   struct glist_head *glist;
00401 
00402   P(all_locks_mutex);
00403 
00404   if(glist_empty(&state_all_locks))
00405     {
00406       LogFullDebug(COMPONENT_STATE, "All Locks are freed");
00407       V(all_locks_mutex);
00408       return;
00409     }
00410 
00411   glist_for_each(glist, &state_all_locks)
00412     LogEntry(label, glist_entry(glist, state_lock_entry_t, sle_all_locks));
00413 
00414   V(all_locks_mutex);
00415 #else
00416   return;
00417 #endif
00418 }
00419 
00420 /******************************************************************************
00421  *
00422  * Functions to manage lock entries and lock list
00423  *
00424  ******************************************************************************/
00425 static state_lock_entry_t *create_state_lock_entry(cache_entry_t      * pentry,
00426                                                    fsal_op_context_t  * pcontext,
00427                                                    exportlist_t       * pexport,
00428                                                    state_blocking_t     blocked,
00429                                                    state_owner_t      * powner,
00430                                                    state_t            * pstate,
00431                                                    fsal_lock_param_t  * plock)
00432 {
00433   state_lock_entry_t *new_entry;
00434 
00435   new_entry = gsh_malloc(sizeof(*new_entry));
00436   if(!new_entry)
00437       return NULL;
00438 
00439   LogFullDebug(COMPONENT_STATE,
00440                "new_entry = %p", new_entry);
00441 
00442   memset(new_entry, 0, sizeof(*new_entry));
00443 
00444   if(pthread_mutex_init(&new_entry->sle_mutex, NULL) == -1)
00445     {
00446       gsh_free(new_entry);
00447       return NULL;
00448     }
00449 
00450   new_entry->sle_ref_count  = 1;
00451   new_entry->sle_pentry     = pentry;
00452   new_entry->sle_blocked    = blocked;
00453   new_entry->sle_owner      = powner;
00454   new_entry->sle_state      = pstate;
00455   new_entry->sle_block_data = NULL;   /* will be filled in later if necessary */
00456   new_entry->sle_lock       = *plock;
00457   new_entry->sle_pexport    = pexport;
00458 
00459 #ifdef _USE_NLM
00460   if(powner->so_type == STATE_LOCK_OWNER_NLM)
00461     {
00462       /* Add to list of locks owned by client that powner belongs to */
00463       P(powner->so_owner.so_nlm_owner.so_client->slc_nsm_client->ssc_mutex);
00464 
00465       glist_add_tail(&powner->so_owner.so_nlm_owner.so_client->slc_nsm_client->ssc_lock_list,
00466                      &new_entry->sle_client_locks);
00467 
00468       inc_nsm_client_ref_locked(powner->so_owner.so_nlm_owner.so_client->slc_nsm_client);
00469 
00470       /* Add to list of locks owned by export */
00471       P(pexport->exp_state_mutex);
00472       glist_add_tail(&pexport->exp_lock_list,
00473                      &new_entry->sle_export_locks);
00474       V(pexport->exp_state_mutex);
00475     }
00476 #endif
00477   /* Add to list of locks owned by powner */
00478   P(powner->so_mutex);
00479 
00480   if(powner->so_type == STATE_LOCK_OWNER_NFSV4 && pstate != NULL)
00481     {
00482       glist_add_tail(&pstate->state_data.lock.state_locklist,
00483                      &new_entry->sle_state_locks);
00484     }
00485 
00486   glist_add_tail(&powner->so_lock_list, &new_entry->sle_owner_locks);
00487 
00488   inc_state_owner_ref_locked(powner);
00489 
00490 #ifdef _DEBUG_MEMLEAKS
00491   P(all_locks_mutex);
00492 
00493   glist_add_tail(&state_all_locks, &new_entry->sle_all_locks);
00494 
00495   V(all_locks_mutex);
00496 #endif
00497 
00498   return new_entry;
00499 }
00500 
00501 inline state_lock_entry_t *state_lock_entry_t_dup(fsal_op_context_t  * pcontext,
00502                                                   state_lock_entry_t * orig_entry)
00503 {
00504   return create_state_lock_entry(orig_entry->sle_pentry,
00505                                  pcontext,
00506                                  orig_entry->sle_pexport,
00507                                  orig_entry->sle_blocked,
00508                                  orig_entry->sle_owner,
00509                                  orig_entry->sle_state,
00510                                  &orig_entry->sle_lock);
00511 }
00512 
00513 void lock_entry_inc_ref(state_lock_entry_t *lock_entry)
00514 {
00515     P(lock_entry->sle_mutex);
00516     lock_entry->sle_ref_count++;
00517     LogEntry("Increment refcount", lock_entry);
00518     V(lock_entry->sle_mutex);
00519 }
00520 
00521 void lock_entry_dec_ref(state_lock_entry_t *lock_entry)
00522 {
00523   bool_t to_free = FALSE;
00524 
00525   P(lock_entry->sle_mutex);
00526 
00527   lock_entry->sle_ref_count--;
00528 
00529     LogEntry("Decrement refcount", lock_entry);
00530 
00531   if(!lock_entry->sle_ref_count)
00532     {
00533       /*
00534        * We should already be removed from the lock_list
00535        * So we can free the lock_entry without any locking
00536        */
00537       to_free = TRUE;
00538     }
00539 
00540   V(lock_entry->sle_mutex);
00541 
00542   if(to_free)
00543     {
00544       LogEntry("Freeing", lock_entry);
00545 
00546 #ifdef _USE_BLOCKING_LOCKS
00547       /* Release block data if present */
00548       if(lock_entry->sle_block_data != NULL)
00549         {
00550           memset(lock_entry->sle_block_data, 0, sizeof(*(lock_entry->sle_block_data)));
00551           gsh_free(lock_entry->sle_block_data);
00552         }
00553 #endif
00554 #ifdef _DEBUG_MEMLEAKS
00555       P(all_locks_mutex);
00556       glist_del(&lock_entry->sle_all_locks);
00557       V(all_locks_mutex);
00558 #endif
00559 
00560       memset(lock_entry, 0, sizeof(*lock_entry));
00561       gsh_free(lock_entry);
00562     }
00563 }
00564 
00565 static void remove_from_locklist(state_lock_entry_t   * lock_entry)
00566 {
00567   state_owner_t * powner = lock_entry->sle_owner;
00568 
00569   LogEntry("Removing", lock_entry);
00570 
00571   /*
00572    * If some other thread is holding a reference to this nlm_lock_entry
00573    * don't free the structure. But drop from the lock list
00574    */
00575   if(powner != NULL)
00576     {
00577 #ifdef _USE_NLM
00578       if(powner->so_type == STATE_LOCK_OWNER_NLM)
00579         {
00580           /* Remove from list of locks owned by client that powner belongs to */
00581           P(powner->so_owner.so_nlm_owner.so_client->slc_nsm_client->ssc_mutex);
00582 
00583           glist_del(&lock_entry->sle_client_locks);
00584 
00585           dec_nsm_client_ref_locked(powner->so_owner.so_nlm_owner.so_client->slc_nsm_client);
00586 
00587           /* Remove from list of locks owned by export */
00588           P(lock_entry->sle_pexport->exp_state_mutex);
00589           glist_del(&lock_entry->sle_export_locks);
00590           V(lock_entry->sle_pexport->exp_state_mutex);
00591         }
00592 #endif
00593 
00594       /* Remove from list of locks owned by powner */
00595       P(powner->so_mutex);
00596 
00597       if(powner->so_type == STATE_LOCK_OWNER_NFSV4)
00598         {
00599           glist_del(&lock_entry->sle_state_locks);
00600         }
00601 
00602       glist_del(&lock_entry->sle_owner_locks);
00603 
00604       dec_state_owner_ref_locked(powner);
00605     }
00606 
00607   lock_entry->sle_owner = NULL;
00608   glist_del(&lock_entry->sle_list);
00609   lock_entry_dec_ref(lock_entry);
00610 }
00611 
00612 static state_lock_entry_t *get_overlapping_entry(cache_entry_t     * pentry,
00613                                                  fsal_op_context_t * pcontext,
00614                                                  state_owner_t     * powner,
00615                                                  fsal_lock_param_t * plock)
00616 {
00617   struct glist_head *glist;
00618   state_lock_entry_t *found_entry = NULL;
00619   uint64_t found_entry_end, plock_end = lock_end(plock);
00620 
00621   glist_for_each(glist, &pentry->object.file.lock_list)
00622     {
00623       found_entry = glist_entry(glist, state_lock_entry_t, sle_list);
00624 
00625       LogEntry("Checking", found_entry);
00626 
00627       /* Skip blocked or cancelled locks */
00628       if(found_entry->sle_blocked == STATE_NLM_BLOCKING ||
00629          found_entry->sle_blocked == STATE_NFSV4_BLOCKING ||
00630          found_entry->sle_blocked == STATE_CANCELED)
00631           continue;
00632 
00633       found_entry_end = lock_end(&found_entry->sle_lock);
00634 
00635       if((found_entry_end >= plock->lock_start) &&
00636          (found_entry->sle_lock.lock_start <= plock_end))
00637         {
00638           /* lock overlaps see if we can allow
00639            * allow if neither lock is exclusive or the owner is the same
00640            */
00641           if((found_entry->sle_lock.lock_type == FSAL_LOCK_W ||
00642               plock->lock_type == FSAL_LOCK_W) &&
00643              different_owners(found_entry->sle_owner, powner)
00644              )
00645             {
00646               /* found a conflicting lock, return it */
00647               return found_entry;
00648             }
00649         }
00650     }
00651 
00652   return NULL;
00653 }
00654 
00655 /* We need to iterate over the full lock list and remove
00656  * any mapping entry. And l_offset = 0 and sle_lock.lock_length = 0 lock_entry
00657  * implies remove all entries
00658  */
00659 static void merge_lock_entry(cache_entry_t        * pentry,
00660                              fsal_op_context_t    * pcontext,
00661                              state_lock_entry_t   * lock_entry)
00662 {
00663   state_lock_entry_t * check_entry;
00664   state_lock_entry_t * check_entry_right;
00665   uint64_t             check_entry_end;
00666   uint64_t             lock_entry_end;
00667   struct glist_head  * glist;
00668   struct glist_head  * glistn;
00669 
00670   /* lock_entry might be STATE_NON_BLOCKING or STATE_GRANTING */
00671 
00672   glist_for_each_safe(glist, glistn, &pentry->object.file.lock_list)
00673     {
00674       check_entry = glist_entry(glist, state_lock_entry_t, sle_list);
00675 
00676       /* Skip entry being merged - it could be in the list */
00677       if(check_entry == lock_entry)
00678         continue;
00679 
00680       if(different_owners(check_entry->sle_owner, lock_entry->sle_owner))
00681         continue;
00682 
00683       /* Only merge fully granted locks */
00684       if(check_entry->sle_blocked != STATE_NON_BLOCKING)
00685         continue;
00686 
00687       check_entry_end = lock_end(&check_entry->sle_lock);
00688       lock_entry_end  = lock_end(&lock_entry->sle_lock);
00689 
00690       if((check_entry_end + 1) < lock_entry->sle_lock.lock_start)
00691         /* nothing to merge */
00692         continue;
00693 
00694       if((lock_entry_end + 1) < check_entry->sle_lock.lock_start)
00695         /* nothing to merge */
00696         continue;
00697 
00698       /* Need to handle locks of different types differently, may split an old lock.
00699        * If new lock totally overlaps old lock, the new lock will replace the old
00700        * lock so no special work to be done.
00701        */
00702       if((check_entry->sle_lock.lock_type != lock_entry->sle_lock.lock_type) &&
00703          ((lock_entry_end < check_entry_end) ||
00704           (check_entry->sle_lock.lock_start < lock_entry->sle_lock.lock_start)))
00705         {
00706           if(lock_entry_end < check_entry_end &&
00707              check_entry->sle_lock.lock_start < lock_entry->sle_lock.lock_start)
00708             {
00709               /* Need to split old lock */
00710               check_entry_right = state_lock_entry_t_dup(pcontext, check_entry);
00711               if(check_entry_right == NULL)
00712                 {
00713                   // TODO FSF: OOPS....
00714                   // Leave old lock in place, it may cause false conflicts, but should eventually be released
00715                   LogMajor(COMPONENT_STATE,
00716                            "Memory allocation failure during lock upgrade/downgrade");
00717                   continue;
00718                 }
00719               glist_add_tail(&pentry->object.file.lock_list, &(check_entry_right->sle_list));
00720             }
00721           else
00722             {
00723               /* No split, just shrink, make the logic below work on original lock */
00724               check_entry_right = check_entry;
00725             }
00726           if(lock_entry_end < check_entry_end)
00727             {
00728               /* Need to shrink old lock from beginning (right lock if split) */
00729               LogEntry("Merge shrinking right", check_entry_right);
00730               check_entry_right->sle_lock.lock_start  = lock_entry_end + 1;
00731               check_entry_right->sle_lock.lock_length = check_entry_end - lock_entry_end;
00732               LogEntry("Merge shrunk right", check_entry_right);
00733               continue;
00734             }
00735           if(check_entry->sle_lock.lock_start < lock_entry->sle_lock.lock_start)
00736             {
00737               /* Need to shrink old lock from end (left lock if split) */
00738               LogEntry("Merge shrinking left", check_entry);
00739               check_entry->sle_lock.lock_length = lock_entry->sle_lock.lock_start - check_entry->sle_lock.lock_start;
00740               LogEntry("Merge shrunk left", check_entry);
00741               continue;
00742             }
00743           /* Done splitting/shrinking old lock */
00744           continue;
00745         }
00746 
00747       /* check_entry touches or overlaps lock_entry, expand lock_entry */
00748       if(lock_entry_end < check_entry_end)
00749         /* Expand end of lock_entry */
00750         lock_entry_end = check_entry_end;
00751 
00752       if(check_entry->sle_lock.lock_start < lock_entry->sle_lock.lock_start)
00753         /* Expand start of lock_entry */
00754         lock_entry->sle_lock.lock_start = check_entry->sle_lock.lock_start;
00755 
00756       /* Compute new lock length */
00757       lock_entry->sle_lock.lock_length = lock_entry_end - lock_entry->sle_lock.lock_start + 1;
00758 
00759       /* Remove merged entry */
00760       LogEntry("Merged", lock_entry);
00761       LogEntry("Merging removing", check_entry);
00762       remove_from_locklist(check_entry);
00763     }
00764 }
00765 
00766 static void free_list(struct glist_head    * list)
00767 {
00768   state_lock_entry_t *found_entry;
00769   struct glist_head *glist, *glistn;
00770 
00771   glist_for_each_safe(glist, glistn, list)
00772     {
00773       found_entry = glist_entry(glist, state_lock_entry_t, sle_list);
00774 
00775       remove_from_locklist(found_entry);
00776     }
00777 }
00778 
00779 /* Subtract a lock from a lock entry, placing any remaining bits into the split list. */
00780 static bool_t subtract_lock_from_entry(cache_entry_t        * pentry,
00781                                        fsal_op_context_t    * pcontext,
00782                                        state_lock_entry_t   * found_entry,
00783                                        fsal_lock_param_t    * plock,
00784                                        struct glist_head    * split_list,
00785                                        struct glist_head    * remove_list,
00786                                        state_status_t       * pstatus)
00787 {
00788   uint64_t found_entry_end = lock_end(&found_entry->sle_lock);
00789   uint64_t plock_end = lock_end(plock);
00790   state_lock_entry_t *found_entry_left = NULL;
00791   state_lock_entry_t *found_entry_right = NULL;
00792 
00793   *pstatus = STATE_SUCCESS;
00794 
00795   if(plock_end < found_entry->sle_lock.lock_start)
00796     /* nothing to split */
00797     return FALSE;
00798 
00799   if(found_entry_end < plock->lock_start)
00800     /* nothing to split */
00801     return FALSE;
00802 
00803   if((plock->lock_start <= found_entry->sle_lock.lock_start) &&
00804      plock_end >= found_entry_end)
00805     {
00806       /* Fully overlap */
00807       LogEntry("Remove Complete", found_entry);
00808       goto complete_remove;
00809     }
00810 
00811   LogEntry("Split", found_entry);
00812 
00813   /* Delete the old entry and add one or two new entries */
00814   if(plock->lock_start > found_entry->sle_lock.lock_start)
00815     {
00816       found_entry_left = state_lock_entry_t_dup(pcontext, found_entry);
00817       if(found_entry_left == NULL)
00818         {
00819           free_list(split_list);
00820           *pstatus = STATE_MALLOC_ERROR;
00821           return FALSE;
00822         }
00823 
00824       found_entry_left->sle_lock.lock_length = plock->lock_start - found_entry->sle_lock.lock_start;
00825       LogEntry("Left split", found_entry_left);
00826       glist_add_tail(split_list, &(found_entry_left->sle_list));
00827     }
00828 
00829   if(plock_end < found_entry_end)
00830     {
00831       found_entry_right = state_lock_entry_t_dup(pcontext, found_entry);
00832       if(found_entry_right == NULL)
00833         {
00834           free_list(split_list);
00835           *pstatus = STATE_MALLOC_ERROR;
00836           return FALSE;
00837         }
00838 
00839       found_entry_right->sle_lock.lock_start  = plock_end + 1;
00840       found_entry_right->sle_lock.lock_length = found_entry_end - plock_end;
00841       LogEntry("Right split", found_entry_right);
00842       glist_add_tail(split_list, &(found_entry_right->sle_list));
00843     }
00844 
00845 complete_remove:
00846 
00847   /* Remove the lock from the list it's on and put it on the remove_list */
00848   glist_del(&found_entry->sle_list);
00849   glist_add_tail(remove_list, &(found_entry->sle_list));
00850 
00851   return TRUE;
00852 }
00853 
00854 /* Subtract a lock from a list of locks, possibly splitting entries in the list. */
00855 static bool_t subtract_lock_from_list(cache_entry_t        * pentry,
00856                                       fsal_op_context_t    * pcontext,
00857                                       state_owner_t        * powner,
00858                                       state_t              * pstate,
00859                                       fsal_lock_param_t    * plock,
00860                                       state_status_t       * pstatus,
00861                                       struct glist_head    * list)
00862 {
00863   state_lock_entry_t *found_entry;
00864   struct glist_head split_lock_list, remove_list;
00865   struct glist_head *glist, *glistn;
00866   bool_t rc = FALSE;
00867 
00868   init_glist(&split_lock_list);
00869   init_glist(&remove_list);
00870 
00871   *pstatus = STATE_SUCCESS;
00872   glist_for_each_safe(glist, glistn, list)
00873     {
00874       found_entry = glist_entry(glist, state_lock_entry_t, sle_list);
00875 
00876       if(powner != NULL && different_owners(found_entry->sle_owner, powner))
00877         continue;
00878 
00879       /* Only care about granted locks */
00880       if(found_entry->sle_blocked != STATE_NON_BLOCKING)
00881         continue;
00882 
00883 
00884 #ifdef _USE_NLM
00885       /* Skip locks owned by this NLM state.
00886        * This protects NLM locks from the current iteration of an NLM
00887        * client from being released by SM_NOTIFY.
00888        */
00889       if(pstate != NULL &&
00890          lock_owner_is_nlm(found_entry) &&
00891          found_entry->sle_state == pstate)
00892         continue;
00893 #endif
00894 
00895       /*
00896        * We have matched owner.
00897        * Even though we are taking a reference to found_entry, we
00898        * don't inc the ref count because we want to drop the lock entry.
00899        */
00900       rc |= subtract_lock_from_entry(pentry,
00901                                      pcontext,
00902                                      found_entry,
00903                                      plock,
00904                                      &split_lock_list,
00905                                      &remove_list,
00906                                      pstatus);
00907       if(*pstatus != STATE_SUCCESS)
00908         {
00909           /* We ran out of memory while splitting, deal with it outside loop */
00910           break;
00911         }
00912     }
00913 
00914   if(*pstatus != STATE_SUCCESS)
00915     {
00916       /* We ran out of memory while splitting. split_lock_list has been freed.
00917        * For each entry on the remove_list, put it back on the list.
00918        */
00919       LogDebug(COMPONENT_STATE,
00920                "Failed %s",
00921                state_err_str(*pstatus));
00922       glist_for_each_safe(glist, glistn, &remove_list)
00923         {
00924           found_entry = glist_entry(glist, state_lock_entry_t, sle_list);
00925           glist_del(&found_entry->sle_list);
00926           glist_add_tail(list, &(found_entry->sle_list));
00927         }
00928     }
00929   else
00930     {
00931       /* free the enttries on the remove_list*/
00932       free_list(&remove_list);
00933 
00934       /* now add the split lock list */
00935       glist_add_list_tail(list, &split_lock_list);
00936     }
00937 
00938   LogFullDebug(COMPONENT_STATE,
00939                "List of all locks for pentry=%p returning %d",
00940                pentry, (int) rc);
00941 
00942   return rc;
00943 }
00944 
00945 static state_status_t subtract_list_from_list(cache_entry_t        * pentry,
00946                                               fsal_op_context_t    * pcontext,
00947                                               struct glist_head    * target,
00948                                               struct glist_head    * source,
00949                                               state_status_t       * pstatus)
00950 {
00951   state_lock_entry_t *found_entry;
00952   struct glist_head *glist, *glistn;
00953 
00954   *pstatus = STATE_SUCCESS;
00955 
00956   glist_for_each_safe(glist, glistn, source)
00957     {
00958       found_entry = glist_entry(glist, state_lock_entry_t, sle_list);
00959 
00960       subtract_lock_from_list(pentry,
00961                               pcontext,
00962                               NULL,
00963                               NULL,
00964                               &found_entry->sle_lock,
00965                               pstatus,
00966                               target);
00967       if(*pstatus != STATE_SUCCESS)
00968         break;
00969     }
00970 
00971   return *pstatus;
00972 }
00973 
00974 /******************************************************************************
00975  *
00976  * Implement hash table to hash blocked lock entries by cookie
00977  *
00978  ******************************************************************************/
00979 
00980 #ifdef _USE_BLOCKING_LOCKS
00981 static void grant_blocked_locks(cache_entry_t        * pentry,
00982                                 fsal_op_context_t    * pcontext);
00983 
00984 int display_lock_cookie_key(hash_buffer_t * pbuff, char *str)
00985 {
00986   return DisplayOpaqueValue((char *)pbuff->pdata, pbuff->len, str);
00987 }
00988 
00989 int display_lock_cookie_entry(state_cookie_entry_t * he, char * str)
00990 {
00991   char *tmp = str;
00992 
00993   tmp += sprintf(tmp, "%p: cookie ", he);
00994   tmp += DisplayOpaqueValue(he->sce_pcookie, he->sce_cookie_size, tmp);
00995   tmp += sprintf(tmp, " entry {%p fileid=%"PRIu64"} lock {",
00996                  he->sce_pentry,
00997                  (uint64_t)he->sce_pentry->attributes.fileid);
00998   if(he->sce_lock_entry != NULL)
00999     {
01000       tmp += sprintf(tmp, "%p owner {", he->sce_lock_entry);
01001 
01002       tmp += DisplayOwner(he->sce_lock_entry->sle_owner, tmp);
01003 
01004       tmp += sprintf(tmp, "} type=%s start=0x%llx end=0x%llx blocked=%s}",
01005                      str_lockt(he->sce_lock_entry->sle_lock.lock_type),
01006                      (unsigned long long) he->sce_lock_entry->sle_lock.lock_start,
01007                      (unsigned long long) lock_end(&he->sce_lock_entry->sle_lock),
01008                      str_blocked(he->sce_lock_entry->sle_blocked));
01009     }
01010   else
01011     {
01012       tmp += sprintf(tmp, "<NULL>}");
01013     }
01014 
01015   return tmp - str;
01016 }
01017 
01018 int display_lock_cookie_val(hash_buffer_t * pbuff, char *str)
01019 {
01020   return display_lock_cookie_entry((state_cookie_entry_t *)pbuff->pdata, str);
01021 }
01022 
01023 int compare_lock_cookie_key(hash_buffer_t * buff1, hash_buffer_t * buff2)
01024 {
01025   if(isFullDebug(COMPONENT_STATE) && isDebug(COMPONENT_HASHTABLE))
01026     {
01027       char str1[HASHTABLE_DISPLAY_STRLEN];
01028       char str2[HASHTABLE_DISPLAY_STRLEN];
01029 
01030       display_lock_cookie_key(buff1, str1);
01031       display_lock_cookie_key(buff2, str2);
01032       LogFullDebug(COMPONENT_STATE,
01033                    "{%s} vs {%s}", str1, str2);
01034     }
01035 
01036   if(buff1->pdata == buff2->pdata)
01037     return 0;
01038 
01039   if(buff1->len != buff2->len)
01040     return 1;
01041 
01042   if(buff1->pdata == NULL || buff2->pdata == NULL)
01043     return 1;
01044 
01045   return memcmp(buff1->pdata, buff2->pdata, buff1->len);
01046 }
01047 
01048 uint32_t lock_cookie_value_hash_func(hash_parameter_t * p_hparam,
01049                                      hash_buffer_t * buffclef)
01050 {
01051   unsigned int sum = 0;
01052   unsigned int i;
01053   unsigned long res;
01054   unsigned char *pdata = (unsigned char *) buffclef->pdata;
01055 
01056   /* Compute the sum of all the characters */
01057   for(i = 0; i < buffclef->len; i++)
01058     sum +=(unsigned char) pdata[i];
01059 
01060   res = (unsigned long) sum +
01061         (unsigned long) buffclef->len;
01062 
01063   if(isDebug(COMPONENT_HASHTABLE))
01064     LogFullDebug(COMPONENT_STATE,
01065                  "value = %lu", res % p_hparam->index_size);
01066 
01067   return (unsigned long)(res % p_hparam->index_size);
01068 }
01069 
01070 uint64_t lock_cookie_rbt_hash_func(hash_parameter_t * p_hparam,
01071                                    hash_buffer_t * buffclef)
01072 {
01073   unsigned int sum = 0;
01074   unsigned int i;
01075   unsigned long res;
01076   unsigned char *pdata = (unsigned char *) buffclef->pdata;
01077 
01078   /* Compute the sum of all the characters */
01079   for(i = 0; i < buffclef->len; i++)
01080     sum +=(unsigned char) pdata[i];
01081 
01082   res = (unsigned long) sum +
01083         (unsigned long) buffclef->len;
01084 
01085   if(isDebug(COMPONENT_HASHTABLE))
01086     LogFullDebug(COMPONENT_STATE, "rbt = %lu", res);
01087 
01088   return res;
01089 }
01090 
01091 void free_cookie(state_cookie_entry_t * p_cookie_entry,
01092                  bool_t                 unblock)
01093 {
01094   char   str[HASHTABLE_DISPLAY_STRLEN];
01095   void * pcookie = p_cookie_entry->sce_pcookie;
01096 
01097   if(isFullDebug(COMPONENT_STATE))
01098     display_lock_cookie_entry(p_cookie_entry, str);
01099 
01100   /* Since the cookie is not in the hash table, we can just free the memory */
01101   LogFullDebug(COMPONENT_STATE,
01102                "Free Lock Cookie {%s}",
01103                str);
01104 
01105   /* If block data is still attached to lock entry, remove it */
01106   if(p_cookie_entry->sce_lock_entry != NULL && unblock)
01107     {
01108       if(p_cookie_entry->sce_lock_entry->sle_block_data != NULL)
01109         p_cookie_entry->sce_lock_entry->sle_block_data->sbd_blocked_cookie = NULL;
01110 
01111       lock_entry_dec_ref(p_cookie_entry->sce_lock_entry);
01112     }
01113 
01114   /* Free the memory for the cookie and the cookie entry */
01115   memset(pcookie, 0, p_cookie_entry->sce_cookie_size);
01116   memset(p_cookie_entry, 0, sizeof(*p_cookie_entry));
01117 
01118   gsh_free(pcookie);
01119   gsh_free(p_cookie_entry);
01120 }
01121 
01122 state_status_t state_add_grant_cookie(cache_entry_t         * pentry,
01123                                       fsal_op_context_t     * pcontext,
01124                                       void                  * pcookie,
01125                                       int                     cookie_size,
01126                                       state_lock_entry_t    * lock_entry,
01127                                       state_cookie_entry_t ** ppcookie_entry,
01128                                       state_status_t        * pstatus)
01129 {
01130   hash_buffer_t          buffkey, buffval;
01131   state_cookie_entry_t * hash_entry;
01132   char                   str[HASHTABLE_DISPLAY_STRLEN];
01133 
01134   *ppcookie_entry = NULL;
01135 
01136   if(lock_entry->sle_block_data == NULL || pcookie == NULL || cookie_size == 0)
01137     {
01138       /* Something's wrong with this entry */
01139       *pstatus = STATE_INCONSISTENT_ENTRY;
01140       return *pstatus;
01141     }
01142 
01143   if(isFullDebug(COMPONENT_STATE))
01144     DisplayOpaqueValue(pcookie, cookie_size, str);
01145 
01146   hash_entry = gsh_malloc(sizeof(*hash_entry));
01147   if(hash_entry == NULL)
01148     {
01149       LogFullDebug(COMPONENT_STATE,
01150                    "KEY {%s} NO MEMORY",
01151                    str);
01152       *pstatus = STATE_MALLOC_ERROR;
01153       return *pstatus;
01154     }
01155 
01156   memset(hash_entry, 0, sizeof(*hash_entry));
01157 
01158   buffkey.pdata = gsh_malloc(cookie_size);
01159   if(buffkey.pdata == NULL)
01160     {
01161       LogFullDebug(COMPONENT_STATE,
01162                    "KEY {%s} NO MEMORY",
01163                    str);
01164       gsh_free(hash_entry);
01165       *pstatus = STATE_MALLOC_ERROR;
01166       return *pstatus;
01167     }
01168 
01169   hash_entry->sce_pentry      = pentry;
01170   hash_entry->sce_lock_entry  = lock_entry;
01171   hash_entry->sce_pcookie     = buffkey.pdata;
01172   hash_entry->sce_cookie_size = cookie_size;
01173 
01174   memcpy(buffkey.pdata, pcookie, cookie_size);
01175   buffkey.len   = cookie_size;
01176   buffval.pdata = (void *)hash_entry;
01177   buffval.len   = sizeof(*hash_entry);
01178 
01179   if(isFullDebug(COMPONENT_STATE))
01180     display_lock_cookie_entry(hash_entry, str);
01181 
01182 
01183   if(HashTable_Test_And_Set
01184      (ht_lock_cookies, &buffkey, &buffval,
01185       HASHTABLE_SET_HOW_SET_NO_OVERWRITE) != HASHTABLE_SUCCESS)
01186     {
01187       gsh_free(hash_entry);
01188       LogFullDebug(COMPONENT_STATE,
01189                    "Lock Cookie {%s} HASH TABLE ERROR",
01190                    str);
01191       *pstatus = STATE_HASH_TABLE_ERROR;
01192       return *pstatus;
01193     }
01194 
01195   /* Increment lock entry reference count and link it to the cookie */
01196   lock_entry_inc_ref(lock_entry);
01197   lock_entry->sle_block_data->sbd_blocked_cookie = hash_entry;
01198 
01199   LogFullDebug(COMPONENT_STATE,
01200                "Lock Cookie {%s} Added",
01201                str);
01202 
01203   switch(lock_entry->sle_block_data->sbd_grant_type)
01204     {
01205       case STATE_GRANT_NONE:
01206         /* Shouldn't get here */
01207         *pstatus = STATE_INCONSISTENT_ENTRY;
01208         break;
01209 
01210       case STATE_GRANT_FSAL_AVAILABLE:
01211         /* Now that we are sure we can continue, try to acquire the FSAL lock */
01212         /* If we get STATE_LOCK_BLOCKED we need to return... */
01213         *pstatus = do_lock_op(pentry,
01214                               pcontext,
01215                               lock_entry->sle_pexport,
01216                               FSAL_OP_LOCKB,
01217                               lock_entry->sle_owner,
01218                               &lock_entry->sle_lock,
01219                               NULL,
01220                               NULL,
01221                               FALSE);
01222         break;
01223 
01224       case STATE_GRANT_INTERNAL:
01225         /* Now that we are sure we can continue, acquire the FSAL lock */
01226         /* If we get STATE_LOCK_BLOCKED we need to return... */
01227         *pstatus = do_lock_op(pentry,
01228                               pcontext,
01229                               lock_entry->sle_pexport,
01230                               FSAL_OP_LOCK,
01231                               lock_entry->sle_owner,
01232                               &lock_entry->sle_lock,
01233                               NULL,
01234                               NULL,
01235                               FALSE);
01236         break;
01237 
01238       case STATE_GRANT_FSAL:
01239         /* No need to go to FSAL for lock */
01240         *pstatus = STATE_SUCCESS;
01241         break;
01242     }
01243 
01244   if(*pstatus != STATE_SUCCESS)
01245     {
01246       /* lock will be returned to right blocking type if it is still blocking
01247        * we could lose a block if we failed for any other reason
01248        */
01249       if(*pstatus == STATE_LOCK_BLOCKED)
01250         LogDebug(COMPONENT_STATE,
01251                  "Unable to lock FSAL for %s lock, error=%s",
01252                  str_blocked(lock_entry->sle_blocked),
01253                  state_err_str(*pstatus));
01254       else
01255         LogMajor(COMPONENT_STATE,
01256                  "Unable to lock FSAL for %s lock, error=%s",
01257                  str_blocked(lock_entry->sle_blocked),
01258                  state_err_str(*pstatus));
01259 
01260       LogEntry("Entry", lock_entry);
01261 
01262       /* And release the cookie without unblocking the lock.
01263        * grant_blocked_locks() will decide whether to keep or free the block.
01264        */
01265       free_cookie(hash_entry, FALSE);
01266 
01267       return *pstatus;
01268     }
01269 
01270   *ppcookie_entry = hash_entry;
01271   return *pstatus;
01272 }
01273 
01274 state_status_t state_cancel_grant(fsal_op_context_t    * pcontext,
01275                                   state_cookie_entry_t * cookie_entry,
01276                                   state_status_t       * pstatus)
01277 {
01278   /* We had acquired an FSAL lock, need to release it. */
01279   *pstatus = do_lock_op(cookie_entry->sce_pentry,
01280                         pcontext,
01281                         cookie_entry->sce_lock_entry->sle_pexport,
01282                         FSAL_OP_UNLOCK,
01283                         cookie_entry->sce_lock_entry->sle_owner,
01284                         &cookie_entry->sce_lock_entry->sle_lock,
01285                         NULL,   /* no conflict expected */
01286                         NULL,
01287                         FALSE);
01288 
01289   if(*pstatus != STATE_SUCCESS)
01290     LogMajor(COMPONENT_STATE,
01291              "Unable to unlock FSAL for canceled GRANTED lock, error=%s",
01292              state_err_str(*pstatus));
01293 
01294   /* And release the cookie and unblock lock (because lock will be removed) */
01295   free_cookie(cookie_entry, TRUE);
01296 
01297   return *pstatus;
01298 }
01299 
01300 state_status_t state_find_grant(void                  * pcookie,
01301                                 int                     cookie_size,
01302                                 state_cookie_entry_t ** ppcookie_entry,
01303                                 state_status_t        * pstatus)
01304 {
01305   hash_buffer_t buffkey;
01306   hash_buffer_t buffval;
01307   hash_buffer_t buffused_key;
01308   char          str[HASHTABLE_DISPLAY_STRLEN];
01309 
01310   buffkey.pdata = (caddr_t) pcookie;
01311   buffkey.len   = cookie_size;
01312 
01313   if(isFullDebug(COMPONENT_STATE) && isDebug(COMPONENT_HASHTABLE))
01314     {
01315       display_lock_cookie_key(&buffkey, str);
01316       LogFullDebug(COMPONENT_STATE,
01317                    "KEY {%s}", str);
01318     }
01319 
01320   if(HashTable_Get_and_Del(ht_lock_cookies, &buffkey, &buffval, &buffused_key) != HASHTABLE_SUCCESS)
01321     {
01322       LogFullDebug(COMPONENT_STATE,
01323                    "KEY {%s} NOTFOUND", str);
01324       *pstatus = STATE_BAD_COOKIE;
01325       return *pstatus;
01326     }
01327 
01328   *ppcookie_entry = (state_cookie_entry_t *) buffval.pdata;
01329 
01330   if(isFullDebug(COMPONENT_STATE) && isDebug(COMPONENT_HASHTABLE))
01331     {
01332       char str[HASHTABLE_DISPLAY_STRLEN];
01333 
01334       display_lock_cookie_entry(*ppcookie_entry, str);
01335       LogFullDebug(COMPONENT_STATE,
01336                    "Found Lock Cookie {%s}", str);
01337     }
01338 
01339   *pstatus = STATE_SUCCESS;
01340   return *pstatus;
01341 }
01342 
01343 void grant_blocked_lock_immediate(cache_entry_t         * pentry,
01344                                   fsal_op_context_t     * pcontext,
01345                                   state_lock_entry_t    * lock_entry)
01346 {
01347   state_cookie_entry_t * pcookie = NULL;
01348   state_status_t         state_status;
01349 
01350   /* Try to clean up blocked lock. */
01351   if(lock_entry->sle_block_data != NULL)
01352     {
01353       if(lock_entry->sle_block_data->sbd_blocked_cookie != NULL)
01354         {
01355           /* Cookie is attached, try to get it */
01356           pcookie = lock_entry->sle_block_data->sbd_blocked_cookie;
01357 
01358           if(state_find_grant(pcookie->sce_pcookie,
01359                               pcookie->sce_cookie_size,
01360                               &pcookie,
01361                               &state_status) == STATE_SUCCESS)
01362             {
01363               /* We've got the cookie, free the cookie and the blocked lock */
01364               free_cookie(pcookie, TRUE);
01365             }
01366           else
01367             {
01368               /* Otherwise, another thread has the cookie, let it do it's business. */
01369               return;
01370             }
01371         }
01372       else
01373         {
01374           /* We have block data but no cookie, so we can just free the block data */
01375           memset(lock_entry->sle_block_data, 0, sizeof(*lock_entry->sle_block_data));
01376           gsh_free(lock_entry->sle_block_data);
01377           lock_entry->sle_block_data = NULL;
01378         }
01379     }
01380 
01381   /* Mark lock as granted */
01382   lock_entry->sle_blocked = STATE_NON_BLOCKING;
01383 
01384   /* Merge any touching or overlapping locks into this one. */
01385   LogEntry("Granted immediate, merging locks for", lock_entry);
01386 
01387   merge_lock_entry(pentry, pcontext, lock_entry);
01388   LogEntry("Immediate Granted entry", lock_entry);
01389 
01390   /* A lock downgrade could unblock blocked locks */
01391   grant_blocked_locks(pentry, pcontext);
01392 }
01393 
01394 void state_complete_grant(fsal_op_context_t     * pcontext,
01395                           state_cookie_entry_t  * cookie_entry)
01396 {
01397   state_lock_entry_t   * lock_entry;
01398   cache_entry_t        * pentry;
01399 
01400   lock_entry = cookie_entry->sce_lock_entry;
01401   pentry     = cookie_entry->sce_pentry;
01402 
01403   /* This routine does not call cache_inode_inc_pin_ref() because there MUST be
01404    * at least one lock present for there to be a cookie_entry to even allow this
01405    * routine to be called, and therefor the cache entry MUST be pinned.
01406    */
01407 
01408   pthread_rwlock_wrlock(&pentry->state_lock);
01409 
01410   /* We need to make sure lock is ready to be granted */
01411   if(lock_entry->sle_blocked == STATE_GRANTING)
01412     {
01413       /* Mark lock as granted */
01414       lock_entry->sle_blocked = STATE_NON_BLOCKING;
01415 
01416       /* Merge any touching or overlapping locks into this one. */
01417       LogEntry("Granted, merging locks for", lock_entry);
01418       merge_lock_entry(pentry, pcontext, lock_entry);
01419 
01420       LogEntry("Granted entry", lock_entry);
01421 
01422       /* A lock downgrade could unblock blocked locks */
01423       grant_blocked_locks(pentry, pcontext);
01424     }
01425 
01426   /* Free cookie and unblock lock.
01427    * If somehow the lock was unlocked/canceled while the GRANT
01428    * was in progress, this will completely clean up the lock.
01429    */
01430   free_cookie(cookie_entry, TRUE);
01431 
01432   /* In case all locks have wound up free, we must release the pin reference. */
01433   if(glist_empty(&pentry->object.file.lock_list))
01434       cache_inode_dec_pin_ref(pentry);
01435 
01436   pthread_rwlock_unlock(&pentry->state_lock);
01437 }
01438 
01439 void try_to_grant_lock(state_lock_entry_t   * lock_entry)
01440 {
01441   granted_callback_t     call_back;
01442   state_blocking_t       blocked;
01443   state_status_t         status;
01444 
01445   /* Try to grant if not cancelled and has block data */
01446   if(lock_entry->sle_blocked != STATE_CANCELED &&
01447      lock_entry->sle_block_data != NULL)
01448     {
01449       call_back = lock_entry->sle_block_data->sbd_granted_callback;
01450       /*
01451        * Mark the lock_entry as provisionally granted and make the granted
01452        * call back. The granted call back is responsible for acquiring a
01453        * reference to the lock entry if needed.
01454        */
01455       blocked = lock_entry->sle_blocked;
01456       lock_entry->sle_blocked = STATE_GRANTING;
01457       if(lock_entry->sle_block_data->sbd_grant_type == STATE_GRANT_NONE)
01458         lock_entry->sle_block_data->sbd_grant_type = STATE_GRANT_INTERNAL;
01459 
01460       if(call_back(lock_entry->sle_pentry,
01461                    lock_entry,
01462                    &status) == STATE_LOCK_BLOCKED)
01463         {
01464           /* The lock is still blocked, restore it's type and leave it in the list */
01465           lock_entry->sle_blocked = blocked;
01466           return;
01467         }
01468 
01469       if(status == STATE_SUCCESS)
01470         return;
01471     }
01472 
01473   /* There was no call back data, the call back failed, or the block was cancelled.
01474    * Remove lock from list.
01475    */
01476   LogEntry("Removing blocked entry", lock_entry);
01477   remove_from_locklist(lock_entry);
01478 }
01479 
01480 void process_blocked_lock_upcall(state_block_data_t   * block_data)
01481 {
01482   state_lock_entry_t * lock_entry = block_data->sbd_lock_entry;
01483   cache_entry_t      * pentry = lock_entry->sle_pentry;
01484 
01485   /* This routine does not call cache_inode_inc_pin_ref() because there MUST be
01486    * at least one lock present for there to be a block_data to even allow this
01487    * routine to be called, and therefor the cache entry MUST be pinned.
01488    */
01489 
01490   pthread_rwlock_wrlock(&pentry->state_lock);
01491 
01492   try_to_grant_lock(lock_entry);
01493 
01494   /* In case all locks have wound up free, we must release the pin reference. */
01495   if(glist_empty(&pentry->object.file.lock_list))
01496       cache_inode_dec_pin_ref(pentry);
01497 
01498   pthread_rwlock_unlock(&pentry->state_lock);
01499 }
01500 
01501 static void grant_blocked_locks(cache_entry_t        * pentry,
01502                                 fsal_op_context_t    * pcontext)
01503 {
01504   state_lock_entry_t   * found_entry;
01505   struct glist_head    * glist, * glistn;
01506   fsal_staticfsinfo_t  * pstatic = pcontext->export_context->fe_static_fs_info;
01507 
01508   /* If FSAL supports async blocking locks, allow it to grant blocked locks. */
01509   if(pstatic->lock_support_async_block)
01510     return;
01511 
01512   glist_for_each_safe(glist, glistn, &pentry->object.file.lock_list)
01513     {
01514       found_entry = glist_entry(glist, state_lock_entry_t, sle_list);
01515 
01516       if(found_entry->sle_blocked != STATE_NLM_BLOCKING &&
01517          found_entry->sle_blocked != STATE_NFSV4_BLOCKING)
01518           continue;
01519 
01520       /* Found a blocked entry for this file, see if we can place the lock. */
01521       if(get_overlapping_entry(pentry,
01522                                pcontext,
01523                                found_entry->sle_owner,
01524                                &found_entry->sle_lock) != NULL)
01525         continue;
01526 
01527       /* Found an entry that might work, try to grant it. */
01528       try_to_grant_lock(found_entry);
01529     }
01530 }
01531 
01532 state_status_t cancel_blocked_lock(cache_entry_t        * pentry,
01533                                    fsal_op_context_t    * pcontext,
01534                                    state_lock_entry_t   * lock_entry)
01535 {
01536   state_cookie_entry_t * pcookie = NULL;
01537   state_status_t         state_status;
01538 
01539   /* Mark lock as canceled */
01540   LogEntry("Cancelling blocked", lock_entry);
01541   lock_entry->sle_blocked = STATE_CANCELED;
01542 
01543       /* Unlocking the entire region will remove any FSAL locks we held, whether
01544        * from fully granted locks, or from blocking locks that were in the process
01545        * of being granted.
01546        */
01547 
01548   /* Try to clean up blocked lock if a cookie is present */
01549   if(lock_entry->sle_block_data != NULL &&
01550      lock_entry->sle_block_data->sbd_blocked_cookie != NULL)
01551     {
01552       /* Cookie is attached, try to get it */
01553       pcookie = lock_entry->sle_block_data->sbd_blocked_cookie;
01554 
01555       if(state_find_grant(pcookie->sce_pcookie,
01556                           pcookie->sce_cookie_size,
01557                           &pcookie,
01558                           &state_status) == STATE_SUCCESS)
01559         {
01560           /* We've got the cookie, free the cookie and the blocked lock */
01561           free_cookie(pcookie, TRUE);
01562         }
01563       /* otherwise, another thread has the cookie, let it do it's business,
01564        * which won't be much, since we've already marked the lock CANCELED.
01565        */
01566     }
01567   else
01568     {
01569       /* Otherwise, if block data is present, it will be freed when the lock
01570        * entry is freed. If the cookie is held, the refcount it holds will
01571        * prevent the lock entry from being released until the cookie is
01572        * freed.
01573        */
01574 
01575       /* Since a cookie was not found, the lock must still be in a state
01576        * of needing cancelling.
01577        */
01578       state_status = do_lock_op(pentry,
01579                                 pcontext,
01580                                 lock_entry->sle_pexport,
01581                                 FSAL_OP_CANCEL,
01582                                 lock_entry->sle_owner,
01583                                 &lock_entry->sle_lock,
01584                                 NULL,   /* no conflict expected */
01585                                 NULL,
01586                                 FALSE); /* overlap not relevant */
01587 
01588       if(state_status != STATE_SUCCESS)
01589         {
01590           /* Unable to cancel, assume that granted upcall is on it's way. */
01591           LogEntry("Unable to cancel (grant upcall expected)", lock_entry);
01592           return STATE_SUCCESS;
01593         }
01594     }
01595 
01596   /* Remove the lock from the lock list*/
01597   LogEntry("Removing", lock_entry);
01598   remove_from_locklist(lock_entry);
01599 
01600   return state_status;
01601 }
01602 
01623 void cancel_blocked_locks_range(cache_entry_t        * pentry,
01624                                 fsal_op_context_t    * pcontext,
01625                                 state_owner_t        * powner,
01626                                 state_t              * pstate,
01627                                 fsal_lock_param_t    * plock)
01628 {
01629   struct glist_head  * glist, * glistn;
01630   state_lock_entry_t * found_entry = NULL;
01631   uint64_t             found_entry_end, plock_end = lock_end(plock);
01632 
01633   glist_for_each_safe(glist, glistn, &pentry->object.file.lock_list)
01634     {
01635       found_entry = glist_entry(glist, state_lock_entry_t, sle_list);
01636 
01637       /* Skip locks not owned by owner */
01638       if(powner != NULL && different_owners(found_entry->sle_owner, powner))
01639         continue;
01640 
01641       /* Skip locks owned by this NLM state.
01642        * This protects NLM locks from the current iteration of an NLM
01643        * client from being released by SM_NOTIFY.
01644        */
01645       if(pstate != NULL &&
01646          lock_owner_is_nlm(found_entry) &&
01647          found_entry->sle_state == pstate)
01648         continue;
01649 
01650       /* Skip granted locks */
01651       if(found_entry->sle_blocked == STATE_NON_BLOCKING)
01652         continue;
01653 
01654       LogEntry("Checking", found_entry);
01655 
01656       found_entry_end = lock_end(&found_entry->sle_lock);
01657 
01658       if((found_entry_end >= plock->lock_start) &&
01659          (found_entry->sle_lock.lock_start <= plock_end))
01660         {
01661           /* lock overlaps, cancel it. */
01662           (void) cancel_blocked_lock(pentry, pcontext, found_entry);
01663         }
01664     }
01665 }
01666 
01667 state_status_t state_release_grant(fsal_op_context_t     * pcontext,
01668                                    state_cookie_entry_t  * cookie_entry,
01669                                    state_status_t        * pstatus)
01670 {
01671   state_lock_entry_t   * lock_entry;
01672   cache_entry_t        * pentry;
01673 
01674   *pstatus = STATE_SUCCESS;
01675 
01676   lock_entry = cookie_entry->sce_lock_entry;
01677   pentry     = cookie_entry->sce_pentry;
01678 
01679   /* This routine does not call cache_inode_inc_pin_ref() because there MUST be
01680    * at least one lock present for there to be a cookie_entry to even allow this
01681    * routine to be called, and therefor the cache entry MUST be pinned.
01682    */
01683 
01684   pthread_rwlock_wrlock(&pentry->state_lock);
01685 
01686   /* We need to make sure lock is only "granted" once...
01687    * It's (remotely) possible that due to latency, we might end up processing
01688    * two GRANTED_RSP calls at the same time.
01689    */
01690   if(lock_entry->sle_blocked == STATE_GRANTING)
01691     {
01692       /* Mark lock as canceled */
01693       lock_entry->sle_blocked = STATE_CANCELED;
01694 
01695       /* Remove the lock from the lock list.
01696        * Will not free yet because of cookie reference to lock entry.
01697        */
01698       LogEntry("Release Grant Removing", lock_entry);
01699       remove_from_locklist(lock_entry);
01700 
01701       /* We had acquired an FSAL lock, need to release it. */
01702       *pstatus = do_lock_op(pentry,
01703                             pcontext,
01704                             lock_entry->sle_pexport,
01705                             FSAL_OP_UNLOCK,
01706                             lock_entry->sle_owner,
01707                             &lock_entry->sle_lock,
01708                             NULL,   /* no conflict expected */
01709                             NULL,
01710                             FALSE);
01711 
01712       if(*pstatus != STATE_SUCCESS)
01713         LogMajor(COMPONENT_STATE,
01714                  "Unable to unlock FSAL for released GRANTED lock, error=%s",
01715                  state_err_str(*pstatus));
01716     }
01717 
01718   /* Free the cookie and unblock the lock.
01719    * This will release our final reference on the lock entry and should free it.
01720    * (Unless another thread has a reference for some reason.
01721    */
01722   free_cookie(cookie_entry, TRUE);
01723 
01724   /* Check to see if we can grant any blocked locks. */
01725   grant_blocked_locks(pentry, pcontext);
01726 
01727   /* In case all locks have wound up free, we must release the pin reference. */
01728   if(glist_empty(&pentry->object.file.lock_list))
01729       cache_inode_dec_pin_ref(pentry);
01730 
01731   pthread_rwlock_unlock(&pentry->state_lock);
01732 
01733   return *pstatus;
01734 }
01735 #endif
01736 
01737 /******************************************************************************
01738  *
01739  * Functions to interract with FSAL
01740  *
01741  ******************************************************************************/
01742 inline const char *fsal_lock_op_str(fsal_lock_op_t op)
01743 {
01744   switch(op)
01745     {
01746       case FSAL_OP_LOCKT:  return "FSAL_OP_LOCKT ";
01747       case FSAL_OP_LOCK:   return "FSAL_OP_LOCK  ";
01748       case FSAL_OP_LOCKB:  return "FSAL_OP_LOCKB ";
01749       case FSAL_OP_UNLOCK: return "FSAL_OP_UNLOCK";
01750       case FSAL_OP_CANCEL: return "FSAL_OP_CANCEL";
01751     }
01752   return "unknown";
01753 }
01754 
01774 state_status_t do_unlock_no_owner(cache_entry_t        * pentry,
01775                                   fsal_op_context_t    * pcontext,
01776                                   exportlist_t         * pexport,
01777                                   fsal_lock_param_t    * plock)
01778 {
01779   state_lock_entry_t * unlock_entry;
01780   struct glist_head    fsal_unlock_list;
01781   struct glist_head  * glist, *glistn;
01782   state_lock_entry_t * found_entry;
01783   fsal_status_t        fsal_status;
01784   state_status_t       status = STATE_SUCCESS, t_status;
01785   fsal_lock_param_t  * punlock;
01786 
01787   unlock_entry = create_state_lock_entry(pentry,
01788                                          pcontext,
01789                                          pexport,
01790                                          STATE_NON_BLOCKING,
01791                                          &unknown_owner, /* no real owner */
01792                                          NULL, /* no real state */
01793                                          plock);
01794 
01795   if(unlock_entry == NULL)
01796     return STATE_MALLOC_ERROR;
01797 
01798   init_glist(&fsal_unlock_list);
01799 
01800   glist_add_tail(&fsal_unlock_list, &unlock_entry->sle_list);
01801 
01802   LogEntry("Generating FSAL Unlock List", unlock_entry);
01803 
01804   if(subtract_list_from_list(pentry,
01805                              pcontext,
01806                              &fsal_unlock_list,
01807                              &pentry->object.file.lock_list,
01808                              &status) != STATE_SUCCESS)
01809     {
01810       /* We ran out of memory while trying to build the unlock list.
01811        * We have already released the locks from cache inode lock list.
01812        */
01813       // TODO FSF: what do we do now?
01814       LogMajor(COMPONENT_STATE,
01815                "Error %s while trying to create unlock list",
01816                state_err_str(status));
01817     }
01818 
01819   glist_for_each_safe(glist, glistn, &fsal_unlock_list)
01820     {
01821       found_entry = glist_entry(glist, state_lock_entry_t, sle_list);
01822       punlock     = &found_entry->sle_lock;
01823 
01824       LogEntry("FSAL Unlock", found_entry);
01825 
01826       fsal_status = FSAL_lock_op(cache_inode_fd(pentry),
01827                                  &pentry->handle,
01828                                  pcontext,
01829                                  NULL,
01830                                  FSAL_OP_UNLOCK,
01831                                  *punlock,
01832                                  NULL);
01833 
01834       t_status = state_error_convert(fsal_status);
01835 
01836       LogFullDebug(COMPONENT_STATE,
01837                    "FSAL_lock_op returned %s",
01838                    state_err_str(t_status));
01839 
01840       if(t_status != STATE_SUCCESS)
01841         {
01842           // TODO FSF: what do we do now?
01843           LogMajor(COMPONENT_STATE,
01844                    "Error %s while trying to do FSAL Unlock",
01845                    state_err_str(status));
01846           status = t_status;
01847         }
01848 
01849       remove_from_locklist(found_entry);
01850     }
01851 
01852   return status;
01853 }
01854 
01855 state_status_t do_lock_op(cache_entry_t        * pentry,
01856                           fsal_op_context_t    * pcontext,
01857                           exportlist_t         * pexport,
01858                           fsal_lock_op_t         lock_op,
01859                           state_owner_t        * powner,
01860                           fsal_lock_param_t    * plock,
01861                           state_owner_t       ** holder,   /* owner that holds conflicting lock */
01862                           fsal_lock_param_t    * conflict, /* description of conflicting lock */
01863                           bool_t                 overlap)  /* hint that lock overlaps */
01864 {
01865   fsal_status_t         fsal_status;
01866   state_status_t        status = STATE_SUCCESS;
01867   fsal_lock_param_t     conflicting_lock;
01868   fsal_staticfsinfo_t * pstatic = pcontext->export_context->fe_static_fs_info;
01869 
01870   /* Quick exit if:
01871    * Locks are not supported by FSAL
01872    * Async blocking locks are not supported and this is a cancel
01873    * Async blocking locks are not supported and this lock overlaps
01874    * Lock owners are not supported and hint tells us that lock fully overlaps a
01875    *   lock we already have (no need to make another FSAL call in that case)
01876    */
01877   if(!pstatic->lock_support ||
01878      (!pstatic->lock_support_async_block && lock_op == FSAL_OP_CANCEL) ||
01879      (!pstatic->lock_support_async_block && overlap) ||
01880      (!pstatic->lock_support_owner && overlap))
01881     return STATE_SUCCESS;
01882 
01883   LogLock(COMPONENT_STATE, NIV_FULL_DEBUG,
01884           fsal_lock_op_str(lock_op), pentry, pcontext, powner, plock);
01885 
01886   memset(&conflicting_lock, 0, sizeof(conflicting_lock));
01887 
01888   if(pstatic->lock_support_owner || lock_op != FSAL_OP_UNLOCK)
01889     {
01890       if(lock_op == FSAL_OP_LOCKB && !pstatic->lock_support_async_block)
01891         lock_op = FSAL_OP_LOCK;
01892 
01893       fsal_status = FSAL_lock_op(cache_inode_fd(pentry),
01894                                  &pentry->handle,
01895                                  pcontext,
01896                                  pstatic->lock_support_owner ? powner : NULL,
01897                                  lock_op,
01898                                  *plock,
01899                                  &conflicting_lock);
01900 
01901       status = state_error_convert(fsal_status);
01902 
01903       LogFullDebug(COMPONENT_STATE,
01904                    "FSAL_lock_op returned %s",
01905                    state_err_str(status));
01906 
01907       if(status == STATE_LOCK_BLOCKED && lock_op != FSAL_OP_LOCKB)
01908         {
01909           /* This is an unexpected return code, make sure caller reports an error */
01910           LogMajor(COMPONENT_STATE,
01911                    "FSAL returned unexpected STATE_LOCK_BLOCKED result");
01912           status = STATE_FSAL_ERROR;
01913         }
01914     }
01915   else
01916     {
01917       status = do_unlock_no_owner(pentry, pcontext, pexport, plock);
01918     }
01919 
01920   if(status == STATE_LOCK_CONFLICT)
01921     {
01922       if(holder != NULL)
01923         {
01924           *holder = &unknown_owner;
01925           inc_state_owner_ref(&unknown_owner);
01926         }
01927       if(conflict != NULL)
01928         {
01929           *conflict = conflicting_lock;
01930         }
01931     }
01932 
01933   return status;
01934 }
01935 
01936 void copy_conflict(state_lock_entry_t  * found_entry,
01937                    state_owner_t      ** holder,   /* owner that holds conflicting lock */
01938                    fsal_lock_param_t   * conflict) /* description of conflicting lock */
01939 {
01940   if(found_entry == NULL)
01941     return;
01942 
01943   if(holder != NULL)
01944     {
01945       *holder = found_entry->sle_owner;
01946       inc_state_owner_ref(found_entry->sle_owner);
01947     }
01948   if(conflict != NULL)
01949     *conflict = found_entry->sle_lock;
01950 }
01951 
01952 /******************************************************************************
01953  *
01954  * Primary lock interface functions
01955  *
01956  ******************************************************************************/
01957 
01967 state_status_t state_test(cache_entry_t        * pentry,
01968                           fsal_op_context_t    * pcontext,
01969                           exportlist_t         * pexport,
01970                           state_owner_t        * powner,
01971                           fsal_lock_param_t    * plock,
01972                           state_owner_t       ** holder,   /* owner that holds conflicting lock */
01973                           fsal_lock_param_t    * conflict, /* description of conflicting lock */
01974                           state_status_t       * pstatus)
01975 {
01976   state_lock_entry_t   * found_entry;
01977   cache_inode_status_t   cache_status;
01978 
01979   LogLock(COMPONENT_STATE, NIV_FULL_DEBUG,
01980           "TEST",
01981           pentry, pcontext, powner, plock);
01982 
01983   cache_status = cache_inode_inc_pin_ref(pentry);
01984 
01985   if(cache_status != CACHE_INODE_SUCCESS)
01986     {
01987       *pstatus = cache_inode_status_to_state_status(cache_status);
01988       LogDebug(COMPONENT_STATE,
01989                "Could not pin file");
01990       return *pstatus;
01991     }
01992 
01993   if(cache_inode_open(pentry, FSAL_O_RDWR, pcontext, 0, &cache_status) != CACHE_INODE_SUCCESS)
01994     {
01995       *pstatus = cache_inode_status_to_state_status(cache_status);
01996       LogFullDebug(COMPONENT_STATE,
01997                    "Could not open file");
01998 
01999       cache_inode_dec_pin_ref(pentry);
02000 
02001       return *pstatus;
02002     }
02003 
02004   pthread_rwlock_rdlock(&pentry->state_lock);
02005 
02006   found_entry = get_overlapping_entry(pentry, pcontext, powner, plock);
02007 
02008   if(found_entry != NULL)
02009     {
02010       /* found a conflicting lock, return it */
02011       LogEntry("Found conflict", found_entry);
02012       copy_conflict(found_entry, holder, conflict);
02013       *pstatus = STATE_LOCK_CONFLICT;
02014     }
02015   else
02016     {
02017       /* Prepare to make call to FSAL for this lock */
02018       *pstatus = do_lock_op(pentry,
02019                             pcontext,
02020                             pexport,
02021                             FSAL_OP_LOCKT,
02022                             powner,
02023                             plock,
02024                             holder,
02025                             conflict,
02026                             FALSE);
02027 
02028       if(*pstatus != STATE_SUCCESS &&
02029          *pstatus != STATE_LOCK_CONFLICT)
02030         {
02031           LogMajor(COMPONENT_STATE,
02032                    "Got error from FSAL lock operation, error=%s",
02033                    state_err_str(*pstatus));
02034         }
02035       if(*pstatus == STATE_SUCCESS)
02036         LogFullDebug(COMPONENT_STATE,
02037                      "No Conflict");
02038       else
02039         LogLock(COMPONENT_STATE, NIV_FULL_DEBUG,
02040                 "Conflict from FSAL",
02041                 pentry, pcontext, *holder, conflict);
02042     }
02043 
02044   if(isFullDebug(COMPONENT_STATE) && isFullDebug(COMPONENT_MEMLEAKS))
02045     LogList("Lock List", pentry, &pentry->object.file.lock_list);
02046 
02047   pthread_rwlock_unlock(&pentry->state_lock);
02048 
02049   cache_inode_dec_pin_ref(pentry);
02050 
02051   return *pstatus;
02052 }
02053 
02061 state_status_t state_lock(cache_entry_t         * pentry,
02062                           fsal_op_context_t     * pcontext,
02063                           exportlist_t          * pexport,
02064                           state_owner_t         * powner,
02065                           state_t               * pstate,
02066                           state_blocking_t        blocking,
02067                           state_block_data_t    * block_data,
02068                           fsal_lock_param_t     * plock,
02069                           state_owner_t        ** holder,   /* owner that holds conflicting lock */
02070                           fsal_lock_param_t     * conflict, /* description of conflicting lock */
02071                           state_status_t        * pstatus)
02072 {
02073   bool_t                 allow = TRUE, overlap = FALSE;
02074   struct glist_head    * glist;
02075   state_lock_entry_t   * found_entry;
02076   uint64_t               found_entry_end;
02077   uint64_t               plock_end = lock_end(plock);
02078   cache_inode_status_t   cache_status;
02079   fsal_staticfsinfo_t  * pstatic = pcontext->export_context->fe_static_fs_info;
02080   fsal_lock_op_t         lock_op;
02081 
02082   cache_status = cache_inode_inc_pin_ref(pentry);
02083 
02084   if(cache_status != CACHE_INODE_SUCCESS)
02085     {
02086       *pstatus = cache_inode_status_to_state_status(cache_status);
02087       LogDebug(COMPONENT_STATE,
02088                "Could not pin file");
02089       return *pstatus;
02090     }
02091 
02092   if(cache_inode_open(pentry, FSAL_O_RDWR, pcontext, 0, &cache_status) != CACHE_INODE_SUCCESS)
02093     {
02094       cache_inode_dec_pin_ref(pentry);
02095       *pstatus = cache_inode_status_to_state_status(cache_status);
02096       LogFullDebug(COMPONENT_STATE,
02097                    "Could not open file");
02098       return *pstatus;
02099     }
02100 
02101   pthread_rwlock_wrlock(&pentry->state_lock);
02102 
02103 #ifdef _USE_BLOCKING_LOCKS
02104 
02105   if(blocking != STATE_NON_BLOCKING)
02106     {
02107       /*
02108        * First search for a blocked request. Client can ignore the blocked
02109        * request and keep sending us new lock request again and again. So if
02110        * we have a mapping blocked request return that
02111        */
02112       glist_for_each(glist, &pentry->object.file.lock_list)
02113         {
02114           found_entry = glist_entry(glist, state_lock_entry_t, sle_list);
02115 
02116           if(different_owners(found_entry->sle_owner, powner))
02117             continue;
02118 
02119           /* Need to reject lock request if this lock owner already has a lock
02120            * on this file via a different export.
02121            */
02122           if(found_entry->sle_pexport != pexport)
02123             {
02124               pthread_rwlock_unlock(&pentry->state_lock);
02125 
02126               cache_inode_dec_pin_ref(pentry);
02127 
02128               LogEvent(COMPONENT_STATE,
02129                        "Lock Owner Export Conflict, Lock held for export %d (%s), request for export %d (%s)",
02130                        found_entry->sle_pexport->id,
02131                        found_entry->sle_pexport->fullpath,
02132                        pexport->id,
02133                        pexport->fullpath);
02134               LogEntry("Found lock entry belonging to another export", found_entry);
02135               *pstatus = STATE_INVALID_ARGUMENT;
02136               return *pstatus;
02137             }
02138 
02139           if(found_entry->sle_blocked != blocking)
02140             continue;
02141 
02142           if(different_lock(&found_entry->sle_lock, plock))
02143             continue;
02144 
02145           pthread_rwlock_unlock(&pentry->state_lock);
02146 
02147           cache_inode_dec_pin_ref(pentry);
02148 
02149           /*
02150            * We have matched all atribute of the existing lock.
02151            * Just return with blocked status. Client may be polling.
02152            */
02153           LogEntry("Found blocked", found_entry);
02154           *pstatus = STATE_LOCK_BLOCKED;
02155           return *pstatus;
02156         }
02157     }
02158 #endif
02159 
02160   glist_for_each(glist, &pentry->object.file.lock_list)
02161     {
02162       found_entry = glist_entry(glist, state_lock_entry_t, sle_list);
02163 
02164       /* Need to reject lock request if this lock owner already has a lock
02165        * on this file via a different export.
02166        */
02167       if(found_entry->sle_pexport != pexport &&
02168          !different_owners(found_entry->sle_owner, powner))
02169         {
02170           pthread_rwlock_unlock(&pentry->state_lock);
02171 
02172           cache_inode_dec_pin_ref(pentry);
02173 
02174           LogEvent(COMPONENT_STATE,
02175                    "Lock Owner Export Conflict, Lock held for export %d (%s), request for export %d (%s)",
02176                    found_entry->sle_pexport->id,
02177                    found_entry->sle_pexport->fullpath,
02178                    pexport->id,
02179                    pexport->fullpath);
02180 
02181           LogEntry("Found lock entry belonging to another export", found_entry);
02182 
02183           *pstatus = STATE_INVALID_ARGUMENT;
02184           return *pstatus;
02185         }
02186 
02187       /* Don't skip blocked locks for fairness */
02188 
02189       found_entry_end = lock_end(&found_entry->sle_lock);
02190 
02191       if((found_entry_end >= plock->lock_start) &&
02192          (found_entry->sle_lock.lock_start <= plock_end))
02193         {
02194           /* lock overlaps see if we can allow
02195            * allow if neither lock is exclusive or the owner is the same
02196            */
02197           if((found_entry->sle_lock.lock_type == FSAL_LOCK_W ||
02198               plock->lock_type == FSAL_LOCK_W) &&
02199              different_owners(found_entry->sle_owner, powner))
02200             {
02201               /* Found a conflicting lock, break out of loop.
02202                * Also indicate overlap hint.
02203                */
02204               LogEntry("Conflicts with", found_entry);
02205               LogList("Locks", pentry, &pentry->object.file.lock_list);
02206               copy_conflict(found_entry, holder, conflict);
02207               allow   = FALSE;
02208               overlap = TRUE;
02209               break;
02210             }
02211         }
02212 
02213       if(found_entry_end >= plock_end &&
02214          found_entry->sle_lock.lock_start <= plock->lock_start &&
02215          found_entry->sle_lock.lock_type == plock->lock_type &&
02216          (found_entry->sle_blocked == STATE_NON_BLOCKING ||
02217           found_entry->sle_blocked == STATE_GRANTING))
02218         {
02219           /* Found an entry that entirely overlaps the new entry
02220            * (and due to the preceding test does not prevent
02221            * granting this lock - therefore there can't be any
02222            * other locks that would prevent granting this lock
02223            */
02224           if(!different_owners(found_entry->sle_owner, powner))
02225             {
02226  #ifdef _USE_BLOCKING_LOCKS
02227              /* The lock actually has the same owner, we're done,
02228               * other than dealing with a lock in GRANTING state.
02229               */
02230               if(found_entry->sle_blocked == STATE_GRANTING)
02231                 {
02232                   /* Need to handle completion of granting of this lock
02233                    * because a GRANT was in progress.
02234                    * This could be a client retrying a blocked lock
02235                    * due to mis-trust of server. If the client
02236                    * also accepts the GRANT_MSG with a GRANT_RESP,
02237                    * that will be just fine.
02238                    */
02239                   grant_blocked_lock_immediate(pentry,
02240                                                pcontext,
02241                                                found_entry);
02242                 }
02243 #endif
02244               pthread_rwlock_unlock(&pentry->state_lock);
02245 
02246               cache_inode_dec_pin_ref(pentry);
02247 
02248               LogEntry("Found existing", found_entry);
02249 
02250               *pstatus = STATE_SUCCESS;
02251               return *pstatus;
02252             }
02253 
02254           /* Found a compatible lock with a different lock owner that
02255            * fully overlaps, set hint.
02256            */
02257           LogEntry("state_lock Found overlapping", found_entry);
02258           overlap = TRUE;
02259         }
02260     }
02261 
02262   /* Decide how to proceed */
02263   if(pstatic->lock_support_async_block && blocking == STATE_NLM_BLOCKING)
02264     {
02265       /* FSAL supports blocking locks, and this is an NLM blocking lock request,
02266        * request blocking lock from FSAL.
02267        */
02268       lock_op = FSAL_OP_LOCKB;
02269     }
02270   else if(allow || blocking == STATE_NLM_BLOCKING)
02271     {
02272       /* No conflict found in Ganesha, or NLM blocking lock when FSAL doesn't
02273        * support blocking locks. In either case, proceed with non-blocking
02274        * request to FSAL.
02275        */
02276       lock_op = FSAL_OP_LOCK;
02277     }
02278   else
02279     {
02280       /* Can't do async blocking lock in FSAL and have a conflict.
02281        * Return it.
02282        */
02283       pthread_rwlock_unlock(&pentry->state_lock);
02284 
02285       cache_inode_dec_pin_ref(pentry);
02286 
02287       *pstatus = STATE_LOCK_CONFLICT;
02288       return *pstatus;
02289     }
02290 
02291   /* We have already returned if:
02292    * + we have found an identical blocking lock
02293    * + we have found an entirely overlapping lock with the same lock owner
02294    * + this was not a supported blocking lock and we found a conflict
02295    *
02296    * So at this point, we are either going to do one of the following (all
02297    * descriptions below assume no problems occur):
02298    *
02299    * (1) FSAL supports async blocking locks, we know there is a conflict, and
02300    *     this is a supported blocking lock request
02301    *
02302    *     Make FSAL_OP_LOCKB call anyway, we will rely on FSAL to grant blocking
02303    *     locks. We will return the conflict we know about rather than what the
02304    *     FSAL returns. Insert blocking lock into queue.
02305    *
02306    * (2) FSAL supports async blocking locks, we don't know about any conflict,
02307    *     and this is a supported blocking lock request
02308    *
02309    *     Make FSAL_OP_LOCKB call, if it indicates block, insert blocking lock
02310    *     into queue, and return the conflict the FSAL indicates. If FSAL grants
02311    *     lock, then return granted lock and insert into lock list, otherwise
02312    *     insert blocking lock into queue.
02313    *
02314    * (3) FSAL doesn't support async blocking locks, this is a supported blocking
02315    *     lock and we know there is a conflict
02316    *
02317    *     Insert blocking lock into queue, we will grant lock when possible.
02318    *
02319    * (4) FSAL doesn't support async blocking locks and we don't know about any
02320    *     conflict
02321    *
02322    *     Make FSAL_OP_LOCK call, if it indicates conflict, return that. Even if
02323    *     this is a supported blocking lock call, there is no way to block. If
02324    *     lock is granted, return that and insert lock into list.
02325    *
02326    * (5) FSAL supports async blocking locks, we don't know about any conflict,
02327    *     and this is not a supported blocking lock request
02328    *
02329    *     Make FSAL_OP_LOCK call, if it indicates conflict, return that. If
02330    *     lock is granted, return that and insert lock into list.
02331    */
02332 
02333   /* Create the new lock entry.
02334    * Provisionally mark this lock as granted.
02335    */
02336   found_entry = create_state_lock_entry(pentry,
02337                                         pcontext,
02338                                         pexport,
02339                                         STATE_NON_BLOCKING,
02340                                         powner,
02341                                         pstate,
02342                                         plock);
02343   if(!found_entry)
02344     {
02345       pthread_rwlock_unlock(&pentry->state_lock);
02346 
02347       cache_inode_dec_pin_ref(pentry);
02348 
02349       *pstatus = STATE_MALLOC_ERROR;
02350       return *pstatus;
02351     }
02352 
02353   /* If no conflict in lock list, or FSAL supports async blocking locks,
02354    * make FSAL call. Don't ask for conflict if we know about a conflict.
02355    */
02356   if(allow || pstatic->lock_support_async_block)
02357     {
02358       /* Prepare to make call to FSAL for this lock */
02359       *pstatus = do_lock_op(pentry,
02360                             pcontext,
02361                             pexport,
02362                             lock_op,
02363                             powner,
02364                             plock,
02365                             allow ? holder : NULL,
02366                             allow ? conflict : NULL,
02367                             overlap);
02368     }
02369   else
02370     *pstatus = STATE_LOCK_BLOCKED;
02371 
02372   if(*pstatus == STATE_SUCCESS)
02373     {
02374       /* Merge any touching or overlapping locks into this one */
02375       LogEntry("FSAL lock acquired, merging locks for", found_entry);
02376 
02377       merge_lock_entry(pentry, pcontext, found_entry);
02378 
02379       /* Insert entry into lock list */
02380       LogEntry("New", found_entry);
02381 
02382       /* if the list is empty to start with; increment the pin ref count
02383        * before adding it to the list
02384        */
02385       if(glist_empty(&pentry->object.file.lock_list))
02386           cache_inode_inc_pin_ref(pentry);
02387 
02388       glist_add_tail(&pentry->object.file.lock_list, &found_entry->sle_list);
02389 
02390 #ifdef _USE_BLOCKING_LOCKS
02391       /* A lock downgrade could unblock blocked locks */
02392       grant_blocked_locks(pentry, pcontext);
02393 #endif
02394       /* Don't need to unpin, we know there is state on file. */
02395     }
02396   else if(*pstatus == STATE_LOCK_CONFLICT)
02397     {
02398       LogEntry("Conflict in FSAL for", found_entry);
02399 
02400       /* Discard lock entry */
02401       remove_from_locklist(found_entry);
02402     }
02403 #ifdef _USE_BLOCKING_LOCKS
02404   else if(*pstatus == STATE_LOCK_BLOCKED)
02405     {
02406       /* Mark entry as blocking and attach block_data */
02407       found_entry->sle_block_data = block_data;
02408       found_entry->sle_blocked    = blocking;
02409       block_data->sbd_lock_entry  = found_entry;
02410 
02411       /* Insert entry into lock list */
02412       LogEntry("FSAL block for", found_entry);
02413 
02414       /* if the list is empty to start with; increment the pin ref count
02415        * before adding it to the list
02416        */
02417       if(glist_empty(&pentry->object.file.lock_list))
02418           cache_inode_inc_pin_ref(pentry);
02419 
02420       glist_add_tail(&pentry->object.file.lock_list, &found_entry->sle_list);
02421 
02422       pthread_rwlock_unlock(&pentry->state_lock);
02423 
02424       cache_inode_dec_pin_ref(pentry);
02425 
02426       P(blocked_locks_mutex);
02427 
02428       glist_add_tail(&state_blocked_locks, &block_data->sbd_list);
02429 
02430       V(blocked_locks_mutex);
02431 
02432       return *pstatus;
02433     }
02434 #endif /* _USE_BLOCKING_LOCKS */
02435   else
02436     {
02437       LogMajor(COMPONENT_STATE,
02438                "Unable to lock FSAL, error=%s",
02439                state_err_str(*pstatus));
02440 
02441       /* Discard lock entry */
02442       remove_from_locklist(found_entry);
02443     }
02444 
02445   pthread_rwlock_unlock(&pentry->state_lock);
02446 
02447   cache_inode_dec_pin_ref(pentry);
02448 
02449   return *pstatus;
02450 }
02451 
02457 state_status_t state_unlock(cache_entry_t        * pentry,
02458                             fsal_op_context_t    * pcontext,
02459                             exportlist_t         * pexport,
02460                             state_owner_t        * powner,
02461                             state_t              * pstate,
02462                             fsal_lock_param_t    * plock,
02463                             state_status_t       * pstatus)
02464 {
02465   bool_t                 empty = FALSE;
02466   cache_inode_status_t   cache_status;
02467 
02468   cache_status = cache_inode_inc_pin_ref(pentry);
02469 
02470   if(cache_status != CACHE_INODE_SUCCESS)
02471     {
02472       *pstatus = cache_inode_status_to_state_status(cache_status);
02473       LogDebug(COMPONENT_STATE,
02474                "Could not pin file");
02475       return *pstatus;
02476     }
02477 
02478   if(pentry->type != REGULAR_FILE)
02479     {
02480       LogLock(COMPONENT_STATE, NIV_DEBUG,
02481               "Bad Unlock",
02482               pentry, pcontext, powner, plock);
02483       *pstatus = STATE_BAD_TYPE;
02484       return *pstatus;
02485     }
02486 
02487   /* We need to iterate over the full lock list and remove
02488    * any mapping entry. And sle_lock.lock_start = 0 and sle_lock.lock_length = 0 nlm_lock
02489    * implies remove all entries
02490    */
02491   pthread_rwlock_wrlock(&pentry->state_lock);
02492 
02493   /* If lock list is empty, there really isn't any work for us to do. */
02494   if(glist_empty(&pentry->object.file.lock_list))
02495     {
02496       pthread_rwlock_unlock(&pentry->state_lock);
02497 
02498       cache_inode_dec_pin_ref(pentry);
02499       LogDebug(COMPONENT_STATE,
02500                "Unlock success on file with no locks");
02501 
02502       *pstatus = STATE_SUCCESS;
02503       return *pstatus;
02504     }
02505 
02506   LogFullDebug(COMPONENT_STATE,
02507                "----------------------------------------------------------------------");
02508   LogLock(COMPONENT_STATE, NIV_FULL_DEBUG,
02509           "Subtracting",
02510           pentry, pcontext, powner, plock);
02511   LogFullDebug(COMPONENT_STATE,
02512                "----------------------------------------------------------------------");
02513 
02514 #ifdef _USE_BLOCKING_LOCKS
02515   /* First cancel any blocking locks that might overlap the unlocked range. */
02516   cancel_blocked_locks_range(pentry,
02517                              pcontext,
02518                              powner,
02519                              pstate,
02520                              plock);
02521 #endif
02522 
02523   /* Release the lock from cache inode lock list for pentry */
02524   subtract_lock_from_list(pentry,
02525                           pcontext,
02526                           powner,
02527                           pstate,
02528                           plock,
02529                           pstatus,
02530                           &pentry->object.file.lock_list);
02531 
02532   if(*pstatus != STATE_SUCCESS)
02533     {
02534       /* The unlock has not taken affect (other than canceling any blocking locks. */
02535       LogMajor(COMPONENT_STATE,
02536                "Unable to remove lock from list for unlock, error=%s",
02537                state_err_str(*pstatus));
02538 
02539       pthread_rwlock_unlock(&pentry->state_lock);
02540 
02541       cache_inode_dec_pin_ref(pentry);
02542 
02543       return *pstatus;
02544     }
02545 
02546   /* If the lock list has become zero; decrement the pin ref count pt placed */
02547   if(glist_empty(&pentry->object.file.lock_list))
02548       cache_inode_dec_pin_ref(pentry);
02549 
02550 
02551   /* Unlocking the entire region will remove any FSAL locks we held, whether
02552    * from fully granted locks, or from blocking locks that were in the process
02553    * of being granted.
02554    */
02555   *pstatus = do_lock_op(pentry,
02556                         pcontext,
02557                         pexport,
02558                         FSAL_OP_UNLOCK,
02559                         powner,
02560                         plock,
02561                         NULL,   /* no conflict expected */
02562                         NULL,
02563                         FALSE);
02564 
02565   if(*pstatus != STATE_SUCCESS)
02566     LogMajor(COMPONENT_STATE,
02567              "Unable to unlock FSAL, error=%s",
02568              state_err_str(*pstatus));
02569 
02570   LogFullDebug(COMPONENT_STATE,
02571                "----------------------------------------------------------------------");
02572   LogLock(COMPONENT_STATE, NIV_FULL_DEBUG,
02573           "Done", pentry, pcontext, powner, plock);
02574   LogFullDebug(COMPONENT_STATE,
02575                "----------------------------------------------------------------------");
02576 
02577   if(isFullDebug(COMPONENT_STATE) &&
02578      isFullDebug(COMPONENT_MEMLEAKS) &&
02579      plock->lock_start == 0 && plock->lock_length == 0)
02580     empty = LogList("Lock List", pentry, &pentry->object.file.lock_list);
02581 
02582 #ifdef _USE_BLOCKING_LOCKS
02583   grant_blocked_locks(pentry, pcontext);
02584 #endif
02585 
02586   pthread_rwlock_unlock(&pentry->state_lock);
02587 
02588   cache_inode_dec_pin_ref(pentry);
02589 
02590   if(isFullDebug(COMPONENT_STATE) &&
02591      isFullDebug(COMPONENT_MEMLEAKS) &&
02592      plock->lock_start == 0 && plock->lock_length == 0 &&
02593      empty)
02594     dump_all_locks("All locks (after unlock)");
02595 
02596   return *pstatus;
02597 }
02598 
02599 #ifdef _USE_BLOCKING_LOCKS
02600 
02606 state_status_t state_cancel(cache_entry_t        * pentry,
02607                             fsal_op_context_t    * pcontext,
02608                             exportlist_t         * pexport,
02609                             state_owner_t        * powner,
02610                             fsal_lock_param_t    * plock,
02611                             state_status_t       * pstatus)
02612 {
02613   struct glist_head    * glist;
02614   state_lock_entry_t   * found_entry;
02615   cache_inode_status_t   cache_status;
02616 
02617   if(pentry->type != REGULAR_FILE)
02618     {
02619       LogLock(COMPONENT_STATE, NIV_DEBUG,
02620               "Bad Cancel",
02621               pentry, pcontext, powner, plock);
02622       *pstatus = STATE_BAD_TYPE;
02623       return *pstatus;
02624     }
02625 
02626   *pstatus = STATE_NOT_FOUND;
02627 
02628   cache_status = cache_inode_inc_pin_ref(pentry);
02629 
02630   if(cache_status != CACHE_INODE_SUCCESS)
02631     {
02632       *pstatus = cache_inode_status_to_state_status(cache_status);
02633       LogDebug(COMPONENT_STATE,
02634                "Could not pin file");
02635       return *pstatus;
02636     }
02637 
02638   pthread_rwlock_wrlock(&pentry->state_lock);
02639 
02640   /* If lock list is empty, there really isn't any work for us to do. */
02641   if(glist_empty(&pentry->object.file.lock_list))
02642     {
02643       pthread_rwlock_unlock(&pentry->state_lock);
02644 
02645       cache_inode_dec_pin_ref(pentry);
02646       LogDebug(COMPONENT_STATE,
02647                "Cancel success on file with no locks");
02648 
02649       *pstatus = STATE_SUCCESS;
02650       return *pstatus;
02651     }
02652 
02653   glist_for_each(glist, &pentry->object.file.lock_list)
02654     {
02655       found_entry = glist_entry(glist, state_lock_entry_t, sle_list);
02656 
02657       if(different_owners(found_entry->sle_owner, powner))
02658         continue;
02659 
02660       /* Can not cancel a lock once it is granted */
02661       if(found_entry->sle_blocked == STATE_NON_BLOCKING)
02662         continue;
02663 
02664       if(different_lock(&found_entry->sle_lock, plock))
02665         continue;
02666 
02667       /* Cancel the blocked lock */
02668       *pstatus = cancel_blocked_lock(pentry, pcontext, found_entry);
02669 
02670       /* Check to see if we can grant any blocked locks. */
02671       grant_blocked_locks(pentry, pcontext);
02672 
02673       break;
02674     }
02675 
02676   /* If the lock list has become zero; decrement the pin ref count pt placed */
02677   if(glist_empty(&pentry->object.file.lock_list))
02678       cache_inode_dec_pin_ref(pentry);
02679 
02680   pthread_rwlock_unlock(&pentry->state_lock);
02681 
02682   cache_inode_dec_pin_ref(pentry);
02683 
02684   return *pstatus;
02685 }
02686 #endif
02687 
02688 #ifdef _USE_NLM
02689 
02697 state_status_t state_nlm_notify(state_nsm_client_t   * pnsmclient,
02698                                 state_t              * pstate,
02699                                 state_status_t       * pstatus)
02700 {
02701   state_owner_t      * powner;
02702   state_lock_entry_t * found_entry;
02703   exportlist_t       * pexport;
02704   fsal_lock_param_t    lock;
02705   cache_entry_t      * pentry;
02706   int                  errcnt = 0;
02707   struct glist_head    newlocks;
02708   fsal_op_context_t    fsal_context;
02709   fsal_status_t        fsal_status;
02710   state_nlm_share_t  * found_share;
02711 
02712   if(isFullDebug(COMPONENT_STATE))
02713     {
02714       char client[HASHTABLE_DISPLAY_STRLEN];
02715 
02716       display_nsm_client(pnsmclient, client);
02717 
02718       LogFullDebug(COMPONENT_STATE,
02719                    "state_nlm_notify for %s", client);
02720     }
02721 
02722   init_glist(&newlocks);
02723 
02724   /* First remove byte range locks.
02725    * Only accept so many errors before giving up.
02726    */
02727   while(errcnt < STATE_ERR_MAX)
02728     {
02729       P(pnsmclient->ssc_mutex);
02730 
02731       /* We just need to find any file this client has locks on.
02732        * We pick the first lock the client holds, and use it's file.
02733        */
02734       found_entry = glist_first_entry(&pnsmclient->ssc_lock_list,
02735                                       state_lock_entry_t,
02736                                       sle_client_locks);
02737 
02738       /* If we don't find any entries, then we are done. */
02739       if(found_entry == NULL)
02740         {
02741           V(pnsmclient->ssc_mutex);
02742           break;
02743         }
02744 
02745       /* Get a reference so the lock entry will still be valid when we release the ssc_mutex */
02746       lock_entry_inc_ref(found_entry);
02747 
02748       /* Remove from the client lock list */
02749       glist_del(&found_entry->sle_client_locks);
02750 
02751       if(found_entry->sle_state == pstate)
02752         {
02753           /* This is a new lock acquired since the client rebooted, retain it. */
02754           LogEntry("Don't release new lock", found_entry);
02755           glist_add_tail(&newlocks, &found_entry->sle_client_locks);
02756           V(pnsmclient->ssc_mutex);
02757           continue;
02758         }
02759 
02760       LogEntry("Release client locks based on", found_entry);
02761 
02762       /* Move this entry to the end of the list (this will help if errors occur) */
02763       glist_add_tail(&pnsmclient->ssc_lock_list, &found_entry->sle_client_locks);
02764 
02765       V(pnsmclient->ssc_mutex);
02766 
02767       /* Extract the cache inode entry from the lock entry and release the lock entry */
02768       pentry  = found_entry->sle_pentry;
02769       powner  = found_entry->sle_owner;
02770       pexport = found_entry->sle_pexport;
02771 
02772       pthread_rwlock_wrlock(&pentry->state_lock);
02773 
02774       lock_entry_dec_ref(found_entry);
02775 
02776       pthread_rwlock_unlock(&pentry->state_lock);
02777 
02778       /* Make lock that covers the whole file - type doesn't matter for unlock */
02779       lock.lock_type   = FSAL_LOCK_R;
02780       lock.lock_start  = 0;
02781       lock.lock_length = 0;
02782 
02783       /* construct the fsal context based on the export and root credential */
02784       fsal_status = FSAL_GetClientContext(&fsal_context,
02785                                           &pexport->FS_export_context,
02786                                           0,
02787                                           0,
02788                                           NULL,
02789                                           0);
02790       if(FSAL_IS_ERROR(fsal_status))
02791         {
02792           /* log error here , and continue? */
02793           LogDebug(COMPONENT_STATE,
02794                    "FSAL_GetClientConext failed");
02795           continue;
02796         }
02797 
02798       /* Make sure we hold an lru ref to the cache inode while calling unlock */
02799       if(cache_inode_lru_ref(pentry, 0) != CACHE_INODE_SUCCESS)
02800         LogCrit(COMPONENT_STATE,
02801                 "Ugliness - cache_inode_lru_ref has returned non-success");
02802 
02803       /* Remove all locks held by this NLM Client on the file */
02804       if(state_unlock(pentry,
02805                       &fsal_context,
02806                       pexport,
02807                       powner,
02808                       pstate,
02809                       &lock,
02810                       pstatus) != STATE_SUCCESS)
02811         {
02812           /* Increment the error count and try the next lock, with any luck
02813            * the memory pressure which is causing the problem will resolve itself.
02814            */
02815           LogFullDebug(COMPONENT_STATE,
02816                        "state_unlock returned %s",
02817                        state_err_str(*pstatus));
02818           errcnt++;
02819         }
02820 
02821       /* Release the lru ref to the cache inode we held while calling unlock */
02822       cache_inode_lru_unref(pentry, 0);
02823     }
02824 
02825   /* Now remove NLM_SHARE reservations.
02826    * Only accept so many errors before giving up.
02827    */
02828   while(errcnt < STATE_ERR_MAX)
02829     {
02830       P(pnsmclient->ssc_mutex);
02831 
02832       /* We just need to find any file this client has locks on.
02833        * We pick the first lock the client holds, and use it's file.
02834        */
02835       found_share = glist_first_entry(&pnsmclient->ssc_share_list,
02836                                       state_nlm_share_t,
02837                                       sns_share_per_client);
02838 
02839       /* If we don't find any entries, then we are done. */
02840       if(found_share == NULL)
02841         {
02842           V(pnsmclient->ssc_mutex);
02843           break;
02844         }
02845 
02846       /* Extract the cache inode entry from the share */
02847       pentry  = found_share->sns_pentry;
02848       powner  = found_share->sns_powner;
02849       pexport = found_share->sns_pexport;
02850 
02851       /* get a reference to the owner */
02853 #ifdef FSF
02854       inc_state_owner_ref_locked(powner);
02855 #endif
02856 
02857       V(pnsmclient->ssc_mutex);
02858 
02859       /* construct the fsal context based on the export and root credential */
02860       fsal_status = FSAL_GetClientContext(&fsal_context,
02861                                           &pexport->FS_export_context,
02862                                           0,
02863                                           0,
02864                                           NULL,
02865                                           0);
02866       if(FSAL_IS_ERROR(fsal_status))
02867         {
02868 #ifdef FSF
02869           dec_state_owner_ref_locked(powner);
02870 #endif
02871 
02872           /* log error here , and continue? */
02873           LogDebug(COMPONENT_STATE,
02874                    "FSAL_GetClientConext failed");
02875           continue;
02876         }
02877 
02878       /* Remove all shares held by this NSM Client and Owner on the file */
02879       if(state_nlm_unshare(pentry,
02880                            &fsal_context,
02881                            OPEN4_SHARE_ACCESS_NONE,
02882                            OPEN4_SHARE_DENY_NONE,
02883                            powner,
02884                            pstatus) != STATE_SUCCESS)
02885         {
02886           /* Increment the error count and try the next share, with any luck
02887            * the memory pressure which is causing the problem will resolve itself.
02888            */
02889           LogFullDebug(COMPONENT_STATE,
02890                        "state_nlm_unshare returned %s",
02891                        state_err_str(*pstatus));
02892           errcnt++;
02893         }
02894 
02895 #ifdef FSF
02896       dec_state_owner_ref_locked(powner);
02897 #endif
02898     }
02899 
02900   /* Put locks from current client incarnation onto end of list */
02901   P(pnsmclient->ssc_mutex);
02902   glist_add_list_tail(&pnsmclient->ssc_lock_list, &newlocks);
02903   V(pnsmclient->ssc_mutex);
02904   LogFullDebug(COMPONENT_STATE, "DONE");
02905 
02906   return *pstatus;
02907 }
02908 #endif
02909 
02915 state_status_t state_owner_unlock_all(fsal_op_context_t    * pcontext,
02916                                       state_owner_t        * powner,
02917                                       state_t              * pstate,
02918                                       state_status_t       * pstatus)
02919 {
02920   state_lock_entry_t * found_entry;
02921   exportlist_t       * pexport;
02922   fsal_lock_param_t    lock;
02923   cache_entry_t      * pentry;
02924   int                  errcnt = 0;
02925 
02926   /* Only accept so many errors before giving up. */
02927   while(errcnt < STATE_ERR_MAX)
02928     {
02929       P(powner->so_mutex);
02930 
02931       /* We just need to find any file this owner has locks on.
02932        * We pick the first lock the owner holds, and use it's file.
02933        */
02934       found_entry = glist_first_entry(&powner->so_lock_list, state_lock_entry_t, sle_owner_locks);
02935 
02936       /* If we don't find any entries, then we are done. */
02937       if((found_entry == NULL) || (found_entry->sle_state != pstate))
02938       {
02939         V(powner->so_mutex);
02940         break;
02941       }
02942 
02943       lock_entry_inc_ref(found_entry);
02944 
02945       /* Move this entry to the end of the list (this will help if errors occur) */
02946       glist_del(&found_entry->sle_owner_locks);
02947       glist_add_tail(&powner->so_lock_list, &found_entry->sle_owner_locks);
02948 
02949       V(powner->so_mutex);
02950 
02951       /* Extract the cache inode entry from the lock entry and release the lock entry */
02952       pentry  = found_entry->sle_pentry;
02953       pexport = found_entry->sle_pexport;
02954 
02955       pthread_rwlock_wrlock(&pentry->state_lock);
02956 
02957       lock_entry_dec_ref(found_entry);
02958 
02959       pthread_rwlock_unlock(&pentry->state_lock);
02960 
02961       /* Make lock that covers the whole file - type doesn't matter for unlock */
02962       lock.lock_type   = FSAL_LOCK_R;
02963       lock.lock_start  = 0;
02964       lock.lock_length = 0;
02965 
02966       /* Make sure we hold an lru ref to the cache inode while calling unlock */
02967       if(cache_inode_lru_ref(pentry, 0) != CACHE_INODE_SUCCESS)
02968         LogCrit(COMPONENT_STATE,
02969                 "Ugliness - cache_inode_lru_ref has returned non-success");
02970 
02971       /* Remove all locks held by this owner on the file */
02972       if(state_unlock(pentry,
02973                       pcontext,
02974                       pexport,
02975                       powner,
02976                       pstate,
02977                       &lock,
02978                       pstatus) != STATE_SUCCESS)
02979         {
02980           /* Increment the error count and try the next lock, with any luck
02981            * the memory pressure which is causing the problem will resolve itself.
02982            */
02983           LogDebug(COMPONENT_STATE,
02984                "state_unlock failed %s",
02985                state_err_str(*pstatus));
02986           errcnt++;
02987         }
02988 
02989       /* Release the lru ref to the cache inode we held while calling unlock */
02990       cache_inode_lru_unref(pentry, 0);
02991     }
02992   return *pstatus;
02993 }
02994 
02995 #ifdef _USE_BLOCKING_LOCKS
02996 
02997 void find_blocked_lock_upcall(cache_entry_t        * pentry,
02998                               void                 * powner,
02999                               fsal_lock_param_t    * plock,
03000                               state_grant_type_t     grant_type)
03001 {
03002   state_lock_entry_t   * found_entry;
03003   struct glist_head    * glist;
03004   state_block_data_t   * pblock;
03005 
03006   P(blocked_locks_mutex);
03007 
03008   glist_for_each(glist, &state_blocked_locks)
03009     {
03010       pblock = glist_entry(glist, state_block_data_t, sbd_list);
03011 
03012       found_entry = pblock->sbd_lock_entry;
03013 
03014       /* Check if for same file */
03015       if(found_entry->sle_pentry != pentry)
03016         continue;
03017 
03018       /* Check if for same owner */
03019       if(found_entry->sle_owner != powner)
03020         continue;
03021 
03022       /* Check if same lock */
03023       if(different_lock(&found_entry->sle_lock, plock))
03024         continue;
03025 
03026       /* Put lock on list of locks granted by FSAL */
03027       glist_del(&pblock->sbd_list);
03028       glist_add_tail(&state_notified_locks, &pblock->sbd_list);
03029       pblock->sbd_grant_type = grant_type;
03030 
03031       LogEntry("Blocked Lock found", found_entry);
03032 
03033       V(blocked_locks_mutex);
03034 
03035       signal_async_work();
03036 
03037       return;
03038     } /* glist_for_each_safe */
03039 
03040   if(isFullDebug(COMPONENT_STATE) &&
03041      isFullDebug(COMPONENT_MEMLEAKS))
03042     LogBlockedList("Blocked Lock List", NULL, &state_blocked_locks);
03043 
03044   V(blocked_locks_mutex);
03045 
03046   if(isFullDebug(COMPONENT_STATE) &&
03047      isFullDebug(COMPONENT_MEMLEAKS))
03048     {
03049       pthread_rwlock_rdlock(&pentry->state_lock);
03050 
03051       LogList("File Lock List", pentry, &pentry->object.file.lock_list);
03052 
03053       pthread_rwlock_unlock(&pentry->state_lock);
03054     }
03055 
03056   /* We must be out of sync with FSAL, this is fatal */
03057   LogLockDesc(COMPONENT_STATE, NIV_MAJOR,
03058               "Blocked Lock Not Found for", pentry, powner, plock);
03059   LogFatal(COMPONENT_STATE, "Locks out of sync with FSAL");
03060 }
03061 
03067 void grant_blocked_lock_upcall(cache_entry_t        * pentry,
03068                                void                 * powner,
03069                                fsal_lock_param_t    * plock)
03070 {
03071   LogLockDesc(COMPONENT_STATE, NIV_DEBUG,
03072               "Grant Upcall for", pentry, powner, plock);
03073 
03074   find_blocked_lock_upcall(pentry, powner, plock, STATE_GRANT_FSAL);
03075 }
03076 
03082 void available_blocked_lock_upcall(cache_entry_t        * pentry,
03083                                    void                 * powner,
03084                                    fsal_lock_param_t    * plock)
03085 {
03086   LogLockDesc(COMPONENT_STATE, NIV_DEBUG,
03087               "Available Upcall for", pentry, powner, plock);
03088 
03089   find_blocked_lock_upcall(pentry, powner, plock, STATE_GRANT_FSAL_AVAILABLE);
03090 }
03091 
03092 #endif
03093 
03094 void state_lock_wipe(cache_entry_t        * pentry)
03095 {
03096   if(glist_empty(&pentry->object.file.lock_list))
03097     return;
03098 
03099   free_list(&pentry->object.file.lock_list);
03100 
03101   cache_inode_dec_pin_ref(pentry);
03102 }