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 <libcfs/libcfs.h>
40 #include <libcfs/libcfs_hash.h>
41 #include <obd_support.h>
42 #include <lustre/lustre_user.h>
43 #include <lprocfs_status.h>
44 #include "mdt_internal.h"
47 cdt_request_cookie_hash(struct cfs_hash *hs, const void *key, unsigned int mask)
49 return cfs_hash_djb2_hash(key, sizeof(u64), mask);
52 static void *cdt_request_cookie_object(struct hlist_node *hnode)
54 return hlist_entry(hnode, struct cdt_agent_req, car_cookie_hash);
57 static void *cdt_request_cookie_key(struct hlist_node *hnode)
59 struct cdt_agent_req *car = cdt_request_cookie_object(hnode);
61 return &car->car_hai->hai_cookie;
64 static int cdt_request_cookie_keycmp(const void *key, struct hlist_node *hnode)
66 const u64 *cookie2 = cdt_request_cookie_key(hnode);
68 return *(u64 *)key == *cookie2;
72 cdt_request_cookie_get(struct cfs_hash *hs, struct hlist_node *hnode)
74 struct cdt_agent_req *car = cdt_request_cookie_object(hnode);
76 mdt_cdt_get_request(car);
80 cdt_request_cookie_put(struct cfs_hash *hs, struct hlist_node *hnode)
82 struct cdt_agent_req *car = cdt_request_cookie_object(hnode);
84 mdt_cdt_put_request(car);
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,
98 * \param cdt [IN] coordinator
100 void dump_requests(char *prefix, struct coordinator *cdt)
102 struct cdt_agent_req *car;
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 " compound/cookie=%#llx/%#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_compound_id, 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 atomic_read(&car->car_refcount),
122 up_read(&cdt->cdt_request_lock);
125 struct req_interval_data {
126 struct cdt_req_progress *crp;
131 * interval tree cb, used to go through all the tree of extent done
133 static enum interval_iter req_interval_cb(struct interval_node *node,
136 struct req_interval_data *data;
140 data->done_sz += node->in_extent.end - node->in_extent.start;
141 RETURN(INTERVAL_ITER_CONT);
145 * scan the interval tree associated to a request
146 * to compute the amount of work done
147 * \param car [IN] request
148 * \param done_sz [OUT] will be set to the size of work done
150 void mdt_cdt_get_work_done(struct cdt_agent_req *car, __u64 *done_sz)
152 struct req_interval_data rid;
153 struct cdt_req_progress *crp = &car->car_progress;
155 mutex_lock(&crp->crp_lock);
159 interval_iterate(crp->crp_root, req_interval_cb, &rid);
160 *done_sz = rid.done_sz;
162 mutex_unlock(&crp->crp_lock);
165 #define NODE_VECTOR_SZ 256
167 * free the interval tree associated to a request
169 static void mdt_cdt_free_request_tree(struct cdt_req_progress *crp)
171 struct interval_node *node, *vn;
175 mutex_lock(&crp->crp_lock);
177 if (crp->crp_max == 0)
180 /* remove all nodes from tree */
181 for (i = 0 ; i < crp->crp_cnt ; i++) {
182 vn = crp->crp_node[i / NODE_VECTOR_SZ];
183 node = &vn[i % NODE_VECTOR_SZ];
184 interval_erase(node, &crp->crp_root);
186 /* free all sub vectors */
187 for (i = 0 ; i <= crp->crp_max / NODE_VECTOR_SZ ; i++)
188 OBD_FREE(crp->crp_node[i],
189 NODE_VECTOR_SZ * sizeof(crp->crp_node[i][0]));
191 /* free main vector */
192 OBD_FREE(crp->crp_node,
193 sizeof(crp->crp_node[0]) *
194 (crp->crp_max / NODE_VECTOR_SZ + 1));
199 mutex_unlock(&crp->crp_lock);
204 * update data moved information during a request
206 static int hsm_update_work(struct cdt_req_progress *crp,
207 const struct hsm_extent *extent)
210 struct interval_node **new_vv;
211 struct interval_node *v, *node;
215 end = extent->offset + extent->length;
216 if (end <= extent->offset)
219 mutex_lock(&crp->crp_lock);
222 if (crp->crp_cnt >= crp->crp_max) {
224 /* allocate a new vector */
225 OBD_ALLOC(v, NODE_VECTOR_SZ * sizeof(v[0]));
227 GOTO(out, rc = -ENOMEM);
229 if (crp->crp_max == 0)
232 osz = sizeof(new_vv[0]) *
233 (crp->crp_max / NODE_VECTOR_SZ + 1);
235 nsz = osz + sizeof(new_vv[0]);
236 /* increase main vector size */
237 OBD_ALLOC(new_vv, nsz);
238 if (new_vv == NULL) {
239 OBD_FREE(v, NODE_VECTOR_SZ * sizeof(v[0]));
240 GOTO(out, rc = -ENOMEM);
244 crp->crp_max = NODE_VECTOR_SZ - 1;
246 memcpy(new_vv, crp->crp_node, osz);
247 OBD_FREE(crp->crp_node, osz);
248 crp->crp_max += NODE_VECTOR_SZ;
251 crp->crp_node = new_vv;
252 crp->crp_node[crp->crp_max / NODE_VECTOR_SZ] = v;
255 v = crp->crp_node[crp->crp_cnt / NODE_VECTOR_SZ];
256 node = &v[crp->crp_cnt % NODE_VECTOR_SZ];
257 rc = interval_set(node, extent->offset, end);
260 /* try to insert, if entry already exist ignore the new one
261 * it can happen if ct sends 2 times the same progress */
262 if (interval_insert(node, &crp->crp_root) == NULL)
267 mutex_unlock(&crp->crp_lock);
272 * init the interval tree associated to a request
274 static void mdt_cdt_init_request_tree(struct cdt_req_progress *crp)
276 mutex_init(&crp->crp_lock);
277 crp->crp_root = NULL;
282 /** Allocate/init an agent request and its sub-structures.
284 * \param compound_id [IN]
285 * \param archive_id [IN]
289 * \retval car [OUT] success valid structure
292 struct cdt_agent_req *mdt_cdt_alloc_request(__u64 compound_id, __u32 archive_id,
293 __u64 flags, struct obd_uuid *uuid,
294 struct hsm_action_item *hai)
296 struct cdt_agent_req *car;
299 OBD_SLAB_ALLOC_PTR(car, mdt_hsm_car_kmem);
301 RETURN(ERR_PTR(-ENOMEM));
303 atomic_set(&car->car_refcount, 1);
304 car->car_compound_id = compound_id;
305 car->car_archive_id = archive_id;
306 car->car_flags = flags;
307 car->car_canceled = 0;
308 car->car_req_start = cfs_time_current_sec();
309 car->car_req_update = car->car_req_start;
310 car->car_uuid = *uuid;
311 OBD_ALLOC(car->car_hai, hai->hai_len);
312 if (car->car_hai == NULL) {
313 OBD_SLAB_FREE_PTR(car, mdt_hsm_car_kmem);
314 RETURN(ERR_PTR(-ENOMEM));
316 memcpy(car->car_hai, hai, hai->hai_len);
317 mdt_cdt_init_request_tree(&car->car_progress);
323 * Free an agent request and its sub-structures.
325 * \param car [IN] Request to be freed.
327 void mdt_cdt_free_request(struct cdt_agent_req *car)
329 mdt_cdt_free_request_tree(&car->car_progress);
330 OBD_FREE(car->car_hai, car->car_hai->hai_len);
331 OBD_SLAB_FREE_PTR(car, mdt_hsm_car_kmem);
335 * inc refcount of a request
336 * \param car [IN] request
338 void mdt_cdt_get_request(struct cdt_agent_req *car)
340 atomic_inc(&car->car_refcount);
344 * dec refcount of a request
345 * free if no more refcount
346 * \param car [IN] request
348 void mdt_cdt_put_request(struct cdt_agent_req *car)
350 LASSERT(atomic_read(&car->car_refcount) > 0);
351 if (atomic_dec_and_test(&car->car_refcount))
352 mdt_cdt_free_request(car);
356 * add a request to the list
357 * \param cdt [IN] coordinator
358 * \param car [IN] request
360 * \retval -ve failure
362 int mdt_cdt_add_request(struct coordinator *cdt, struct cdt_agent_req *car)
367 /* cancel requests are not kept in memory */
368 LASSERT(car->car_hai->hai_action != HSMA_CANCEL);
370 down_write(&cdt->cdt_request_lock);
372 rc = cfs_hash_add_unique(cdt->cdt_request_cookie_hash,
373 &car->car_hai->hai_cookie,
374 &car->car_cookie_hash);
376 up_write(&cdt->cdt_request_lock);
380 list_add_tail(&car->car_request_list, &cdt->cdt_request_list);
382 up_write(&cdt->cdt_request_lock);
384 mdt_hsm_agent_update_statistics(cdt, 0, 0, 1, &car->car_uuid);
386 atomic_inc(&cdt->cdt_request_count);
392 * find request in the list by cookie or by fid
393 * \param cdt [IN] coordinator
394 * \param cookie [IN] request cookie
395 * \param fid [IN] fid
396 * \retval request pointer or NULL if not found
398 struct cdt_agent_req *mdt_cdt_find_request(struct coordinator *cdt, u64 cookie)
400 struct cdt_agent_req *car;
403 down_read(&cdt->cdt_request_lock);
404 car = cfs_hash_lookup(cdt->cdt_request_cookie_hash, &cookie);
405 up_read(&cdt->cdt_request_lock);
411 * remove request from the list
412 * \param cdt [IN] coordinator
413 * \param cookie [IN] request cookie
414 * \retval request pointer
416 int mdt_cdt_remove_request(struct coordinator *cdt, __u64 cookie)
418 struct cdt_agent_req *car;
421 down_write(&cdt->cdt_request_lock);
422 car = cfs_hash_del_key(cdt->cdt_request_cookie_hash, &cookie);
424 up_write(&cdt->cdt_request_lock);
428 list_del(&car->car_request_list);
429 up_write(&cdt->cdt_request_lock);
431 /* Drop reference from cdt_request_list. */
432 mdt_cdt_put_request(car);
434 LASSERT(atomic_read(&cdt->cdt_request_count) >= 1);
435 atomic_dec(&cdt->cdt_request_count);
441 * update a request in the list
442 * on success, add a ref to the request returned
443 * \param cdt [IN] coordinator
444 * \param pgs [IN] progression (cookie + extent + err)
445 * \retval request pointer
446 * \retval -ve failure
448 struct cdt_agent_req *mdt_cdt_update_request(struct coordinator *cdt,
449 const struct hsm_progress_kernel *pgs)
451 struct cdt_agent_req *car;
455 car = mdt_cdt_find_request(cdt, pgs->hpk_cookie);
457 RETURN(ERR_PTR(-ENOENT));
459 car->car_req_update = cfs_time_current_sec();
461 /* update data move progress done by copy tool */
462 if (car->car_hai->hai_action != HSMA_REMOVE && pgs->hpk_errval == 0 &&
463 pgs->hpk_extent.length != 0) {
464 rc = hsm_update_work(&car->car_progress, &pgs->hpk_extent);
466 mdt_cdt_put_request(car);
471 if (pgs->hpk_flags & HP_FLAG_COMPLETED) {
472 if (pgs->hpk_errval != 0)
473 mdt_hsm_agent_update_statistics(cdt, 0, 1, 0,
476 mdt_hsm_agent_update_statistics(cdt, 1, 0, 0,
483 * seq_file method called to start access to /proc file
485 static void *mdt_hsm_active_requests_proc_start(struct seq_file *s, loff_t *p)
487 struct mdt_device *mdt = s->private;
488 struct coordinator *cdt = &mdt->mdt_coordinator;
489 struct list_head *pos;
493 down_read(&cdt->cdt_request_lock);
495 if (list_empty(&cdt->cdt_request_list))
499 RETURN(SEQ_START_TOKEN);
502 list_for_each(pos, &cdt->cdt_request_list) {
511 * seq_file method called to get next item
512 * just returns NULL at eof
514 static void *mdt_hsm_active_requests_proc_next(struct seq_file *s, void *v,
517 struct mdt_device *mdt = s->private;
518 struct coordinator *cdt = &mdt->mdt_coordinator;
519 struct list_head *pos = v;
522 if (pos == SEQ_START_TOKEN)
523 pos = cdt->cdt_request_list.next;
528 if (pos != &cdt->cdt_request_list)
535 * display request data
537 static int mdt_hsm_active_requests_proc_show(struct seq_file *s, void *v)
539 struct list_head *pos = v;
540 struct cdt_agent_req *car;
545 if (pos == SEQ_START_TOKEN)
548 car = list_entry(pos, struct cdt_agent_req, car_request_list);
549 mdt_cdt_get_work_done(car, &data_moved);
551 seq_printf(s, "fid="DFID" dfid="DFID
552 " compound/cookie=%#llx/%#llx"
553 " action=%s archive#=%d flags=%#llx"
554 " extent=%#llx-%#llx gid=%#llx"
555 " data=[%s] canceled=%d uuid=%s done=%llu\n",
556 PFID(&car->car_hai->hai_fid),
557 PFID(&car->car_hai->hai_dfid),
558 car->car_compound_id, car->car_hai->hai_cookie,
559 hsm_copytool_action2name(car->car_hai->hai_action),
560 car->car_archive_id, car->car_flags,
561 car->car_hai->hai_extent.offset,
562 car->car_hai->hai_extent.length,
563 car->car_hai->hai_gid,
564 hai_dump_data_field(car->car_hai, buf, sizeof(buf)),
565 car->car_canceled, obd_uuid2str(&car->car_uuid),
571 * seq_file method called to stop access to /proc file
573 static void mdt_hsm_active_requests_proc_stop(struct seq_file *s, void *v)
575 struct mdt_device *mdt = s->private;
576 struct coordinator *cdt = &mdt->mdt_coordinator;
579 up_read(&cdt->cdt_request_lock);
584 /* hsm agent list proc functions */
585 static const struct seq_operations mdt_hsm_active_requests_proc_ops = {
586 .start = mdt_hsm_active_requests_proc_start,
587 .next = mdt_hsm_active_requests_proc_next,
588 .show = mdt_hsm_active_requests_proc_show,
589 .stop = mdt_hsm_active_requests_proc_stop,
593 * public function called at open of /proc file to get
596 static int lprocfs_open_hsm_active_requests(struct inode *inode,
603 rc = seq_open(file, &mdt_hsm_active_requests_proc_ops);
607 s = file->private_data;
608 s->private = PDE_DATA(inode);
613 /* methods to access hsm request list */
614 const struct file_operations mdt_hsm_active_requests_fops = {
615 .owner = THIS_MODULE,
616 .open = lprocfs_open_hsm_active_requests,
619 .release = lprocfs_seq_release,