linux/drivers/staging/lustre/lnet/libcfs/libcfs_lock.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * GPL HEADER START
   4 *
   5 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 only,
   9 * as published by the Free Software Foundation.
  10 *
  11 * This program is distributed in the hope that it will be useful, but
  12 * WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14 * General Public License version 2 for more details (a copy is included
  15 * in the LICENSE file that accompanied this code).
  16 *
  17 * GPL HEADER END
  18 */
  19/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  20 * Copyright (c) 2012, 2015 Intel Corporation.
  21 */
  22/*
  23 * This file is part of Lustre, http://www.lustre.org/
  24 * Lustre is a trademark of Sun Microsystems, Inc.
  25 *
  26 * Author: liang@whamcloud.com
  27 */
  28
  29#define DEBUG_SUBSYSTEM S_LNET
  30
  31#include <linux/libcfs/libcfs.h>
  32
  33/** destroy cpu-partition lock, see libcfs_private.h for more detail */
  34void
  35cfs_percpt_lock_free(struct cfs_percpt_lock *pcl)
  36{
  37        LASSERT(pcl->pcl_locks);
  38        LASSERT(!pcl->pcl_locked);
  39
  40        cfs_percpt_free(pcl->pcl_locks);
  41        kfree(pcl);
  42}
  43EXPORT_SYMBOL(cfs_percpt_lock_free);
  44
  45/**
  46 * create cpu-partition lock, see libcfs_private.h for more detail.
  47 *
  48 * cpu-partition lock is designed for large-scale SMP system, so we need to
  49 * reduce cacheline conflict as possible as we can, that's the
  50 * reason we always allocate cacheline-aligned memory block.
  51 */
  52struct cfs_percpt_lock *
  53cfs_percpt_lock_create(struct cfs_cpt_table *cptab,
  54                       struct lock_class_key *keys)
  55{
  56        struct cfs_percpt_lock *pcl;
  57        spinlock_t *lock;
  58        int i;
  59
  60        /* NB: cptab can be NULL, pcl will be for HW CPUs on that case */
  61        pcl = kzalloc(sizeof(*pcl), GFP_NOFS);
  62        if (!pcl)
  63                return NULL;
  64
  65        pcl->pcl_cptab = cptab;
  66        pcl->pcl_locks = cfs_percpt_alloc(cptab, sizeof(*lock));
  67        if (!pcl->pcl_locks) {
  68                kfree(pcl);
  69                return NULL;
  70        }
  71
  72        if (!keys)
  73                CWARN("Cannot setup class key for percpt lock, you may see recursive locking warnings which are actually fake.\n");
  74
  75        cfs_percpt_for_each(lock, i, pcl->pcl_locks) {
  76                spin_lock_init(lock);
  77                if (keys)
  78                        lockdep_set_class(lock, &keys[i]);
  79        }
  80
  81        return pcl;
  82}
  83EXPORT_SYMBOL(cfs_percpt_lock_create);
  84
  85/**
  86 * lock a CPU partition
  87 *
  88 * \a index != CFS_PERCPT_LOCK_EX
  89 *     hold private lock indexed by \a index
  90 *
  91 * \a index == CFS_PERCPT_LOCK_EX
  92 *     exclusively lock @pcl and nobody can take private lock
  93 */
  94void
  95cfs_percpt_lock(struct cfs_percpt_lock *pcl, int index)
  96        __acquires(pcl->pcl_locks)
  97{
  98        int ncpt = cfs_cpt_number(pcl->pcl_cptab);
  99        int i;
 100
 101        LASSERT(index >= CFS_PERCPT_LOCK_EX && index < ncpt);
 102
 103        if (ncpt == 1) {
 104                index = 0;
 105        } else { /* serialize with exclusive lock */
 106                while (pcl->pcl_locked)
 107                        cpu_relax();
 108        }
 109
 110        if (likely(index != CFS_PERCPT_LOCK_EX)) {
 111                spin_lock(pcl->pcl_locks[index]);
 112                return;
 113        }
 114
 115        /* exclusive lock request */
 116        for (i = 0; i < ncpt; i++) {
 117                spin_lock(pcl->pcl_locks[i]);
 118                if (!i) {
 119                        LASSERT(!pcl->pcl_locked);
 120                        /* nobody should take private lock after this
 121                         * so I wouldn't starve for too long time
 122                         */
 123                        pcl->pcl_locked = 1;
 124                }
 125        }
 126}
 127EXPORT_SYMBOL(cfs_percpt_lock);
 128
 129/** unlock a CPU partition */
 130void
 131cfs_percpt_unlock(struct cfs_percpt_lock *pcl, int index)
 132        __releases(pcl->pcl_locks)
 133{
 134        int ncpt = cfs_cpt_number(pcl->pcl_cptab);
 135        int i;
 136
 137        index = ncpt == 1 ? 0 : index;
 138
 139        if (likely(index != CFS_PERCPT_LOCK_EX)) {
 140                spin_unlock(pcl->pcl_locks[index]);
 141                return;
 142        }
 143
 144        for (i = ncpt - 1; i >= 0; i--) {
 145                if (!i) {
 146                        LASSERT(pcl->pcl_locked);
 147                        pcl->pcl_locked = 0;
 148                }
 149                spin_unlock(pcl->pcl_locks[i]);
 150        }
 151}
 152EXPORT_SYMBOL(cfs_percpt_unlock);
 153