/* * Copyright (c) 2016 Oracle. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * OpenIB.org BSD license below: * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE.
*/
#include"ib_mr.h"
staticinlinevoid
rds_transition_frwr_state(struct rds_ib_mr *ibmr, enum rds_ib_fr_state old_state, enum rds_ib_fr_state new_state)
{ if (cmpxchg(&ibmr->u.frmr.fr_state,
old_state, new_state) == old_state &&
old_state == FRMR_IS_INUSE) { /* enforce order of ibmr->u.frmr.fr_state update * before decrementing i_fastreg_inuse_count
*/
smp_mb__before_atomic();
atomic_dec(&ibmr->ic->i_fastreg_inuse_count); if (waitqueue_active(&rds_ib_ring_empty_wait))
wake_up(&rds_ib_ring_empty_wait);
}
}
if (drop)
llist_add(&ibmr->llnode, &pool->drop_list); else
llist_add(&ibmr->llnode, &pool->free_list);
atomic_add(ibmr->sg_len, &pool->free_pinned);
atomic_inc(&pool->dirty_count);
/* If we've pinned too many pages, request a flush */ if (atomic_read(&pool->free_pinned) >= pool->max_free_pinned ||
atomic_read(&pool->dirty_count) >= pool->max_items / 5)
queue_delayed_work(rds_ib_mr_wq, &pool->flush_worker, 10);
}
staticint rds_ib_post_reg_frmr(struct rds_ib_mr *ibmr)
{ struct rds_ib_frmr *frmr = &ibmr->u.frmr; struct ib_reg_wr reg_wr; int ret, off = 0;
while (atomic_dec_return(&ibmr->ic->i_fastreg_wrs) <= 0) {
atomic_inc(&ibmr->ic->i_fastreg_wrs);
cpu_relax();
}
ret = ib_map_mr_sg_zbva(frmr->mr, ibmr->sg, ibmr->sg_dma_len,
&off, PAGE_SIZE); if (unlikely(ret != ibmr->sg_dma_len)) {
ret = ret < 0 ? ret : -EINVAL; goto out_inc;
}
if (cmpxchg(&frmr->fr_state, FRMR_IS_FREE, FRMR_IS_INUSE) != FRMR_IS_FREE) {
ret = -EBUSY; goto out_inc;
}
atomic_inc(&ibmr->ic->i_fastreg_inuse_count);
/* Perform a WR for the fast_reg_mr. Each individual page * in the sg list is added to the fast reg page list and placed * inside the fast_reg_mr WR. The key used is a rolling 8bit * counter, which should guarantee uniqueness.
*/
ib_update_fast_reg_key(frmr->mr, ibmr->remap_count++);
frmr->fr_reg = true;
ret = ib_post_send(ibmr->ic->i_cm_id->qp, ®_wr.wr, NULL); if (unlikely(ret)) { /* Failure here can be because of -ENOMEM as well */
rds_transition_frwr_state(ibmr, FRMR_IS_INUSE, FRMR_IS_STALE);
if (printk_ratelimit())
pr_warn("RDS/IB: %s returned error(%d)\n",
__func__, ret); goto out_inc;
}
/* Wait for the registration to complete in order to prevent an invalid * access error resulting from a race between the memory region already * being accessed while registration is still pending.
*/
wait_event(frmr->fr_reg_done, !frmr->fr_reg);
ret = ib_post_send(i_cm_id->qp, s_wr, NULL); if (unlikely(ret)) {
rds_transition_frwr_state(ibmr, FRMR_IS_INUSE, FRMR_IS_STALE);
frmr->fr_inv = false; /* enforce order of frmr->fr_inv update * before incrementing i_fastreg_wrs
*/
smp_mb__before_atomic();
atomic_inc(&ibmr->ic->i_fastreg_wrs);
pr_err("RDS/IB: %s returned error(%d)\n", __func__, ret); goto out;
}
/* Wait for the FRMR_IS_FREE (or FRMR_IS_STALE) transition in order to * 1) avoid a silly bouncing between "clean_list" and "drop_list" * triggered by function "rds_ib_reg_frmr" as it is releases frmr * regions whose state is not "FRMR_IS_FREE" right away. * 2) prevents an invalid access error in a race * from a pending "IB_WR_LOCAL_INV" operation * with a teardown ("dma_unmap_sg", "put_page") * and de-registration ("ib_dereg_mr") of the corresponding * memory region.
*/
wait_event(frmr->fr_inv_done, frmr->fr_state != FRMR_IS_INUSE);
/* String all ib_mr's onto one list and hand them to ib_unmap_fmr */
list_for_each_entry(ibmr, list, unmap_list) { if (ibmr->sg_dma_len) {
ret2 = rds_ib_post_inv(ibmr); if (ret2 && !ret)
ret = ret2;
}
}
if (ret)
pr_warn("RDS/IB: %s failed (err=%d)\n", __func__, ret);
/* Now we can destroy the DMA mapping and unpin any pages */
list_for_each_entry_safe(ibmr, next, list, unmap_list) {
*unpinned += ibmr->sg_len;
frmr = &ibmr->u.frmr;
__rds_ib_teardown_mr(ibmr); if (freed < goal || frmr->fr_state == FRMR_IS_STALE) { /* Don't de-allocate if the MR is not free yet */ if (frmr->fr_state == FRMR_IS_INUSE) continue;
if (ibmr->pool->pool_type == RDS_IB_MR_8K_POOL)
rds_ib_stats_inc(s_ib_rdma_mr_8k_free); else
rds_ib_stats_inc(s_ib_rdma_mr_1m_free);
list_del(&ibmr->unmap_list); if (frmr->mr)
ib_dereg_mr(frmr->mr);
kfree(ibmr);
freed++;
}
}
*nfreed = freed;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.