Whamcloud - gitweb
LU-6245 server: remove types abstraction from MDS/MGS code
[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, 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 <obd_support.h>
40 #include <lustre/lustre_user.h>
41 #include <lprocfs_status.h>
42 #include "mdt_internal.h"
43
44 /**
45  * dump requests list
46  * \param cdt [IN] coordinator
47  */
48 void dump_requests(char *prefix, struct coordinator *cdt)
49 {
50         struct cdt_agent_req    *car;
51
52         down_read(&cdt->cdt_request_lock);
53         list_for_each_entry(car, &cdt->cdt_requests, car_request_list) {
54                 CDEBUG(D_HSM, "%s fid="DFID" dfid="DFID
55                        " compound/cookie=%#llx/%#llx"
56                        " action=%s archive#=%d flags=%#llx"
57                        " extent=%#llx-%#llx"
58                        " gid=%#llx refcount=%d canceled=%d\n",
59                        prefix, PFID(&car->car_hai->hai_fid),
60                        PFID(&car->car_hai->hai_dfid),
61                        car->car_compound_id, car->car_hai->hai_cookie,
62                        hsm_copytool_action2name(car->car_hai->hai_action),
63                        car->car_archive_id, car->car_flags,
64                        car->car_hai->hai_extent.offset,
65                        car->car_hai->hai_extent.length,
66                        car->car_hai->hai_gid,
67                        atomic_read(&car->car_refcount),
68                        car->car_canceled);
69         }
70         up_read(&cdt->cdt_request_lock);
71 }
72
73 struct req_interval_data {
74         struct cdt_req_progress *crp;
75         __u64                    done_sz;
76 };
77
78 /**
79  * interval tree cb, used to go through all the tree of extent done
80  */
81 static enum interval_iter req_interval_cb(struct interval_node *node,
82                                           void *args)
83 {
84         struct req_interval_data        *data;
85         ENTRY;
86
87         data = args;
88         data->done_sz += node->in_extent.end - node->in_extent.start;
89         RETURN(INTERVAL_ITER_CONT);
90 }
91
92 /**
93  * scan the interval tree associated to a request
94  * to compute the amount of work done
95  * \param car [IN] request
96  * \param done_sz [OUT] will be set to the size of work done
97  */
98 void mdt_cdt_get_work_done(struct cdt_agent_req *car, __u64 *done_sz)
99 {
100         struct req_interval_data         rid;
101         struct cdt_req_progress         *crp = &car->car_progress;
102
103         mutex_lock(&crp->crp_lock);
104
105         rid.crp = crp;
106         rid.done_sz = 0;
107         interval_iterate(crp->crp_root, req_interval_cb, &rid);
108         *done_sz = rid.done_sz;
109
110         mutex_unlock(&crp->crp_lock);
111 }
112
113 #define NODE_VECTOR_SZ 256
114 /**
115  * free the interval tree associated to a request
116  */
117 static void mdt_cdt_free_request_tree(struct cdt_req_progress *crp)
118 {
119         struct interval_node    *node, *vn;
120         int                      i;
121         ENTRY;
122
123         mutex_lock(&crp->crp_lock);
124
125         if (crp->crp_max == 0)
126                 goto out;
127
128         /* remove all nodes from tree */
129         for (i = 0 ; i < crp->crp_cnt ; i++) {
130                 vn = crp->crp_node[i / NODE_VECTOR_SZ];
131                 node = &vn[i % NODE_VECTOR_SZ];
132                 interval_erase(node, &crp->crp_root);
133         }
134         /* free all sub vectors */
135         for (i = 0 ; i <= crp->crp_max / NODE_VECTOR_SZ ; i++)
136                 OBD_FREE(crp->crp_node[i],
137                          NODE_VECTOR_SZ * sizeof(crp->crp_node[i][0]));
138
139         /* free main vector */
140         OBD_FREE(crp->crp_node,
141                  sizeof(crp->crp_node[0]) *
142                   (crp->crp_max / NODE_VECTOR_SZ + 1));
143
144         crp->crp_cnt = 0;
145         crp->crp_max = 0;
146 out:
147         mutex_unlock(&crp->crp_lock);
148         EXIT;
149 }
150
151 /**
152  * update data moved information during a request
153  */
154 static int hsm_update_work(struct cdt_req_progress *crp,
155                            const struct hsm_extent *extent)
156 {
157         int                       rc, osz, nsz;
158         struct interval_node    **new_vv;
159         struct interval_node     *v, *node;
160         __u64                     end;
161         ENTRY;
162
163         end = extent->offset + extent->length;
164         if (end <= extent->offset)
165                 RETURN(-EINVAL);
166
167         mutex_lock(&crp->crp_lock);
168         /* new node index */
169
170         if (crp->crp_cnt >= crp->crp_max) {
171                 /* no more room */
172                 /* allocate a new vector */
173                 OBD_ALLOC(v, NODE_VECTOR_SZ * sizeof(v[0]));
174                 if (v == NULL)
175                         GOTO(out, rc = -ENOMEM);
176
177                 if (crp->crp_max == 0)
178                         osz = 0;
179                 else
180                         osz = sizeof(new_vv[0]) *
181                               (crp->crp_max / NODE_VECTOR_SZ + 1);
182
183                 nsz = osz + sizeof(new_vv[0]);
184                 /* increase main vector size */
185                 OBD_ALLOC(new_vv, nsz);
186                 if (new_vv == NULL) {
187                         OBD_FREE(v, NODE_VECTOR_SZ * sizeof(v[0]));
188                         GOTO(out, rc = -ENOMEM);
189                 }
190
191                 if (osz == 0) {
192                         crp->crp_max = NODE_VECTOR_SZ - 1;
193                 } else {
194                         memcpy(new_vv, crp->crp_node, osz);
195                         OBD_FREE(crp->crp_node, osz);
196                         crp->crp_max += NODE_VECTOR_SZ;
197                 }
198
199                 crp->crp_node = new_vv;
200                 crp->crp_node[crp->crp_max / NODE_VECTOR_SZ] = v;
201         }
202
203         v = crp->crp_node[crp->crp_cnt / NODE_VECTOR_SZ];
204         node = &v[crp->crp_cnt % NODE_VECTOR_SZ];
205         interval_set(node, extent->offset, end);
206         /* try to insert, if entry already exist ignore the new one
207          * it can happen if ct sends 2 times the same progress */
208         if (interval_insert(node, &crp->crp_root) == NULL)
209                 crp->crp_cnt++;
210
211         rc = 0;
212 out:
213         mutex_unlock(&crp->crp_lock);
214         RETURN(rc);
215 }
216
217 /**
218  * init the interval tree associated to a request
219  */
220 static void mdt_cdt_init_request_tree(struct cdt_req_progress *crp)
221 {
222         mutex_init(&crp->crp_lock);
223         crp->crp_root = NULL;
224         crp->crp_cnt = 0;
225         crp->crp_max = 0;
226 }
227
228 /** Allocate/init an agent request and its sub-structures.
229  *
230  * \param compound_id [IN]
231  * \param archive_id [IN]
232  * \param flags [IN]
233  * \param uuid [IN]
234  * \param hai [IN]
235  * \retval car [OUT] success valid structure
236  * \retval car [OUT]
237  */
238 struct cdt_agent_req *mdt_cdt_alloc_request(__u64 compound_id, __u32 archive_id,
239                                             __u64 flags, struct obd_uuid *uuid,
240                                             struct hsm_action_item *hai)
241 {
242         struct cdt_agent_req *car;
243         ENTRY;
244
245         OBD_SLAB_ALLOC_PTR(car, mdt_hsm_car_kmem);
246         if (car == NULL)
247                 RETURN(ERR_PTR(-ENOMEM));
248
249         atomic_set(&car->car_refcount, 1);
250         car->car_compound_id = compound_id;
251         car->car_archive_id = archive_id;
252         car->car_flags = flags;
253         car->car_canceled = 0;
254         car->car_req_start = cfs_time_current_sec();
255         car->car_req_update = car->car_req_start;
256         car->car_uuid = *uuid;
257         OBD_ALLOC(car->car_hai, hai->hai_len);
258         if (car->car_hai == NULL) {
259                 OBD_SLAB_FREE_PTR(car, mdt_hsm_car_kmem);
260                 RETURN(ERR_PTR(-ENOMEM));
261         }
262         memcpy(car->car_hai, hai, hai->hai_len);
263         mdt_cdt_init_request_tree(&car->car_progress);
264
265         RETURN(car);
266 }
267
268 /**
269  * Free an agent request and its sub-structures.
270  *
271  * \param car [IN]  Request to be freed.
272  */
273 void mdt_cdt_free_request(struct cdt_agent_req *car)
274 {
275         mdt_cdt_free_request_tree(&car->car_progress);
276         OBD_FREE(car->car_hai, car->car_hai->hai_len);
277         OBD_SLAB_FREE_PTR(car, mdt_hsm_car_kmem);
278 }
279
280 /**
281  * inc refcount of a request
282  * \param car [IN] request
283  */
284 void mdt_cdt_get_request(struct cdt_agent_req *car)
285 {
286         atomic_inc(&car->car_refcount);
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         LASSERT(atomic_read(&car->car_refcount) > 0);
297         if (atomic_dec_and_test(&car->car_refcount))
298                 mdt_cdt_free_request(car);
299 }
300
301 /**
302  * find request in the list by cookie or by fid
303  * lock cdt_request_lock needs to be held by caller
304  * \param cdt [IN] coordinator
305  * \param cookie [IN] request cookie
306  * \param fid [IN] fid
307  * \retval request pointer or NULL if not found
308  */
309 static struct cdt_agent_req *cdt_find_request_nolock(struct coordinator *cdt,
310                                                      __u64 cookie,
311                                                      const struct lu_fid *fid)
312 {
313         struct cdt_agent_req *car;
314         struct cdt_agent_req *found = NULL;
315         ENTRY;
316
317         list_for_each_entry(car, &cdt->cdt_requests, car_request_list) {
318                 if (car->car_hai->hai_cookie == cookie ||
319                     (fid != NULL && lu_fid_eq(fid, &car->car_hai->hai_fid))) {
320                         mdt_cdt_get_request(car);
321                         found = car;
322                         break;
323                 }
324         }
325
326         RETURN(found);
327 }
328
329 /**
330  * add a request to the list
331  * \param cdt [IN] coordinator
332  * \param car [IN] request
333  * \retval 0 success
334  * \retval -ve failure
335  */
336 int mdt_cdt_add_request(struct coordinator *cdt, struct cdt_agent_req *new_car)
337 {
338         struct cdt_agent_req    *car;
339         ENTRY;
340
341         /* cancel requests are not kept in memory */
342         LASSERT(new_car->car_hai->hai_action != HSMA_CANCEL);
343
344         down_write(&cdt->cdt_request_lock);
345         car = cdt_find_request_nolock(cdt, new_car->car_hai->hai_cookie, NULL);
346         if (car != NULL) {
347                 mdt_cdt_put_request(car);
348                 up_write(&cdt->cdt_request_lock);
349                 RETURN(-EEXIST);
350         }
351
352         list_add_tail(&new_car->car_request_list, &cdt->cdt_requests);
353         up_write(&cdt->cdt_request_lock);
354
355         mdt_hsm_agent_update_statistics(cdt, 0, 0, 1, &new_car->car_uuid);
356
357         atomic_inc(&cdt->cdt_request_count);
358
359         RETURN(0);
360 }
361
362 /**
363  * find request in the list by cookie or by fid
364  * \param cdt [IN] coordinator
365  * \param cookie [IN] request cookie
366  * \param fid [IN] fid
367  * \retval request pointer or NULL if not found
368  */
369 struct cdt_agent_req *mdt_cdt_find_request(struct coordinator *cdt,
370                                            const __u64 cookie,
371                                            const struct lu_fid *fid)
372 {
373         struct cdt_agent_req    *car;
374         ENTRY;
375
376         down_read(&cdt->cdt_request_lock);
377         car = cdt_find_request_nolock(cdt, cookie, fid);
378         up_read(&cdt->cdt_request_lock);
379
380         RETURN(car);
381 }
382
383 /**
384  * remove request from the list
385  * \param cdt [IN] coordinator
386  * \param cookie [IN] request cookie
387  * \retval request pointer
388  */
389 int mdt_cdt_remove_request(struct coordinator *cdt, __u64 cookie)
390 {
391         struct cdt_agent_req *car;
392         ENTRY;
393
394         down_write(&cdt->cdt_request_lock);
395         car = cdt_find_request_nolock(cdt, cookie, NULL);
396         if (car != NULL) {
397                 list_del(&car->car_request_list);
398                 up_write(&cdt->cdt_request_lock);
399
400                 /* reference from cdt_requests list */
401                 mdt_cdt_put_request(car);
402
403                 /* reference from cdt_find_request_nolock() */
404                 mdt_cdt_put_request(car);
405
406                 LASSERT(atomic_read(&cdt->cdt_request_count) >= 1);
407                 atomic_dec(&cdt->cdt_request_count);
408
409                 RETURN(0);
410         }
411         up_write(&cdt->cdt_request_lock);
412
413         RETURN(-ENOENT);
414 }
415
416 /**
417  * update a request in the list
418  * on success, add a ref to the request returned
419  * \param cdt [IN] coordinator
420  * \param pgs [IN] progression (cookie + extent + err)
421  * \retval request pointer
422  * \retval -ve failure
423  */
424 struct cdt_agent_req *mdt_cdt_update_request(struct coordinator *cdt,
425                                           const struct hsm_progress_kernel *pgs)
426 {
427         struct cdt_agent_req    *car;
428         int                      rc;
429         ENTRY;
430
431         car = mdt_cdt_find_request(cdt, pgs->hpk_cookie, NULL);
432         if (car == NULL)
433                 RETURN(ERR_PTR(-ENOENT));
434
435         car->car_req_update = cfs_time_current_sec();
436
437         /* update progress done by copy tool */
438         if (pgs->hpk_errval == 0 && pgs->hpk_extent.length != 0) {
439                 rc = hsm_update_work(&car->car_progress, &pgs->hpk_extent);
440                 if (rc) {
441                         mdt_cdt_put_request(car);
442                         RETURN(ERR_PTR(rc));
443                 }
444         }
445
446         if (pgs->hpk_flags & HP_FLAG_COMPLETED) {
447                 if (pgs->hpk_errval != 0)
448                         mdt_hsm_agent_update_statistics(cdt, 0, 1, 0,
449                                                         &car->car_uuid);
450                 else
451                         mdt_hsm_agent_update_statistics(cdt, 1, 0, 0,
452                                                         &car->car_uuid);
453         }
454         RETURN(car);
455 }
456
457 /**
458  * seq_file method called to start access to /proc file
459  */
460 static void *mdt_hsm_active_requests_proc_start(struct seq_file *s, loff_t *p)
461 {
462         struct mdt_device       *mdt = s->private;
463         struct coordinator      *cdt = &mdt->mdt_coordinator;
464         struct list_head        *pos;
465         loff_t                   i;
466         ENTRY;
467
468         down_read(&cdt->cdt_request_lock);
469
470         if (list_empty(&cdt->cdt_requests))
471                 RETURN(NULL);
472
473         if (*p == 0)
474                 RETURN(SEQ_START_TOKEN);
475
476         i = 0;
477         list_for_each(pos, &cdt->cdt_requests) {
478                 i++;
479                 if (i >= *p)
480                         RETURN(pos);
481         }
482         RETURN(NULL);
483 }
484
485 /**
486  * seq_file method called to get next item
487  * just returns NULL at eof
488  */
489 static void *mdt_hsm_active_requests_proc_next(struct seq_file *s, void *v,
490                                                loff_t *p)
491 {
492         struct mdt_device       *mdt = s->private;
493         struct coordinator      *cdt = &mdt->mdt_coordinator;
494         struct list_head        *pos = v;
495         ENTRY;
496
497         if (pos == SEQ_START_TOKEN)
498                 pos = cdt->cdt_requests.next;
499         else
500                 pos = pos->next;
501
502         (*p)++;
503         if (pos != &cdt->cdt_requests)
504                 RETURN(pos);
505         else
506                 RETURN(NULL);
507 }
508
509 /**
510  * display request data
511  */
512 static int mdt_hsm_active_requests_proc_show(struct seq_file *s, void *v)
513 {
514         struct list_head        *pos = v;
515         struct cdt_agent_req    *car;
516         char                     buf[12];
517         __u64                    data_moved;
518         ENTRY;
519
520         if (pos == SEQ_START_TOKEN)
521                 RETURN(0);
522
523         car = list_entry(pos, struct cdt_agent_req, car_request_list);
524         mdt_cdt_get_work_done(car, &data_moved);
525
526         seq_printf(s, "fid="DFID" dfid="DFID
527                    " compound/cookie=%#llx/%#llx"
528                    " action=%s archive#=%d flags=%#llx"
529                    " extent=%#llx-%#llx gid=%#llx"
530                    " data=[%s] canceled=%d uuid=%s done=%llu\n",
531                    PFID(&car->car_hai->hai_fid),
532                    PFID(&car->car_hai->hai_dfid),
533                    car->car_compound_id, car->car_hai->hai_cookie,
534                    hsm_copytool_action2name(car->car_hai->hai_action),
535                    car->car_archive_id, car->car_flags,
536                    car->car_hai->hai_extent.offset,
537                    car->car_hai->hai_extent.length,
538                    car->car_hai->hai_gid,
539                    hai_dump_data_field(car->car_hai, buf, sizeof(buf)),
540                    car->car_canceled, obd_uuid2str(&car->car_uuid),
541                    data_moved);
542         RETURN(0);
543 }
544
545 /**
546  * seq_file method called to stop access to /proc file
547  */
548 static void mdt_hsm_active_requests_proc_stop(struct seq_file *s, void *v)
549 {
550         struct mdt_device       *mdt = s->private;
551         struct coordinator      *cdt = &mdt->mdt_coordinator;
552         ENTRY;
553
554         up_read(&cdt->cdt_request_lock);
555
556         EXIT;
557 }
558
559 /* hsm agent list proc functions */
560 static const struct seq_operations mdt_hsm_active_requests_proc_ops = {
561         .start          = mdt_hsm_active_requests_proc_start,
562         .next           = mdt_hsm_active_requests_proc_next,
563         .show           = mdt_hsm_active_requests_proc_show,
564         .stop           = mdt_hsm_active_requests_proc_stop,
565 };
566
567 /**
568  * public function called at open of /proc file to get
569  * list of agents
570  */
571 static int lprocfs_open_hsm_active_requests(struct inode *inode,
572                                             struct file *file)
573 {
574         struct seq_file *s;
575         int              rc;
576         ENTRY;
577
578         rc = seq_open(file, &mdt_hsm_active_requests_proc_ops);
579         if (rc) {
580                 RETURN(rc);
581         }
582         s = file->private_data;
583         s->private = PDE_DATA(inode);
584
585         RETURN(rc);
586 }
587
588 /* methods to access hsm request list */
589 const struct file_operations mdt_hsm_active_requests_fops = {
590         .owner          = THIS_MODULE,
591         .open           = lprocfs_open_hsm_active_requests,
592         .read           = seq_read,
593         .llseek         = seq_lseek,
594         .release        = lprocfs_seq_release,
595 };
596