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 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 <fcntl.h> 00049 #include <sys/file.h> /* for having FNDELAY */ 00050 #include "HashData.h" 00051 #include "HashTable.h" 00052 #include "log.h" 00053 #include "ganesha_rpc.h" 00054 #include "nfs23.h" 00055 #include "nfs4.h" 00056 #include "mount.h" 00057 #include "nfs_core.h" 00058 #include "cache_inode.h" 00059 #include "nfs_exports.h" 00060 #include "nfs_creds.h" 00061 #include "nfs_proto_functions.h" 00062 #include "nfs_tools.h" 00063 #include "nfs_file_handle.h" 00064 #include "nfs_proto_tools.h" 00065 00085 int nfs_Create(nfs_arg_t *parg, 00086 exportlist_t *pexport, 00087 fsal_op_context_t *pcontext, 00088 nfs_worker_data_t *pworker, 00089 struct svc_req *preq, 00090 nfs_res_t *pres) 00091 { 00092 char *str_file_name = NULL; 00093 fsal_name_t file_name; 00094 fsal_accessmode_t mode = 0; 00095 cache_entry_t *file_pentry = NULL; 00096 cache_entry_t *parent_pentry = NULL; 00097 fsal_attrib_list_t parent_attr; 00098 fsal_attrib_list_t attr; 00099 fsal_attrib_list_t attr_parent_after; 00100 fsal_attrib_list_t attr_newfile; 00101 fsal_attrib_list_t attributes_create; 00102 fsal_attrib_list_t *ppre_attr; 00103 cache_inode_status_t cache_status = CACHE_INODE_SUCCESS; 00104 cache_inode_status_t cache_status_lookup; 00105 cache_inode_file_type_t parent_filetype; 00106 int rc = NFS_REQ_OK; 00107 #ifdef _USE_QUOTA 00108 fsal_status_t fsal_status ; 00109 #endif 00110 00111 if(isDebug(COMPONENT_NFSPROTO)) 00112 { 00113 char str[LEN_FH_STR]; 00114 00115 switch (preq->rq_vers) 00116 { 00117 case NFS_V2: 00118 str_file_name = parg->arg_create2.where.name; 00119 break; 00120 case NFS_V3: 00121 str_file_name = parg->arg_create3.where.name; 00122 break; 00123 } 00124 00125 nfs_FhandleToStr(preq->rq_vers, 00126 &(parg->arg_create2.where.dir), 00127 &(parg->arg_create3.where.dir), 00128 NULL, 00129 str); 00130 LogDebug(COMPONENT_NFSPROTO, 00131 "REQUEST PROCESSING: Calling nfs_Create handle: %s name: %s", 00132 str, str_file_name); 00133 } 00134 00135 if((preq->rq_vers == NFS_V3) && (nfs3_Is_Fh_Xattr(&(parg->arg_create3.where.dir)))) 00136 { 00137 rc = nfs3_Create_Xattr(parg, pexport, pcontext, preq, pres); 00138 goto out; 00139 } 00140 00141 if(preq->rq_vers == NFS_V3) 00142 { 00143 /* to avoid setting it on each error case */ 00144 pres->res_create3.CREATE3res_u.resfail.dir_wcc.before.attributes_follow = FALSE; 00145 pres->res_create3.CREATE3res_u.resfail.dir_wcc.after.attributes_follow = FALSE; 00146 ppre_attr = NULL; 00147 } 00148 00149 if((parent_pentry = nfs_FhandleToCache(preq->rq_vers, 00150 &(parg->arg_create2.where.dir), 00151 &(parg->arg_create3.where.dir), 00152 NULL, 00153 &(pres->res_dirop2.status), 00154 &(pres->res_create3.status), 00155 NULL, 00156 &parent_attr, 00157 pcontext, &rc)) == NULL) 00158 { 00159 /* Stale NFS FH ? */ 00160 goto out; 00161 } 00162 00163 /* get directory attributes before action (for V3 reply) */ 00164 ppre_attr = &parent_attr; 00165 00166 /* Extract the filetype */ 00167 parent_filetype = cache_inode_fsal_type_convert(parent_attr.type); 00168 00169 /* 00170 * Sanity checks: new file name must be non-null; parent must be a 00171 * directory. 00172 */ 00173 if(parent_filetype != DIRECTORY) 00174 { 00175 switch (preq->rq_vers) 00176 { 00177 case NFS_V2: 00178 pres->res_dirop2.status = NFSERR_NOTDIR; 00179 break; 00180 00181 case NFS_V3: 00182 pres->res_create3.status = NFS3ERR_NOTDIR; 00183 break; 00184 } 00185 00186 rc = NFS_REQ_OK; 00187 goto out; 00188 } 00189 00190 switch (preq->rq_vers) 00191 { 00192 case NFS_V2: 00193 str_file_name = parg->arg_create2.where.name; 00194 00195 if(parg->arg_create2.attributes.mode != (unsigned int)-1) 00196 { 00197 mode = unix2fsal_mode(parg->arg_create2.attributes.mode); 00198 } 00199 else 00200 { 00201 mode = 0; 00202 } 00203 00204 break; 00205 00206 case NFS_V3: 00207 str_file_name = parg->arg_create3.where.name; 00208 if(parg->arg_create3.how.mode == EXCLUSIVE) 00209 { 00210 /* 00211 * Client has not provided mode information. 00212 * If the create works, the client will issue 00213 * a separate setattr request to fix up the 00214 * file's mode, so pick arbitrary value for now. 00215 */ 00216 00217 mode = 0; 00218 } 00219 else if(parg->arg_create3.how.createhow3_u.obj_attributes.mode.set_it == TRUE) 00220 mode = 00221 unix2fsal_mode(parg->arg_create3.how.createhow3_u.obj_attributes.mode. 00222 set_mode3_u.mode); 00223 else 00224 mode = 0; 00225 break; 00226 } 00227 00228 #ifdef _USE_QUOTA 00229 /* if quota support is active, then we should check is the FSAL allows inode creation or not */ 00230 fsal_status = FSAL_check_quota( pexport->fullpath, 00231 FSAL_QUOTA_INODES, 00232 FSAL_OP_CONTEXT_TO_UID( pcontext ) ) ; 00233 if( FSAL_IS_ERROR( fsal_status ) ) 00234 { 00235 00236 switch (preq->rq_vers) 00237 { 00238 case NFS_V2: 00239 pres->res_dirop2.status = NFSERR_DQUOT ; 00240 break; 00241 00242 case NFS_V3: 00243 pres->res_create3.status = NFS3ERR_DQUOT; 00244 break; 00245 } 00246 00247 rc = NFS_REQ_OK ; 00248 goto out; 00249 } 00250 #endif /* _USE_QUOTA */ 00251 00252 // if(str_file_name == NULL || strlen(str_file_name) == 0) 00253 if(str_file_name == NULL || *str_file_name == '\0' ) 00254 { 00255 if(preq->rq_vers == NFS_V2) 00256 pres->res_dirop2.status = NFSERR_IO; 00257 if(preq->rq_vers == NFS_V3) 00258 pres->res_create3.status = NFS3ERR_INVAL; 00259 } 00260 else 00261 { 00262 if((cache_status = cache_inode_error_convert(FSAL_str2name(str_file_name, 00263 FSAL_MAX_NAME_LEN, 00264 &file_name))) == 00265 CACHE_INODE_SUCCESS) 00266 { 00267 /* 00268 * Lookup file to see if it exists. If so, use it. Otherwise 00269 * create a new one. 00270 */ 00271 file_pentry = cache_inode_lookup(parent_pentry, 00272 &file_name, 00273 &attr, 00274 pcontext, 00275 &cache_status_lookup); 00276 00277 if((cache_status_lookup == CACHE_INODE_NOT_FOUND) || 00278 ((cache_status_lookup == CACHE_INODE_SUCCESS) 00279 && (parg->arg_create3.how.mode == UNCHECKED))) 00280 { 00281 /* Create the file */ 00282 if((parg->arg_create3.how.mode == UNCHECKED) 00283 && (cache_status_lookup == CACHE_INODE_SUCCESS)) 00284 { 00285 cache_status = CACHE_INODE_SUCCESS; 00286 attr_newfile = attr; 00287 } 00288 else 00289 file_pentry = cache_inode_create(parent_pentry, 00290 &file_name, 00291 REGULAR_FILE, 00292 mode, 00293 NULL, 00294 &attr_newfile, 00295 pcontext, &cache_status); 00296 00297 if(file_pentry != NULL) 00298 { 00299 /* 00300 * Look at sattr to see if some attributes are to be set at creation time 00301 */ 00302 attributes_create.asked_attributes = 0ULL; 00303 00304 switch (preq->rq_vers) 00305 { 00306 case NFS_V2: 00307 00308 if(nfs2_Sattr_To_FSALattr(&attributes_create, 00309 &parg->arg_create2.attributes) == 0) 00310 { 00311 pres->res_dirop2.status = NFSERR_IO; 00312 rc = NFS_REQ_OK; 00313 goto out; 00314 break; 00315 } 00316 break; 00317 00318 case NFS_V3: 00319 00320 if(nfs3_Sattr_To_FSALattr(&attributes_create, 00321 &parg->arg_create3.how.createhow3_u. 00322 obj_attributes) == 0) 00323 { 00324 pres->res_create3.status = NFS3ERR_INVAL; 00325 rc = NFS_REQ_OK; 00326 goto out; 00327 } 00328 break; 00329 } 00330 00331 /* Mode is managed above (in cache_inode_create), there is no need 00332 * to manage it */ 00333 if(attributes_create.asked_attributes & FSAL_ATTR_MODE) 00334 attributes_create.asked_attributes &= ~FSAL_ATTR_MODE; 00335 00336 /* Some clients (like Solaris 10) try to set the size of the file to 0 00337 * at creation time. The FSAL create empty file, so we ignore this */ 00338 if(attributes_create.asked_attributes & FSAL_ATTR_SIZE) 00339 attributes_create.asked_attributes &= ~FSAL_ATTR_SIZE; 00340 00341 if(attributes_create.asked_attributes & FSAL_ATTR_SPACEUSED) 00342 attributes_create.asked_attributes &= ~FSAL_ATTR_SPACEUSED; 00343 00344 /* Are there attributes to be set (additional to the mode) ? */ 00345 if(attributes_create.asked_attributes != 0ULL && 00346 attributes_create.asked_attributes != FSAL_ATTR_MODE) 00347 { 00348 /* A call to cache_inode_setattr is required */ 00349 if(cache_inode_setattr(file_pentry, 00350 &attributes_create, 00351 pcontext, 00352 &cache_status) != CACHE_INODE_SUCCESS) 00353 { 00354 /* If we are here, there was an error */ 00355 nfs_SetFailedStatus(pcontext, pexport, 00356 preq->rq_vers, 00357 cache_status, 00358 &pres->res_dirop2.status, 00359 &pres->res_create3.status, 00360 NULL, NULL, 00361 parent_pentry, 00362 ppre_attr, 00363 &(pres->res_create3.CREATE3res_u.resfail. 00364 dir_wcc), NULL, NULL, NULL); 00365 00366 if(nfs_RetryableError(cache_status)) { 00367 rc = NFS_REQ_DROP; 00368 goto out; 00369 } 00370 00371 rc = NFS_REQ_OK; 00372 goto out; 00373 } 00374 00375 /* Get the resulting attributes from the Cache Inode */ 00376 if(cache_inode_getattr(file_pentry, 00377 &attr_newfile, 00378 pcontext, 00379 &cache_status) != CACHE_INODE_SUCCESS) 00380 { 00381 /* If we are here, there was an error */ 00382 00383 nfs_SetFailedStatus(pcontext, pexport, 00384 preq->rq_vers, 00385 cache_status, 00386 &pres->res_dirop2.status, 00387 &pres->res_create3.status, 00388 NULL, NULL, 00389 parent_pentry, 00390 ppre_attr, 00391 &(pres->res_create3.CREATE3res_u.resfail. 00392 dir_wcc), NULL, NULL, NULL); 00393 00394 if(nfs_RetryableError(cache_status)) { 00395 rc = NFS_REQ_DROP; 00396 goto out; 00397 } 00398 00399 rc = NFS_REQ_OK; 00400 goto out; 00401 } 00402 00403 } 00404 00405 switch (preq->rq_vers) 00406 { 00407 case NFS_V2: 00408 /* Build file handle */ 00409 if(nfs2_FSALToFhandle( 00410 &(pres->res_dirop2.DIROP2res_u.diropok.file), 00411 &file_pentry->handle, 00412 pexport) == 0) 00413 pres->res_dirop2.status = NFSERR_IO; 00414 else 00415 { 00416 if(!nfs2_FSALattr_To_Fattr( 00417 pexport, &attr_newfile, 00418 &(pres->res_dirop2.DIROP2res_u. 00419 diropok.attributes))) 00420 pres->res_dirop2.status = NFSERR_IO; 00421 else 00422 pres->res_dirop2.status = NFS_OK; 00423 } 00424 break; 00425 00426 case NFS_V3: 00427 /* Build file handle */ 00428 pres->res_create3.status = 00429 nfs3_AllocateFH(&pres->res_create3.CREATE3res_u 00430 .resok.obj.post_op_fh3_u.handle); 00431 if (pres->res_create3.status != NFS3_OK) 00432 { 00433 rc = NFS_REQ_OK; 00434 goto out; 00435 } 00436 00437 /* Set Post Op Fh3 structure */ 00438 if(nfs3_FSALToFhandle( 00439 &(pres->res_create3.CREATE3res_u.resok 00440 .obj.post_op_fh3_u.handle), 00441 &file_pentry->handle, pexport) == 0) 00442 { 00443 gsh_free(pres->res_create3.CREATE3res_u.resok.obj. 00444 post_op_fh3_u.handle.data.data_val); 00445 00446 pres->res_create3.status = NFS3ERR_BADHANDLE; 00447 rc = NFS_REQ_OK; 00448 goto out; 00449 } 00450 00451 /* Set Post Op Fh3 structure */ 00452 pres->res_create3.CREATE3res_u.resok.obj.handle_follows 00453 = TRUE; 00454 00455 /* Get the attributes of the parent after the 00456 operation */ 00457 attr_parent_after = parent_pentry->attributes; 00458 00459 /* Build entry attributes */ 00460 nfs_SetPostOpAttr(pexport, 00461 &attr_newfile, 00462 &(pres->res_create3.CREATE3res_u.resok. 00463 obj_attributes)); 00464 00465 /* 00466 * Build Weak Cache Coherency data 00467 */ 00468 nfs_SetWccData(pexport, 00469 ppre_attr, 00470 &attr_parent_after, 00471 &(pres->res_create3.CREATE3res_u 00472 .resok.dir_wcc)); 00473 00474 pres->res_create3.status = NFS3_OK; 00475 break; 00476 } /* switch */ 00477 rc = NFS_REQ_OK; 00478 goto out; 00479 } 00480 } 00481 else 00482 { 00483 if(cache_status_lookup == CACHE_INODE_SUCCESS) 00484 { 00485 /* Trying to create a file that already exists */ 00486 cache_status = CACHE_INODE_ENTRY_EXISTS; 00487 00488 switch (preq->rq_vers) 00489 { 00490 case NFS_V2: 00491 pres->res_dirop2.status = NFSERR_EXIST; 00492 break; 00493 00494 case NFS_V3: 00495 pres->res_create3.status = NFS3ERR_EXIST; 00496 break; 00497 } 00498 } 00499 else 00500 { 00501 /* Server fault */ 00502 cache_status = cache_status_lookup; 00503 00504 switch (preq->rq_vers) 00505 { 00506 case NFS_V2: 00507 pres->res_dirop2.status = NFSERR_IO; 00508 break; 00509 00510 case NFS_V3: 00511 pres->res_create3.status = NFS3ERR_INVAL; 00512 break; 00513 } 00514 } 00515 00516 nfs_SetFailedStatus(pcontext, pexport, 00517 preq->rq_vers, 00518 cache_status, 00519 &pres->res_dirop2.status, 00520 &pres->res_create3.status, 00521 NULL, NULL, 00522 parent_pentry, 00523 ppre_attr, 00524 &(pres->res_create3.CREATE3res_u.resfail.dir_wcc), 00525 NULL, NULL, NULL); 00526 00527 rc = NFS_REQ_OK; 00528 goto out; 00529 } /* if( cache_status_lookup == CACHE_INODE_NOT_FOUND ) */ 00530 } 00531 } 00532 00533 /* Set the exit status */ 00534 nfs_SetFailedStatus(pcontext, pexport, 00535 preq->rq_vers, 00536 cache_status, 00537 &pres->res_dirop2.status, 00538 &pres->res_create3.status, 00539 NULL, NULL, 00540 parent_pentry, 00541 ppre_attr, 00542 &(pres->res_create3.CREATE3res_u.resfail.dir_wcc), 00543 NULL, NULL, NULL); 00544 00545 /* If we are here, there was an error */ 00546 if(nfs_RetryableError(cache_status)) 00547 { 00548 rc = NFS_REQ_DROP; 00549 goto out; 00550 } 00551 00552 rc = NFS_REQ_OK; 00553 00554 out: 00555 /* return references */ 00556 if (file_pentry) 00557 cache_inode_put(file_pentry); 00558 00559 if (parent_pentry) 00560 cache_inode_put(parent_pentry); 00561 00562 return (rc); 00563 00564 } /* nfs_Create */ 00565 00574 void nfs_Create_Free(nfs_res_t * resp) 00575 { 00576 if((resp->res_create3.status == NFS3_OK) && 00577 (resp->res_create3.CREATE3res_u.resok.obj.handle_follows == TRUE)) 00578 gsh_free(resp->res_create3.CREATE3res_u.resok.obj 00579 .post_op_fh3_u.handle.data.data_val); 00580 }