Whamcloud - gitweb
LU-15067 lod: fix error handling in lod_new_pool
[fs/lustre-release.git] / lustre / obdclass / lu_tgt_pool.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  2008 Sun Microsystems, Inc. All rights reserved
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2012, 2017, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  */
31 /*
32  * lustre/target/tgt_pool.c
33  *
34  * This file handles creation, lookup, and removal of pools themselves, as
35  * well as adding and removing targets to pools.
36  *
37  * Author: Jacques-Charles LAFOUCRIERE <jc.lafoucriere@cea.fr>
38  * Author: Alex Lyashkov <Alexey.Lyashkov@Sun.COM>
39  * Author: Nathaniel Rutman <Nathan.Rutman@Sun.COM>
40  */
41
42 #define DEBUG_SUBSYSTEM S_CLASS
43
44 #include <obd_target.h>
45 #include <obd_support.h>
46 #include <lu_object.h>
47
48 /**
49  * Initialize the pool data structures at startup.
50  *
51  * Allocate and initialize the pool data structures with the specified
52  * array size.  If pool count is not specified (\a count == 0), then
53  * POOL_INIT_COUNT will be used.  Allocating a non-zero initial array
54  * size avoids the need to reallocate as new pools are added.
55  *
56  * \param[in] op        pool structure
57  * \param[in] count     initial size of the target op_array[] array
58  *
59  * \retval              0 indicates successful pool initialization
60  * \retval              negative error number on failure
61  */
62 #define POOL_INIT_COUNT 2
63 int lu_tgt_pool_init(struct lu_tgt_pool *op, unsigned int count)
64 {
65         ENTRY;
66
67         if (count == 0)
68                 count = POOL_INIT_COUNT;
69         op->op_array = NULL;
70         op->op_count = 0;
71         init_rwsem(&op->op_rw_sem);
72         op->op_size = count * sizeof(op->op_array[0]);
73         OBD_ALLOC(op->op_array, op->op_size);
74         if (op->op_array == NULL) {
75                 op->op_size = 0;
76                 RETURN(-ENOMEM);
77         }
78         EXIT;
79         return 0;
80 }
81 EXPORT_SYMBOL(lu_tgt_pool_init);
82
83 /**
84  * Increase the op_array size to hold more targets in this pool.
85  *
86  * The size is increased to at least \a min_count, but may be larger
87  * for an existing pool since ->op_array[] is growing exponentially.
88  * Caller must hold write op_rwlock.
89  *
90  * \param[in] op        pool structure
91  * \param[in] min_count minimum number of entries to handle
92  *
93  * \retval              0 on success
94  * \retval              negative error number on failure.
95  */
96 int lu_tgt_pool_extend(struct lu_tgt_pool *op, unsigned int min_count)
97 {
98         __u32 *new;
99         __u32 new_size;
100
101         LASSERT(min_count != 0);
102
103         if (op->op_count * sizeof(op->op_array[0]) < op->op_size)
104                 return 0;
105
106         new_size = max_t(__u32, min_count * sizeof(op->op_array[0]),
107                          2 * op->op_size);
108         OBD_ALLOC(new, new_size);
109         if (new == NULL)
110                 return -ENOMEM;
111
112         /* copy old array to new one */
113         memcpy(new, op->op_array, op->op_size);
114         OBD_FREE(op->op_array, op->op_size);
115         op->op_array = new;
116         op->op_size = new_size;
117
118         return 0;
119 }
120 EXPORT_SYMBOL(lu_tgt_pool_extend);
121
122 /**
123  * Add a new target to an existing pool.
124  *
125  * Add a new target device to the pool previously created and returned by
126  * lod_pool_new().  Each target can only be in each pool at most one time.
127  *
128  * \param[in] op        target pool to add new entry
129  * \param[in] idx       pool index number to add to the \a op array
130  * \param[in] min_count minimum number of entries to expect in the pool
131  *
132  * \retval              0 if target could be added to the pool
133  * \retval              negative error if target \a idx was not added
134  */
135 int lu_tgt_pool_add(struct lu_tgt_pool *op, __u32 idx, unsigned int min_count)
136 {
137         unsigned int i;
138         int rc = 0;
139         ENTRY;
140
141         down_write(&op->op_rw_sem);
142
143         /* search ost in pool array */
144         for (i = 0; i < op->op_count; i++) {
145                 if (op->op_array[i] == idx)
146                         GOTO(out, rc = -EEXIST);
147         }
148
149         rc = lu_tgt_pool_extend(op, min_count);
150         if (rc)
151                 GOTO(out, rc);
152
153         /* ost not found we add it */
154         op->op_array[op->op_count] = idx;
155         op->op_count++;
156         EXIT;
157 out:
158         up_write(&op->op_rw_sem);
159         return rc;
160 }
161 EXPORT_SYMBOL(lu_tgt_pool_add);
162
163 /**
164  * Remove an existing pool from the system.
165  *
166  * The specified pool must have previously been allocated by
167  * lod_pool_new() and not have any target members in the pool.
168  * If the removed target is not the last, compact the array
169  * to remove empty spaces.
170  *
171  * \param[in] op        pointer to the original data structure
172  * \param[in] idx       target index to be removed
173  *
174  * \retval              0 on success
175  * \retval              negative error number on failure
176  */
177 int lu_tgt_pool_remove(struct lu_tgt_pool *op, __u32 idx)
178 {
179         unsigned int i;
180         ENTRY;
181
182         down_write(&op->op_rw_sem);
183
184         for (i = 0; i < op->op_count; i++) {
185                 if (op->op_array[i] == idx) {
186                         memmove(&op->op_array[i], &op->op_array[i + 1],
187                                 (op->op_count - i - 1) *
188                                 sizeof(op->op_array[0]));
189                         op->op_count--;
190                         up_write(&op->op_rw_sem);
191                         EXIT;
192                         return 0;
193                 }
194         }
195
196         up_write(&op->op_rw_sem);
197         RETURN(-EINVAL);
198 }
199 EXPORT_SYMBOL(lu_tgt_pool_remove);
200
201 int lu_tgt_check_index(int idx, struct lu_tgt_pool *osts)
202 {
203         int rc, i;
204         ENTRY;
205
206         down_read(&osts->op_rw_sem);
207         for (i = 0; i < osts->op_count; i++) {
208                 if (osts->op_array[i] == idx)
209                         GOTO(out, rc = 0);
210         }
211         rc = -ENOENT;
212         EXIT;
213 out:
214         up_read(&osts->op_rw_sem);
215         return rc;
216 }
217 EXPORT_SYMBOL(lu_tgt_check_index);
218
219 /**
220  * Free the pool after it was emptied and removed from /proc.
221  *
222  * Note that all of the child/target entries referenced by this pool
223  * must have been removed by lod_ost_pool_remove() before it can be
224  * deleted from memory.
225  *
226  * \param[in] op        pool to be freed.
227  *
228  * \retval              0 on success or if pool was already freed
229  */
230 int lu_tgt_pool_free(struct lu_tgt_pool *op)
231 {
232         ENTRY;
233
234         if (op->op_size == 0)
235                 RETURN(0);
236
237         down_write(&op->op_rw_sem);
238
239         OBD_FREE(op->op_array, op->op_size);
240         op->op_array = NULL;
241         op->op_count = 0;
242         op->op_size = 0;
243
244         up_write(&op->op_rw_sem);
245         RETURN(0);
246 }
247 EXPORT_SYMBOL(lu_tgt_pool_free);