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>
56 #include <tgt_internal.h>
59 * Create the top transaction.
61 * Create the top transaction on the master device. It will create a top
62 * thandle and a sub thandle on the master device.
64 * \param[in] env execution environment
65 * \param[in] master_dev master_dev the top thandle will be created
67 * \retval pointer to the created thandle.
68 * \retval ERR_PTR(errno) if creation failed.
71 top_trans_create(const struct lu_env *env, struct dt_device *master_dev)
73 struct top_thandle *top_th;
74 struct thandle *child_th;
76 OBD_ALLOC_GFP(top_th, sizeof(*top_th), __GFP_IO);
78 return ERR_PTR(-ENOMEM);
80 child_th = dt_trans_create(env, master_dev);
81 if (IS_ERR(child_th)) {
86 top_th->tt_magic = TOP_THANDLE_MAGIC;
87 top_th->tt_master_sub_thandle = child_th;
88 child_th->th_top = &top_th->tt_super;
90 top_th->tt_update_records = NULL;
91 top_th->tt_super.th_top = &top_th->tt_super;
92 INIT_LIST_HEAD(&top_th->tt_sub_thandle_list);
94 return &top_th->tt_super;
96 EXPORT_SYMBOL(top_trans_create);
99 * start the top transaction.
101 * Start all of its sub transactions, then start master sub transaction.
103 * \param[in] env execution environment
104 * \param[in] master_dev master_dev the top thandle will be start
105 * \param[in] th top thandle
107 * \retval 0 if transaction start succeeds.
108 * \retval negative errno if start fails.
110 int top_trans_start(const struct lu_env *env, struct dt_device *master_dev,
113 struct top_thandle *top_th = container_of(th, struct top_thandle,
115 struct sub_thandle *lst;
118 rc = check_and_prepare_update_record(env, th);
122 LASSERT(top_th->tt_magic == TOP_THANDLE_MAGIC);
123 list_for_each_entry(lst, &top_th->tt_sub_thandle_list, st_sub_list) {
124 lst->st_sub_th->th_sync = th->th_sync;
125 lst->st_sub_th->th_local = th->th_local;
126 rc = dt_trans_start(env, lst->st_sub_th->th_dev,
132 top_th->tt_master_sub_thandle->th_local = th->th_local;
133 top_th->tt_master_sub_thandle->th_sync = th->th_sync;
135 return dt_trans_start(env, master_dev, top_th->tt_master_sub_thandle);
137 EXPORT_SYMBOL(top_trans_start);
140 * Stop the top transaction.
142 * Stop the transaction on the master device first, then stop transactions
143 * on other sub devices.
145 * \param[in] env execution environment
146 * \param[in] master_dev master_dev the top thandle will be created
147 * \param[in] th top thandle
149 * \retval 0 if stop transaction succeeds.
150 * \retval negative errno if stop transaction fails.
152 int top_trans_stop(const struct lu_env *env, struct dt_device *master_dev,
155 struct sub_thandle *lst;
156 struct top_thandle *top_th = container_of(th, struct top_thandle,
158 struct thandle_update_records *tur = top_th->tt_update_records;
162 /* Note: we always need walk through all of sub_transaction to do
163 * transaction stop to release the resource here */
165 rc = merge_params_updates_buf(env, tur);
167 struct update_records *record;
169 record = &tur->tur_update_records->lur_update_rec;
170 update_records_dump(record, D_INFO, false);
172 top_th->tt_update_records = NULL;
175 LASSERT(top_th->tt_magic == TOP_THANDLE_MAGIC);
177 top_th->tt_master_sub_thandle->th_local = th->th_local;
178 top_th->tt_master_sub_thandle->th_sync = th->th_sync;
180 /* To avoid sending RPC while holding thandle, it always stop local
181 * transaction first, then other sub thandle */
182 rc = dt_trans_stop(env, master_dev, top_th->tt_master_sub_thandle);
184 list_for_each_entry(lst, &top_th->tt_sub_thandle_list, st_sub_list) {
188 lst->st_sub_th->th_result = rc;
189 lst->st_sub_th->th_sync = th->th_sync;
190 lst->st_sub_th->th_local = th->th_local;
191 rc2 = dt_trans_stop(env, lst->st_sub_th->th_dev,
193 if (unlikely(rc2 < 0 && rc == 0))
197 top_thandle_destroy(top_th);
201 EXPORT_SYMBOL(top_trans_stop);
206 * Get sub thandle from the top thandle according to the sub dt_device.
208 * \param[in] env execution environment
209 * \param[in] th thandle on the top layer.
210 * \param[in] sub_dt sub dt_device used to get sub transaction
212 * \retval thandle of sub transaction if succeed
213 * \retval PTR_ERR(errno) if failed
215 struct thandle *thandle_get_sub_by_dt(const struct lu_env *env,
217 struct dt_device *sub_dt)
219 struct sub_thandle *lst;
220 struct top_thandle *top_th;
221 struct thandle *sub_th;
224 top_th = container_of(th, struct top_thandle, tt_super);
225 LASSERT(top_th->tt_magic == TOP_THANDLE_MAGIC);
226 LASSERT(top_th->tt_master_sub_thandle != NULL);
227 if (likely(sub_dt == top_th->tt_master_sub_thandle->th_dev))
228 RETURN(top_th->tt_master_sub_thandle);
230 /* Find or create the transaction in tt_trans_list, since there is
231 * always only one thread access the list, so no need lock here */
232 list_for_each_entry(lst, &top_th->tt_sub_thandle_list, st_sub_list) {
233 if (lst->st_sub_th->th_dev == sub_dt)
234 RETURN(lst->st_sub_th);
237 sub_th = dt_trans_create(env, sub_dt);
241 /* XXX all of mixed transaction (see struct th_handle) will
242 * be synchronized until async update is done */
248 dt_trans_stop(env, sub_dt, sub_th);
249 RETURN(ERR_PTR(-ENOMEM));
252 INIT_LIST_HEAD(&lst->st_sub_list);
253 lst->st_sub_th = sub_th;
254 list_add(&lst->st_sub_list, &top_th->tt_sub_thandle_list);
255 lst->st_record_update = 1;
259 EXPORT_SYMBOL(thandle_get_sub_by_dt);
262 * Top thandle destroy
264 * Destroy the top thandle and all of its sub thandle.
266 * \param[in] top_th top thandle to be destroyed.
268 void top_thandle_destroy(struct top_thandle *top_th)
270 struct sub_thandle *st;
271 struct sub_thandle *tmp;
273 LASSERT(top_th->tt_magic == TOP_THANDLE_MAGIC);
274 list_for_each_entry_safe(st, tmp, &top_th->tt_sub_thandle_list,
276 list_del(&st->st_sub_list);
279 OBD_FREE_PTR(top_th);
281 EXPORT_SYMBOL(top_thandle_destroy);