4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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.
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
23 * (C) Copyright 2012 Commissariat a l'energie atomique et aux energies
26 * Copyright (c) 2014, Intel Corporation.
29 * lustre/mdt/mdt_hsm_cdt_requests.c
31 * Lustre HSM Coordinator
33 * Author: Jacques-Charles Lafoucriere <jacques-charles.lafoucriere@cea.fr>
34 * Author: Aurelien Degremont <aurelien.degremont@cea.fr>
37 #define DEBUG_SUBSYSTEM S_MDS
39 #include <obd_support.h>
40 #include <lustre/lustre_user.h>
41 #include <lprocfs_status.h>
42 #include "mdt_internal.h"
46 * \param cdt [IN] coordinator
48 void dump_requests(char *prefix, struct coordinator *cdt)
50 struct cdt_agent_req *car;
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"
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),
70 up_read(&cdt->cdt_request_lock);
73 struct req_interval_data {
74 struct cdt_req_progress *crp;
79 * interval tree cb, used to go through all the tree of extent done
81 static enum interval_iter req_interval_cb(struct interval_node *node,
84 struct req_interval_data *data;
88 data->done_sz += node->in_extent.end - node->in_extent.start;
89 RETURN(INTERVAL_ITER_CONT);
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
98 void mdt_cdt_get_work_done(struct cdt_agent_req *car, __u64 *done_sz)
100 struct req_interval_data rid;
101 struct cdt_req_progress *crp = &car->car_progress;
103 mutex_lock(&crp->crp_lock);
107 interval_iterate(crp->crp_root, req_interval_cb, &rid);
108 *done_sz = rid.done_sz;
110 mutex_unlock(&crp->crp_lock);
113 #define NODE_VECTOR_SZ 256
115 * free the interval tree associated to a request
117 static void mdt_cdt_free_request_tree(struct cdt_req_progress *crp)
119 struct interval_node *node, *vn;
123 mutex_lock(&crp->crp_lock);
125 if (crp->crp_max == 0)
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);
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]));
139 /* free main vector */
140 OBD_FREE(crp->crp_node,
141 sizeof(crp->crp_node[0]) *
142 (crp->crp_max / NODE_VECTOR_SZ + 1));
147 mutex_unlock(&crp->crp_lock);
152 * update data moved information during a request
154 static int hsm_update_work(struct cdt_req_progress *crp,
155 const struct hsm_extent *extent)
158 struct interval_node **new_vv;
159 struct interval_node *v, *node;
163 end = extent->offset + extent->length;
164 if (end <= extent->offset)
167 mutex_lock(&crp->crp_lock);
170 if (crp->crp_cnt >= crp->crp_max) {
172 /* allocate a new vector */
173 OBD_ALLOC(v, NODE_VECTOR_SZ * sizeof(v[0]));
175 GOTO(out, rc = -ENOMEM);
177 if (crp->crp_max == 0)
180 osz = sizeof(new_vv[0]) *
181 (crp->crp_max / NODE_VECTOR_SZ + 1);
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);
192 crp->crp_max = NODE_VECTOR_SZ - 1;
194 memcpy(new_vv, crp->crp_node, osz);
195 OBD_FREE(crp->crp_node, osz);
196 crp->crp_max += NODE_VECTOR_SZ;
199 crp->crp_node = new_vv;
200 crp->crp_node[crp->crp_max / NODE_VECTOR_SZ] = v;
203 v = crp->crp_node[crp->crp_cnt / NODE_VECTOR_SZ];
204 node = &v[crp->crp_cnt % NODE_VECTOR_SZ];
205 rc = interval_set(node, extent->offset, end);
208 /* try to insert, if entry already exist ignore the new one
209 * it can happen if ct sends 2 times the same progress */
210 if (interval_insert(node, &crp->crp_root) == NULL)
215 mutex_unlock(&crp->crp_lock);
220 * init the interval tree associated to a request
222 static void mdt_cdt_init_request_tree(struct cdt_req_progress *crp)
224 mutex_init(&crp->crp_lock);
225 crp->crp_root = NULL;
230 /** Allocate/init an agent request and its sub-structures.
232 * \param compound_id [IN]
233 * \param archive_id [IN]
237 * \retval car [OUT] success valid structure
240 struct cdt_agent_req *mdt_cdt_alloc_request(__u64 compound_id, __u32 archive_id,
241 __u64 flags, struct obd_uuid *uuid,
242 struct hsm_action_item *hai)
244 struct cdt_agent_req *car;
247 OBD_SLAB_ALLOC_PTR(car, mdt_hsm_car_kmem);
249 RETURN(ERR_PTR(-ENOMEM));
251 atomic_set(&car->car_refcount, 1);
252 car->car_compound_id = compound_id;
253 car->car_archive_id = archive_id;
254 car->car_flags = flags;
255 car->car_canceled = 0;
256 car->car_req_start = cfs_time_current_sec();
257 car->car_req_update = car->car_req_start;
258 car->car_uuid = *uuid;
259 OBD_ALLOC(car->car_hai, hai->hai_len);
260 if (car->car_hai == NULL) {
261 OBD_SLAB_FREE_PTR(car, mdt_hsm_car_kmem);
262 RETURN(ERR_PTR(-ENOMEM));
264 memcpy(car->car_hai, hai, hai->hai_len);
265 mdt_cdt_init_request_tree(&car->car_progress);
271 * Free an agent request and its sub-structures.
273 * \param car [IN] Request to be freed.
275 void mdt_cdt_free_request(struct cdt_agent_req *car)
277 mdt_cdt_free_request_tree(&car->car_progress);
278 OBD_FREE(car->car_hai, car->car_hai->hai_len);
279 OBD_SLAB_FREE_PTR(car, mdt_hsm_car_kmem);
283 * inc refcount of a request
284 * \param car [IN] request
286 void mdt_cdt_get_request(struct cdt_agent_req *car)
288 atomic_inc(&car->car_refcount);
292 * dec refcount of a request
293 * free if no more refcount
294 * \param car [IN] request
296 void mdt_cdt_put_request(struct cdt_agent_req *car)
298 LASSERT(atomic_read(&car->car_refcount) > 0);
299 if (atomic_dec_and_test(&car->car_refcount))
300 mdt_cdt_free_request(car);
304 * find request in the list by cookie or by fid
305 * lock cdt_request_lock needs to be held by caller
306 * \param cdt [IN] coordinator
307 * \param cookie [IN] request cookie
308 * \param fid [IN] fid
309 * \retval request pointer or NULL if not found
311 static struct cdt_agent_req *cdt_find_request_nolock(struct coordinator *cdt,
313 const struct lu_fid *fid)
315 struct cdt_agent_req *car;
316 struct cdt_agent_req *found = NULL;
319 list_for_each_entry(car, &cdt->cdt_requests, car_request_list) {
320 if (car->car_hai->hai_cookie == cookie ||
321 (fid != NULL && lu_fid_eq(fid, &car->car_hai->hai_fid))) {
322 mdt_cdt_get_request(car);
332 * add a request to the list
333 * \param cdt [IN] coordinator
334 * \param car [IN] request
336 * \retval -ve failure
338 int mdt_cdt_add_request(struct coordinator *cdt, struct cdt_agent_req *new_car)
340 struct cdt_agent_req *car;
343 /* cancel requests are not kept in memory */
344 LASSERT(new_car->car_hai->hai_action != HSMA_CANCEL);
346 down_write(&cdt->cdt_request_lock);
347 car = cdt_find_request_nolock(cdt, new_car->car_hai->hai_cookie, NULL);
349 mdt_cdt_put_request(car);
350 up_write(&cdt->cdt_request_lock);
354 list_add_tail(&new_car->car_request_list, &cdt->cdt_requests);
355 up_write(&cdt->cdt_request_lock);
357 mdt_hsm_agent_update_statistics(cdt, 0, 0, 1, &new_car->car_uuid);
359 atomic_inc(&cdt->cdt_request_count);
365 * find request in the list by cookie or by fid
366 * \param cdt [IN] coordinator
367 * \param cookie [IN] request cookie
368 * \param fid [IN] fid
369 * \retval request pointer or NULL if not found
371 struct cdt_agent_req *mdt_cdt_find_request(struct coordinator *cdt,
373 const struct lu_fid *fid)
375 struct cdt_agent_req *car;
378 down_read(&cdt->cdt_request_lock);
379 car = cdt_find_request_nolock(cdt, cookie, fid);
380 up_read(&cdt->cdt_request_lock);
386 * remove request from the list
387 * \param cdt [IN] coordinator
388 * \param cookie [IN] request cookie
389 * \retval request pointer
391 int mdt_cdt_remove_request(struct coordinator *cdt, __u64 cookie)
393 struct cdt_agent_req *car;
396 down_write(&cdt->cdt_request_lock);
397 car = cdt_find_request_nolock(cdt, cookie, NULL);
399 list_del(&car->car_request_list);
400 up_write(&cdt->cdt_request_lock);
402 /* reference from cdt_requests list */
403 mdt_cdt_put_request(car);
405 /* reference from cdt_find_request_nolock() */
406 mdt_cdt_put_request(car);
408 LASSERT(atomic_read(&cdt->cdt_request_count) >= 1);
409 atomic_dec(&cdt->cdt_request_count);
413 up_write(&cdt->cdt_request_lock);
419 * update a request in the list
420 * on success, add a ref to the request returned
421 * \param cdt [IN] coordinator
422 * \param pgs [IN] progression (cookie + extent + err)
423 * \retval request pointer
424 * \retval -ve failure
426 struct cdt_agent_req *mdt_cdt_update_request(struct coordinator *cdt,
427 const struct hsm_progress_kernel *pgs)
429 struct cdt_agent_req *car;
433 car = mdt_cdt_find_request(cdt, pgs->hpk_cookie, NULL);
435 RETURN(ERR_PTR(-ENOENT));
437 car->car_req_update = cfs_time_current_sec();
439 /* update progress done by copy tool */
440 if (pgs->hpk_errval == 0 && pgs->hpk_extent.length != 0) {
441 rc = hsm_update_work(&car->car_progress, &pgs->hpk_extent);
443 mdt_cdt_put_request(car);
448 if (pgs->hpk_flags & HP_FLAG_COMPLETED) {
449 if (pgs->hpk_errval != 0)
450 mdt_hsm_agent_update_statistics(cdt, 0, 1, 0,
453 mdt_hsm_agent_update_statistics(cdt, 1, 0, 0,
460 * seq_file method called to start access to /proc file
462 static void *mdt_hsm_active_requests_proc_start(struct seq_file *s, loff_t *p)
464 struct mdt_device *mdt = s->private;
465 struct coordinator *cdt = &mdt->mdt_coordinator;
466 struct list_head *pos;
470 down_read(&cdt->cdt_request_lock);
472 if (list_empty(&cdt->cdt_requests))
476 RETURN(SEQ_START_TOKEN);
479 list_for_each(pos, &cdt->cdt_requests) {
488 * seq_file method called to get next item
489 * just returns NULL at eof
491 static void *mdt_hsm_active_requests_proc_next(struct seq_file *s, void *v,
494 struct mdt_device *mdt = s->private;
495 struct coordinator *cdt = &mdt->mdt_coordinator;
496 struct list_head *pos = v;
499 if (pos == SEQ_START_TOKEN)
500 pos = cdt->cdt_requests.next;
505 if (pos != &cdt->cdt_requests)
512 * display request data
514 static int mdt_hsm_active_requests_proc_show(struct seq_file *s, void *v)
516 struct list_head *pos = v;
517 struct cdt_agent_req *car;
522 if (pos == SEQ_START_TOKEN)
525 car = list_entry(pos, struct cdt_agent_req, car_request_list);
526 mdt_cdt_get_work_done(car, &data_moved);
528 seq_printf(s, "fid="DFID" dfid="DFID
529 " compound/cookie=%#llx/%#llx"
530 " action=%s archive#=%d flags=%#llx"
531 " extent=%#llx-%#llx gid=%#llx"
532 " data=[%s] canceled=%d uuid=%s done=%llu\n",
533 PFID(&car->car_hai->hai_fid),
534 PFID(&car->car_hai->hai_dfid),
535 car->car_compound_id, car->car_hai->hai_cookie,
536 hsm_copytool_action2name(car->car_hai->hai_action),
537 car->car_archive_id, car->car_flags,
538 car->car_hai->hai_extent.offset,
539 car->car_hai->hai_extent.length,
540 car->car_hai->hai_gid,
541 hai_dump_data_field(car->car_hai, buf, sizeof(buf)),
542 car->car_canceled, obd_uuid2str(&car->car_uuid),
548 * seq_file method called to stop access to /proc file
550 static void mdt_hsm_active_requests_proc_stop(struct seq_file *s, void *v)
552 struct mdt_device *mdt = s->private;
553 struct coordinator *cdt = &mdt->mdt_coordinator;
556 up_read(&cdt->cdt_request_lock);
561 /* hsm agent list proc functions */
562 static const struct seq_operations mdt_hsm_active_requests_proc_ops = {
563 .start = mdt_hsm_active_requests_proc_start,
564 .next = mdt_hsm_active_requests_proc_next,
565 .show = mdt_hsm_active_requests_proc_show,
566 .stop = mdt_hsm_active_requests_proc_stop,
570 * public function called at open of /proc file to get
573 static int lprocfs_open_hsm_active_requests(struct inode *inode,
580 rc = seq_open(file, &mdt_hsm_active_requests_proc_ops);
584 s = file->private_data;
585 s->private = PDE_DATA(inode);
590 /* methods to access hsm request list */
591 const struct file_operations mdt_hsm_active_requests_fops = {
592 .owner = THIS_MODULE,
593 .open = lprocfs_open_hsm_active_requests,
596 .release = lprocfs_seq_release,