Logo Search packages:      
Sourcecode: linux version File versions  Download package

dm-path-selector.c

/*
 * Copyright (C) 2003 Sistina Software.
 * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
 *
 * Module Author: Heinz Mauelshagen
 *
 * This file is released under the GPL.
 *
 * Path selector registration.
 */

#include "dm.h"
#include "dm-path-selector.h"

#include <linux/slab.h>

struct ps_internal {
      struct path_selector_type pst;

      struct list_head list;
      long use;
};

#define pst_to_psi(__pst) container_of((__pst), struct ps_internal, pst)

static LIST_HEAD(_path_selectors);
static DECLARE_RWSEM(_ps_lock);

static struct ps_internal *__find_path_selector_type(const char *name)
{
      struct ps_internal *psi;

      list_for_each_entry(psi, &_path_selectors, list) {
            if (!strcmp(name, psi->pst.name))
                  return psi;
      }

      return NULL;
}

static struct ps_internal *get_path_selector(const char *name)
{
      struct ps_internal *psi;

      down_read(&_ps_lock);
      psi = __find_path_selector_type(name);
      if (psi) {
            if ((psi->use == 0) && !try_module_get(psi->pst.module))
                  psi = NULL;
            else
                  psi->use++;
      }
      up_read(&_ps_lock);

      return psi;
}

struct path_selector_type *dm_get_path_selector(const char *name)
{
      struct ps_internal *psi;

      if (!name)
            return NULL;

      psi = get_path_selector(name);
      if (!psi) {
            request_module("dm-%s", name);
            psi = get_path_selector(name);
      }

      return psi ? &psi->pst : NULL;
}

void dm_put_path_selector(struct path_selector_type *pst)
{
      struct ps_internal *psi;

      if (!pst)
            return;

      down_read(&_ps_lock);
      psi = __find_path_selector_type(pst->name);
      if (!psi)
            goto out;

      if (--psi->use == 0)
            module_put(psi->pst.module);

      BUG_ON(psi->use < 0);

out:
      up_read(&_ps_lock);
}

static struct ps_internal *_alloc_path_selector(struct path_selector_type *pst)
{
      struct ps_internal *psi = kzalloc(sizeof(*psi), GFP_KERNEL);

      if (psi)
            psi->pst = *pst;

      return psi;
}

int dm_register_path_selector(struct path_selector_type *pst)
{
      int r = 0;
      struct ps_internal *psi = _alloc_path_selector(pst);

      if (!psi)
            return -ENOMEM;

      down_write(&_ps_lock);

      if (__find_path_selector_type(pst->name)) {
            kfree(psi);
            r = -EEXIST;
      } else
            list_add(&psi->list, &_path_selectors);

      up_write(&_ps_lock);

      return r;
}

int dm_unregister_path_selector(struct path_selector_type *pst)
{
      struct ps_internal *psi;

      down_write(&_ps_lock);

      psi = __find_path_selector_type(pst->name);
      if (!psi) {
            up_write(&_ps_lock);
            return -EINVAL;
      }

      if (psi->use) {
            up_write(&_ps_lock);
            return -ETXTBSY;
      }

      list_del(&psi->list);

      up_write(&_ps_lock);

      kfree(psi);

      return 0;
}

EXPORT_SYMBOL_GPL(dm_register_path_selector);
EXPORT_SYMBOL_GPL(dm_unregister_path_selector);

Generated by  Doxygen 1.6.0   Back to index