Whamcloud - gitweb
LU-8900 snapshot: operate write barrier on MDT
[fs/lustre-release.git] / lustre / target / barrier.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,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License version 2 for more details.  A copy is
14  * included in the COPYING file that accompanied this code.
15
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2016, Intel Corporation.
24  *
25  * lustre/target/barrier.c
26  *
27  * Currently, the Lustre barrier is implemented as write barrier on all MDTs.
28  * For each MDT in the system, when it starts, it registers a barrier instance
29  * that will be used in handling subsequent barrier requests.
30  *
31  * Author: Fan, Yong <fan.yong@intel.com>
32  */
33
34 #define DEBUG_SUBSYSTEM S_SNAPSHOT
35
36 #include <linux/percpu_counter.h>
37
38 #include <lustre/lustre_idl.h>
39 #include <dt_object.h>
40 #include <obd.h>
41 #include <obd_class.h>
42 #include <lustre_barrier.h>
43 #include <lustre/lustre_barrier_user.h>
44
45 static LIST_HEAD(barrier_instance_list);
46 static DEFINE_SPINLOCK(barrier_instance_lock);
47
48 struct barrier_instance {
49         struct list_head         bi_link;
50         struct dt_device        *bi_bottom;
51         struct dt_device        *bi_next;
52         wait_queue_head_t        bi_waitq;
53         rwlock_t                 bi_rwlock;
54         struct percpu_counter    bi_writers;
55         atomic_t                 bi_ref;
56         time_t                   bi_deadline;
57         __u32                    bi_status;
58 };
59
60 static inline char *barrier_barrier2name(struct barrier_instance *barrier)
61 {
62         return barrier->bi_bottom->dd_lu_dev.ld_obd->obd_name;
63 }
64
65 static inline __u32 barrier_dev_idx(struct barrier_instance *barrier)
66 {
67         return lu_site2seq(barrier->bi_bottom->dd_lu_dev.ld_site)->ss_node_id;
68 }
69
70 static void barrier_instance_cleanup(struct barrier_instance *barrier)
71 {
72         LASSERT(list_empty(&barrier->bi_link));
73
74         percpu_counter_destroy(&barrier->bi_writers);
75         OBD_FREE_PTR(barrier);
76 }
77
78 static inline void barrier_instance_put(struct barrier_instance *barrier)
79 {
80         if (atomic_dec_and_test(&barrier->bi_ref))
81                 barrier_instance_cleanup(barrier);
82 }
83
84 static struct barrier_instance *
85 barrier_instance_find_locked(struct dt_device *key)
86 {
87         struct barrier_instance *barrier;
88
89         list_for_each_entry(barrier, &barrier_instance_list, bi_link) {
90                 if (barrier->bi_bottom == key)
91                         return barrier;
92         }
93
94         return NULL;
95 }
96
97 static void barrier_instance_add(struct barrier_instance *barrier)
98 {
99         struct barrier_instance *tmp;
100
101         spin_lock(&barrier_instance_lock);
102         tmp = barrier_instance_find_locked(barrier->bi_bottom);
103         LASSERT(!tmp);
104
105         list_add_tail(&barrier->bi_link, &barrier_instance_list);
106         spin_unlock(&barrier_instance_lock);
107 }
108
109 static struct barrier_instance *barrier_instance_find(struct dt_device *key)
110 {
111         struct barrier_instance *barrier;
112
113         spin_lock(&barrier_instance_lock);
114         barrier = barrier_instance_find_locked(key);
115         if (barrier)
116                 atomic_inc(&barrier->bi_ref);
117         spin_unlock(&barrier_instance_lock);
118
119         return barrier;
120 }
121
122 static void barrier_set(struct barrier_instance *barrier, __u32 status)
123 {
124         if (barrier->bi_status != status) {
125                 CDEBUG(D_SNAPSHOT, "%s: change barrier status from %u to %u\n",
126                        barrier_barrier2name(barrier),
127                        barrier->bi_status, status);
128
129                 barrier->bi_status = status;
130         }
131 }
132
133 /**
134  * Create the barrier for the given instance.
135  *
136  * We use two-phases barrier to guarantee that after the barrier setup:
137  * 1) All the MDT side pending async modification have been flushed.
138  * 2) Any subsequent modification will be blocked.
139  * 3) All async transactions on the MDTs have been committed.
140  *
141  * For phase1, we do the following:
142  *
143  * Firstly, it sets barrier flag on the instance that will block subsequent
144  * modifications from clients. (Note: server sponsored modification will be
145  * allowed for flush pending modifications)
146  *
147  * Secondly, it will flush all pending modification via dt_sync(), such as
148  * async OST-object destroy, async OST-object owner changes, and so on.
149  *
150  * If there are some on-handling clients sponsored modifications during the
151  * barrier freezing, then related modifications may cause pending requests
152  * after the first dt_sync(), so call dt_sync() again after all on-handling
153  * modifications done.
154  *
155  * With the phase1 barrier set, all pending cross-servers modification have
156  * been flushed to remote servers, and any new modification will be blocked.
157  * But it does not guarantees that all the updates have been committed to
158  * storage on remote servers. So when all the instances have done phase1
159  * barrier successfully, the MGS will notify all instances to do the phase2
160  * barrier as following:
161  *
162  * Every barrier instance will call dt_sync() to make all async transactions
163  * to be committed locally.
164  *
165  * \param[in] env       pointer to the thread context
166  * \param[in] barrier   pointer to the barrier instance
167  * \param[in] phase1    indicate whether it is phase1 barrier or not
168  *
169  * \retval              positive number for timeout
170  * \retval              0 for success
171  * \retval              negative error number on failure
172  */
173 static int barrier_freeze(const struct lu_env *env,
174                           struct barrier_instance *barrier, bool phase1)
175 {
176         int left;
177         int rc = 0;
178         __s64 inflight = 0;
179         ENTRY;
180
181         write_lock(&barrier->bi_rwlock);
182         barrier_set(barrier, phase1 ? BS_FREEZING_P1 : BS_FREEZING_P2);
183
184         /* Avoid out-of-order execution the barrier_set()
185          * and the check of inflight modifications count. */
186         smp_mb();
187
188         if (phase1)
189                 inflight = percpu_counter_sum(&barrier->bi_writers);
190         write_unlock(&barrier->bi_rwlock);
191
192         rc = dt_sync(env, barrier->bi_next);
193         if (rc)
194                 RETURN(rc);
195
196         LASSERT(barrier->bi_deadline != 0);
197
198         left = barrier->bi_deadline - cfs_time_current_sec();
199         if (left <= 0)
200                 RETURN(1);
201
202         if (phase1 && inflight != 0) {
203                 struct l_wait_info lwi = LWI_TIMEOUT(cfs_time_seconds(left),
204                                                      NULL, NULL);
205
206                 rc = l_wait_event(barrier->bi_waitq,
207                                   percpu_counter_sum(&barrier->bi_writers) == 0,
208                                   &lwi);
209                 if (rc)
210                         RETURN(1);
211
212                 /* sync again after all inflight modifications done. */
213                 rc = dt_sync(env, barrier->bi_next);
214                 if (rc)
215                         RETURN(rc);
216
217                 if (cfs_time_beforeq(barrier->bi_deadline,
218                                      cfs_time_current_sec()))
219                         RETURN(1);
220         }
221
222         CDEBUG(D_SNAPSHOT, "%s: barrier freezing %s done.\n",
223                barrier_barrier2name(barrier), phase1 ? "phase1" : "phase2");
224
225         if (!phase1)
226                 barrier_set(barrier, BS_FROZEN);
227
228         RETURN(0);
229 }
230
231 void barrier_init(void)
232 {
233 }
234
235 void barrier_fini(void)
236 {
237         LASSERT(list_empty(&barrier_instance_list));
238 }
239
240 int barrier_handler(struct dt_device *key, struct ptlrpc_request *req)
241 {
242         struct ldlm_gl_barrier_desc *desc;
243         struct barrier_instance *barrier;
244         struct barrier_lvb *lvb;
245         struct lu_env env;
246         int rc = 0;
247         ENTRY;
248
249         /* glimpse on barrier locks always packs a glimpse descriptor */
250         req_capsule_extend(&req->rq_pill, &RQF_LDLM_GL_DESC_CALLBACK);
251         desc = req_capsule_client_get(&req->rq_pill, &RMF_DLM_GL_DESC);
252         if (!desc)
253                 GOTO(out, rc = -EPROTO);
254
255         req_capsule_set_size(&req->rq_pill, &RMF_DLM_LVB, RCL_SERVER,
256                               sizeof(struct barrier_lvb));
257         rc = req_capsule_server_pack(&req->rq_pill);
258         if (rc)
259                 GOTO(out, rc);
260
261         lvb = req_capsule_server_get(&req->rq_pill, &RMF_DLM_LVB);
262         barrier = barrier_instance_find(key);
263         if (!barrier)
264                 GOTO(out, rc = -ENODEV);
265
266         rc = lu_env_init(&env, LCT_MD_THREAD | LCT_DT_THREAD);
267         if (rc)
268                 GOTO(out_barrier, rc);
269
270         CDEBUG(D_SNAPSHOT,
271                "%s: handling barrier request: status %u, timeout %u\n",
272                barrier_barrier2name(barrier),
273                desc->lgbd_status, desc->lgbd_timeout);
274
275         switch (desc->lgbd_status) {
276         case BS_RESCAN:
277                 barrier_set(barrier, BS_INIT);
278                 break;
279         case BS_FREEZING_P1:
280         case BS_FREEZING_P2:
281                 barrier->bi_deadline = cfs_time_current_sec() +
282                                         desc->lgbd_timeout;
283                 rc = barrier_freeze(&env, barrier,
284                                     desc->lgbd_status == BS_FREEZING_P1);
285                 break;
286         case BS_THAWING:
287         case BS_FAILED:
288         case BS_EXPIRED:
289                 barrier_set(barrier, BS_THAWED);
290                 break;
291         default:
292                 CWARN("%s: unexpected barrier status %u\n",
293                       barrier_barrier2name(barrier), desc->lgbd_status);
294                 rc = -EINVAL;
295                 break;
296         }
297
298         GOTO(fini, rc);
299
300 fini:
301         lu_env_fini(&env);
302
303 out_barrier:
304         if (rc < 0)
305                 barrier_set(barrier, BS_FAILED);
306         else if (rc > 0)
307                 barrier_set(barrier, BS_EXPIRED);
308
309         lvb->lvb_status = barrier->bi_status;
310         lvb->lvb_index = barrier_dev_idx(barrier);
311
312         CDEBUG(D_SNAPSHOT, "%s: handled barrier request: status %u, "
313                "deadline %lu: rc = %d\n", barrier_barrier2name(barrier),
314                lvb->lvb_status, barrier->bi_deadline, rc);
315
316         barrier_instance_put(barrier);
317         rc = 0;
318
319 out:
320         req->rq_status = rc;
321         return rc;
322 }
323 EXPORT_SYMBOL(barrier_handler);
324
325 int barrier_register(struct dt_device *key, struct dt_device *next)
326 {
327         struct barrier_instance *barrier;
328         int rc;
329         ENTRY;
330
331         OBD_ALLOC_PTR(barrier);
332         if (!barrier)
333                 RETURN(-ENOMEM);
334
335         INIT_LIST_HEAD(&barrier->bi_link);
336         barrier->bi_bottom = key;
337         barrier->bi_next = next;
338         init_waitqueue_head(&barrier->bi_waitq);
339         rwlock_init(&barrier->bi_rwlock);
340         atomic_set(&barrier->bi_ref, 1);
341 #ifdef HAVE_PERCPU_COUNTER_INIT_GFP_FLAG
342         rc = percpu_counter_init(&barrier->bi_writers, 0, GFP_KERNEL);
343 #else
344         rc = percpu_counter_init(&barrier->bi_writers, 0);
345 #endif
346         if (rc)
347                 barrier_instance_cleanup(barrier);
348         else
349                 barrier_instance_add(barrier);
350
351         RETURN(rc);
352 }
353 EXPORT_SYMBOL(barrier_register);
354
355 void barrier_deregister(struct dt_device *key)
356 {
357         struct barrier_instance *barrier;
358
359         spin_lock(&barrier_instance_lock);
360         barrier = barrier_instance_find_locked(key);
361         if (barrier)
362                 list_del_init(&barrier->bi_link);
363         spin_unlock(&barrier_instance_lock);
364
365         if (barrier)
366                 barrier_instance_put(barrier);
367 }
368 EXPORT_SYMBOL(barrier_deregister);