Whamcloud - gitweb
cc5ab2c931e470ee398facb48ea5c497b589d124
[fs/lustre-release.git] / lustre / obdclass / lu_tgt_descs.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  * This file is part of Lustre, http://www.lustre.org/
24  *
25  * lustre/obdclass/lu_tgt_descs.c
26  *
27  * Lustre target descriptions
28  * These are the only exported functions, they provide some generic
29  * infrastructure for target description management used by LOD/LMV
30  *
31  */
32
33 #define DEBUG_SUBSYSTEM S_CLASS
34
35 #include <linux/module.h>
36 #include <linux/list.h>
37 #include <libcfs/libcfs.h>
38 #include <libcfs/libcfs_hash.h> /* hash_long() */
39 #include <libcfs/linux/linux-mem.h>
40 #include <obd_class.h>
41 #include <obd_support.h>
42 #include <lustre_disk.h>
43 #include <lustre_fid.h>
44 #include <lu_object.h>
45
46 /**
47  * Allocate and initialize target table.
48  *
49  * A helper function to initialize the target table and allocate
50  * a bitmap of the available targets.
51  *
52  * \param[in] ltd               target's table to initialize
53  *
54  * \retval 0                    on success
55  * \retval negative             negated errno on error
56  **/
57 int lu_tgt_descs_init(struct lu_tgt_descs *ltd)
58 {
59         mutex_init(&ltd->ltd_mutex);
60         init_rwsem(&ltd->ltd_rw_sem);
61
62         /*
63          * the tgt array and bitmap are allocated/grown dynamically as tgts are
64          * added to the LOD/LMV, see lu_tgt_descs_add()
65          */
66         ltd->ltd_tgt_bitmap = CFS_ALLOCATE_BITMAP(BITS_PER_LONG);
67         if (!ltd->ltd_tgt_bitmap)
68                 return -ENOMEM;
69
70         ltd->ltd_tgts_size  = BITS_PER_LONG;
71         ltd->ltd_tgtnr      = 0;
72
73         ltd->ltd_death_row = 0;
74         ltd->ltd_refcount  = 0;
75
76         return 0;
77 }
78 EXPORT_SYMBOL(lu_tgt_descs_init);
79
80 /**
81  * Free bitmap and target table pages.
82  *
83  * \param[in] ltd       target table
84  */
85 void lu_tgt_descs_fini(struct lu_tgt_descs *ltd)
86 {
87         int i;
88
89         CFS_FREE_BITMAP(ltd->ltd_tgt_bitmap);
90         for (i = 0; i < TGT_PTRS; i++) {
91                 if (ltd->ltd_tgt_idx[i])
92                         OBD_FREE_PTR(ltd->ltd_tgt_idx[i]);
93         }
94         ltd->ltd_tgts_size = 0;
95 }
96 EXPORT_SYMBOL(lu_tgt_descs_fini);
97
98 /**
99  * Expand size of target table.
100  *
101  * When the target table is full, we have to extend the table. To do so,
102  * we allocate new memory with some reserve, move data from the old table
103  * to the new one and release memory consumed by the old table.
104  *
105  * \param[in] ltd               target table
106  * \param[in] newsize           new size of the table
107  *
108  * \retval                      0 on success
109  * \retval                      -ENOMEM if reallocation failed
110  */
111 static int lu_tgt_descs_resize(struct lu_tgt_descs *ltd, __u32 newsize)
112 {
113         struct cfs_bitmap *new_bitmap, *old_bitmap = NULL;
114
115         /* someone else has already resize the array */
116         if (newsize <= ltd->ltd_tgts_size)
117                 return 0;
118
119         new_bitmap = CFS_ALLOCATE_BITMAP(newsize);
120         if (!new_bitmap)
121                 return -ENOMEM;
122
123         if (ltd->ltd_tgts_size > 0) {
124                 /* the bitmap already exists, copy data from old one */
125                 cfs_bitmap_copy(new_bitmap, ltd->ltd_tgt_bitmap);
126                 old_bitmap = ltd->ltd_tgt_bitmap;
127         }
128
129         ltd->ltd_tgts_size  = newsize;
130         ltd->ltd_tgt_bitmap = new_bitmap;
131
132         if (old_bitmap)
133                 CFS_FREE_BITMAP(old_bitmap);
134
135         CDEBUG(D_CONFIG, "tgt size: %d\n", ltd->ltd_tgts_size);
136
137         return 0;
138 }
139
140 /**
141  * Add new target to target table.
142  *
143  * Extend target table if it's full, update target table and bitmap.
144  * Notice we need to take ltd_rw_sem exclusively before entry to ensure
145  * atomic switch.
146  *
147  * \param[in] ltd               target table
148  * \param[in] tgt               new target desc
149  *
150  * \retval                      0 on success
151  * \retval                      -ENOMEM if reallocation failed
152  *                              -EEXIST if target existed
153  */
154 int lu_tgt_descs_add(struct lu_tgt_descs *ltd, struct lu_tgt_desc *tgt)
155 {
156         __u32 index = tgt->ltd_index;
157         int rc;
158
159         ENTRY;
160
161         if (index >= ltd->ltd_tgts_size) {
162                 __u32 newsize = 1;
163
164                 while (newsize < index + 1)
165                         newsize = newsize << 1;
166
167                 rc = lu_tgt_descs_resize(ltd, newsize);
168                 if (rc)
169                         RETURN(rc);
170         } else if (cfs_bitmap_check(ltd->ltd_tgt_bitmap, index)) {
171                 RETURN(-EEXIST);
172         }
173
174         if (ltd->ltd_tgt_idx[index / TGT_PTRS_PER_BLOCK] == NULL) {
175                 OBD_ALLOC_PTR(ltd->ltd_tgt_idx[index / TGT_PTRS_PER_BLOCK]);
176                 if (ltd->ltd_tgt_idx[index / TGT_PTRS_PER_BLOCK] == NULL)
177                         RETURN(-ENOMEM);
178         }
179
180         LTD_TGT(ltd, tgt->ltd_index) = tgt;
181         cfs_bitmap_set(ltd->ltd_tgt_bitmap, tgt->ltd_index);
182         ltd->ltd_tgtnr++;
183
184         RETURN(0);
185 }
186 EXPORT_SYMBOL(lu_tgt_descs_add);
187
188 /**
189  * Delete target from target table
190  */
191 void lu_tgt_descs_del(struct lu_tgt_descs *ltd, struct lu_tgt_desc *tgt)
192 {
193         LTD_TGT(ltd, tgt->ltd_index) = NULL;
194         cfs_bitmap_clear(ltd->ltd_tgt_bitmap, tgt->ltd_index);
195         ltd->ltd_tgtnr--;
196 }
197 EXPORT_SYMBOL(lu_tgt_descs_del);