[PATCH 5/5] IB/isert: switch on IB pool device interface

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Signed-off-by: Roman Pen <roman.penyaev@xxxxxxxxxxxxxxxx>
Cc: Christoph Hellwig <hch@xxxxxx>
Cc: Steve Wise <swise@xxxxxxxxxxxxxxxxxxxxx>
Cc: Bart Van Assche <bart.vanassche@xxxxxxxxxxx>
Cc: Sagi Grimberg <sagi@xxxxxxxxxxx>
Cc: Doug Ledford <dledford@xxxxxxxxxx>
---
 drivers/infiniband/ulp/isert/ib_isert.c | 191 +++++++++++++-------------------
 drivers/infiniband/ulp/isert/ib_isert.h |   7 +-
 2 files changed, 82 insertions(+), 116 deletions(-)

diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c
index fff40b097947..6d7036fc1017 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.c
+++ b/drivers/infiniband/ulp/isert/ib_isert.c
@@ -42,8 +42,7 @@ static int isert_debug_level;
 module_param_named(debug_level, isert_debug_level, int, 0644);
 MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0 (default:0)");
 
-static DEFINE_MUTEX(device_list_mutex);
-static LIST_HEAD(device_list);
+static struct ib_device_pool ib_devs_pool;
 static struct workqueue_struct *isert_comp_wq;
 static struct workqueue_struct *isert_release_wq;
 
@@ -96,14 +95,14 @@ isert_comp_get(struct isert_conn *isert_conn)
 	struct isert_comp *comp;
 	int i, min = 0;
 
-	mutex_lock(&device_list_mutex);
+	mutex_lock(&device->comps_mutex);
 	for (i = 0; i < device->comps_used; i++)
 		if (device->comps[i].active_qps <
 		    device->comps[min].active_qps)
 			min = i;
 	comp = &device->comps[min];
 	comp->active_qps++;
-	mutex_unlock(&device_list_mutex);
+	mutex_unlock(&device->comps_mutex);
 
 	isert_info("conn %p, using comp %p min_index: %d\n",
 		   isert_conn, comp, min);
@@ -114,9 +113,11 @@ isert_comp_get(struct isert_conn *isert_conn)
 static void
 isert_comp_put(struct isert_comp *comp)
 {
-	mutex_lock(&device_list_mutex);
+	struct isert_device *device = comp->device;
+
+	mutex_lock(&device->comps_mutex);
 	comp->active_qps--;
-	mutex_unlock(&device_list_mutex);
+	mutex_unlock(&device->comps_mutex);
 }
 
 static struct ib_qp *
@@ -136,14 +137,14 @@ isert_create_qp(struct isert_conn *isert_conn,
 	attr.cap.max_send_wr = ISERT_QP_MAX_REQ_DTOS + 1;
 	attr.cap.max_recv_wr = ISERT_QP_MAX_RECV_DTOS + 1;
 	attr.cap.max_rdma_ctxs = ISCSI_DEF_XMIT_CMDS_MAX;
-	attr.cap.max_send_sge = device->ib_device->attrs.max_sge;
+	attr.cap.max_send_sge = device->dev.ib_dev->attrs.max_sge;
 	attr.cap.max_recv_sge = 1;
 	attr.sq_sig_type = IB_SIGNAL_REQ_WR;
 	attr.qp_type = IB_QPT_RC;
 	if (device->pi_capable)
 		attr.create_flags |= IB_QP_CREATE_SIGNATURE_EN;
 
-	ret = rdma_create_qp(cma_id, device->pd, &attr);
+	ret = rdma_create_qp(cma_id, device->dev.ib_pd, &attr);
 	if (ret) {
 		isert_err("rdma_create_qp failed for cma_id %d\n", ret);
 		return ERR_PTR(ret);
@@ -175,7 +176,7 @@ static int
 isert_alloc_rx_descriptors(struct isert_conn *isert_conn)
 {
 	struct isert_device *device = isert_conn->device;
-	struct ib_device *ib_dev = device->ib_device;
+	struct ib_device *ib_dev = device->dev.ib_dev;
 	struct iser_rx_desc *rx_desc;
 	struct ib_sge *rx_sg;
 	u64 dma_addr;
@@ -199,7 +200,7 @@ isert_alloc_rx_descriptors(struct isert_conn *isert_conn)
 		rx_sg = &rx_desc->rx_sg;
 		rx_sg->addr = rx_desc->dma_addr;
 		rx_sg->length = ISER_RX_PAYLOAD_SIZE;
-		rx_sg->lkey = device->pd->local_dma_lkey;
+		rx_sg->lkey = device->dev.ib_pd->local_dma_lkey;
 		rx_desc->rx_cqe.done = isert_recv_done;
 	}
 
@@ -220,7 +221,7 @@ isert_alloc_rx_descriptors(struct isert_conn *isert_conn)
 static void
 isert_free_rx_descriptors(struct isert_conn *isert_conn)
 {
-	struct ib_device *ib_dev = isert_conn->device->ib_device;
+	struct ib_device *ib_dev = isert_conn->device->dev.ib_dev;
 	struct iser_rx_desc *rx_desc;
 	int i;
 
@@ -257,12 +258,12 @@ isert_alloc_comps(struct isert_device *device)
 	int i, max_cqe, ret = 0;
 
 	device->comps_used = min(ISERT_MAX_CQ, min_t(int, num_online_cpus(),
-				 device->ib_device->num_comp_vectors));
+				 device->dev.ib_dev->num_comp_vectors));
 
 	isert_info("Using %d CQs, %s supports %d vectors support "
 		   "pi_capable %d\n",
-		   device->comps_used, device->ib_device->name,
-		   device->ib_device->num_comp_vectors,
+		   device->comps_used, device->dev.ib_dev->name,
+		   device->dev.ib_dev->num_comp_vectors,
 		   device->pi_capable);
 
 	device->comps = kcalloc(device->comps_used, sizeof(struct isert_comp),
@@ -270,13 +271,13 @@ isert_alloc_comps(struct isert_device *device)
 	if (!device->comps)
 		return -ENOMEM;
 
-	max_cqe = min(ISER_MAX_CQ_LEN, device->ib_device->attrs.max_cqe);
+	max_cqe = min(ISER_MAX_CQ_LEN, device->dev.ib_dev->attrs.max_cqe);
 
 	for (i = 0; i < device->comps_used; i++) {
 		struct isert_comp *comp = &device->comps[i];
 
 		comp->device = device;
-		comp->cq = ib_alloc_cq(device->ib_device, comp, max_cqe, i,
+		comp->cq = ib_alloc_cq(device->dev.ib_dev, comp, max_cqe, i,
 				IB_POLL_WORKQUEUE);
 		if (IS_ERR(comp->cq)) {
 			isert_err("Unable to allocate cq\n");
@@ -292,10 +293,36 @@ isert_alloc_comps(struct isert_device *device)
 	return ret;
 }
 
+static struct ib_pool_device *
+isert_ib_pool_dev_alloc(void)
+{
+	struct isert_device *device;
+
+	device = kzalloc(sizeof(*device), GFP_KERNEL);
+	if (likely(device)) {
+		isert_info("device alloced %p\n", device);
+		return &device->dev;
+	}
+
+	return NULL;
+}
+
+static void
+isert_ib_pool_dev_free(struct ib_pool_device *dev)
+{
+	struct isert_device *device;
+
+	device = container_of(dev, typeof(*device), dev);
+	isert_info("device freed %p\n", device);
+
+	isert_free_comps(device);
+	kfree(device);
+}
+
 static int
 isert_create_device_ib_res(struct isert_device *device)
 {
-	struct ib_device *ib_dev = device->ib_device;
+	struct ib_device *ib_dev = device->dev.ib_dev;
 	int ret;
 
 	isert_dbg("devattr->max_sge: %d\n", ib_dev->attrs.max_sge);
@@ -305,91 +332,26 @@ isert_create_device_ib_res(struct isert_device *device)
 	if (ret)
 		goto out;
 
-	device->pd = ib_alloc_pd(ib_dev, 0);
-	if (IS_ERR(device->pd)) {
-		ret = PTR_ERR(device->pd);
-		isert_err("failed to allocate pd, device %p, ret=%d\n",
-			  device, ret);
-		goto out_cq;
-	}
-
 	/* Check signature cap */
 	device->pi_capable = ib_dev->attrs.device_cap_flags &
 			     IB_DEVICE_SIGNATURE_HANDOVER ? true : false;
 
 	return 0;
 
-out_cq:
-	isert_free_comps(device);
 out:
 	if (ret > 0)
 		ret = -EINVAL;
 	return ret;
 }
 
-static void
-isert_free_device_ib_res(struct isert_device *device)
-{
-	isert_info("device %p\n", device);
-
-	ib_dealloc_pd(device->pd);
-	isert_free_comps(device);
-}
-
-static void
-isert_device_put(struct isert_device *device)
-{
-	mutex_lock(&device_list_mutex);
-	device->refcount--;
-	isert_info("device %p refcount %d\n", device, device->refcount);
-	if (!device->refcount) {
-		isert_free_device_ib_res(device);
-		list_del(&device->dev_node);
-		kfree(device);
-	}
-	mutex_unlock(&device_list_mutex);
-}
-
-static struct isert_device *
-isert_device_get(struct rdma_cm_id *cma_id)
+static int isert_ib_pool_dev_init(struct ib_pool_device *dev)
 {
 	struct isert_device *device;
-	int ret;
-
-	mutex_lock(&device_list_mutex);
-	list_for_each_entry(device, &device_list, dev_node) {
-		if (device->ib_device->node_guid == cma_id->device->node_guid) {
-			device->refcount++;
-			isert_info("Found iser device %p refcount %d\n",
-				   device, device->refcount);
-			mutex_unlock(&device_list_mutex);
-			return device;
-		}
-	}
-
-	device = kzalloc(sizeof(struct isert_device), GFP_KERNEL);
-	if (!device) {
-		mutex_unlock(&device_list_mutex);
-		return ERR_PTR(-ENOMEM);
-	}
 
-	INIT_LIST_HEAD(&device->dev_node);
+	device = container_of(dev, typeof(*device), dev);
+	mutex_init(&device->comps_mutex);
 
-	device->ib_device = cma_id->device;
-	ret = isert_create_device_ib_res(device);
-	if (ret) {
-		kfree(device);
-		mutex_unlock(&device_list_mutex);
-		return ERR_PTR(ret);
-	}
-
-	device->refcount++;
-	list_add_tail(&device->dev_node, &device_list);
-	isert_info("Created a new iser device %p refcount %d\n",
-		   device, device->refcount);
-	mutex_unlock(&device_list_mutex);
-
-	return device;
+	return isert_create_device_ib_res(device);
 }
 
 static void
@@ -408,7 +370,7 @@ isert_init_conn(struct isert_conn *isert_conn)
 static void
 isert_free_login_buf(struct isert_conn *isert_conn)
 {
-	struct ib_device *ib_dev = isert_conn->device->ib_device;
+	struct ib_device *ib_dev = isert_conn->device->dev.ib_dev;
 
 	ib_dma_unmap_single(ib_dev, isert_conn->login_rsp_dma,
 			    ISER_RX_PAYLOAD_SIZE, DMA_TO_DEVICE);
@@ -473,7 +435,7 @@ static void
 isert_set_nego_params(struct isert_conn *isert_conn,
 		      struct rdma_conn_param *param)
 {
-	struct ib_device_attr *attr = &isert_conn->device->ib_device->attrs;
+	struct ib_device_attr *attr = &isert_conn->device->dev.ib_dev->attrs;
 
 	/* Set max inflight RDMA READ requests */
 	isert_conn->initiator_depth = min_t(u8, param->initiator_depth,
@@ -500,8 +462,8 @@ isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
 {
 	struct isert_np *isert_np = cma_id->context;
 	struct iscsi_np *np = isert_np->np;
+	struct ib_pool_device *pool_dev;
 	struct isert_conn *isert_conn;
-	struct isert_device *device;
 	int ret = 0;
 
 	spin_lock_bh(&np->np_thread_lock);
@@ -526,12 +488,13 @@ isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
 	if (ret)
 		goto out;
 
-	device = isert_device_get(cma_id);
-	if (IS_ERR(device)) {
-		ret = PTR_ERR(device);
+	pool_dev = ib_pool_dev_find_get_or_create(cma_id->device,
+						  &ib_devs_pool);
+	if (unlikely(!pool_dev)) {
+		ret = -ENOMEM;
 		goto out_rsp_dma_map;
 	}
-	isert_conn->device = device;
+	isert_conn->device = container_of(pool_dev, struct isert_device, dev);
 
 	isert_set_nego_params(isert_conn, &event->param.conn);
 
@@ -554,7 +517,7 @@ isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
 	return 0;
 
 out_conn_dev:
-	isert_device_put(device);
+	ib_pool_dev_put(pool_dev);
 out_rsp_dma_map:
 	isert_free_login_buf(isert_conn);
 out:
@@ -587,7 +550,7 @@ isert_connect_release(struct isert_conn *isert_conn)
 	if (isert_conn->login_req_buf)
 		isert_free_login_buf(isert_conn);
 
-	isert_device_put(device);
+	ib_pool_dev_put(&device->dev);
 
 	if (isert_conn->dev_removed)
 		wake_up_interruptible(&isert_conn->rem_wait);
@@ -891,7 +854,7 @@ isert_create_send_desc(struct isert_conn *isert_conn,
 		       struct iser_tx_desc *tx_desc)
 {
 	struct isert_device *device = isert_conn->device;
-	struct ib_device *ib_dev = device->ib_device;
+	struct ib_device *ib_dev = device->dev.ib_dev;
 
 	ib_dma_sync_single_for_cpu(ib_dev, tx_desc->dma_addr,
 				   ISER_HEADERS_LEN, DMA_TO_DEVICE);
@@ -901,8 +864,8 @@ isert_create_send_desc(struct isert_conn *isert_conn,
 
 	tx_desc->num_sge = 1;
 
-	if (tx_desc->tx_sg[0].lkey != device->pd->local_dma_lkey) {
-		tx_desc->tx_sg[0].lkey = device->pd->local_dma_lkey;
+	if (tx_desc->tx_sg[0].lkey != device->dev.ib_pd->local_dma_lkey) {
+		tx_desc->tx_sg[0].lkey = device->dev.ib_pd->local_dma_lkey;
 		isert_dbg("tx_desc %p lkey mismatch, fixing\n", tx_desc);
 	}
 }
@@ -912,7 +875,7 @@ isert_init_tx_hdrs(struct isert_conn *isert_conn,
 		   struct iser_tx_desc *tx_desc)
 {
 	struct isert_device *device = isert_conn->device;
-	struct ib_device *ib_dev = device->ib_device;
+	struct ib_device *ib_dev = device->dev.ib_dev;
 	u64 dma_addr;
 
 	dma_addr = ib_dma_map_single(ib_dev, (void *)tx_desc,
@@ -925,7 +888,7 @@ isert_init_tx_hdrs(struct isert_conn *isert_conn,
 	tx_desc->dma_addr = dma_addr;
 	tx_desc->tx_sg[0].addr	= tx_desc->dma_addr;
 	tx_desc->tx_sg[0].length = ISER_HEADERS_LEN;
-	tx_desc->tx_sg[0].lkey = device->pd->local_dma_lkey;
+	tx_desc->tx_sg[0].lkey = device->dev.ib_pd->local_dma_lkey;
 
 	isert_dbg("Setup tx_sg[0].addr: 0x%llx length: %u lkey: 0x%x\n",
 		  tx_desc->tx_sg[0].addr, tx_desc->tx_sg[0].length,
@@ -965,7 +928,7 @@ isert_login_post_recv(struct isert_conn *isert_conn)
 	memset(&sge, 0, sizeof(struct ib_sge));
 	sge.addr = isert_conn->login_req_dma;
 	sge.length = ISER_RX_PAYLOAD_SIZE;
-	sge.lkey = isert_conn->device->pd->local_dma_lkey;
+	sge.lkey = isert_conn->device->dev.ib_pd->local_dma_lkey;
 
 	isert_dbg("Setup sge: addr: %llx length: %d 0x%08x\n",
 		sge.addr, sge.length, sge.lkey);
@@ -990,7 +953,7 @@ isert_put_login_tx(struct iscsi_conn *conn, struct iscsi_login *login,
 {
 	struct isert_conn *isert_conn = conn->context;
 	struct isert_device *device = isert_conn->device;
-	struct ib_device *ib_dev = device->ib_device;
+	struct ib_device *ib_dev = device->dev.ib_dev;
 	struct iser_tx_desc *tx_desc = &isert_conn->login_tx_desc;
 	int ret;
 
@@ -1014,7 +977,7 @@ isert_put_login_tx(struct iscsi_conn *conn, struct iscsi_login *login,
 
 		tx_dsg->addr	= isert_conn->login_rsp_dma;
 		tx_dsg->length	= length;
-		tx_dsg->lkey	= isert_conn->device->pd->local_dma_lkey;
+		tx_dsg->lkey	= isert_conn->device->dev.ib_pd->local_dma_lkey;
 		tx_desc->num_sge = 2;
 	}
 	if (!login->login_failed) {
@@ -1454,7 +1417,7 @@ static void
 isert_login_recv_done(struct ib_cq *cq, struct ib_wc *wc)
 {
 	struct isert_conn *isert_conn = wc->qp->qp_context;
-	struct ib_device *ib_dev = isert_conn->device->ib_device;
+	struct ib_device *ib_dev = isert_conn->device->dev.ib_dev;
 
 	if (unlikely(wc->status != IB_WC_SUCCESS)) {
 		isert_print_wc(wc, "login recv");
@@ -1662,7 +1625,7 @@ isert_rdma_write_done(struct ib_cq *cq, struct ib_wc *wc)
 		isert_print_wc(wc, "rdma write");
 		if (wc->status != IB_WC_WR_FLUSH_ERR)
 			iscsit_cause_connection_reinstatement(isert_conn->conn, 0);
-		isert_completion_put(desc, isert_cmd, device->ib_device, true);
+		isert_completion_put(desc, isert_cmd, device->dev.ib_dev, true);
 		return;
 	}
 
@@ -1705,7 +1668,7 @@ isert_rdma_read_done(struct ib_cq *cq, struct ib_wc *wc)
 		isert_print_wc(wc, "rdma read");
 		if (wc->status != IB_WC_WR_FLUSH_ERR)
 			iscsit_cause_connection_reinstatement(isert_conn->conn, 0);
-		isert_completion_put(desc, isert_cmd, device->ib_device, true);
+		isert_completion_put(desc, isert_cmd, device->dev.ib_dev, true);
 		return;
 	}
 
@@ -1857,7 +1820,7 @@ isert_put_response(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
 	    ((cmd->se_cmd.se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) ||
 	    (cmd->se_cmd.se_cmd_flags & SCF_EMULATED_TASK_SENSE))) {
 		struct isert_device *device = isert_conn->device;
-		struct ib_device *ib_dev = device->ib_device;
+		struct ib_device *ib_dev = device->dev.ib_dev;
 		struct ib_sge *tx_dsg = &isert_cmd->tx_desc.tx_sg[1];
 		u32 padding, pdu_len;
 
@@ -1878,7 +1841,7 @@ isert_put_response(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
 		isert_cmd->pdu_buf_len = pdu_len;
 		tx_dsg->addr	= isert_cmd->pdu_buf_dma;
 		tx_dsg->length	= pdu_len;
-		tx_dsg->lkey	= device->pd->local_dma_lkey;
+		tx_dsg->lkey	= device->dev.ib_pd->local_dma_lkey;
 		isert_cmd->tx_desc.num_sge = 2;
 	}
 
@@ -1988,7 +1951,7 @@ isert_put_reject(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
 	struct isert_conn *isert_conn = conn->context;
 	struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr;
 	struct isert_device *device = isert_conn->device;
-	struct ib_device *ib_dev = device->ib_device;
+	struct ib_device *ib_dev = device->dev.ib_dev;
 	struct ib_sge *tx_dsg = &isert_cmd->tx_desc.tx_sg[1];
 	struct iscsi_reject *hdr =
 		(struct iscsi_reject *)&isert_cmd->tx_desc.iscsi_header;
@@ -2006,7 +1969,7 @@ isert_put_reject(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
 	isert_cmd->pdu_buf_len = ISCSI_HDR_LEN;
 	tx_dsg->addr	= isert_cmd->pdu_buf_dma;
 	tx_dsg->length	= ISCSI_HDR_LEN;
-	tx_dsg->lkey	= device->pd->local_dma_lkey;
+	tx_dsg->lkey	= device->dev.ib_pd->local_dma_lkey;
 	isert_cmd->tx_desc.num_sge = 2;
 
 	isert_init_send_wr(isert_conn, isert_cmd, send_wr);
@@ -2037,7 +2000,7 @@ isert_put_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
 
 	if (txt_rsp_len) {
 		struct isert_device *device = isert_conn->device;
-		struct ib_device *ib_dev = device->ib_device;
+		struct ib_device *ib_dev = device->dev.ib_dev;
 		struct ib_sge *tx_dsg = &isert_cmd->tx_desc.tx_sg[1];
 		void *txt_rsp_buf = cmd->buf_ptr;
 
@@ -2049,7 +2012,7 @@ isert_put_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
 		isert_cmd->pdu_buf_len = txt_rsp_len;
 		tx_dsg->addr	= isert_cmd->pdu_buf_dma;
 		tx_dsg->length	= txt_rsp_len;
-		tx_dsg->lkey	= device->pd->local_dma_lkey;
+		tx_dsg->lkey	= device->dev.ib_pd->local_dma_lkey;
 		isert_cmd->tx_desc.num_sge = 2;
 	}
 	isert_init_send_wr(isert_conn, isert_cmd, send_wr);
@@ -2682,6 +2645,9 @@ static int __init isert_init(void)
 {
 	int ret;
 
+	ib_pool_dev_init(0, isert_ib_pool_dev_alloc, isert_ib_pool_dev_free,
+			 isert_ib_pool_dev_init,  &ib_devs_pool);
+
 	isert_comp_wq = alloc_workqueue("isert_comp_wq",
 					WQ_UNBOUND | WQ_HIGHPRI, 0);
 	if (!isert_comp_wq) {
@@ -2714,6 +2680,7 @@ static void __exit isert_exit(void)
 	destroy_workqueue(isert_release_wq);
 	destroy_workqueue(isert_comp_wq);
 	iscsit_unregister_transport(&iser_target_transport);
+	ib_pool_dev_deinit(&ib_devs_pool);
 	isert_info("iSER_TARGET[0] - Released iser_target_transport\n");
 }
 
diff --git a/drivers/infiniband/ulp/isert/ib_isert.h b/drivers/infiniband/ulp/isert/ib_isert.h
index 3b296bac4f60..4d2cab73728a 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.h
+++ b/drivers/infiniband/ulp/isert/ib_isert.h
@@ -4,6 +4,7 @@
 #include <linux/in6.h>
 #include <rdma/ib_verbs.h>
 #include <rdma/rdma_cm.h>
+#include <rdma/dev_pool.h>
 #include <rdma/rw.h>
 #include <scsi/iser.h>
 
@@ -182,13 +183,11 @@ struct isert_comp {
 };
 
 struct isert_device {
+	struct ib_pool_device	dev;
 	bool			pi_capable;
-	int			refcount;
-	struct ib_device	*ib_device;
-	struct ib_pd		*pd;
 	struct isert_comp	*comps;
 	int                     comps_used;
-	struct list_head	dev_node;
+	struct mutex            comps_mutex;
 };
 
 struct isert_np {
-- 
2.13.1

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Photo]     [Yosemite News]     [Yosemite Photos]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux