Whamcloud - gitweb
LU-6285 libcfs: get rid of deprecated cpumask function usage
[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
57 /**
58  * Create the top transaction.
59  *
60  * Create the top transaction on the master device. It will create a top
61  * thandle and a sub thandle on the master device.
62  *
63  * \param[in] env               execution environment
64  * \param[in] master_dev        master_dev the top thandle will be created
65  *
66  * \retval                      pointer to the created thandle.
67  * \retval                      ERR_PTR(errno) if creation failed.
68  */
69 struct thandle *
70 top_trans_create(const struct lu_env *env, struct dt_device *master_dev)
71 {
72         struct top_thandle      *top_th;
73         struct thandle          *child_th;
74
75         OBD_ALLOC_GFP(top_th, sizeof(*top_th), __GFP_IO);
76         if (top_th == NULL)
77                 return ERR_PTR(-ENOMEM);
78
79         child_th = dt_trans_create(env, master_dev);
80         if (IS_ERR(child_th)) {
81                 OBD_FREE_PTR(top_th);
82                 return child_th;
83         }
84
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;
90
91         return &top_th->tt_super;
92 }
93 EXPORT_SYMBOL(top_trans_create);
94
95 /**
96  * start the top transaction.
97  *
98  * Start all of its sub transactions, then start master sub transaction.
99  *
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
103  *
104  * \retval                      0 if transaction start succeeds.
105  * \retval                      negative errno if start fails.
106  */
107 int top_trans_start(const struct lu_env *env, struct dt_device *master_dev,
108                     struct thandle *th)
109 {
110         struct top_thandle      *top_th = container_of(th, struct top_thandle,
111                                                        tt_super);
112         struct sub_thandle      *lst;
113         int                     rc = 0;
114
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,
120                                     lst->st_sub_th);
121                 if (rc != 0)
122                         return rc;
123         }
124
125         top_th->tt_master_sub_thandle->th_local = th->th_local;
126         top_th->tt_master_sub_thandle->th_sync = th->th_sync;
127
128         return dt_trans_start(env, master_dev, top_th->tt_master_sub_thandle);
129 }
130 EXPORT_SYMBOL(top_trans_start);
131
132 /**
133  * Stop the top transaction.
134  *
135  * Stop the transaction on the master device first, then stop transactions
136  * on other sub devices.
137  *
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
141  *
142  * \retval                      0 if stop transaction succeeds.
143  * \retval                      negative errno if stop transaction fails.
144  */
145 int top_trans_stop(const struct lu_env *env, struct dt_device *master_dev,
146                    struct thandle *th)
147 {
148         struct sub_thandle      *lst;
149         struct top_thandle      *top_th = container_of(th, struct top_thandle,
150                                                        tt_super);
151         int                     rc;
152         ENTRY;
153
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);
157
158         top_th->tt_master_sub_thandle->th_local = th->th_local;
159         top_th->tt_master_sub_thandle->th_sync = th->th_sync;
160
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);
164
165         list_for_each_entry(lst, &top_th->tt_sub_thandle_list, st_sub_list) {
166                 int     rc2;
167
168                 if (rc != 0)
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,
173                                     lst->st_sub_th);
174                 if (unlikely(rc2 < 0 && rc == 0))
175                         rc = rc2;
176         }
177
178         top_thandle_destroy(top_th);
179
180         RETURN(rc);
181 }
182 EXPORT_SYMBOL(top_trans_stop);
183
184 /**
185  * Get sub thandle.
186  *
187  * Get sub thandle from the top thandle according to the sub dt_device.
188  *
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
192  *
193  * \retval              thandle of sub transaction if succeed
194  * \retval              PTR_ERR(errno) if failed
195  */
196 struct thandle *thandle_get_sub_by_dt(const struct lu_env *env,
197                                       struct thandle *th,
198                                       struct dt_device *sub_dt)
199 {
200         struct sub_thandle      *lst;
201         struct top_thandle      *top_th = container_of(th, struct top_thandle,
202                                                        tt_super);
203         struct thandle          *sub_th;
204         ENTRY;
205
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);
210
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);
216         }
217
218         sub_th = dt_trans_create(env, sub_dt);
219         if (IS_ERR(sub_th))
220                 RETURN(sub_th);
221
222         /* XXX all of mixed transaction (see struct th_handle) will
223          * be synchronized until async update is done */
224         th->th_sync = 1;
225
226         sub_th->th_top = th;
227         OBD_ALLOC_PTR(lst);
228         if (lst == NULL) {
229                 dt_trans_stop(env, sub_dt, sub_th);
230                 RETURN(ERR_PTR(-ENOMEM));
231         }
232
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);
236
237         RETURN(sub_th);
238 }
239 EXPORT_SYMBOL(thandle_get_sub_by_dt);
240
241 /**
242  * Top thandle destroy
243  *
244  * Destroy the top thandle and all of its sub thandle.
245  *
246  * \param[in] top_th    top thandle to be destroyed.
247  */
248 void top_thandle_destroy(struct top_thandle *top_th)
249 {
250         struct sub_thandle *st;
251         struct sub_thandle *tmp;
252
253         LASSERT(top_th->tt_magic == TOP_THANDLE_MAGIC);
254         list_for_each_entry_safe(st, tmp, &top_th->tt_sub_thandle_list,
255                                  st_sub_list) {
256                 list_del(&st->st_sub_list);
257                 OBD_FREE_PTR(st);
258         }
259         OBD_FREE_PTR(top_th);
260 }
261 EXPORT_SYMBOL(top_thandle_destroy);