コード例 #1
0
/*!	Writes the specified \a block back to disk. It will always only write back
	the oldest change of the block if it is part of more than one transaction.
	It will automatically send out TRANSACTION_WRITTEN notices, as well as
	delete transactions when they are no longer used, and \a deleteTransaction
	is \c true.
*/
static fssh_status_t
write_cached_block(block_cache* cache, cached_block* block,
	bool deleteTransaction)
{
	cache_transaction* previous = block->previous_transaction;
	int32_t blockSize = cache->block_size;

	void* data = previous && block->original_data
		? block->original_data : block->current_data;
		// we first need to write back changes from previous transactions

	TRACE(("write_cached_block(block %Ld)\n", block->block_number));

	fssh_ssize_t written = fssh_write_pos(cache->fd, block->block_number * blockSize,
		data, blockSize);

	if (written < blockSize) {
		FATAL(("could not write back block %" FSSH_B_PRIdOFF " (%s)\n",
			block->block_number, fssh_strerror(fssh_get_errno())));
		return FSSH_B_IO_ERROR;
	}

	if (data == block->current_data)
		block->is_dirty = false;

	if (previous != NULL) {
		previous->blocks.Remove(block);
		block->previous_transaction = NULL;

		if (block->original_data != NULL && block->transaction == NULL) {
			// This block is not part of a transaction, so it does not need
			// its original pointer anymore.
			cache->Free(block->original_data);
			block->original_data = NULL;
		}

		// Has the previous transation been finished with that write?
		if (--previous->num_blocks == 0) {
			TRACE(("cache transaction %ld finished!\n", previous->id));

			notify_transaction_listeners(cache, previous, FSSH_TRANSACTION_WRITTEN);

			if (deleteTransaction) {
				hash_remove(cache->transaction_hash, previous);
				delete_transaction(cache, previous);
			}
		}
	}
	if (block->transaction == NULL && block->ref_count == 0) {
		// the block is no longer used
		block->unused = true;
		cache->unused_blocks.Add(block);
	}

	return FSSH_B_OK;
}
コード例 #2
0
static void
wait_for_port_to_be_deleted( void *user_data ) {
  transaction_entry *entry = user_data;

  debug( "Waiting for a tunnel port to be deleted ( entry = %p, datapath_id = %#" PRIx64 ", vni = %#x ).",
         entry, entry != NULL ? entry->datapath_id : 0, entry != NULL ? entry->vni : 0 );

  assert( user_data != NULL );

  uint16_t port_no = 0;
  char name[ IFNAMSIZ ];
  memset( name, '\0', sizeof( name ) );
  snprintf( name, sizeof( name ), "vxlan%u", entry->vni & VNI_MASK );
  bool ret = get_port_no_by_name( entry->datapath_id, name, &port_no );
  if ( ret ) {
    if ( entry->port_wait_count >= 10 ) {
      warn( "A tunnel port is not deleted from a switch ( datapath_id = %#" PRIx64 ", vni = %#x, name = %s ).",
            entry->datapath_id, entry->vni, name );
      if ( entry->callback != NULL ) {
        debug( "Calling a callback function ( calback = %p, user_data = %p ).", entry->callback, entry->user_data );
        entry->callback( OVERLAY_NETWORK_OPERATION_FAILED, entry->user_data );
      }
      delete_timer_event( wait_for_port_to_be_deleted, entry );
      delete_transaction( entry->datapath_id, entry->vni );
    }
    else {
      entry->port_wait_count++;
      debug( "port_wait_count = %d.", entry->port_wait_count );
    }
    return;
  }

  debug( "A tunnel port is successfully deleted from a switch ( datapath_id = %#" PRIx64 ", vni = %#x, name = %s, port_no = %u ).",
         entry->datapath_id, entry->vni, name, port_no );
  if ( entry->callback != NULL ) {
    debug( "Calling a callback function ( calback = %p, user_data = %p ).", entry->callback, entry->user_data );
    entry->callback( OVERLAY_NETWORK_OPERATION_SUCCEEDED, entry->user_data );
  }
  delete_timer_event( wait_for_port_to_be_deleted, entry );
  delete_transaction( entry->datapath_id, entry->vni );
}
コード例 #3
0
static void
http_transaction_completed( int status, int code, const http_content *content, void *user_data ) {
  debug( "A HTTP transaction completed ( status = %d, code = %d, content = %p, user_data = %p ).",
         status, code, content, user_data );

  assert( user_data != NULL );

  transaction_entry *entry = user_data;

  entry->n_ongoing_http_requests--;

  if ( status == HTTP_TRANSACTION_FAILED ) {
    if ( !( ( entry->operation == OPERATION_ATTACH ) && ( code == 440 ) ) &&   // 440: Specified TEP has already been added.
         !( ( entry->operation == OPERATION_DETACH ) && ( code == 404 ) ) ) {  // 404: Already deleted.
      error( "HTTP transaction failed ( vni = %#x, datapath_id = %#" PRIx64 ", operation = %#x, port_wait_count = %d, "
             "n_ongoing_http_requests = %u, n_failed_http_requests = %u, status = %d, code = %d ).",
             entry->vni, entry->datapath_id, entry->operation, entry->port_wait_count,
             entry->n_ongoing_http_requests, entry->n_failed_http_requests, status, code );
      entry->n_failed_http_requests++;
    }
  }

  if ( entry->n_ongoing_http_requests > 0 ) {
    return;
  }

  assert( entry->n_ongoing_http_requests == 0 );

  if ( entry->n_failed_http_requests == 0 ) {
    if ( entry->callback != NULL ) {
      if ( entry->operation == OPERATION_ATTACH ) {
        add_periodic_event_callback( 1, wait_for_port_to_be_added, entry );
        return;
      }
      else if ( entry->operation == OPERATION_DETACH ) {
        add_periodic_event_callback( 1, wait_for_port_to_be_deleted, entry );
        return;
      }
    }
  }
  else {
    if ( entry->callback != NULL ) {
      debug( "Calling a callback function ( calback = %p, user_data = %p ).", entry->callback, entry->user_data );
      entry->callback( OVERLAY_NETWORK_OPERATION_FAILED, entry->user_data );
    }
  }

  delete_transaction( entry->datapath_id, entry->vni );
}
コード例 #4
0
int
detach_from_network( uint64_t datapath_id, uint32_t vni,
                     overlay_operation_completed_handler callback, void *user_data ) {
  debug( "Detaching a switch %#" PRIx64 " from an overlay network ( vni = %#x, callback = %p, user_data = %p ).",
         datapath_id, vni, callback, user_data );

  char *local_address = NULL;
  char *broadcast_address = NULL;
  uint16_t local_port = 0;
  uint16_t broadcast_port = 0;

  if ( !valid_vni( vni ) ) {
    return OVERLAY_NETWORK_OPERATION_FAILED;
  }

  transaction_entry *entry = lookup_transaction( datapath_id, vni );
  if ( entry != NULL ) {
    if ( entry->datapath_id == datapath_id && entry->vni == vni &&
         entry->operation == OPERATION_DETACH ) {
      debug( "Same operation is in progress ( datapath_id = %#" PRIx64 ", vni = %#x, operation = %#x ).",
             entry->datapath_id, entry->vni, entry->operation );
      return OVERLAY_NETWORK_OPERATION_IN_PROGRESS;
    }
    error( "Another operation is in progress ( datapath_id = %#" PRIx64 ", vni = %#x, operation = %#x ).",
           entry->datapath_id, entry->vni, entry->operation );
    return OVERLAY_NETWORK_OPERATION_FAILED;
  }

  bool ret = add_transaction( datapath_id, vni, OPERATION_DETACH, callback, user_data );
  if ( !ret ) {
    error( "Failed to add a transaction for detaching from a network "
           "( datapath_id = %" PRIx64 ", vni = %#x, callback = %p, user_data = %p ).",
           datapath_id, vni, callback, user_data );
    return OVERLAY_NETWORK_OPERATION_FAILED;
  }

  ret = get_overlay_info( vni, datapath_id, &local_address, &local_port, &broadcast_address, &broadcast_port );
  if ( !ret ) {
    error( "Failed to retrieve overlay network information ( datapath_id = %#" PRIx64 ", vni = %#x ).",
           datapath_id, vni );
    goto error;
  }

  entry = lookup_transaction( datapath_id, vni );
  if ( entry == NULL ) {
    error( "Failed to retrieve transaction entry ( datapath_id = %#" PRIx64 ", vni = %#x ).",
           datapath_id, vni );
    goto error;
  }

  ret = delete_tunnel_from_tep( entry, vni, datapath_id );
  if ( !ret ) {
    if ( entry->n_ongoing_http_requests == 0 ) {
      error( "Failed to delete a tunnel." );
      goto error;
    }
    error( "Failed to delete a tunnel, but http request to delete a tunnel is ongoing." );
  }

  if ( !valid_multicast_address( broadcast_address ) ) {
    if ( ret ) {
      ret = delete_tep_from_packet_reflectors( entry, vni, local_address );
      if ( !ret ) {
        if ( entry->n_ongoing_http_requests == 0 ) {
          error( "Failed to delete TEP from all Packet Reflectors." );
          goto error;
        }
        error( "Failed to delete TEP from some Packet Reflectors." );
      }
    }
  }

  xfree( broadcast_address );
  xfree( local_address );

  debug( "A HTTP request is sent to HTTP client thread ( datapath_id = %" PRIx64 ", vni = %#x, callback = %p, user_data = %p ).",
         datapath_id, vni, callback, user_data );

  return OVERLAY_NETWORK_OPERATION_SUCCEEDED;

error:
  delete_transaction( datapath_id, vni );

  if ( broadcast_address != NULL ) {
    xfree( broadcast_address );
  }
  if ( local_address != NULL ) {
    xfree( local_address );
  }

  return OVERLAY_NETWORK_OPERATION_FAILED;
}