nfs-ganesha 1.4

state_share.c

Go to the documentation of this file.
00001 /*
00002  * vim:expandtab:shiftwidth=8:tabstop=8:
00003  *
00004  * Copyright CEA/DAM/DIF  (2008)
00005  * contributeur : Philippe DENIEL   philippe.deniel@cea.fr
00006  *                Thomas LEIBOVICI  thomas.leibovici@cea.fr
00007  *
00008  *
00009  * This program is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public
00011  * License as published by the Free Software Foundation; either
00012  * version 3 of the License, or (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * Lesser General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU Lesser General Public
00020  * License along with this library; if not, write to the Free Software
00021  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00022  *
00023  * ---------------------------------------
00024  */
00025 
00037 #ifdef HAVE_CONFIG_H
00038 #include "config.h"
00039 #endif
00040 
00041 #ifdef _SOLARIS
00042 #include "solaris_port.h"
00043 #endif                          /* _SOLARIS */
00044 
00045 #include <unistd.h>
00046 #include <sys/types.h>
00047 #include <sys/param.h>
00048 #include <time.h>
00049 #include <pthread.h>
00050 #include <string.h>
00051 #include <assert.h>
00052 
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 /* Update the ref counter of share state of given file. */
00063 static void state_share_update_counter(cache_entry_t * pentry,
00064                                        int old_access,
00065                                        int old_deny,
00066                                        int new_access,
00067                                        int new_deny,
00068                                        bool_t v4);
00069 
00070 /* Calculate the union of share access of given file. */
00071 static unsigned int state_share_get_share_access(cache_entry_t * pentry);
00072 
00073 /* Calculate the union of share deny of given file. */
00074 static unsigned int state_share_get_share_deny(cache_entry_t * pentry);
00075 
00076 /* Push share state down to FSAL. Only the union of share states should be
00077  * passed to this function.
00078  */
00079 static state_status_t do_share_op(cache_entry_t        * pentry,
00080                                   fsal_op_context_t    * pcontext,
00081                                   state_owner_t        * powner,
00082                                   fsal_share_param_t   * pshare)
00083 {
00084   fsal_status_t fsal_status;
00085   state_status_t status = STATE_SUCCESS;
00086   fsal_staticfsinfo_t * pstatic = pcontext->export_context->fe_static_fs_info;
00087 
00088   /* Quick exit if share reservation is not supported by FSAL */
00089   if(!pstatic->share_support)
00090     return STATE_SUCCESS;
00091 
00092   fsal_status = FSAL_share_op(cache_inode_fd(pentry),
00093                               &pentry->handle,
00094                               pcontext,
00095                               NULL,
00096                               *pshare);
00097 
00098   status = state_error_convert(fsal_status);
00099 
00100   LogFullDebug(COMPONENT_STATE,
00101                "FSAL_share_op returned %s",
00102                state_err_str(status));
00103 
00104   return status;
00105 }
00106 
00107 /* This is called when new share state is added. The state lock MUST
00108    be held. */
00109 state_status_t state_share_add(cache_entry_t         * pentry,
00110                                fsal_op_context_t     * pcontext,
00111                                state_owner_t         * powner,
00112                                state_t               * pstate,  /* state that holds share bits to be added */
00113                                state_status_t        * pstatus)
00114 {
00115   state_status_t status = STATE_SUCCESS;
00116   unsigned int            old_pentry_share_access = 0;
00117   unsigned int            old_pentry_share_deny = 0;
00118   unsigned int            new_pentry_share_access = 0;
00119   unsigned int            new_pentry_share_deny = 0;
00120   unsigned int            new_share_access = 0;
00121   unsigned int            new_share_deny = 0;
00122   fsal_share_param_t      share_param;
00123 
00124   /* Check if new share state has conflicts. */
00125   status = state_share_check_conflict(pentry,
00126                                       pstate->state_data.share.share_access,
00127                                       pstate->state_data.share.share_deny,
00128                                       pstatus);
00129   if(status != STATE_SUCCESS)
00130     {
00131       LogEvent(COMPONENT_STATE, "Share conflicts detected during add");
00132       *pstatus = STATE_STATE_CONFLICT;
00133       return *pstatus;
00134     }
00135 
00136   /* Get the current union of share states of this file. */
00137   old_pentry_share_access = state_share_get_share_access(pentry);
00138   old_pentry_share_deny = state_share_get_share_deny(pentry);
00139 
00140   /* Share state to be added. */
00141   new_share_access = pstate->state_data.share.share_access;
00142   new_share_deny = pstate->state_data.share.share_deny;
00143 
00144   /* Update the ref counted share state of this file. */
00145   state_share_update_counter(pentry,
00146                              OPEN4_SHARE_ACCESS_NONE,
00147                              OPEN4_SHARE_DENY_NONE,
00148                              new_share_access,
00149                              new_share_deny,
00150                              TRUE);
00151 
00152   /* Get the updated union of share states of this file. */
00153   new_pentry_share_access = state_share_get_share_access(pentry);
00154   new_pentry_share_deny = state_share_get_share_deny(pentry);
00155 
00156   /* If this file's share bits are different from the supposed value, update
00157    * it.
00158    */
00159   if((new_pentry_share_access != old_pentry_share_access) ||
00160      (new_pentry_share_deny != old_pentry_share_deny))
00161     {
00162       /* Try to push to FSAL. */
00163       share_param.share_access = new_pentry_share_access;
00164       share_param.share_deny = new_pentry_share_deny;
00165 
00166       status = do_share_op(pentry, pcontext, powner, &share_param);
00167       if(status != STATE_SUCCESS)
00168         {
00169           /* Revert the ref counted share state of this file. */
00170           state_share_update_counter(pentry,
00171                                      new_share_access,
00172                                      new_share_deny,
00173                                      OPEN4_SHARE_ACCESS_NONE,
00174                                      OPEN4_SHARE_DENY_NONE,
00175                                      TRUE);
00176           LogDebug(COMPONENT_STATE, "do_share_op failed");
00177           *pstatus = status;
00178           return *pstatus;
00179         }
00180     }
00181 
00182   LogFullDebug(COMPONENT_STATE, "pstate %p: added share_access %u, "
00183                "share_deny %u",
00184                pstate, new_share_access, new_share_deny);
00185 
00186   /* Update previously seen share state in the bitmap. */
00187   state_share_set_prev(pstate, &(pstate->state_data));
00188 
00189   return status;
00190 }
00191 
00192 /* This is called when a share state is removed.  The state lock MUST
00193    be held. */
00194 state_status_t state_share_remove(cache_entry_t         * pentry,
00195                                   fsal_op_context_t     * pcontext,
00196                                   state_owner_t         * powner,
00197                                   state_t               * pstate,  /* state that holds share bits to be removed */
00198                                   state_status_t        * pstatus)
00199 {
00200   state_status_t status = STATE_SUCCESS;
00201   unsigned int            old_pentry_share_access = 0;
00202   unsigned int            old_pentry_share_deny = 0;
00203   unsigned int            new_pentry_share_access = 0;
00204   unsigned int            new_pentry_share_deny = 0;
00205   unsigned int            removed_share_access = 0;
00206   unsigned int            removed_share_deny = 0;
00207   fsal_share_param_t      share_param;
00208 
00209   /* Get the current union of share states of this file. */
00210   old_pentry_share_access = state_share_get_share_access(pentry);
00211   old_pentry_share_deny = state_share_get_share_deny(pentry);
00212 
00213   /* Share state to be removed. */
00214   removed_share_access = pstate->state_data.share.share_access;
00215   removed_share_deny = pstate->state_data.share.share_deny;
00216 
00217   /* Update the ref counted share state of this file. */
00218   state_share_update_counter(pentry,
00219                              removed_share_access,
00220                              removed_share_deny,
00221                              OPEN4_SHARE_ACCESS_NONE,
00222                              OPEN4_SHARE_DENY_NONE,
00223                              TRUE);
00224 
00225   /* Get the updated union of share states of this file. */
00226   new_pentry_share_access = state_share_get_share_access(pentry);
00227   new_pentry_share_deny = state_share_get_share_deny(pentry);
00228 
00229   /* If this file's share bits are different from the supposed value, update
00230    * it.
00231    */
00232   if((new_pentry_share_access != old_pentry_share_access) ||
00233      (new_pentry_share_deny != old_pentry_share_deny))
00234     {
00235       /* Try to push to FSAL. */
00236       share_param.share_access = new_pentry_share_access;
00237       share_param.share_deny = new_pentry_share_deny;
00238 
00239       status = do_share_op(pentry, pcontext, powner, &share_param);
00240       if(status != STATE_SUCCESS)
00241         {
00242           /* Revert the ref counted share state of this file. */
00243           state_share_update_counter(pentry,
00244                                      OPEN4_SHARE_ACCESS_NONE,
00245                                      OPEN4_SHARE_DENY_NONE,
00246                                      removed_share_access,
00247                                      removed_share_deny,
00248                                      TRUE);
00249           LogDebug(COMPONENT_STATE, "do_share_op failed");
00250           *pstatus = status;
00251           return *pstatus;
00252         }
00253     }
00254 
00255   LogFullDebug(COMPONENT_STATE, "pstate %p: removed share_access %u, "
00256                "share_deny %u",
00257                pstate,
00258                removed_share_access,
00259                removed_share_deny);
00260 
00261   return status;
00262 }
00263 
00264 /* This is called when share state is upgraded during open.  The
00265    state ock MUST be held. */
00266 state_status_t state_share_upgrade(cache_entry_t         * pentry,
00267                                    fsal_op_context_t     * pcontext,
00268                                    state_data_t          * pstate_data, /* new share bits */
00269                                    state_owner_t         * powner,
00270                                    state_t               * pstate,      /* state that holds current share bits */
00271                                    state_status_t        * pstatus)
00272 {
00273   state_status_t status = STATE_SUCCESS;
00274   unsigned int            old_pentry_share_access = 0;
00275   unsigned int            old_pentry_share_deny = 0;
00276   unsigned int            new_pentry_share_access = 0;
00277   unsigned int            new_pentry_share_deny = 0;
00278   unsigned int            old_share_access = 0;
00279   unsigned int            old_share_deny = 0;
00280   unsigned int            new_share_access = 0;
00281   unsigned int            new_share_deny = 0;
00282   fsal_share_param_t share_param;
00283 
00284   /* Check if new share state has conflicts. */
00285   status = state_share_check_conflict(pentry,
00286                                       pstate_data->share.share_access,
00287                                       pstate_data->share.share_deny,
00288                                       pstatus);
00289   if(status != STATE_SUCCESS)
00290     {
00291       LogEvent(COMPONENT_STATE, "Share conflicts detected during upgrade");
00292       *pstatus = STATE_STATE_CONFLICT;
00293       return *pstatus;
00294     }
00295 
00296   /* Get the current union of share states of this file. */
00297   old_pentry_share_access = state_share_get_share_access(pentry);
00298   old_pentry_share_deny = state_share_get_share_deny(pentry);
00299 
00300   /* Old share state. */
00301   old_share_access = pstate->state_data.share.share_access;
00302   old_share_deny = pstate->state_data.share.share_deny;
00303 
00304   /* New share state. */
00305   new_share_access = pstate_data->share.share_access;
00306   new_share_deny = pstate_data->share.share_deny;
00307 
00308   /* Update the ref counted share state of this file. */
00309   state_share_update_counter(pentry,
00310                              old_share_access,
00311                              old_share_deny,
00312                              new_share_access,
00313                              new_share_deny,
00314                              TRUE);
00315 
00316   /* Get the updated union of share states of this file. */
00317   new_pentry_share_access = state_share_get_share_access(pentry);
00318   new_pentry_share_deny = state_share_get_share_deny(pentry);
00319 
00320   /* If this file's share bits are different from the supposed value, update
00321    * it.
00322    */
00323   if((new_pentry_share_access != old_pentry_share_access) ||
00324      (new_pentry_share_deny != old_pentry_share_deny))
00325     {
00326       /* Try to push to FSAL. */
00327       share_param.share_access = new_pentry_share_access;
00328       share_param.share_deny = new_pentry_share_deny;
00329 
00330       status = do_share_op(pentry, pcontext, powner, &share_param);
00331       if(status != STATE_SUCCESS)
00332         {
00333           /* Revert the ref counted share state of this file. */
00334           state_share_update_counter(pentry,
00335                                      new_share_access,
00336                                      new_share_deny,
00337                                      old_share_access,
00338                                      old_share_deny,
00339                                      TRUE);
00340           LogDebug(COMPONENT_STATE, "do_share_op failed");
00341           *pstatus = status;
00342           return *pstatus;
00343         }
00344     }
00345 
00346   /* Update share state. */
00347   pstate->state_data.share.share_access = new_share_access;
00348   pstate->state_data.share.share_deny = new_share_deny;
00349   LogFullDebug(COMPONENT_STATE, "pstate %p: upgraded share_access %u, share_deny %u",
00350                pstate,
00351                pstate->state_data.share.share_access,
00352                pstate->state_data.share.share_deny);
00353 
00354   /* Update previously seen share state. */
00355   state_share_set_prev(pstate, pstate_data);
00356 
00357   return status;
00358 }
00359 
00360 /* This is called when share is downgraded via open_downgrade op.
00361    The state lock MUST be held. */
00362 state_status_t state_share_downgrade(cache_entry_t         * pentry,
00363                                      fsal_op_context_t     * pcontext,
00364                                      state_data_t          * pstate_data, /* new share bits */
00365                                      state_owner_t         * powner,
00366                                      state_t               * pstate,      /* state that holds current share bits */
00367                                      state_status_t        * pstatus)
00368 {
00369   state_status_t status = STATE_SUCCESS;
00370   unsigned int            old_pentry_share_access = 0;
00371   unsigned int            old_pentry_share_deny = 0;
00372   unsigned int            new_pentry_share_access = 0;
00373   unsigned int            new_pentry_share_deny = 0;
00374   unsigned int            old_share_access = 0;
00375   unsigned int            old_share_deny = 0;
00376   unsigned int            new_share_access = 0;
00377   unsigned int            new_share_deny = 0;
00378   fsal_share_param_t      share_param;
00379 
00380   /* Get the current union of share states of this file. */
00381   old_pentry_share_access = state_share_get_share_access(pentry);
00382   old_pentry_share_deny = state_share_get_share_deny(pentry);
00383 
00384   /* Old share state. */
00385   old_share_access = pstate->state_data.share.share_access;
00386   old_share_deny = pstate->state_data.share.share_deny;
00387 
00388   /* New share state. */
00389   new_share_access = pstate_data->share.share_access;
00390   new_share_deny = pstate_data->share.share_deny;
00391 
00392   /* Update the ref counted share state of this file. */
00393   state_share_update_counter(pentry,
00394                              old_share_access,
00395                              old_share_deny,
00396                              new_share_access,
00397                              new_share_deny,
00398                              TRUE);
00399 
00400   /* Get the updated union of share states of this file. */
00401   new_pentry_share_access = state_share_get_share_access(pentry);
00402   new_pentry_share_deny = state_share_get_share_deny(pentry);
00403 
00404   /* If this file's share bits are different from the supposed value, update
00405    * it.
00406    */
00407   if((new_pentry_share_access != old_pentry_share_access) ||
00408      (new_pentry_share_deny != old_pentry_share_deny))
00409     {
00410       /* Try to push to FSAL. */
00411       share_param.share_access = new_pentry_share_access;
00412       share_param.share_deny = new_pentry_share_deny;
00413 
00414       status = do_share_op(pentry, pcontext, powner, &share_param);
00415       if(status != STATE_SUCCESS)
00416         {
00417           /* Revert the ref counted share state of this file. */
00418           state_share_update_counter(pentry,
00419                                      new_share_access,
00420                                      new_share_deny,
00421                                      old_share_access,
00422                                      old_share_deny,
00423                                      TRUE);
00424           LogDebug(COMPONENT_STATE, "do_share_op failed");
00425           *pstatus = status;
00426           return *pstatus;
00427         }
00428     }
00429 
00430   /* Update share state. */
00431   pstate->state_data.share.share_access = new_share_access;
00432   pstate->state_data.share.share_deny   = new_share_deny;
00433   LogFullDebug(COMPONENT_STATE, "pstate %p: downgraded share_access %u, "
00434                "share_deny %u",
00435                pstate,
00436                pstate->state_data.share.share_access,
00437                pstate->state_data.share.share_deny);
00438 
00439   return status;
00440 }
00441 
00442 /* Update the bitmap of previously seen share access and deny bits for the
00443  * given state.
00444  */
00445 state_status_t state_share_set_prev(state_t      * pstate,
00446                                     state_data_t * pstate_data)
00447 {
00448   state_status_t status = STATE_SUCCESS;
00449 
00450   pstate->state_data.share.share_access_prev |=
00451     (1 << pstate_data->share.share_access);
00452 
00453   pstate->state_data.share.share_deny_prev |=
00454     (1 << pstate_data->share.share_deny);
00455 
00456   return status;
00457 }
00458 
00459 /* Check if the given state has seen the given share access and deny bits
00460  * before. This is needed when we check validity of open downgrade.
00461  */
00462 state_status_t state_share_check_prev(state_t      * pstate,
00463                                     state_data_t * pstate_data)
00464 {
00465   state_status_t status = STATE_SUCCESS;
00466 
00467   if((pstate->state_data.share.share_access_prev &
00468      (1 << pstate_data->share.share_access)) == 0)
00469     return STATE_STATE_ERROR;
00470 
00471   if((pstate->state_data.share.share_deny_prev &
00472      (1 << pstate_data->share.share_deny)) == 0)
00473     return STATE_STATE_ERROR;
00474 
00475   return status;
00476 }
00477 
00478 /* Check if the given share access and deny bits have conflict.  The
00479    state lock MUST be held. */
00480 state_status_t state_share_check_conflict(cache_entry_t  * pentry,
00481                                           int              share_acccess,
00482                                           int              share_deny,
00483                                           state_status_t * pstatus)
00484 {
00485   char * cause = "";
00486 
00487   if((share_acccess & OPEN4_SHARE_ACCESS_READ) != 0 &&
00488      pentry->object.file.share_state.share_deny_read > 0)
00489     {
00490       cause = "access read denied by existing deny read";
00491       goto out_conflict;
00492     }
00493 
00494   if((share_acccess & OPEN4_SHARE_ACCESS_WRITE) != 0 &&
00495      pentry->object.file.share_state.share_deny_write > 0)
00496     {
00497       cause = "access write denied by existing deny write";
00498       goto out_conflict;
00499     }
00500 
00501   if((share_deny & OPEN4_SHARE_DENY_READ) != 0 &&
00502      pentry->object.file.share_state.share_access_read > 0)
00503     {
00504       cause = "deny read denied by existing access read";
00505       goto out_conflict;
00506     }
00507 
00508   if((share_deny & OPEN4_SHARE_DENY_WRITE) != 0 &&
00509      pentry->object.file.share_state.share_access_write > 0)
00510     {
00511       cause = "deny write denied by existing access write";
00512       goto out_conflict;
00513     }
00514 
00515   *pstatus = STATE_SUCCESS;
00516   return *pstatus;
00517 
00518 out_conflict:
00519 
00520   LogDebug(COMPONENT_STATE, "Share conflict detected: %s", cause);
00521   *pstatus = STATE_STATE_CONFLICT;
00522   return *pstatus;
00523 }
00524 
00525 /* Update the ref counter of share state. This function should be called with
00526  * the state lock held
00527  */
00528 static void state_share_update_counter(cache_entry_t * pentry,
00529                                        int old_access,
00530                                        int old_deny,
00531                                        int new_access,
00532                                        int new_deny,
00533                                        bool_t v4)
00534 {
00535   int access_read_inc  = ((new_access & OPEN4_SHARE_ACCESS_READ) != 0) - ((old_access & OPEN4_SHARE_ACCESS_READ) != 0);
00536   int access_write_inc = ((new_access & OPEN4_SHARE_ACCESS_WRITE) != 0) - ((old_access & OPEN4_SHARE_ACCESS_WRITE) != 0);
00537   int deny_read_inc    = ((new_deny   & OPEN4_SHARE_ACCESS_READ) != 0) - ((old_deny   & OPEN4_SHARE_ACCESS_READ) != 0);
00538   int deny_write_inc   = ((new_deny   & OPEN4_SHARE_ACCESS_WRITE) != 0) - ((old_deny   & OPEN4_SHARE_ACCESS_WRITE) != 0);
00539 
00540   pentry->object.file.share_state.share_access_read  += access_read_inc;
00541   pentry->object.file.share_state.share_access_write += access_write_inc;
00542   pentry->object.file.share_state.share_deny_read    += deny_read_inc;
00543   pentry->object.file.share_state.share_deny_write   += deny_write_inc;
00544   if(v4)
00545     pentry->object.file.share_state.share_deny_write_v4 += deny_write_inc;
00546 
00547   LogFullDebug(COMPONENT_STATE, "pentry %p: share counter: "
00548                "access_read %u, access_write %u, "
00549                "deny_read %u, deny_write %u, deny_write_v4 %u",
00550                pentry,
00551                pentry->object.file.share_state.share_access_read,
00552                pentry->object.file.share_state.share_access_write,
00553                pentry->object.file.share_state.share_deny_read,
00554                pentry->object.file.share_state.share_deny_write,
00555                pentry->object.file.share_state.share_deny_write_v4);
00556 }
00557 
00558 /* Utility function to calculate the union of share access of given file. */
00559 static unsigned int state_share_get_share_access(cache_entry_t * pentry)
00560 {
00561   unsigned int share_access = 0;
00562 
00563   if(pentry->object.file.share_state.share_access_read > 0)
00564     share_access |= OPEN4_SHARE_ACCESS_READ;
00565 
00566   if(pentry->object.file.share_state.share_access_write > 0)
00567     share_access |= OPEN4_SHARE_ACCESS_WRITE;
00568 
00569   LogFullDebug(COMPONENT_STATE, "pentry %p: union share access = %u",
00570                pentry, share_access);
00571 
00572   return share_access;
00573 }
00574 
00575 /* Utility function to calculate the union of share deny of given file. */
00576 static unsigned int state_share_get_share_deny(cache_entry_t * pentry)
00577 {
00578   unsigned int share_deny = 0;
00579 
00580   if(pentry->object.file.share_state.share_deny_read > 0)
00581     share_deny |= OPEN4_SHARE_DENY_READ;
00582 
00583   if(pentry->object.file.share_state.share_deny_write > 0)
00584     share_deny |= OPEN4_SHARE_DENY_WRITE;
00585 
00586   LogFullDebug(COMPONENT_STATE, "pentry %p: union share deny = %u",
00587                pentry, share_deny);
00588 
00589   return share_deny;
00590 }
00591 
00592 state_status_t state_share_anonymous_io_start(cache_entry_t  * pentry,
00593                                               int              share_access,
00594                                               state_status_t * pstatus)
00595 {
00596   pthread_rwlock_wrlock(&pentry->state_lock);
00597 
00598   if(state_share_check_conflict(pentry,
00599                                 share_access,
00600                                 0,
00601                                 pstatus) == STATE_SUCCESS)
00602     {
00603       /* Temporarily bump the access counters, v4 mode doesn't matter
00604        * since there is no deny mode associated with anonymous I/O.
00605        */
00606       state_share_update_counter(pentry,
00607                                  OPEN4_SHARE_ACCESS_NONE,
00608                                  OPEN4_SHARE_DENY_NONE,
00609                                  share_access,
00610                                  OPEN4_SHARE_DENY_NONE,
00611                                  FALSE);
00612     }
00613 
00614   pthread_rwlock_unlock(&pentry->state_lock);
00615 
00616   return *pstatus;
00617 }
00618 
00619 void state_share_anonymous_io_done(cache_entry_t  * pentry,
00620                                    int              share_access)
00621 {
00622   pthread_rwlock_wrlock(&pentry->state_lock);
00623 
00624   /* Undo the temporary bump to the access counters, v4 mode doesn't
00625    * matter since there is no deny mode associated with anonymous I/O.
00626    */
00627   state_share_update_counter(pentry,
00628                              share_access,
00629                              OPEN4_SHARE_DENY_NONE,
00630                              OPEN4_SHARE_ACCESS_NONE,
00631                              OPEN4_SHARE_DENY_NONE,
00632                              FALSE);
00633 
00634   pthread_rwlock_unlock(&pentry->state_lock);
00635 }
00636 
00637 #ifdef _USE_NLM
00638 state_status_t state_nlm_share(cache_entry_t        * pentry,
00639                                fsal_op_context_t    * pcontext,
00640                                exportlist_t         * pexport,
00641                                int                    share_access,
00642                                int                    share_deny,
00643                                state_owner_t        * powner,
00644                                state_status_t       * pstatus)
00645 {
00646   unsigned int           old_pentry_share_access;
00647   unsigned int           old_pentry_share_deny;
00648   unsigned int           new_pentry_share_access;
00649   unsigned int           new_pentry_share_deny;
00650   fsal_share_param_t     share_param;
00651   state_nlm_share_t    * nlm_share;
00652   cache_inode_status_t   cache_status;
00653 
00654   cache_status = cache_inode_inc_pin_ref(pentry);
00655 
00656   if(cache_status != CACHE_INODE_SUCCESS)
00657     {
00658       *pstatus = cache_inode_status_to_state_status(cache_status);
00659       LogDebug(COMPONENT_STATE,
00660                "Could not pin file");
00661       return *pstatus;
00662     }
00663 
00664   if(cache_inode_open(pentry,
00665                       FSAL_O_RDWR,
00666                       pcontext,
00667                       0,
00668                       &cache_status) != CACHE_INODE_SUCCESS)
00669     {
00670       cache_inode_dec_pin_ref(pentry);
00671 
00672       *pstatus = cache_inode_status_to_state_status(cache_status);
00673 
00674       LogFullDebug(COMPONENT_STATE,
00675                    "Could not open file");
00676 
00677       return *pstatus;
00678     }
00679 
00680   pthread_rwlock_wrlock(&pentry->state_lock);
00681 
00682   /* Check if new share state has conflicts. */
00683   if(state_share_check_conflict(pentry,
00684                                 share_access,
00685                                 share_deny,
00686                                 pstatus) != STATE_SUCCESS)
00687     {
00688       pthread_rwlock_unlock(&pentry->state_lock);
00689 
00690       cache_inode_dec_pin_ref(pentry);
00691 
00692       LogEvent(COMPONENT_STATE, "Share conflicts detected during add");
00693 
00694       return *pstatus;
00695     }
00696 
00697   /* Create a new NLM Share object */
00698   nlm_share = gsh_calloc(1, sizeof(state_nlm_share_t));
00699 
00700   if(nlm_share == NULL)
00701     {
00702       pthread_rwlock_unlock(&pentry->state_lock);
00703 
00704       cache_inode_dec_pin_ref(pentry);
00705 
00706       LogEvent(COMPONENT_STATE, "Can not allocate memory for share");
00707 
00708       *pstatus = STATE_MALLOC_ERROR;
00709 
00710       return *pstatus;
00711     }
00712 
00713   nlm_share->sns_powner  = powner;
00714   nlm_share->sns_pentry  = pentry;
00715   nlm_share->sns_access  = share_access;
00716   nlm_share->sns_deny    = share_deny;
00717   nlm_share->sns_pexport = pexport;
00718 
00719   /* Add share to list for NLM Owner */
00720   P(powner->so_mutex);
00721 
00722   glist_add_tail(&powner->so_owner.so_nlm_owner.so_nlm_shares, &nlm_share->sns_share_per_owner);
00723 
00724   inc_state_owner_ref_locked(powner);
00725   /* implicit V(powner->so_mutex); */
00726 
00727   /* Add share to list for NSM Client */
00728   P(powner->so_owner.so_nlm_owner.so_client->slc_nsm_client->ssc_mutex);
00729 
00730   glist_add_tail(&powner->so_owner.so_nlm_owner.so_client->slc_nsm_client->ssc_share_list,
00731                  &nlm_share->sns_share_per_client);
00732 
00733   inc_nsm_client_ref_locked(powner->so_owner.so_nlm_owner.so_client->slc_nsm_client);
00734   /* implicit V(powner->so_owner.so_nlm_owner.so_client->slc_nsm_client->ssc_mutex); */
00735 
00736   /* Add share to list for file, if list was empty take a pin ref to keep this
00737    * file pinned in the inode cache.
00738    */
00739   if(glist_empty(&pentry->object.file.nlm_share_list))
00740     cache_inode_inc_pin_ref(pentry);
00741 
00742   glist_add_tail(&pentry->object.file.nlm_share_list, &nlm_share->sns_share_per_file);
00743 
00744   /* Get the current union of share states of this file. */
00745   old_pentry_share_access = state_share_get_share_access(pentry);
00746   old_pentry_share_deny   = state_share_get_share_deny(pentry);
00747 
00748   /* Update the ref counted share state of this file. */
00749   state_share_update_counter(pentry,
00750                              OPEN4_SHARE_ACCESS_NONE,
00751                              OPEN4_SHARE_DENY_NONE,
00752                              share_access,
00753                              share_deny,
00754                              TRUE);
00755 
00756   /* Get the updated union of share states of this file. */
00757   new_pentry_share_access = state_share_get_share_access(pentry);
00758   new_pentry_share_deny   = state_share_get_share_deny(pentry);
00759 
00760   /* If this file's share bits are different from the supposed value, update
00761    * it.
00762    */
00763   if((new_pentry_share_access != old_pentry_share_access) ||
00764      (new_pentry_share_deny   != old_pentry_share_deny))
00765     {
00766       /* Try to push to FSAL. */
00767       share_param.share_access = new_pentry_share_access;
00768       share_param.share_deny   = new_pentry_share_deny;
00769 
00770       *pstatus = do_share_op(pentry, pcontext, powner, &share_param);
00771 
00772       if(*pstatus != STATE_SUCCESS)
00773         {
00774           /* Revert the ref counted share state of this file. */
00775           state_share_update_counter(pentry,
00776                                      share_access,
00777                                      share_deny,
00778                                      OPEN4_SHARE_ACCESS_NONE,
00779                                      OPEN4_SHARE_DENY_NONE,
00780                                      TRUE);
00781 
00782           /* Remove the share from the list for the file. If the list is now
00783            * empty also remove the extra pin ref.
00784            */
00785           glist_del(&nlm_share->sns_share_per_file);
00786 
00787           if(glist_empty(&pentry->object.file.nlm_share_list))
00788             cache_inode_dec_pin_ref(pentry);
00789 
00790           /* Remove the share from the NSM Client list */
00791           P(powner->so_owner.so_nlm_owner.so_client->slc_nsm_client->ssc_mutex);
00792 
00793           glist_del(&nlm_share->sns_share_per_client);
00794 
00795           dec_nsm_client_ref_locked(powner->so_owner.so_nlm_owner.so_client->slc_nsm_client);
00796           /* implicit V(powner->so_owner.so_nlm_owner.so_client->slc_nsm_client->ssc_mutex); */
00797 
00798           /* Remove the share from the NLM Owner list */
00799           P(powner->so_mutex);
00800 
00801           glist_del(&nlm_share->sns_share_per_owner);
00802 
00803           dec_state_owner_ref_locked(powner);
00804           /* implicit V(powner->so_mutex); */
00805 
00806           /* Free the NLM Share and exit */
00807           gsh_free(nlm_share);
00808 
00809           pthread_rwlock_unlock(&pentry->state_lock);
00810 
00811           cache_inode_dec_pin_ref(pentry);
00812 
00813           LogDebug(COMPONENT_STATE, "do_share_op failed");
00814 
00815           return *pstatus;
00816         }
00817     }
00818 
00819   LogFullDebug(COMPONENT_STATE, "added share_access %u, "
00820                "share_deny %u",
00821                share_access, share_deny);
00822 
00823   pthread_rwlock_unlock(&pentry->state_lock);
00824 
00825   cache_inode_dec_pin_ref(pentry);
00826 
00827   return *pstatus;
00828 }
00829 
00830 state_status_t state_nlm_unshare(cache_entry_t        * pentry,
00831                                  fsal_op_context_t    * pcontext,
00832                                  int                    share_access,
00833                                  int                    share_deny,
00834                                  state_owner_t        * powner,
00835                                  state_status_t       * pstatus)
00836 {
00837   struct glist_head      *glist, *glistn;
00838   unsigned int           old_pentry_share_access;
00839   unsigned int           old_pentry_share_deny;
00840   unsigned int           new_pentry_share_access;
00841   unsigned int           new_pentry_share_deny;
00842   unsigned int           removed_share_access;
00843   unsigned int           removed_share_deny;
00844   fsal_share_param_t     share_param;
00845   state_nlm_share_t    * nlm_share;
00846   cache_inode_status_t   cache_status;
00847 
00848   cache_status = cache_inode_inc_pin_ref(pentry);
00849 
00850   if(cache_status != CACHE_INODE_SUCCESS)
00851     {
00852       *pstatus = cache_inode_status_to_state_status(cache_status);
00853       LogDebug(COMPONENT_STATE,
00854                "Could not pin file");
00855       return *pstatus;
00856     }
00857 
00858   pthread_rwlock_wrlock(&pentry->state_lock);
00859 
00860   glist_for_each_safe(glist, glistn, &pentry->object.file.nlm_share_list)
00861     {
00862       nlm_share = glist_entry(glist, state_nlm_share_t, sns_share_per_file);
00863 
00864       if(different_owners(powner, nlm_share->sns_powner))
00865         continue;
00866 
00867       /* share_access == OPEN4_SHARE_ACCESS_NONE indicates that any share
00868        * should be matched for unshare.
00869        */
00870       if(share_access != OPEN4_SHARE_ACCESS_NONE &&
00871          (nlm_share->sns_access != share_access ||
00872           nlm_share->sns_deny   != share_deny))
00873         continue;
00874 
00875       /* Get the current union of share states of this file. */
00876       old_pentry_share_access = state_share_get_share_access(pentry);
00877       old_pentry_share_deny   = state_share_get_share_deny(pentry);
00878 
00879       /* Share state to be removed. */
00880       removed_share_access = nlm_share->sns_access;
00881       removed_share_deny   = nlm_share->sns_deny;
00882 
00883       /* Update the ref counted share state of this file. */
00884       state_share_update_counter(pentry,
00885                                  removed_share_access,
00886                                  removed_share_deny,
00887                                  OPEN4_SHARE_ACCESS_NONE,
00888                                  OPEN4_SHARE_DENY_NONE,
00889                                  TRUE);
00890 
00891       /* Get the updated union of share states of this file. */
00892       new_pentry_share_access = state_share_get_share_access(pentry);
00893       new_pentry_share_deny   = state_share_get_share_deny(pentry);
00894 
00895       /* If this file's share bits are different from the supposed value, update
00896        * it.
00897        */
00898       if((new_pentry_share_access != old_pentry_share_access) ||
00899          (new_pentry_share_deny   != old_pentry_share_deny))
00900         {
00901           /* Try to push to FSAL. */
00902           share_param.share_access = new_pentry_share_access;
00903           share_param.share_deny   = new_pentry_share_deny;
00904 
00905           *pstatus = do_share_op(pentry, pcontext, powner, &share_param);
00906 
00907           if(*pstatus != STATE_SUCCESS)
00908             {
00909               /* Revert the ref counted share state of this file. */
00910               state_share_update_counter(pentry,
00911                                          OPEN4_SHARE_ACCESS_NONE,
00912                                          OPEN4_SHARE_DENY_NONE,
00913                                          removed_share_access,
00914                                          removed_share_deny,
00915                                          TRUE);
00916 
00917               pthread_rwlock_unlock(&pentry->state_lock);
00918 
00919               cache_inode_dec_pin_ref(pentry);
00920 
00921               LogDebug(COMPONENT_STATE, "do_share_op failed");
00922 
00923               return *pstatus;
00924             }
00925         }
00926 
00927       LogFullDebug(COMPONENT_STATE,
00928                    "removed share_access %u, share_deny %u",
00929                    removed_share_access,
00930                    removed_share_deny);
00931 
00932       /* Remove the share from the list for the file. If the list is now
00933        * empty also remove the extra pin ref.
00934        */
00935       glist_del(&nlm_share->sns_share_per_file);
00936 
00937       if(glist_empty(&pentry->object.file.nlm_share_list))
00938         cache_inode_dec_pin_ref(pentry);
00939 
00940       /* Remove the share from the NSM Client list */
00941       P(powner->so_owner.so_nlm_owner.so_client->slc_nsm_client->ssc_mutex);
00942 
00943       glist_del(&nlm_share->sns_share_per_client);
00944 
00945       dec_nsm_client_ref_locked(powner->so_owner.so_nlm_owner.so_client->slc_nsm_client);
00946       /* implicit V(powner->so_owner.so_nlm_owner.so_client->slc_nsm_client->ssc_mutex); */
00947 
00948       /* Remove the share from the NLM Owner list */
00949       P(powner->so_mutex);
00950 
00951       glist_del(&nlm_share->sns_share_per_owner);
00952 
00953       dec_state_owner_ref_locked(powner);
00954       /* implicit V(powner->so_mutex); */
00955 
00956       /* Free the NLM Share (and continue to look for more) */
00957       gsh_free(nlm_share);
00958     }
00959 
00960   pthread_rwlock_unlock(&pentry->state_lock);
00961 
00962   cache_inode_dec_pin_ref(pentry);
00963 
00964   return *pstatus;
00965 }
00966 
00967 #endif /* _USE_NLM */