Whamcloud - gitweb
LU-1346 libcfs: replace libcfs wrappers with kernel API
[fs/lustre-release.git] / lustre / lmv / lmv_object.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.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2011, Whamcloud, Inc.
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 #define DEBUG_SUBSYSTEM S_LMV
38 #ifdef __KERNEL__
39 #include <linux/slab.h>
40 #include <linux/module.h>
41 #include <linux/init.h>
42 #include <linux/slab.h>
43 #include <linux/pagemap.h>
44 #include <asm/div64.h>
45 #include <linux/seq_file.h>
46 #else
47 #include <liblustre.h>
48 #endif
49
50 #include <obd_support.h>
51 #include <lustre/lustre_idl.h>
52 #include <lustre_lib.h>
53 #include <lustre_net.h>
54 #include <lustre_dlm.h>
55 #include <obd_class.h>
56 #include <lprocfs_status.h>
57 #include "lmv_internal.h"
58
59 extern cfs_mem_cache_t *lmv_object_cache;
60 extern cfs_atomic_t lmv_object_count;
61
62 static CFS_LIST_HEAD(obj_list);
63 static DEFINE_SPINLOCK(obj_list_lock);
64
65 struct lmv_object *lmv_object_alloc(struct obd_device *obd,
66                                     const struct lu_fid *fid,
67                                     struct lmv_stripe_md *mea)
68 {
69         struct lmv_obd          *lmv = &obd->u.lmv;
70         unsigned int             obj_size;
71         struct lmv_object       *obj;
72         int                      i;
73
74         LASSERT(mea->mea_magic == MEA_MAGIC_LAST_CHAR
75                 || mea->mea_magic == MEA_MAGIC_ALL_CHARS
76                 || mea->mea_magic == MEA_MAGIC_HASH_SEGMENT);
77
78         OBD_SLAB_ALLOC_PTR(obj, lmv_object_cache);
79         if (!obj)
80                 return NULL;
81
82         cfs_atomic_inc(&lmv_object_count);
83
84         obj->lo_fid = *fid;
85         obj->lo_obd = obd;
86         obj->lo_state = 0;
87         obj->lo_hashtype = mea->mea_magic;
88
89         mutex_init(&obj->lo_guard);
90         cfs_atomic_set(&obj->lo_count, 0);
91         obj->lo_objcount = mea->mea_count;
92
93         obj_size = sizeof(struct lmv_stripe) * 
94                 lmv->desc.ld_tgt_count;
95
96         OBD_ALLOC_LARGE(obj->lo_stripes, obj_size);
97         if (!obj->lo_stripes)
98                 goto err_obj;
99
100         CDEBUG(D_INODE, "Allocate object for "DFID"\n", 
101                PFID(fid));
102         for (i = 0; i < mea->mea_count; i++) {
103                 int rc;
104
105                 CDEBUG(D_INODE, "Process subobject "DFID"\n", 
106                        PFID(&mea->mea_ids[i]));
107                 obj->lo_stripes[i].ls_fid = mea->mea_ids[i];
108                 LASSERT(fid_is_sane(&obj->lo_stripes[i].ls_fid));
109
110                 /*
111                  * Cache slave mds number to use it in all cases it is needed
112                  * instead of constant lookup.
113                  */
114                 rc = lmv_fld_lookup(lmv, &obj->lo_stripes[i].ls_fid,
115                                     &obj->lo_stripes[i].ls_mds);
116                 if (rc)
117                         goto err_obj;
118         }
119
120         return obj;
121 err_obj:
122         OBD_FREE(obj, sizeof(*obj));
123         return NULL;
124 }
125
126 void lmv_object_free(struct lmv_object *obj)
127 {
128         struct lmv_obd          *lmv = &obj->lo_obd->u.lmv;
129         unsigned int             obj_size;
130
131         LASSERT(!cfs_atomic_read(&obj->lo_count));
132
133         obj_size = sizeof(struct lmv_stripe) *
134                 lmv->desc.ld_tgt_count;
135
136         OBD_FREE_LARGE(obj->lo_stripes, obj_size);
137         OBD_SLAB_FREE(obj, lmv_object_cache, sizeof(*obj));
138         cfs_atomic_dec(&lmv_object_count);
139 }
140
141 static void __lmv_object_add(struct lmv_object *obj)
142 {
143         cfs_atomic_inc(&obj->lo_count);
144         cfs_list_add(&obj->lo_list, &obj_list);
145 }
146
147 void lmv_object_add(struct lmv_object *obj)
148 {
149         spin_lock(&obj_list_lock);
150         __lmv_object_add(obj);
151         spin_unlock(&obj_list_lock);
152 }
153
154 static void __lmv_object_del(struct lmv_object *obj)
155 {
156         cfs_list_del(&obj->lo_list);
157         lmv_object_free(obj);
158 }
159
160 void lmv_object_del(struct lmv_object *obj)
161 {
162         spin_lock(&obj_list_lock);
163         __lmv_object_del(obj);
164         spin_unlock(&obj_list_lock);
165 }
166
167 static struct lmv_object *__lmv_object_get(struct lmv_object *obj)
168 {
169         LASSERT(obj != NULL);
170         cfs_atomic_inc(&obj->lo_count);
171         return obj;
172 }
173
174 struct lmv_object *lmv_object_get(struct lmv_object *obj)
175 {
176         spin_lock(&obj_list_lock);
177         __lmv_object_get(obj);
178         spin_unlock(&obj_list_lock);
179         return obj;
180 }
181
182 static void __lmv_object_put(struct lmv_object *obj)
183 {
184         LASSERT(obj);
185
186         if (cfs_atomic_dec_and_test(&obj->lo_count)) {
187                 CDEBUG(D_INODE, "Last reference to "DFID" - "
188                        "destroying\n", PFID(&obj->lo_fid));
189                 __lmv_object_del(obj);
190         }
191 }
192
193 void lmv_object_put(struct lmv_object *obj)
194 {
195         spin_lock(&obj_list_lock);
196         __lmv_object_put(obj);
197         spin_unlock(&obj_list_lock);
198 }
199
200 void lmv_object_put_unlock(struct lmv_object *obj)
201 {
202         lmv_object_unlock(obj);
203         lmv_object_put(obj);
204 }
205
206 static struct lmv_object *__lmv_object_find(struct obd_device *obd, const struct lu_fid *fid)
207 {
208         struct lmv_object       *obj;
209         cfs_list_t              *cur;
210
211         cfs_list_for_each(cur, &obj_list) {
212                 obj = cfs_list_entry(cur, struct lmv_object, lo_list);
213
214                 /*
215                  * Check if object is in destroying phase. If so - skip
216                  * it.
217                  */
218                 if (obj->lo_state & O_FREEING)
219                         continue;
220
221                 /*
222                  * We should make sure, that we have found object belong to
223                  * passed obd. It is possible that, object manager will have two
224                  * objects with the same fid belong to different obds, if client
225                  * and mds runs on the same host. May be it is good idea to have
226                  * objects list associated with obd.
227                  */
228                 if (obj->lo_obd != obd)
229                         continue;
230
231                 /*
232                  * Check if this is what we're looking for.
233                  */
234                 if (lu_fid_eq(&obj->lo_fid, fid))
235                         return __lmv_object_get(obj);
236         }
237
238         return NULL;
239 }
240
241 struct lmv_object *lmv_object_find(struct obd_device *obd,
242                                    const struct lu_fid *fid)
243 {
244         struct lmv_obd          *lmv = &obd->u.lmv;
245         struct lmv_object       *obj = NULL;
246         ENTRY;
247
248         /* For single MDT case, lmv_object list is always empty. */
249         if (lmv->desc.ld_tgt_count > 1) {
250                 spin_lock(&obj_list_lock);
251                 obj = __lmv_object_find(obd, fid);
252                 spin_unlock(&obj_list_lock);
253         }
254
255         RETURN(obj);
256 }
257
258 struct lmv_object *lmv_object_find_lock(struct obd_device *obd, 
259                                         const struct lu_fid *fid)
260 {
261         struct lmv_object       *obj;
262         ENTRY;
263
264         obj = lmv_object_find(obd, fid);
265         if (obj)
266                 lmv_object_lock(obj);
267
268         RETURN(obj);
269 }
270
271 static struct lmv_object *__lmv_object_create(struct obd_device *obd, 
272                                               const struct lu_fid *fid,
273                                               struct lmv_stripe_md *mea)
274 {
275         struct lmv_object       *new;
276         struct lmv_object       *obj;
277         ENTRY;
278
279         obj = lmv_object_find(obd, fid);
280         if (obj)
281                 RETURN(obj);
282
283         new = lmv_object_alloc(obd, fid, mea);
284         if (!new)
285                 RETURN(NULL);
286
287         /*
288          * Check if someone created it already while we were dealing with
289          * allocating @obj.
290          */
291         spin_lock(&obj_list_lock);
292         obj = __lmv_object_find(obd, fid);
293         if (obj) {
294                 /*
295                  * Someone created it already - put @obj and getting out.
296                  */
297                 spin_unlock(&obj_list_lock);
298                 lmv_object_free(new);
299                 RETURN(obj);
300         }
301
302         __lmv_object_add(new);
303         __lmv_object_get(new);
304
305         spin_unlock(&obj_list_lock);
306
307         CDEBUG(D_INODE, "New obj in lmv cache: "DFID"\n", 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         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         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         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         spin_unlock(&obj_list_lock);
450         EXIT;
451 }