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 if (atomic_dec_and_test(&cdt->cdt_request_count)) {
436 /* request count is empty, nudge coordinator for more work */
437 cdt->cdt_wakeup_coordinator = true;
438 wake_up_interruptible(&cdt->cdt_waitq);
445 * update a request in the list
446 * on success, add a ref to the request returned
447 * \param cdt [IN] coordinator
448 * \param pgs [IN] progression (cookie + extent + err)
449 * \retval request pointer
450 * \retval -ve failure
452 struct cdt_agent_req *mdt_cdt_update_request(struct coordinator *cdt,
453 const struct hsm_progress_kernel *pgs)
455 struct cdt_agent_req *car;
459 car = mdt_cdt_find_request(cdt, pgs->hpk_cookie);
461 RETURN(ERR_PTR(-ENOENT));
463 car->car_req_update = cfs_time_current_sec();
465 /* update data move progress done by copy tool */
466 if (car->car_hai->hai_action != HSMA_REMOVE && pgs->hpk_errval == 0 &&
467 pgs->hpk_extent.length != 0) {
468 rc = hsm_update_work(&car->car_progress, &pgs->hpk_extent);
470 mdt_cdt_put_request(car);
475 if (pgs->hpk_flags & HP_FLAG_COMPLETED) {
476 if (pgs->hpk_errval != 0)
477 mdt_hsm_agent_update_statistics(cdt, 0, 1, 0,
480 mdt_hsm_agent_update_statistics(cdt, 1, 0, 0,
487 * seq_file method called to start access to /proc file
489 static void *mdt_hsm_active_requests_proc_start(struct seq_file *s, loff_t *p)
491 struct mdt_device *mdt = s->private;
492 struct coordinator *cdt = &mdt->mdt_coordinator;
493 struct list_head *pos;
497 down_read(&cdt->cdt_request_lock);
499 if (list_empty(&cdt->cdt_request_list))
503 RETURN(SEQ_START_TOKEN);
506 list_for_each(pos, &cdt->cdt_request_list) {
515 * seq_file method called to get next item
516 * just returns NULL at eof
518 static void *mdt_hsm_active_requests_proc_next(struct seq_file *s, void *v,
521 struct mdt_device *mdt = s->private;
522 struct coordinator *cdt = &mdt->mdt_coordinator;
523 struct list_head *pos = v;
526 if (pos == SEQ_START_TOKEN)
527 pos = cdt->cdt_request_list.next;
532 if (pos != &cdt->cdt_request_list)
539 * display request data
541 static int mdt_hsm_active_requests_proc_show(struct seq_file *s, void *v)
543 struct list_head *pos = v;
544 struct cdt_agent_req *car;
549 if (pos == SEQ_START_TOKEN)
552 car = list_entry(pos, struct cdt_agent_req, car_request_list);
553 mdt_cdt_get_work_done(car, &data_moved);
555 seq_printf(s, "fid="DFID" dfid="DFID
556 " compound/cookie=%#llx/%#llx"
557 " action=%s archive#=%d flags=%#llx"
558 " extent=%#llx-%#llx gid=%#llx"
559 " data=[%s] canceled=%d uuid=%s done=%llu\n",
560 PFID(&car->car_hai->hai_fid),
561 PFID(&car->car_hai->hai_dfid),
562 car->car_compound_id, car->car_hai->hai_cookie,
563 hsm_copytool_action2name(car->car_hai->hai_action),
564 car->car_archive_id, car->car_flags,
565 car->car_hai->hai_extent.offset,
566 car->car_hai->hai_extent.length,
567 car->car_hai->hai_gid,
568 hai_dump_data_field(car->car_hai, buf, sizeof(buf)),
569 car->car_canceled, obd_uuid2str(&car->car_uuid),
575 * seq_file method called to stop access to /proc file
577 static void mdt_hsm_active_requests_proc_stop(struct seq_file *s, void *v)
579 struct mdt_device *mdt = s->private;
580 struct coordinator *cdt = &mdt->mdt_coordinator;
583 up_read(&cdt->cdt_request_lock);
588 /* hsm agent list proc functions */
589 static const struct seq_operations mdt_hsm_active_requests_proc_ops = {
590 .start = mdt_hsm_active_requests_proc_start,
591 .next = mdt_hsm_active_requests_proc_next,
592 .show = mdt_hsm_active_requests_proc_show,
593 .stop = mdt_hsm_active_requests_proc_stop,
597 * public function called at open of /proc file to get
600 static int lprocfs_open_hsm_active_requests(struct inode *inode,
607 rc = seq_open(file, &mdt_hsm_active_requests_proc_ops);
611 s = file->private_data;
612 s->private = PDE_DATA(inode);
617 /* methods to access hsm request list */
618 const struct file_operations mdt_hsm_active_requests_fops = {
619 .owner = THIS_MODULE,
620 .open = lprocfs_open_hsm_active_requests,
623 .release = lprocfs_seq_release,