int _9p_lcreate(struct _9p_request_data *req9p, u32 *plenout, char *preply) { char *cursor = req9p->_9pmsg + _9P_HDR_SIZE + _9P_TYPE_SIZE; u16 *msgtag = NULL; u32 *fid = NULL; u32 *flags = NULL; u32 *mode = NULL; u32 *gid = NULL; u16 *name_len = NULL; char *name_str = NULL; struct _9p_fid *pfid = NULL; struct _9p_qid qid_newfile; u32 iounit = _9P_IOUNIT; struct fsal_obj_handle *pentry_newfile = NULL; char file_name[MAXNAMLEN+1]; fsal_status_t fsal_status; fsal_openflags_t openflags = 0; struct attrlist sattr; fsal_verifier_t verifier; enum fsal_create_mode createmode = FSAL_UNCHECKED; /* Get data */ _9p_getptr(cursor, msgtag, u16); _9p_getptr(cursor, fid, u32); _9p_getstr(cursor, name_len, name_str); _9p_getptr(cursor, flags, u32); _9p_getptr(cursor, mode, u32); _9p_getptr(cursor, gid, u32); LogDebug(COMPONENT_9P, "TLCREATE: tag=%u fid=%u name=%.*s flags=0%o mode=0%o gid=%u", (u32) *msgtag, *fid, *name_len, name_str, *flags, *mode, *gid); if (*fid >= _9P_FID_PER_CONN) return _9p_rerror(req9p, msgtag, ERANGE, plenout, preply); pfid = req9p->pconn->fids[*fid]; /* Check that it is a valid fid */ if (pfid == NULL || pfid->pentry == NULL) { LogDebug(COMPONENT_9P, "request on invalid fid=%u", *fid); return _9p_rerror(req9p, msgtag, EIO, plenout, preply); } _9p_init_opctx(pfid, req9p); if ((op_ctx->export_perms->options & EXPORT_OPTION_WRITE_ACCESS) == 0) return _9p_rerror(req9p, msgtag, EROFS, plenout, preply); if (*name_len >= sizeof(file_name)) { LogDebug(COMPONENT_9P, "request with name too long (%u)", *name_len); return _9p_rerror(req9p, msgtag, ENAMETOOLONG, plenout, preply); } snprintf(file_name, sizeof(file_name), "%.*s", *name_len, name_str); _9p_openflags2FSAL(flags, &openflags); pfid->state->state_data.fid.share_access = _9p_openflags_to_share_access(flags); memset(&verifier, 0, sizeof(verifier)); memset(&sattr, 0, sizeof(sattr)); sattr.valid_mask = ATTR_MODE | ATTR_GROUP; sattr.mode = *mode; sattr.group = *gid; if (*flags & 0x10) { /* Filesize is already 0. */ sattr.valid_mask |= ATTR_SIZE; } if (*flags & 0x1000) { /* If OEXCL, use FSAL_EXCLUSIVE_9P create mode * so that we can pass the attributes specified * above. Verifier is ignored for this create mode * because we don't have to deal with retry. */ createmode = FSAL_EXCLUSIVE_9P; } fsal_status = fsal_open2(pfid->pentry, pfid->state, openflags, createmode, file_name, &sattr, verifier, &pentry_newfile, NULL); /* Release the attributes (may release an inherited ACL) */ fsal_release_attrs(&sattr); if (FSAL_IS_ERROR(fsal_status)) return _9p_rerror(req9p, msgtag, _9p_tools_errno(fsal_status), plenout, preply); /* put parent directory entry */ pfid->pentry->obj_ops->put_ref(pfid->pentry); /* Build the qid */ qid_newfile.type = _9P_QTFILE; qid_newfile.version = 0; qid_newfile.path = pentry_newfile->fileid; /* The fid will represent the new file now - we can't fail anymore */ pfid->pentry = pentry_newfile; pfid->qid = qid_newfile; pfid->xattr = NULL; pfid->opens = 1; /* Build the reply */ _9p_setinitptr(cursor, preply, _9P_RLCREATE); _9p_setptr(cursor, msgtag, u16); _9p_setqid(cursor, qid_newfile); _9p_setvalue(cursor, iounit, u32); _9p_setendptr(cursor, preply); _9p_checkbound(cursor, preply, plenout); LogDebug(COMPONENT_9P, "RLCREATE: tag=%u fid=%u name=%.*s qid=(type=%u,version=%u,path=%llu) iounit=%u pentry=%p", (u32) *msgtag, *fid, *name_len, name_str, qid_newfile.type, qid_newfile.version, (unsigned long long)qid_newfile.path, iounit, pfid->pentry); return 1; }
int _9p_xattrwalk( _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 ; u16 * msgtag = NULL ; u32 * fid = NULL ; u32 * attrfid = NULL ; u16 * wnames_len ; char * wnames_str ; int rc = 0 ; u32 err = 0 ; if ( !preq9p || !pworker_data || !plenout || !preply ) return -1 ; /* Get data */ _9p_getptr( cursor, msgtag, u16 ) ; _9p_getptr( cursor, fid, u32 ) ; _9p_getptr( cursor, attrfid, u32 ) ; LogDebug( COMPONENT_9P, "TXATTRWALK: tag=%u fid=%u attrfid=%u" , (u32)*msgtag, *fid, *attrfid ) ; _9p_getstr( cursor, wnames_len, wnames_str ) ; LogDebug( COMPONENT_9P, "TXATTRWALK (component): tag=%u fid=%u attrfid=%u nwnames=%.*s", (u32)*msgtag, *fid, *attrfid, *wnames_len, wnames_str ) ; if( *fid >= _9P_FID_PER_CONN ) { err = ERANGE ; rc = _9p_rerror( preq9p, msgtag, &err, plenout, preply ) ; return rc ; } if( *attrfid >= _9P_FID_PER_CONN ) { err = ERANGE ; rc = _9p_rerror( preq9p, msgtag, &err, plenout, preply ) ; return rc ; } /* Build the reply */ _9p_setinitptr( cursor, preply, _9P_RXATTRWALK ) ; _9p_setptr( cursor, msgtag, u16 ) ; _9p_setvalue( cursor, 0LL, u64 ) ; /* No xattr for now */ _9p_setendptr( cursor, preply ) ; _9p_checkbound( cursor, preply, plenout ) ; LogDebug( COMPONENT_9P, "RXATTRWALK: tag=%u fid=%u attrfid=%u nwnames=%.*s", (u32)*msgtag, *fid, *attrfid, *wnames_len, wnames_str ) ; return 1 ; } /* _9p_xattrwalk */
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 _9p_xattrwalk(struct _9p_request_data *req9p, u32 *plenout, char *preply) { char *cursor = req9p->_9pmsg + _9P_HDR_SIZE + _9P_TYPE_SIZE; u16 *msgtag = NULL; u32 *fid = NULL; u32 *attrfid = NULL; u16 *name_len; char *name_str; size_t attrsize = 0; fsal_status_t fsal_status; char name[MAXNAMLEN]; fsal_xattrent_t xattrs_arr[XATTRS_ARRAY_LEN]; int eod_met = false; unsigned int nb_xattrs_read = 0; unsigned int i = 0; char *xattr_cursor = NULL; unsigned int tmplen = 0; struct _9p_fid *pfid = NULL; struct _9p_fid *pxattrfid = NULL; /* Get data */ _9p_getptr(cursor, msgtag, u16); _9p_getptr(cursor, fid, u32); _9p_getptr(cursor, attrfid, u32); LogDebug(COMPONENT_9P, "TXATTRWALK: tag=%u fid=%u attrfid=%u", (u32) *msgtag, *fid, *attrfid); _9p_getstr(cursor, name_len, name_str); if (*name_len == 0) LogDebug(COMPONENT_9P, "TXATTRWALK (component): tag=%u fid=%u attrfid=%u name=(LIST XATTR)", (u32) *msgtag, *fid, *attrfid); else LogDebug(COMPONENT_9P, "TXATTRWALK (component): tag=%u fid=%u attrfid=%u name=%.*s", (u32) *msgtag, *fid, *attrfid, *name_len, name_str); if (*fid >= _9P_FID_PER_CONN) return _9p_rerror(req9p, msgtag, ERANGE, plenout, preply); if (*attrfid >= _9P_FID_PER_CONN) return _9p_rerror(req9p, msgtag, ERANGE, plenout, preply); pfid = req9p->pconn->fids[*fid]; /* Check that it is a valid fid */ if (pfid == NULL || pfid->pentry == NULL) { LogDebug(COMPONENT_9P, "request on invalid fid=%u", *fid); return _9p_rerror(req9p, msgtag, EIO, plenout, preply); } pxattrfid = gsh_calloc(1, sizeof(struct _9p_fid)); if (pxattrfid == NULL) return _9p_rerror(req9p, msgtag, ENOMEM, plenout, preply); /* set op_ctx, it will be useful if FSAL is later called */ _9p_init_opctx(pfid, req9p); /* Initiate xattr's fid by copying file's fid in it */ memcpy((char *)pxattrfid, (char *)pfid, sizeof(struct _9p_fid)); snprintf(name, MAXNAMLEN, "%.*s", *name_len, name_str); pxattrfid->specdata.xattr.xattr_content = gsh_malloc(XATTR_BUFFERSIZE); if (pxattrfid->specdata.xattr.xattr_content == NULL) { gsh_free(pxattrfid); return _9p_rerror(req9p, msgtag, ENOMEM, plenout, preply); } if (*name_len == 0) { /* xattrwalk is used with an empty name, * this is a listxattr request */ fsal_status = pxattrfid->pentry->obj_handle->obj_ops.list_ext_attrs( pxattrfid->pentry->obj_handle, FSAL_XATTR_RW_COOKIE, /* Start with RW cookie, * hiding RO ones */ xattrs_arr, XATTRS_ARRAY_LEN, /** @todo fix static length */ &nb_xattrs_read, &eod_met); if (FSAL_IS_ERROR(fsal_status)) { gsh_free(pxattrfid->specdata.xattr.xattr_content); gsh_free(pxattrfid); return _9p_rerror(req9p, msgtag, _9p_tools_errno (cache_inode_error_convert (fsal_status)), plenout, preply); } /* if all xattrent are not read, * returns ERANGE as listxattr does */ if (eod_met != true) { gsh_free(pxattrfid->specdata.xattr.xattr_content); gsh_free(pxattrfid); return _9p_rerror(req9p, msgtag, ERANGE, plenout, preply); } xattr_cursor = pxattrfid->specdata.xattr.xattr_content; attrsize = 0; for (i = 0; i < nb_xattrs_read; i++) { tmplen = snprintf(xattr_cursor, MAXNAMLEN, "%s", xattrs_arr[i].xattr_name); xattr_cursor[tmplen] = '\0'; /* Just to be sure */ /* +1 for trailing '\0' */ xattr_cursor += tmplen + 1; attrsize += tmplen + 1; /* Make sure not to go beyond the buffer */ if (attrsize > XATTR_BUFFERSIZE) { gsh_free(pxattrfid->specdata.xattr. xattr_content); gsh_free(pxattrfid); return _9p_rerror(req9p, msgtag, ERANGE, plenout, preply); } } } else { /* xattrwalk has a non-empty name, use regular setxattr */ fsal_status = pxattrfid->pentry->obj_handle->obj_ops. getextattr_id_by_name(pxattrfid->pentry->obj_handle, name, &pxattrfid->specdata.xattr.xattr_id); if (FSAL_IS_ERROR(fsal_status)) { gsh_free(pxattrfid->specdata.xattr.xattr_content); gsh_free(pxattrfid); /* ENOENT for xattr is ENOATTR */ if (fsal_status.major == ERR_FSAL_NOENT) return _9p_rerror(req9p, msgtag, ENOATTR, plenout, preply); else return _9p_rerror(req9p, msgtag, _9p_tools_errno (cache_inode_error_convert (fsal_status)), plenout, preply); } fsal_status = pxattrfid->pentry->obj_handle->obj_ops. getextattr_value_by_name(pxattrfid->pentry->obj_handle, name, pxattrfid->specdata.xattr. xattr_content, XATTR_BUFFERSIZE, &attrsize); if (FSAL_IS_ERROR(fsal_status)) { gsh_free(pxattrfid->specdata.xattr.xattr_content); gsh_free(pxattrfid); /* fsal_status.minor is a valid errno code */ return _9p_rerror(req9p, msgtag, fsal_status.minor, plenout, preply); } } req9p->pconn->fids[*attrfid] = pxattrfid; /* Increments refcount as we're manually making a new copy */ (void) cache_inode_lru_ref(pfid->pentry, LRU_REQ_STALE_OK); /* hold reference on gdata */ uid2grp_hold_group_data(pxattrfid->gdata); get_gsh_export_ref(pfid->export); get_9p_user_cred_ref(pfid->ucred); /* Build the reply */ _9p_setinitptr(cursor, preply, _9P_RXATTRWALK); _9p_setptr(cursor, msgtag, u16); _9p_setvalue(cursor, attrsize, u64); _9p_setendptr(cursor, preply); _9p_checkbound(cursor, preply, plenout); LogDebug(COMPONENT_9P, "RXATTRWALK: tag=%u fid=%u attrfid=%u name=%.*s size=%llu", (u32) *msgtag, *fid, *attrfid, *name_len, name_str, (unsigned long long)attrsize); return 1; } /* _9p_xattrwalk */
int _9p_write(struct _9p_request_data *req9p, u32 *plenout, char *preply) { char *cursor = req9p->_9pmsg + _9P_HDR_SIZE + _9P_TYPE_SIZE; u16 *msgtag = NULL; u32 *fid = NULL; u64 *offset = NULL; u32 *count = NULL; u32 outcount = 0; struct _9p_fid *pfid = NULL; size_t size; size_t written_size = 0; char *databuffer = NULL; /* Get data */ _9p_getptr(cursor, msgtag, u16); _9p_getptr(cursor, fid, u32); _9p_getptr(cursor, offset, u64); _9p_getptr(cursor, count, u32); databuffer = cursor; LogDebug(COMPONENT_9P, "TWRITE: tag=%u fid=%u offset=%llu count=%u", (u32) *msgtag, *fid, (unsigned long long)*offset, *count); if (*fid >= _9P_FID_PER_CONN) return _9p_rerror(req9p, msgtag, ERANGE, plenout, preply); pfid = req9p->pconn->fids[*fid]; /* Make sure the requested amount of data respects negotiated msize */ if (*count + _9P_ROOM_TWRITE > req9p->pconn->msize) return _9p_rerror(req9p, msgtag, ERANGE, plenout, preply); /* Check that it is a valid fid */ if (pfid == NULL || pfid->pentry == NULL) { LogDebug(COMPONENT_9P, "request on invalid fid=%u", *fid); return _9p_rerror(req9p, msgtag, EIO, plenout, preply); } _9p_init_opctx(pfid, req9p); if ((op_ctx->export_perms->options & EXPORT_OPTION_WRITE_ACCESS) == 0) return _9p_rerror(req9p, msgtag, EROFS, plenout, preply); /* Do the job */ size = *count; if (pfid->xattr != NULL) { if (*offset > pfid->xattr->xattr_size) return _9p_rerror(req9p, msgtag, EINVAL, plenout, preply); if (pfid->xattr->xattr_write != _9P_XATTR_CAN_WRITE && pfid->xattr->xattr_write != _9P_XATTR_DID_WRITE) return _9p_rerror(req9p, msgtag, EINVAL, plenout, preply); written_size = MIN(*count, pfid->xattr->xattr_size - *offset); memcpy(pfid->xattr->xattr_content + *offset, databuffer, written_size); pfid->xattr->xattr_offset += size; pfid->xattr->xattr_write = _9P_XATTR_DID_WRITE; /* ADD CODE TO DETECT GAP */ #if 0 fsal_status = pfid->pentry->ops->setextattr_value_by_id( pfid->pentry, &pfid->op_context, pfid->xattr->xattr_id, xattrval, size + 1); if (FSAL_IS_ERROR(fsal_status)) return _9p_rerror(req9p, msgtag, _9p_tools_errno(fsal_status), plenout, preply); #endif outcount = written_size; } else { struct _9p_write_data write_data; struct fsal_io_arg *write_arg = alloca(sizeof(*write_arg) + sizeof(struct iovec)); write_arg->info = NULL; write_arg->state = pfid->state; write_arg->offset = *offset; write_arg->iov_count = 1; write_arg->iov[0].iov_len = size; write_arg->iov[0].iov_base = databuffer; write_arg->io_amount = 0; write_arg->fsal_stable = false; write_data.client = req9p->pconn->client; /* Do the actual write */ pfid->pentry->obj_ops->write2(pfid->pentry, true, _9p_write_cb, write_arg, &write_data); if (FSAL_IS_ERROR(write_data.ret)) return _9p_rerror(req9p, msgtag, _9p_tools_errno(write_data.ret), plenout, preply); outcount = (u32) write_arg->io_amount; } /* Build the reply */ _9p_setinitptr(cursor, preply, _9P_RWRITE); _9p_setptr(cursor, msgtag, u16); _9p_setvalue(cursor, outcount, u32); _9p_setendptr(cursor, preply); _9p_checkbound(cursor, preply, plenout); LogDebug(COMPONENT_9P, "RWRITE: tag=%u fid=%u offset=%llu input count=%u output count=%u", (u32) *msgtag, *fid, (unsigned long long)*offset, *count, outcount); /** * @todo write statistics accounting goes here * modeled on nfs I/O stats */ return 1; }
int _9p_statfs(struct _9p_request_data *req9p, void *worker_data, u32 *plenout, char *preply) { char *cursor = req9p->_9pmsg + _9P_HDR_SIZE + _9P_TYPE_SIZE; u16 *msgtag = NULL; u32 *fid = NULL; struct _9p_fid *pfid = NULL; u32 type = 0x6969; /* NFS_SUPER_MAGIC for wanting of better, * FSAL do not return this information */ u32 bsize = 1; /* cache_inode_statfs and * FSAL already care for blocksize */ u64 *blocks = NULL; u64 *bfree = NULL; u64 *bavail = NULL; u64 *files = NULL; u64 *ffree = NULL; u64 fsid = 0LL; u32 namelen = MAXNAMLEN; fsal_dynamicfsinfo_t dynamicinfo; cache_inode_status_t cache_status; /* Get data */ _9p_getptr(cursor, msgtag, u16); _9p_getptr(cursor, fid, u32); LogDebug(COMPONENT_9P, "TSTATFS: tag=%u fid=%u", (u32) *msgtag, *fid); if (*fid >= _9P_FID_PER_CONN) return _9p_rerror(req9p, worker_data, msgtag, ERANGE, plenout, preply); pfid = req9p->pconn->fids[*fid]; if (pfid == NULL) return _9p_rerror(req9p, worker_data, msgtag, EINVAL, plenout, preply); /* Get the FS's stats */ cache_status = cache_inode_statfs(pfid->pentry, &dynamicinfo, &pfid->op_context); if (cache_status != CACHE_INODE_SUCCESS) return _9p_rerror(req9p, worker_data, msgtag, _9p_tools_errno(cache_status), plenout, preply); blocks = (u64 *) &dynamicinfo.total_bytes; bfree = (u64 *) &dynamicinfo.free_bytes; bavail = (u64 *) &dynamicinfo.avail_bytes; files = (u64 *) &dynamicinfo.total_files; ffree = (u64 *) &dynamicinfo.free_files; fsid = (u64) pfid->pentry->obj_handle->attributes.rawdev.major; /* Build the reply */ _9p_setinitptr(cursor, preply, _9P_RSTATFS); _9p_setptr(cursor, msgtag, u16); _9p_setvalue(cursor, type, u32); _9p_setvalue(cursor, bsize, u32); _9p_setptr(cursor, blocks, u64); _9p_setptr(cursor, bfree, u64); _9p_setptr(cursor, bavail, u64); _9p_setptr(cursor, files, u64); _9p_setptr(cursor, ffree, u64); _9p_setvalue(cursor, fsid, u64); _9p_setvalue(cursor, namelen, u32); _9p_setendptr(cursor, preply); _9p_checkbound(cursor, preply, plenout); LogDebug(COMPONENT_9P, "RSTATFS: tag=%u fid=%u", (u32) *msgtag, *fid); return 1; }
int _9p_statfs( _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 ; u16 * msgtag = NULL ; u32 * fid = NULL ; u64 * request_mask = NULL ; _9p_fid_t * pfid = NULL ; u32 type = 0x6969 ; /* NFS_SUPER_MAGIC for wanting of better, FSAL do not return this information */ u32 bsize = DEV_BSIZE ; u64 * blocks = NULL ; u64 * bfree = NULL ; u64 * bavail = NULL ; u64 * files = NULL ; u64 * ffree = NULL ; u64 fsid = 0LL ; u32 namelen = MAXNAMLEN ; int rc = 0 ; int err = 0 ; fsal_dynamicfsinfo_t dynamicinfo; cache_inode_status_t cache_status; if ( !preq9p || !pworker_data || !plenout || !preply ) return -1 ; /* Get data */ _9p_getptr( cursor, msgtag, u16 ) ; _9p_getptr( cursor, fid, u32 ) ; LogDebug( COMPONENT_9P, "TSTATFS: tag=%u fid=%u", (u32)*msgtag, *fid ) ; if( *fid >= _9P_FID_PER_CONN ) { err = ERANGE ; rc = _9p_rerror( preq9p, msgtag, &err, plenout, preply ) ; return rc ; } pfid = &preq9p->pconn->fids[*fid] ; /* Get the FS's stats */ if( cache_inode_statfs( pfid->pentry, &dynamicinfo, &pfid->fsal_op_context, &cache_status ) != CACHE_INODE_SUCCESS ) { err = _9p_tools_errno( cache_status ) ; ; rc = _9p_rerror( preq9p, msgtag, &err, plenout, preply ) ; return rc ; } blocks = (u64 *)&dynamicinfo.total_bytes ; bfree = (u64 *)&dynamicinfo.free_bytes ; bavail = (u64 *)&dynamicinfo.avail_bytes ; files = (u64 *)&dynamicinfo.total_files ; ffree = (u64 *)&dynamicinfo.free_files ; fsid = (u64 )pfid->attr.st_dev ; /* Build the reply */ _9p_setinitptr( cursor, preply, _9P_RSTATFS ) ; _9p_setptr( cursor, msgtag, u16 ) ; _9p_setvalue( cursor, type, u32 ) ; _9p_setvalue( cursor, bsize, u32 ) ; _9p_setptr( cursor, blocks, u64 ) ; _9p_setptr( cursor, bfree, u64 ) ; _9p_setptr( cursor, bavail, u64 ) ; _9p_setptr( cursor, files, u64 ) ; _9p_setptr( cursor, ffree, u64 ) ; _9p_setvalue( cursor, fsid, u64 ) ; _9p_setvalue( cursor, namelen, u32 ) ; _9p_setendptr( cursor, preply ) ; _9p_checkbound( cursor, preply, plenout ) ; LogDebug( COMPONENT_9P, "RSTATFS: tag=%u fid=%u", (u32)*msgtag, *fid ) ; return 1 ; }
int _9p_write( _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 outcount = 0 ; _9p_fid_t * pfid = NULL ; fsal_seek_t seek_descriptor; fsal_size_t size; fsal_size_t written_size = 0; fsal_attrib_list_t attr; fsal_boolean_t eof_met; cache_inode_status_t cache_status = CACHE_INODE_SUCCESS; uint64_t stable_flag = FSAL_SAFE_WRITE_TO_FS; caddr_t databuffer = NULL ; /* Get data */ _9p_getptr( cursor, msgtag, u16 ) ; _9p_getptr( cursor, fid, u32 ) ; _9p_getptr( cursor, offset, u64 ) ; _9p_getptr( cursor, count, u32 ) ; databuffer = cursor ; LogDebug( COMPONENT_9P, "TWRITE: 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] ; /* Do the job */ seek_descriptor.whence = FSAL_SEEK_SET ; seek_descriptor.offset = *offset; size = *count ; if(cache_inode_rdwr( pfid->pentry, CACHE_INODE_WRITE, &seek_descriptor, size, &written_size, &attr, databuffer, &eof_met, pwkrdata->ht, &pwkrdata->cache_inode_client, &pfid->fsal_op_context, stable_flag, &cache_status ) != CACHE_INODE_SUCCESS ) { err = _9p_tools_errno( cache_status ) ; ; rc = _9p_rerror( preq9p, msgtag, &err, plenout, preply ) ; return rc ; } outcount = (u32)written_size ; /* Build the reply */ _9p_setinitptr( cursor, preply, _9P_RWRITE ) ; _9p_setptr( cursor, msgtag, u16 ) ; _9p_setvalue( cursor, outcount, u32 ) ; _9p_setendptr( cursor, preply ) ; _9p_checkbound( cursor, preply, plenout ) ; LogDebug( COMPONENT_9P, "RWRITE: tag=%u fid=%u offset=%llu input count=%u output count=%u", (u32)*msgtag, *fid , (unsigned long long)*offset, *count, outcount ) ; return 1 ; }
int _9p_write(struct _9p_request_data *req9p, u32 *plenout, char *preply) { char *cursor = req9p->_9pmsg + _9P_HDR_SIZE + _9P_TYPE_SIZE; u16 *msgtag = NULL; u32 *fid = NULL; u64 *offset = NULL; u32 *count = NULL; u32 outcount = 0; struct _9p_fid *pfid = NULL; size_t size; size_t written_size = 0; bool eof_met; cache_inode_status_t cache_status = CACHE_INODE_SUCCESS; /* bool sync = true; */ bool sync = false; char *databuffer = NULL; /* fsal_status_t fsal_status; */ /* Get data */ _9p_getptr(cursor, msgtag, u16); _9p_getptr(cursor, fid, u32); _9p_getptr(cursor, offset, u64); _9p_getptr(cursor, count, u32); databuffer = cursor; LogDebug(COMPONENT_9P, "TWRITE: tag=%u fid=%u offset=%llu count=%u", (u32) *msgtag, *fid, (unsigned long long)*offset, *count); if (*fid >= _9P_FID_PER_CONN) return _9p_rerror(req9p, msgtag, ERANGE, plenout, preply); pfid = req9p->pconn->fids[*fid]; /* Make sure the requested amount of data respects negotiated msize */ if (*count + _9P_ROOM_TWRITE > req9p->pconn->msize) return _9p_rerror(req9p, msgtag, ERANGE, plenout, preply); /* Check that it is a valid fid */ if (pfid == NULL || pfid->pentry == NULL) { LogDebug(COMPONENT_9P, "request on invalid fid=%u", *fid); return _9p_rerror(req9p, msgtag, EIO, plenout, preply); } _9p_init_opctx(pfid, req9p); if ((op_ctx->export_perms->options & EXPORT_OPTION_WRITE_ACCESS) == 0) return _9p_rerror(req9p, msgtag, EROFS, plenout, preply); /* Do the job */ size = *count; if (pfid->specdata.xattr.xattr_content != NULL) { memcpy(pfid->specdata.xattr.xattr_content + (*offset), databuffer, size); pfid->specdata.xattr.xattr_offset += size; pfid->specdata.xattr.xattr_write = true; /* ADD CODE TO DETECT GAP */ #if 0 fsal_status = pfid->pentry->obj_handle->ops->setextattr_value_by_id( pfid->pentry->obj_handle, &pfid->op_context, pfid->specdata.xattr.xattr_id, xattrval, size + 1); if (FSAL_IS_ERROR(fsal_status)) return _9p_rerror(req9p, msgtag, _9p_tools_errno (cache_inode_error_convert (fsal_status)), plenout, preply); #endif outcount = *count; } else { cache_status = cache_inode_rdwr(pfid->pentry, CACHE_INODE_WRITE, *offset, size, &written_size, databuffer, &eof_met, &sync, NULL); /* Get the handle, for stats */ struct gsh_client *client = req9p->pconn->client; if (client == NULL) { LogDebug(COMPONENT_9P, "Cannot get client block for 9P request"); } else { op_ctx->client = client; server_stats_io_done(size, written_size, (cache_status == CACHE_INODE_SUCCESS) ? true : false, true); } if (cache_status != CACHE_INODE_SUCCESS) return _9p_rerror(req9p, msgtag, _9p_tools_errno(cache_status), plenout, preply); outcount = (u32) written_size; } /* Build the reply */ _9p_setinitptr(cursor, preply, _9P_RWRITE); _9p_setptr(cursor, msgtag, u16); _9p_setvalue(cursor, outcount, u32); _9p_setendptr(cursor, preply); _9p_checkbound(cursor, preply, plenout); LogDebug(COMPONENT_9P, "RWRITE: tag=%u fid=%u offset=%llu input count=%u output count=%u", (u32) *msgtag, *fid, (unsigned long long)*offset, *count, outcount); /** * @todo write statistics accounting goes here * modeled on nfs I/O stats */ return 1; }
int _9p_xattrwalk(struct _9p_request_data *req9p, void *worker_data, u32 *plenout, char *preply) { char *cursor = req9p->_9pmsg + _9P_HDR_SIZE + _9P_TYPE_SIZE; u16 *msgtag = NULL; u32 *fid = NULL; u32 *attrfid = NULL; u16 *name_len; char *name_str; u64 attrsize = 0LL; fsal_status_t fsal_status; char name[MAXNAMLEN]; fsal_xattrent_t xattrs_tab[255]; int eod_met = false; unsigned int nb_xattrs_read = 0; unsigned int i = 0; char *xattr_cursor = NULL; unsigned int tmplen = 0; struct _9p_fid *pfid = NULL; struct _9p_fid *pxattrfid = NULL; /* Get data */ _9p_getptr(cursor, msgtag, u16); _9p_getptr(cursor, fid, u32); _9p_getptr(cursor, attrfid, u32); LogDebug(COMPONENT_9P, "TXATTRWALK: tag=%u fid=%u attrfid=%u", (u32) *msgtag, *fid, *attrfid); _9p_getstr(cursor, name_len, name_str); if (*name_len == 0) LogDebug(COMPONENT_9P, "TXATTRWALK (component): tag=%u fid=%u attrfid=%u name=(LIST XATTR)", (u32) *msgtag, *fid, *attrfid); else LogDebug(COMPONENT_9P, "TXATTRWALK (component): tag=%u fid=%u attrfid=%u name=%.*s", (u32) *msgtag, *fid, *attrfid, *name_len, name_str); if (*fid >= _9P_FID_PER_CONN) return _9p_rerror(req9p, worker_data, msgtag, ERANGE, plenout, preply); if (*attrfid >= _9P_FID_PER_CONN) return _9p_rerror(req9p, worker_data, msgtag, ERANGE, plenout, preply); pfid = req9p->pconn->fids[*fid]; /* Check that it is a valid fid */ if (pfid == NULL || pfid->pentry == NULL) { LogDebug(COMPONENT_9P, "request on invalid fid=%u", *fid); return _9p_rerror(req9p, worker_data, msgtag, EIO, plenout, preply); } pxattrfid = gsh_calloc(1, sizeof(struct _9p_fid)); if (pxattrfid == NULL) return _9p_rerror(req9p, worker_data, msgtag, ENOMEM, plenout, preply); /* Initiate xattr's fid by copying file's fid in it */ memcpy((char *)pxattrfid, (char *)pfid, sizeof(struct _9p_fid)); snprintf(name, MAXNAMLEN, "%.*s", *name_len, name_str); pxattrfid->specdata.xattr.xattr_content = gsh_malloc(XATTR_BUFFERSIZE); if (pxattrfid->specdata.xattr.xattr_content == NULL) { gsh_free(pxattrfid); return _9p_rerror(req9p, worker_data, msgtag, ENOMEM, plenout, preply); } if (*name_len == 0) { /* xattrwalk is used with an empty name, * this is a listxattr request */ fsal_status = pxattrfid->pentry->obj_handle->ops->list_ext_attrs( pxattrfid->pentry->obj_handle, &pfid->op_context, FSAL_XATTR_RW_COOKIE, /* Start with RW cookie, * hiding RO ones */ xattrs_tab, 100, /* static array size for now */ &nb_xattrs_read, &eod_met); if (FSAL_IS_ERROR(fsal_status)) { gsh_free(pxattrfid->specdata.xattr.xattr_content); gsh_free(pxattrfid); return _9p_rerror(req9p, worker_data, msgtag, _9p_tools_errno (cache_inode_error_convert (fsal_status)), plenout, preply); } /* if all xattrent are not read, * returns ERANGE as listxattr does */ if (eod_met != TRUE) { gsh_free(pxattrfid->specdata.xattr.xattr_content); gsh_free(pxattrfid); return _9p_rerror(req9p, worker_data, msgtag, ERANGE, plenout, preply); } xattr_cursor = pxattrfid->specdata.xattr.xattr_content; attrsize = 0LL; for (i = 0; i < nb_xattrs_read; i++) { tmplen = snprintf(xattr_cursor, MAXNAMLEN, "%s", xattrs_tab[i].xattr_name); xattr_cursor[tmplen] = '\0'; /* Just to be sure */ /* +1 for trailing '\0' */ xattr_cursor += tmplen + 1; attrsize += tmplen + 1; /* Make sure not to go beyond the buffer */ if (attrsize > XATTR_BUFFERSIZE) { gsh_free(pxattrfid->specdata.xattr. xattr_content); gsh_free(pxattrfid); return _9p_rerror(req9p, worker_data, msgtag, ERANGE, plenout, preply); } } } else { /* xattrwalk has a non-empty name, use regular setxattr */ fsal_status = pxattrfid->pentry->obj_handle->ops-> getextattr_id_by_name(pxattrfid->pentry->obj_handle, &pfid->op_context, name, &pxattrfid->specdata.xattr.xattr_id); if (FSAL_IS_ERROR(fsal_status)) { gsh_free(pxattrfid->specdata.xattr.xattr_content); gsh_free(pxattrfid); /* Hook dedicated to ACL management. When attributes * system.posix_acl_access is used, it can't be * created, but can be written anyway. * To do this, return ENODATA instead of ENOATTR * In this case, we do created what's needed to * setxattr() into the special xattr */ if (!strncmp(name, "system.posix_acl_access", MAXNAMLEN)) return _9p_rerror(req9p, worker_data, msgtag, ENODATA, plenout, preply); /* ENOENT for xattr is ENOATTR */ if (fsal_status.major == ERR_FSAL_NOENT) return _9p_rerror(req9p, worker_data, msgtag, ENOATTR, plenout, preply); else return _9p_rerror(req9p, worker_data, msgtag, _9p_tools_errno (cache_inode_error_convert (fsal_status)), plenout, preply); } fsal_status = pxattrfid->pentry->obj_handle->ops-> getextattr_value_by_name(pxattrfid->pentry->obj_handle, &pfid->op_context, name, pxattrfid->specdata.xattr. xattr_content, XATTR_BUFFERSIZE, &attrsize); if (FSAL_IS_ERROR(fsal_status)) { gsh_free(pxattrfid->specdata.xattr.xattr_content); gsh_free(pxattrfid); if (fsal_status.minor == ENODATA) { return _9p_rerror(req9p, worker_data, msgtag, ENODATA, plenout, preply); } return _9p_rerror(req9p, worker_data, msgtag, _9p_tools_errno (cache_inode_error_convert (fsal_status)), plenout, preply); } } req9p->pconn->fids[*attrfid] = pxattrfid; /* Increments refcount so it won't fall below 0 when we clunk later */ cache_inode_lru_ref(pxattrfid->pentry, LRU_REQ_INITIAL); /* Build the reply */ _9p_setinitptr(cursor, preply, _9P_RXATTRWALK); _9p_setptr(cursor, msgtag, u16); _9p_setvalue(cursor, attrsize, u64); _9p_setendptr(cursor, preply); _9p_checkbound(cursor, preply, plenout); LogDebug(COMPONENT_9P, "RXATTRWALK: tag=%u fid=%u attrfid=%u name=%.*s size=%llu", (u32) *msgtag, *fid, *attrfid, *name_len, name_str, (unsigned long long)attrsize); return 1; } /* _9p_xattrwalk */