nfs-ganesha 1.4

nfs4_op_read.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 #ifdef _PNFS_DS
00058 #include <stdlib.h>
00059 #include <unistd.h>
00060 #include "fsal_pnfs.h"
00061 #endif /* _PNFS_DS */
00062 
00063 #ifdef _PNFS_DS
00064 static int op_dsread(struct nfs_argop4 *op,
00065                      compound_data_t * data,
00066                      struct nfs_resop4 *resp);
00067 #endif /* _PNFS_DS */
00068 
00083 #define arg_READ4 op->nfs_argop4_u.opread
00084 #define res_READ4 resp->nfs_resop4_u.opread
00085 
00086 int nfs4_op_read(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp)
00087 {
00088   size_t                   size = 0;
00089   size_t                   read_size = 0;
00090   fsal_off_t               offset = 0;
00091   fsal_boolean_t           eof_met = FALSE;
00092   caddr_t                  bufferdata = NULL;
00093   cache_inode_status_t     cache_status = CACHE_INODE_SUCCESS;
00094   state_t                * pstate_found = NULL;
00095   state_t                * pstate_open = NULL;
00096   fsal_attrib_list_t       attr;
00097   cache_entry_t          * pentry = NULL;
00098   /* This flag is set to true in the case of an anonymous read so that
00099      we know to release the state lock afterward.  The state lock does
00100      not need to be held during a non-anonymous read, since the open
00101      state itself prevents a conflict. */
00102   bool_t                   anonymous = FALSE;
00103 
00104   /* Say we are managing NFS4_OP_READ */
00105   resp->resop = NFS4_OP_READ;
00106   res_READ4.status = NFS4_OK;
00107 
00108   /*
00109    * Do basic checks on a filehandle
00110    * Only files can be read
00111    */
00112   res_READ4.status = nfs4_sanity_check_FH(data, REGULAR_FILE);
00113   if(res_READ4.status != NFS4_OK)
00114     return res_READ4.status;
00115 
00116   /* If Filehandle points to a xattr object, manage it via the xattrs
00117      specific functions */
00118   if(nfs4_Is_Fh_Xattr(&(data->currentFH)))
00119     return nfs4_op_read_xattr(op, data, resp);
00120 
00121 #ifdef _PNFS_DS
00122   if((data->minorversion == 1) &&
00123      (nfs4_Is_Fh_DSHandle(&data->currentFH)))
00124     {
00125       return(op_dsread(op, data, resp));
00126     }
00127 #endif /* _PNFS_DS */
00128 
00129   /* Manage access type MDONLY */
00130   if(( data->pexport->access_type == ACCESSTYPE_MDONLY ) ||
00131      ( data->pexport->access_type == ACCESSTYPE_MDONLY_RO ) )
00132     {
00133       res_READ4.status = NFS4ERR_DQUOT;
00134       return res_READ4.status;
00135     }
00136 
00137   /* vnode to manage is the current one */
00138   pentry = data->current_entry;
00139 
00140   /* Check stateid correctness and get pointer to state
00141    * (also checks for special stateids)
00142    */
00143   res_READ4.status = nfs4_Check_Stateid(&arg_READ4.stateid,
00144                                         pentry,
00145                                         &pstate_found,
00146                                         data,
00147                                         STATEID_SPECIAL_ANY,
00148                                         "READ");
00149   if(res_READ4.status != NFS4_OK)
00150     return res_READ4.status;
00151 
00152   /* NB: After this point, if pstate_found == NULL, then the stateid
00153      is all-0 or all-1 */
00154 
00155   if(pstate_found != NULL)
00156     {
00157       switch(pstate_found->state_type)
00158         {
00159           case STATE_TYPE_SHARE:
00160             pstate_open = pstate_found;
00161             // TODO FSF: need to check against existing locks
00162             break;
00163 
00164           case STATE_TYPE_LOCK:
00165             pstate_open = pstate_found->state_data.lock.popenstate;
00166             // TODO FSF: should check that write is in range of an byte range lock...
00167             break;
00168 
00169           case STATE_TYPE_DELEG:
00170             pstate_open = NULL;
00171             // TODO FSF: should check that this is a read delegation?
00172             break;
00173 
00174           default:
00175             res_READ4.status = NFS4ERR_BAD_STATEID;
00176             LogDebug(COMPONENT_NFS_V4_LOCK,
00177                      "READ with invalid statid of type %d",
00178                      (int) pstate_found->state_type);
00179             return res_READ4.status;
00180         }
00181 
00182       /* This is a read operation, this means that the file MUST have
00183          been opened for reading */
00184       if(pstate_open != NULL &&
00185          (pstate_open->state_data.share.share_access &
00186           OPEN4_SHARE_ACCESS_READ) == 0)
00187         {
00188          /* Even if file is open for write, the client may do
00189           * accidently read operation (caching).  Because of this,
00190           * READ is allowed if not explicitely denied.  See page 72 in
00191           * RFC3530 for more details */
00192 
00193           if (pstate_open->state_data.share.share_deny & OPEN4_SHARE_DENY_READ)
00194            {
00195              /* Bad open mode, return NFS4ERR_OPENMODE */
00196              res_READ4.status = NFS4ERR_OPENMODE;
00197              LogDebug(COMPONENT_NFS_V4_LOCK,
00198                       "READ state %p doesn't have OPEN4_SHARE_ACCESS_READ",
00199                        pstate_found);
00200              return res_READ4.status;
00201            }
00202         }
00203 
00213       switch( pstate_found->state_type )
00214         {
00215           case STATE_TYPE_SHARE:
00216             if ((data->minorversion == 0) &&
00217                 ((pstate_found->state_powner->so_owner.so_nfs4_owner
00218                   .so_confirmed) == FALSE))
00219               {
00220                  res_READ4.status = NFS4ERR_BAD_STATEID;
00221                  return res_READ4.status;
00222               }
00223             break ;
00224 
00225          case STATE_TYPE_LOCK:
00226             /* Nothing to do */
00227             break ;
00228 
00229          default:
00230             /* Sanity check: all other types are illegal.  we should
00231              * not got that place (similar check above), anyway it
00232              * costs nothing to add this test */
00233             res_READ4.status = NFS4ERR_BAD_STATEID;
00234             return res_READ4.status;
00235             break ;
00236         }
00237     }
00238   else
00239     {
00240       /* Special stateid, no open state, check to see if any share conflicts */
00241       pstate_open = NULL;
00242 
00243       pthread_rwlock_rdlock(&pentry->state_lock);
00244       anonymous = TRUE;
00245 
00246       /*
00247        * Special stateid, no open state, check to see if any share conflicts
00248        * The stateid is all-0 or all-1
00249        */
00250       res_READ4.status = nfs4_check_special_stateid(pentry,"READ",
00251                                                     FATTR4_ATTR_READ);
00252       if(res_READ4.status != NFS4_OK)
00253         {
00254           pthread_rwlock_unlock(&pentry->state_lock);
00255           return res_READ4.status;
00256         }
00257     }
00258 
00259   if (pstate_open == NULL)
00260     {
00261       if(cache_inode_access(pentry,
00262                             FSAL_READ_ACCESS,
00263                             data->pcontext,
00264                             &cache_status) != CACHE_INODE_SUCCESS)
00265         {
00266           if (anonymous)
00267              {
00268                pthread_rwlock_unlock(&pentry->state_lock);
00269              }
00270           res_READ4.status = nfs4_Errno(cache_status);
00271           return res_READ4.status;
00272         }
00273     }
00274   /* Get the size and offset of the read operation */
00275   offset = arg_READ4.offset;
00276   size = arg_READ4.count;
00277 
00278   LogFullDebug(COMPONENT_NFS_V4,
00279                "NFS4_OP_READ: offset = %"PRIu64"  length = %zu",
00280                offset, size);
00281 
00282   if((data->pexport->options & EXPORT_OPTION_MAXOFFSETREAD) ==
00283      EXPORT_OPTION_MAXOFFSETREAD)
00284     if((fsal_off_t) (offset + size) > data->pexport->MaxOffsetRead)
00285       {
00286         res_READ4.status = NFS4ERR_DQUOT;
00287         if (anonymous)
00288           {
00289             pthread_rwlock_unlock(&pentry->state_lock);
00290           }
00291         return res_READ4.status;
00292       }
00293 
00294   /* Do not read more than FATTR4_MAXREAD */
00295   if( size > data->pexport->MaxRead )
00296     {
00297       /* the client asked for too much data,
00298        * this should normally not happen because
00299        * client will get FATTR4_MAXREAD value at mount time */
00300       
00301       LogFullDebug(COMPONENT_NFS_V4,
00302                "NFS4_OP_READ: read requested size = %zu  read allowed size = %zu",
00303                size, data->pexport->MaxRead);
00304       size = data->pexport->MaxRead;
00305     }
00306 
00307   /* If size == 0 , no I/O is to be made and everything is alright */
00308   if(size == 0)
00309     {
00310       res_READ4.READ4res_u.resok4.eof = FALSE;  /* end of file was not reached because READ occured, and a size = 0 can not lead to eof */
00311       res_READ4.READ4res_u.resok4.data.data_len = 0;
00312       res_READ4.READ4res_u.resok4.data.data_val = NULL;
00313 
00314       res_READ4.status = NFS4_OK;
00315       if (anonymous)
00316         {
00317           pthread_rwlock_unlock(&pentry->state_lock);
00318         }
00319       return res_READ4.status;
00320     }
00321 
00322   /* Some work is to be done */
00323   if((bufferdata = gsh_malloc_aligned(4096, size)) == NULL)
00324     {
00325       res_READ4.status = NFS4ERR_SERVERFAULT;
00326       if (anonymous)
00327         {
00328           pthread_rwlock_unlock(&pentry->state_lock);
00329         }
00330       return res_READ4.status;
00331     }
00332   if(data->pexport->options & EXPORT_OPTION_USE_DATACACHE)
00333     memset(bufferdata, 0, size);
00334 
00335   if((cache_inode_rdwr(pentry,
00336                       CACHE_INODE_READ,
00337                       offset,
00338                       size,
00339                       &read_size,
00340                       bufferdata,
00341                       &eof_met,
00342                       data->pcontext,
00343                       CACHE_INODE_SAFE_WRITE_TO_FS,
00344                       &cache_status) != CACHE_INODE_SUCCESS) ||
00345      ((cache_inode_getattr(pentry, &attr, data->pcontext,
00346                            &cache_status)) != CACHE_INODE_SUCCESS))
00347 
00348     {
00349       res_READ4.status = nfs4_Errno(cache_status);
00350       if (anonymous)
00351         {
00352           pthread_rwlock_unlock(&pentry->state_lock);
00353         }
00354       return res_READ4.status;
00355     }
00356 
00357   res_READ4.READ4res_u.resok4.data.data_len = read_size;
00358   res_READ4.READ4res_u.resok4.data.data_val = bufferdata;
00359 
00360   LogFullDebug(COMPONENT_NFS_V4,
00361                "NFS4_OP_READ: offset = %"PRIu64" read length = %zu eof=%u",
00362                offset, read_size, eof_met);
00363 
00364   /* Is EOF met or not ? */
00365   if( ( eof_met == TRUE ) ||
00366       ( (offset + read_size) >= attr.filesize) )
00367     res_READ4.READ4res_u.resok4.eof = TRUE;
00368   else
00369     res_READ4.READ4res_u.resok4.eof = FALSE;
00370 
00371   /* Say it is ok */
00372   res_READ4.status = NFS4_OK;
00373   if (anonymous)
00374     {
00375       pthread_rwlock_unlock(&pentry->state_lock);
00376     }
00377 
00378   return res_READ4.status;
00379 }                               /* nfs4_op_read */
00380 
00391 void nfs4_op_read_Free(READ4res * resp)
00392 {
00393   if(resp->status == NFS4_OK)
00394     if(resp->READ4res_u.resok4.data.data_len != 0)
00395       gsh_free(resp->READ4res_u.resok4.data.data_val);
00396   return;
00397 }                               /* nfs4_op_read_Free */
00398 
00399 
00400 #ifdef _PNFS_DS
00401 
00413 static int op_dsread(struct nfs_argop4 *op,
00414                      compound_data_t * data,
00415                      struct nfs_resop4 *resp)
00416 {
00417   /* The FSAL file handle */
00418   fsal_handle_t handle;
00419   struct fsal_handle_desc fh_desc;
00420   /* NFSv4 return code */
00421   nfsstat4 nfs_status = 0;
00422   /* Buffer into which data is to be read */
00423   caddr_t buffer = NULL;
00424   /* End of file flag */
00425   fsal_boolean_t eof = FALSE;
00426 
00427   /* Don't bother calling the FSAL if the read length is 0. */
00428 
00429   if(arg_READ4.count == 0)
00430     {
00431       res_READ4.READ4res_u.resok4.eof = FALSE;
00432       res_READ4.READ4res_u.resok4.data.data_len = 0;
00433       res_READ4.READ4res_u.resok4.data.data_val = NULL;
00434       res_READ4.status = NFS4_OK;
00435       return res_READ4.status;
00436     }
00437 
00438   /* Construct the FSAL file handle */
00439 
00440   if ((nfs4_FhandleToFSAL(&data->currentFH,
00441                           &fh_desc,
00442                           data->pcontext)) == 0)
00443     {
00444       res_READ4.status = NFS4ERR_INVAL;
00445       return res_READ4.status;
00446     }
00447   memset(&handle, 0, sizeof(handle));
00448   memcpy(&handle, fh_desc.start, fh_desc.len);
00449 
00450   buffer = gsh_malloc_aligned(4096, arg_READ4.count);
00451   if (buffer == NULL)
00452     {
00453       res_READ4.status = NFS4ERR_SERVERFAULT;
00454       return res_READ4.status;
00455     }
00456 
00457   res_READ4.READ4res_u.resok4.data.data_val = buffer;
00458 
00459   if ((nfs_status
00460        = fsal_dsfunctions.DS_read(&handle,
00461                                   data->pcontext,
00462                                   &arg_READ4.stateid,
00463                                   arg_READ4.offset,
00464                                   arg_READ4.count,
00465                                   res_READ4.READ4res_u.resok4.data.data_val,
00466                                   &res_READ4.READ4res_u.resok4.data.data_len,
00467                                   &eof))
00468       != NFS4_OK)
00469     {
00470       gsh_free(buffer);
00471       buffer = NULL;
00472     }
00473 
00474   res_READ4.READ4res_u.resok4.eof = eof;
00475 
00476   res_READ4.status = nfs_status;
00477 
00478   return res_READ4.status;
00479 }
00480 
00481 #endif /* _PNFS_DS */