X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=kernel%2Fdrivers%2Fstaging%2Flustre%2Flustre%2Flov%2Flov_dev.c;fp=kernel%2Fdrivers%2Fstaging%2Flustre%2Flustre%2Flov%2Flov_dev.c;h=711b837ddba23aa8fa6028a828f06f8753ce979b;hb=9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00;hp=0000000000000000000000000000000000000000;hpb=98260f3884f4a202f9ca5eabed40b1354c489b29;p=kvmfornfv.git diff --git a/kernel/drivers/staging/lustre/lustre/lov/lov_dev.c b/kernel/drivers/staging/lustre/lustre/lov/lov_dev.c new file mode 100644 index 000000000..711b837dd --- /dev/null +++ b/kernel/drivers/staging/lustre/lustre/lov/lov_dev.c @@ -0,0 +1,528 @@ +/* + * GPL HEADER START + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 only, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 for more details (a copy is included + * in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; If not, see + * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * GPL HEADER END + */ +/* + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + * Use is subject to license terms. + * + * Copyright (c) 2012, Intel Corporation. + */ +/* + * This file is part of Lustre, http://www.lustre.org/ + * Lustre is a trademark of Sun Microsystems, Inc. + * + * Implementation of cl_device and cl_device_type for LOV layer. + * + * Author: Nikita Danilov + */ + +#define DEBUG_SUBSYSTEM S_LOV + +/* class_name2obd() */ +#include "../include/obd_class.h" + +#include "lov_cl_internal.h" +#include "lov_internal.h" + + +struct kmem_cache *lov_lock_kmem; +struct kmem_cache *lov_object_kmem; +struct kmem_cache *lov_thread_kmem; +struct kmem_cache *lov_session_kmem; +struct kmem_cache *lov_req_kmem; + +struct kmem_cache *lovsub_lock_kmem; +struct kmem_cache *lovsub_object_kmem; +struct kmem_cache *lovsub_req_kmem; + +struct kmem_cache *lov_lock_link_kmem; + +/** Lock class of lov_device::ld_mutex. */ +static struct lock_class_key cl_lov_device_mutex_class; + +struct lu_kmem_descr lov_caches[] = { + { + .ckd_cache = &lov_lock_kmem, + .ckd_name = "lov_lock_kmem", + .ckd_size = sizeof(struct lov_lock) + }, + { + .ckd_cache = &lov_object_kmem, + .ckd_name = "lov_object_kmem", + .ckd_size = sizeof(struct lov_object) + }, + { + .ckd_cache = &lov_thread_kmem, + .ckd_name = "lov_thread_kmem", + .ckd_size = sizeof(struct lov_thread_info) + }, + { + .ckd_cache = &lov_session_kmem, + .ckd_name = "lov_session_kmem", + .ckd_size = sizeof(struct lov_session) + }, + { + .ckd_cache = &lov_req_kmem, + .ckd_name = "lov_req_kmem", + .ckd_size = sizeof(struct lov_req) + }, + { + .ckd_cache = &lovsub_lock_kmem, + .ckd_name = "lovsub_lock_kmem", + .ckd_size = sizeof(struct lovsub_lock) + }, + { + .ckd_cache = &lovsub_object_kmem, + .ckd_name = "lovsub_object_kmem", + .ckd_size = sizeof(struct lovsub_object) + }, + { + .ckd_cache = &lovsub_req_kmem, + .ckd_name = "lovsub_req_kmem", + .ckd_size = sizeof(struct lovsub_req) + }, + { + .ckd_cache = &lov_lock_link_kmem, + .ckd_name = "lov_lock_link_kmem", + .ckd_size = sizeof(struct lov_lock_link) + }, + { + .ckd_cache = NULL + } +}; + +/***************************************************************************** + * + * Lov transfer operations. + * + */ + +static void lov_req_completion(const struct lu_env *env, + const struct cl_req_slice *slice, int ioret) +{ + struct lov_req *lr; + + lr = cl2lov_req(slice); + OBD_SLAB_FREE_PTR(lr, lov_req_kmem); +} + +static const struct cl_req_operations lov_req_ops = { + .cro_completion = lov_req_completion +}; + +/***************************************************************************** + * + * Lov device and device type functions. + * + */ + +static void *lov_key_init(const struct lu_context *ctx, + struct lu_context_key *key) +{ + struct lov_thread_info *info; + + OBD_SLAB_ALLOC_PTR_GFP(info, lov_thread_kmem, GFP_NOFS); + if (info != NULL) + INIT_LIST_HEAD(&info->lti_closure.clc_list); + else + info = ERR_PTR(-ENOMEM); + return info; +} + +static void lov_key_fini(const struct lu_context *ctx, + struct lu_context_key *key, void *data) +{ + struct lov_thread_info *info = data; + LINVRNT(list_empty(&info->lti_closure.clc_list)); + OBD_SLAB_FREE_PTR(info, lov_thread_kmem); +} + +struct lu_context_key lov_key = { + .lct_tags = LCT_CL_THREAD, + .lct_init = lov_key_init, + .lct_fini = lov_key_fini +}; + +static void *lov_session_key_init(const struct lu_context *ctx, + struct lu_context_key *key) +{ + struct lov_session *info; + + OBD_SLAB_ALLOC_PTR_GFP(info, lov_session_kmem, GFP_NOFS); + if (info == NULL) + info = ERR_PTR(-ENOMEM); + return info; +} + +static void lov_session_key_fini(const struct lu_context *ctx, + struct lu_context_key *key, void *data) +{ + struct lov_session *info = data; + OBD_SLAB_FREE_PTR(info, lov_session_kmem); +} + +struct lu_context_key lov_session_key = { + .lct_tags = LCT_SESSION, + .lct_init = lov_session_key_init, + .lct_fini = lov_session_key_fini +}; + +/* type constructor/destructor: lov_type_{init,fini,start,stop}() */ +LU_TYPE_INIT_FINI(lov, &lov_key, &lov_session_key); + +static struct lu_device *lov_device_fini(const struct lu_env *env, + struct lu_device *d) +{ + int i; + struct lov_device *ld = lu2lov_dev(d); + + LASSERT(ld->ld_lov != NULL); + if (ld->ld_target == NULL) + return NULL; + + lov_foreach_target(ld, i) { + struct lovsub_device *lsd; + + lsd = ld->ld_target[i]; + if (lsd != NULL) { + cl_stack_fini(env, lovsub2cl_dev(lsd)); + ld->ld_target[i] = NULL; + } + } + return NULL; +} + +static int lov_device_init(const struct lu_env *env, struct lu_device *d, + const char *name, struct lu_device *next) +{ + struct lov_device *ld = lu2lov_dev(d); + int i; + int rc = 0; + + LASSERT(d->ld_site != NULL); + if (ld->ld_target == NULL) + return rc; + + lov_foreach_target(ld, i) { + struct lovsub_device *lsd; + struct cl_device *cl; + struct lov_tgt_desc *desc; + + desc = ld->ld_lov->lov_tgts[i]; + if (desc == NULL) + continue; + + cl = cl_type_setup(env, d->ld_site, &lovsub_device_type, + desc->ltd_obd->obd_lu_dev); + if (IS_ERR(cl)) { + rc = PTR_ERR(cl); + break; + } + lsd = cl2lovsub_dev(cl); + lsd->acid_idx = i; + lsd->acid_super = ld; + ld->ld_target[i] = lsd; + } + + if (rc) + lov_device_fini(env, d); + else + ld->ld_flags |= LOV_DEV_INITIALIZED; + + return rc; +} + +static int lov_req_init(const struct lu_env *env, struct cl_device *dev, + struct cl_req *req) +{ + struct lov_req *lr; + int result; + + OBD_SLAB_ALLOC_PTR_GFP(lr, lov_req_kmem, GFP_NOFS); + if (lr != NULL) { + cl_req_slice_add(req, &lr->lr_cl, dev, &lov_req_ops); + result = 0; + } else + result = -ENOMEM; + return result; +} + +static const struct cl_device_operations lov_cl_ops = { + .cdo_req_init = lov_req_init +}; + +static void lov_emerg_free(struct lov_device_emerg **emrg, int nr) +{ + int i; + + for (i = 0; i < nr; ++i) { + struct lov_device_emerg *em; + + em = emrg[i]; + if (em != NULL) { + LASSERT(em->emrg_page_list.pl_nr == 0); + if (em->emrg_env != NULL) + cl_env_put(em->emrg_env, &em->emrg_refcheck); + OBD_FREE_PTR(em); + } + } + OBD_FREE(emrg, nr * sizeof(emrg[0])); +} + +static struct lu_device *lov_device_free(const struct lu_env *env, + struct lu_device *d) +{ + struct lov_device *ld = lu2lov_dev(d); + const int nr = ld->ld_target_nr; + + cl_device_fini(lu2cl_dev(d)); + if (ld->ld_target != NULL) + OBD_FREE(ld->ld_target, nr * sizeof(ld->ld_target[0])); + if (ld->ld_emrg != NULL) + lov_emerg_free(ld->ld_emrg, nr); + OBD_FREE_PTR(ld); + return NULL; +} + +static void lov_cl_del_target(const struct lu_env *env, struct lu_device *dev, + __u32 index) +{ + struct lov_device *ld = lu2lov_dev(dev); + + if (ld->ld_target[index] != NULL) { + cl_stack_fini(env, lovsub2cl_dev(ld->ld_target[index])); + ld->ld_target[index] = NULL; + } +} + +static struct lov_device_emerg **lov_emerg_alloc(int nr) +{ + struct lov_device_emerg **emerg; + int i; + int result; + + OBD_ALLOC(emerg, nr * sizeof(emerg[0])); + if (emerg == NULL) + return ERR_PTR(-ENOMEM); + for (result = i = 0; i < nr && result == 0; i++) { + struct lov_device_emerg *em; + + OBD_ALLOC_PTR(em); + if (em != NULL) { + emerg[i] = em; + cl_page_list_init(&em->emrg_page_list); + em->emrg_env = cl_env_alloc(&em->emrg_refcheck, + LCT_REMEMBER|LCT_NOREF); + if (!IS_ERR(em->emrg_env)) + em->emrg_env->le_ctx.lc_cookie = 0x2; + else { + result = PTR_ERR(em->emrg_env); + em->emrg_env = NULL; + } + } else + result = -ENOMEM; + } + if (result != 0) { + lov_emerg_free(emerg, nr); + emerg = ERR_PTR(result); + } + return emerg; +} + +static int lov_expand_targets(const struct lu_env *env, struct lov_device *dev) +{ + int result; + __u32 tgt_size; + __u32 sub_size; + + result = 0; + tgt_size = dev->ld_lov->lov_tgt_size; + sub_size = dev->ld_target_nr; + if (sub_size < tgt_size) { + struct lovsub_device **newd; + struct lov_device_emerg **emerg; + const size_t sz = sizeof(newd[0]); + + emerg = lov_emerg_alloc(tgt_size); + if (IS_ERR(emerg)) + return PTR_ERR(emerg); + + OBD_ALLOC(newd, tgt_size * sz); + if (newd != NULL) { + mutex_lock(&dev->ld_mutex); + if (sub_size > 0) { + memcpy(newd, dev->ld_target, sub_size * sz); + OBD_FREE(dev->ld_target, sub_size * sz); + } + dev->ld_target = newd; + dev->ld_target_nr = tgt_size; + + if (dev->ld_emrg != NULL) + lov_emerg_free(dev->ld_emrg, sub_size); + dev->ld_emrg = emerg; + mutex_unlock(&dev->ld_mutex); + } else { + lov_emerg_free(emerg, tgt_size); + result = -ENOMEM; + } + } + return result; +} + +static int lov_cl_add_target(const struct lu_env *env, struct lu_device *dev, + __u32 index) +{ + struct obd_device *obd = dev->ld_obd; + struct lov_device *ld = lu2lov_dev(dev); + struct lov_tgt_desc *tgt; + struct lovsub_device *lsd; + struct cl_device *cl; + int rc; + + obd_getref(obd); + + tgt = obd->u.lov.lov_tgts[index]; + LASSERT(tgt != NULL); + LASSERT(tgt->ltd_obd != NULL); + + if (!tgt->ltd_obd->obd_set_up) { + CERROR("Target %s not set up\n", obd_uuid2str(&tgt->ltd_uuid)); + return -EINVAL; + } + + rc = lov_expand_targets(env, ld); + if (rc == 0 && ld->ld_flags & LOV_DEV_INITIALIZED) { + LASSERT(dev->ld_site != NULL); + + cl = cl_type_setup(env, dev->ld_site, &lovsub_device_type, + tgt->ltd_obd->obd_lu_dev); + if (!IS_ERR(cl)) { + lsd = cl2lovsub_dev(cl); + lsd->acid_idx = index; + lsd->acid_super = ld; + ld->ld_target[index] = lsd; + } else { + CERROR("add failed (%d), deleting %s\n", rc, + obd_uuid2str(&tgt->ltd_uuid)); + lov_cl_del_target(env, dev, index); + rc = PTR_ERR(cl); + } + } + obd_putref(obd); + return rc; +} + +static int lov_process_config(const struct lu_env *env, + struct lu_device *d, struct lustre_cfg *cfg) +{ + struct obd_device *obd = d->ld_obd; + int cmd; + int rc; + int gen; + __u32 index; + + obd_getref(obd); + + cmd = cfg->lcfg_command; + rc = lov_process_config_base(d->ld_obd, cfg, &index, &gen); + if (rc == 0) { + switch (cmd) { + case LCFG_LOV_ADD_OBD: + case LCFG_LOV_ADD_INA: + rc = lov_cl_add_target(env, d, index); + if (rc != 0) + lov_del_target(d->ld_obd, index, NULL, 0); + break; + case LCFG_LOV_DEL_OBD: + lov_cl_del_target(env, d, index); + break; + } + } + obd_putref(obd); + return rc; +} + +static const struct lu_device_operations lov_lu_ops = { + .ldo_object_alloc = lov_object_alloc, + .ldo_process_config = lov_process_config, +}; + +static struct lu_device *lov_device_alloc(const struct lu_env *env, + struct lu_device_type *t, + struct lustre_cfg *cfg) +{ + struct lu_device *d; + struct lov_device *ld; + struct obd_device *obd; + int rc; + + OBD_ALLOC_PTR(ld); + if (ld == NULL) + return ERR_PTR(-ENOMEM); + + cl_device_init(&ld->ld_cl, t); + d = lov2lu_dev(ld); + d->ld_ops = &lov_lu_ops; + ld->ld_cl.cd_ops = &lov_cl_ops; + + mutex_init(&ld->ld_mutex); + lockdep_set_class(&ld->ld_mutex, &cl_lov_device_mutex_class); + + /* setup the LOV OBD */ + obd = class_name2obd(lustre_cfg_string(cfg, 0)); + LASSERT(obd != NULL); + rc = lov_setup(obd, cfg); + if (rc) { + lov_device_free(env, d); + return ERR_PTR(rc); + } + + ld->ld_lov = &obd->u.lov; + return d; +} + +static const struct lu_device_type_operations lov_device_type_ops = { + .ldto_init = lov_type_init, + .ldto_fini = lov_type_fini, + + .ldto_start = lov_type_start, + .ldto_stop = lov_type_stop, + + .ldto_device_alloc = lov_device_alloc, + .ldto_device_free = lov_device_free, + + .ldto_device_init = lov_device_init, + .ldto_device_fini = lov_device_fini +}; + +struct lu_device_type lov_device_type = { + .ldt_tags = LU_DEVICE_CL, + .ldt_name = LUSTRE_LOV_NAME, + .ldt_ops = &lov_device_type_ops, + .ldt_ctx_tags = LCT_CL_THREAD +}; +EXPORT_SYMBOL(lov_device_type); + +/** @} lov */