Whamcloud - gitweb
1c79efefc037011ecbcb961d5231ae5c90279822
[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
47 /**
48  * Initialize the pool data structures at startup.
49  *
50  * Allocate and initialize the pool data structures with the specified
51  * array size.  If pool count is not specified (\a count == 0), then
52  * POOL_INIT_COUNT will be used.  Allocating a non-zero initial array
53  * size avoids the need to reallocate as new pools are added.
54  *
55  * \param[in] op        pool structure
56  * \param[in] count     initial size of the target op_array[] array
57  *
58  * \retval              0 indicates successful pool initialization
59  * \retval              negative error number on failure
60  */
61 #define POOL_INIT_COUNT 2
62 int tgt_pool_init(struct lu_tgt_pool *op, unsigned int count)
63 {
64         ENTRY;
65
66         if (count == 0)
67                 count = POOL_INIT_COUNT;
68         op->op_array = NULL;
69         op->op_count = 0;
70         init_rwsem(&op->op_rw_sem);
71         op->op_size = count * sizeof(op->op_array[0]);
72         OBD_ALLOC(op->op_array, op->op_size);
73         if (op->op_array == NULL) {
74                 op->op_size = 0;
75                 RETURN(-ENOMEM);
76         }
77         EXIT;
78         return 0;
79 }
80 EXPORT_SYMBOL(tgt_pool_init);
81
82 /**
83  * Increase the op_array size to hold more targets in this pool.
84  *
85  * The size is increased to at least \a min_count, but may be larger
86  * for an existing pool since ->op_array[] is growing exponentially.
87  * Caller must hold write op_rwlock.
88  *
89  * \param[in] op        pool structure
90  * \param[in] min_count minimum number of entries to handle
91  *
92  * \retval              0 on success
93  * \retval              negative error number on failure.
94  */
95 int tgt_pool_extend(struct lu_tgt_pool *op, unsigned int min_count)
96 {
97         __u32 *new;
98         __u32 new_size;
99
100         LASSERT(min_count != 0);
101
102         if (op->op_count * sizeof(op->op_array[0]) < op->op_size)
103                 return 0;
104
105         new_size = max_t(__u32, min_count * sizeof(op->op_array[0]),
106                          2 * op->op_size);
107         OBD_ALLOC(new, new_size);
108         if (new == NULL)
109                 return -ENOMEM;
110
111         /* copy old array to new one */
112         memcpy(new, op->op_array, op->op_size);
113         OBD_FREE(op->op_array, op->op_size);
114         op->op_array = new;
115         op->op_size = new_size;
116
117         return 0;
118 }
119 EXPORT_SYMBOL(tgt_pool_extend);
120
121 /**
122  * Add a new target to an existing pool.
123  *
124  * Add a new target device to the pool previously created and returned by
125  * lod_pool_new().  Each target can only be in each pool at most one time.
126  *
127  * \param[in] op        target pool to add new entry
128  * \param[in] idx       pool index number to add to the \a op array
129  * \param[in] min_count minimum number of entries to expect in the pool
130  *
131  * \retval              0 if target could be added to the pool
132  * \retval              negative error if target \a idx was not added
133  */
134 int tgt_pool_add(struct lu_tgt_pool *op, __u32 idx, unsigned int min_count)
135 {
136         unsigned int i;
137         int rc = 0;
138         ENTRY;
139
140         down_write(&op->op_rw_sem);
141
142         rc = tgt_pool_extend(op, min_count);
143         if (rc)
144                 GOTO(out, rc);
145
146         /* search ost in pool array */
147         for (i = 0; i < op->op_count; i++) {
148                 if (op->op_array[i] == idx)
149                         GOTO(out, rc = -EEXIST);
150         }
151         /* ost not found we add it */
152         op->op_array[op->op_count] = idx;
153         op->op_count++;
154         EXIT;
155 out:
156         up_write(&op->op_rw_sem);
157         return rc;
158 }
159 EXPORT_SYMBOL(tgt_pool_add);
160
161 /**
162  * Remove an existing pool from the system.
163  *
164  * The specified pool must have previously been allocated by
165  * lod_pool_new() and not have any target members in the pool.
166  * If the removed target is not the last, compact the array
167  * to remove empty spaces.
168  *
169  * \param[in] op        pointer to the original data structure
170  * \param[in] idx       target index to be removed
171  *
172  * \retval              0 on success
173  * \retval              negative error number on failure
174  */
175 int tgt_pool_remove(struct lu_tgt_pool *op, __u32 idx)
176 {
177         unsigned int i;
178         ENTRY;
179
180         down_write(&op->op_rw_sem);
181
182         for (i = 0; i < op->op_count; i++) {
183                 if (op->op_array[i] == idx) {
184                         memmove(&op->op_array[i], &op->op_array[i + 1],
185                                 (op->op_count - i - 1) *
186                                 sizeof(op->op_array[0]));
187                         op->op_count--;
188                         up_write(&op->op_rw_sem);
189                         EXIT;
190                         return 0;
191                 }
192         }
193
194         up_write(&op->op_rw_sem);
195         RETURN(-EINVAL);
196 }
197 EXPORT_SYMBOL(tgt_pool_remove);
198
199 int tgt_check_index(int idx, struct lu_tgt_pool *osts)
200 {
201         int rc, i;
202         ENTRY;
203
204         down_read(&osts->op_rw_sem);
205         for (i = 0; i < osts->op_count; i++) {
206                 if (osts->op_array[i] == idx)
207                         GOTO(out, rc = 0);
208         }
209         rc = -ENOENT;
210         EXIT;
211 out:
212         up_read(&osts->op_rw_sem);
213         return rc;
214 }
215 EXPORT_SYMBOL(tgt_check_index);
216
217 /**
218  * Free the pool after it was emptied and removed from /proc.
219  *
220  * Note that all of the child/target entries referenced by this pool
221  * must have been removed by lod_ost_pool_remove() before it can be
222  * deleted from memory.
223  *
224  * \param[in] op        pool to be freed.
225  *
226  * \retval              0 on success or if pool was already freed
227  */
228 int tgt_pool_free(struct lu_tgt_pool *op)
229 {
230         ENTRY;
231
232         if (op->op_size == 0)
233                 RETURN(0);
234
235         down_write(&op->op_rw_sem);
236
237         OBD_FREE(op->op_array, op->op_size);
238         op->op_array = NULL;
239         op->op_count = 0;
240         op->op_size = 0;
241
242         up_write(&op->op_rw_sem);
243         RETURN(0);
244 }
245 EXPORT_SYMBOL(tgt_pool_free);