Whamcloud - gitweb
09d9d896881f5aa9234d6c1be291fb4ebab6abff
[fs/lustre-release.git] / lustre / target / update_trans.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
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.
9  *
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).
15  *
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
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2014, Intel Corporation.
24  */
25 /*
26  * lustre/target/update_trans.c
27  *
28  * This file implements the update distribute transaction API.
29  *
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.
33  *
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.
39  *
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
45  *    OSD.
46  *
47  * Author: Di Wang <di.wang@intel.com>
48  */
49
50 #define DEBUG_SUBSYSTEM S_CLASS
51
52 #include <lu_target.h>
53 #include <lustre_update.h>
54 #include <obd.h>
55 #include <obd_class.h>
56 #include <tgt_internal.h>
57
58 /**
59  * Create the top transaction.
60  *
61  * Create the top transaction on the master device. It will create a top
62  * thandle and a sub thandle on the master device.
63  *
64  * \param[in] env               execution environment
65  * \param[in] master_dev        master_dev the top thandle will be created
66  *
67  * \retval                      pointer to the created thandle.
68  * \retval                      ERR_PTR(errno) if creation failed.
69  */
70 struct thandle *
71 top_trans_create(const struct lu_env *env, struct dt_device *master_dev)
72 {
73         struct top_thandle      *top_th;
74         struct thandle          *child_th;
75
76         OBD_ALLOC_GFP(top_th, sizeof(*top_th), __GFP_IO);
77         if (top_th == NULL)
78                 return ERR_PTR(-ENOMEM);
79
80         child_th = dt_trans_create(env, master_dev);
81         if (IS_ERR(child_th)) {
82                 OBD_FREE_PTR(top_th);
83                 return child_th;
84         }
85
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;
89
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);
93
94         return &top_th->tt_super;
95 }
96 EXPORT_SYMBOL(top_trans_create);
97
98 /**
99  * start the top transaction.
100  *
101  * Start all of its sub transactions, then start master sub transaction.
102  *
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
106  *
107  * \retval                      0 if transaction start succeeds.
108  * \retval                      negative errno if start fails.
109  */
110 int top_trans_start(const struct lu_env *env, struct dt_device *master_dev,
111                     struct thandle *th)
112 {
113         struct top_thandle      *top_th = container_of(th, struct top_thandle,
114                                                        tt_super);
115         struct sub_thandle      *lst;
116         int                     rc;
117
118         rc = check_and_prepare_update_record(env, th);
119         if (rc < 0)
120                 return rc;
121
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,
127                                     lst->st_sub_th);
128                 if (rc != 0)
129                         return rc;
130         }
131
132         top_th->tt_master_sub_thandle->th_local = th->th_local;
133         top_th->tt_master_sub_thandle->th_sync = th->th_sync;
134
135         return dt_trans_start(env, master_dev, top_th->tt_master_sub_thandle);
136 }
137 EXPORT_SYMBOL(top_trans_start);
138
139 /**
140  * Stop the top transaction.
141  *
142  * Stop the transaction on the master device first, then stop transactions
143  * on other sub devices.
144  *
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
148  *
149  * \retval                      0 if stop transaction succeeds.
150  * \retval                      negative errno if stop transaction fails.
151  */
152 int top_trans_stop(const struct lu_env *env, struct dt_device *master_dev,
153                    struct thandle *th)
154 {
155         struct sub_thandle      *lst;
156         struct top_thandle      *top_th = container_of(th, struct top_thandle,
157                                                        tt_super);
158         struct thandle_update_records *tur = top_th->tt_update_records;
159         int                     rc;
160         ENTRY;
161
162         /* Note: we always need walk through all of sub_transaction to do
163          * transaction stop to release the resource here */
164         if (tur != NULL) {
165                 rc = merge_params_updates_buf(env, tur);
166                 if (rc == 0) {
167                         struct update_records *record;
168
169                         record = &tur->tur_update_records->lur_update_rec;
170                         update_records_dump(record, D_INFO, false);
171                 }
172                 top_th->tt_update_records = NULL;
173         }
174
175         LASSERT(top_th->tt_magic == TOP_THANDLE_MAGIC);
176
177         top_th->tt_master_sub_thandle->th_local = th->th_local;
178         top_th->tt_master_sub_thandle->th_sync = th->th_sync;
179
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);
183
184         list_for_each_entry(lst, &top_th->tt_sub_thandle_list, st_sub_list) {
185                 int     rc2;
186
187                 if (rc != 0)
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,
192                                     lst->st_sub_th);
193                 if (unlikely(rc2 < 0 && rc == 0))
194                         rc = rc2;
195         }
196
197         top_thandle_destroy(top_th);
198
199         RETURN(rc);
200 }
201 EXPORT_SYMBOL(top_trans_stop);
202
203 /**
204  * Get sub thandle.
205  *
206  * Get sub thandle from the top thandle according to the sub dt_device.
207  *
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
211  *
212  * \retval              thandle of sub transaction if succeed
213  * \retval              PTR_ERR(errno) if failed
214  */
215 struct thandle *thandle_get_sub_by_dt(const struct lu_env *env,
216                                       struct thandle *th,
217                                       struct dt_device *sub_dt)
218 {
219         struct sub_thandle      *lst;
220         struct top_thandle      *top_th;
221         struct thandle          *sub_th;
222         ENTRY;
223
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);
229
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);
235         }
236
237         sub_th = dt_trans_create(env, sub_dt);
238         if (IS_ERR(sub_th))
239                 RETURN(sub_th);
240
241         /* XXX all of mixed transaction (see struct th_handle) will
242          * be synchronized until async update is done */
243         th->th_sync = 1;
244
245         sub_th->th_top = th;
246         OBD_ALLOC_PTR(lst);
247         if (lst == NULL) {
248                 dt_trans_stop(env, sub_dt, sub_th);
249                 RETURN(ERR_PTR(-ENOMEM));
250         }
251
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;
256
257         RETURN(sub_th);
258 }
259 EXPORT_SYMBOL(thandle_get_sub_by_dt);
260
261 /**
262  * Top thandle destroy
263  *
264  * Destroy the top thandle and all of its sub thandle.
265  *
266  * \param[in] top_th    top thandle to be destroyed.
267  */
268 void top_thandle_destroy(struct top_thandle *top_th)
269 {
270         struct sub_thandle *st;
271         struct sub_thandle *tmp;
272
273         LASSERT(top_th->tt_magic == TOP_THANDLE_MAGIC);
274         list_for_each_entry_safe(st, tmp, &top_th->tt_sub_thandle_list,
275                                  st_sub_list) {
276                 list_del(&st->st_sub_list);
277                 OBD_FREE_PTR(st);
278         }
279         OBD_FREE_PTR(top_th);
280 }
281 EXPORT_SYMBOL(top_thandle_destroy);