int nfs41_op_read(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp) { char __attribute__ ((__unused__)) funcname[] = "nfs41_op_read"; fsal_seek_t seek_descriptor; fsal_size_t size; fsal_size_t read_size; fsal_off_t offset; fsal_boolean_t eof_met; caddr_t bufferdata; cache_inode_status_t cache_status; cache_inode_state_t *pstate_found = NULL; cache_content_status_t content_status; fsal_attrib_list_t attr; cache_entry_t *entry = NULL; cache_inode_state_t *pstate_iterate = NULL; cache_inode_state_t *pstate_previous_iterate = NULL; int rc = 0; cache_content_policy_data_t datapol; datapol.UseMaxCacheSize = FALSE; /* Say we are managing NFS4_OP_READ */ resp->resop = NFS4_OP_READ; res_READ4.status = NFS4_OK; /* If there is no FH */ if(nfs4_Is_Fh_Empty(&(data->currentFH))) { res_READ4.status = NFS4ERR_NOFILEHANDLE; return res_READ4.status; } /* If the filehandle is invalid */ if(nfs4_Is_Fh_Invalid(&(data->currentFH))) { res_READ4.status = NFS4ERR_BADHANDLE; return res_READ4.status; } /* Tests if the Filehandle is expired (for volatile filehandle) */ if(nfs4_Is_Fh_Expired(&(data->currentFH))) { res_READ4.status = NFS4ERR_FHEXPIRED; return res_READ4.status; } /* vnode to manage is the current one */ entry = data->current_entry; /* If Filehandle points to a xattr object, manage it via the xattrs specific functions */ if(nfs4_Is_Fh_Xattr(&(data->currentFH))) return nfs4_op_read_xattr(op, data, resp); /* Manage access type MDONLY */ if(data->pexport->access_type == ACCESSTYPE_MDONLY) { res_READ4.status = NFS4ERR_DQUOT; return res_READ4.status; } /* Check for special stateid */ if(!memcmp((char *)all_zero, arg_READ4.stateid.other, 12) && arg_READ4.stateid.seqid == 0) { /* "All 0 stateid special case" */ /* This will be treated as a client that held no lock at all, * I set pstate_found to NULL to remember this situation later */ pstate_found = NULL; } else if(!memcmp((char *)all_one, arg_READ4.stateid.other, 12) && arg_READ4.stateid.seqid == 0xFFFFFFFF) { /* "All 1 stateid special case" */ /* This will be treated as a client that held no lock at all, but may goes through locks * I set pstate_found to 1 to remember this situation later */ pstate_found = NULL; } /* NB: After this points, if pstate_found == NULL, then the stateid is all-0 or all-1 */ /* Iterate through file's state to look for conflicts */ pstate_iterate = NULL; pstate_previous_iterate = NULL; do { cache_inode_state_iterate(data->current_entry, &pstate_iterate, pstate_previous_iterate, data->pclient, data->pcontext, &cache_status); if(cache_status == CACHE_INODE_STATE_ERROR) break; /* Get out of the loop */ if(cache_status == CACHE_INODE_INVALID_ARGUMENT) { res_READ4.status = NFS4ERR_INVAL; return res_READ4.status; } if(pstate_iterate != NULL) { switch (pstate_iterate->state_type) { case CACHE_INODE_STATE_SHARE: if(pstate_found != pstate_iterate) { if(pstate_iterate->state_data.share.share_deny & OPEN4_SHARE_DENY_READ) { /* Writing to this file if prohibited, file is write-denied */ res_READ4.status = NFS4ERR_LOCKED; return res_READ4.status; } } break; } } pstate_previous_iterate = pstate_iterate; } while(pstate_iterate != NULL); /* Only files can be read */ if(data->current_filetype != REGULAR_FILE) { /* If the source is no file, return EISDIR if it is a directory and EINAVL otherwise */ if(data->current_filetype == DIR_BEGINNING || data->current_filetype == DIR_CONTINUE) res_READ4.status = NFS4ERR_ISDIR; else res_READ4.status = NFS4ERR_INVAL; return res_READ4.status; } /* Get the size and offset of the read operation */ offset = arg_READ4.offset; size = arg_READ4.count; LogFullDebug(COMPONENT_NFS_V4, " NFS4_OP_READ: offset = %llu length = %llu\n", offset, size); if((data->pexport->options & EXPORT_OPTION_MAXOFFSETREAD) == EXPORT_OPTION_MAXOFFSETREAD) if((fsal_off_t) (offset + size) > data->pexport->MaxOffsetRead) { res_READ4.status = NFS4ERR_DQUOT; return res_READ4.status; } /* Do not read more than FATTR4_MAXREAD */ if((data->pexport->options & EXPORT_OPTION_MAXREAD == EXPORT_OPTION_MAXREAD) && size > data->pexport->MaxRead) { /* the client asked for too much data, * this should normally not happen because * client will get FATTR4_MAXREAD value at mount time */ size = data->pexport->MaxRead; } /* If size == 0 , no I/O is to be made and everything is alright */ if(size == 0) { 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 */ res_READ4.READ4res_u.resok4.data.data_len = 0; res_READ4.READ4res_u.resok4.data.data_val = NULL; res_READ4.status = NFS4_OK; return res_READ4.status; } if((data->pexport->options & EXPORT_OPTION_USE_DATACACHE) && (entry->object.file.pentry_content == NULL)) { /* Entry is not in datacache, but should be in, cache it . * Several threads may call this function at the first time and a race condition can occur here * in order to avoid this, cache_inode_add_data_cache is "mutex protected" * The first call will create the file content cache entry, the further will return * with error CACHE_INODE_CACHE_CONTENT_EXISTS which is not a pathological thing here */ datapol.UseMaxCacheSize = data->pexport->options & EXPORT_OPTION_MAXCACHESIZE; datapol.MaxCacheSize = data->pexport->MaxCacheSize; /* Status is set in last argument */ cache_inode_add_data_cache(entry, data->ht, data->pclient, data->pcontext, &cache_status); if((cache_status != CACHE_INODE_SUCCESS) && (cache_content_cache_behaviour(entry, &datapol, (cache_content_client_t *) (data->pclient-> pcontent_client), &content_status) == CACHE_CONTENT_FULLY_CACHED) && (cache_status != CACHE_INODE_CACHE_CONTENT_EXISTS)) { res_READ4.status = NFS4ERR_SERVERFAULT; return res_READ4.status; } } /* Some work is to be done */ if((bufferdata = (char *)Mem_Alloc(size)) == NULL) { res_READ4.status = NFS4ERR_SERVERFAULT; return res_READ4.status; } memset((char *)bufferdata, 0, size); seek_descriptor.whence = FSAL_SEEK_SET; seek_descriptor.offset = offset; if(cache_inode_rdwr(entry, CACHE_CONTENT_READ, &seek_descriptor, size, &read_size, &attr, bufferdata, &eof_met, data->ht, data->pclient, data->pcontext, TRUE, &cache_status) != CACHE_INODE_SUCCESS) { res_READ4.status = nfs4_Errno(cache_status); return res_READ4.status; } /* What is the filesize ? */ if((offset + read_size) > attr.filesize) res_READ4.READ4res_u.resok4.eof = TRUE; res_READ4.READ4res_u.resok4.data.data_len = read_size; res_READ4.READ4res_u.resok4.data.data_val = bufferdata; LogFullDebug(COMPONENT_NFS_V4," NFS4_OP_READ: offset = %llu read length = %llu eof=%u\n", offset, read_size, eof_met); /* Is EOF met or not ? */ if(eof_met == TRUE) res_READ4.READ4res_u.resok4.eof = TRUE; else res_READ4.READ4res_u.resok4.eof = FALSE; /* Say it is ok */ res_READ4.status = NFS4_OK; return res_READ4.status; } /* nfs41_op_read */
int nfs41_op_write(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp) { char __attribute__ ((__unused__)) funcname[] = "nfs41_op_write"; fsal_seek_t seek_descriptor; fsal_size_t size; fsal_size_t written_size; fsal_off_t offset; fsal_boolean_t eof_met; bool_t stable_flag = TRUE; caddr_t bufferdata; stable_how4 stable_how; cache_content_status_t content_status; cache_inode_state_t *pstate_found = NULL; cache_inode_status_t cache_status; fsal_attrib_list_t attr; cache_entry_t *entry = NULL; cache_inode_state_t *pstate_iterate = NULL; cache_inode_state_t *pstate_previous_iterate = NULL; int rc = 0; cache_content_policy_data_t datapol; datapol.UseMaxCacheSize = FALSE; /* Lock are not supported */ resp->resop = NFS4_OP_WRITE; res_WRITE4.status = NFS4_OK; /* If there is no FH */ if(nfs4_Is_Fh_Empty(&(data->currentFH))) { res_WRITE4.status = NFS4ERR_NOFILEHANDLE; return res_WRITE4.status; } /* If the filehandle is invalid */ if(nfs4_Is_Fh_Invalid(&(data->currentFH))) { res_WRITE4.status = NFS4ERR_BADHANDLE; return res_WRITE4.status; } /* Tests if the Filehandle is expired (for volatile filehandle) */ if(nfs4_Is_Fh_Expired(&(data->currentFH))) { res_WRITE4.status = NFS4ERR_FHEXPIRED; return res_WRITE4.status; } /* If Filehandle points to a xattr object, manage it via the xattrs specific functions */ if(nfs4_Is_Fh_Xattr(&(data->currentFH))) return nfs4_op_write_xattr(op, data, resp); /* Manage access type MDONLY */ if(data->pexport->access_type == ACCESSTYPE_MDONLY) { res_WRITE4.status = NFS4ERR_DQUOT; return res_WRITE4.status; } /* vnode to manage is the current one */ entry = data->current_entry; /* Check for special stateid */ if(!memcmp((char *)all_zero, arg_WRITE4.stateid.other, 12) && arg_WRITE4.stateid.seqid == 0) { /* "All 0 stateid special case", see RFC3530 page 220-221 for details * This will be treated as a client that held no lock at all, * I set pstate_found to NULL to remember this situation later */ pstate_found = NULL; } else if(!memcmp((char *)all_one, arg_WRITE4.stateid.other, 12) && arg_WRITE4.stateid.seqid == 0xFFFFFFFF) { /* "All 1 stateid special case", see RFC3530 page 220-221 for details * This will be treated as a client that held no lock at all, * I set pstate_found to NULL to remember this situation later */ pstate_found = NULL; } /* NB: After this points, if pstate_found == NULL, then the stateid is all-0 or all-1 */ /* Iterate through file's state to look for conflicts */ pstate_iterate = NULL; pstate_previous_iterate = NULL; do { cache_inode_state_iterate(data->current_entry, &pstate_iterate, pstate_previous_iterate, data->pclient, data->pcontext, &cache_status); if(cache_status == CACHE_INODE_STATE_ERROR) break; /* Get out of the loop */ if(cache_status == CACHE_INODE_INVALID_ARGUMENT) { res_WRITE4.status = NFS4ERR_INVAL; return res_WRITE4.status; } if(pstate_iterate != NULL) { switch (pstate_iterate->state_type) { case CACHE_INODE_STATE_SHARE: if(pstate_found != pstate_iterate) { if(pstate_iterate->state_data.share.share_deny & OPEN4_SHARE_DENY_WRITE) { /* Writing to this file if prohibited, file is write-denied */ res_WRITE4.status = NFS4ERR_LOCKED; return res_WRITE4.status; } } break; } } pstate_previous_iterate = pstate_iterate; } while(pstate_iterate != NULL); /* Only files can be written */ if(data->current_filetype != REGULAR_FILE) { /* If the destination is no file, return EISDIR if it is a directory and EINAVL otherwise */ if(data->current_filetype == DIR_BEGINNING || data->current_filetype == DIR_CONTINUE) res_WRITE4.status = NFS4ERR_ISDIR; else res_WRITE4.status = NFS4ERR_INVAL; return res_WRITE4.status; } /* Get the characteristics of the I/O to be made */ offset = arg_WRITE4.offset; size = arg_WRITE4.data.data_len; stable_how = arg_WRITE4.stable; LogFullDebug(COMPONENT_NFS_V4," NFS4_OP_WRITE: offset = %llu length = %llu stable = %d\n", offset, size, stable_how); if((data->pexport->options & EXPORT_OPTION_MAXOFFSETWRITE) == EXPORT_OPTION_MAXOFFSETWRITE) if((fsal_off_t) (offset + size) > data->pexport->MaxOffsetWrite) { res_WRITE4.status = NFS4ERR_DQUOT; return res_WRITE4.status; } /* The size to be written should not be greater than FATTR4_MAXWRITESIZE because this value is asked * by the client at mount time, but we check this by security */ if((data->pexport->options & EXPORT_OPTION_MAXWRITE == EXPORT_OPTION_MAXWRITE) && size > data->pexport->MaxWrite) { /* * The client asked for too much data, we * must restrict him */ size = data->pexport->MaxWrite; } /* Where are the data ? */ bufferdata = arg_WRITE4.data.data_val; LogFullDebug(COMPONENT_NFS_V4, " NFS4_OP_WRITE: offset = %llu length = %llu\n", offset, size); /* if size == 0 , no I/O) are actually made and everything is alright */ if(size == 0) { res_WRITE4.WRITE4res_u.resok4.count = 0; res_WRITE4.WRITE4res_u.resok4.committed = FILE_SYNC4; memcpy(res_WRITE4.WRITE4res_u.resok4.writeverf, NFS4_write_verifier, sizeof(verifier4)); res_WRITE4.status = NFS4_OK; return res_WRITE4.status; } if((data->pexport->options & EXPORT_OPTION_USE_DATACACHE) && (cache_content_cache_behaviour(entry, &datapol, (cache_content_client_t *) (data->pclient-> pcontent_client), &content_status) == CACHE_CONTENT_FULLY_CACHED) && (entry->object.file.pentry_content == NULL)) { /* Entry is not in datacache, but should be in, cache it . * Several threads may call this function at the first time and a race condition can occur here * in order to avoid this, cache_inode_add_data_cache is "mutex protected" * The first call will create the file content cache entry, the further will return * with error CACHE_INODE_CACHE_CONTENT_EXISTS which is not a pathological thing here */ datapol.UseMaxCacheSize = data->pexport->options & EXPORT_OPTION_MAXCACHESIZE; datapol.MaxCacheSize = data->pexport->MaxCacheSize; /* Status is set in last argument */ cache_inode_add_data_cache(entry, data->ht, data->pclient, data->pcontext, &cache_status); if((cache_status != CACHE_INODE_SUCCESS) && (cache_status != CACHE_INODE_CACHE_CONTENT_EXISTS)) { res_WRITE4.status = NFS4ERR_SERVERFAULT; return res_WRITE4.status; } } if((nfs_param.core_param.use_nfs_commit == TRUE) && (arg_WRITE4.stable == UNSTABLE4)) { stable_flag = FALSE; } else { stable_flag = TRUE; } /* An actual write is to be made, prepare it */ /* only FILE_SYNC mode is supported */ /* Set up uio to define the transfer */ seek_descriptor.whence = FSAL_SEEK_SET; seek_descriptor.offset = offset; if(cache_inode_rdwr(entry, CACHE_CONTENT_WRITE, &seek_descriptor, size, &written_size, &attr, bufferdata, &eof_met, data->ht, data->pclient, data->pcontext, stable_flag, &cache_status) != CACHE_INODE_SUCCESS) { res_WRITE4.status = nfs4_Errno(cache_status); return res_WRITE4.status; } /* Set the returned value */ if(stable_flag == TRUE) res_WRITE4.WRITE4res_u.resok4.committed = FILE_SYNC4; else res_WRITE4.WRITE4res_u.resok4.committed = UNSTABLE4; res_WRITE4.WRITE4res_u.resok4.count = written_size; memcpy(res_WRITE4.WRITE4res_u.resok4.writeverf, NFS4_write_verifier, sizeof(verifier4)); res_WRITE4.status = NFS4_OK; return res_WRITE4.status; } /* nfs41_op_write */
int nfs_Write(nfs_arg_t * parg, exportlist_t * pexport, fsal_op_context_t * pcontext, cache_inode_client_t * pclient, hash_table_t * ht, struct svc_req *preq, nfs_res_t * pres) { static char __attribute__ ((__unused__)) funcName[] = "nfs_Write"; cache_entry_t *pentry; fsal_attrib_list_t attr; fsal_attrib_list_t pre_attr; fsal_attrib_list_t *ppre_attr; int rc; cache_inode_status_t cache_status = CACHE_INODE_SUCCESS; cache_content_status_t content_status; fsal_seek_t seek_descriptor; fsal_size_t size = 0; fsal_size_t written_size; fsal_off_t offset = 0; caddr_t data = NULL; enum stable_how stable; /* NFS V3 storage stability, see RFC1813 page 50 */ cache_inode_file_type_t filetype; fsal_boolean_t eof_met; uint64_t stable_flag = FSAL_SAFE_WRITE_TO_FS; if(isDebug(COMPONENT_NFSPROTO)) { char str[LEN_FH_STR], *stables = ""; switch (preq->rq_vers) { case NFS_V2: offset = parg->arg_write2.offset; size = parg->arg_write2.data.nfsdata2_len; stables = "FILE_SYNC"; break; case NFS_V3: offset = parg->arg_write3.offset; size = parg->arg_write3.count; switch (parg->arg_write3.stable) { case UNSTABLE: stables = "UNSTABLE"; break; case DATA_SYNC: stables = "DATA_SYNC"; break; case FILE_SYNC: stables = "FILE_SYNC"; break; } } nfs_FhandleToStr(preq->rq_vers, &(parg->arg_write2.file), &(parg->arg_write3.file), NULL, str); LogDebug(COMPONENT_NFSPROTO, "REQUEST PROCESSING: Calling nfs_Write handle: %s start: %llx len: %llx %s", str, (unsigned long long) offset, (unsigned long long) size, stables); } cache_content_policy_data_t datapol; datapol.UseMaxCacheSize = FALSE; if(preq->rq_vers == NFS_V3) { /* to avoid setting it on each error case */ pres->res_write3.WRITE3res_u.resfail.file_wcc.before.attributes_follow = FALSE; pres->res_write3.WRITE3res_u.resfail.file_wcc.after.attributes_follow = FALSE; ppre_attr = NULL; } /* Convert file handle into a cache entry */ if((pentry = nfs_FhandleToCache(preq->rq_vers, &(parg->arg_write2.file), &(parg->arg_write3.file), NULL, &(pres->res_attr2.status), &(pres->res_write3.status), NULL, &pre_attr, pcontext, pclient, ht, &rc)) == NULL) { /* Stale NFS FH ? */ return rc; } if((preq->rq_vers == NFS_V3) && (nfs3_Is_Fh_Xattr(&(parg->arg_write3.file)))) return nfs3_Write_Xattr(parg, pexport, pcontext, pclient, ht, preq, pres); /* get directory attributes before action (for V3 reply) */ ppre_attr = &pre_attr; /* Extract the filetype */ filetype = cache_inode_fsal_type_convert(pre_attr.type); /* Sanity check: write only a regular file */ if(filetype != REGULAR_FILE) { switch (preq->rq_vers) { case NFS_V2: /* * In the RFC tell it not good but it does * not tell what to do ... * We use NFSERR_ISDIR for lack of better */ pres->res_attr2.status = NFSERR_ISDIR; break; case NFS_V3: if(filetype == DIR_BEGINNING || filetype == DIR_CONTINUE) pres->res_write3.status = NFS3ERR_ISDIR; else pres->res_write3.status = NFS3ERR_INVAL; break; } return NFS_REQ_OK; } /* For MDONLY export, reject write operation */ /* Request of type MDONLY_RO were rejected at the nfs_rpc_dispatcher level */ /* This is done by replying EDQUOT (this error is known for not disturbing the client's requests cache */ if(pexport->access_type == ACCESSTYPE_MDONLY) { switch (preq->rq_vers) { case NFS_V2: pres->res_attr2.status = NFSERR_DQUOT; break; case NFS_V3: pres->res_write3.status = NFS3ERR_DQUOT; break; } nfs_SetFailedStatus(pcontext, pexport, preq->rq_vers, cache_status, &pres->res_attr2.status, &pres->res_write3.status, NULL, NULL, pentry, ppre_attr, &(pres->res_write3.WRITE3res_u.resfail.file_wcc), NULL, NULL, NULL); return NFS_REQ_OK; } /* Extract the argument from the request */ switch (preq->rq_vers) { case NFS_V2: if(ppre_attr && ppre_attr->filesize > NFS2_MAX_FILESIZE) { /* * V2 clients don't understand filesizes > * 2GB, so we don't allow them to alter * them in any way. BJP 6/26/2001 */ pres->res_attr2.status = NFSERR_FBIG; return NFS_REQ_OK; } offset = parg->arg_write2.offset; /* beginoffset is obsolete */ size = parg->arg_write2.data.nfsdata2_len; /* totalcount is obsolete */ data = parg->arg_write2.data.nfsdata2_val; stable = FILE_SYNC; if (pexport->use_commit == TRUE) stable_flag = FSAL_SAFE_WRITE_TO_FS; break; case NFS_V3: offset = parg->arg_write3.offset; size = parg->arg_write3.count; if(size > parg->arg_write3.data.data_len) { /* should never happen */ pres->res_write3.status = NFS3ERR_INVAL; return NFS_REQ_OK; } if((pexport->use_commit == TRUE) && (pexport->use_ganesha_write_buffer == FALSE) && (parg->arg_write3.stable == UNSTABLE)) { stable_flag = FSAL_UNSAFE_WRITE_TO_FS_BUFFER; } else if((pexport->use_commit == TRUE) && (pexport->use_ganesha_write_buffer == TRUE) && (parg->arg_write3.stable == UNSTABLE)) { stable_flag = FSAL_UNSAFE_WRITE_TO_GANESHA_BUFFER; } else { stable_flag = FSAL_SAFE_WRITE_TO_FS; } data = parg->arg_write3.data.data_val; stable = parg->arg_write3.stable; break; } /* * do not exceed maxium WRITE offset if set */ if((pexport->options & EXPORT_OPTION_MAXOFFSETWRITE) == EXPORT_OPTION_MAXOFFSETWRITE) { LogFullDebug(COMPONENT_NFSPROTO, "-----> Write offset=%llu count=%llu MaxOffSet=%llu", (unsigned long long) offset, (unsigned long long) size, (unsigned long long) pexport->MaxOffsetWrite); if((fsal_off_t) (offset + size) > pexport->MaxOffsetWrite) { LogEvent(COMPONENT_NFSPROTO, "NFS WRITE: A client tryed to violate max file size %llu for exportid #%hu", (unsigned long long) pexport->MaxOffsetWrite, pexport->id); switch (preq->rq_vers) { case NFS_V2: pres->res_attr2.status = NFSERR_DQUOT; break; case NFS_V3: pres->res_write3.status = NFS3ERR_INVAL; break; } nfs_SetFailedStatus(pcontext, pexport, preq->rq_vers, cache_status, &pres->res_attr2.status, &pres->res_write3.status, NULL, NULL, pentry, ppre_attr, &(pres->res_write3.WRITE3res_u.resfail.file_wcc), NULL, NULL, NULL); return NFS_REQ_OK; } } /* * We should take care not to exceed FSINFO wtmax * field for the size */ if(((pexport->options & EXPORT_OPTION_MAXWRITE) == EXPORT_OPTION_MAXWRITE) && size > pexport->MaxWrite) { /* * The client asked for too much data, we * must restrict him */ size = pexport->MaxWrite; } if(size == 0) { cache_status = CACHE_INODE_SUCCESS; written_size = 0; } else { /* An actual write is to be made, prepare it */ /* If entry is not cached, cache it now */ datapol.UseMaxCacheSize = pexport->options & EXPORT_OPTION_MAXCACHESIZE; datapol.MaxCacheSize = pexport->MaxCacheSize; if((pexport->options & EXPORT_OPTION_USE_DATACACHE) && (cache_content_cache_behaviour(pentry, &datapol, (cache_content_client_t *) pclient->pcontent_client, &content_status) == CACHE_CONTENT_FULLY_CACHED) && (pentry->object.file.pentry_content == NULL)) { /* Entry is not in datacache, but should be in, cache it . * Several threads may call this function at the first time and a race condition can occur here * in order to avoid this, cache_inode_add_data_cache is "mutex protected" * The first call will create the file content cache entry, the further will return * with error CACHE_INODE_CACHE_CONTENT_EXISTS which is not a pathological thing here */ /* Status is set in last argument */ cache_inode_add_data_cache(pentry, ht, pclient, pcontext, &cache_status); if((cache_status != CACHE_INODE_SUCCESS) && (cache_status != CACHE_INODE_CACHE_CONTENT_EXISTS)) { /* If we are here, there was an error */ if(nfs_RetryableError(cache_status)) { return NFS_REQ_DROP; } nfs_SetFailedStatus(pcontext, pexport, preq->rq_vers, cache_status, &pres->res_attr2.status, &pres->res_write3.status, NULL, NULL, pentry, ppre_attr, &(pres->res_write3.WRITE3res_u.resfail.file_wcc), NULL, NULL, NULL); return NFS_REQ_OK; } } /* only FILE_SYNC mode is supported */ /* Set up uio to define the transfer */ seek_descriptor.whence = FSAL_SEEK_SET; seek_descriptor.offset = offset; if(cache_inode_rdwr(pentry, CACHE_INODE_WRITE, &seek_descriptor, size, &written_size, &attr, data, &eof_met, ht, pclient, pcontext, stable_flag, &cache_status) == CACHE_INODE_SUCCESS) { switch (preq->rq_vers) { case NFS_V2: nfs2_FSALattr_To_Fattr(pexport, &attr, &(pres->res_attr2.ATTR2res_u.attributes)); pres->res_attr2.status = NFS_OK; break; case NFS_V3: /* Build Weak Cache Coherency data */ nfs_SetWccData(pcontext, pexport, pentry, ppre_attr, &attr, &(pres->res_write3.WRITE3res_u.resok.file_wcc)); /* Set the written size */ pres->res_write3.WRITE3res_u.resok.count = written_size; /* How do we commit data ? */ if(stable_flag == FSAL_SAFE_WRITE_TO_FS) { pres->res_write3.WRITE3res_u.resok.committed = FILE_SYNC; } else { pres->res_write3.WRITE3res_u.resok.committed = UNSTABLE; } /* Set the write verifier */ memcpy(pres->res_write3.WRITE3res_u.resok.verf, NFS3_write_verifier, sizeof(writeverf3)); pres->res_write3.status = NFS3_OK; break; } return NFS_REQ_OK; } } LogFullDebug(COMPONENT_NFSPROTO, "---> failed write: cache_status=%d", cache_status); /* If we are here, there was an error */ if(nfs_RetryableError(cache_status)) { return NFS_REQ_DROP; } nfs_SetFailedStatus(pcontext, pexport, preq->rq_vers, cache_status, &pres->res_attr2.status, &pres->res_write3.status, NULL, NULL, pentry, ppre_attr, &(pres->res_write3.WRITE3res_u.resfail.file_wcc), NULL, NULL, NULL); return NFS_REQ_OK; } /* nfs_Write.c */