| /* |
| * 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) 2003, 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. |
| * |
| * lustre/lov/lov_log.c |
| * |
| * Author: Phil Schwan <phil@clusterfs.com> |
| * Author: Peter Braam <braam@clusterfs.com> |
| * Author: Mike Shaver <shaver@clusterfs.com> |
| */ |
| |
| #define DEBUG_SUBSYSTEM S_LOV |
| #include <linux/libcfs/libcfs.h> |
| |
| #include <obd_support.h> |
| #include <lustre_lib.h> |
| #include <lustre_net.h> |
| #include <lustre/lustre_idl.h> |
| #include <lustre_dlm.h> |
| #include <lustre_mds.h> |
| #include <obd_class.h> |
| #include <obd_lov.h> |
| #include <obd_ost.h> |
| #include <lprocfs_status.h> |
| #include <lustre_log.h> |
| |
| #include "lov_internal.h" |
| |
| /* Add log records for each OSC that this object is striped over, and return |
| * cookies for each one. We _would_ have nice abstraction here, except that |
| * we need to keep cookies in stripe order, even if some are NULL, so that |
| * the right cookies are passed back to the right OSTs at the client side. |
| * Unset cookies should be all-zero (which will never occur naturally). */ |
| static int lov_llog_origin_add(const struct lu_env *env, |
| struct llog_ctxt *ctxt, |
| struct llog_rec_hdr *rec, |
| struct lov_stripe_md *lsm, |
| struct llog_cookie *logcookies, int numcookies) |
| { |
| struct obd_device *obd = ctxt->loc_obd; |
| struct lov_obd *lov = &obd->u.lov; |
| int i, rc = 0, cookies = 0; |
| |
| LASSERTF(logcookies && numcookies >= lsm->lsm_stripe_count, |
| "logcookies %p, numcookies %d lsm->lsm_stripe_count %d \n", |
| logcookies, numcookies, lsm->lsm_stripe_count); |
| |
| for (i = 0; i < lsm->lsm_stripe_count; i++) { |
| struct lov_oinfo *loi = lsm->lsm_oinfo[i]; |
| struct obd_device *child = |
| lov->lov_tgts[loi->loi_ost_idx]->ltd_exp->exp_obd; |
| struct llog_ctxt *cctxt = llog_get_context(child, ctxt->loc_idx); |
| |
| /* fill mds unlink/setattr log record */ |
| switch (rec->lrh_type) { |
| case MDS_UNLINK_REC: { |
| struct llog_unlink_rec *lur = (struct llog_unlink_rec *)rec; |
| lur->lur_oid = ostid_id(&loi->loi_oi); |
| lur->lur_oseq = (__u32)ostid_seq(&loi->loi_oi); |
| break; |
| } |
| case MDS_SETATTR64_REC: { |
| struct llog_setattr64_rec *lsr = (struct llog_setattr64_rec *)rec; |
| lsr->lsr_oi = loi->loi_oi; |
| break; |
| } |
| default: |
| break; |
| } |
| |
| /* inject error in llog_obd_add() below */ |
| if (OBD_FAIL_CHECK(OBD_FAIL_MDS_FAIL_LOV_LOG_ADD)) { |
| llog_ctxt_put(cctxt); |
| cctxt = NULL; |
| } |
| rc = llog_obd_add(env, cctxt, rec, NULL, logcookies + cookies, |
| numcookies - cookies); |
| llog_ctxt_put(cctxt); |
| if (rc < 0) { |
| CERROR("Can't add llog (rc = %d) for stripe %d\n", |
| rc, cookies); |
| memset(logcookies + cookies, 0, |
| sizeof(struct llog_cookie)); |
| rc = 1; /* skip this cookie */ |
| } |
| /* Note that rc is always 1 if llog_obd_add was successful */ |
| cookies += rc; |
| } |
| return cookies; |
| } |
| |
| static int lov_llog_origin_connect(struct llog_ctxt *ctxt, |
| struct llog_logid *logid, |
| struct llog_gen *gen, |
| struct obd_uuid *uuid) |
| { |
| struct obd_device *obd = ctxt->loc_obd; |
| struct lov_obd *lov = &obd->u.lov; |
| int i, rc = 0, err = 0; |
| |
| obd_getref(obd); |
| for (i = 0; i < lov->desc.ld_tgt_count; i++) { |
| struct obd_device *child; |
| struct llog_ctxt *cctxt; |
| |
| if (!lov->lov_tgts[i] || !lov->lov_tgts[i]->ltd_active) |
| continue; |
| if (uuid && !obd_uuid_equals(uuid, &lov->lov_tgts[i]->ltd_uuid)) |
| continue; |
| CDEBUG(D_CONFIG, "connect %d/%d\n", i, lov->desc.ld_tgt_count); |
| child = lov->lov_tgts[i]->ltd_exp->exp_obd; |
| cctxt = llog_get_context(child, ctxt->loc_idx); |
| rc = llog_connect(cctxt, logid, gen, uuid); |
| llog_ctxt_put(cctxt); |
| |
| if (rc) { |
| CERROR("error osc_llog_connect tgt %d (%d)\n", i, rc); |
| if (!err) |
| err = rc; |
| } |
| } |
| obd_putref(obd); |
| |
| return err; |
| } |
| |
| /* the replicators commit callback */ |
| static int lov_llog_repl_cancel(const struct lu_env *env, |
| struct llog_ctxt *ctxt, |
| struct lov_stripe_md *lsm, |
| int count, struct llog_cookie *cookies, |
| int flags) |
| { |
| struct lov_obd *lov; |
| struct obd_device *obd = ctxt->loc_obd; |
| int rc = 0, i; |
| |
| LASSERT(lsm != NULL); |
| LASSERT(count == lsm->lsm_stripe_count); |
| |
| lov = &obd->u.lov; |
| obd_getref(obd); |
| for (i = 0; i < count; i++, cookies++) { |
| struct lov_oinfo *loi = lsm->lsm_oinfo[i]; |
| struct obd_device *child = |
| lov->lov_tgts[loi->loi_ost_idx]->ltd_exp->exp_obd; |
| struct llog_ctxt *cctxt = |
| llog_get_context(child, ctxt->loc_idx); |
| int err; |
| |
| err = llog_cancel(env, cctxt, NULL, 1, cookies, flags); |
| llog_ctxt_put(cctxt); |
| if (err && lov->lov_tgts[loi->loi_ost_idx]->ltd_active) { |
| CERROR("%s: objid "DOSTID" subobj "DOSTID |
| " on OST idx %d: rc = %d\n", |
| obd->obd_name, POSTID(&lsm->lsm_oi), |
| POSTID(&loi->loi_oi), loi->loi_ost_idx, err); |
| if (!rc) |
| rc = err; |
| } |
| } |
| obd_putref(obd); |
| return rc; |
| } |
| |
| static struct llog_operations lov_mds_ost_orig_logops = { |
| .lop_obd_add = lov_llog_origin_add, |
| .lop_connect = lov_llog_origin_connect, |
| }; |
| |
| static struct llog_operations lov_size_repl_logops = { |
| .lop_cancel = lov_llog_repl_cancel, |
| }; |
| |
| int lov_llog_init(struct obd_device *obd, struct obd_llog_group *olg, |
| struct obd_device *disk_obd, int *index) |
| { |
| struct lov_obd *lov = &obd->u.lov; |
| struct obd_device *child; |
| int i, rc = 0; |
| |
| LASSERT(olg == &obd->obd_olg); |
| rc = llog_setup(NULL, obd, olg, LLOG_MDS_OST_ORIG_CTXT, disk_obd, |
| &lov_mds_ost_orig_logops); |
| if (rc) |
| return rc; |
| |
| rc = llog_setup(NULL, obd, olg, LLOG_SIZE_REPL_CTXT, disk_obd, |
| &lov_size_repl_logops); |
| if (rc) |
| GOTO(err_cleanup, rc); |
| |
| obd_getref(obd); |
| /* count may not match lov->desc.ld_tgt_count during dynamic ost add */ |
| for (i = 0; i < lov->desc.ld_tgt_count; i++) { |
| if (!lov->lov_tgts[i]) |
| continue; |
| |
| if (index && i != *index) |
| continue; |
| |
| child = lov->lov_tgts[i]->ltd_obd; |
| rc = obd_llog_init(child, &child->obd_olg, disk_obd, &i); |
| if (rc) |
| CERROR("error osc_llog_init idx %d osc '%s' tgt '%s' " |
| "(rc=%d)\n", i, child->obd_name, |
| disk_obd->obd_name, rc); |
| rc = 0; |
| } |
| obd_putref(obd); |
| GOTO(err_cleanup, rc); |
| err_cleanup: |
| if (rc) { |
| struct llog_ctxt *ctxt = |
| llog_get_context(obd, LLOG_SIZE_REPL_CTXT); |
| if (ctxt) |
| llog_cleanup(NULL, ctxt); |
| ctxt = llog_get_context(obd, LLOG_MDS_OST_ORIG_CTXT); |
| if (ctxt) |
| llog_cleanup(NULL, ctxt); |
| } |
| return rc; |
| } |
| |
| int lov_llog_finish(struct obd_device *obd, int count) |
| { |
| struct llog_ctxt *ctxt; |
| |
| /* cleanup our llogs only if the ctxts have been setup |
| * (client lov doesn't setup, mds lov does). */ |
| ctxt = llog_get_context(obd, LLOG_MDS_OST_ORIG_CTXT); |
| if (ctxt) |
| llog_cleanup(NULL, ctxt); |
| |
| ctxt = llog_get_context(obd, LLOG_SIZE_REPL_CTXT); |
| if (ctxt) |
| llog_cleanup(NULL, ctxt); |
| |
| /* lov->tgt llogs are cleaned during osc_cleanup. */ |
| return 0; |
| } |