Whamcloud - gitweb
LU-1406 ofd: transaction and last_rcvd functions
authorMikhail Pershin <tappro@whamcloud.com>
Wed, 23 May 2012 07:58:03 +0000 (11:58 +0400)
committerOleg Drokin <green@whamcloud.com>
Mon, 11 Jun 2012 12:48:15 +0000 (08:48 -0400)
Add ofd transaction handlers and last_rcvd update function

Signed-off-by: Mikhail Pershin <tappro@whamcloud.com>
Change-Id: I14467658ea36d5b71eec7ce183190509a049eb09
Reviewed-on: http://review.whamcloud.com/2886
Tested-by: Hudson
Tested-by: Maloo <whamcloud.maloo@gmail.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Alex Zhuravlev <bzzz@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
lustre/ofd/Makefile.in
lustre/ofd/ofd_dev.c
lustre/ofd/ofd_fs.c
lustre/ofd/ofd_internal.h
lustre/ofd/ofd_trans.c [new file with mode: 0644]

index 96e41a4..7d72020 100644 (file)
@@ -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
index c0e3f8f..4c816df 100644 (file)
@@ -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 = {
index 7d14975..1828758 100644 (file)
@@ -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;
index 77559aa..55aeb4f 100644 (file)
@@ -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 (file)
index 0000000..4d09bce
--- /dev/null
@@ -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 <bzzz@whamcloud.com>
+ * Author: Mikhail Pershin <tappro@whamcloud.com>
+ */
+
+#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);
+}
+