Whamcloud - gitweb
LU-17744 ldiskfs: mballoc stats fixes
[fs/lustre-release.git] / lustre / mdt / mdt_hsm_cdt_requests.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,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License version 2 for more details.  A copy is
14  * included in the COPYING file that accompanied this code.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  * GPL HEADER END
21  */
22 /*
23  * (C) Copyright 2012 Commissariat a l'energie atomique et aux energies
24  *     alternatives
25  *
26  * Copyright (c) 2014, 2017, Intel Corporation.
27  */
28 /*
29  * lustre/mdt/mdt_hsm_cdt_requests.c
30  *
31  * Lustre HSM Coordinator
32  *
33  * Author: Jacques-Charles Lafoucriere <jacques-charles.lafoucriere@cea.fr>
34  * Author: Aurelien Degremont <aurelien.degremont@cea.fr>
35  */
36
37 #define DEBUG_SUBSYSTEM S_MDS
38
39 #include <libcfs/libcfs.h>
40 #include <libcfs/libcfs_hash.h>
41 #include <obd_support.h>
42 #include <lprocfs_status.h>
43 #include <linux/interval_tree_generic.h>
44 #include "mdt_internal.h"
45
46 static unsigned int
47 cdt_request_cookie_hash(struct cfs_hash *hs, const void *key,
48                         const unsigned int bits)
49 {
50         return cfs_hash_djb2_hash(key, sizeof(u64), bits);
51 }
52
53 static void *cdt_request_cookie_object(struct hlist_node *hnode)
54 {
55         return hlist_entry(hnode, struct cdt_agent_req, car_cookie_hash);
56 }
57
58 static void *cdt_request_cookie_key(struct hlist_node *hnode)
59 {
60         struct cdt_agent_req *car = cdt_request_cookie_object(hnode);
61
62         return &car->car_hai->hai_cookie;
63 }
64
65 static int cdt_request_cookie_keycmp(const void *key, struct hlist_node *hnode)
66 {
67         const u64 *cookie2 = cdt_request_cookie_key(hnode);
68
69         return *(u64 *)key == *cookie2;
70 }
71
72 static void
73 cdt_request_cookie_get(struct cfs_hash *hs, struct hlist_node *hnode)
74 {
75         struct cdt_agent_req *car = cdt_request_cookie_object(hnode);
76
77         mdt_cdt_get_request(car);
78 }
79
80 static void
81 cdt_request_cookie_put(struct cfs_hash *hs, struct hlist_node *hnode)
82 {
83         struct cdt_agent_req *car = cdt_request_cookie_object(hnode);
84
85         mdt_cdt_put_request(car);
86 }
87
88 struct cfs_hash_ops cdt_request_cookie_hash_ops = {
89         .hs_hash        = cdt_request_cookie_hash,
90         .hs_key         = cdt_request_cookie_key,
91         .hs_keycmp      = cdt_request_cookie_keycmp,
92         .hs_object      = cdt_request_cookie_object,
93         .hs_get         = cdt_request_cookie_get,
94         .hs_put_locked  = cdt_request_cookie_put,
95 };
96
97 /**
98  * dump requests list
99  * \param cdt [IN] coordinator
100  */
101 void dump_requests(char *prefix, struct coordinator *cdt)
102 {
103         struct cdt_agent_req    *car;
104
105         down_read(&cdt->cdt_request_lock);
106         list_for_each_entry(car, &cdt->cdt_request_list, car_request_list) {
107                 CDEBUG(D_HSM, "%s fid="DFID" dfid="DFID
108                        " cookie=%#llx"
109                        " action=%s archive#=%d flags=%#llx"
110                        " extent=%#llx-%#llx"
111                        " gid=%#llx refcount=%d canceled=%d\n",
112                        prefix, PFID(&car->car_hai->hai_fid),
113                        PFID(&car->car_hai->hai_dfid),
114                        car->car_hai->hai_cookie,
115                        hsm_copytool_action2name(car->car_hai->hai_action),
116                        car->car_archive_id, car->car_flags,
117                        car->car_hai->hai_extent.offset,
118                        car->car_hai->hai_extent.length,
119                        car->car_hai->hai_gid,
120                        kref_read(&car->car_refcount),
121                        car->car_canceled);
122         }
123         up_read(&cdt->cdt_request_lock);
124 }
125
126 /* Interval tree to track reported progress.
127  * Intervals stored are non-overlapping and non-adjacent.
128  * When a new interval is added, all intervals that might overlap
129  * or be adjacent are first removed, with any extra length added to
130  * the new interval.
131  */
132 struct progress_node {
133         __u64           pn_offset;
134         __u64           pn_end;
135         __u64           pn_subtree_last;
136         struct rb_node  pn_rb;
137 };
138
139 #define START(node) ((node)->pn_offset)
140 #define LAST(node) ((node)->pn_end)
141
142 INTERVAL_TREE_DEFINE(struct progress_node, pn_rb, __u64, pn_subtree_last,
143                      START, LAST, static, progress)
144
145 #define progress_first(root) rb_entry_safe(interval_tree_first(root),   \
146                                            struct progress_node, pn_rb)
147
148 /*
149  * free the interval tree associated to a request
150  */
151 static void mdt_cdt_free_request_tree(struct cdt_req_progress *crp)
152 {
153         struct progress_node *node;
154         ENTRY;
155
156         while ((node = progress_first(&crp->crp_root)) != NULL) {
157                 progress_remove(node, &crp->crp_root);
158                 OBD_FREE_PTR(node);
159         }
160
161         EXIT;
162 }
163
164 /**
165  * update data moved information during a request
166  */
167 static int hsm_update_work(struct cdt_req_progress *crp,
168                            const struct hsm_extent *extent)
169 {
170         struct progress_node *node;
171         struct progress_node *overlap;
172         __u64 end;
173         __u64 total;
174         ENTRY;
175
176         end = extent->offset + extent->length - 1;
177         if (end < extent->offset)
178                 RETURN(-EINVAL);
179
180         OBD_ALLOC_PTR(node);
181         if (!node)
182                 RETURN(-ENOMEM);
183         node->pn_offset = extent->offset;
184         node->pn_end = end;
185
186         spin_lock(&crp->crp_lock);
187         total = crp->crp_total;
188         /* Search just before and just after the target interval
189          * to find intervals that would be adjacent.  Remove them
190          * too and add their extra length to 'node'.
191          */
192         while ((overlap = progress_iter_first(&crp->crp_root,
193                                               (node->pn_offset == 0 ?
194                                                0 : node->pn_offset - 1),
195                                               (node->pn_end == LUSTRE_EOF ?
196                                                LUSTRE_EOF : node->pn_end + 1)))
197                != NULL) {
198                 node->pn_offset = min(node->pn_offset, overlap->pn_offset);
199                 node->pn_end = max(node->pn_end, overlap->pn_end);
200                 progress_remove(overlap, &crp->crp_root);
201                 total -= overlap->pn_end - overlap->pn_offset + 1;
202                 OBD_FREE_PTR(overlap);
203         }
204         progress_insert(node, &crp->crp_root);
205         total += node->pn_end - node->pn_offset + 1;
206         crp->crp_total = total;
207         spin_unlock(&crp->crp_lock);
208         RETURN(0);
209 }
210
211 /**
212  * init the interval tree associated to a request
213  */
214 static void mdt_cdt_init_request_tree(struct cdt_req_progress *crp)
215 {
216         spin_lock_init(&crp->crp_lock);
217         crp->crp_root = INTERVAL_TREE_ROOT;
218         if (0)
219                 /* Silence a warning about unused function */
220                 progress_iter_next(NULL, 0, 0);
221 }
222
223 /** Allocate/init an agent request and its sub-structures.
224  *
225  * \param archive_id [IN]
226  * \param flags [IN]
227  * \param uuid [IN]
228  * \param hai [IN]
229  * \retval car [OUT] success valid structure
230  * \retval car [OUT]
231  */
232 struct cdt_agent_req *mdt_cdt_alloc_request(__u32 archive_id, __u64 flags,
233                                             struct obd_uuid *uuid,
234                                             struct hsm_action_item *hai)
235 {
236         struct cdt_agent_req *car;
237         ENTRY;
238
239         OBD_SLAB_ALLOC_PTR(car, mdt_hsm_car_kmem);
240         if (car == NULL)
241                 RETURN(ERR_PTR(-ENOMEM));
242
243         kref_init(&car->car_refcount);
244         car->car_archive_id = archive_id;
245         car->car_flags = flags;
246         car->car_canceled = 0;
247         car->car_req_start = ktime_get_real_seconds();
248         car->car_req_update = car->car_req_start;
249         car->car_uuid = *uuid;
250         OBD_ALLOC(car->car_hai, hai->hai_len);
251         if (car->car_hai == NULL) {
252                 OBD_SLAB_FREE_PTR(car, mdt_hsm_car_kmem);
253                 RETURN(ERR_PTR(-ENOMEM));
254         }
255         memcpy(car->car_hai, hai, hai->hai_len);
256         mdt_cdt_init_request_tree(&car->car_progress);
257
258         RETURN(car);
259 }
260
261 /**
262  * Free an agent request and its sub-structures.
263  *
264  * \param car [IN]  Request to be freed.
265  */
266 void mdt_cdt_free_request(struct cdt_agent_req *car)
267 {
268         mdt_cdt_free_request_tree(&car->car_progress);
269         OBD_FREE(car->car_hai, car->car_hai->hai_len);
270         OBD_SLAB_FREE_PTR(car, mdt_hsm_car_kmem);
271 }
272
273 /**
274  * inc refcount of a request
275  * \param car [IN] request
276  */
277 void mdt_cdt_get_request(struct cdt_agent_req *car)
278 {
279         kref_get(&car->car_refcount);
280 }
281
282 void mdt_cdt_put_request_free(struct kref *kref)
283 {
284         struct cdt_agent_req *car;
285
286         car = container_of(kref, struct cdt_agent_req, car_refcount);
287         mdt_cdt_free_request(car);
288 }
289
290 /**
291  * dec refcount of a request
292  * free if no more refcount
293  * \param car [IN] request
294  */
295 void mdt_cdt_put_request(struct cdt_agent_req *car)
296 {
297         kref_put(&car->car_refcount, mdt_cdt_put_request_free);
298 }
299
300 /**
301  * add a request to the list
302  * \param cdt [IN] coordinator
303  * \param car [IN] request
304  * \retval 0 success
305  * \retval -ve failure
306  */
307 int mdt_cdt_add_request(struct coordinator *cdt, struct cdt_agent_req *car)
308 {
309         int rc;
310         ENTRY;
311
312         /* cancel requests are not kept in memory */
313         LASSERT(car->car_hai->hai_action != HSMA_CANCEL);
314
315         down_write(&cdt->cdt_request_lock);
316
317         rc = cfs_hash_add_unique(cdt->cdt_request_cookie_hash,
318                                  &car->car_hai->hai_cookie,
319                                  &car->car_cookie_hash);
320         if (rc < 0) {
321                 up_write(&cdt->cdt_request_lock);
322                 RETURN(-EEXIST);
323         }
324
325         list_add_tail(&car->car_request_list, &cdt->cdt_request_list);
326
327         up_write(&cdt->cdt_request_lock);
328
329         mdt_hsm_agent_update_statistics(cdt, 0, 0, 1, &car->car_uuid);
330
331         switch (car->car_hai->hai_action) {
332         case HSMA_ARCHIVE:
333                 atomic_inc(&cdt->cdt_archive_count);
334                 break;
335         case HSMA_RESTORE:
336                 atomic_inc(&cdt->cdt_restore_count);
337                 break;
338         case HSMA_REMOVE:
339                 atomic_inc(&cdt->cdt_remove_count);
340                 break;
341         }
342         atomic_inc(&cdt->cdt_request_count);
343
344         RETURN(0);
345 }
346
347 /**
348  * find request in the list by cookie or by fid
349  * \param cdt [IN] coordinator
350  * \param cookie [IN] request cookie
351  * \param fid [IN] fid
352  * \retval request pointer or NULL if not found
353  */
354 struct cdt_agent_req *mdt_cdt_find_request(struct coordinator *cdt, u64 cookie)
355 {
356         struct cdt_agent_req    *car;
357         ENTRY;
358
359         down_read(&cdt->cdt_request_lock);
360         car = cfs_hash_lookup(cdt->cdt_request_cookie_hash, &cookie);
361         up_read(&cdt->cdt_request_lock);
362
363         RETURN(car);
364 }
365
366 /**
367  * remove request from the list
368  * \param cdt [IN] coordinator
369  * \param cookie [IN] request cookie
370  * \retval request pointer
371  */
372 int mdt_cdt_remove_request(struct coordinator *cdt, __u64 cookie)
373 {
374         struct cdt_agent_req *car;
375         ENTRY;
376
377         down_write(&cdt->cdt_request_lock);
378         car = cfs_hash_del_key(cdt->cdt_request_cookie_hash, &cookie);
379         if (car == NULL) {
380                 up_write(&cdt->cdt_request_lock);
381                 RETURN(-ENOENT);
382         }
383
384         list_del(&car->car_request_list);
385         up_write(&cdt->cdt_request_lock);
386
387         switch (car->car_hai->hai_action) {
388         case HSMA_ARCHIVE:
389                 atomic_dec(&cdt->cdt_archive_count);
390                 break;
391         case HSMA_RESTORE:
392                 atomic_dec(&cdt->cdt_restore_count);
393                 break;
394         case HSMA_REMOVE:
395                 atomic_dec(&cdt->cdt_remove_count);
396                 break;
397         }
398
399         /* Drop reference from cdt_request_list. */
400         mdt_cdt_put_request(car);
401
402         LASSERT(atomic_read(&cdt->cdt_request_count) >= 1);
403         if (atomic_dec_and_test(&cdt->cdt_request_count)) {
404                 /* request count is empty, nudge coordinator for more work */
405                 cdt->cdt_wakeup_coordinator = true;
406                 wake_up_interruptible(&cdt->cdt_waitq);
407         }
408
409         RETURN(0);
410 }
411
412 /**
413  * update a request in the list
414  * on success, add a ref to the request returned
415  * \param cdt [IN] coordinator
416  * \param pgs [IN] progression (cookie + extent + err)
417  * \retval request pointer
418  * \retval -ve failure
419  */
420 struct cdt_agent_req *mdt_cdt_update_request(struct coordinator *cdt,
421                                           const struct hsm_progress_kernel *pgs)
422 {
423         struct cdt_agent_req    *car;
424         int                      rc;
425         ENTRY;
426
427         car = mdt_cdt_find_request(cdt, pgs->hpk_cookie);
428         if (car == NULL)
429                 RETURN(ERR_PTR(-ENOENT));
430
431         car->car_req_update = ktime_get_real_seconds();
432
433         /* update data move progress done by copy tool */
434         if (car->car_hai->hai_action != HSMA_REMOVE && pgs->hpk_errval == 0 &&
435             pgs->hpk_extent.length != 0) {
436                 rc = hsm_update_work(&car->car_progress, &pgs->hpk_extent);
437                 if (rc) {
438                         mdt_cdt_put_request(car);
439                         RETURN(ERR_PTR(rc));
440                 }
441         }
442
443         if (pgs->hpk_flags & HP_FLAG_COMPLETED) {
444                 if (pgs->hpk_errval != 0)
445                         mdt_hsm_agent_update_statistics(cdt, 0, 1, 0,
446                                                         &car->car_uuid);
447                 else
448                         mdt_hsm_agent_update_statistics(cdt, 1, 0, 0,
449                                                         &car->car_uuid);
450         }
451         RETURN(car);
452 }
453
454 /**
455  * seq_file method called to start access to /proc file
456  */
457 static void *mdt_hsm_active_requests_proc_start(struct seq_file *s, loff_t *p)
458 {
459         struct mdt_device       *mdt = s->private;
460         struct coordinator      *cdt = &mdt->mdt_coordinator;
461         struct list_head        *pos;
462         loff_t                   i;
463         ENTRY;
464
465         down_read(&cdt->cdt_request_lock);
466
467         if (list_empty(&cdt->cdt_request_list))
468                 RETURN(NULL);
469
470         if (*p == 0)
471                 RETURN(SEQ_START_TOKEN);
472
473         i = 0;
474         list_for_each(pos, &cdt->cdt_request_list) {
475                 i++;
476                 if (i >= *p)
477                         RETURN(pos);
478         }
479         RETURN(NULL);
480 }
481
482 /**
483  * seq_file method called to get next item
484  * just returns NULL at eof
485  */
486 static void *mdt_hsm_active_requests_proc_next(struct seq_file *s, void *v,
487                                                loff_t *p)
488 {
489         struct mdt_device       *mdt = s->private;
490         struct coordinator      *cdt = &mdt->mdt_coordinator;
491         struct list_head        *pos = v;
492         ENTRY;
493
494         if (pos == SEQ_START_TOKEN)
495                 pos = cdt->cdt_request_list.next;
496         else
497                 pos = pos->next;
498
499         (*p)++;
500         if (pos != &cdt->cdt_request_list)
501                 RETURN(pos);
502         else
503                 RETURN(NULL);
504 }
505
506 /**
507  * display request data
508  */
509 static int mdt_hsm_active_requests_proc_show(struct seq_file *s, void *v)
510 {
511         struct list_head        *pos = v;
512         struct cdt_agent_req    *car;
513         char                     buf[12];
514         ENTRY;
515
516         if (pos == SEQ_START_TOKEN)
517                 RETURN(0);
518
519         car = list_entry(pos, struct cdt_agent_req, car_request_list);
520
521         seq_printf(s, "fid="DFID" dfid="DFID
522                    " compound/cookie=%#llx/%#llx"
523                    " action=%s archive#=%d flags=%#llx"
524                    " extent=%#llx-%#llx gid=%#llx"
525                    " data=[%s] canceled=%d uuid=%s done=%llu\n",
526                    PFID(&car->car_hai->hai_fid),
527                    PFID(&car->car_hai->hai_dfid),
528                    0ULL /* compound_id */, car->car_hai->hai_cookie,
529                    hsm_copytool_action2name(car->car_hai->hai_action),
530                    car->car_archive_id, car->car_flags,
531                    car->car_hai->hai_extent.offset,
532                    car->car_hai->hai_extent.length,
533                    car->car_hai->hai_gid,
534                    hai_dump_data_field(car->car_hai, buf, sizeof(buf)),
535                    car->car_canceled, obd_uuid2str(&car->car_uuid),
536                    car->car_progress.crp_total);
537         RETURN(0);
538 }
539
540 /**
541  * seq_file method called to stop access to /proc file
542  */
543 static void mdt_hsm_active_requests_proc_stop(struct seq_file *s, void *v)
544 {
545         struct mdt_device       *mdt = s->private;
546         struct coordinator      *cdt = &mdt->mdt_coordinator;
547         ENTRY;
548
549         up_read(&cdt->cdt_request_lock);
550
551         EXIT;
552 }
553
554 /* hsm agent list proc functions */
555 static const struct seq_operations mdt_hsm_active_requests_proc_ops = {
556         .start          = mdt_hsm_active_requests_proc_start,
557         .next           = mdt_hsm_active_requests_proc_next,
558         .show           = mdt_hsm_active_requests_proc_show,
559         .stop           = mdt_hsm_active_requests_proc_stop,
560 };
561
562 /**
563  * public function called at open of /proc file to get
564  * list of agents
565  */
566 static int ldebugfs_open_hsm_active_requests(struct inode *inode,
567                                              struct file *file)
568 {
569         struct seq_file *s;
570         int              rc;
571         ENTRY;
572
573         rc = seq_open(file, &mdt_hsm_active_requests_proc_ops);
574         if (rc) {
575                 RETURN(rc);
576         }
577         s = file->private_data;
578         s->private = inode->i_private;
579
580         RETURN(rc);
581 }
582
583 /* methods to access hsm request list */
584 const struct file_operations mdt_hsm_active_requests_fops = {
585         .owner          = THIS_MODULE,
586         .open           = ldebugfs_open_hsm_active_requests,
587         .read           = seq_read,
588         .llseek         = seq_lseek,
589         .release        = seq_release,
590 };
591