linux/drivers/staging/lustre/lustre/libcfs/libcfs_mem.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, write to the
  18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  19 * Boston, MA 021110-1307, USA
  20 *
  21 * GPL HEADER END
  22 */
  23/*
  24 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  25 * Copyright (c) 2012, Intel Corporation.
  26 */
  27/*
  28 * This file is part of Lustre, http://www.lustre.org/
  29 * Lustre is a trademark of Sun Microsystems, Inc.
  30 *
  31 * Author: liang@whamcloud.com
  32 */
  33
  34#ifndef EXPORT_SYMTAB
  35# define EXPORT_SYMTAB
  36#endif
  37#define DEBUG_SUBSYSTEM S_LNET
  38
  39#include <linux/libcfs/libcfs.h>
  40
  41struct cfs_var_array {
  42        unsigned int            va_count;       /* # of buffers */
  43        unsigned int            va_size;        /* size of each var */
  44        struct cfs_cpt_table    *va_cptab;      /* cpu partition table */
  45        void                    *va_ptrs[0];    /* buffer addresses */
  46};
  47
  48/*
  49 * free per-cpu data, see more detail in cfs_percpt_free
  50 */
  51void
  52cfs_percpt_free(void *vars)
  53{
  54        struct  cfs_var_array *arr;
  55        int     i;
  56
  57        arr = container_of(vars, struct cfs_var_array, va_ptrs[0]);
  58
  59        for (i = 0; i < arr->va_count; i++) {
  60                if (arr->va_ptrs[i] != NULL)
  61                        LIBCFS_FREE(arr->va_ptrs[i], arr->va_size);
  62        }
  63
  64        LIBCFS_FREE(arr, offsetof(struct cfs_var_array,
  65                                  va_ptrs[arr->va_count]));
  66}
  67EXPORT_SYMBOL(cfs_percpt_free);
  68
  69/*
  70 * allocate per cpu-partition variables, returned value is an array of pointers,
  71 * variable can be indexed by CPU partition ID, i.e:
  72 *
  73 *      arr = cfs_percpt_alloc(cfs_cpu_pt, size);
  74 *      then caller can access memory block for CPU 0 by arr[0],
  75 *      memory block for CPU 1 by arr[1]...
  76 *      memory block for CPU N by arr[N]...
  77 *
  78 * cacheline aligned.
  79 */
  80void *
  81cfs_percpt_alloc(struct cfs_cpt_table *cptab, unsigned int size)
  82{
  83        struct cfs_var_array    *arr;
  84        int                     count;
  85        int                     i;
  86
  87        count = cfs_cpt_number(cptab);
  88
  89        LIBCFS_ALLOC(arr, offsetof(struct cfs_var_array, va_ptrs[count]));
  90        if (arr == NULL)
  91                return NULL;
  92
  93        arr->va_size    = size = L1_CACHE_ALIGN(size);
  94        arr->va_count   = count;
  95        arr->va_cptab   = cptab;
  96
  97        for (i = 0; i < count; i++) {
  98                LIBCFS_CPT_ALLOC(arr->va_ptrs[i], cptab, i, size);
  99                if (arr->va_ptrs[i] == NULL) {
 100                        cfs_percpt_free((void *)&arr->va_ptrs[0]);
 101                        return NULL;
 102                }
 103        }
 104
 105        return (void *)&arr->va_ptrs[0];
 106}
 107EXPORT_SYMBOL(cfs_percpt_alloc);
 108
 109/*
 110 * return number of CPUs (or number of elements in per-cpu data)
 111 * according to cptab of @vars
 112 */
 113int
 114cfs_percpt_number(void *vars)
 115{
 116        struct cfs_var_array *arr;
 117
 118        arr = container_of(vars, struct cfs_var_array, va_ptrs[0]);
 119
 120        return arr->va_count;
 121}
 122EXPORT_SYMBOL(cfs_percpt_number);
 123
 124/*
 125 * return memory block shadowed from current CPU
 126 */
 127void *
 128cfs_percpt_current(void *vars)
 129{
 130        struct cfs_var_array *arr;
 131        int    cpt;
 132
 133        arr = container_of(vars, struct cfs_var_array, va_ptrs[0]);
 134        cpt = cfs_cpt_current(arr->va_cptab, 0);
 135        if (cpt < 0)
 136                return NULL;
 137
 138        return arr->va_ptrs[cpt];
 139}
 140EXPORT_SYMBOL(cfs_percpt_current);
 141
 142void *
 143cfs_percpt_index(void *vars, int idx)
 144{
 145        struct cfs_var_array *arr;
 146
 147        arr = container_of(vars, struct cfs_var_array, va_ptrs[0]);
 148
 149        LASSERT(idx >= 0 && idx < arr->va_count);
 150        return arr->va_ptrs[idx];
 151}
 152EXPORT_SYMBOL(cfs_percpt_index);
 153
 154/*
 155 * free variable array, see more detail in cfs_array_alloc
 156 */
 157void
 158cfs_array_free(void *vars)
 159{
 160        struct cfs_var_array    *arr;
 161        int                     i;
 162
 163        arr = container_of(vars, struct cfs_var_array, va_ptrs[0]);
 164
 165        for (i = 0; i < arr->va_count; i++) {
 166                if (arr->va_ptrs[i] == NULL)
 167                        continue;
 168
 169                LIBCFS_FREE(arr->va_ptrs[i], arr->va_size);
 170        }
 171        LIBCFS_FREE(arr, offsetof(struct cfs_var_array,
 172                                  va_ptrs[arr->va_count]));
 173}
 174EXPORT_SYMBOL(cfs_array_free);
 175
 176/*
 177 * allocate a variable array, returned value is an array of pointers.
 178 * Caller can specify length of array by @count, @size is size of each
 179 * memory block in array.
 180 */
 181void *
 182cfs_array_alloc(int count, unsigned int size)
 183{
 184        struct cfs_var_array    *arr;
 185        int                     i;
 186
 187        LIBCFS_ALLOC(arr, offsetof(struct cfs_var_array, va_ptrs[count]));
 188        if (arr == NULL)
 189                return NULL;
 190
 191        arr->va_count   = count;
 192        arr->va_size    = size;
 193
 194        for (i = 0; i < count; i++) {
 195                LIBCFS_ALLOC(arr->va_ptrs[i], size);
 196
 197                if (arr->va_ptrs[i] == NULL) {
 198                        cfs_array_free((void *)&arr->va_ptrs[0]);
 199                        return NULL;
 200                }
 201        }
 202
 203        return (void *)&arr->va_ptrs[0];
 204}
 205EXPORT_SYMBOL(cfs_array_alloc);
 206