Beispiel #1
0
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;
}
Beispiel #2
0
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 */
Beispiel #3
0
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 */
Beispiel #5
0
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;
}
Beispiel #6
0
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;
}
Beispiel #7
0
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 ;
}
Beispiel #8
0
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 ;
}
Beispiel #9
0
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;
}
Beispiel #10
0
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 */