nfs-ganesha 1.4

nfs41_op_close.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 
00034 #ifdef HAVE_CONFIG_H
00035 #include "config.h"
00036 #endif
00037 
00038 #ifdef _SOLARIS
00039 #include "solaris_port.h"
00040 #endif
00041 
00042 #include <pthread.h>
00043 #include <stdint.h>
00044 #include "log.h"
00045 #include "nfs4.h"
00046 #include "sal_functions.h"
00047 #include "nfs_proto_functions.h"
00048 #include "nfs_proto_tools.h"
00049 
00064 #define arg_CLOSE4 op->nfs_argop4_u.opclose
00065 #define res_CLOSE4 resp->nfs_resop4_u.opclose
00066 
00067 int nfs41_op_close(struct nfs_argop4 *op, compound_data_t * data,
00068                    struct nfs_resop4 *resp)
00069 {
00070   int                    rc = 0;
00071   state_t              * pstate_found = NULL;
00072   cache_inode_status_t   cache_status;
00073   state_status_t         state_status;
00074   const char           * tag = "CLOSE";
00075   struct glist_head    * glist, * glistn;
00076 #ifdef _PNFS_MDS
00077   bool_t                 last_close = TRUE;
00078 #endif /* _PNFS_MDS */
00079 
00080   LogDebug(COMPONENT_STATE,
00081            "Entering NFS v4.1 CLOSE handler -----------------------------------------------------");
00082 
00083   memset(&res_CLOSE4, 0, sizeof(res_CLOSE4));
00084   resp->resop = NFS4_OP_CLOSE;
00085   res_CLOSE4.status = NFS4_OK;
00086 
00087   /*
00088    * Do basic checks on a filehandle
00089    * Object should be a file
00090    */
00091   res_CLOSE4.status = nfs4_sanity_check_FH(data, REGULAR_FILE);
00092   if(res_CLOSE4.status != NFS4_OK)
00093     return res_CLOSE4.status;
00094 
00095   if(data->current_entry == NULL)
00096     {
00097       res_CLOSE4.status = NFS4ERR_SERVERFAULT;
00098       return res_CLOSE4.status;
00099     }
00100 
00101   /* Check stateid correctness and get pointer to state */
00102   if((rc = nfs4_Check_Stateid(&arg_CLOSE4.open_stateid,
00103                               data->current_entry,
00104                               &pstate_found,
00105                               data,
00106                               STATEID_SPECIAL_FOR_LOCK,
00107                               tag)) != NFS4_OK)
00108     {
00109       res_CLOSE4.status = rc;
00110       LogDebug(COMPONENT_STATE,
00111                "CLOSE failed nfs4_Check_Stateid");
00112       return res_CLOSE4.status;
00113     }
00114 
00115   /* Check is held locks remain */
00116   glist_for_each(glist, &pstate_found->state_data.share.share_lockstates)
00117     {
00118       state_t * plock_state = glist_entry(glist,
00119                                           state_t,
00120                                           state_data.lock.state_sharelist);
00121 
00122       if(!glist_empty(&plock_state->state_data.lock.state_locklist))
00123         {
00124           res_CLOSE4.status = NFS4ERR_LOCKS_HELD;
00125 
00126           LogDebug(COMPONENT_STATE,
00127                    "NFS4 Close with existing locks");
00128 
00129           return res_CLOSE4.status;
00130         }
00131     }
00132 
00133 
00134   /* Handle stateid/seqid for success */
00135   update_stateid(pstate_found,
00136                  &res_CLOSE4.CLOSE4res_u.open_stateid,
00137                  data,
00138                  tag);
00139 
00140   /* File is closed, release the corresponding lock states */
00141   glist_for_each_safe(glist, glistn, &pstate_found->state_data.share.share_lockstates)
00142     {
00143       state_t * plock_state = glist_entry(glist,
00144                                           state_t,
00145                                           state_data.lock.state_sharelist);
00146 
00147       if(state_del(plock_state,
00148                    &state_status) != STATE_SUCCESS)
00149         {
00150           LogDebug(COMPONENT_STATE,
00151                    "CLOSE failed to release lock stateid error %s",
00152                    state_err_str(state_status));
00153         }
00154     }
00155 
00156   /* File is closed, release the corresponding state */
00157   if(state_del(pstate_found,
00158                &state_status) != STATE_SUCCESS)
00159     {
00160       LogDebug(COMPONENT_STATE,
00161                "CLOSE failed to release stateid error %s",
00162                state_err_str(state_status));
00163     }
00164 
00165 #ifdef _PNFS_MDS
00166   /* We can't simply grab a pointer to a layout state and free it
00167      later, since a client could have multiple layout states (since a
00168      layout state covers layouts of only one layout type) each marked
00169      return_on_close. */
00170 
00171   glist_for_each(glist, &data->current_entry->object.file.state_list)
00172     {
00173       state_t *pstate = glist_entry(glist, state_t, state_list);
00174 
00175       if ((pstate->state_type == STATE_TYPE_SHARE) &&
00176           (pstate->state_powner->so_type == STATE_OPEN_OWNER_NFSV4) &&
00177           (pstate->state_powner->so_owner.so_nfs4_owner.so_clientid ==
00178            data->psession->clientid))
00179         {
00180           last_close = FALSE;
00181           break;
00182         }
00183     }
00184 
00185   if (last_close)
00186     {
00187       glist_for_each_safe(glist,
00188                           glistn,
00189                           &data->current_entry->object.file.state_list)
00190         {
00191           state_t *pstate = glist_entry(glist, state_t, state_list);
00192           bool_t deleted = FALSE;
00193           struct pnfs_segment entire = {
00194                .io_mode = LAYOUTIOMODE4_ANY,
00195                .offset = 0,
00196                .length = NFS4_UINT64_MAX
00197           };
00198 
00199           if ((pstate->state_type == STATE_TYPE_LAYOUT) &&
00200               (pstate->state_powner->so_type == STATE_CLIENTID_OWNER_NFSV4) &&
00201               (pstate->state_powner->so_owner.so_nfs4_owner.so_clientid ==
00202                data->psession->clientid) &&
00203               pstate->state_data.layout.state_return_on_close)
00204             {
00205               nfs4_return_one_state(data->current_entry,
00206                                     data->pcontext,
00207                                     TRUE,
00208                                     FALSE,
00209                                     0,
00210                                     pstate,
00211                                     entire,
00212                                     0,
00213                                     NULL,
00214                                     &deleted);
00215               if (!deleted)
00216                 {
00217                   LogCrit(COMPONENT_PNFS,
00218                           "Layout state not destroyed on last close return.");
00219                 }
00220             }
00221         }
00222     }
00223 #endif /* _PNFS_MDS */
00224 
00225 
00226   /* Close the file in FSAL through the cache inode */
00227   if(cache_inode_close(data->current_entry,
00228                        0,
00229                        &cache_status) != CACHE_INODE_SUCCESS)
00230     {
00231       res_CLOSE4.status = nfs4_Errno(cache_status);
00232       return res_CLOSE4.status;
00233     }
00234 
00235   res_CLOSE4.status = NFS4_OK;
00236 
00237   if(isFullDebug(COMPONENT_STATE) && isFullDebug(COMPONENT_MEMLEAKS))
00238     {
00239       nfs_State_PrintAll();
00240       nfs4_owner_PrintAll();
00241     }
00242 
00243   return NFS4_OK;
00244 }                               /* nfs41_op_close */
00245 
00256 void nfs41_op_close_Free(CLOSE4res * resp)
00257 {
00258   /* Nothing to be done */
00259   return;
00260 }                               /* nfs41_op_close_Free */