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