linux/drivers/staging/lustre/lustre/lov/lov_pool.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://http://www.gnu.org/licenses/gpl-2.0.html
  19 *
  20 * GPL HEADER END
  21 */
  22/*
  23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  24 * Use is subject to license terms.
  25 *
  26 * Copyright (c) 2012, 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 * lustre/lov/lov_pool.c
  33 *
  34 * OST pool methods
  35 *
  36 * Author: Jacques-Charles LAFOUCRIERE <jc.lafoucriere@cea.fr>
  37 * Author: Alex Lyashkov <Alexey.Lyashkov@Sun.COM>
  38 * Author: Nathaniel Rutman <Nathan.Rutman@Sun.COM>
  39 */
  40
  41#define DEBUG_SUBSYSTEM S_LOV
  42
  43#include <linux/libcfs/libcfs.h>
  44
  45#include <obd.h>
  46#include "lov_internal.h"
  47
  48#define pool_tgt(_p, _i) \
  49                _p->pool_lobd->u.lov.lov_tgts[_p->pool_obds.op_array[_i]]
  50
  51static void lov_pool_getref(struct pool_desc *pool)
  52{
  53        CDEBUG(D_INFO, "pool %p\n", pool);
  54        atomic_inc(&pool->pool_refcount);
  55}
  56
  57void lov_pool_putref(struct pool_desc *pool)
  58{
  59        CDEBUG(D_INFO, "pool %p\n", pool);
  60        if (atomic_dec_and_test(&pool->pool_refcount)) {
  61                LASSERT(hlist_unhashed(&pool->pool_hash));
  62                LASSERT(list_empty(&pool->pool_list));
  63                LASSERT(!pool->pool_debugfs_entry);
  64                lov_ost_pool_free(&pool->pool_obds);
  65                kfree(pool);
  66        }
  67}
  68
  69static void lov_pool_putref_locked(struct pool_desc *pool)
  70{
  71        CDEBUG(D_INFO, "pool %p\n", pool);
  72        LASSERT(atomic_read(&pool->pool_refcount) > 1);
  73
  74        atomic_dec(&pool->pool_refcount);
  75}
  76
  77/*
  78 * hash function using a Rotating Hash algorithm
  79 * Knuth, D. The Art of Computer Programming,
  80 * Volume 3: Sorting and Searching,
  81 * Chapter 6.4.
  82 * Addison Wesley, 1973
  83 */
  84static __u32 pool_hashfn(struct cfs_hash *hash_body, const void *key,
  85                         unsigned int mask)
  86{
  87        int i;
  88        __u32 result;
  89        char *poolname;
  90
  91        result = 0;
  92        poolname = (char *)key;
  93        for (i = 0; i < LOV_MAXPOOLNAME; i++) {
  94                if (poolname[i] == '\0')
  95                        break;
  96                result = (result << 4) ^ (result >> 28) ^  poolname[i];
  97        }
  98        return (result % mask);
  99}
 100
 101static void *pool_key(struct hlist_node *hnode)
 102{
 103        struct pool_desc *pool;
 104
 105        pool = hlist_entry(hnode, struct pool_desc, pool_hash);
 106        return pool->pool_name;
 107}
 108
 109static int pool_hashkey_keycmp(const void *key, struct hlist_node *compared_hnode)
 110{
 111        char *pool_name;
 112        struct pool_desc *pool;
 113
 114        pool_name = (char *)key;
 115        pool = hlist_entry(compared_hnode, struct pool_desc, pool_hash);
 116        return !strncmp(pool_name, pool->pool_name, LOV_MAXPOOLNAME);
 117}
 118
 119static void *pool_hashobject(struct hlist_node *hnode)
 120{
 121        return hlist_entry(hnode, struct pool_desc, pool_hash);
 122}
 123
 124static void pool_hashrefcount_get(struct cfs_hash *hs, struct hlist_node *hnode)
 125{
 126        struct pool_desc *pool;
 127
 128        pool = hlist_entry(hnode, struct pool_desc, pool_hash);
 129        lov_pool_getref(pool);
 130}
 131
 132static void pool_hashrefcount_put_locked(struct cfs_hash *hs,
 133                                         struct hlist_node *hnode)
 134{
 135        struct pool_desc *pool;
 136
 137        pool = hlist_entry(hnode, struct pool_desc, pool_hash);
 138        lov_pool_putref_locked(pool);
 139}
 140
 141struct cfs_hash_ops pool_hash_operations = {
 142        .hs_hash        = pool_hashfn,
 143        .hs_key         = pool_key,
 144        .hs_keycmp      = pool_hashkey_keycmp,
 145        .hs_object      = pool_hashobject,
 146        .hs_get         = pool_hashrefcount_get,
 147        .hs_put_locked  = pool_hashrefcount_put_locked,
 148
 149};
 150
 151/*
 152 * pool debugfs seq_file methods
 153 */
 154/*
 155 * iterator is used to go through the target pool entries
 156 * index is the current entry index in the lp_array[] array
 157 * index >= pos returned to the seq_file interface
 158 * pos is from 0 to (pool->pool_obds.op_count - 1)
 159 */
 160#define POOL_IT_MAGIC 0xB001CEA0
 161struct pool_iterator {
 162        int magic;
 163        struct pool_desc *pool;
 164        int idx;        /* from 0 to pool_tgt_size - 1 */
 165};
 166
 167static void *pool_proc_next(struct seq_file *s, void *v, loff_t *pos)
 168{
 169        struct pool_iterator *iter = (struct pool_iterator *)s->private;
 170        int prev_idx;
 171
 172        LASSERTF(iter->magic == POOL_IT_MAGIC, "%08X\n", iter->magic);
 173
 174        /* test if end of file */
 175        if (*pos >= pool_tgt_count(iter->pool))
 176                return NULL;
 177
 178        /* iterate to find a non empty entry */
 179        prev_idx = iter->idx;
 180        down_read(&pool_tgt_rw_sem(iter->pool));
 181        iter->idx++;
 182        if (iter->idx == pool_tgt_count(iter->pool)) {
 183                iter->idx = prev_idx; /* we stay on the last entry */
 184                up_read(&pool_tgt_rw_sem(iter->pool));
 185                return NULL;
 186        }
 187        up_read(&pool_tgt_rw_sem(iter->pool));
 188        (*pos)++;
 189        /* return != NULL to continue */
 190        return iter;
 191}
 192
 193static void *pool_proc_start(struct seq_file *s, loff_t *pos)
 194{
 195        struct pool_desc *pool = (struct pool_desc *)s->private;
 196        struct pool_iterator *iter;
 197
 198        lov_pool_getref(pool);
 199        if ((pool_tgt_count(pool) == 0) ||
 200            (*pos >= pool_tgt_count(pool))) {
 201                /* iter is not created, so stop() has no way to
 202                 * find pool to dec ref
 203                 */
 204                lov_pool_putref(pool);
 205                return NULL;
 206        }
 207
 208        iter = kzalloc(sizeof(*iter), GFP_NOFS);
 209        if (!iter)
 210                return ERR_PTR(-ENOMEM);
 211        iter->magic = POOL_IT_MAGIC;
 212        iter->pool = pool;
 213        iter->idx = 0;
 214
 215        /* we use seq_file private field to memorized iterator so
 216         * we can free it at stop()
 217         */
 218        /* /!\ do not forget to restore it to pool before freeing it */
 219        s->private = iter;
 220        if (*pos > 0) {
 221                loff_t i;
 222                void *ptr;
 223
 224                i = 0;
 225                do {
 226                        ptr = pool_proc_next(s, &iter, &i);
 227                } while ((i < *pos) && ptr);
 228                return ptr;
 229        }
 230        return iter;
 231}
 232
 233static void pool_proc_stop(struct seq_file *s, void *v)
 234{
 235        struct pool_iterator *iter = (struct pool_iterator *)s->private;
 236
 237        /* in some cases stop() method is called 2 times, without
 238         * calling start() method (see seq_read() from fs/seq_file.c)
 239         * we have to free only if s->private is an iterator
 240         */
 241        if ((iter) && (iter->magic == POOL_IT_MAGIC)) {
 242                /* we restore s->private so next call to pool_proc_start()
 243                 * will work
 244                 */
 245                s->private = iter->pool;
 246                lov_pool_putref(iter->pool);
 247                kfree(iter);
 248        }
 249}
 250
 251static int pool_proc_show(struct seq_file *s, void *v)
 252{
 253        struct pool_iterator *iter = (struct pool_iterator *)v;
 254        struct lov_tgt_desc *tgt;
 255
 256        LASSERTF(iter->magic == POOL_IT_MAGIC, "%08X\n", iter->magic);
 257        LASSERT(iter->pool);
 258        LASSERT(iter->idx <= pool_tgt_count(iter->pool));
 259
 260        down_read(&pool_tgt_rw_sem(iter->pool));
 261        tgt = pool_tgt(iter->pool, iter->idx);
 262        up_read(&pool_tgt_rw_sem(iter->pool));
 263        if (tgt)
 264                seq_printf(s, "%s\n", obd_uuid2str(&tgt->ltd_uuid));
 265
 266        return 0;
 267}
 268
 269static const struct seq_operations pool_proc_ops = {
 270        .start    = pool_proc_start,
 271        .next      = pool_proc_next,
 272        .stop      = pool_proc_stop,
 273        .show      = pool_proc_show,
 274};
 275
 276static int pool_proc_open(struct inode *inode, struct file *file)
 277{
 278        int rc;
 279
 280        rc = seq_open(file, &pool_proc_ops);
 281        if (!rc) {
 282                struct seq_file *s = file->private_data;
 283
 284                s->private = inode->i_private;
 285        }
 286        return rc;
 287}
 288
 289static const struct file_operations pool_proc_operations = {
 290        .open      = pool_proc_open,
 291        .read      = seq_read,
 292        .llseek  = seq_lseek,
 293        .release        = seq_release,
 294};
 295
 296#define LOV_POOL_INIT_COUNT 2
 297int lov_ost_pool_init(struct ost_pool *op, unsigned int count)
 298{
 299        if (count == 0)
 300                count = LOV_POOL_INIT_COUNT;
 301        op->op_array = NULL;
 302        op->op_count = 0;
 303        init_rwsem(&op->op_rw_sem);
 304        op->op_size = count;
 305        op->op_array = kcalloc(op->op_size, sizeof(op->op_array[0]), GFP_NOFS);
 306        if (!op->op_array) {
 307                op->op_size = 0;
 308                return -ENOMEM;
 309        }
 310        return 0;
 311}
 312
 313/* Caller must hold write op_rwlock */
 314int lov_ost_pool_extend(struct ost_pool *op, unsigned int min_count)
 315{
 316        __u32 *new;
 317        int new_size;
 318
 319        LASSERT(min_count != 0);
 320
 321        if (op->op_count < op->op_size)
 322                return 0;
 323
 324        new_size = max(min_count, 2 * op->op_size);
 325        new = kcalloc(new_size, sizeof(op->op_array[0]), GFP_NOFS);
 326        if (!new)
 327                return -ENOMEM;
 328
 329        /* copy old array to new one */
 330        memcpy(new, op->op_array, op->op_size * sizeof(op->op_array[0]));
 331        kfree(op->op_array);
 332        op->op_array = new;
 333        op->op_size = new_size;
 334        return 0;
 335}
 336
 337int lov_ost_pool_add(struct ost_pool *op, __u32 idx, unsigned int min_count)
 338{
 339        int rc = 0, i;
 340
 341        down_write(&op->op_rw_sem);
 342
 343        rc = lov_ost_pool_extend(op, min_count);
 344        if (rc)
 345                goto out;
 346
 347        /* search ost in pool array */
 348        for (i = 0; i < op->op_count; i++) {
 349                if (op->op_array[i] == idx) {
 350                        rc = -EEXIST;
 351                        goto out;
 352                }
 353        }
 354        /* ost not found we add it */
 355        op->op_array[op->op_count] = idx;
 356        op->op_count++;
 357out:
 358        up_write(&op->op_rw_sem);
 359        return rc;
 360}
 361
 362int lov_ost_pool_remove(struct ost_pool *op, __u32 idx)
 363{
 364        int i;
 365
 366        down_write(&op->op_rw_sem);
 367
 368        for (i = 0; i < op->op_count; i++) {
 369                if (op->op_array[i] == idx) {
 370                        memmove(&op->op_array[i], &op->op_array[i + 1],
 371                                (op->op_count - i - 1) * sizeof(op->op_array[0]));
 372                        op->op_count--;
 373                        up_write(&op->op_rw_sem);
 374                        return 0;
 375                }
 376        }
 377
 378        up_write(&op->op_rw_sem);
 379        return -EINVAL;
 380}
 381
 382int lov_ost_pool_free(struct ost_pool *op)
 383{
 384        if (op->op_size == 0)
 385                return 0;
 386
 387        down_write(&op->op_rw_sem);
 388
 389        kfree(op->op_array);
 390        op->op_array = NULL;
 391        op->op_count = 0;
 392        op->op_size = 0;
 393
 394        up_write(&op->op_rw_sem);
 395        return 0;
 396}
 397
 398int lov_pool_new(struct obd_device *obd, char *poolname)
 399{
 400        struct lov_obd *lov;
 401        struct pool_desc *new_pool;
 402        int rc;
 403
 404        lov = &obd->u.lov;
 405
 406        if (strlen(poolname) > LOV_MAXPOOLNAME)
 407                return -ENAMETOOLONG;
 408
 409        new_pool = kzalloc(sizeof(*new_pool), GFP_NOFS);
 410        if (!new_pool)
 411                return -ENOMEM;
 412
 413        strlcpy(new_pool->pool_name, poolname, sizeof(new_pool->pool_name));
 414        new_pool->pool_lobd = obd;
 415        /* ref count init to 1 because when created a pool is always used
 416         * up to deletion
 417         */
 418        atomic_set(&new_pool->pool_refcount, 1);
 419        rc = lov_ost_pool_init(&new_pool->pool_obds, 0);
 420        if (rc)
 421                goto out_err;
 422
 423        INIT_HLIST_NODE(&new_pool->pool_hash);
 424
 425        /* get ref for debugfs file */
 426        lov_pool_getref(new_pool);
 427        new_pool->pool_debugfs_entry = ldebugfs_add_simple(
 428                                                lov->lov_pool_debugfs_entry,
 429                                                poolname, new_pool,
 430                                                &pool_proc_operations);
 431        if (IS_ERR_OR_NULL(new_pool->pool_debugfs_entry)) {
 432                CWARN("Cannot add debugfs pool entry " LOV_POOLNAMEF "\n",
 433                      poolname);
 434                new_pool->pool_debugfs_entry = NULL;
 435                lov_pool_putref(new_pool);
 436        }
 437        CDEBUG(D_INFO, "pool %p - proc %p\n",
 438               new_pool, new_pool->pool_debugfs_entry);
 439
 440        spin_lock(&obd->obd_dev_lock);
 441        list_add_tail(&new_pool->pool_list, &lov->lov_pool_list);
 442        lov->lov_pool_count++;
 443        spin_unlock(&obd->obd_dev_lock);
 444
 445        /* add to find only when it fully ready  */
 446        rc = cfs_hash_add_unique(lov->lov_pools_hash_body, poolname,
 447                                 &new_pool->pool_hash);
 448        if (rc) {
 449                rc = -EEXIST;
 450                goto out_err;
 451        }
 452
 453        CDEBUG(D_CONFIG, LOV_POOLNAMEF " is pool #%d\n",
 454               poolname, lov->lov_pool_count);
 455
 456        return 0;
 457
 458out_err:
 459        spin_lock(&obd->obd_dev_lock);
 460        list_del_init(&new_pool->pool_list);
 461        lov->lov_pool_count--;
 462        spin_unlock(&obd->obd_dev_lock);
 463        ldebugfs_remove(&new_pool->pool_debugfs_entry);
 464        lov_ost_pool_free(&new_pool->pool_obds);
 465        kfree(new_pool);
 466
 467        return rc;
 468}
 469
 470int lov_pool_del(struct obd_device *obd, char *poolname)
 471{
 472        struct lov_obd *lov;
 473        struct pool_desc *pool;
 474
 475        lov = &obd->u.lov;
 476
 477        /* lookup and kill hash reference */
 478        pool = cfs_hash_del_key(lov->lov_pools_hash_body, poolname);
 479        if (!pool)
 480                return -ENOENT;
 481
 482        if (!IS_ERR_OR_NULL(pool->pool_debugfs_entry)) {
 483                CDEBUG(D_INFO, "proc entry %p\n", pool->pool_debugfs_entry);
 484                ldebugfs_remove(&pool->pool_debugfs_entry);
 485                lov_pool_putref(pool);
 486        }
 487
 488        spin_lock(&obd->obd_dev_lock);
 489        list_del_init(&pool->pool_list);
 490        lov->lov_pool_count--;
 491        spin_unlock(&obd->obd_dev_lock);
 492
 493        /* release last reference */
 494        lov_pool_putref(pool);
 495
 496        return 0;
 497}
 498
 499int lov_pool_add(struct obd_device *obd, char *poolname, char *ostname)
 500{
 501        struct obd_uuid ost_uuid;
 502        struct lov_obd *lov;
 503        struct pool_desc *pool;
 504        unsigned int lov_idx;
 505        int rc;
 506
 507        lov = &obd->u.lov;
 508
 509        pool = cfs_hash_lookup(lov->lov_pools_hash_body, poolname);
 510        if (!pool)
 511                return -ENOENT;
 512
 513        obd_str2uuid(&ost_uuid, ostname);
 514
 515        /* search ost in lov array */
 516        obd_getref(obd);
 517        for (lov_idx = 0; lov_idx < lov->desc.ld_tgt_count; lov_idx++) {
 518                if (!lov->lov_tgts[lov_idx])
 519                        continue;
 520                if (obd_uuid_equals(&ost_uuid,
 521                                    &lov->lov_tgts[lov_idx]->ltd_uuid))
 522                        break;
 523        }
 524        /* test if ost found in lov */
 525        if (lov_idx == lov->desc.ld_tgt_count) {
 526                rc = -EINVAL;
 527                goto out;
 528        }
 529
 530        rc = lov_ost_pool_add(&pool->pool_obds, lov_idx, lov->lov_tgt_size);
 531        if (rc)
 532                goto out;
 533
 534        CDEBUG(D_CONFIG, "Added %s to " LOV_POOLNAMEF " as member %d\n",
 535               ostname, poolname,  pool_tgt_count(pool));
 536
 537out:
 538        obd_putref(obd);
 539        lov_pool_putref(pool);
 540        return rc;
 541}
 542
 543int lov_pool_remove(struct obd_device *obd, char *poolname, char *ostname)
 544{
 545        struct obd_uuid ost_uuid;
 546        struct lov_obd *lov;
 547        struct pool_desc *pool;
 548        unsigned int lov_idx;
 549        int rc = 0;
 550
 551        lov = &obd->u.lov;
 552
 553        pool = cfs_hash_lookup(lov->lov_pools_hash_body, poolname);
 554        if (!pool)
 555                return -ENOENT;
 556
 557        obd_str2uuid(&ost_uuid, ostname);
 558
 559        obd_getref(obd);
 560        /* search ost in lov array, to get index */
 561        for (lov_idx = 0; lov_idx < lov->desc.ld_tgt_count; lov_idx++) {
 562                if (!lov->lov_tgts[lov_idx])
 563                        continue;
 564
 565                if (obd_uuid_equals(&ost_uuid,
 566                                    &lov->lov_tgts[lov_idx]->ltd_uuid))
 567                        break;
 568        }
 569
 570        /* test if ost found in lov */
 571        if (lov_idx == lov->desc.ld_tgt_count) {
 572                rc = -EINVAL;
 573                goto out;
 574        }
 575
 576        lov_ost_pool_remove(&pool->pool_obds, lov_idx);
 577
 578        CDEBUG(D_CONFIG, "%s removed from " LOV_POOLNAMEF "\n", ostname,
 579               poolname);
 580
 581out:
 582        obd_putref(obd);
 583        lov_pool_putref(pool);
 584        return rc;
 585}
 586