Whamcloud - gitweb
- update from b1_4_mountconf
[fs/lustre-release.git] / lustre / lov / lov_qos.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Copyright (C) 2002, 2003 Cluster File Systems, Inc.
5  *
6  *   This file is part of the Lustre file system, http://www.lustre.org
7  *   Lustre is a trademark of Cluster File Systems, Inc.
8  *
9  *   You may have signed or agreed to another license before downloading
10  *   this software.  If so, you are bound by the terms and conditions
11  *   of that agreement, and the following does not apply to you.  See the
12  *   LICENSE file included with this distribution for more information.
13  *
14  *   If you did not agree to a different license, then this copy of Lustre
15  *   is open source software; you can redistribute it and/or modify it
16  *   under the terms of version 2 of the GNU General Public License as
17  *   published by the Free Software Foundation.
18  *
19  *   In either case, Lustre is distributed in the hope that it will be
20  *   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
21  *   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  *   license text for more details.
23  */
24
25 #ifndef EXPORT_SYMTAB
26 # define EXPORT_SYMTAB
27 #endif
28 #define DEBUG_SUBSYSTEM S_LOV
29
30 #ifdef __KERNEL__
31 #include <libcfs/libcfs.h>
32 #else
33 #include <liblustre.h>
34 #endif
35
36 #include <obd_class.h>
37 #include <obd_lov.h>
38
39 #include "lov_internal.h"
40
41 void qos_shrink_lsm(struct lov_request_set *set)
42 {
43         struct lov_stripe_md *lsm = set->set_md, *lsm_new;
44         /* XXX LOV STACKING call into osc for sizes */
45         unsigned oldsize, newsize;
46
47         if (set->set_oti && set->set_cookies && set->set_cookie_sent) {
48                 struct llog_cookie *cookies;
49                 oldsize = lsm->lsm_stripe_count * sizeof(*cookies);
50                 newsize = set->set_count * sizeof(*cookies);
51
52                 cookies = set->set_cookies;
53                 oti_alloc_cookies(set->set_oti, set->set_count);
54                 if (set->set_oti->oti_logcookies) {
55                         memcpy(set->set_oti->oti_logcookies, cookies, newsize);
56                         OBD_FREE(cookies, oldsize);
57                         set->set_cookies = set->set_oti->oti_logcookies;
58                 } else {
59                         CWARN("'leaking' %d bytes\n", oldsize - newsize);
60                 }
61         }
62
63         CWARN("using fewer stripes for object "LPX64": old %u new %u\n",
64               lsm->lsm_object_id, lsm->lsm_stripe_count, set->set_count);
65
66         oldsize = lov_stripe_md_size(lsm->lsm_stripe_count);
67         newsize = lov_stripe_md_size(set->set_count);
68         OBD_ALLOC(lsm_new, newsize);
69         if (lsm_new != NULL) {
70                 memcpy(lsm_new, lsm, newsize);
71                 lsm_new->lsm_stripe_count = set->set_count;
72                 OBD_FREE(lsm, oldsize);
73                 set->set_md = lsm_new;
74         } else {
75                 CWARN("'leaking' %d bytes\n", oldsize - newsize);
76         }
77 }
78
79 int qos_remedy_create(struct lov_request_set *set, struct lov_request *req)
80 {
81         struct lov_stripe_md *lsm = set->set_md;
82         struct lov_obd *lov = &set->set_exp->exp_obd->u.lov;
83         unsigned ost_idx, ost_count = lov->desc.ld_tgt_count;
84         int stripe, i, rc = -EIO;
85         ENTRY;
86
87         ost_idx = (req->rq_idx + lsm->lsm_stripe_count) % ost_count;
88         for (i = 0; i < ost_count; i++, ost_idx = (ost_idx + 1) % ost_count) {
89                 if (lov->tgts[ost_idx].active == 0) {
90                         CDEBUG(D_HA, "lov idx %d inactive\n", ost_idx);
91                         continue;
92                 }
93                 /* check if objects has been created on this ost */
94                 for (stripe = 0; stripe < lsm->lsm_stripe_count; stripe++) {
95                         if (stripe == req->rq_stripe)
96                                 continue;
97                         if (ost_idx == lsm->lsm_oinfo[stripe].loi_ost_idx)
98                                 break;
99                 }
100
101                 if (stripe >= lsm->lsm_stripe_count) {
102                         req->rq_idx = ost_idx;
103                         rc = obd_create(lov->tgts[ost_idx].ltd_exp, req->rq_oa, 
104                                         &req->rq_md, set->set_oti);
105                         if (!rc)
106                                 break;
107                 }
108         }
109         RETURN(rc);
110 }
111
112 #define LOV_CREATE_RESEED_MULT 4
113 #define LOV_CREATE_RESEED_MIN  1000
114 /* alloc objects on osts with round-robin algorithm */
115 static int alloc_rr(struct lov_obd *lov, int *idx_arr, int *stripe_cnt)
116 {
117         static int ost_start_count, ost_start_idx;
118         unsigned ost_idx, ost_count = lov->desc.ld_tgt_count;
119         unsigned ost_active_count = lov->desc.ld_active_tgt_count;
120         int i, *idx_pos = idx_arr;
121         ENTRY;
122         
123         if (--ost_start_count <= 0) {
124                 ost_start_idx = ll_rand();
125                 ost_start_count = 
126                         (LOV_CREATE_RESEED_MIN / max(ost_active_count, 1U) +
127                          LOV_CREATE_RESEED_MULT) * max(ost_active_count, 1U);
128         } else if (*stripe_cnt >= lov->desc.ld_active_tgt_count) {
129                 /* If we allocate from all of the stripes, make the
130                  * next file start on the next OST. */
131                 ++ost_start_idx;
132         }
133         ost_idx = ost_start_idx % ost_count;
134
135         for (i = 0; i < ost_count; i++, ost_idx = (ost_idx + 1) % ost_count) {
136                 ++ost_start_idx;
137                 
138                 if (lov->tgts[ost_idx].active == 0) {
139                         CDEBUG(D_HA, "lov idx %d inactive\n", ost_idx);
140                         continue;
141                 }
142                 
143                 *idx_pos = ost_idx;
144                 idx_pos++;
145                 /* got enough ost */
146                 if (idx_pos - idx_arr == *stripe_cnt)
147                         RETURN(0);
148         }
149         *stripe_cnt = idx_pos - idx_arr;
150         RETURN(0);
151 }
152
153 /* alloc objects on osts with specific stripe offset */
154 static int alloc_specific(struct lov_obd *lov, struct lov_stripe_md *lsm,
155                           int *idx_arr)
156 {
157         unsigned ost_idx, ost_count = lov->desc.ld_tgt_count;
158         int i, *idx_pos = idx_arr;
159         ENTRY;
160
161         ost_idx = lsm->lsm_oinfo[0].loi_ost_idx;
162         for (i = 0; i < ost_count; i++, ost_idx = (ost_idx + 1) % ost_count) {
163                 if (lov->tgts[ost_idx].active == 0) {
164                         CDEBUG(D_HA, "lov idx %d inactive\n", ost_idx);
165                         continue;
166                 }
167                 *idx_pos = ost_idx;
168                 idx_pos++;
169                 /* got enough ost */
170                 if (idx_pos - idx_arr == lsm->lsm_stripe_count)
171                         RETURN(0);
172         }
173         /* If we were passed specific striping params, then a failure to
174          * meet those requirements is an error, since we can't reallocate
175          * that memory (it might be part of a larger array or something).
176          *
177          * We can only get here if lsm_stripe_count was originally > 1.
178          */
179         CERROR("can't lstripe objid "LPX64": have %u want %u\n",
180                lsm->lsm_object_id, idx_pos - idx_arr, lsm->lsm_stripe_count);
181         RETURN(-EFBIG);
182 }
183
184 /* free space OST must have to be used for object allocation. */
185 #define QOS_MIN                 (lov->desc.ld_qos_threshold << 20)
186
187 #define TGT_BAVAIL(tgt)         (tgt->ltd_exp->exp_obd->obd_osfs.os_bavail * \
188                                  tgt->ltd_exp->exp_obd->obd_osfs.os_bsize) 
189 #define TGT_FFREE(tgt)          (tgt->ltd_exp->exp_obd->obd_osfs.os_ffree)
190
191 /* alloc objects on osts with free space weighted algorithm */
192 static int alloc_qos(struct obd_export *exp, int *idx_arr, int *stripe_cnt)
193 {
194         struct lov_obd *lov = &exp->exp_obd->u.lov;
195         unsigned ost_count = lov->desc.ld_tgt_count;
196         __u64 cur_bavail, rand, *availspace, total_bavail = 0;
197         int *indexes, nfound, good_osts, i, warn = 0, rc = 0;
198         struct lov_tgt_desc *tgt;
199         int shift, require_stripes = *stripe_cnt;
200         static time_t last_warn = 0;
201         time_t now = cfs_time_current_sec();
202         ENTRY;
203         
204         availspace = NULL;
205         indexes = NULL;
206         OBD_ALLOC(availspace, sizeof(__u64) * ost_count);
207         OBD_ALLOC(indexes, sizeof(int) * require_stripes);
208         if (!availspace || !indexes)
209                 GOTO(out_free, rc = -EAGAIN);
210         
211         mutex_down(&lov->lov_lock);
212  
213         /* if free space is below some threshold, just go
214          * to do round-robin allocation */
215         total_bavail = (exp->exp_obd->obd_osfs.os_bavail * \
216                         exp->exp_obd->obd_osfs.os_bsize);
217         if (ost_count < 2 || total_bavail <= QOS_MIN) {
218                 mutex_up(&lov->lov_lock);
219                 GOTO(out_free, rc = -EAGAIN);
220         }
221
222         /* if each ost has almost same free space, go to 
223          * do rr allocation for better creation performance */
224         if (!list_empty(&lov->qos_bavail_list)) {
225                 __u64 max, min, val;
226                 tgt = list_entry(lov->qos_bavail_list.next, 
227                                  struct lov_tgt_desc, qos_bavail_list);
228                 max = TGT_BAVAIL(tgt);
229                 tgt = list_entry(lov->qos_bavail_list.prev,
230                                  struct lov_tgt_desc, qos_bavail_list);
231                 min = TGT_BAVAIL(tgt);
232
233                 val = (max >= min) ? (max - min) : (min - max);
234                 min = (min * 13) >> 8;          /* less than 5% of gap */ 
235
236                 if (val < min) {
237                         mutex_up(&lov->lov_lock);
238                         GOTO(out_free, rc = -EAGAIN);
239                 }
240         } else {
241                 mutex_up(&lov->lov_lock);
242                 GOTO(out_free, rc = -EAGAIN);
243         }
244         
245         total_bavail = 0;
246         good_osts = 0;
247         /* warn zero available space/inode every 30 min */
248         if (cfs_time_sub(now, last_warn) > 60 * 30)
249                 warn = 1;
250         /* Find all the OSTs big enough to be stripe candidates */
251         list_for_each_entry(tgt, &lov->qos_bavail_list, qos_bavail_list) {
252                 if (!tgt->active)
253                         continue;
254                 if (!TGT_BAVAIL(tgt)) {
255                         if (warn) {
256                                 CWARN("no free space on %s\n", 
257                                       tgt->uuid.uuid);
258                                 last_warn = now;
259                         }
260                         continue;
261                 }
262                 if (!TGT_FFREE(tgt)) {
263                         if (warn) {
264                                 CWARN("no free inodes on %s\n", 
265                                       tgt->uuid.uuid);
266                                 last_warn = now;
267                         }
268                         continue;
269                 }
270                 /* We can stop if we have enough good osts and our osts
271                    are getting too small */ 
272                 if ((TGT_BAVAIL(tgt) <= QOS_MIN) && (good_osts >= *stripe_cnt))
273                         break;
274                 availspace[good_osts] = TGT_BAVAIL(tgt);
275                 indexes[good_osts] = tgt->index;
276                 total_bavail += availspace[good_osts];
277                 good_osts++;
278         }
279         
280         mutex_up(&lov->lov_lock);
281         
282         if (!total_bavail)
283                 GOTO(out_free, rc = -ENOSPC);
284        
285         /* if we don't have enough good OSTs, we reduce the stripe count. */
286         if (good_osts < *stripe_cnt)
287                 *stripe_cnt = good_osts;
288
289         if (!*stripe_cnt) 
290                 GOTO(out_free, rc = -EAGAIN);
291         
292         /* The point of all this shift and rand is to choose a 64-bit 
293            random number between 0 and total_bavail. Apparently '%' doesn't
294            work for 64bit numbers. */
295         nfound = shift = 0;
296         while ((total_bavail >> shift) > 0)
297                 shift++;
298         shift++;
299         /* Find enough OSTs with free space weighted random allocation */
300         while (nfound < *stripe_cnt) {
301                 cur_bavail = 0;
302
303                 /* If the total storage left is < 4GB, don't use random order, 
304                    store in biggest OST first. (Low storage situation.) 
305                    Otherwise, choose a 64bit random number... */
306                 rand = (shift < 32 ? 0ULL : (__u64)ll_rand() << 32) | ll_rand();
307                 /* ... mask everything above shift... */
308                 if (shift < 64)
309                         rand &= ((1ULL << shift) - 1);
310                 /* ... and this while should execute at most once... */
311                 while (rand > total_bavail)
312                         rand -= total_bavail;
313                 /* ... leaving us a 64bit number between 0 and total_bavail. */
314                 
315                 /* Try to fit in bigger OSTs first. On average, this will
316                    fill more toward the front of the OST array */
317                 for (i = 0; i < good_osts; i++) {
318                         cur_bavail += availspace[i];
319                         if (cur_bavail >= rand) {
320                                 total_bavail -= availspace[i];
321                                 availspace[i] = 0;
322                                 idx_arr[nfound] = indexes[i];
323                                 nfound++;
324                                 break;
325                         }
326                 }
327                 /* should never satisfy below condition */
328                 if (cur_bavail == 0)
329                         break;
330         }
331         LASSERT(nfound == *stripe_cnt);
332         
333 out_free:
334         if (availspace)
335                 OBD_FREE(availspace, sizeof(__u64) * ost_count);
336         if (indexes)
337                 OBD_FREE(indexes, sizeof(int) * require_stripes);
338         if (rc != -EAGAIN)
339                 /* rc == 0 or err */
340                 RETURN(rc);
341
342         rc = alloc_rr(lov, idx_arr, stripe_cnt);
343         RETURN(rc);
344 }
345
346 /* return new alloced stripe count on success */
347 static int alloc_idx_array(struct obd_export *exp, struct lov_stripe_md *lsm, 
348                            int newea, int **idx_arr, int *arr_cnt)
349 {
350         struct lov_obd *lov = &exp->exp_obd->u.lov;
351         int stripe_cnt = lsm->lsm_stripe_count;
352         int i, rc = 0;
353         int *tmp_arr = NULL;
354         ENTRY;
355
356         *arr_cnt = stripe_cnt;
357         OBD_ALLOC(tmp_arr, *arr_cnt * sizeof(int));
358         if (tmp_arr == NULL)
359                 RETURN(-ENOMEM);
360         for (i = 0; i < *arr_cnt; i++)
361                 tmp_arr[i] = -1;
362
363         if (newea || 
364             lsm->lsm_oinfo[0].loi_ost_idx >= lov->desc.ld_tgt_count) 
365                 rc = alloc_qos(exp, tmp_arr, &stripe_cnt);
366         else
367                 rc = alloc_specific(lov, lsm, tmp_arr);
368
369         if (rc)
370                 GOTO(out_arr, rc);
371
372         *idx_arr = tmp_arr;
373         RETURN(stripe_cnt);
374 out_arr:
375         OBD_FREE(tmp_arr, *arr_cnt * sizeof(int));
376         *arr_cnt = 0;
377         RETURN(rc);
378 }
379
380 static void free_idx_array(int *idx_arr, int arr_cnt)
381 {
382         if (arr_cnt)
383                 OBD_FREE(idx_arr, arr_cnt * sizeof(int));
384 }
385
386 int qos_prep_create(struct obd_export *exp, struct lov_request_set *set)
387 {
388         struct lov_obd *lov = &exp->exp_obd->u.lov;
389         struct lov_stripe_md *lsm;
390         struct obdo *src_oa = set->set_oa;
391         struct obd_trans_info *oti = set->set_oti;
392         int i, stripes, rc = 0, newea = 0;
393         int *idx_arr, idx_cnt = 0;
394         ENTRY;
395
396         LASSERT(src_oa->o_valid & OBD_MD_FLID);
397  
398         if (set->set_md == NULL) {
399                 int stripe_cnt = lov_get_stripecnt(lov, 0);
400
401                 /* If the MDS file was truncated up to some size, stripe over
402                  * enough OSTs to allow the file to be created at that size. 
403                  * This may mean we use more than the default # of stripes. */
404                 if (src_oa->o_valid & OBD_MD_FLSIZE) {
405                         struct lov_tgt_desc *tgt;
406                         
407                         /* Find the smallest number of stripes we can use 
408                            (up to # of active osts). */
409                         stripes = 1;
410                         mutex_down(&lov->lov_lock);
411                         list_for_each_entry(tgt, &lov->qos_bavail_list, 
412                                             qos_bavail_list) {
413                                 if (!tgt->active)
414                                         continue;
415                                 /* All earlier tgts have at least this many 
416                                    bytes available also, since our list is
417                                    sorted by size  */
418                                 if (TGT_BAVAIL(tgt) * stripes > src_oa->o_size)
419                                         break;
420                                 stripes++;
421                         }
422                         mutex_up(&lov->lov_lock);
423
424                         if (stripes < stripe_cnt)
425                                 stripes = stripe_cnt;
426                 } else {
427                         stripes = stripe_cnt;
428                 }
429
430                 rc = lov_alloc_memmd(&set->set_md, stripes, 
431                                      lov->desc.ld_pattern ?
432                                      lov->desc.ld_pattern : LOV_PATTERN_RAID0,
433                                      LOV_MAGIC);
434                 if (rc < 0)
435                         GOTO(out_err, rc);
436                 rc = 0;
437                 newea = 1;
438         }
439         lsm = set->set_md;
440        
441         lsm->lsm_object_id = src_oa->o_id;
442         if (!lsm->lsm_stripe_size)
443                 lsm->lsm_stripe_size = lov->desc.ld_default_stripe_size;
444         if (!lsm->lsm_pattern) {
445                 LASSERT(lov->desc.ld_pattern);
446                 lsm->lsm_pattern = lov->desc.ld_pattern;
447         }
448
449         stripes = alloc_idx_array(exp, lsm, newea, &idx_arr, &idx_cnt);
450         LASSERT(stripes <= lsm->lsm_stripe_count);
451         if (stripes <= 0)
452                 GOTO(out_err, rc = stripes ? stripes : -EIO);
453         
454         for (i = 0; i < stripes; i++) {
455                 struct lov_request *req;
456                 int ost_idx = idx_arr[i];
457                 LASSERT(ost_idx >= 0);
458                 
459                 OBD_ALLOC(req, sizeof(*req));
460                 if (req == NULL)
461                         GOTO(out_err, rc = -ENOMEM);
462                 lov_set_add_req(req, set);
463
464                 req->rq_buflen = sizeof(*req->rq_md);
465                 OBD_ALLOC(req->rq_md, req->rq_buflen);
466                 if (req->rq_md == NULL)
467                         GOTO(out_err, rc = -ENOMEM);
468                 
469                 req->rq_oa = obdo_alloc();
470                 if (req->rq_oa == NULL)
471                         GOTO(out_err, rc = -ENOMEM);
472                 
473                 req->rq_idx = ost_idx;
474                 req->rq_stripe = i;
475                 /* create data objects with "parent" OA */
476                 memcpy(req->rq_oa, src_oa, sizeof(*req->rq_oa));
477
478                 /* XXX When we start creating objects on demand, we need to
479                  *     make sure that we always create the object on the
480                  *     stripe which holds the existing file size.
481                  */
482                 if (src_oa->o_valid & OBD_MD_FLSIZE) {
483                         req->rq_oa->o_size = 
484                                 lov_size_to_stripe(lsm, src_oa->o_size, i);
485
486                         CDEBUG(D_INODE, "stripe %d has size "LPU64"/"LPU64"\n",
487                                i, req->rq_oa->o_size, src_oa->o_size);
488                 }
489
490         }
491         LASSERT(set->set_count == stripes);
492
493         if (stripes < lsm->lsm_stripe_count)
494                 qos_shrink_lsm(set);
495
496         if (oti && (src_oa->o_valid & OBD_MD_FLCOOKIE)) {
497                 oti_alloc_cookies(oti, set->set_count);
498                 if (!oti->oti_logcookies)
499                         GOTO(out_err, rc = -ENOMEM);
500                 set->set_cookies = oti->oti_logcookies;
501         }
502 out_err:
503         if (newea && rc)
504                 obd_free_memmd(exp, &set->set_md);
505         free_idx_array(idx_arr, idx_cnt);
506         EXIT;
507         return rc;
508 }
509
510 /* An caveat here is don't use list_move() on same list */
511 #define list_adjust(tgt, lov, list_name, value) \
512 { \
513         struct list_head *element; \
514         struct lov_tgt_desc *tmp;  \
515         if (list_empty(&(tgt)->list_name)) \
516                 list_add(&(tgt)->list_name, &(lov)->list_name); \
517         element = (tgt)->list_name.next; \
518         while((element != &(lov)->list_name) && \
519               (tmp = list_entry(element, struct lov_tgt_desc, list_name)) && \
520               (value(tgt) < value(tmp))) \
521                 element = element->next; \
522         if (element != (tgt)->list_name.next) { \
523                 list_del_init(&(tgt)->list_name); \
524                 list_add(&(tgt)->list_name, element->prev); \
525         } \
526         element = (tgt)->list_name.prev; \
527         while ((element != &(lov)->list_name) && \
528                (tmp = list_entry(element, struct lov_tgt_desc, list_name)) && \
529                (value(tgt) > value(tmp))) \
530                 element = element->prev; \
531         if (element != (tgt)->list_name.prev) { \
532                 list_del_init(&(tgt)->list_name); \
533                 list_add_tail(&(tgt)->list_name, element->prev); \
534         } \
535 }
536
537 void qos_update(struct lov_obd *lov, int idx, struct obd_statfs *osfs)
538 {
539         struct lov_tgt_desc *tgt = &lov->tgts[idx];
540         __u64 bavail;
541         ENTRY;
542         
543         bavail = osfs->os_bavail * osfs->os_bsize;
544         if (!bavail) 
545                 CWARN("ost %d has zero avail space!\n", idx);
546         
547         CDEBUG(D_OTHER, "QOS: bfree now "LPU64"\n", bavail);
548         
549         mutex_down(&lov->lov_lock);
550         list_adjust(tgt, lov, qos_bavail_list, TGT_BAVAIL);
551         mutex_up(&lov->lov_lock);
552 }
553