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