From 9e9efd99580c8e7d2064d7d1f76041843f8a2036 Mon Sep 17 00:00:00 2001 From: Mikhail Pershin Date: Wed, 23 May 2012 11:58:03 +0400 Subject: [PATCH] LU-1406 ofd: transaction and last_rcvd functions Add ofd transaction handlers and last_rcvd update function Signed-off-by: Mikhail Pershin Change-Id: I14467658ea36d5b71eec7ce183190509a049eb09 Reviewed-on: http://review.whamcloud.com/2886 Tested-by: Hudson Tested-by: Maloo Reviewed-by: Andreas Dilger Reviewed-by: Alex Zhuravlev Reviewed-by: Oleg Drokin --- lustre/ofd/Makefile.in | 2 +- lustre/ofd/ofd_dev.c | 10 ++ lustre/ofd/ofd_fs.c | 14 +++ lustre/ofd/ofd_internal.h | 41 +++++++++ lustre/ofd/ofd_trans.c | 228 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 294 insertions(+), 1 deletion(-) create mode 100644 lustre/ofd/ofd_trans.c diff --git a/lustre/ofd/Makefile.in b/lustre/ofd/Makefile.in index 96e41a48..7d72020 100644 --- a/lustre/ofd/Makefile.in +++ b/lustre/ofd/Makefile.in @@ -1,6 +1,6 @@ MODULES := ofd -ofd-objs := ofd_dev.o ofd_obd.o ofd_fs.o +ofd-objs := ofd_dev.o ofd_obd.o ofd_fs.o ofd_trans.o ofd-objs += lproc_ofd.o ofd_capa.o ofd_fmd.o ofd_grant.o EXTRA_DIST = $(ofd-objs:%.o=%.c) ofd_internal.h diff --git a/lustre/ofd/ofd_dev.c b/lustre/ofd/ofd_dev.c index c0e3f8f..4c816df 100644 --- a/lustre/ofd/ofd_dev.c +++ b/lustre/ofd/ofd_dev.c @@ -643,6 +643,16 @@ static void ofd_key_exit(const struct lu_context *ctx, info->fti_env = NULL; info->fti_exp = NULL; + + info->fti_xid = 0; + info->fti_transno = 0; + info->fti_pre_version = 0; + info->fti_obj = NULL; + info->fti_has_trans = 0; + info->fti_mult_trans = 0; + info->fti_used = 0; + + memset(&info->fti_attr, 0, sizeof info->fti_attr); } struct lu_context_key ofd_thread_key = { diff --git a/lustre/ofd/ofd_fs.c b/lustre/ofd/ofd_fs.c index 7d14975..1828758 100644 --- a/lustre/ofd/ofd_fs.c +++ b/lustre/ofd/ofd_fs.c @@ -467,6 +467,16 @@ int ofd_fs_setup(const struct lu_env *env, struct ofd_device *ofd, if (OBD_FAIL_CHECK(OBD_FAIL_MDS_FS_SETUP)) RETURN (-ENOENT); + /* prepare transactions callbacks */ + ofd->ofd_txn_cb.dtc_txn_start = NULL; + ofd->ofd_txn_cb.dtc_txn_stop = ofd_txn_stop_cb; + ofd->ofd_txn_cb.dtc_txn_commit = NULL; + ofd->ofd_txn_cb.dtc_cookie = ofd; + ofd->ofd_txn_cb.dtc_tag = LCT_DT_THREAD; + CFS_INIT_LIST_HEAD(&ofd->ofd_txn_cb.dtc_linkage); + + dt_txn_callback_add(ofd->ofd_osd, &ofd->ofd_txn_cb); + rc = ofd_server_data_init(env, ofd); if (rc) GOTO(out, rc); @@ -507,6 +517,7 @@ out_lg: out_hc: lu_object_put(env, &ofd->ofd_health_check_file->do_lu); out: + dt_txn_callback_del(ofd->ofd_osd, &ofd->ofd_txn_cb); return rc; } @@ -529,6 +540,9 @@ void ofd_fs_cleanup(const struct lu_env *env, struct ofd_device *ofd) if (i) CERROR("can't sync: %d\n", i); + /* Remove transaction callback */ + dt_txn_callback_del(ofd->ofd_osd, &ofd->ofd_txn_cb); + if (ofd->ofd_last_group_file) { lu_object_put(env, &ofd->ofd_last_group_file->do_lu); ofd->ofd_last_group_file = NULL; diff --git a/lustre/ofd/ofd_internal.h b/lustre/ofd/ofd_internal.h index 77559aa..55aeb4f 100644 --- a/lustre/ofd/ofd_internal.h +++ b/lustre/ofd/ofd_internal.h @@ -74,6 +74,9 @@ struct ofd_device { /* DLM name-space for meta-data locks maintained by this server */ struct ldlm_namespace *ofd_namespace; + /* transaction callbacks */ + struct dt_txn_callback ofd_txn_cb; + /* last_rcvd file */ struct lu_target ofd_lut; struct dt_object *ofd_last_group_file; @@ -167,6 +170,26 @@ static inline struct ofd_object *ofd_obj(struct lu_object *o) return container_of0(o, struct ofd_object, ofo_obj.do_lu); } +static inline int ofd_object_exists(struct ofd_object *obj) +{ + LASSERT(obj != NULL); + if (lu_object_is_dying(obj->ofo_obj.do_lu.lo_header)) + return 0; + return lu_object_exists(&obj->ofo_obj.do_lu); +} + +static inline struct dt_object *fo2dt(struct ofd_object *obj) +{ + return &obj->ofo_obj; +} + +static inline struct dt_object *ofd_object_child(struct ofd_object *_obj) +{ + struct lu_object *lu = &(_obj)->ofo_obj.do_lu; + + return container_of0(lu_object_next(lu), struct dt_object, do_lu); +} + /* * Common data shared by obdofd-level handlers. This is allocated per-thread * to reduce stack consumption. @@ -175,8 +198,15 @@ struct ofd_thread_info { const struct lu_env *fti_env; struct obd_export *fti_exp; + __u64 fti_xid; + __u64 fti_transno; + __u64 fti_pre_version; + __u32 fti_has_trans:1, /* has txn already */ + fti_mult_trans:1; + struct lu_fid fti_fid; struct lu_attr fti_attr; + struct ofd_object *fti_obj; union { char name[64]; /* for ofd_init0() */ struct obd_statfs osfs; /* for obdofd_statfs() */ @@ -215,6 +245,17 @@ int ofd_fs_setup(const struct lu_env *env, struct ofd_device *ofd, struct obd_device *obd); void ofd_fs_cleanup(const struct lu_env *env, struct ofd_device *ofd); +/* ofd_trans.c */ +struct thandle *ofd_trans_create(const struct lu_env *env, + struct ofd_device *ofd); +int ofd_trans_start(const struct lu_env *env, + struct ofd_device *ofd, struct ofd_object *fo, + struct thandle *th); +void ofd_trans_stop(const struct lu_env *env, struct ofd_device *ofd, + struct thandle *th, int rc); +int ofd_txn_stop_cb(const struct lu_env *env, struct thandle *txn, + void *cookie); + /* lproc_ofd.c */ void lprocfs_ofd_init_vars(struct lprocfs_static_vars *lvars); int lproc_ofd_attach_seqstat(struct obd_device *dev); diff --git a/lustre/ofd/ofd_trans.c b/lustre/ofd/ofd_trans.c new file mode 100644 index 0000000..4d09bce --- /dev/null +++ b/lustre/ofd/ofd_trans.c @@ -0,0 +1,228 @@ +/* + * 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) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * Use is subject to license terms. + * + * Copyright (c) 2011, 2012, Whamcloud, Inc. + */ +/* + * This file is part of Lustre, http://www.lustre.org/ + * Lustre is a trademark of Sun Microsystems, Inc. + * + * lustre/ofd/ofd_recovery.c + * + * Author: Alex Zhuravlev + * Author: Mikhail Pershin + */ + +#define DEBUG_SUBSYSTEM S_FILTER + +#include "ofd_internal.h" + +struct thandle *ofd_trans_create(const struct lu_env *env, + struct ofd_device *ofd) +{ + struct ofd_thread_info *info = ofd_info(env); + struct thandle *th; + + LASSERT(info); + + th = dt_trans_create(env, ofd->ofd_osd); + if (IS_ERR(th)) + return th; + + /* export can require sync operations */ + if (info->fti_exp != NULL) + th->th_sync |= info->fti_exp->exp_need_sync; + return th; +} + +int ofd_trans_start(const struct lu_env *env, struct ofd_device *ofd, + struct ofd_object *obj, struct thandle *th) +{ + struct ofd_thread_info *info = ofd_info(env); + int rc; + + if (info->fti_exp == NULL) + return 0; + + /* declare last_rcvd update */ + rc = dt_declare_record_write(env, ofd->ofd_lut.lut_last_rcvd, + sizeof(struct lsd_client_data), + info->fti_exp->exp_target_data.ted_lr_off, + th); + if (rc) + RETURN(rc); + + /* declare last_rcvd header update */ + rc = dt_declare_record_write(env, ofd->ofd_lut.lut_last_rcvd, + sizeof(ofd->ofd_lut.lut_lsd), 0, th); + if (rc) + RETURN(rc); + + /* version change is required for this object */ + if (obj) { + ofd_info(env)->fti_obj = obj; + rc = dt_declare_version_set(env, ofd_object_child(obj), th); + if (rc) + RETURN(rc); + } + + return dt_trans_start(env, ofd->ofd_osd, th); +} + +void ofd_trans_stop(const struct lu_env *env, struct ofd_device *ofd, + struct thandle *th, int rc) +{ + th->th_result = rc; + dt_trans_stop(env, ofd->ofd_osd, th); +} + +/* + * last_rcvd & last_committed update callbacks + */ +static int ofd_last_rcvd_update(struct ofd_thread_info *info, + struct thandle *th) +{ + struct ofd_device *ofd = ofd_exp(info->fti_exp); + struct filter_export_data *fed; + struct lsd_client_data *lcd; + __s32 rc = th->th_result; + __u64 *transno_p; + loff_t off; + int err; + + ENTRY; + + LASSERT(ofd); + LASSERT(info->fti_exp); + + fed = &info->fti_exp->exp_filter_data; + LASSERT(fed); + lcd = fed->fed_ted.ted_lcd; + /* if the export has already been disconnected, we have no last_rcvd + * slot, update server data with latest transno then */ + if (lcd == NULL) { + CWARN("commit transaction for disconnected client %s: rc %d\n", + info->fti_exp->exp_client_uuid.uuid, rc); + err = lut_server_data_write(info->fti_env, &ofd->ofd_lut, th); + RETURN(err); + } + /* ofd connect may cause transaction before export has last_rcvd + * slot */ + if (fed->fed_ted.ted_lr_off < 0) + RETURN(0); + off = fed->fed_ted.ted_lr_off; + + transno_p = &lcd->lcd_last_transno; + lcd->lcd_last_xid = info->fti_xid; + + /* + * When we store zero transno in mcd we can lost last transno value + * because mcd contains 0, but msd is not yet written + * The server data should be updated also if the latest + * transno is rewritten by zero. See the bug 11125 for details. + */ + if (info->fti_transno == 0 && + *transno_p == ofd->ofd_lut.lut_last_transno) { + cfs_spin_lock(&ofd->ofd_lut.lut_translock); + ofd->ofd_lut.lut_lsd.lsd_last_transno = + ofd->ofd_lut.lut_last_transno; + cfs_spin_unlock(&ofd->ofd_lut.lut_translock); + lut_server_data_write(info->fti_env, &ofd->ofd_lut, th); + } + + *transno_p = info->fti_transno; + LASSERT(fed->fed_ted.ted_lr_off > 0); + err = lut_client_data_write(info->fti_env, &ofd->ofd_lut, lcd, + &off, th); + + RETURN(err); +} + +/* Update last_rcvd records with the latest transaction data */ +int ofd_txn_stop_cb(const struct lu_env *env, struct thandle *txn, + void *cookie) +{ + struct ofd_device *ofd = cookie; + struct ofd_thread_info *info; + + ENTRY; + + info = lu_context_key_get(&env->le_ctx, &ofd_thread_key); + + if (info->fti_exp == NULL) + RETURN(0); + + LASSERT(ofd_exp(info->fti_exp) == ofd); + if (info->fti_has_trans) { + if (info->fti_mult_trans == 0) { + CERROR("More than one transaction "LPU64"\n", + info->fti_transno); + RETURN(0); + } + /* we need another transno to be assigned */ + info->fti_transno = 0; + } else if (txn->th_result == 0) { + info->fti_has_trans = 1; + } + + cfs_spin_lock(&ofd->ofd_lut.lut_translock); + if (txn->th_result != 0) { + if (info->fti_transno != 0) { + CERROR("Replay transno "LPU64" failed: rc %d\n", + info->fti_transno, txn->th_result); + info->fti_transno = 0; + } + } else if (info->fti_transno == 0) { + info->fti_transno = ++ofd->ofd_lut.lut_last_transno; + } else { + /* should be replay */ + if (info->fti_transno > ofd->ofd_lut.lut_last_transno) + ofd->ofd_lut.lut_last_transno = info->fti_transno; + } + cfs_spin_unlock(&ofd->ofd_lut.lut_translock); + + /** VBR: set new versions */ + if (txn->th_result == 0 && info->fti_obj != NULL) { + dt_version_set(env, ofd_object_child(info->fti_obj), + info->fti_transno, txn); + info->fti_obj = NULL; + } + + /* filling reply data */ + CDEBUG(D_INODE, "transno = %llu, last_committed = %llu\n", + info->fti_transno, ofd_obd(ofd)->obd_last_committed); + + /* if can't add callback, do sync write */ + txn->th_sync = !!lut_last_commit_cb_add(txn, &ofd->ofd_lut, + info->fti_exp, + info->fti_transno); + + return ofd_last_rcvd_update(info, txn); +} + -- 1.8.3.1