4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.gnu.org/licenses/gpl-2.0.html
23 * Copyright (c) 2014, Intel Corporation.
26 * lustre/target/update_trans.c
28 * This file implements the update distribute transaction API.
30 * To manage the cross-MDT operation (distribute operation) transaction,
31 * the transaction will also be separated two layers on MD stack, top
32 * transaction and sub transaction.
34 * During the distribute operation, top transaction is created in the LOD
35 * layer, and represent the operation. Sub transaction is created by
36 * each OSD or OSP. Top transaction start/stop will trigger all of its sub
37 * transaction start/stop. Top transaction (the whole operation) is committed
38 * only all of its sub transaction are committed.
40 * there are three kinds of transactions
41 * 1. local transaction: All updates are in a single local OSD.
42 * 2. Remote transaction: All Updates are only in the remote OSD,
43 * i.e. locally all updates are in OSP.
44 * 3. Mixed transaction: Updates are both in local OSD and remote
47 * Author: Di Wang <di.wang@intel.com>
50 #define DEBUG_SUBSYSTEM S_CLASS
52 #include <lu_target.h>
53 #include <lustre_update.h>
55 #include <obd_class.h>
58 * Create the top transaction.
60 * Create the top transaction on the master device. It will create a top
61 * thandle and a sub thandle on the master device.
63 * \param[in] env execution environment
64 * \param[in] master_dev master_dev the top thandle will be created
66 * \retval pointer to the created thandle.
67 * \retval ERR_PTR(errno) if creation failed.
70 top_trans_create(const struct lu_env *env, struct dt_device *master_dev)
72 struct top_thandle *top_th;
73 struct thandle *child_th;
75 OBD_ALLOC_GFP(top_th, sizeof(*top_th), __GFP_IO);
77 return ERR_PTR(-ENOMEM);
79 child_th = dt_trans_create(env, master_dev);
80 if (IS_ERR(child_th)) {
85 top_th->tt_magic = TOP_THANDLE_MAGIC;
86 top_th->tt_master_sub_thandle = child_th;
87 child_th->th_top = &top_th->tt_super;
88 INIT_LIST_HEAD(&top_th->tt_sub_thandle_list);
89 top_th->tt_super.th_top = &top_th->tt_super;
91 return &top_th->tt_super;
93 EXPORT_SYMBOL(top_trans_create);
96 * start the top transaction.
98 * Start all of its sub transactions, then start master sub transaction.
100 * \param[in] env execution environment
101 * \param[in] master_dev master_dev the top thandle will be start
102 * \param[in] th top thandle
104 * \retval 0 if transaction start succeeds.
105 * \retval negative errno if start fails.
107 int top_trans_start(const struct lu_env *env, struct dt_device *master_dev,
110 struct top_thandle *top_th = container_of(th, struct top_thandle,
112 struct sub_thandle *lst;
115 LASSERT(top_th->tt_magic == TOP_THANDLE_MAGIC);
116 list_for_each_entry(lst, &top_th->tt_sub_thandle_list, st_sub_list) {
117 lst->st_sub_th->th_sync = th->th_sync;
118 lst->st_sub_th->th_local = th->th_local;
119 rc = dt_trans_start(env, lst->st_sub_th->th_dev,
125 top_th->tt_master_sub_thandle->th_local = th->th_local;
126 top_th->tt_master_sub_thandle->th_sync = th->th_sync;
128 return dt_trans_start(env, master_dev, top_th->tt_master_sub_thandle);
130 EXPORT_SYMBOL(top_trans_start);
133 * Stop the top transaction.
135 * Stop the transaction on the master device first, then stop transactions
136 * on other sub devices.
138 * \param[in] env execution environment
139 * \param[in] master_dev master_dev the top thandle will be created
140 * \param[in] th top thandle
142 * \retval 0 if stop transaction succeeds.
143 * \retval negative errno if stop transaction fails.
145 int top_trans_stop(const struct lu_env *env, struct dt_device *master_dev,
148 struct sub_thandle *lst;
149 struct top_thandle *top_th = container_of(th, struct top_thandle,
154 /* Note: we always need walk through all of sub_transaction to do
155 * transaction stop to release the resource here */
156 LASSERT(top_th->tt_magic == TOP_THANDLE_MAGIC);
158 top_th->tt_master_sub_thandle->th_local = th->th_local;
159 top_th->tt_master_sub_thandle->th_sync = th->th_sync;
161 /* To avoid sending RPC while holding thandle, it always stop local
162 * transaction first, then other sub thandle */
163 rc = dt_trans_stop(env, master_dev, top_th->tt_master_sub_thandle);
165 list_for_each_entry(lst, &top_th->tt_sub_thandle_list, st_sub_list) {
169 lst->st_sub_th->th_result = rc;
170 lst->st_sub_th->th_sync = th->th_sync;
171 lst->st_sub_th->th_local = th->th_local;
172 rc2 = dt_trans_stop(env, lst->st_sub_th->th_dev,
174 if (unlikely(rc2 < 0 && rc == 0))
178 top_thandle_destroy(top_th);
182 EXPORT_SYMBOL(top_trans_stop);
187 * Get sub thandle from the top thandle according to the sub dt_device.
189 * \param[in] env execution environment
190 * \param[in] th thandle on the top layer.
191 * \param[in] sub_dt sub dt_device used to get sub transaction
193 * \retval thandle of sub transaction if succeed
194 * \retval PTR_ERR(errno) if failed
196 struct thandle *thandle_get_sub_by_dt(const struct lu_env *env,
198 struct dt_device *sub_dt)
200 struct sub_thandle *lst;
201 struct top_thandle *top_th = container_of(th, struct top_thandle,
203 struct thandle *sub_th;
206 LASSERT(top_th->tt_magic == TOP_THANDLE_MAGIC);
207 LASSERT(top_th->tt_master_sub_thandle != NULL);
208 if (likely(sub_dt == top_th->tt_master_sub_thandle->th_dev))
209 RETURN(top_th->tt_master_sub_thandle);
211 /* Find or create the transaction in tt_trans_list, since there is
212 * always only one thread access the list, so no need lock here */
213 list_for_each_entry(lst, &top_th->tt_sub_thandle_list, st_sub_list) {
214 if (lst->st_sub_th->th_dev == sub_dt)
215 RETURN(lst->st_sub_th);
218 sub_th = dt_trans_create(env, sub_dt);
222 /* XXX all of mixed transaction (see struct th_handle) will
223 * be synchronized until async update is done */
229 dt_trans_stop(env, sub_dt, sub_th);
230 RETURN(ERR_PTR(-ENOMEM));
233 INIT_LIST_HEAD(&lst->st_sub_list);
234 lst->st_sub_th = sub_th;
235 list_add(&lst->st_sub_list, &top_th->tt_sub_thandle_list);
239 EXPORT_SYMBOL(thandle_get_sub_by_dt);
242 * Top thandle destroy
244 * Destroy the top thandle and all of its sub thandle.
246 * \param[in] top_th top thandle to be destroyed.
248 void top_thandle_destroy(struct top_thandle *top_th)
250 struct sub_thandle *st;
251 struct sub_thandle *tmp;
253 LASSERT(top_th->tt_magic == TOP_THANDLE_MAGIC);
254 list_for_each_entry_safe(st, tmp, &top_th->tt_sub_thandle_list,
256 list_del(&st->st_sub_list);
259 OBD_FREE_PTR(top_th);
261 EXPORT_SYMBOL(top_thandle_destroy);