[infiniband] Flush uncompleted work queue entries at QP teardown

Avoid leaking I/O buffers in ib_destroy_qp() by completing any
outstanding work queue entries with a generic error code.  This
requires the completion handlers to be available to ib_destroy_qp(),
which is done by making them static configuration parameters of the CQ
(set by ib_create_cq()) rather than being provided on each call to
ib_poll_cq().

This mimics the functionality of netdev_{tx,rx}_flush().  The netdev
flush functions would previously have been catching any I/O buffers
leaked by the IPoIB data queue (though not by the IPoIB metadata
queue).
This commit is contained in:
Michael Brown
2008-10-03 00:07:52 +01:00
parent dd34500188
commit d9751edafa
5 changed files with 134 additions and 73 deletions

View File

@@ -101,6 +101,37 @@ enum ib_queue_pair_mods {
IB_MODIFY_QKEY = 0x0001,
};
/** An Infiniband completion */
struct ib_completion {
/** Syndrome
*
* If non-zero, then the completion is in error.
*/
unsigned int syndrome;
/** Length */
size_t len;
};
/** Infiniband completion syndromes */
enum ib_syndrome {
IB_SYN_NONE = 0,
IB_SYN_LOCAL_LENGTH = 1,
IB_SYN_LOCAL_QP = 2,
IB_SYN_LOCAL_PROT = 4,
};
/** An Infiniband completion handler
*
* @v ibdev Infiniband device
* @v qp Queue pair
* @v completion Completion
* @v iobuf I/O buffer
*/
typedef void ( * ib_completer_t ) ( struct ib_device *ibdev,
struct ib_queue_pair *qp,
struct ib_completion *completion,
struct io_buffer *iobuf );
/** An Infiniband Completion Queue */
struct ib_completion_queue {
/** Completion queue number */
@@ -117,33 +148,14 @@ struct ib_completion_queue {
unsigned long next_idx;
/** List of work queues completing to this queue */
struct list_head work_queues;
/** Send completion handler */
ib_completer_t complete_send;
/** Receive completion handler */
ib_completer_t complete_recv;
/** Driver private data */
void *drv_priv;
};
/** An Infiniband completion */
struct ib_completion {
/** Syndrome
*
* If non-zero, then the completion is in error.
*/
unsigned int syndrome;
/** Length */
size_t len;
};
/** An Infiniband completion handler
*
* @v ibdev Infiniband device
* @v qp Queue pair
* @v completion Completion
* @v iobuf I/O buffer
*/
typedef void ( * ib_completer_t ) ( struct ib_device *ibdev,
struct ib_queue_pair *qp,
struct ib_completion *completion,
struct io_buffer *iobuf );
/** An Infiniband Address Vector */
struct ib_address_vector {
/** Destination Queue Pair */
@@ -246,15 +258,12 @@ struct ib_device_operations {
*
* @v ibdev Infiniband device
* @v cq Completion queue
* @v complete_send Send completion handler
* @v complete_recv Receive completion handler
*
* The completion handler takes ownership of the I/O buffer.
* The relevant completion handler (specified at completion
* queue creation time) takes ownership of the I/O buffer.
*/
void ( * poll_cq ) ( struct ib_device *ibdev,
struct ib_completion_queue *cq,
ib_completer_t complete_send,
ib_completer_t complete_recv );
struct ib_completion_queue *cq );
/**
* Poll event queue
*
@@ -331,8 +340,9 @@ struct ib_device {
void *owner_priv;
};
extern struct ib_completion_queue * ib_create_cq ( struct ib_device *ibdev,
unsigned int num_cqes );
extern struct ib_completion_queue *
ib_create_cq ( struct ib_device *ibdev, unsigned int num_cqes,
ib_completer_t complete_send, ib_completer_t complete_recv );
extern void ib_destroy_cq ( struct ib_device *ibdev,
struct ib_completion_queue *cq );
extern struct ib_queue_pair *
@@ -379,18 +389,45 @@ ib_post_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp,
return ibdev->op->post_recv ( ibdev, qp, iobuf );
}
/**
* Complete send work queue entry
*
* @v ibdev Infiniband device
* @v qp Queue pair
* @v completion Completion
* @v iobuf I/O buffer
*/
static inline __attribute__ (( always_inline )) void
ib_complete_send ( struct ib_device *ibdev, struct ib_queue_pair *qp,
struct ib_completion *completion,
struct io_buffer *iobuf ) {
return qp->send.cq->complete_send ( ibdev, qp, completion, iobuf );
}
/**
* Complete receive work queue entry
*
* @v ibdev Infiniband device
* @v qp Queue pair
* @v completion Completion
* @v iobuf I/O buffer
*/
static inline __attribute__ (( always_inline )) void
ib_complete_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp,
struct ib_completion *completion,
struct io_buffer *iobuf ) {
return qp->recv.cq->complete_recv ( ibdev, qp, completion, iobuf );
}
/**
* Poll completion queue
*
* @v ibdev Infiniband device
* @v cq Completion queue
* @v complete_send Send completion handler
* @v complete_recv Receive completion handler
*/
static inline __attribute__ (( always_inline )) void
ib_poll_cq ( struct ib_device *ibdev, struct ib_completion_queue *cq,
ib_completer_t complete_send, ib_completer_t complete_recv ) {
ibdev->op->poll_cq ( ibdev, cq, complete_send, complete_recv );
ib_poll_cq ( struct ib_device *ibdev, struct ib_completion_queue *cq ) {
ibdev->op->poll_cq ( ibdev, cq );
}
/**