linux/drivers/staging/lustre/lustre/ptlrpc/connection.c
<<
>>
Prefs
   1/*
   2 * GPL HEADER START
   3 *
   4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 only,
   8 * as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful, but
  11 * WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13 * General Public License version 2 for more details (a copy is included
  14 * in the LICENSE file that accompanied this code).
  15 *
  16 * You should have received a copy of the GNU General Public License
  17 * version 2 along with this program; If not, see
  18 * http://www.gnu.org/licenses/gpl-2.0.html
  19 *
  20 * GPL HEADER END
  21 */
  22/*
  23 * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
  24 * Use is subject to license terms.
  25 *
  26 * Copyright (c) 2011, Intel Corporation.
  27 */
  28/*
  29 * This file is part of Lustre, http://www.lustre.org/
  30 * Lustre is a trademark of Sun Microsystems, Inc.
  31 */
  32
  33#define DEBUG_SUBSYSTEM S_RPC
  34#include "../include/obd_support.h"
  35#include "../include/obd_class.h"
  36#include "../include/lustre_net.h"
  37
  38#include "ptlrpc_internal.h"
  39
  40static struct cfs_hash *conn_hash;
  41static struct cfs_hash_ops conn_hash_ops;
  42
  43struct ptlrpc_connection *
  44ptlrpc_connection_get(lnet_process_id_t peer, lnet_nid_t self,
  45                      struct obd_uuid *uuid)
  46{
  47        struct ptlrpc_connection *conn, *conn2;
  48
  49        conn = cfs_hash_lookup(conn_hash, &peer);
  50        if (conn)
  51                goto out;
  52
  53        conn = kzalloc(sizeof(*conn), GFP_NOFS);
  54        if (!conn)
  55                return NULL;
  56
  57        conn->c_peer = peer;
  58        conn->c_self = self;
  59        INIT_HLIST_NODE(&conn->c_hash);
  60        atomic_set(&conn->c_refcount, 1);
  61        if (uuid)
  62                obd_str2uuid(&conn->c_remote_uuid, uuid->uuid);
  63
  64        /*
  65         * Add the newly created conn to the hash, on key collision we
  66         * lost a racing addition and must destroy our newly allocated
  67         * connection.  The object which exists in the has will be
  68         * returned and may be compared against out object.
  69         */
  70        /* In the function below, .hs_keycmp resolves to
  71         * conn_keycmp()
  72         */
  73        /* coverity[overrun-buffer-val] */
  74        conn2 = cfs_hash_findadd_unique(conn_hash, &peer, &conn->c_hash);
  75        if (conn != conn2) {
  76                kfree(conn);
  77                conn = conn2;
  78        }
  79out:
  80        CDEBUG(D_INFO, "conn=%p refcount %d to %s\n",
  81               conn, atomic_read(&conn->c_refcount),
  82               libcfs_nid2str(conn->c_peer.nid));
  83        return conn;
  84}
  85
  86int ptlrpc_connection_put(struct ptlrpc_connection *conn)
  87{
  88        int rc = 0;
  89
  90        if (!conn)
  91                return rc;
  92
  93        LASSERT(atomic_read(&conn->c_refcount) > 1);
  94
  95        /*
  96         * We do not remove connection from hashtable and
  97         * do not free it even if last caller released ref,
  98         * as we want to have it cached for the case it is
  99         * needed again.
 100         *
 101         * Deallocating it and later creating new connection
 102         * again would be wastful. This way we also avoid
 103         * expensive locking to protect things from get/put
 104         * race when found cached connection is freed by
 105         * ptlrpc_connection_put().
 106         *
 107         * It will be freed later in module unload time,
 108         * when ptlrpc_connection_fini()->lh_exit->conn_exit()
 109         * path is called.
 110         */
 111        if (atomic_dec_return(&conn->c_refcount) == 1)
 112                rc = 1;
 113
 114        CDEBUG(D_INFO, "PUT conn=%p refcount %d to %s\n",
 115               conn, atomic_read(&conn->c_refcount),
 116               libcfs_nid2str(conn->c_peer.nid));
 117
 118        return rc;
 119}
 120
 121struct ptlrpc_connection *
 122ptlrpc_connection_addref(struct ptlrpc_connection *conn)
 123{
 124        atomic_inc(&conn->c_refcount);
 125        CDEBUG(D_INFO, "conn=%p refcount %d to %s\n",
 126               conn, atomic_read(&conn->c_refcount),
 127               libcfs_nid2str(conn->c_peer.nid));
 128
 129        return conn;
 130}
 131
 132int ptlrpc_connection_init(void)
 133{
 134        conn_hash = cfs_hash_create("CONN_HASH",
 135                                    HASH_CONN_CUR_BITS,
 136                                    HASH_CONN_MAX_BITS,
 137                                    HASH_CONN_BKT_BITS, 0,
 138                                    CFS_HASH_MIN_THETA,
 139                                    CFS_HASH_MAX_THETA,
 140                                    &conn_hash_ops, CFS_HASH_DEFAULT);
 141        if (!conn_hash)
 142                return -ENOMEM;
 143
 144        return 0;
 145}
 146
 147void ptlrpc_connection_fini(void)
 148{
 149        cfs_hash_putref(conn_hash);
 150}
 151
 152/*
 153 * Hash operations for net_peer<->connection
 154 */
 155static unsigned
 156conn_hashfn(struct cfs_hash *hs, const void *key, unsigned mask)
 157{
 158        return cfs_hash_djb2_hash(key, sizeof(lnet_process_id_t), mask);
 159}
 160
 161static int
 162conn_keycmp(const void *key, struct hlist_node *hnode)
 163{
 164        struct ptlrpc_connection *conn;
 165        const lnet_process_id_t *conn_key;
 166
 167        LASSERT(key);
 168        conn_key = key;
 169        conn = hlist_entry(hnode, struct ptlrpc_connection, c_hash);
 170
 171        return conn_key->nid == conn->c_peer.nid &&
 172               conn_key->pid == conn->c_peer.pid;
 173}
 174
 175static void *
 176conn_key(struct hlist_node *hnode)
 177{
 178        struct ptlrpc_connection *conn;
 179
 180        conn = hlist_entry(hnode, struct ptlrpc_connection, c_hash);
 181        return &conn->c_peer;
 182}
 183
 184static void *
 185conn_object(struct hlist_node *hnode)
 186{
 187        return hlist_entry(hnode, struct ptlrpc_connection, c_hash);
 188}
 189
 190static void
 191conn_get(struct cfs_hash *hs, struct hlist_node *hnode)
 192{
 193        struct ptlrpc_connection *conn;
 194
 195        conn = hlist_entry(hnode, struct ptlrpc_connection, c_hash);
 196        atomic_inc(&conn->c_refcount);
 197}
 198
 199static void
 200conn_put_locked(struct cfs_hash *hs, struct hlist_node *hnode)
 201{
 202        struct ptlrpc_connection *conn;
 203
 204        conn = hlist_entry(hnode, struct ptlrpc_connection, c_hash);
 205        atomic_dec(&conn->c_refcount);
 206}
 207
 208static void
 209conn_exit(struct cfs_hash *hs, struct hlist_node *hnode)
 210{
 211        struct ptlrpc_connection *conn;
 212
 213        conn = hlist_entry(hnode, struct ptlrpc_connection, c_hash);
 214        /*
 215         * Nothing should be left. Connection user put it and
 216         * connection also was deleted from table by this time
 217         * so we should have 0 refs.
 218         */
 219        LASSERTF(atomic_read(&conn->c_refcount) == 0,
 220                 "Busy connection with %d refs\n",
 221                 atomic_read(&conn->c_refcount));
 222        kfree(conn);
 223}
 224
 225static struct cfs_hash_ops conn_hash_ops = {
 226        .hs_hash        = conn_hashfn,
 227        .hs_keycmp      = conn_keycmp,
 228        .hs_key         = conn_key,
 229        .hs_object      = conn_object,
 230        .hs_get         = conn_get,
 231        .hs_put_locked  = conn_put_locked,
 232        .hs_exit        = conn_exit,
 233};
 234