nfs-ganesha 1.4
|
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 */