nfs-ganesha 1.4

nfs4_op_lockt.c

Go to the documentation of this file.
00001 /*
00002  * vim:expandtab:shiftwidth=8:tabstop=8:
00003  *
00004  * Copyright CEA/DAM/DIF  (2008)
00005  * contributeur : Philippe DENIEL   philippe.deniel@cea.fr
00006  *                Thomas LEIBOVICI  thomas.leibovici@cea.fr
00007  *
00008  *
00009  * This program is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public
00011  * License as published by the Free Software Foundation; either
00012  * version 3 of the License, or (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * Lesser General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU Lesser General Public
00020  * License along with this library; if not, write to the Free Software
00021  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00022  *
00023  * ---------------------------------------
00024  */
00025 
00037 #ifdef HAVE_CONFIG_H
00038 #include "config.h"
00039 #endif
00040 
00041 #ifdef _SOLARIS
00042 #include "solaris_port.h"
00043 #endif
00044 
00045 #include <stdio.h>
00046 #include <string.h>
00047 #include <pthread.h>
00048 #include "HashData.h"
00049 #include "HashTable.h"
00050 #include "log.h"
00051 #include "ganesha_rpc.h"
00052 #include "nfs4.h"
00053 #include "nfs_core.h"
00054 #include "sal_functions.h"
00055 #include "nfs_proto_functions.h"
00056 #include "nfs_proto_tools.h"
00057 
00075 #define arg_LOCKT4 op->nfs_argop4_u.oplockt
00076 #define res_LOCKT4 resp->nfs_resop4_u.oplockt
00077 
00078 int nfs4_op_lockt(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp)
00079 {
00080   state_status_t            state_status;
00081   nfs_client_id_t         * pclientid;
00082   state_nfs4_owner_name_t   owner_name;
00083   state_owner_t           * plock_owner;
00084   state_owner_t           * conflict_owner = NULL;
00085   fsal_lock_param_t         lock_desc, conflict_desc;
00086 
00087   LogDebug(COMPONENT_NFS_V4_LOCK,
00088            "Entering NFS v4 LOCKT handler -----------------------------------------------------");
00089 
00090   /* Initialize to sane default */
00091   resp->resop = NFS4_OP_LOCKT;
00092   res_LOCKT4.status = NFS4_OK;
00093 
00094   /*
00095    * Do basic checks on a filehandle
00096    * LOCKT is done only on a file
00097    */
00098   res_LOCKT4.status = nfs4_sanity_check_FH(data, REGULAR_FILE);
00099   if(res_LOCKT4.status != NFS4_OK)
00100     return res_LOCKT4.status;
00101 
00102   /* This can't be done on the pseudofs */
00103   if(nfs4_Is_Fh_Pseudo(&(data->currentFH)))
00104     { 
00105       res_LOCKT4.status = NFS4ERR_ROFS;
00106       LogDebug(COMPONENT_STATE,
00107                "NFS4 LOCKT returning NFS4ERR_ROFS");
00108       return res_LOCKT4.status;
00109     }
00110 
00111   if (nfs_export_check_security(data->reqp, data->pexport) == FALSE)
00112     {
00113       res_LOCKT4.status = NFS4ERR_PERM;
00114       return res_LOCKT4.status;
00115     }
00116 
00117   /* Lock length should not be 0 */
00118   if(arg_LOCKT4.length == 0LL)
00119     {
00120       res_LOCKT4.status = NFS4ERR_INVAL;
00121       return res_LOCKT4.status;
00122     }
00123 
00124   if (nfs_in_grace())
00125     {
00126       res_LOCKT4.status = NFS4ERR_GRACE;
00127       return res_LOCKT4.status;
00128     }
00129 
00130   /* Convert lock parameters to internal types */
00131   switch(arg_LOCKT4.locktype)
00132     {
00133       case READ_LT:
00134       case READW_LT:
00135         lock_desc.lock_type = FSAL_LOCK_R;
00136         break;
00137 
00138       case WRITE_LT:
00139       case WRITEW_LT:
00140         lock_desc.lock_type = FSAL_LOCK_W;
00141         break;
00142     }
00143 
00144   lock_desc.lock_start = arg_LOCKT4.offset;
00145 
00146   if(arg_LOCKT4.length != STATE_LOCK_OFFSET_EOF)
00147     lock_desc.lock_length = arg_LOCKT4.length;
00148   else
00149     lock_desc.lock_length = 0;
00150 
00151   /* Check for range overflow.
00152    * Comparing beyond 2^64 is not possible int 64 bits precision,
00153    * but off+len > 2^64-1 is equivalent to len > 2^64-1 - off
00154    */
00155   if(lock_desc.lock_length > (STATE_LOCK_OFFSET_EOF - lock_desc.lock_start))
00156     {
00157       res_LOCKT4.status = NFS4ERR_INVAL;
00158       return res_LOCKT4.status;
00159     }
00160 
00161   /* Check clientid */
00162   if(nfs_client_id_get_confirmed(arg_LOCKT4.owner.clientid,
00163                                  &pclientid) != CLIENT_ID_SUCCESS)
00164     {
00165       res_LOCKT4.status = NFS4ERR_STALE_CLIENTID;
00166       return res_LOCKT4.status;
00167     }
00168 
00169   /* The protocol doesn't allow for EXPIRED, so return STALE_CLIENTID */
00170   P(pclientid->cid_mutex);
00171 
00172   if(!reserve_lease(pclientid))
00173     {
00174       V(pclientid->cid_mutex);
00175 
00176       dec_client_id_ref(pclientid);
00177 
00178       res_LOCKT4.status = NFS4ERR_STALE_CLIENTID;
00179       return res_LOCKT4.status;
00180     }
00181 
00182   V(pclientid->cid_mutex);
00183 
00184   /* Is this lock_owner known ? */
00185   convert_nfs4_lock_owner(&arg_LOCKT4.owner, &owner_name, 0LL);
00186 
00187   if(!nfs4_owner_Get_Pointer(&owner_name, &plock_owner))
00188     {
00189       /* This lock owner is not known yet, allocated and set up a new one */
00190       plock_owner = create_nfs4_owner(&owner_name,
00191                                       pclientid,
00192                                       STATE_LOCK_OWNER_NFSV4,
00193                                       NULL,
00194                                       0);
00195 
00196       if(plock_owner == NULL)
00197         {
00198           LogFullDebug(COMPONENT_NFS_V4_LOCK,
00199                        "LOCKT unable to create lock owner");
00200           res_LOCKT4.status = NFS4ERR_SERVERFAULT;
00201           goto out;
00202         }
00203     }
00204   else if(isFullDebug(COMPONENT_NFS_V4_LOCK))
00205     {
00206       char str[HASHTABLE_DISPLAY_STRLEN];
00207 
00208       DisplayOwner(plock_owner, str);
00209       
00210       LogFullDebug(COMPONENT_NFS_V4_LOCK,
00211                    "LOCKT A previously known owner is used %s",
00212                    str);
00213     }
00214 
00215   LogLock(COMPONENT_NFS_V4_LOCK, NIV_FULL_DEBUG,
00216           "LOCKT",
00217           data->current_entry,
00218           data->pcontext,
00219           plock_owner,
00220           &lock_desc);
00221 
00222   /* Now we have a lock owner and a stateid.
00223    * Go ahead and test the lock in SAL (and FSAL).
00224    */
00225   if(state_test(data->current_entry,
00226                 data->pcontext,
00227                 data->pexport,
00228                 plock_owner,
00229                 &lock_desc,
00230                 &conflict_owner,
00231                 &conflict_desc,
00232                 &state_status) == STATE_LOCK_CONFLICT)
00233     {
00234       /* A  conflicting lock from a different lock_owner, returns NFS4ERR_DENIED */
00235       Process_nfs4_conflict(&res_LOCKT4.LOCKT4res_u.denied,
00236                             conflict_owner,
00237                             &conflict_desc);
00238     }
00239 
00240   /* Release NFS4 Open Owner reference */
00241   dec_state_owner_ref(plock_owner);
00242 
00243   /* Return result */
00244   res_LOCKT4.status = nfs4_Errno_state(state_status);
00245 
00246  out:
00247  
00248   /* Update the lease before exit */
00249   P(pclientid->cid_mutex);
00250 
00251   update_lease(pclientid);
00252 
00253   V(pclientid->cid_mutex);
00254 
00255   dec_client_id_ref(pclientid);
00256 
00257   return res_LOCKT4.status;
00258 
00259 }                               /* nfs4_op_lockt */
00260 
00271 void nfs4_op_lockt_Free(LOCKT4res * resp)
00272 {
00273   if(resp->status == NFS4ERR_DENIED)
00274     Release_nfs4_denied(&resp->LOCKT4res_u.denied);
00275 }                               /* nfs4_op_lockt_Free */