Whamcloud - gitweb
LU-1798 tests: add set_and_check to test-framework
[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         cfs_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         cfs_spin_lock(&obj_list_lock);
150         __lmv_object_add(obj);
151         cfs_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         cfs_spin_lock(&obj_list_lock);
163         __lmv_object_del(obj);
164         cfs_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         cfs_spin_lock(&obj_list_lock);
177         __lmv_object_get(obj);
178         cfs_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         cfs_spin_lock(&obj_list_lock);
196         __lmv_object_put(obj);
197         cfs_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                 cfs_spin_lock(&obj_list_lock);
251                 obj = __lmv_object_find(obd, fid);
252                 cfs_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         cfs_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                 cfs_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         cfs_spin_unlock(&obj_list_lock);
306
307         CDEBUG(D_INODE, "New obj in lmv cache: "DFID"\n",
308                PFID(fid));
309
310         RETURN(new);
311 }
312
313 struct lmv_object *lmv_object_create(struct obd_export *exp, 
314                                      const struct lu_fid *fid,
315                                      struct lmv_stripe_md *mea)
316 {
317         struct obd_device       *obd = exp->exp_obd;
318         struct lmv_obd          *lmv = &obd->u.lmv;
319         struct ptlrpc_request   *req = NULL;
320         struct lmv_tgt_desc     *tgt;
321         struct lmv_object       *obj;
322         struct lustre_md         md;
323         int                      mealen;
324         int                      rc;
325         ENTRY;
326
327         CDEBUG(D_INODE, "Get mea for "DFID" and create lmv obj\n",
328                PFID(fid));
329
330         md.mea = NULL;
331
332         if (mea == NULL) {
333                 struct md_op_data *op_data;
334                 __u64 valid;
335
336                 CDEBUG(D_INODE, "Mea isn't passed in, get it now\n");
337                 mealen = lmv_get_easize(lmv);
338
339                 /*
340                  * Time to update mea of parent fid.
341                  */
342                 md.mea = NULL;
343                 valid = OBD_MD_FLEASIZE | OBD_MD_FLDIREA | OBD_MD_MEA;
344
345                 tgt = lmv_find_target(lmv, fid);
346                 if (IS_ERR(tgt))
347                         GOTO(cleanup, obj = (void *)tgt);
348
349                 OBD_ALLOC_PTR(op_data);
350                 if (op_data == NULL)
351                         GOTO(cleanup, obj = ERR_PTR(-ENOMEM));
352
353                 op_data->op_fid1 = *fid;
354                 op_data->op_mode = mealen;
355                 op_data->op_valid = valid;
356                 rc = md_getattr(tgt->ltd_exp, op_data, &req);
357                 OBD_FREE_PTR(op_data);
358                 if (rc) {
359                         CERROR("md_getattr() failed, error %d\n", rc);
360                         GOTO(cleanup, obj = ERR_PTR(rc));
361                 }
362
363                 rc = md_get_lustre_md(exp, req, NULL, exp, &md);
364                 if (rc) {
365                         CERROR("md_get_lustre_md() failed, error %d\n", rc);
366                         GOTO(cleanup, obj = ERR_PTR(rc));
367                 }
368
369                 if (md.mea == NULL)
370                         GOTO(cleanup, obj = ERR_PTR(-ENODATA));
371
372                 mea = md.mea;
373         }
374
375         /*
376          * Got mea, now create obj for it.
377          */
378         obj = __lmv_object_create(obd, fid, mea);
379         if (!obj) {
380                 CERROR("Can't create new object "DFID"\n",
381                        PFID(fid));
382                 GOTO(cleanup, obj = ERR_PTR(-ENOMEM));
383         }
384
385         if (md.mea != NULL)
386                 obd_free_memmd(exp, (void *)&md.mea);
387
388         EXIT;
389 cleanup:
390         if (req)
391                 ptlrpc_req_finished(req);
392         return obj;
393 }
394
395 int lmv_object_delete(struct obd_export *exp, const struct lu_fid *fid)
396 {
397         struct obd_device       *obd = exp->exp_obd;
398         struct lmv_object       *obj;
399         int                      rc = 0;
400         ENTRY;
401
402         cfs_spin_lock(&obj_list_lock);
403         obj = __lmv_object_find(obd, fid);
404         if (obj) {
405                 obj->lo_state |= O_FREEING;
406                 __lmv_object_put(obj);
407                 __lmv_object_put(obj);
408                 rc = 1;
409         }
410         cfs_spin_unlock(&obj_list_lock);
411         RETURN(rc);
412 }
413
414 int lmv_object_setup(struct obd_device *obd)
415 {
416         ENTRY;
417         LASSERT(obd != NULL);
418
419         CDEBUG(D_INFO, "LMV object manager setup (%s)\n",
420                obd->obd_uuid.uuid);
421
422         RETURN(0);
423 }
424
425 void lmv_object_cleanup(struct obd_device *obd)
426 {
427         cfs_list_t              *cur;
428         cfs_list_t              *tmp;
429         struct lmv_object       *obj;
430         ENTRY;
431
432         CDEBUG(D_INFO, "LMV object manager cleanup (%s)\n",
433                obd->obd_uuid.uuid);
434
435         cfs_spin_lock(&obj_list_lock);
436         cfs_list_for_each_safe(cur, tmp, &obj_list) {
437                 obj = cfs_list_entry(cur, struct lmv_object, lo_list);
438
439                 if (obj->lo_obd != obd)
440                         continue;
441
442                 obj->lo_state |= O_FREEING;
443                 if (cfs_atomic_read(&obj->lo_count) > 1) {
444                         CERROR("Object "DFID" has count (%d)\n", 
445                                PFID(&obj->lo_fid),
446                                cfs_atomic_read(&obj->lo_count));
447                 }
448                 __lmv_object_put(obj);
449         }
450         cfs_spin_unlock(&obj_list_lock);
451         EXIT;
452 }