Whamcloud - gitweb
LU-477 allocate memory for s_group_desc and s_group_info by vmalloc()
[fs/lustre-release.git] / lustre / lmv / lmv_object.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see
20  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
30  * Use is subject to license terms.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  */
36
37 #ifndef EXPORT_SYMTAB
38 # define EXPORT_SYMTAB
39 #endif
40 #define DEBUG_SUBSYSTEM S_LMV
41 #ifdef __KERNEL__
42 #include <linux/slab.h>
43 #include <linux/module.h>
44 #include <linux/init.h>
45 #include <linux/slab.h>
46 #include <linux/pagemap.h>
47 #include <asm/div64.h>
48 #include <linux/seq_file.h>
49 #else
50 #include <liblustre.h>
51 #endif
52
53 #include <obd_support.h>
54 #include <lustre/lustre_idl.h>
55 #include <lustre_lib.h>
56 #include <lustre_net.h>
57 #include <lustre_dlm.h>
58 #include <obd_class.h>
59 #include <lprocfs_status.h>
60 #include "lmv_internal.h"
61
62 extern cfs_mem_cache_t *lmv_object_cache;
63 extern cfs_atomic_t lmv_object_count;
64
65 static CFS_LIST_HEAD(obj_list);
66 static cfs_spinlock_t obj_list_lock = CFS_SPIN_LOCK_UNLOCKED;
67
68 struct lmv_object *lmv_object_alloc(struct obd_device *obd,
69                                     const struct lu_fid *fid,
70                                     struct lmv_stripe_md *mea)
71 {
72         struct lmv_obd          *lmv = &obd->u.lmv;
73         unsigned int             obj_size;
74         struct lmv_object       *obj;
75         int                      i;
76
77         LASSERT(mea->mea_magic == MEA_MAGIC_LAST_CHAR
78                 || mea->mea_magic == MEA_MAGIC_ALL_CHARS
79                 || mea->mea_magic == MEA_MAGIC_HASH_SEGMENT);
80
81         OBD_SLAB_ALLOC_PTR(obj, lmv_object_cache);
82         if (!obj)
83                 return NULL;
84
85         cfs_atomic_inc(&lmv_object_count);
86
87         obj->lo_fid = *fid;
88         obj->lo_obd = obd;
89         obj->lo_state = 0;
90         obj->lo_hashtype = mea->mea_magic;
91
92         cfs_init_mutex(&obj->lo_guard);
93         cfs_atomic_set(&obj->lo_count, 0);
94         obj->lo_objcount = mea->mea_count;
95
96         obj_size = sizeof(struct lmv_stripe) * 
97                 lmv->desc.ld_tgt_count;
98
99         OBD_ALLOC_LARGE(obj->lo_stripes, obj_size);
100         if (!obj->lo_stripes)
101                 goto err_obj;
102
103         CDEBUG(D_INODE, "Allocate object for "DFID"\n", 
104                PFID(fid));
105         for (i = 0; i < mea->mea_count; i++) {
106                 int rc;
107
108                 CDEBUG(D_INODE, "Process subobject "DFID"\n", 
109                        PFID(&mea->mea_ids[i]));
110                 obj->lo_stripes[i].ls_fid = mea->mea_ids[i];
111                 LASSERT(fid_is_sane(&obj->lo_stripes[i].ls_fid));
112
113                 /*
114                  * Cache slave mds number to use it in all cases it is needed
115                  * instead of constant lookup.
116                  */
117                 rc = lmv_fld_lookup(lmv, &obj->lo_stripes[i].ls_fid,
118                                     &obj->lo_stripes[i].ls_mds);
119                 if (rc)
120                         goto err_obj;
121         }
122
123         return obj;
124 err_obj:
125         OBD_FREE(obj, sizeof(*obj));
126         return NULL;
127 }
128
129 void lmv_object_free(struct lmv_object *obj)
130 {
131         struct lmv_obd          *lmv = &obj->lo_obd->u.lmv;
132         unsigned int             obj_size;
133
134         LASSERT(!cfs_atomic_read(&obj->lo_count));
135
136         obj_size = sizeof(struct lmv_stripe) *
137                 lmv->desc.ld_tgt_count;
138
139         OBD_FREE_LARGE(obj->lo_stripes, obj_size);
140         OBD_SLAB_FREE(obj, lmv_object_cache, sizeof(*obj));
141         cfs_atomic_dec(&lmv_object_count);
142 }
143
144 static void __lmv_object_add(struct lmv_object *obj)
145 {
146         cfs_atomic_inc(&obj->lo_count);
147         cfs_list_add(&obj->lo_list, &obj_list);
148 }
149
150 void lmv_object_add(struct lmv_object *obj)
151 {
152         cfs_spin_lock(&obj_list_lock);
153         __lmv_object_add(obj);
154         cfs_spin_unlock(&obj_list_lock);
155 }
156
157 static void __lmv_object_del(struct lmv_object *obj)
158 {
159         cfs_list_del(&obj->lo_list);
160         lmv_object_free(obj);
161 }
162
163 void lmv_object_del(struct lmv_object *obj)
164 {
165         cfs_spin_lock(&obj_list_lock);
166         __lmv_object_del(obj);
167         cfs_spin_unlock(&obj_list_lock);
168 }
169
170 static struct lmv_object *__lmv_object_get(struct lmv_object *obj)
171 {
172         LASSERT(obj != NULL);
173         cfs_atomic_inc(&obj->lo_count);
174         return obj;
175 }
176
177 struct lmv_object *lmv_object_get(struct lmv_object *obj)
178 {
179         cfs_spin_lock(&obj_list_lock);
180         __lmv_object_get(obj);
181         cfs_spin_unlock(&obj_list_lock);
182         return obj;
183 }
184
185 static void __lmv_object_put(struct lmv_object *obj)
186 {
187         LASSERT(obj);
188
189         if (cfs_atomic_dec_and_test(&obj->lo_count)) {
190                 CDEBUG(D_INODE, "Last reference to "DFID" - "
191                        "destroying\n", PFID(&obj->lo_fid));
192                 __lmv_object_del(obj);
193         }
194 }
195
196 void lmv_object_put(struct lmv_object *obj)
197 {
198         cfs_spin_lock(&obj_list_lock);
199         __lmv_object_put(obj);
200         cfs_spin_unlock(&obj_list_lock);
201 }
202
203 void lmv_object_put_unlock(struct lmv_object *obj)
204 {
205         lmv_object_unlock(obj);
206         lmv_object_put(obj);
207 }
208
209 static struct lmv_object *__lmv_object_find(struct obd_device *obd, const struct lu_fid *fid)
210 {
211         struct lmv_object       *obj;
212         cfs_list_t              *cur;
213
214         cfs_list_for_each(cur, &obj_list) {
215                 obj = cfs_list_entry(cur, struct lmv_object, lo_list);
216
217                 /*
218                  * Check if object is in destroying phase. If so - skip
219                  * it.
220                  */
221                 if (obj->lo_state & O_FREEING)
222                         continue;
223
224                 /*
225                  * We should make sure, that we have found object belong to
226                  * passed obd. It is possible that, object manager will have two
227                  * objects with the same fid belong to different obds, if client
228                  * and mds runs on the same host. May be it is good idea to have
229                  * objects list associated with obd.
230                  */
231                 if (obj->lo_obd != obd)
232                         continue;
233
234                 /*
235                  * Check if this is what we're looking for.
236                  */
237                 if (lu_fid_eq(&obj->lo_fid, fid))
238                         return __lmv_object_get(obj);
239         }
240
241         return NULL;
242 }
243
244 struct lmv_object *lmv_object_find(struct obd_device *obd, 
245                                    const struct lu_fid *fid)
246 {
247         struct lmv_object       *obj;
248         ENTRY;
249
250         cfs_spin_lock(&obj_list_lock);
251         obj = __lmv_object_find(obd, fid);
252         cfs_spin_unlock(&obj_list_lock);
253
254         RETURN(obj);
255 }
256
257 struct lmv_object *lmv_object_find_lock(struct obd_device *obd, 
258                                         const struct lu_fid *fid)
259 {
260         struct lmv_object       *obj;
261         ENTRY;
262
263         obj = lmv_object_find(obd, fid);
264         if (obj)
265                 lmv_object_lock(obj);
266
267         RETURN(obj);
268 }
269
270 static struct lmv_object *__lmv_object_create(struct obd_device *obd, 
271                                               const struct lu_fid *fid,
272                                               struct lmv_stripe_md *mea)
273 {
274         struct lmv_object       *new;
275         struct lmv_object       *obj;
276         ENTRY;
277
278         obj = lmv_object_find(obd, fid);
279         if (obj)
280                 RETURN(obj);
281
282         new = lmv_object_alloc(obd, fid, mea);
283         if (!new)
284                 RETURN(NULL);
285
286         /* 
287          * Check if someone created it already while we were dealing with
288          * allocating @obj. 
289          */
290         cfs_spin_lock(&obj_list_lock);
291         obj = __lmv_object_find(obd, fid);
292         if (obj) {
293                 /* 
294                  * Someone created it already - put @obj and getting out. 
295                  */
296                 cfs_spin_unlock(&obj_list_lock);
297                 lmv_object_free(new);
298                 RETURN(obj);
299         }
300
301         __lmv_object_add(new);
302         __lmv_object_get(new);
303
304         cfs_spin_unlock(&obj_list_lock);
305
306         CDEBUG(D_INODE, "New obj in lmv cache: "DFID"\n",
307                PFID(fid));
308
309         RETURN(new);
310 }
311
312 struct lmv_object *lmv_object_create(struct obd_export *exp, 
313                                      const struct lu_fid *fid,
314                                      struct lmv_stripe_md *mea)
315 {
316         struct obd_device       *obd = exp->exp_obd;
317         struct lmv_obd          *lmv = &obd->u.lmv;
318         struct ptlrpc_request   *req = NULL;
319         struct lmv_tgt_desc     *tgt;
320         struct lmv_object       *obj;
321         struct lustre_md         md;
322         int                      mealen;
323         int                      rc;
324         ENTRY;
325
326         CDEBUG(D_INODE, "Get mea for "DFID" and create lmv obj\n",
327                PFID(fid));
328
329         md.mea = NULL;
330
331         if (mea == NULL) {
332                 struct md_op_data *op_data;
333                 __u64 valid;
334
335                 CDEBUG(D_INODE, "Mea isn't passed in, get it now\n");
336                 mealen = lmv_get_easize(lmv);
337
338                 /*
339                  * Time to update mea of parent fid.
340                  */
341                 md.mea = NULL;
342                 valid = OBD_MD_FLEASIZE | OBD_MD_FLDIREA | OBD_MD_MEA;
343
344                 tgt = lmv_find_target(lmv, fid);
345                 if (IS_ERR(tgt))
346                         GOTO(cleanup, obj = (void *)tgt);
347
348                 OBD_ALLOC_PTR(op_data);
349                 if (op_data == NULL)
350                         GOTO(cleanup, obj = ERR_PTR(-ENOMEM));
351
352                 op_data->op_fid1 = *fid;
353                 op_data->op_mode = mealen;
354                 op_data->op_valid = valid;
355                 rc = md_getattr(tgt->ltd_exp, op_data, &req);
356                 OBD_FREE_PTR(op_data);
357                 if (rc) {
358                         CERROR("md_getattr() failed, error %d\n", rc);
359                         GOTO(cleanup, obj = ERR_PTR(rc));
360                 }
361
362                 rc = md_get_lustre_md(exp, req, NULL, exp, &md);
363                 if (rc) {
364                         CERROR("md_get_lustre_md() failed, error %d\n", rc);
365                         GOTO(cleanup, obj = ERR_PTR(rc));
366                 }
367
368                 if (md.mea == NULL)
369                         GOTO(cleanup, obj = ERR_PTR(-ENODATA));
370
371                 mea = md.mea;
372         }
373
374         /*
375          * Got mea, now create obj for it.
376          */
377         obj = __lmv_object_create(obd, fid, mea);
378         if (!obj) {
379                 CERROR("Can't create new object "DFID"\n",
380                        PFID(fid));
381                 GOTO(cleanup, obj = ERR_PTR(-ENOMEM));
382         }
383
384         if (md.mea != NULL)
385                 obd_free_memmd(exp, (void *)&md.mea);
386
387         EXIT;
388 cleanup:
389         if (req)
390                 ptlrpc_req_finished(req);
391         return obj;
392 }
393
394 int lmv_object_delete(struct obd_export *exp, const struct lu_fid *fid)
395 {
396         struct obd_device       *obd = exp->exp_obd;
397         struct lmv_object       *obj;
398         int                      rc = 0;
399         ENTRY;
400
401         cfs_spin_lock(&obj_list_lock);
402         obj = __lmv_object_find(obd, fid);
403         if (obj) {
404                 obj->lo_state |= O_FREEING;
405                 __lmv_object_put(obj);
406                 __lmv_object_put(obj);
407                 rc = 1;
408         }
409         cfs_spin_unlock(&obj_list_lock);
410         RETURN(rc);
411 }
412
413 int lmv_object_setup(struct obd_device *obd)
414 {
415         ENTRY;
416         LASSERT(obd != NULL);
417
418         CDEBUG(D_INFO, "LMV object manager setup (%s)\n",
419                obd->obd_uuid.uuid);
420
421         RETURN(0);
422 }
423
424 void lmv_object_cleanup(struct obd_device *obd)
425 {
426         cfs_list_t              *cur;
427         cfs_list_t              *tmp;
428         struct lmv_object       *obj;
429         ENTRY;
430
431         CDEBUG(D_INFO, "LMV object manager cleanup (%s)\n",
432                obd->obd_uuid.uuid);
433
434         cfs_spin_lock(&obj_list_lock);
435         cfs_list_for_each_safe(cur, tmp, &obj_list) {
436                 obj = cfs_list_entry(cur, struct lmv_object, lo_list);
437
438                 if (obj->lo_obd != obd)
439                         continue;
440
441                 obj->lo_state |= O_FREEING;
442                 if (cfs_atomic_read(&obj->lo_count) > 1) {
443                         CERROR("Object "DFID" has count (%d)\n", 
444                                PFID(&obj->lo_fid),
445                                cfs_atomic_read(&obj->lo_count));
446                 }
447                 __lmv_object_put(obj);
448         }
449         cfs_spin_unlock(&obj_list_lock);
450         EXIT;
451 }