fsal_status_t MFSL_close(mfsl_file_t * file_descriptor, /* IN */ mfsl_context_t * p_mfsl_context, /* IN */ void * pextra ) { return FSAL_close(&file_descriptor->fsal_file); } /* MFSL_close */
fsal_status_t MFSL_close(mfsl_file_t * file_descriptor, /* IN */ mfsl_context_t * p_mfsl_context, /* IN */ void * pextra ) { struct timeval start, stop, delta ; fsal_status_t fsal_status = { ERR_FSAL_NO_ERROR, 0 } ; gettimeofday( &start, 0 ) ; fsal_status = FSAL_close(&file_descriptor->fsal_file); gettimeofday( &stop, 0 ) ; delta = mfsl_timer_diff( &stop, &start ) ; LogFullDebug( COMPONENT_MFSL, "%s: duration=%ld.%06ld", __FUNCTION__, delta.tv_sec, delta.tv_usec ) ; return fsal_status ; } /* MFSL_close */
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 */
/** * * 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))) { LogDebug(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 */
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 */
cache_inode_status_t cache_inode_open(cache_entry_t * pentry, cache_inode_client_t * pclient, fsal_openflags_t openflags, fsal_op_context_t * pcontext, cache_inode_status_t * pstatus) { fsal_status_t fsal_status; if((pentry == NULL) || (pclient == NULL) || (pcontext == NULL) || (pstatus == NULL)) return CACHE_INODE_INVALID_ARGUMENT; if(pentry->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->object.file.open_fd.openflags != FSAL_O_RDWR) && (pentry->object.file.open_fd.openflags != 0) && (pentry->object.file.open_fd.fileno != 0) && (pentry->object.file.open_fd.openflags != openflags)) { #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 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: returning %d(%s) from FSAL_close", *pstatus, cache_inode_err_str(*pstatus)); return *pstatus; } /* force re-openning */ pentry->object.file.open_fd.last_op = 0; pentry->object.file.open_fd.fileno = 0; } if((pentry->object.file.open_fd.last_op == 0) || (pentry->object.file.open_fd.fileno == 0)) { /* opened file is not preserved yet */ #ifdef _USE_MFSL fsal_status = MFSL_open(&(pentry->mobject), pcontext, &pclient->mfsl_context, openflags, &pentry->object.file.open_fd.mfsl_fd, &(pentry->object.file.attributes), NULL ); #else fsal_status = FSAL_open(&(pentry->object.file.handle), pcontext, openflags, &pentry->object.file.open_fd.fd, &(pentry->object.file.attributes)); #endif if(FSAL_IS_ERROR(fsal_status)) { *pstatus = cache_inode_error_convert(fsal_status); LogDebug(COMPONENT_CACHE_INODE, "cache_inode_open: returning %d(%s) from FSAL_open", *pstatus, cache_inode_err_str(*pstatus)); return *pstatus; } #ifdef _USE_MFSL pentry->object.file.open_fd.fileno = FSAL_FILENO(&(pentry->object.file.open_fd.mfsl_fd.fsal_file)); #else pentry->object.file.open_fd.fileno = FSAL_FILENO(&(pentry->object.file.open_fd.fd)); #endif pentry->object.file.open_fd.openflags = openflags; LogDebug(COMPONENT_CACHE_INODE, "cache_inode_open: pentry %p: lastop=0, fileno = %d, openflags = %d", pentry, pentry->object.file.open_fd.fileno, (int) openflags); } /* regular exit */ pentry->object.file.open_fd.last_op = time(NULL); /* if file descriptor is too high, garbage collect FDs */ if(pclient->use_fd_cache && (pentry->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 */
fsal_status_t PROXYFSAL_rcp_by_fileid(proxyfsal_handle_t * filehandle, /* IN */ fsal_u64_t fileid, /* IN */ proxyfsal_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; proxyfsal_file_t fs_fd; fsal_openflags_t fs_flags; fsal_status_t st = FSAL_STATUS_NO_ERROR; /* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> * This is a template implementation of rcp based on FSAL_read and FSAL_write * function. You may chose keeping it or doing your own implementation * that is optimal for your filesystems. * <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */ 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, 0644); if(local_fd == -1) { /** @todo : put a function in fsal_convert.c that convert your local * filesystem errors to an FSAL error code. * So you will have a call like : * Return( unix2fsal_error(errno) , errno , INDEX_FSAL_rcp ); */ Return(ERR_FSAL_SERVERFAULT, errno, 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_by_fileid(filehandle, fileid, 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(RCP_BUFFER_SIZE); 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 */ { 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); } else /* from FSAL filesystem */ { fs_size = 0; st = FSAL_read(&fs_fd, NULL, RCP_BUFFER_SIZE, IObuffer, &fs_size, &eof); if(FSAL_IS_ERROR(st)) break; /* exit loop */ } /* write (if not eof) */ if(!eof || ((!to_fs) && (fs_size > 0))) { LogFullDebug(COMPONENT_FSAL, "Write a block to destination"); if(to_fs) /* to FSAL filesystem */ { st = FSAL_write(&fs_fd, NULL, local_size, IObuffer, &fs_size); if(FSAL_IS_ERROR(st)) break; /* exit loop */ } else /* to local filesystem */ { local_size = write(local_fd, IObuffer, fs_size); if(local_size == -1) { st.major = ERR_FSAL_IO; st.minor = errno; break; /* exit loop */ } } /* if to_fs */ } /* if eof */ else LogFullDebug(COMPONENT_FSAL, "End of source file reached"); } /* while !eof */ /* Clean */ Mem_Free(IObuffer); close(local_fd); FSAL_close_by_fileid(&fs_fd, fileid); /* return status. */ Return(st.major, st.minor, INDEX_FSAL_rcp); } /* FSAL_rcp_by_name */
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 */
fsal_status_t MFSL_close(fsal_file_t * file_descriptor, /* IN */ mfsl_context_t * p_mfsl_context /* IN */ ) { return FSAL_close(file_descriptor); } /* MFSL_close */
fsal_status_t GPFSFSAL_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 = gsh_malloc(RCP_BUFFER_SIZE); if(IObuffer == NULL) { /* clean & return */ close(local_fd); FSAL_close(&fs_fd, p_context); Return(ERR_FSAL_NOMEM, ENOMEM, 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, p_context, 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, p_context, 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 */ gsh_free(IObuffer); close(local_fd); FSAL_close(&fs_fd, p_context); /* return status. */ Return(st.major, st.minor, INDEX_FSAL_rcp); }
/** * FSAL_create: * Create a regular file. * * \param parent_directory_handle (input): * Handle of the parent directory where the file is to be created. * \param p_filename (input): * Pointer to the name of the file to be created. * \param cred (input): * Authentication context for the operation (user, export...). * \param accessmode (input): * Mode for the file to be created. * (the umask defined into the FSAL configuration file * will be applied on it). * \param object_handle (output): * Pointer to the handle of the created file. * \param object_attributes (optionnal input/output): * The postop attributes of the created file. * As input, it defines the attributes that the caller * wants to retrieve (by positioning flags into this structure) * and the output is built considering this input * (it fills the structure according to the flags it contains). * Can be NULL. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - ERR_FSAL_STALE (parent_directory_handle does not address an existing object) * - ERR_FSAL_FAULT (a NULL pointer was passed as mandatory argument) * - Other error codes can be returned : * ERR_FSAL_ACCESS, ERR_FSAL_EXIST, ERR_FSAL_IO, ... * * NB: if getting postop attributes failed, * the function does not return an error * but the FSAL_ATTR_RDATTR_ERR bit is set in * the object_attributes->asked_attributes field. */ fsal_status_t PROXYFSAL_create(proxyfsal_handle_t * parent_directory_handle, /* IN */ fsal_name_t * p_filename, /* IN */ proxyfsal_op_context_t * p_context, /* IN */ fsal_accessmode_t accessmode, /* IN */ proxyfsal_handle_t * object_handle, /* OUT */ fsal_attrib_list_t * object_attributes /* [ IN/OUT ] */ ) { int rc; COMPOUND4args argnfs4; COMPOUND4res resnfs4; nfs_fh4 nfs4fh; bitmap4 bitmap; uint32_t bitmap_val[2]; uint32_t bitmap_res[2]; uint32_t bitmap_conv_val[2]; uint32_t bitmap_create[2]; uint32_t bitmap_getattr_res[2]; fattr4 input_attr; bitmap4 convert_bitmap; component4 name; char nameval[MAXNAMLEN]; char padfilehandle[FSAL_PROXY_FILEHANDLE_MAX_LEN]; fsal_status_t fsal_status; proxyfsal_file_t fd; #define FSAL_CREATE_NB_OP_ALLOC 4 #define FSAL_CREATE_VAL_BUFFER 1024 fsal_proxy_internal_fattr_t fattr_internal; fsal_attrib_list_t create_mode_attr; fsal_attrib_list_t attributes; nfs_argop4 argoparray[FSAL_CREATE_NB_OP_ALLOC]; nfs_resop4 resoparray[FSAL_CREATE_NB_OP_ALLOC]; char fattr_val[FSAL_CREATE_VAL_BUFFER]; struct timeval timeout = { 25, 0 }; char owner_val[FSAL_PROXY_OWNER_LEN]; unsigned int owner_len = 0; /* sanity checks. * note : object_attributes is optional. */ if(!parent_directory_handle || !p_context || !object_handle || !p_filename) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_create); PRINT_HANDLE("FSAL_create", parent_directory_handle); /* Create the owner */ snprintf(owner_val, FSAL_PROXY_OWNER_LEN, "GANESHA/PROXY: pid=%u ctx=%p file=%llu", getpid(), p_context, (unsigned long long int)p_context->file_counter); owner_len = strnlen(owner_val, FSAL_PROXY_OWNER_LEN); p_context->file_counter += 1; /* Setup results structures */ argnfs4.argarray.argarray_val = argoparray; resnfs4.resarray.resarray_val = resoparray; argnfs4.minorversion = 0; /* argnfs4.tag.utf8string_val = "GANESHA NFSv4 Proxy: Mkdir" ; */ argnfs4.tag.utf8string_val = NULL; argnfs4.tag.utf8string_len = 0; argnfs4.argarray.argarray_len = 0; input_attr.attrmask.bitmap4_val = bitmap_val; input_attr.attrmask.bitmap4_len = 2; input_attr.attr_vals.attrlist4_val = fattr_val; input_attr.attr_vals.attrlist4_len = FSAL_CREATE_VAL_BUFFER; fsal_internal_proxy_setup_fattr(&fattr_internal); convert_bitmap.bitmap4_val = bitmap_conv_val; convert_bitmap.bitmap4_len = 2; memset((char *)&name, 0, sizeof(component4)); name.utf8string_val = nameval; if(fsal_internal_proxy_fsal_name_2_utf8(p_filename, &name) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_create); /* Get NFSv4 File handle */ if(fsal_internal_proxy_extract_fh(&nfs4fh, parent_directory_handle) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_create); if(isFullDebug(COMPONENT_FSAL)) { char outstr[1024]; nfs4_sprint_fhandle(&nfs4fh, outstr); LogFullDebug(COMPONENT_FSAL, "FSAL_CREATE: extracted server (as client) parent handle=%s\n", outstr); } bitmap.bitmap4_val = bitmap_create; bitmap.bitmap4_len = 2; fsal_internal_proxy_create_fattr_bitmap(&bitmap); create_mode_attr.asked_attributes = FSAL_ATTR_MODE; create_mode_attr.mode = accessmode; fsal_interval_proxy_fsalattr2bitmap4(&create_mode_attr, &convert_bitmap); if(nfs4_FSALattr_To_Fattr(NULL, /* no exportlist required here */ &create_mode_attr, &input_attr, NULL, /* no compound data required here */ NULL, /* No fh here, filehandle is not a settable attribute */ &convert_bitmap) == -1) Return(ERR_FSAL_INVAL, -1, INDEX_FSAL_create); #define FSAL_CREATE_IDX_OP_PUTFH 0 #define FSAL_CREATE_IDX_OP_OPEN_CREATE 1 #define FSAL_CREATE_IDX_OP_GETFH 2 #define FSAL_CREATE_IDX_OP_GETATTR 3 COMPOUNDV4_ARG_ADD_OP_PUTFH(argnfs4, nfs4fh); COMPOUNDV4_ARG_ADD_OP_OPEN_CREATE(argnfs4, name, input_attr, p_context->clientid, owner_val, owner_len); COMPOUNDV4_ARG_ADD_OP_GETFH(argnfs4); COMPOUNDV4_ARG_ADD_OP_GETATTR(argnfs4, bitmap); resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_OPEN_CREATE].nfs_resop4_u.opopen. OPEN4res_u.resok4.attrset.bitmap4_val = bitmap_res; resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_OPEN_CREATE].nfs_resop4_u.opopen. OPEN4res_u.resok4.attrset.bitmap4_len = 2; resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_GETFH].nfs_resop4_u.opgetfh. GETFH4res_u.resok4.object.nfs_fh4_val = (char *)padfilehandle; resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_GETFH].nfs_resop4_u.opgetfh. GETFH4res_u.resok4.object.nfs_fh4_len = FSAL_PROXY_FILEHANDLE_MAX_LEN; resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_val = bitmap_getattr_res; resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attrmask.bitmap4_len = 2; resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_val = (char *)&fattr_internal; resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_GETATTR].nfs_resop4_u.opgetattr. GETATTR4res_u.resok4.obj_attributes.attr_vals.attrlist4_len = sizeof(fattr_internal); TakeTokenFSCall(); /* Call the NFSv4 function */ COMPOUNDV4_EXECUTE(p_context, argnfs4, resnfs4, rc); if(rc != RPC_SUCCESS) { ReleaseTokenFSCall(); Return(ERR_FSAL_IO, rc, INDEX_FSAL_create); } ReleaseTokenFSCall(); /* >> convert error code, and return on error << */ if(resnfs4.status != NFS4_OK) return fsal_internal_proxy_error_convert(resnfs4.status, INDEX_FSAL_create); /* Use NFSv4 service function to build the FSAL_attr */ if(nfs4_Fattr_To_FSAL_attr(&attributes, &resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_GETATTR]. nfs_resop4_u.opgetattr.GETATTR4res_u.resok4. obj_attributes) != 1) { FSAL_CLEAR_MASK(attributes.asked_attributes); FSAL_SET_MASK(attributes.asked_attributes, FSAL_ATTR_RDATTR_ERR); Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_create); } /* Return attributes if asked */ if(object_attributes) { memcpy(object_attributes, &attributes, sizeof(attributes)); } if(isFullDebug(COMPONENT_FSAL)) { char outstr[1024]; nfs4_sprint_fhandle(&nfs4fh, outstr); LogFullDebug(COMPONENT_FSAL, "FSAL_CREATE: extracted server (as client) created file handle=%s\n", outstr); } if(fsal_internal_proxy_create_fh (& (resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_GETFH].nfs_resop4_u.opgetfh. GETFH4res_u.resok4.object), FSAL_TYPE_FILE, attributes.fileid, object_handle) == FALSE) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_create); /* Keep the information into the file descriptor as well */ memcpy((char *)&fd.fhandle, (char *)object_handle, sizeof(fd.fhandle)); fd.openflags = FSAL_O_RDWR; fd.current_offset = 0; fd.pcontext = p_context; /* Keep the returned stateid for later use */ fd.stateid.seqid = resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_OPEN_CREATE].nfs_resop4_u.opopen. OPEN4res_u.resok4.stateid.seqid; memcpy((char *)fd.stateid.other, resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_OPEN_CREATE].nfs_resop4_u. opopen.OPEN4res_u.resok4.stateid.other, 12); /* See if a OPEN_CONFIRM is required */ if(resnfs4.resarray.resarray_val[FSAL_CREATE_IDX_OP_OPEN_CREATE].nfs_resop4_u.opopen. OPEN4res_u.resok4.rflags & OPEN4_RESULT_CONFIRM) { fsal_status = FSAL_proxy_open_confirm(&fd); if(FSAL_IS_ERROR(fsal_status)) Return(fsal_status.major, fsal_status.minor, INDEX_FSAL_create); } #ifdef _FSAL_CREATE_CLOSE_FILE /* The craeted file is still opened, to preserve the correct seqid for later use, we close it */ fsal_status = FSAL_close(&fd); if(FSAL_IS_ERROR(fsal_status)) Return(fsal_status.major, fsal_status.minor, INDEX_FSAL_create); #endif /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_create); } /* FSAL_create */