Linux-libre 4.15.7-gnu
[librecmc/linux-libre.git] / drivers / staging / lustre / lustre / obdclass / llog_obd.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * GPL HEADER START
4  *
5  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 only,
9  * as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License version 2 for more details (a copy is included
15  * in the LICENSE file that accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License
18  * version 2 along with this program; If not, see
19  * http://www.gnu.org/licenses/gpl-2.0.html
20  *
21  * GPL HEADER END
22  */
23 /*
24  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
25  * Use is subject to license terms.
26  *
27  * Copyright (c) 2012, 2015, Intel Corporation.
28  */
29 /*
30  * This file is part of Lustre, http://www.lustre.org/
31  * Lustre is a trademark of Sun Microsystems, Inc.
32  */
33
34 #define DEBUG_SUBSYSTEM S_LOG
35
36 #include <obd_class.h>
37 #include <lustre_log.h>
38 #include "llog_internal.h"
39
40 /* helper functions for calling the llog obd methods */
41 static struct llog_ctxt *llog_new_ctxt(struct obd_device *obd)
42 {
43         struct llog_ctxt *ctxt;
44
45         ctxt = kzalloc(sizeof(*ctxt), GFP_NOFS);
46         if (!ctxt)
47                 return NULL;
48
49         ctxt->loc_obd = obd;
50         atomic_set(&ctxt->loc_refcount, 1);
51
52         return ctxt;
53 }
54
55 static void llog_ctxt_destroy(struct llog_ctxt *ctxt)
56 {
57         if (ctxt->loc_exp) {
58                 class_export_put(ctxt->loc_exp);
59                 ctxt->loc_exp = NULL;
60         }
61         if (ctxt->loc_imp) {
62                 class_import_put(ctxt->loc_imp);
63                 ctxt->loc_imp = NULL;
64         }
65         kfree(ctxt);
66 }
67
68 int __llog_ctxt_put(const struct lu_env *env, struct llog_ctxt *ctxt)
69 {
70         struct obd_llog_group *olg = ctxt->loc_olg;
71         struct obd_device *obd;
72         int rc = 0;
73
74         spin_lock(&olg->olg_lock);
75         if (!atomic_dec_and_test(&ctxt->loc_refcount)) {
76                 spin_unlock(&olg->olg_lock);
77                 return rc;
78         }
79         olg->olg_ctxts[ctxt->loc_idx] = NULL;
80         spin_unlock(&olg->olg_lock);
81
82         obd = ctxt->loc_obd;
83         spin_lock(&obd->obd_dev_lock);
84         /* sync with llog ctxt user thread */
85         spin_unlock(&obd->obd_dev_lock);
86
87         /* obd->obd_starting is needed for the case of cleanup
88          * in error case while obd is starting up.
89          */
90         LASSERTF(obd->obd_starting == 1 ||
91                  obd->obd_stopping == 1 || obd->obd_set_up == 0,
92                  "wrong obd state: %d/%d/%d\n", !!obd->obd_starting,
93                  !!obd->obd_stopping, !!obd->obd_set_up);
94
95         /* cleanup the llog ctxt here */
96         if (CTXTP(ctxt, cleanup))
97                 rc = CTXTP(ctxt, cleanup)(env, ctxt);
98
99         llog_ctxt_destroy(ctxt);
100         wake_up(&olg->olg_waitq);
101         return rc;
102 }
103 EXPORT_SYMBOL(__llog_ctxt_put);
104
105 int llog_cleanup(const struct lu_env *env, struct llog_ctxt *ctxt)
106 {
107         struct l_wait_info lwi = LWI_INTR(LWI_ON_SIGNAL_NOOP, NULL);
108         struct obd_llog_group *olg;
109         int rc, idx;
110
111         olg = ctxt->loc_olg;
112         LASSERT(olg);
113         LASSERT(olg != LP_POISON);
114
115         idx = ctxt->loc_idx;
116
117         /*
118          * Banlance the ctxt get when calling llog_cleanup()
119          */
120         LASSERT(atomic_read(&ctxt->loc_refcount) < LI_POISON);
121         LASSERT(atomic_read(&ctxt->loc_refcount) > 1);
122         llog_ctxt_put(ctxt);
123
124         /*
125          * Try to free the ctxt.
126          */
127         rc = __llog_ctxt_put(env, ctxt);
128         if (rc)
129                 CERROR("Error %d while cleaning up ctxt %p\n",
130                        rc, ctxt);
131
132         l_wait_event(olg->olg_waitq,
133                      llog_group_ctxt_null(olg, idx), &lwi);
134
135         return rc;
136 }
137 EXPORT_SYMBOL(llog_cleanup);
138
139 int llog_setup(const struct lu_env *env, struct obd_device *obd,
140                struct obd_llog_group *olg, int index,
141                struct obd_device *disk_obd, struct llog_operations *op)
142 {
143         struct llog_ctxt *ctxt;
144         int rc = 0;
145
146         if (index < 0 || index >= LLOG_MAX_CTXTS)
147                 return -EINVAL;
148
149         LASSERT(olg);
150
151         ctxt = llog_new_ctxt(obd);
152         if (!ctxt)
153                 return -ENOMEM;
154
155         ctxt->loc_obd = obd;
156         ctxt->loc_olg = olg;
157         ctxt->loc_idx = index;
158         ctxt->loc_logops = op;
159         mutex_init(&ctxt->loc_mutex);
160         ctxt->loc_exp = class_export_get(disk_obd->obd_self_export);
161         ctxt->loc_flags = LLOG_CTXT_FLAG_UNINITIALIZED;
162         ctxt->loc_chunk_size = LLOG_MIN_CHUNK_SIZE;
163
164         rc = llog_group_set_ctxt(olg, ctxt, index);
165         if (rc) {
166                 llog_ctxt_destroy(ctxt);
167                 if (rc == -EEXIST) {
168                         ctxt = llog_group_get_ctxt(olg, index);
169                         if (ctxt) {
170                                 /*
171                                  * mds_lov_update_desc() might call here multiple
172                                  * times. So if the llog is already set up then
173                                  * don't to do it again.
174                                  */
175                                 CDEBUG(D_CONFIG, "obd %s ctxt %d already set up\n",
176                                        obd->obd_name, index);
177                                 LASSERT(ctxt->loc_olg == olg);
178                                 LASSERT(ctxt->loc_obd == obd);
179                                 LASSERT(ctxt->loc_exp == disk_obd->obd_self_export);
180                                 LASSERT(ctxt->loc_logops == op);
181                                 llog_ctxt_put(ctxt);
182                         }
183                         rc = 0;
184                 }
185                 return rc;
186         }
187
188         if (op->lop_setup) {
189                 if (OBD_FAIL_CHECK(OBD_FAIL_OBD_LLOG_SETUP))
190                         rc = -EOPNOTSUPP;
191                 else
192                         rc = op->lop_setup(env, obd, olg, index, disk_obd);
193         }
194
195         if (rc) {
196                 CERROR("%s: ctxt %d lop_setup=%p failed: rc = %d\n",
197                        obd->obd_name, index, op->lop_setup, rc);
198                 llog_group_clear_ctxt(olg, index);
199                 llog_ctxt_destroy(ctxt);
200         } else {
201                 CDEBUG(D_CONFIG, "obd %s ctxt %d is initialized\n",
202                        obd->obd_name, index);
203                 ctxt->loc_flags &= ~LLOG_CTXT_FLAG_UNINITIALIZED;
204         }
205
206         return rc;
207 }
208 EXPORT_SYMBOL(llog_setup);
209
210 /* context key constructor/destructor: llog_key_init, llog_key_fini */
211 LU_KEY_INIT_FINI(llog, struct llog_thread_info);
212 /* context key: llog_thread_key */
213 LU_CONTEXT_KEY_DEFINE(llog, LCT_MD_THREAD | LCT_MG_THREAD | LCT_LOCAL);
214 LU_KEY_INIT_GENERIC(llog);
215
216 int llog_info_init(void)
217 {
218         llog_key_init_generic(&llog_thread_key, NULL);
219         lu_context_key_register(&llog_thread_key);
220         return 0;
221 }
222
223 void llog_info_fini(void)
224 {
225         lu_context_key_degister(&llog_thread_key);
226 }