nfs-ganesha 1.4

nfs_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 
00036 #ifdef HAVE_CONFIG_H
00037 #include "config.h"
00038 #endif
00039 
00040 #ifdef _SOLARIS
00041 #include "solaris_port.h"
00042 #endif
00043 
00044 #include <stdio.h>
00045 #include <string.h>
00046 #include <pthread.h>
00047 #include <fcntl.h>
00048 #include <sys/file.h>           /* for having FNDELAY */
00049 #include "HashData.h"
00050 #include "HashTable.h"
00051 #include "log.h"
00052 #include "ganesha_rpc.h"
00053 #include "nfs23.h"
00054 #include "nfs4.h"
00055 #include "mount.h"
00056 #include "nfs_core.h"
00057 #include "cache_inode.h"
00058 #include "nfs_exports.h"
00059 #include "nfs_creds.h"
00060 #include "nfs_proto_functions.h"
00061 #include "nfs_proto_tools.h"
00062 #include "nfs_tools.h"
00063 
00064 static void
00065 nfs_read_ok(exportlist_t * pexport,
00066             struct svc_req *preq, 
00067             nfs_res_t * pres,
00068             char *data,
00069             fsal_size_t read_size,
00070             fsal_attrib_list_t *attr,
00071             int eof)
00072 {
00073     if((read_size == 0) && (data != NULL)) {
00074         gsh_free(data);
00075         data = NULL;
00076     }
00077     switch (preq->rq_vers) {
00078     case NFS_V2:
00079         pres->res_read2.READ2res_u.readok.data.nfsdata2_val = data;
00080         pres->res_read2.READ2res_u.readok.data.nfsdata2_len = read_size;
00081 
00082         nfs2_FSALattr_To_Fattr(pexport, attr,
00083                                &(pres->res_read2.READ2res_u.readok.attributes));
00084 
00085         pres->res_attr2.status = NFS_OK;
00086         break;
00087 
00088     case NFS_V3:
00089         /* Build Post Op Attributes */
00090         nfs_SetPostOpAttr(pexport, attr,
00091                           &(pres->res_read3.READ3res_u.resok.file_attributes));
00092 
00093         pres->res_read3.READ3res_u.resok.eof = eof;
00094         pres->res_read3.READ3res_u.resok.count = read_size;
00095         pres->res_read3.READ3res_u.resok.data.data_val = data;
00096         pres->res_read3.READ3res_u.resok.data.data_len = read_size;
00097 
00098         pres->res_read3.status = NFS3_OK;
00099         break;
00100     }                   /* switch */
00101 }
00102 
00122 int nfs_Read(nfs_arg_t *parg,
00123              exportlist_t *pexport,
00124              fsal_op_context_t *pcontext,
00125              nfs_worker_data_t *pworker,
00126              struct svc_req *preq,
00127              nfs_res_t *pres)
00128 {
00129   cache_entry_t *pentry;
00130   fsal_attrib_list_t attr;
00131   fsal_attrib_list_t pre_attr;
00132   cache_inode_status_t cache_status = CACHE_INODE_SUCCESS;
00133   size_t size = 0;
00134   size_t read_size = 0;
00135   fsal_off_t offset = 0;
00136   void *data = NULL;
00137   cache_inode_file_type_t filetype;
00138   fsal_boolean_t eof_met=FALSE;
00139   int rc = NFS_REQ_OK;
00140 
00141   if(isDebug(COMPONENT_NFSPROTO))
00142     {
00143       char str[LEN_FH_STR];
00144 
00145       switch (preq->rq_vers)
00146         {
00147         case NFS_V2:
00148           offset = parg->arg_read2.offset;
00149           size = parg->arg_read2.count;
00150           break;
00151         case NFS_V3:
00152           offset = parg->arg_read3.offset;
00153           size = parg->arg_read3.count;
00154         }
00155 
00156       nfs_FhandleToStr(preq->rq_vers,
00157                        &(parg->arg_read2.file),
00158                        &(parg->arg_read3.file),
00159                        NULL,
00160                        str);
00161       LogDebug(COMPONENT_NFSPROTO,
00162                "REQUEST PROCESSING: Calling nfs_Read handle: %s start: %llx len: %llx",
00163                str, (unsigned long long) offset, (unsigned long long) size);
00164     }
00165 
00166   if(preq->rq_vers == NFS_V3)
00167     {
00168       /* to avoid setting it on each error case */
00169       pres->res_read3.READ3res_u.resfail.file_attributes.attributes_follow = FALSE;
00170       /* initialize for read of size 0 */
00171       pres->res_read3.READ3res_u.resok.eof = FALSE;
00172       pres->res_read3.READ3res_u.resok.count = 0;
00173       pres->res_read3.READ3res_u.resok.data.data_val = NULL;
00174       pres->res_read3.READ3res_u.resok.data.data_len = 0;
00175       pres->res_read3.status = NFS3_OK;
00176     }
00177   else if(preq->rq_vers == NFS_V2)
00178     {
00179       /* initialize for read of size 0 */
00180       pres->res_read2.READ2res_u.readok.data.nfsdata2_val = NULL;
00181       pres->res_read2.READ2res_u.readok.data.nfsdata2_len = 0;
00182       pres->res_attr2.status = NFS_OK;
00183     }
00184 
00185   /* Convert file handle into a cache entry */
00186   if((pentry = nfs_FhandleToCache(preq->rq_vers,
00187                                   &(parg->arg_read2.file),
00188                                   &(parg->arg_read3.file),
00189                                   NULL,
00190                                   &(pres->res_read2.status),
00191                                   &(pres->res_read3.status),
00192                                   NULL, &pre_attr, pcontext, &rc)) == NULL)
00193     {
00194       /* Stale NFS FH ? */
00195       goto out;
00196     }
00197 
00198   if((preq->rq_vers == NFS_V3) && (nfs3_Is_Fh_Xattr(&(parg->arg_read3.file))))
00199   {
00200     rc = nfs3_Read_Xattr(parg, pexport, pcontext, preq, pres);
00201     goto out;
00202   }
00203 
00204   if(cache_inode_access(pentry,
00205                         FSAL_READ_ACCESS,
00206                         pcontext,
00207                         &cache_status) != CACHE_INODE_SUCCESS)
00208     {
00209       switch (preq->rq_vers)
00210         {
00211         case NFS_V2:
00212           pres->res_attr2.status = nfs2_Errno(cache_status);
00213           break;
00214 
00215         case NFS_V3:
00216           pres->res_read3.status = nfs3_Errno(cache_status);
00217           break;
00218         }
00219       rc = NFS_REQ_OK;
00220       goto out;
00221     }
00222 
00223   /* Extract the filetype */
00224   filetype = cache_inode_fsal_type_convert(pre_attr.type);
00225 
00226   /* Sanity check: read only from a regular file */
00227   if(filetype != REGULAR_FILE)
00228     {
00229       switch (preq->rq_vers)
00230         {
00231         case NFS_V2:
00232           /*
00233            * In the RFC tell it not good but it does
00234            * not tell what to do ... 
00235            */
00236           pres->res_attr2.status = NFSERR_ISDIR;
00237           break;
00238 
00239         case NFS_V3:
00240           if(filetype == DIRECTORY)
00241             pres->res_read3.status = NFS3ERR_ISDIR;
00242           else
00243             pres->res_read3.status = NFS3ERR_INVAL;
00244           break;
00245         }
00246 
00247       rc = NFS_REQ_OK;
00248       goto out;
00249     }
00250 
00251   /* For MDONLY export, reject write operation */
00252   /* Request of type MDONLY_RO were rejected at the nfs_rpc_dispatcher level */
00253   /* This is done by replying EDQUOT (this error is known for not disturbing the client's requests cache */
00254   if(pexport->access_type == ACCESSTYPE_MDONLY
00255      || pexport->access_type == ACCESSTYPE_MDONLY_RO)
00256     {
00257       switch (preq->rq_vers)
00258         {
00259         case NFS_V2:
00260           pres->res_attr2.status = NFSERR_DQUOT;
00261           break;
00262 
00263         case NFS_V3:
00264           pres->res_read3.status = NFS3ERR_DQUOT;
00265           break;
00266         }
00267 
00268       nfs_SetFailedStatus(pcontext, pexport,
00269                           preq->rq_vers,
00270                           cache_status,
00271                           &pres->res_read2.status,
00272                           &pres->res_read3.status,
00273                           pentry,
00274                           &(pres->res_read3.READ3res_u.resfail.file_attributes),
00275                           NULL, NULL, NULL, NULL, NULL, NULL);
00276 
00277       rc = NFS_REQ_OK;
00278       goto out;
00279     }
00280 
00281   /* Extract the argument from the request */
00282   switch (preq->rq_vers)
00283     {
00284     case NFS_V2:
00285       offset = parg->arg_read2.offset;  /* beginoffset is obsolete */
00286       size = parg->arg_read2.count;     /* totalcount is obsolete  */
00287       break;
00288 
00289     case NFS_V3:
00290       offset = parg->arg_read3.offset;
00291       size = parg->arg_read3.count;
00292       break;
00293     }
00294 
00295   /* 
00296    * do not exceed maxium READ offset if set 
00297    */
00298   if((pexport->options & EXPORT_OPTION_MAXOFFSETREAD) == EXPORT_OPTION_MAXOFFSETREAD)
00299     {
00300       LogFullDebug(COMPONENT_NFSPROTO,
00301                    "-----> Read offset=%llu count=%llu MaxOffSet=%llu",
00302                    (unsigned long long) offset,
00303                    (unsigned long long) size,
00304                    (unsigned long long) pexport->MaxOffsetRead);
00305 
00306       if((fsal_off_t) (offset + size) > pexport->MaxOffsetRead)
00307         {
00308           LogEvent(COMPONENT_NFSPROTO,
00309                    "NFS READ: A client tryed to violate max file size %llu for exportid #%hu",
00310                    (unsigned long long) pexport->MaxOffsetRead, pexport->id);
00311 
00312           switch (preq->rq_vers)
00313             {
00314             case NFS_V2:
00315               pres->res_attr2.status = NFSERR_DQUOT;
00316               break;
00317 
00318             case NFS_V3:
00319               pres->res_read3.status = NFS3ERR_INVAL;
00320               break;
00321             }
00322 
00323           nfs_SetFailedStatus(pcontext, pexport,
00324                               preq->rq_vers,
00325                               cache_status,
00326                               &pres->res_read2.status,
00327                               &pres->res_read3.status,
00328                               pentry,
00329                               &(pres->res_read3.READ3res_u.resfail.file_attributes),
00330                               NULL, NULL, NULL, NULL, NULL, NULL);
00331 
00332           rc = NFS_REQ_OK;
00333           goto out;
00334         }
00335     }
00336 
00337   /*
00338    * We should not exceed the FSINFO rtmax field for
00339    * the size 
00340    */
00341   if(((pexport->options & EXPORT_OPTION_MAXREAD) == EXPORT_OPTION_MAXREAD) &&
00342      size > pexport->MaxRead)
00343     {
00344       /*
00345        * The client asked for too much, normally
00346        * this should not happen because the client
00347        * is calling nfs_Fsinfo at mount time and so
00348        * is aware of the server maximum write size 
00349        */
00350       size = pexport->MaxRead;
00351     }
00352 
00353   if(size == 0)
00354     {
00355       nfs_read_ok(pexport, preq, pres, NULL, 0, &pre_attr, 0);
00356       rc = NFS_REQ_OK;
00357       goto out;
00358     }
00359   else
00360     {
00361       data = gsh_malloc(size);
00362       if(data == NULL)
00363         {
00364           rc = NFS_REQ_DROP;
00365           goto out;
00366         }
00367 
00368       if((cache_inode_rdwr(pentry,
00369                            CACHE_INODE_READ,
00370                            offset,
00371                            size,
00372                            &read_size,
00373                            data,
00374                            &eof_met,
00375                            pcontext,
00376                            CACHE_INODE_SAFE_WRITE_TO_FS,
00377                            &cache_status) == CACHE_INODE_SUCCESS) &&
00378          (cache_inode_getattr(pentry, &attr, pcontext,
00379                               &cache_status)) == CACHE_INODE_SUCCESS)
00380 
00381         {
00382           nfs_read_ok(pexport, preq, pres, data, read_size, &attr, 
00383                       ((offset + read_size) >= attr.filesize));
00384           rc = NFS_REQ_OK;
00385           goto out;
00386         }
00387       gsh_free(data);
00388     }
00389 
00390   /* If we are here, there was an error */
00391   if(nfs_RetryableError(cache_status))
00392     {
00393       rc = NFS_REQ_DROP;
00394       goto out;
00395     }
00396 
00397   nfs_SetFailedStatus(pcontext, pexport,
00398                       preq->rq_vers,
00399                       cache_status,
00400                       &pres->res_read2.status,
00401                       &pres->res_read3.status,
00402                       pentry,
00403                       &(pres->res_read3.READ3res_u.resfail.file_attributes),
00404                       NULL, NULL, NULL, NULL, NULL, NULL);
00405 
00406   rc = NFS_REQ_OK;
00407 
00408 out:
00409   /* return references */
00410   if (pentry)
00411       cache_inode_put(pentry);
00412 
00413   return (rc);
00414 
00415 }                               /* nfs_Read */
00416 
00425 void nfs2_Read_Free(nfs_res_t * resp)
00426 {
00427   if((resp->res_read2.status == NFS_OK) &&
00428      (resp->res_read2.READ2res_u.readok.data.nfsdata2_len != 0))
00429     gsh_free(resp->res_read2.READ2res_u.readok.data.nfsdata2_val);
00430 }                               /* nfs2_Read_Free */
00431 
00440 void nfs3_Read_Free(nfs_res_t * resp)
00441 {
00442   if((resp->res_read3.status == NFS3_OK) &&
00443      (resp->res_read3.READ3res_u.resok.data.data_len != 0))
00444     gsh_free(resp->res_read3.READ3res_u.resok.data.data_val);
00445 }                               /* nfs3_Read_Free */