+static int out_tx_start(const struct lu_env *env, struct dt_device *dt,
+ struct thandle_exec_args *ta, struct obd_export *exp)
+{
+ ta->ta_argno = 0;
+ ta->ta_handle = dt_trans_create(env, dt);
+ if (IS_ERR(ta->ta_handle)) {
+ int rc;
+
+ rc = PTR_ERR(ta->ta_handle);
+ ta->ta_handle = NULL;
+ CERROR("%s: start handle error: rc = %d\n", dt_obd_name(dt),
+ rc);
+ return rc;
+ }
+ if (exp->exp_need_sync)
+ ta->ta_handle->th_sync = 1;
+
+ return 0;
+}
+
+static int out_trans_start(const struct lu_env *env,
+ struct thandle_exec_args *ta)
+{
+ return dt_trans_start(env, ta->ta_handle->th_dev, ta->ta_handle);
+}
+
+static int out_trans_stop(const struct lu_env *env,
+ struct thandle_exec_args *ta, int err)
+{
+ int i;
+ int rc;
+
+ ta->ta_handle->th_result = err;
+ rc = dt_trans_stop(env, ta->ta_handle->th_dev, ta->ta_handle);
+ for (i = 0; i < ta->ta_argno; i++) {
+ if (ta->ta_args[i]->object != NULL) {
+ struct dt_object *obj = ta->ta_args[i]->object;
+
+ /* If the object is being created during this
+ * transaction, we need to remove them from the
+ * cache immediately, because a few layers are
+ * missing in OUT handler, i.e. the object might
+ * not be initialized in all layers */
+ if (ta->ta_args[i]->exec_fn == out_tx_create_exec)
+ set_bit(LU_OBJECT_HEARD_BANSHEE,
+ &obj->do_lu.lo_header->loh_flags);
+ lu_object_put(env, &ta->ta_args[i]->object->do_lu);
+ ta->ta_args[i]->object = NULL;
+ }
+ }
+ ta->ta_handle = NULL;
+ ta->ta_argno = 0;
+
+ return rc;
+}
+
+int out_tx_end(const struct lu_env *env, struct thandle_exec_args *ta,
+ int declare_ret)
+{
+ struct tgt_session_info *tsi = tgt_ses_info(env);
+ int i;
+ int rc;
+ int rc1;
+ ENTRY;
+
+ if (ta->ta_handle == NULL)
+ RETURN(0);
+
+ if (declare_ret != 0 || ta->ta_argno == 0)
+ GOTO(stop, rc = declare_ret);
+
+ LASSERT(ta->ta_handle->th_dev != NULL);
+ rc = out_trans_start(env, ta);
+ if (unlikely(rc != 0))
+ GOTO(stop, rc);
+
+ for (i = 0; i < ta->ta_argno; i++) {
+ rc = ta->ta_args[i]->exec_fn(env, ta->ta_handle,
+ ta->ta_args[i]);
+ if (unlikely(rc != 0)) {
+ CDEBUG(D_INFO, "error during execution of #%u from"
+ " %s:%d: rc = %d\n", i, ta->ta_args[i]->file,
+ ta->ta_args[i]->line, rc);
+ while (--i >= 0) {
+ if (ta->ta_args[i]->undo_fn != NULL)
+ ta->ta_args[i]->undo_fn(env,
+ ta->ta_handle,
+ ta->ta_args[i]);
+ else
+ CERROR("%s: undo for %s:%d: rc = %d\n",
+ dt_obd_name(ta->ta_handle->th_dev),
+ ta->ta_args[i]->file,
+ ta->ta_args[i]->line, -ENOTSUPP);
+ }
+ break;
+ }
+ CDEBUG(D_INFO, "%s: executed %u/%u: rc = %d\n",
+ dt_obd_name(ta->ta_handle->th_dev), i, ta->ta_argno, rc);
+ }
+
+ /* Only fail for real update */
+ tsi->tsi_reply_fail_id = OBD_FAIL_OUT_UPDATE_NET_REP;
+stop:
+ rc1 = out_trans_stop(env, ta, rc);
+ if (rc == 0)
+ rc = rc1;
+
+ ta->ta_handle = NULL;
+ ta->ta_argno = 0;
+
+ RETURN(rc);
+}
+