Whamcloud - gitweb
LU-17705 ptlrpc: replace synchronize_rcu() with rcu_barrier()
[fs/lustre-release.git] / lnet / lnet / lib-eq.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) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2012, 2016, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  * Lustre is a trademark of Sun Microsystems, Inc.
31  *
32  * lnet/lnet/lib-eq.c
33  *
34  * Library level Event queue management routines
35  */
36
37 #define DEBUG_SUBSYSTEM S_LNET
38 #include <lnet/lib-lnet.h>
39
40 /**
41  * Create an event queue that calls a @callback on each event.
42  *
43  * \param callback A handler function that runs when an event is deposited
44  * into the EQ.
45  *
46  * \retval eq      On successful return, the newly created EQ is returned.
47  *                 On failure, an error code encoded with ERR_PTR() is returned.
48  * \retval -EINVAL If an parameter is not valid.
49  * \retval -ENOMEM If memory for the EQ can't be allocated.
50  *
51  * \see lnet_eq_handler_t for the discussion on EQ handler semantics.
52  */
53 struct lnet_eq *
54 LNetEQAlloc(lnet_eq_handler_t callback)
55 {
56         struct lnet_eq *eq;
57
58         LASSERT(the_lnet.ln_refcount > 0);
59
60         if (callback == LNET_EQ_HANDLER_NONE)
61                 return ERR_PTR(-EINVAL);
62
63         eq = lnet_eq_alloc();
64         if (eq == NULL)
65                 return ERR_PTR(-ENOMEM);
66
67         eq->eq_callback = callback;
68
69         eq->eq_refs = cfs_percpt_alloc(lnet_cpt_table(),
70                                        sizeof(*eq->eq_refs[0]));
71         if (eq->eq_refs == NULL)
72                 goto failed;
73
74         return eq;
75
76 failed:
77         if (eq->eq_refs != NULL)
78                 cfs_percpt_free(eq->eq_refs);
79
80         lnet_eq_free(eq);
81         return ERR_PTR(-ENOMEM);
82 }
83 EXPORT_SYMBOL(LNetEQAlloc);
84
85 /**
86  * Release the resources associated with an event queue if it's idle;
87  * otherwise do nothing and it's up to the user to try again.
88  *
89  * \param eq The event queue to be released.
90  *
91  * \retval 0 If the EQ is not in use and freed.
92  * \retval -EBUSY  If the EQ is still in use by some MDs.
93  */
94 int
95 LNetEQFree(struct lnet_eq *eq)
96 {
97         int             **refs = NULL;
98         int             *ref;
99         int             rc = 0;
100         int             i;
101
102         lnet_res_lock(LNET_LOCK_EX);
103         /* NB: hold lnet_eq_wait_lock for EQ link/unlink, so we can do
104          * both EQ lookup and poll event with only lnet_eq_wait_lock */
105         lnet_eq_wait_lock();
106
107         cfs_percpt_for_each(ref, i, eq->eq_refs) {
108                 LASSERT(*ref >= 0);
109                 if (*ref == 0)
110                         continue;
111
112                 CDEBUG(D_NET, "Event equeue (%d: %d) busy on destroy.\n",
113                        i, *ref);
114                 rc = -EBUSY;
115                 goto out;
116         }
117
118         /* stash for free after lock dropped */
119         refs    = eq->eq_refs;
120
121         lnet_eq_free(eq);
122  out:
123         lnet_eq_wait_unlock();
124         lnet_res_unlock(LNET_LOCK_EX);
125
126         if (refs != NULL)
127                 cfs_percpt_free(refs);
128
129         return rc;
130 }
131 EXPORT_SYMBOL(LNetEQFree);
132
133 void
134 lnet_eq_enqueue_event(struct lnet_eq *eq, struct lnet_event *ev)
135 {
136         LASSERT(eq->eq_callback != LNET_EQ_HANDLER_NONE);
137         eq->eq_callback(ev);
138 }