int fsal_internal_proxy_fsal_path_2_utf8(fsal_path_t * ppath, utf8string * utf8str) { char tmpstr[FSAL_MAX_PATH_LEN]; fsal_status_t fsal_status; if(ppath == NULL || utf8str == NULL) return FALSE; fsal_status = FSAL_path2str(ppath, tmpstr, FSAL_MAX_NAME_LEN); if(fsal_status.major != ERR_FSAL_NO_ERROR) return FALSE; if(utf8str->utf8string_len == 0) { if((utf8str->utf8string_val = (char *)Mem_Alloc_Label(ppath->len, "fsal_internal_proxy_fsal_path_2_utf8")) == NULL) return FALSE; else utf8str->utf8string_len = ppath->len; } if(str2utf8(tmpstr, utf8str) == -1) return FALSE; return TRUE; } /* fsal_internal_proxy_fsal_path_2_utf8 */
/** * * gid2utf8: converts a gid to a utf8 string descriptor. * * Converts a gid to a utf8 string descriptor. * * @param gid [IN] the input gid * @param utf8str [OUT] computed UTF8 string descriptor * * @return the length of the utf8 buffer if succesfull, -1 if failed * */ int gid2utf8(gid_t gid, utf8string * utf8str) { char buff[NFS4_MAX_DOMAIN_LEN]; unsigned int len = 0; if(gid2str(gid, buff) == -1) return -1; len = strlen(buff); /* A matching gid was found */ /* Do the conversion to uft8 format */ if((utf8str->utf8string_val = (char *)Mem_Alloc_Label(len, "gid2utf8")) == NULL) return -1; else utf8str->utf8string_len = len; return str2utf8(buff, utf8str); } /* gid2utf8 */
/** * * uid2utf8: converts a uid to a utf8 string descriptor. * * Converts a uid to a utf8 string descriptor. * * @param uid [IN] the input uid * @param utf8str [OUT] computed UTF8 string descriptor * * @return the length of the utf8 buffer if succesfull, -1 if failed * */ int uid2utf8(uid_t uid, utf8string * utf8str) { char buff[NFS4_MAX_DOMAIN_LEN]; unsigned int len = 0; if(uid2str(uid, buff) == -1) return -1; len = strlen(buff); /* A matching uid was found, now do the conversion to utf8 */ if((utf8str->utf8string_val = (char *)Mem_Alloc_Label(len, "uid2utf8")) == NULL) return -1; else utf8str->utf8string_len = len; return str2utf8(buff, utf8str); } /* uid2utf8 */
cache_inode_status_t cache_inode_rdwr(cache_entry_t * pentry, cache_inode_io_direction_t read_or_write, fsal_seek_t * seek_descriptor, fsal_size_t buffer_size, fsal_size_t * pio_size, fsal_attrib_list_t * pfsal_attr, caddr_t buffer, fsal_boolean_t * p_fsal_eof, hash_table_t * ht, cache_inode_client_t * pclient, fsal_op_context_t * pcontext, uint64_t stable, cache_inode_status_t * pstatus) { int statindex = 0; cache_content_io_direction_t io_direction; cache_content_status_t cache_content_status; fsal_status_t fsal_status; fsal_openflags_t openflags; fsal_size_t io_size; fsal_attrib_list_t post_write_attr; fsal_status_t fsal_status_getattr; struct stat buffstat; /* Set the return default to CACHE_INODE_SUCCESS */ *pstatus = CACHE_INODE_SUCCESS; /* For now, only FSAL_SEEK_SET is supported */ if(seek_descriptor->whence != FSAL_SEEK_SET) { LogCrit(COMPONENT_CACHE_INODE, "Implementation trouble: seek_descriptor was not a 'FSAL_SEEK_SET' cursor"); *pstatus = CACHE_INODE_INVALID_ARGUMENT; return *pstatus; } io_size = buffer_size; LogDebug(COMPONENT_CACHE_INODE, "cache_inode_rdwr: INODE : IO Size = %llu fdsize =%zu seeksize=%zu", buffer_size, sizeof(fsal_file_t), sizeof(fsal_seek_t)); /* stat */ pclient->stat.nb_call_total += 1; if(read_or_write == CACHE_INODE_READ) { statindex = CACHE_INODE_READ_DATA; io_direction = CACHE_CONTENT_READ; openflags = FSAL_O_RDONLY; pclient->stat.func_stats.nb_call[CACHE_INODE_READ_DATA] += 1; } else { statindex = CACHE_INODE_WRITE_DATA; io_direction = CACHE_CONTENT_WRITE; openflags = FSAL_O_WRONLY; pclient->stat.func_stats.nb_call[CACHE_INODE_WRITE_DATA] += 1; } P_w(&pentry->lock); /* IO are done only on REGULAR_FILEs */ if(pentry->internal_md.type != REGULAR_FILE) { *pstatus = CACHE_INODE_BAD_TYPE; V_w(&pentry->lock); /* stats */ pclient->stat.func_stats.nb_err_unrecover[statindex] += 1; return *pstatus; } /* Non absolute address within the file are not supported (we act only like pread/pwrite) */ if(seek_descriptor->whence != FSAL_SEEK_SET) { *pstatus = CACHE_INODE_INVALID_ARGUMENT; V_w(&pentry->lock); /* stats */ pclient->stat.func_stats.nb_err_unrecover[statindex] += 1; return *pstatus; } /* Do we use stable or unstable storage ? */ if(stable == FSAL_UNSAFE_WRITE_TO_GANESHA_BUFFER) { /* Data will be stored in memory and not flush to FSAL */ /* If the unstable_data buffer allocated ? */ if(pentry->object.file.unstable_data.buffer == NULL) { if((pentry->object.file.unstable_data.buffer = Mem_Alloc_Label(CACHE_INODE_UNSTABLE_BUFFERSIZE, "Cache_Inode Unstable Buffer")) == NULL) { *pstatus = CACHE_INODE_MALLOC_ERROR; V_w(&pentry->lock); /* stats */ pclient->stat.func_stats.nb_err_unrecover[statindex] += 1; return *pstatus; } pentry->object.file.unstable_data.offset = seek_descriptor->offset; pentry->object.file.unstable_data.length = buffer_size; memcpy(pentry->object.file.unstable_data.buffer, buffer, buffer_size); /* Set mtime and ctime */ cache_inode_set_time_current( &pentry->attributes.mtime ) ; /* BUGAZOMEU : write operation must NOT modify file's ctime */ pentry->attributes.ctime = pentry->attributes.mtime; *pio_size = buffer_size; } /* if( pentry->object.file.unstable_data.buffer == NULL ) */ else { if((pentry->object.file.unstable_data.offset < seek_descriptor->offset) && (buffer_size + seek_descriptor->offset < CACHE_INODE_UNSTABLE_BUFFERSIZE)) { pentry->object.file.unstable_data.length = buffer_size + seek_descriptor->offset; memcpy((char *)(pentry->object.file.unstable_data.buffer + seek_descriptor->offset), buffer, buffer_size); /* Set mtime and ctime */ cache_inode_set_time_current( &pentry->attributes.mtime ) ; /* BUGAZOMEU : write operation must NOT modify file's ctime */ pentry->attributes.ctime = pentry->attributes.mtime; *pio_size = buffer_size; } else { /* Go back to regular situation */ stable = FSAL_SAFE_WRITE_TO_FS; } } } /* if( stable == FALSE ) */ if(stable == FSAL_SAFE_WRITE_TO_FS || stable == FSAL_UNSAFE_WRITE_TO_FS_BUFFER) { /* Calls file content cache to operate on the cache */ if(pentry->object.file.pentry_content != NULL) { /* Entry is data cached */ cache_content_rdwr(pentry->object.file.pentry_content, io_direction, seek_descriptor, &io_size, pio_size, buffer, p_fsal_eof, &buffstat, (cache_content_client_t *) pclient->pcontent_client, pcontext, &cache_content_status); /* If the entry under resync */ if(cache_content_status == CACHE_CONTENT_LOCAL_CACHE_NOT_FOUND) { /* Data cache gc has removed this entry */ if(cache_content_new_entry(pentry, NULL, (cache_content_client_t *)pclient->pcontent_client, RENEW_ENTRY, pcontext, &cache_content_status) == NULL) { /* Entry could not be recoverd, cache_content_status contains an error, let it be managed by the next block */ LogCrit(COMPONENT_CACHE_INODE, "Read/Write Operation through cache failed with status %d (renew process failed)", cache_content_status); /* Will go to the end of the function on the error clause with cache_content_status describing the error */ } else { /* Entry was successfully renewed */ LogInfo(COMPONENT_CACHE_INODE, "----> File Content Entry %p was successfully renewed", pentry); /* Try to access the content of the file again */ cache_content_rdwr(pentry->object.file.pentry_content, io_direction, seek_descriptor, &io_size, pio_size, buffer, p_fsal_eof, &buffstat, (cache_content_client_t *) pclient->pcontent_client, pcontext, &cache_content_status); /* No management of cache_content_status in case of failure, this will be done * within the next block */ } } if(cache_content_status != CACHE_CONTENT_SUCCESS) { *pstatus = cache_content_error_convert(cache_content_status); V_w(&pentry->lock); LogCrit(COMPONENT_CACHE_INODE, "Read/Write Operation through cache failed with status %d", cache_content_status); /* stats */ pclient->stat.func_stats.nb_err_unrecover[statindex] += 1; return *pstatus; } LogFullDebug(COMPONENT_CACHE_INODE, "cache_inode_rdwr: inode/dc: io_size=%llu, pio_size=%llu, eof=%d, seek=%d.%"PRIu64, io_size, *pio_size, *p_fsal_eof, seek_descriptor->whence, seek_descriptor->offset); LogMidDebug(COMPONENT_CACHE_INODE, "cache_inode_rdwr: INODE AFTER : IO Size = %llu %llu", io_size, *pio_size); /* Use information from the buffstat to update the file metadata */ pentry->attributes.filesize = buffstat.st_size; pentry->attributes.spaceused = buffstat.st_blksize * buffstat.st_blocks; } else { /* No data cache entry, we operated directly on FSAL */ pentry->attributes.asked_attributes = pclient->attrmask; /* We need to open if we don't have a cached * descriptor or our open flags differs. */ if(cache_inode_open(pentry, pclient, openflags, pcontext, pstatus) != CACHE_INODE_SUCCESS) { V_w(&pentry->lock); /* stats */ pclient->stat.func_stats.nb_err_unrecover[statindex] += 1; return *pstatus; } /* Call FSAL_read or FSAL_write */ if(read_or_write == CACHE_INODE_READ) { #ifdef _USE_MFSL fsal_status = MFSL_read(&(pentry->object.file.open_fd.mfsl_fd), seek_descriptor, io_size, buffer, pio_size, p_fsal_eof, &pclient->mfsl_context, NULL); #else fsal_status = FSAL_read(&(pentry->object.file.open_fd.fd), seek_descriptor, io_size, buffer, pio_size, p_fsal_eof); #endif } else { #ifdef _USE_MFSL fsal_status = MFSL_write(&(pentry->object.file.open_fd.mfsl_fd), seek_descriptor, io_size, buffer, pio_size, &pclient->mfsl_context, NULL); #else fsal_status = FSAL_write(&(pentry->object.file.open_fd.fd), seek_descriptor, io_size, buffer, pio_size); #endif #if 0 /* Alright, the unstable write is complete. Now if it was supposed to be a stable write * we can sync to the hard drive. */ if(stable == FSAL_SAFE_WRITE_TO_FS) { #ifdef _USE_MFSL fsal_status = MFSL_commit(&(pentry->object.file.open_fd.mfsl_fd), NULL); #else fsal_status = FSAL_commit(&(pentry->object.file.open_fd.fd)); #endif #endif } LogFullDebug(COMPONENT_FSAL, "cache_inode_rdwr: FSAL IO operation returned %d, asked_size=%llu, effective_size=%llu", fsal_status.major, (unsigned long long)io_size, (unsigned long long)*pio_size); if(FSAL_IS_ERROR(fsal_status)) { if(fsal_status.major == ERR_FSAL_DELAY) LogEvent(COMPONENT_CACHE_INODE, "cache_inode_rdwr: FSAL_write returned EBUSY"); else LogDebug(COMPONENT_CACHE_INODE, "cache_inode_rdwr: fsal_status.major = %d", fsal_status.major); if((fsal_status.major != ERR_FSAL_NOT_OPENED) && (pentry->object.file.open_fd.fileno != 0)) { LogDebug(COMPONENT_CACHE_INODE, "cache_inode_rdwr: CLOSING pentry %p: fd=%d", pentry, pentry->object.file.open_fd.fileno); #ifdef _USE_MFSL MFSL_close(&(pentry->object.file.open_fd.mfsl_fd), &pclient->mfsl_context, NULL); #else FSAL_close(&(pentry->object.file.open_fd.fd)); #endif *pstatus = cache_inode_error_convert(fsal_status); } else { /* the fd has been close by another thread. * return CACHE_INODE_FSAL_DELAY so the client will * retry with a new fd. */ *pstatus = CACHE_INODE_FSAL_DELAY; } pentry->object.file.open_fd.last_op = 0; pentry->object.file.open_fd.fileno = 0; V_w(&pentry->lock); /* stats */ pclient->stat.func_stats.nb_err_unrecover[statindex] += 1; return *pstatus; } LogFullDebug(COMPONENT_CACHE_INODE, "cache_inode_rdwr: inode/direct: io_size=%llu, pio_size=%llu, eof=%d, seek=%d.%"PRIu64, io_size, *pio_size, *p_fsal_eof, seek_descriptor->whence, seek_descriptor->offset); if(cache_inode_close(pentry, pclient, pstatus) != CACHE_INODE_SUCCESS) { LogEvent(COMPONENT_CACHE_INODE, "cache_inode_rdwr: cache_inode_close = %d", *pstatus); V_w(&pentry->lock); /* stats */ pclient->stat.func_stats.nb_err_unrecover[statindex] += 1; return *pstatus; } if(read_or_write == CACHE_INODE_WRITE) { /* Do a getattr in order to have update information on filesize * This query is done directly on FSAL (object is not data cached), and result * will be propagated to cache Inode */ /* WARNING: This operation is to be done AFTER FSAL_close (some FSAL, like POSIX, * may not flush data until the file is closed */ /*post_write_attr.asked_attributes = pclient->attrmask ; */ post_write_attr.asked_attributes = FSAL_ATTR_SIZE | FSAL_ATTR_SPACEUSED; fsal_status_getattr = FSAL_getattrs(&(pentry->handle), pcontext, &post_write_attr); /* if failed, the next block will handle the error */ if(FSAL_IS_ERROR(fsal_status_getattr)) fsal_status = fsal_status_getattr; else { /* Update Cache Inode attributes */ pentry->attributes.filesize = post_write_attr.filesize; pentry->attributes.spaceused = post_write_attr.spaceused; } } } /* IO was successfull (through cache content or not), we manually update the times in the attributes */ switch (read_or_write) { case CACHE_INODE_READ: /* Set the atime */ cache_inode_set_time_current( & pentry->attributes.atime ) ; break; case CACHE_INODE_WRITE: /* Set mtime and ctime */ cache_inode_set_time_current( & pentry->attributes.mtime ) ; /* BUGAZOMEU : write operation must NOT modify file's ctime */ pentry->attributes.ctime = pentry->attributes.mtime; break; } } /* if(stable == TRUE ) */ /* Return attributes to caller */ if(pfsal_attr != NULL) *pfsal_attr = pentry->attributes; *pstatus = CACHE_INODE_SUCCESS; /* stat */ if(read_or_write == CACHE_INODE_READ) { *pstatus = cache_inode_valid(pentry, CACHE_INODE_OP_GET, pclient); if(*pstatus != CACHE_INODE_SUCCESS) pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_READ] += 1; else pclient->stat.func_stats.nb_success[CACHE_INODE_READ] += 1; } else { *pstatus = cache_inode_valid(pentry, CACHE_INODE_OP_SET, pclient); if(*pstatus != CACHE_INODE_SUCCESS) pclient->stat.func_stats.nb_err_unrecover[CACHE_INODE_WRITE] += 1; else pclient->stat.func_stats.nb_success[CACHE_INODE_WRITE] += 1; } V_w(&pentry->lock); return *pstatus; } /* cache_inode_rdwr */
int _9p_readdir( _9p_request_data_t * preq9p, void * pworker_data, u32 * plenout, char * preply) { char * cursor = preq9p->_9pmsg + _9P_HDR_SIZE + _9P_TYPE_SIZE ; nfs_worker_data_t * pwkrdata = (nfs_worker_data_t *)pworker_data ; int rc = 0 ; u32 err = 0 ; u16 * msgtag = NULL ; u32 * fid = NULL ; u64 * offset = NULL ; u32 * count = NULL ; u32 dcount = 0 ; u32 recsize = 0 ; u16 name_len = 0 ; char * name_str = NULL ; u8 * qid_type = NULL ; u64 * qid_path = NULL ; char * dcount_pos = NULL ; cache_inode_status_t cache_status; cache_inode_dir_entry_t **dirent_array = NULL; cache_inode_endofdir_t eod_met; cache_entry_t * pentry_dot_dot = NULL ; cache_inode_dir_entry_t dirent_dot ; cache_inode_dir_entry_t dirent_dot_dot ; unsigned int cookie = 0; unsigned int end_cookie = 0; unsigned int estimated_num_entries = 0 ; unsigned int num_entries = 0 ; unsigned int delta = 0 ; int unlock = FALSE ; u64 i = 0LL ; if ( !preq9p || !pworker_data || !plenout || !preply ) return -1 ; _9p_fid_t * pfid = NULL ; /* Get data */ _9p_getptr( cursor, msgtag, u16 ) ; _9p_getptr( cursor, fid, u32 ) ; _9p_getptr( cursor, offset, u64 ) ; _9p_getptr( cursor, count, u32 ) ; LogDebug( COMPONENT_9P, "TREADDIR: tag=%u fid=%u offset=%llu count=%u", (u32)*msgtag, *fid, (unsigned long long)*offset, *count ) ; if( *fid >= _9P_FID_PER_CONN ) { err = ERANGE ; rc = _9p_rerror( preq9p, msgtag, &err, plenout, preply ) ; return rc ; } pfid = &preq9p->pconn->fids[*fid] ; /* Use Cache Inode to read the directory's content */ cookie = (unsigned int)*offset ; /* For each entry, returns: * qid = 13 bytes * offset = 8 bytes * type = 1 byte * namelen = 2 bytes * namestr = ~16 bytes (average size) * ------------------- * total = ~40 bytes (average size) per dentry */ estimated_num_entries = (unsigned int)( *count / 40 ) ; if((dirent_array = (cache_inode_dir_entry_t **) Mem_Alloc_Label( estimated_num_entries * sizeof(cache_inode_dir_entry_t*), "cache_inode_dir_entry_t in _9p_readdir")) == NULL) { err = EIO ; rc = _9p_rerror( preq9p, msgtag, &err, plenout, preply ) ; return rc ; } /* Is this the first request ? */ if( *offset == 0 ) { /* compute the parent entry */ if( ( pentry_dot_dot = cache_inode_lookupp( pfid->pentry, pwkrdata->ht, &pwkrdata->cache_inode_client, &pfid->fsal_op_context, &cache_status) ) == NULL ) { err = _9p_tools_errno( cache_status ) ; ; rc = _9p_rerror( preq9p, msgtag, &err, plenout, preply ) ; return rc ; } /* Deal with "." and ".." */ dirent_dot.pentry = pfid->pentry ; strcpy( dirent_dot.name.name, "." ) ; dirent_dot.name.len = strlen( dirent_dot.name.name ) ; dirent_array[0] = &dirent_dot ; dirent_dot_dot.pentry = pentry_dot_dot ; strcpy( dirent_dot_dot.name.name, ".." ) ; dirent_dot_dot.name.len = strlen( dirent_dot_dot.name.name ) ; dirent_array[1] = &dirent_dot_dot ; delta = 2 ; } else delta = 0 ; if( *offset == 2 ) { /* offset == 2 as an input as one and only reason: * - a former call with offset=0 was made and the dir was empty * - '.' and '..' were returned and nothing else * - the client makes a new call, expecting it to have empty return */ num_entries = 0 ; /* Empty return */ unlock = FALSE ; } else if(cache_inode_readdir( pfid->pentry, pfid->pexport->cache_inode_policy, cookie, estimated_num_entries - delta, &num_entries, (uint64_t *)&end_cookie, &eod_met, &dirent_array[delta], pwkrdata->ht, &unlock, &pwkrdata->cache_inode_client, &pfid->fsal_op_context, &cache_status) != CACHE_INODE_SUCCESS) { if( unlock ) V_r( &pfid->pentry->lock ) ; err = _9p_tools_errno( cache_status ) ; ; rc = _9p_rerror( preq9p, msgtag, &err, plenout, preply ) ; return rc ; } /* Unlock the directory if needed */ if( unlock ) V_r( &pfid->pentry->lock ) ; /* Never go behind _9P_MAXDIRCOUNT */ if( num_entries > _9P_MAXDIRCOUNT ) num_entries = _9P_MAXDIRCOUNT ; /* Build the reply */ _9p_setinitptr( cursor, preply, _9P_RREADDIR ) ; _9p_setptr( cursor, msgtag, u16 ) ; /* Remember dcount position for later use */ _9p_savepos( cursor, dcount_pos, u32 ) ; /* fills in the dentry in 9P marshalling */ for( i = 0 ; i < num_entries + delta ; i++ ) { recsize = 0 ; /* Build qid */ switch( dirent_array[i]->pentry->internal_md.type ) { case REGULAR_FILE: qid_path = (u64 *)&dirent_array[i]->pentry->object.file.attributes.fileid ; qid_type = &qid_type_file ; break ; case CHARACTER_FILE: case BLOCK_FILE: case SOCKET_FILE: case FIFO_FILE: qid_path = (u64 *)&dirent_array[i]->pentry->object.special_obj.attributes.fileid ; qid_type = &qid_type_file ; break ; case SYMBOLIC_LINK: qid_path = (u64 *)&dirent_array[i]->pentry->object.symlink->attributes.fileid ; qid_type = &qid_type_symlink; break ; case DIRECTORY: case FS_JUNCTION: qid_path = (u64 *)&dirent_array[i]->pentry->object.dir.attributes.fileid ; qid_type = &qid_type_dir ; break ; case UNASSIGNED: case RECYCLED: default: LogMajor( COMPONENT_9P, "implementation error, you should not see this message !!!!!!" ) ; err = EINVAL ; rc = _9p_rerror( preq9p, msgtag, &err, plenout, preply ) ; return rc ; break ; } /* Get dirent name information */ name_str = dirent_array[i]->name.name ; name_len = dirent_array[i]->name.len ; /* Add 13 bytes in recsize for qid + 8 bytes for offset + 1 for type + 2 for strlen = 24 bytes*/ recsize = 24 + name_len ; /* Check if there is room left for another dentry */ if( dcount + recsize > *count ) break ; /* exit for loop */ else dcount += recsize ; /* qid in 3 parts */ _9p_setptr( cursor, qid_type, u8 ) ; _9p_setvalue( cursor, 0, u32 ) ; /* qid_version set to 0 to prevent the client from caching */ _9p_setptr( cursor, qid_path, u64 ) ; /* offset */ _9p_setvalue( cursor, i+cookie+1, u64 ) ; /* Type (again ?) */ _9p_setptr( cursor, qid_type, u8 ) ; /* name */ _9p_setstr( cursor, name_len, name_str ) ; LogDebug( COMPONENT_9P, "RREADDIR dentry: recsize=%u dentry={ off=%llu,qid=(type=%u,version=%u,path=%llu),type=%u,name=%s,pentry=%p", recsize, (unsigned long long)i+cookie+1, *qid_type, 0, (unsigned long long)*qid_path, *qid_type, name_str, dirent_array[i]->pentry ) ; } /* for( i = 0 , ... ) */ if( !CACHE_INODE_KEEP_CONTENT( pfid->pentry->policy ) ) cache_inode_release_dirent( dirent_array, num_entries, &pwkrdata->cache_inode_client ) ; Mem_Free((char *)dirent_array); /* Set buffsize in previously saved position */ _9p_setvalue( dcount_pos, dcount, u32 ) ; _9p_setendptr( cursor, preply ) ; _9p_checkbound( cursor, preply, plenout ) ; LogDebug( COMPONENT_9P, "RREADDIR: tag=%u fid=%u dcount=%u", (u32)*msgtag, *fid , dcount ) ; return 1 ; }
int nfs4_op_readlink(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp) { cache_inode_status_t cache_status; fsal_path_t symlink_path; char __attribute__ ((__unused__)) funcname[] = "nfs4_op_readlink"; resp->resop = NFS4_OP_READLINK; res_READLINK4.status = NFS4_OK; /* If there is no FH */ if(nfs4_Is_Fh_Empty(&(data->currentFH))) { res_READLINK4.status = NFS4ERR_NOFILEHANDLE; return NFS4ERR_NOFILEHANDLE; } /* If the filehandle is invalid */ if(nfs4_Is_Fh_Invalid(&(data->currentFH))) { res_READLINK4.status = NFS4ERR_BADHANDLE; return NFS4ERR_BADHANDLE; } /* Tests if the Filehandle is expired (for volatile filehandle) */ if(nfs4_Is_Fh_Expired(&(data->currentFH))) { res_READLINK4.status = NFS4ERR_FHEXPIRED; return NFS4ERR_FHEXPIRED; } /* You can readlink only on a link ... */ if(data->current_filetype != SYMBOLIC_LINK) { /* As said on page 194 of RFC3530, return NFS4ERR_INVAL in this case */ res_READLINK4.status = NFS4ERR_INVAL; return res_READLINK4.status; } /* Using cache_inode_readlink */ if(cache_inode_readlink(data->current_entry, &symlink_path, data->ht, data->pclient, data->pcontext, &cache_status) == CACHE_INODE_SUCCESS) { /* Alloc read link */ if((res_READLINK4.READLINK4res_u.resok4.link.utf8string_val = (char *)Mem_Alloc_Label(symlink_path.len, "nfs4_op_readlink")) == NULL) { res_READLINK4.status = NFS4ERR_INVAL; return res_READLINK4.status; } /* convert the fsal path to a utf8 string */ if(str2utf8((char *)symlink_path.path, &res_READLINK4.READLINK4res_u.resok4.link) == -1) { res_READLINK4.status = NFS4ERR_INVAL; return res_READLINK4.status; } res_READLINK4.status = NFS4_OK; return res_READLINK4.status; } res_READLINK4.status = nfs4_Errno(cache_status); return res_READLINK4.status; } /* nfs4_op_readlink */
int nlm_process_parameters(struct svc_req * preq, bool_t exclusive, nlm4_lock * alock, state_lock_desc_t * plock, hash_table_t * ht, cache_entry_t ** ppentry, fsal_op_context_t * pcontext, cache_inode_client_t * pclient, care_t care, state_nsm_client_t ** ppnsm_client, state_nlm_client_t ** ppnlm_client, state_owner_t ** ppowner, state_block_data_t ** ppblock_data) { cache_inode_fsal_data_t fsal_data; fsal_attrib_list_t attr; cache_inode_status_t cache_status; SVCXPRT *ptr_svc = preq->rq_xprt; *ppnsm_client = NULL; *ppnlm_client = NULL; *ppowner = NULL; /* Convert file handle into a cache entry */ if(alock->fh.n_len > MAX_NETOBJ_SZ || !nfs3_FhandleToFSAL((nfs_fh3 *) &alock->fh, &fsal_data.handle, pcontext)) { /* handle is not valid */ return NLM4_STALE_FH; } /* Now get the cached inode attributes */ fsal_data.cookie = DIR_START; *ppentry = cache_inode_get(&fsal_data, CACHE_INODE_JOKER_POLICY, &attr, ht, pclient, pcontext, &cache_status); if(*ppentry == NULL) { /* handle is not valid */ return NLM4_STALE_FH; } *ppnsm_client = get_nsm_client(care, ptr_svc, alock->caller_name); if(*ppnsm_client == NULL) { /* If NSM Client is not found, and we don't care (such as unlock), * just return GRANTED (the unlock must succeed, there can't be * any locks). */ if(care != CARE_NOT) return NLM4_DENIED_NOLOCKS; else return NLM4_GRANTED; } *ppnlm_client = get_nlm_client(care, ptr_svc, *ppnsm_client, alock->caller_name); if(*ppnlm_client == NULL) { /* If NLM Client is not found, and we don't care (such as unlock), * just return GRANTED (the unlock must succeed, there can't be * any locks). */ dec_nsm_client_ref(*ppnsm_client); if(care != CARE_NOT) return NLM4_DENIED_NOLOCKS; else return NLM4_GRANTED; } *ppowner = get_nlm_owner(care, *ppnlm_client, &alock->oh, alock->svid); if(*ppowner == NULL) { LogDebug(COMPONENT_NLM, "Could not get NLM Owner"); dec_nsm_client_ref(*ppnsm_client); dec_nlm_client_ref(*ppnlm_client); *ppnlm_client = NULL; /* If owner is not found, and we don't care (such as unlock), * just return GRANTED (the unlock must succeed, there can't be * any locks). */ if(care) return NLM4_DENIED_NOLOCKS; else return NLM4_GRANTED; } if(ppblock_data != NULL) { *ppblock_data = (state_block_data_t *) Mem_Alloc_Label(sizeof(**ppblock_data), "NLM_Block_Data"); /* Fill in the block data, if we don't get one, we will just proceed * without (which will mean the lock doesn't block. */ if(*ppblock_data != NULL) { memset(*ppblock_data, 0, sizeof(**ppblock_data)); if(copy_xprt_addr(&(*ppblock_data)->sbd_block_data.sbd_nlm_block_data.sbd_nlm_hostaddr, ptr_svc) == 0) { LogFullDebug(COMPONENT_NLM, "copy_xprt_addr failed for Program %d, Version %d, Function %d", (int)preq->rq_prog, (int)preq->rq_vers, (int)preq->rq_proc); Mem_Free(*ppblock_data); *ppblock_data = NULL; return NLM4_FAILED; } (*ppblock_data)->sbd_granted_callback = nlm_granted_callback; (*ppblock_data)->sbd_block_data.sbd_nlm_block_data.sbd_nlm_fh.n_bytes = (*ppblock_data)->sbd_block_data.sbd_nlm_block_data.sbd_nlm_fh_buf; (*ppblock_data)->sbd_block_data.sbd_nlm_block_data.sbd_nlm_fh.n_len = alock->fh.n_len; memcpy((*ppblock_data)->sbd_block_data.sbd_nlm_block_data.sbd_nlm_fh_buf, alock->fh.n_bytes, alock->fh.n_len); /* FSF TODO: Ultimately I think the following will go away, we won't need the context, just the export */ /* Copy credentials from pcontext */ (*ppblock_data)->sbd_block_data.sbd_nlm_block_data.sbd_credential = pcontext->credential; } } /* Fill in plock */ plock->sld_type = exclusive ? STATE_LOCK_W : STATE_LOCK_R; plock->sld_offset = alock->l_offset; plock->sld_length = alock->l_len; LogFullDebug(COMPONENT_NLM, "Parameters Processed"); return -1; }
SVCXPRT *Svcudp_bufcreate(register int sock, u_int sendsz, u_int recvsz) { bool_t madesock = FALSE; register SVCXPRT *xprt; register struct Svcudp_data *su; struct sockaddr_in addr; unsigned long len = sizeof(struct sockaddr_in); if(sock == RPC_ANYSOCK) { if((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { perror("Svcudp_create: socket creation problem"); return ((SVCXPRT *) NULL); } madesock = TRUE; } memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; if(bindresvport(sock, &addr)) { addr.sin_port = 0; (void)bind(sock, (struct sockaddr *)&addr, len); } if(getsockname(sock, (struct sockaddr *)&addr, (socklen_t *) & len) != 0) { perror("Svcudp_create - cannot getsockname"); if(madesock) (void)close(sock); return ((SVCXPRT *) NULL); } xprt = (SVCXPRT *) Mem_Alloc_Label(sizeof(SVCXPRT), "SVCXPRT (UDP)"); if(xprt == NULL) { return (NULL); } su = (struct Svcudp_data *)Mem_Alloc_Label(sizeof(*su), "struct Svcudp_data"); if(su == NULL) { Mem_Free( xprt ) ; return (NULL); } su->su_iosz = ((MAX(sendsz, recvsz) + 3) / 4) * 4; if((rpc_buffer(xprt) = Mem_Alloc_Label(su->su_iosz, "UDP IO Buffer")) == NULL) { Mem_Free( su ) ; Mem_Free( xprt ) ; return (NULL); } xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), su->su_iosz, XDR_DECODE); xprt->xp_p2 = (caddr_t) su; xprt->xp_verf.oa_base = su->su_verfbody; xprt->xp_ops = &Svcudp_op; xprt->xp_port = ntohs(addr.sin_port); xprt->XP_SOCK = sock; Xprt_register(xprt); return (xprt); }
cache_inode_status_t cache_inode_open_by_name(cache_entry_t * pentry_dir, fsal_name_t * pname, cache_entry_t * pentry_file, cache_inode_client_t * pclient, fsal_openflags_t openflags, fsal_op_context_t * pcontext, cache_inode_status_t * pstatus) { fsal_status_t fsal_status; fsal_size_t save_filesize = 0; fsal_size_t save_spaceused = 0; fsal_time_t save_mtime = { .seconds = 0, .nseconds = 0 }; if((pentry_dir == NULL) || (pname == NULL) || (pentry_file == NULL) || (pclient == NULL) || (pcontext == NULL) || (pstatus == NULL)) return CACHE_INODE_INVALID_ARGUMENT; if((pentry_dir->internal_md.type != DIRECTORY)) { *pstatus = CACHE_INODE_BAD_TYPE; return *pstatus; } if(pentry_file->internal_md.type != REGULAR_FILE) { *pstatus = CACHE_INODE_BAD_TYPE; return *pstatus; } /* Open file need to be closed, unless it is already open as read/write */ if((pentry_file->object.file.open_fd.openflags != FSAL_O_RDWR) && (pentry_file->object.file.open_fd.openflags != 0) && (pentry_file->object.file.open_fd.fileno >= 0) && (pentry_file->object.file.open_fd.openflags != openflags)) { #ifdef _USE_MFSL fsal_status = MFSL_close(&(pentry_file->object.file.open_fd.mfsl_fd), &pclient->mfsl_context, NULL); #else fsal_status = FSAL_close(&(pentry_file->object.file.open_fd.fd)); #endif if(FSAL_IS_ERROR(fsal_status) && (fsal_status.major != ERR_FSAL_NOT_OPENED)) { *pstatus = cache_inode_error_convert(fsal_status); LogDebug(COMPONENT_CACHE_INODE, "cache_inode_open_by_name: returning %d(%s) from FSAL_close", *pstatus, cache_inode_err_str(*pstatus)); return *pstatus; } pentry_file->object.file.open_fd.last_op = 0; pentry_file->object.file.open_fd.fileno = 0; } if(pentry_file->object.file.open_fd.last_op == 0 || pentry_file->object.file.open_fd.fileno == 0) { LogDebug(COMPONENT_FSAL, "cache_inode_open_by_name: pentry %p: lastop=0", pentry_file); /* Keep coherency with the cache_content */ if(pentry_file->object.file.pentry_content != NULL) { save_filesize = pentry_file->object.file.attributes.filesize; save_spaceused = pentry_file->object.file.attributes.spaceused; save_mtime = pentry_file->object.file.attributes.mtime; } /* opened file is not preserved yet */ #ifdef _USE_MFSL fsal_status = MFSL_open_by_name(&(pentry_dir->mobject), pname, pcontext, &pclient->mfsl_context, openflags, &pentry_file->object.file.open_fd.mfsl_fd, &(pentry_file->object.file.attributes), #ifdef _USE_PNFS &pentry_file->object.file.pnfs_file ) ; #else NULL ); #endif /* _USE_PNFS */ #else fsal_status = FSAL_open_by_name(&(pentry_dir->object.file.handle), pname, pcontext, openflags, &pentry_file->object.file.open_fd.fd, &(pentry_file->object.file.attributes)); #endif if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); LogDebug(COMPONENT_CACHE_INODE, "cache_inode_open_by_name: returning %d(%s) from FSAL_open_by_name", *pstatus, cache_inode_err_str(*pstatus)); return *pstatus; } #ifdef _USE_PROXY /* If proxy if used, we should keep the name of the file to do FSAL_rcp if needed */ if((pentry_file->object.file.pname = (fsal_name_t *) Mem_Alloc_Label(sizeof(fsal_name_t), "fsal_name_t")) == NULL) { *pstatus = CACHE_INODE_MALLOC_ERROR; return *pstatus; } pentry_file->object.file.pentry_parent_open = pentry_dir; pentry_file->object.file.pname->len = pname->len; memcpy((char *)(pentry_file->object.file.pname->name), (char *)(pname->name), FSAL_MAX_NAME_LEN); #endif /* Keep coherency with the cache_content */ if(pentry_file->object.file.pentry_content != NULL) { pentry_file->object.file.attributes.filesize = save_filesize; pentry_file->object.file.attributes.spaceused = save_spaceused; pentry_file->object.file.attributes.mtime = save_mtime; } #ifdef _USE_MFSL pentry_file->object.file.open_fd.fileno = (int)FSAL_FILENO(&(pentry_file->object.file.open_fd.mfsl_fd.fsal_file)); #else pentry_file->object.file.open_fd.fileno = (int)FSAL_FILENO(&(pentry_file->object.file.open_fd.fd)); #endif pentry_file->object.file.open_fd.last_op = time(NULL); pentry_file->object.file.open_fd.openflags = openflags; LogDebug(COMPONENT_FSAL, "cache_inode_open_by_name: pentry %p: fd=%u", pentry_file, pentry_file->object.file.open_fd.fileno); } /* regular exit */ pentry_file->object.file.open_fd.last_op = time(NULL); /* if file descriptor is too high, garbage collect FDs */ if(pclient->use_fd_cache && (pentry_file->object.file.open_fd.fileno > pclient->max_fd)) { if(cache_inode_gc_fd(pclient, pstatus) != CACHE_INODE_SUCCESS) { LogCrit(COMPONENT_CACHE_INODE_GC, "FAILURE performing FD garbage collection"); return *pstatus; } } *pstatus = CACHE_INODE_SUCCESS; return *pstatus; } /* cache_inode_open_by_name */
int nfs3_Readdirplus(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[] = "nfs3_Readdirplus"; typedef char entry_name_array_item_t[FSAL_MAX_NAME_LEN]; typedef char fh3_buffer_item_t[NFS3_FHSIZE]; unsigned int delta = 0; cache_entry_t *dir_pentry = NULL; cache_entry_t *pentry_dot_dot = NULL; unsigned long dircount; unsigned long maxcount; fsal_attrib_list_t dir_attr; fsal_attrib_list_t entry_attr; uint64_t begin_cookie; uint64_t end_cookie; uint64_t cache_inode_cookie; cache_inode_dir_entry_t **dirent_array = NULL; cookieverf3 cookie_verifier; int rc; unsigned int i = 0; unsigned int num_entries; unsigned long space_used; unsigned long estimated_num_entries; unsigned long asked_num_entries; cache_inode_file_type_t dir_filetype; cache_inode_endofdir_t eod_met = UNASSIGNED_EOD; cache_inode_status_t cache_status; cache_inode_status_t cache_status_gethandle; fsal_handle_t *pfsal_handle = NULL; entry_name_array_item_t *entry_name_array = NULL; fh3_buffer_item_t *fh3_array = NULL; entryplus3 reference_entry; READDIRPLUS3resok reference_reply; int dir_pentry_unlock = FALSE; if(isDebug(COMPONENT_NFSPROTO) || isDebug(COMPONENT_NFS_READDIR)) { char str[LEN_FH_STR]; log_components_t component; sprint_fhandle3(str, &(parg->arg_readdirplus3.dir)); if(isDebug(COMPONENT_NFSPROTO)) component = COMPONENT_NFSPROTO; else component = COMPONENT_NFS_READDIR; LogDebug(component, "REQUEST PROCESSING: Calling nfs3_Readdirplus handle: %s", str); } /* to avoid setting it on each error case */ pres->res_readdir3.READDIR3res_u.resfail.dir_attributes.attributes_follow = FALSE; dircount = parg->arg_readdirplus3.dircount; maxcount = parg->arg_readdirplus3.maxcount; begin_cookie = (unsigned int)parg->arg_readdirplus3.cookie; /* FIXME: This calculation over estimates the number of bytes that * READDIRPLUS3resok will use on the wire by 4 bytes on x86_64. */ space_used = sizeof(reference_reply.dir_attributes.attributes_follow) + sizeof(reference_reply.dir_attributes.post_op_attr_u.attributes) + sizeof(reference_reply.cookieverf) + sizeof(reference_reply.reply.eof); estimated_num_entries = (dircount - space_used + sizeof(entry3 *)) / (sizeof(entry3) - sizeof(char *)*2); // estimated_num_entries *= 4; LogFullDebug(COMPONENT_NFS_READDIR, "nfs3_Readdirplus: dircount=%lu maxcount=%lu begin_cookie=%" PRIu64" space_used=%lu estimated_num_entries=%lu", dircount, maxcount, begin_cookie, space_used, estimated_num_entries); /* Is this a xattr FH ? */ if(nfs3_Is_Fh_Xattr(&(parg->arg_readdirplus3.dir))) return nfs3_Readdirplus_Xattr(parg, pexport, pcontext, pclient, ht, preq, pres); /* Convert file handle into a vnode */ if((dir_pentry = nfs_FhandleToCache(preq->rq_vers, NULL, &(parg->arg_readdirplus3.dir), NULL, NULL, &(pres->res_readdirplus3.status), NULL, &dir_attr, pcontext, pclient, ht, &rc)) == NULL) { /* return NFS_REQ_DROP ; */ return rc; } /* Extract the filetype */ dir_filetype = cache_inode_fsal_type_convert(dir_attr.type); /* Sanity checks -- must be a directory */ if(dir_filetype != DIRECTORY) { pres->res_readdirplus3.status = NFS3ERR_NOTDIR; return NFS_REQ_OK; } /* switch */ memset(cookie_verifier, 0, sizeof(cookieverf3)); /* * If cookie verifier is used, then an non-trivial value is * returned to the client This value is the mtime of * the directory. If verifier is unused (as in many NFS * Servers) then only a set of zeros is returned (trivial * value) */ if(pexport->UseCookieVerifier) memcpy(cookie_verifier, &(dir_attr.mtime), sizeof(dir_attr.mtime)); /* * nothing to do if != 0 because the area is already full of * zero */ if(pexport->UseCookieVerifier && (begin_cookie != 0)) { /* * Not the first call, so we have to check the cookie * verifier */ if(memcmp(cookie_verifier, parg->arg_readdirplus3.cookieverf, NFS3_COOKIEVERFSIZE) != 0) { pres->res_readdirplus3.status = NFS3ERR_BAD_COOKIE; return NFS_REQ_OK; } } if((dirent_array = (cache_inode_dir_entry_t **) Mem_Alloc_Label( estimated_num_entries * sizeof(cache_inode_dir_entry_t*), "cache_inode_dir_entry_t in nfs3_Readdirplus")) == NULL) { pres->res_readdirplus3.status = NFS3ERR_IO; return NFS_REQ_DROP; } pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries = NULL; pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.eof = FALSE; /** @todo XXXX fix this--compare nfs4_op_readdir */ /* How many entries will we retry from cache_inode ? */ if(begin_cookie > 1) { asked_num_entries = estimated_num_entries; cache_inode_cookie = begin_cookie; } else { asked_num_entries = ((estimated_num_entries > 2) ? estimated_num_entries - 2 : 0); /* Keep space for '.' and '..' */ cache_inode_cookie = 0; } /* A definition that will be very useful to avoid very long names for variables */ #define RES_READDIRPLUS_REPLY pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply /* Call readdir */ if(cache_inode_readdir(dir_pentry, pexport->cache_inode_policy, cache_inode_cookie, asked_num_entries, &num_entries, &end_cookie, &eod_met, dirent_array, ht, &dir_pentry_unlock, pclient, pcontext, &cache_status) == CACHE_INODE_SUCCESS) { LogFullDebug(COMPONENT_NFS_READDIR, "Readdirplus3 -> Call to cache_inode_readdir( cookie=%" PRIu64", asked=%lu ) -> num_entries = %u", cache_inode_cookie, asked_num_entries, num_entries); if(eod_met == END_OF_DIR) { LogFullDebug(COMPONENT_NFS_READDIR, "+++++++++++++++++++++++++++++++++++++++++> EOD MET "); } /* If nothing was found, return nothing, but if cookie=0, we should return . and .. */ if((num_entries == 0) && (asked_num_entries != 0) && (begin_cookie > 1)) { pres->res_readdirplus3.status = NFS3_OK; pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries = NULL; pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.eof = TRUE; nfs_SetPostOpAttr(pcontext, pexport, dir_pentry, NULL, &(pres->res_readdirplus3.READDIRPLUS3res_u.resok. dir_attributes)); memcpy(pres->res_readdirplus3.READDIRPLUS3res_u.resok.cookieverf, cookie_verifier, sizeof(cookieverf3)); } else { /* Allocation of the structure for reply */ entry_name_array = (entry_name_array_item_t *) Mem_Alloc_Label(estimated_num_entries * (FSAL_MAX_NAME_LEN + 1), "entry_name_array in nfs3_Readdirplus"); if(entry_name_array == NULL) { /* after successful cache_inode_readdir, dir_pentry may be * read locked */ if (dir_pentry_unlock) V_r(&dir_pentry->lock); if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) cache_inode_release_dirent( dirent_array, num_entries, pclient ) ; Mem_Free((char *)dirent_array); return NFS_REQ_DROP; } pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries = (entryplus3 *) Mem_Alloc_Label(estimated_num_entries * sizeof(entryplus3), "READDIRPLUS3res_u.resok.reply.entries"); if(pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries == NULL) { /* after successful cache_inode_readdir, dir_pentry may be * read locked */ if (dir_pentry_unlock) V_r(&dir_pentry->lock); if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) cache_inode_release_dirent( dirent_array, num_entries, pclient ) ; Mem_Free((char *)dirent_array); Mem_Free((char *)entry_name_array); return NFS_REQ_DROP; } /* Allocation of the file handles */ fh3_array = (fh3_buffer_item_t *) Mem_Alloc_Label(estimated_num_entries * NFS3_FHSIZE, "Filehandle V3 in nfs3_Readdirplus"); if(fh3_array == NULL) { /* after successful cache_inode_readdir, dir_pentry may be * read locked */ if (dir_pentry_unlock) V_r(&dir_pentry->lock); if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) cache_inode_release_dirent( dirent_array, num_entries, pclient ) ; Mem_Free((char *)dirent_array); Mem_Free((char *)entry_name_array); return NFS_REQ_DROP; } delta = 0; /* manage . and .. */ if(begin_cookie == 0) { /* Fill in '.' */ if(estimated_num_entries > 0) { if((pfsal_handle = cache_inode_get_fsal_handle(dir_pentry, &cache_status_gethandle)) == NULL) { /* after successful cache_inode_readdir, dir_pentry * may be read locked */ if (dir_pentry_unlock) V_r(&dir_pentry->lock); if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) cache_inode_release_dirent( dirent_array, num_entries, pclient ) ; Mem_Free((char *)dirent_array); Mem_Free((char *)entry_name_array); Mem_Free((char *)fh3_array); pres->res_readdirplus3.status = nfs3_Errno(cache_status_gethandle); return NFS_REQ_OK; } FSAL_DigestHandle(FSAL_GET_EXP_CTX(pcontext), FSAL_DIGEST_FILEID3, pfsal_handle, (caddr_t) & (RES_READDIRPLUS_REPLY.entries[0]. fileid)); RES_READDIRPLUS_REPLY.entries[0].name = entry_name_array[0]; strcpy(RES_READDIRPLUS_REPLY.entries[0].name, "."); RES_READDIRPLUS_REPLY.entries[0].cookie = 1; pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[0]. name_handle.post_op_fh3_u.handle.data.data_val = (char *)fh3_array[0]; if(nfs3_FSALToFhandle (&pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[0]. name_handle.post_op_fh3_u.handle, pfsal_handle, pexport) == 0) { /* after successful cache_inode_readdir, dir_pentry may * be read locked */ if (dir_pentry_unlock) V_r(&dir_pentry->lock); if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) cache_inode_release_dirent( dirent_array, num_entries, pclient ) ; Mem_Free((char *)dirent_array); Mem_Free((char *)entry_name_array); Mem_Free((char *)fh3_array); pres->res_readdirplus3.status = NFS3ERR_BADHANDLE; return NFS_REQ_OK; } RES_READDIRPLUS_REPLY.entries[0].name_attributes.attributes_follow = FALSE; RES_READDIRPLUS_REPLY.entries[0].name_handle.handle_follows = FALSE; entry_attr = dir_pentry->attributes; /* Set PostPoFh3 structure */ pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[0]. name_handle.handle_follows = TRUE; pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[0]. name_handle.post_op_fh3_u.handle.data.data_len = sizeof(file_handle_v3_t); nfs_SetPostOpAttr(pcontext, pexport, dir_pentry, &entry_attr, &(pres->res_readdirplus3.READDIRPLUS3res_u.resok. reply.entries[0].name_attributes)); LogFullDebug(COMPONENT_NFS_READDIR, "Readdirplus3 -> i=0 num_entries=%d space_used=%lu maxcount=%lu Name=. FileId=%016llx Cookie=%llu", num_entries, space_used, maxcount, RES_READDIRPLUS_REPLY.entries[0].fileid, RES_READDIRPLUS_REPLY.entries[0].cookie); delta += 1; } } /* Fill in '..' */ if(begin_cookie <= 1) { if(estimated_num_entries > delta) { if((pentry_dot_dot = cache_inode_lookupp_sw(dir_pentry, ht, pclient, pcontext, &cache_status_gethandle, !dir_pentry_unlock)) == NULL) { /* after successful cache_inode_readdir, dir_pentry may * be read locked */ if (dir_pentry_unlock) V_r(&dir_pentry->lock); if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) cache_inode_release_dirent( dirent_array, num_entries, pclient ) ; Mem_Free((char *)dirent_array); Mem_Free((char *)entry_name_array); Mem_Free((char *)fh3_array); pres->res_readdirplus3.status = nfs3_Errno(cache_status_gethandle); return NFS_REQ_OK; } if((pfsal_handle = cache_inode_get_fsal_handle(pentry_dot_dot, &cache_status_gethandle)) == NULL) { /* after successful cache_inode_readdir, dir_pentry may * be read locked */ if (dir_pentry_unlock) V_r(&dir_pentry->lock); if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) cache_inode_release_dirent( dirent_array, num_entries, pclient ) ; Mem_Free((char *)dirent_array); Mem_Free((char *)entry_name_array); Mem_Free((char *)fh3_array); pres->res_readdirplus3.status = nfs3_Errno(cache_status_gethandle); return NFS_REQ_OK; } FSAL_DigestHandle(FSAL_GET_EXP_CTX(pcontext), FSAL_DIGEST_FILEID3, pfsal_handle, (caddr_t) & (RES_READDIRPLUS_REPLY.entries[delta]. fileid)); RES_READDIRPLUS_REPLY.entries[delta].name = entry_name_array[delta]; strcpy(RES_READDIRPLUS_REPLY.entries[delta].name, ".."); /* Getting a file handle */ pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[delta]. name_handle.post_op_fh3_u.handle.data.data_val = (char *)fh3_array[delta]; if(nfs3_FSALToFhandle (&pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[delta]. name_handle.post_op_fh3_u.handle, pfsal_handle, pexport) == 0) { /* after successful cache_inode_readdir, dir_pentry may * be read locked */ if (dir_pentry_unlock) V_r(&dir_pentry->lock); if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) cache_inode_release_dirent( dirent_array, num_entries, pclient ) ; Mem_Free((char *)dirent_array); Mem_Free((char *)entry_name_array); Mem_Free((char *)fh3_array); pres->res_readdirplus3.status = NFS3ERR_BADHANDLE; return NFS_REQ_OK; } RES_READDIRPLUS_REPLY.entries[delta].cookie = 2; RES_READDIRPLUS_REPLY.entries[delta].name_attributes.attributes_follow = FALSE; RES_READDIRPLUS_REPLY.entries[delta].name_handle.handle_follows = FALSE; entry_attr = pentry_dot_dot->attributes; /* Set PostPoFh3 structure */ pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[delta]. name_handle.handle_follows = TRUE; pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[delta]. name_handle.post_op_fh3_u.handle.data.data_len = sizeof(file_handle_v3_t); nfs_SetPostOpAttr(pcontext, pexport, pentry_dot_dot, &entry_attr, &(pres->res_readdirplus3.READDIRPLUS3res_u.resok. reply.entries[delta].name_attributes)); LogFullDebug(COMPONENT_NFS_READDIR, "Readdirplus3 -> i=%d num_entries=%d space_used=%lu maxcount=%lu Name=.. FileId=%016llx Cookie=%llu", delta, num_entries, space_used, maxcount, RES_READDIRPLUS_REPLY.entries[delta].fileid, RES_READDIRPLUS_REPLY.entries[delta].cookie); } RES_READDIRPLUS_REPLY.entries[0].nextentry = &(RES_READDIRPLUS_REPLY.entries[delta]); if(num_entries > delta + 1) /* not 0 ??? */ RES_READDIRPLUS_REPLY.entries[delta].nextentry = &(RES_READDIRPLUS_REPLY.entries[delta + 1]); else RES_READDIRPLUS_REPLY.entries[delta].nextentry = NULL; delta += 1; } /* if( begin_cookie == 0 ) */ for(i = delta; i < num_entries + delta; i++) { unsigned long needed; /* maxcount is the size with the FH and attributes overhead, * so entryplus3 is used instead of entry3. The data structures * in nfs23.h have funny padding depending on the arch (32 or 64). * We can't get an accurate estimate by simply using * sizeof(entryplus3). */ /* FIXME: There is still a 4 byte over estimate here on x86_64. */ /** @todo Remove cookie offset calculation in readdir and readdirplus (obsoleted) */ needed = sizeof(reference_entry) + NFS3_FHSIZE + ((strlen(dirent_array[i - delta]->name.name) + 3) & ~3); /* if delta == 1 or 2, then "." and ".." have already been added * to the readdirplus reply. */ if (i == delta) { needed += needed*delta /* size of a dir entry in reply */ - ((strlen(dirent_array[i - delta]->name.name) + 3) & ~3)*delta /* size of filename for current entry */ + 4*delta; /* size of "." and ".." filenames in reply */ } if((space_used += needed) > maxcount) { /* If delta != 0, then we already added "." or ".." to the reply. */ if(i == delta && delta == 0) { /* Not enough room to make even a single reply */ /* after successful cache_inode_readdir, dir_pentry may * be read locked */ if (dir_pentry_unlock) V_r(&dir_pentry->lock); if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) cache_inode_release_dirent( dirent_array, num_entries, pclient ) ; Mem_Free((char *)dirent_array); Mem_Free((char *)entry_name_array); Mem_Free((char *)fh3_array); pres->res_readdirplus3.status = NFS3ERR_TOOSMALL; return NFS_REQ_OK; } break; /* Make post traitement */ } /* * Get information specific to this entry */ if((pfsal_handle = cache_inode_get_fsal_handle(dirent_array[i - delta]->pentry, &cache_status_gethandle)) == NULL) { /* after successful cache_inode_readdir, dir_pentry may be * read locked */ if (dir_pentry_unlock) V_r(&dir_pentry->lock); if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) cache_inode_release_dirent( dirent_array, num_entries, pclient ) ; Mem_Free((char *)dirent_array); Mem_Free((char *)entry_name_array); Mem_Free((char *)fh3_array); pres->res_readdirplus3.status = nfs3_Errno(cache_status_gethandle); return NFS_REQ_OK; } /* Now fill in the replyed entryplus3 list */ FSAL_DigestHandle(FSAL_GET_EXP_CTX(pcontext), FSAL_DIGEST_FILEID3, pfsal_handle, (caddr_t) & (RES_READDIRPLUS_REPLY.entries[i].fileid)); FSAL_name2str(&dirent_array[i - delta]->name, entry_name_array[i], FSAL_MAX_NAME_LEN); RES_READDIRPLUS_REPLY.entries[i].name = entry_name_array[i]; LogFullDebug(COMPONENT_NFS_READDIR, "Readdirplus3 -> i=%u num_entries=%u delta=%u " "num_entries + delta - 1=%u end_cookie=%"PRIu64, i, num_entries, delta, num_entries + delta - 1, end_cookie); if(i != num_entries + delta - 1) RES_READDIRPLUS_REPLY.entries[i].cookie = dirent_array[i - delta]->cookie; else RES_READDIRPLUS_REPLY.entries[i].cookie = end_cookie; RES_READDIRPLUS_REPLY.entries[i].name_attributes.attributes_follow = FALSE; RES_READDIRPLUS_REPLY.entries[i].name_handle.handle_follows = FALSE; entry_attr = dirent_array[i - delta]->pentry->attributes; pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[i].name_handle.post_op_fh3_u.handle.data.data_val = (char *)fh3_array[i]; /* Compute the NFSv3 file handle */ if(nfs3_FSALToFhandle (&pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[i]. name_handle.post_op_fh3_u.handle, pfsal_handle, pexport) == 0) { /* after successful cache_inode_readdir, dir_pentry may be * read locked */ if (dir_pentry_unlock) V_r(&dir_pentry->lock); if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) cache_inode_release_dirent( dirent_array, num_entries, pclient ) ; Mem_Free((char *)dirent_array); Mem_Free((char *)entry_name_array); Mem_Free((char *)fh3_array); pres->res_readdirplus3.status = NFS3ERR_BADHANDLE; return NFS_REQ_OK; } /* Set PostPoFh3 structure */ pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[i].name_handle.handle_follows = TRUE; pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[i].name_handle.post_op_fh3_u.handle.data.data_len = sizeof(file_handle_v3_t); nfs_SetPostOpAttr(pcontext, pexport, dirent_array[i - delta]->pentry, &entry_attr, &(pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.entries[i].name_attributes)); LogFullDebug(COMPONENT_NFS_READDIR, "Readdirplus3 -> i=%d, num_entries=%d needed=%lu space_used=%lu maxcount=%lu Name=%s FileId=%016llx Cookie=%llu", i, num_entries, needed, space_used, maxcount, dirent_array[i - delta]->name.name, RES_READDIRPLUS_REPLY.entries[i].fileid, RES_READDIRPLUS_REPLY.entries[i].cookie); RES_READDIRPLUS_REPLY.entries[i].nextentry = NULL; if(i != 0) RES_READDIRPLUS_REPLY.entries[i - 1].nextentry = &(RES_READDIRPLUS_REPLY.entries[i]); } pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.eof = FALSE; } nfs_SetPostOpAttr(pcontext, pexport, dir_pentry, &dir_attr, &(pres->res_readdirplus3.READDIRPLUS3res_u.resok.dir_attributes)); memcpy(pres->res_readdirplus3.READDIRPLUS3res_u.resok.cookieverf, cookie_verifier, sizeof(cookieverf3)); pres->res_readdirplus3.status = NFS3_OK; if((eod_met == END_OF_DIR) && (i == num_entries + delta)) { /* End of directory */ LogFullDebug(COMPONENT_NFS_READDIR, "============================================================> EOD MET !!!!!!"); pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.eof = TRUE; } else pres->res_readdirplus3.READDIRPLUS3res_u.resok.reply.eof = FALSE; nfs_SetPostOpAttr(pcontext, pexport, dir_pentry, &dir_attr, &(pres->res_readdirplus3.READDIRPLUS3res_u.resok.dir_attributes)); memcpy(pres->res_readdirplus3.READDIRPLUS3res_u.resok.cookieverf, cookie_verifier, sizeof(cookieverf3)); LogFullDebug(COMPONENT_NFS_READDIR, "============================================================"); /* after successful cache_inode_readdir, dir_pentry may be * read locked */ if (dir_pentry_unlock) V_r(&dir_pentry->lock); /* Free the memory */ if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) cache_inode_release_dirent( dirent_array, num_entries, pclient ) ; Mem_Free((char *)dirent_array); return NFS_REQ_OK; } /* If we are here, there was an error */ /* after successful cache_inode_readdir, dir_pentry may be * read locked */ if (dir_pentry_unlock) V_r(&dir_pentry->lock); /* Free the memory */ if( !CACHE_INODE_KEEP_CONTENT( dir_pentry->policy ) ) cache_inode_release_dirent( dirent_array, num_entries, pclient ) ; Mem_Free((char *)dirent_array); Mem_Free((char *)entry_name_array); Mem_Free((char *)fh3_array); /* Is this a retryable error */ if(nfs_RetryableError(cache_status)) return NFS_REQ_DROP; /* Set failed status */ nfs_SetFailedStatus(pcontext, pexport, NFS_V3, cache_status, NULL, &pres->res_readdirplus3.status, dir_pentry, &(pres->res_readdirplus3.READDIRPLUS3res_u.resfail.dir_attributes), NULL, NULL, NULL, NULL, NULL, NULL); return NFS_REQ_OK; } /* nfs3_Readdirplus */
cache_inode_status_t cache_inode_open_by_name(cache_entry_t * pentry_dir, fsal_name_t * pname, cache_entry_t * pentry_file, cache_inode_client_t * pclient, fsal_openflags_t openflags, fsal_op_context_t * pcontext, cache_inode_status_t * pstatus) { fsal_status_t fsal_status; fsal_size_t save_filesize = 0; fsal_size_t save_spaceused = 0; fsal_time_t save_mtime = { .seconds = 0, .nseconds = 0 }; if((pentry_dir == NULL) || (pname == NULL) || (pentry_file == NULL) || (pclient == NULL) || (pcontext == NULL) || (pstatus == NULL)) return CACHE_INODE_INVALID_ARGUMENT; if((pentry_dir->internal_md.type != DIRECTORY)) { *pstatus = CACHE_INODE_BAD_TYPE; return *pstatus; } if(pentry_file->internal_md.type != REGULAR_FILE) { *pstatus = CACHE_INODE_BAD_TYPE; return *pstatus; } /* Open file need to be closed, unless it is already open as read/write */ if((pentry_file->object.file.open_fd.openflags != FSAL_O_RDWR) && (pentry_file->object.file.open_fd.openflags != 0) && (pentry_file->object.file.open_fd.fileno != 0) && (pentry_file->object.file.open_fd.openflags != openflags)) { #ifdef _USE_MFSL fsal_status = MFSL_close(&(pentry_file->object.file.open_fd.mfsl_fd), &pclient->mfsl_context, NULL); #else fsal_status = FSAL_close(&(pentry_file->object.file.open_fd.fd)); #endif if(FSAL_IS_ERROR(fsal_status) && (fsal_status.major != ERR_FSAL_NOT_OPENED)) { *pstatus = cache_inode_error_convert(fsal_status); LogDebug(COMPONENT_CACHE_INODE, "cache_inode_open_by_name: returning %d(%s) from FSAL_close", *pstatus, cache_inode_err_str(*pstatus)); return *pstatus; } pentry_file->object.file.open_fd.last_op = 0; pentry_file->object.file.open_fd.fileno = 0; } if(pentry_file->object.file.open_fd.last_op == 0 || pentry_file->object.file.open_fd.fileno == 0) { LogFullDebug(COMPONENT_FSAL, "cache_inode_open_by_name: pentry %p: lastop=0", pentry_file); /* Keep coherency with the cache_content */ if(pentry_file->object.file.pentry_content != NULL) { save_filesize = pentry_file->attributes.filesize; save_spaceused = pentry_file->attributes.spaceused; save_mtime = pentry_file->attributes.mtime; } /* opened file is not preserved yet */ #ifdef _USE_MFSL fsal_status = MFSL_open_by_name(&(pentry_dir->mobject), pname, pcontext, &pclient->mfsl_context, openflags, &pentry_file->object.file.open_fd.mfsl_fd, &(pentry_file->attributes), NULL ); #else fsal_status = FSAL_open_by_name(&(pentry_dir->handle), pname, pcontext, openflags, &pentry_file->object.file.open_fd.fd, &(pentry_file->attributes)); #endif if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); LogDebug(COMPONENT_CACHE_INODE, "cache_inode_open_by_name: returning %d(%s) from FSAL_open_by_name", *pstatus, cache_inode_err_str(*pstatus)); return *pstatus; } #ifdef _USE_PROXY /* If proxy if used, we should keep the name of the file to do FSAL_rcp if needed */ if((pentry_file->object.file.pname = (fsal_name_t *) Mem_Alloc_Label(sizeof(fsal_name_t), "fsal_name_t")) == NULL) { *pstatus = CACHE_INODE_MALLOC_ERROR; return *pstatus; } pentry_file->object.file.pentry_parent_open = pentry_dir; pentry_file->object.file.pname->len = pname->len; memcpy((char *)(pentry_file->object.file.pname->name), (char *)(pname->name), FSAL_MAX_NAME_LEN); #endif /* Keep coherency with the cache_content */ if(pentry_file->object.file.pentry_content != NULL) { pentry_file->attributes.filesize = save_filesize; pentry_file->attributes.spaceused = save_spaceused; pentry_file->attributes.mtime = save_mtime; } #ifdef _USE_MFSL pentry_file->object.file.open_fd.fileno = (int)FSAL_FILENO(&(pentry_file->object.file.open_fd.mfsl_fd.fsal_file)); #else pentry_file->object.file.open_fd.fileno = (int)FSAL_FILENO(&(pentry_file->object.file.open_fd.fd)); #endif pentry_file->object.file.open_fd.last_op = time(NULL); pentry_file->object.file.open_fd.openflags = openflags; LogFullDebug(COMPONENT_FSAL, "cache_inode_open_by_name: pentry %p: fd=%u", pentry_file, pentry_file->object.file.open_fd.fileno); } /* regular exit */ pentry_file->object.file.open_fd.last_op = time(NULL); /* if file descriptor is too high, garbage collect FDs */ if(pclient->use_fd_cache && (pentry_file->object.file.open_fd.fileno > pclient->max_fd)) { if(cache_inode_gc_fd(pclient, pstatus) != CACHE_INODE_SUCCESS) { LogCrit(COMPONENT_CACHE_INODE_GC, "FAILURE performing FD garbage collection"); return *pstatus; } } *pstatus = CACHE_INODE_SUCCESS; return *pstatus; } /* cache_inode_open_by_name */ /** * * cache_inode_close: closes the local fd in the FSAL. * * Closes the local fd in the FSAL. * * No lock management is done in this layer: the related pentry in the cache inode layer is * locked and will prevent from concurent accesses. * * @param pentry [IN] entry in file content layer whose content is to be accessed. * @param pclient [IN] ressource allocated by the client for the nfs management. * @pstatus [OUT] returned status. * * @return CACHE_CONTENT_SUCCESS is successful . * */ cache_inode_status_t cache_inode_close(cache_entry_t * pentry, cache_inode_client_t * pclient, cache_inode_status_t * pstatus) { fsal_status_t fsal_status; if((pentry == NULL) || (pclient == NULL) || (pstatus == NULL)) return CACHE_CONTENT_INVALID_ARGUMENT; if(pentry->internal_md.type != REGULAR_FILE) { *pstatus = CACHE_INODE_BAD_TYPE; return *pstatus; } /* if nothing is opened, do nothing */ if(pentry->object.file.open_fd.fileno < 0) { *pstatus = CACHE_INODE_SUCCESS; return *pstatus; } /* if locks are held in the file, do not close */ if( cache_inode_file_holds_state( pentry ) ) { *pstatus = CACHE_INODE_SUCCESS; /** @todo : PhD : May be CACHE_INODE_STATE_CONFLICTS would be better ? */ return *pstatus; } if((pclient->use_fd_cache == 0) || (time(NULL) - pentry->object.file.open_fd.last_op > pclient->retention) || (pentry->object.file.open_fd.fileno > (int)(pclient->max_fd))) { LogFullDebug(COMPONENT_CACHE_INODE, "cache_inode_close: pentry %p, fileno = %d, lastop=%d ago", pentry, pentry->object.file.open_fd.fileno, (int)(time(NULL) - pentry->object.file.open_fd.last_op)); #ifdef _USE_MFSL fsal_status = MFSL_close(&(pentry->object.file.open_fd.mfsl_fd), &pclient->mfsl_context, NULL); #else fsal_status = FSAL_close(&(pentry->object.file.open_fd.fd)); #endif pentry->object.file.open_fd.fileno = 0; pentry->object.file.open_fd.last_op = 0; if(FSAL_IS_ERROR(fsal_status) && (fsal_status.major != ERR_FSAL_NOT_OPENED)) { *pstatus = cache_inode_error_convert(fsal_status); LogDebug(COMPONENT_CACHE_INODE, "cache_inode_close: returning %d(%s) from FSAL_close", *pstatus, cache_inode_err_str(*pstatus)); return *pstatus; } } #ifdef _USE_PROXY /* If proxy if used, free the name if needed */ if(pentry->object.file.pname != NULL) { Mem_Free((char *)(pentry->object.file.pname)); pentry->object.file.pname = NULL; } pentry->object.file.pentry_parent_open = NULL; #endif *pstatus = CACHE_CONTENT_SUCCESS; return *pstatus; } /* cache_content_close */
/* * Duplicate xprt from original to copy. */ SVCXPRT *Svcxprt_copy(SVCXPRT *xprt_copy, SVCXPRT *xprt_orig) { if(xprt_copy) FreeXprt(xprt_copy); xprt_copy = (SVCXPRT *) Mem_Alloc(sizeof(SVCXPRT)); if(xprt_copy == NULL) goto fail_no_xprt; LogFullDebug(COMPONENT_RPC, "Svcxprt_copy copying xprt_orig=%p to xprt_copy=%p", xprt_orig, xprt_copy); memcpy(xprt_copy, xprt_orig, sizeof(SVCXPRT)); xprt_copy->xp_p1 = NULL; xprt_copy->xp_p2 = NULL; if(xprt_orig->xp_ops == &Svcudp_op) { if(Su_data(xprt_orig)) { struct Svcudp_data *su_o = Su_data(xprt_orig), *su_c; su_c = (struct Svcudp_data *) Mem_Alloc(sizeof(*su_c)); if(!su_c) goto fail; Su_data_set(xprt_copy) = (void *) su_c; memcpy(su_c, su_o, sizeof(*su_c)); rpc_buffer(xprt_copy) = Mem_Alloc_Label(su_c->su_iosz, "UDP IO Buffer"); if(!rpc_buffer(xprt_copy)) goto fail; xdrmem_create(&(su_c->su_xdrs), rpc_buffer(xprt_copy), su_c->su_iosz, XDR_DECODE); if(xprt_orig->xp_verf.oa_base == su_o->su_verfbody) xprt_copy->xp_verf.oa_base = su_c->su_verfbody; else xprt_copy->xp_verf.oa_base = xprt_orig->xp_verf.oa_base; xprt_copy->xp_verf.oa_flavor = xprt_orig->xp_verf.oa_flavor; xprt_copy->xp_verf.oa_length = xprt_orig->xp_verf.oa_length; } else goto fail; } else if (xprt_orig->xp_ops == &Svctcp_op) { struct tcp_conn *cd_o = (struct tcp_conn *)xprt_orig->xp_p1, *cd_c; cd_c = (struct tcp_conn *) Mem_Alloc(sizeof(*cd_c)); if(!cd_c) goto fail; memcpy(cd_c, cd_o, sizeof(*cd_c)); xprt_copy->xp_p1 = (void *) cd_c; xdrrec_create(&(cd_c->xdrs), 32768, 32768, (caddr_t) xprt_copy, Readtcp, Writetcp); if(xprt_orig->xp_verf.oa_base == cd_o->verf_body) xprt_copy->xp_verf.oa_base = cd_c->verf_body; else xprt_copy->xp_verf.oa_base = xprt_orig->xp_verf.oa_base; xprt_copy->xp_verf.oa_flavor = xprt_orig->xp_verf.oa_flavor; xprt_copy->xp_verf.oa_length = xprt_orig->xp_verf.oa_length; } else if (xprt_orig->xp_ops == &Svctcp_rendezvous_op) { goto fail; } else { LogDebug(COMPONENT_RPC, "Attempt to copy unknown xprt %p", xprt_orig); Mem_Free(xprt_copy); goto fail_no_xprt; } return xprt_copy; fail: FreeXprt(xprt_copy); fail_no_xprt: /* Let caller know about failure */ LogCrit(COMPONENT_RPC, "Failed to copy xprt"); svcerr_systemerr(xprt_orig); return NULL; }
fsal_status_t VFSFSAL_rcp(fsal_handle_t * filehandle, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_path_t * p_local_path, /* IN */ fsal_rcpflag_t transfer_opt /* IN */ ) { int local_fd; int local_flags; int errsv; fsal_file_t fs_fd; fsal_openflags_t fs_flags; fsal_status_t st = FSAL_STATUS_NO_ERROR; /* default buffer size for RCP: 10MB */ #define RCP_BUFFER_SIZE 10485760 caddr_t IObuffer; int to_local = FALSE; int to_fs = FALSE; int eof = FALSE; ssize_t local_size; fsal_size_t fs_size; /* sanity checks. */ if(!filehandle || !p_context || !p_local_path) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_rcp); to_local = ((transfer_opt & FSAL_RCP_FS_TO_LOCAL) == FSAL_RCP_FS_TO_LOCAL); to_fs = ((transfer_opt & FSAL_RCP_LOCAL_TO_FS) == FSAL_RCP_LOCAL_TO_FS); if(to_local) LogFullDebug(COMPONENT_FSAL, "FSAL_rcp: FSAL -> local file (%s)", p_local_path->path); if(to_fs) LogFullDebug(COMPONENT_FSAL, "FSAL_rcp: local file -> FSAL (%s)", p_local_path->path); /* must give the sens of transfert (exactly one) */ if((!to_local && !to_fs) || (to_local && to_fs)) Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_rcp); /* first, open local file with the correct flags */ if(to_fs) { local_flags = O_RDONLY; } else { local_flags = O_WRONLY | O_TRUNC; if((transfer_opt & FSAL_RCP_LOCAL_CREAT) == FSAL_RCP_LOCAL_CREAT) local_flags |= O_CREAT; if((transfer_opt & FSAL_RCP_LOCAL_EXCL) == FSAL_RCP_LOCAL_EXCL) local_flags |= O_EXCL; } if(isFullDebug(COMPONENT_FSAL)) { char msg[1024]; msg[0] = '\0'; if((local_flags & O_RDONLY) == O_RDONLY) strcat(msg, "O_RDONLY "); if((local_flags & O_WRONLY) == O_WRONLY) strcat(msg, "O_WRONLY "); if((local_flags & O_TRUNC) == O_TRUNC) strcat(msg, "O_TRUNC "); if((local_flags & O_CREAT) == O_CREAT) strcat(msg, "O_CREAT "); if((local_flags & O_EXCL) == O_EXCL) strcat(msg, "O_EXCL "); LogFullDebug(COMPONENT_FSAL, "Openning local file %s with flags: %s", p_local_path->path, msg); } local_fd = open(p_local_path->path, local_flags); errsv = errno; if(local_fd == -1) { Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_rcp); } /* call FSAL_open with the correct flags */ if(to_fs) { fs_flags = FSAL_O_WRONLY | FSAL_O_TRUNC; /* invalid flags for local to filesystem */ if(((transfer_opt & FSAL_RCP_LOCAL_CREAT) == FSAL_RCP_LOCAL_CREAT) || ((transfer_opt & FSAL_RCP_LOCAL_EXCL) == FSAL_RCP_LOCAL_EXCL)) { /* clean & return */ close(local_fd); Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_rcp); } } else { fs_flags = FSAL_O_RDONLY; } if(isFullDebug(COMPONENT_FSAL)) { char msg[1024]; msg[0] = '\0'; if((fs_flags & FSAL_O_RDONLY) == FSAL_O_RDONLY) strcat(msg, "FSAL_O_RDONLY "); if((fs_flags & FSAL_O_WRONLY) == FSAL_O_WRONLY) strcat(msg, "FSAL_O_WRONLY "); if((fs_flags & FSAL_O_TRUNC) == FSAL_O_TRUNC) strcat(msg, "FSAL_O_TRUNC "); LogFullDebug(COMPONENT_FSAL, "Openning FSAL file with flags: %s", msg); } st = FSAL_open(filehandle, p_context, fs_flags, &fs_fd, NULL); if(FSAL_IS_ERROR(st)) { /* clean & return */ close(local_fd); Return(st.major, st.minor, INDEX_FSAL_rcp); } LogFullDebug(COMPONENT_FSAL, "Allocating IO buffer of size %llu", (unsigned long long)RCP_BUFFER_SIZE); /* Allocates buffer */ IObuffer = (caddr_t) Mem_Alloc_Label(RCP_BUFFER_SIZE, "IO Buffer"); if(IObuffer == NULL) { /* clean & return */ close(local_fd); FSAL_close(&fs_fd); Return(ERR_FSAL_NOMEM, Mem_Errno, INDEX_FSAL_rcp); } /* read/write loop */ while(!eof) { /* initialize error code */ st = FSAL_STATUS_NO_ERROR; LogFullDebug(COMPONENT_FSAL, "Read a block from source"); /* read */ if(to_fs) /* from local filesystem */ { LogFullDebug(COMPONENT_FSAL, "Read a block from local file system"); local_size = read(local_fd, IObuffer, RCP_BUFFER_SIZE); if(local_size == -1) { st.major = ERR_FSAL_IO; st.minor = errno; break; /* exit loop */ } eof = (local_size == 0); if(!eof) { LogFullDebug(COMPONENT_FSAL, "Write a block (%llu bytes) to FSAL", (unsigned long long)local_size); st = FSAL_write(&fs_fd, NULL, local_size, IObuffer, &fs_size); if(FSAL_IS_ERROR(st)) { LogFullDebug(COMPONENT_FSAL, "Error writing to FSAL"); break; /* exit loop */ } } else { LogFullDebug(COMPONENT_FSAL, "End of file on local file system"); } } else /* from FSAL filesystem */ { LogFullDebug(COMPONENT_FSAL, "Read a block from FSAL"); fs_size = 0; st = FSAL_read(&fs_fd, NULL, RCP_BUFFER_SIZE, IObuffer, &fs_size, &eof); if(FSAL_IS_ERROR(st)) break; /* exit loop */ if(fs_size > 0) { LogFullDebug(COMPONENT_FSAL, "Write a block (%llu bytes) to local file system", (unsigned long long)fs_size); local_size = write(local_fd, IObuffer, fs_size); if(local_size == -1) { st.major = ERR_FSAL_IO; st.minor = errno; break; /* exit loop */ } } else { LogFullDebug(COMPONENT_FSAL, "End of file on FSAL"); break; } LogFullDebug(COMPONENT_FSAL, "Size read from source: %llu", (unsigned long long)fs_size); } } /* while !eof */ /* Clean */ Mem_Free(IObuffer); close(local_fd); FSAL_close(&fs_fd); /* return status. */ Return(st.major, st.minor, INDEX_FSAL_rcp); }
int nfs_Mkdir(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_Mkdir"; char *str_dir_name = NULL; fsal_accessmode_t mode = 0; cache_entry_t *dir_pentry = NULL; cache_entry_t *parent_pentry = NULL; int rc = 0; fsal_attrib_list_t parent_attr; fsal_attrib_list_t attr; fsal_attrib_list_t *ppre_attr; fsal_attrib_list_t attr_parent_after; cache_inode_file_type_t parent_filetype; fsal_handle_t *pfsal_handle; fsal_name_t dir_name; cache_inode_status_t cache_status = CACHE_INODE_SUCCESS; cache_inode_status_t cache_status_lookup; if(isDebug(COMPONENT_NFSPROTO)) { char str[LEN_FH_STR]; switch (preq->rq_vers) { case NFS_V2: str_dir_name = parg->arg_mkdir2.where.name; break; case NFS_V3: str_dir_name = parg->arg_mkdir3.where.name; break; } nfs_FhandleToStr(preq->rq_vers, &(parg->arg_mkdir2.where.dir), &(parg->arg_mkdir3.where.dir), NULL, str); LogDebug(COMPONENT_NFSPROTO, "REQUEST PROCESSING: Calling nfs_Mkdir handle: %s name: %s", str, str_dir_name); } if(preq->rq_vers == NFS_V3) { /* to avoid setting it on each error case */ pres->res_mkdir3.MKDIR3res_u.resfail.dir_wcc.before.attributes_follow = FALSE; pres->res_mkdir3.MKDIR3res_u.resfail.dir_wcc.after.attributes_follow = FALSE; ppre_attr = NULL; } if((parent_pentry = nfs_FhandleToCache(preq->rq_vers, &(parg->arg_mkdir2.where.dir), &(parg->arg_mkdir3.where.dir), NULL, &(pres->res_dirop2.status), &(pres->res_mkdir3.status), NULL, &parent_attr, pcontext, pclient, ht, &rc)) == NULL) { /* Stale NFS FH ? */ return rc; } /* get directory attributes before action (for V3 reply) */ ppre_attr = &parent_attr; /* Extract the filetype */ parent_filetype = cache_inode_fsal_type_convert(parent_attr.type); /* * Sanity checks: */ if(parent_filetype != DIRECTORY) { switch (preq->rq_vers) { case NFS_V2: pres->res_dirop2.status = NFSERR_NOTDIR; break; case NFS_V3: pres->res_mkdir3.status = NFS3ERR_NOTDIR; break; } return NFS_REQ_OK; } switch (preq->rq_vers) { case NFS_V2: str_dir_name = parg->arg_mkdir2.where.name; if(parg->arg_mkdir2.attributes.mode != (unsigned int)-1) { mode = (fsal_accessmode_t) parg->arg_mkdir2.attributes.mode; } else { mode = (fsal_accessmode_t) 0; } break; case NFS_V3: str_dir_name = parg->arg_mkdir3.where.name; if(parg->arg_mkdir3.attributes.mode.set_it == TRUE) mode = (fsal_accessmode_t) parg->arg_mkdir3.attributes.mode.set_mode3_u.mode; else mode = (fsal_accessmode_t) 0; break; } //if(str_dir_name == NULL || strlen(str_dir_name) == 0) if(str_dir_name == NULL || *str_dir_name == '\0' ) { if(preq->rq_vers == NFS_V2) pres->res_dirop2.status = NFSERR_IO; if(preq->rq_vers == NFS_V3) pres->res_mkdir3.status = NFS3ERR_INVAL; } else { /* Make the directory */ if((cache_status = cache_inode_error_convert(FSAL_str2name(str_dir_name, FSAL_MAX_NAME_LEN, &dir_name))) == CACHE_INODE_SUCCESS) { /* * Lookup file to see if it exists. If so, use it. Otherwise * create a new one. */ dir_pentry = cache_inode_lookup( parent_pentry, &dir_name, pexport->cache_inode_policy, &attr, ht, pclient, pcontext, &cache_status_lookup); if(cache_status_lookup == CACHE_INODE_NOT_FOUND) { /* Create the directory */ if((dir_pentry = cache_inode_create(parent_pentry, &dir_name, DIRECTORY, pexport->cache_inode_policy, mode, NULL, &attr, ht, pclient, pcontext, &cache_status)) != NULL) { /* * Get the FSAL handle for this entry */ pfsal_handle = cache_inode_get_fsal_handle(dir_pentry, &cache_status); if(cache_status == CACHE_INODE_SUCCESS) { switch (preq->rq_vers) { case NFS_V2: /* Build file handle */ if(!nfs2_FSALToFhandle (&(pres->res_dirop2.DIROP2res_u.diropok.file), pfsal_handle, pexport)) pres->res_dirop2.status = NFSERR_IO; else { /* * Build entry * attributes */ if(nfs2_FSALattr_To_Fattr(pexport, &attr, &(pres->res_dirop2.DIROP2res_u. diropok.attributes)) == 0) pres->res_dirop2.status = NFSERR_IO; else pres->res_dirop2.status = NFS_OK; } break; case NFS_V3: /* Build file handle */ if((pres->res_mkdir3.MKDIR3res_u.resok.obj.post_op_fh3_u. handle.data.data_val = Mem_Alloc_Label(NFS3_FHSIZE, "Filehandle V3 in nfs3_mkdir")) == NULL) { pres->res_mkdir3.status = NFS3ERR_IO; return NFS_REQ_OK; } if(nfs3_FSALToFhandle (&pres->res_mkdir3.MKDIR3res_u.resok.obj.post_op_fh3_u. handle, pfsal_handle, pexport) == 0) { Mem_Free((char *)pres->res_mkdir3.MKDIR3res_u.resok.obj. post_op_fh3_u.handle.data.data_val); pres->res_mkdir3.status = NFS3ERR_INVAL; return NFS_REQ_OK; } else { /* Set Post Op Fh3 structure */ pres->res_mkdir3.MKDIR3res_u.resok.obj.handle_follows = TRUE; pres->res_mkdir3.MKDIR3res_u.resok.obj.post_op_fh3_u.handle. data.data_len = sizeof(file_handle_v3_t); /* * Build entry * attributes */ nfs_SetPostOpAttr(pcontext, pexport, dir_pentry, &attr, &(pres->res_mkdir3.MKDIR3res_u.resok. obj_attributes)); /* Get the attributes of the parent after the operation */ cache_inode_get_attributes(parent_pentry, &attr_parent_after); /* * Build Weak Cache * Coherency data */ nfs_SetWccData(pcontext, pexport, parent_pentry, ppre_attr, &attr_parent_after, &(pres->res_mkdir3.MKDIR3res_u.resok. dir_wcc)); pres->res_mkdir3.status = NFS3_OK; } break; } return NFS_REQ_OK; } } } /* If( cache_status_lookup == CACHE_INODE_NOT_FOUND ) */ else { /* object already exists or failure during lookup */ if(cache_status_lookup == CACHE_INODE_SUCCESS) { /* Trying to create a file that already exists */ cache_status = CACHE_INODE_ENTRY_EXISTS; switch (preq->rq_vers) { case NFS_V2: pres->res_dirop2.status = NFSERR_EXIST; break; case NFS_V3: pres->res_mkdir3.status = NFS3ERR_EXIST; break; } } else { /* Server fault */ cache_status = cache_status_lookup; switch (preq->rq_vers) { case NFS_V2: pres->res_dirop2.status = NFSERR_IO; break; case NFS_V3: pres->res_mkdir3.status = NFS3ERR_INVAL; break; } } nfs_SetFailedStatus(pcontext, pexport, preq->rq_vers, cache_status, &pres->res_dirop2.status, &pres->res_mkdir3.status, NULL, NULL, parent_pentry, ppre_attr, &(pres->res_mkdir3.MKDIR3res_u.resfail.dir_wcc), NULL, NULL, NULL); return NFS_REQ_OK; } } } /* 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_dirop2.status, &pres->res_mkdir3.status, NULL, NULL, parent_pentry, ppre_attr, &(pres->res_mkdir3.MKDIR3res_u.resfail.dir_wcc), NULL, NULL, NULL); return NFS_REQ_OK; }