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 <lprocfs_status.h>
43 #include "mdt_internal.h"
46 cdt_request_cookie_hash(struct cfs_hash *hs, const void *key, unsigned int mask)
48 return cfs_hash_djb2_hash(key, sizeof(u64), mask);
51 static void *cdt_request_cookie_object(struct hlist_node *hnode)
53 return hlist_entry(hnode, struct cdt_agent_req, car_cookie_hash);
56 static void *cdt_request_cookie_key(struct hlist_node *hnode)
58 struct cdt_agent_req *car = cdt_request_cookie_object(hnode);
60 return &car->car_hai->hai_cookie;
63 static int cdt_request_cookie_keycmp(const void *key, struct hlist_node *hnode)
65 const u64 *cookie2 = cdt_request_cookie_key(hnode);
67 return *(u64 *)key == *cookie2;
71 cdt_request_cookie_get(struct cfs_hash *hs, struct hlist_node *hnode)
73 struct cdt_agent_req *car = cdt_request_cookie_object(hnode);
75 mdt_cdt_get_request(car);
79 cdt_request_cookie_put(struct cfs_hash *hs, struct hlist_node *hnode)
81 struct cdt_agent_req *car = cdt_request_cookie_object(hnode);
83 mdt_cdt_put_request(car);
86 struct cfs_hash_ops cdt_request_cookie_hash_ops = {
87 .hs_hash = cdt_request_cookie_hash,
88 .hs_key = cdt_request_cookie_key,
89 .hs_keycmp = cdt_request_cookie_keycmp,
90 .hs_object = cdt_request_cookie_object,
91 .hs_get = cdt_request_cookie_get,
92 .hs_put_locked = cdt_request_cookie_put,
97 * \param cdt [IN] coordinator
99 void dump_requests(char *prefix, struct coordinator *cdt)
101 struct cdt_agent_req *car;
103 down_read(&cdt->cdt_request_lock);
104 list_for_each_entry(car, &cdt->cdt_request_list, car_request_list) {
105 CDEBUG(D_HSM, "%s fid="DFID" dfid="DFID
106 " compound/cookie=%#llx/%#llx"
107 " action=%s archive#=%d flags=%#llx"
108 " extent=%#llx-%#llx"
109 " gid=%#llx refcount=%d canceled=%d\n",
110 prefix, PFID(&car->car_hai->hai_fid),
111 PFID(&car->car_hai->hai_dfid),
112 car->car_compound_id, car->car_hai->hai_cookie,
113 hsm_copytool_action2name(car->car_hai->hai_action),
114 car->car_archive_id, car->car_flags,
115 car->car_hai->hai_extent.offset,
116 car->car_hai->hai_extent.length,
117 car->car_hai->hai_gid,
118 atomic_read(&car->car_refcount),
121 up_read(&cdt->cdt_request_lock);
124 struct req_interval_data {
125 struct cdt_req_progress *crp;
130 * interval tree cb, used to go through all the tree of extent done
132 static enum interval_iter req_interval_cb(struct interval_node *node,
135 struct req_interval_data *data;
139 data->done_sz += node->in_extent.end - node->in_extent.start;
140 RETURN(INTERVAL_ITER_CONT);
144 * scan the interval tree associated to a request
145 * to compute the amount of work done
146 * \param car [IN] request
147 * \param done_sz [OUT] will be set to the size of work done
149 void mdt_cdt_get_work_done(struct cdt_agent_req *car, __u64 *done_sz)
151 struct req_interval_data rid;
152 struct cdt_req_progress *crp = &car->car_progress;
154 mutex_lock(&crp->crp_lock);
158 interval_iterate(crp->crp_root, req_interval_cb, &rid);
159 *done_sz = rid.done_sz;
161 mutex_unlock(&crp->crp_lock);
164 #define NODE_VECTOR_SZ 256
166 * free the interval tree associated to a request
168 static void mdt_cdt_free_request_tree(struct cdt_req_progress *crp)
170 struct interval_node *node, *vn;
174 mutex_lock(&crp->crp_lock);
176 if (crp->crp_max == 0)
179 /* remove all nodes from tree */
180 for (i = 0 ; i < crp->crp_cnt ; i++) {
181 vn = crp->crp_node[i / NODE_VECTOR_SZ];
182 node = &vn[i % NODE_VECTOR_SZ];
183 interval_erase(node, &crp->crp_root);
185 /* free all sub vectors */
186 for (i = 0 ; i <= crp->crp_max / NODE_VECTOR_SZ ; i++)
187 OBD_FREE(crp->crp_node[i],
188 NODE_VECTOR_SZ * sizeof(crp->crp_node[i][0]));
190 /* free main vector */
191 OBD_FREE(crp->crp_node,
192 sizeof(crp->crp_node[0]) *
193 (crp->crp_max / NODE_VECTOR_SZ + 1));
198 mutex_unlock(&crp->crp_lock);
203 * update data moved information during a request
205 static int hsm_update_work(struct cdt_req_progress *crp,
206 const struct hsm_extent *extent)
209 struct interval_node **new_vv;
210 struct interval_node *v, *node;
214 end = extent->offset + extent->length;
215 if (end <= extent->offset)
218 mutex_lock(&crp->crp_lock);
221 if (crp->crp_cnt >= crp->crp_max) {
223 /* allocate a new vector */
224 OBD_ALLOC(v, NODE_VECTOR_SZ * sizeof(v[0]));
226 GOTO(out, rc = -ENOMEM);
228 if (crp->crp_max == 0)
231 osz = sizeof(new_vv[0]) *
232 (crp->crp_max / NODE_VECTOR_SZ + 1);
234 nsz = osz + sizeof(new_vv[0]);
235 /* increase main vector size */
236 OBD_ALLOC(new_vv, nsz);
237 if (new_vv == NULL) {
238 OBD_FREE(v, NODE_VECTOR_SZ * sizeof(v[0]));
239 GOTO(out, rc = -ENOMEM);
243 crp->crp_max = NODE_VECTOR_SZ - 1;
245 memcpy(new_vv, crp->crp_node, osz);
246 OBD_FREE(crp->crp_node, osz);
247 crp->crp_max += NODE_VECTOR_SZ;
250 crp->crp_node = new_vv;
251 crp->crp_node[crp->crp_max / NODE_VECTOR_SZ] = v;
254 v = crp->crp_node[crp->crp_cnt / NODE_VECTOR_SZ];
255 node = &v[crp->crp_cnt % NODE_VECTOR_SZ];
256 rc = interval_set(node, extent->offset, end);
259 /* try to insert, if entry already exist ignore the new one
260 * it can happen if ct sends 2 times the same progress */
261 if (interval_insert(node, &crp->crp_root) == NULL)
266 mutex_unlock(&crp->crp_lock);
271 * init the interval tree associated to a request
273 static void mdt_cdt_init_request_tree(struct cdt_req_progress *crp)
275 mutex_init(&crp->crp_lock);
276 crp->crp_root = NULL;
281 /** Allocate/init an agent request and its sub-structures.
283 * \param compound_id [IN]
284 * \param archive_id [IN]
288 * \retval car [OUT] success valid structure
291 struct cdt_agent_req *mdt_cdt_alloc_request(__u64 compound_id, __u32 archive_id,
292 __u64 flags, struct obd_uuid *uuid,
293 struct hsm_action_item *hai)
295 struct cdt_agent_req *car;
298 OBD_SLAB_ALLOC_PTR(car, mdt_hsm_car_kmem);
300 RETURN(ERR_PTR(-ENOMEM));
302 atomic_set(&car->car_refcount, 1);
303 car->car_compound_id = compound_id;
304 car->car_archive_id = archive_id;
305 car->car_flags = flags;
306 car->car_canceled = 0;
307 car->car_req_start = ktime_get_real_seconds();
308 car->car_req_update = car->car_req_start;
309 car->car_uuid = *uuid;
310 OBD_ALLOC(car->car_hai, hai->hai_len);
311 if (car->car_hai == NULL) {
312 OBD_SLAB_FREE_PTR(car, mdt_hsm_car_kmem);
313 RETURN(ERR_PTR(-ENOMEM));
315 memcpy(car->car_hai, hai, hai->hai_len);
316 mdt_cdt_init_request_tree(&car->car_progress);
322 * Free an agent request and its sub-structures.
324 * \param car [IN] Request to be freed.
326 void mdt_cdt_free_request(struct cdt_agent_req *car)
328 mdt_cdt_free_request_tree(&car->car_progress);
329 OBD_FREE(car->car_hai, car->car_hai->hai_len);
330 OBD_SLAB_FREE_PTR(car, mdt_hsm_car_kmem);
334 * inc refcount of a request
335 * \param car [IN] request
337 void mdt_cdt_get_request(struct cdt_agent_req *car)
339 atomic_inc(&car->car_refcount);
343 * dec refcount of a request
344 * free if no more refcount
345 * \param car [IN] request
347 void mdt_cdt_put_request(struct cdt_agent_req *car)
349 LASSERT(atomic_read(&car->car_refcount) > 0);
350 if (atomic_dec_and_test(&car->car_refcount))
351 mdt_cdt_free_request(car);
355 * add a request to the list
356 * \param cdt [IN] coordinator
357 * \param car [IN] request
359 * \retval -ve failure
361 int mdt_cdt_add_request(struct coordinator *cdt, struct cdt_agent_req *car)
366 /* cancel requests are not kept in memory */
367 LASSERT(car->car_hai->hai_action != HSMA_CANCEL);
369 down_write(&cdt->cdt_request_lock);
371 rc = cfs_hash_add_unique(cdt->cdt_request_cookie_hash,
372 &car->car_hai->hai_cookie,
373 &car->car_cookie_hash);
375 up_write(&cdt->cdt_request_lock);
379 list_add_tail(&car->car_request_list, &cdt->cdt_request_list);
381 up_write(&cdt->cdt_request_lock);
383 mdt_hsm_agent_update_statistics(cdt, 0, 0, 1, &car->car_uuid);
385 switch (car->car_hai->hai_action) {
387 atomic_inc(&cdt->cdt_archive_count);
390 atomic_inc(&cdt->cdt_restore_count);
393 atomic_inc(&cdt->cdt_remove_count);
396 atomic_inc(&cdt->cdt_request_count);
402 * find request in the list by cookie or by fid
403 * \param cdt [IN] coordinator
404 * \param cookie [IN] request cookie
405 * \param fid [IN] fid
406 * \retval request pointer or NULL if not found
408 struct cdt_agent_req *mdt_cdt_find_request(struct coordinator *cdt, u64 cookie)
410 struct cdt_agent_req *car;
413 down_read(&cdt->cdt_request_lock);
414 car = cfs_hash_lookup(cdt->cdt_request_cookie_hash, &cookie);
415 up_read(&cdt->cdt_request_lock);
421 * remove request from the list
422 * \param cdt [IN] coordinator
423 * \param cookie [IN] request cookie
424 * \retval request pointer
426 int mdt_cdt_remove_request(struct coordinator *cdt, __u64 cookie)
428 struct cdt_agent_req *car;
431 down_write(&cdt->cdt_request_lock);
432 car = cfs_hash_del_key(cdt->cdt_request_cookie_hash, &cookie);
434 up_write(&cdt->cdt_request_lock);
438 list_del(&car->car_request_list);
439 up_write(&cdt->cdt_request_lock);
441 switch (car->car_hai->hai_action) {
443 atomic_dec(&cdt->cdt_archive_count);
446 atomic_dec(&cdt->cdt_restore_count);
449 atomic_dec(&cdt->cdt_remove_count);
453 /* Drop reference from cdt_request_list. */
454 mdt_cdt_put_request(car);
456 LASSERT(atomic_read(&cdt->cdt_request_count) >= 1);
457 if (atomic_dec_and_test(&cdt->cdt_request_count)) {
458 /* request count is empty, nudge coordinator for more work */
459 cdt->cdt_wakeup_coordinator = true;
460 wake_up_interruptible(&cdt->cdt_waitq);
467 * update a request in the list
468 * on success, add a ref to the request returned
469 * \param cdt [IN] coordinator
470 * \param pgs [IN] progression (cookie + extent + err)
471 * \retval request pointer
472 * \retval -ve failure
474 struct cdt_agent_req *mdt_cdt_update_request(struct coordinator *cdt,
475 const struct hsm_progress_kernel *pgs)
477 struct cdt_agent_req *car;
481 car = mdt_cdt_find_request(cdt, pgs->hpk_cookie);
483 RETURN(ERR_PTR(-ENOENT));
485 car->car_req_update = ktime_get_real_seconds();
487 /* update data move progress done by copy tool */
488 if (car->car_hai->hai_action != HSMA_REMOVE && pgs->hpk_errval == 0 &&
489 pgs->hpk_extent.length != 0) {
490 rc = hsm_update_work(&car->car_progress, &pgs->hpk_extent);
492 mdt_cdt_put_request(car);
497 if (pgs->hpk_flags & HP_FLAG_COMPLETED) {
498 if (pgs->hpk_errval != 0)
499 mdt_hsm_agent_update_statistics(cdt, 0, 1, 0,
502 mdt_hsm_agent_update_statistics(cdt, 1, 0, 0,
509 * seq_file method called to start access to /proc file
511 static void *mdt_hsm_active_requests_proc_start(struct seq_file *s, loff_t *p)
513 struct mdt_device *mdt = s->private;
514 struct coordinator *cdt = &mdt->mdt_coordinator;
515 struct list_head *pos;
519 down_read(&cdt->cdt_request_lock);
521 if (list_empty(&cdt->cdt_request_list))
525 RETURN(SEQ_START_TOKEN);
528 list_for_each(pos, &cdt->cdt_request_list) {
537 * seq_file method called to get next item
538 * just returns NULL at eof
540 static void *mdt_hsm_active_requests_proc_next(struct seq_file *s, void *v,
543 struct mdt_device *mdt = s->private;
544 struct coordinator *cdt = &mdt->mdt_coordinator;
545 struct list_head *pos = v;
548 if (pos == SEQ_START_TOKEN)
549 pos = cdt->cdt_request_list.next;
554 if (pos != &cdt->cdt_request_list)
561 * display request data
563 static int mdt_hsm_active_requests_proc_show(struct seq_file *s, void *v)
565 struct list_head *pos = v;
566 struct cdt_agent_req *car;
571 if (pos == SEQ_START_TOKEN)
574 car = list_entry(pos, struct cdt_agent_req, car_request_list);
575 mdt_cdt_get_work_done(car, &data_moved);
577 seq_printf(s, "fid="DFID" dfid="DFID
578 " compound/cookie=%#llx/%#llx"
579 " action=%s archive#=%d flags=%#llx"
580 " extent=%#llx-%#llx gid=%#llx"
581 " data=[%s] canceled=%d uuid=%s done=%llu\n",
582 PFID(&car->car_hai->hai_fid),
583 PFID(&car->car_hai->hai_dfid),
584 car->car_compound_id, car->car_hai->hai_cookie,
585 hsm_copytool_action2name(car->car_hai->hai_action),
586 car->car_archive_id, car->car_flags,
587 car->car_hai->hai_extent.offset,
588 car->car_hai->hai_extent.length,
589 car->car_hai->hai_gid,
590 hai_dump_data_field(car->car_hai, buf, sizeof(buf)),
591 car->car_canceled, obd_uuid2str(&car->car_uuid),
597 * seq_file method called to stop access to /proc file
599 static void mdt_hsm_active_requests_proc_stop(struct seq_file *s, void *v)
601 struct mdt_device *mdt = s->private;
602 struct coordinator *cdt = &mdt->mdt_coordinator;
605 up_read(&cdt->cdt_request_lock);
610 /* hsm agent list proc functions */
611 static const struct seq_operations mdt_hsm_active_requests_proc_ops = {
612 .start = mdt_hsm_active_requests_proc_start,
613 .next = mdt_hsm_active_requests_proc_next,
614 .show = mdt_hsm_active_requests_proc_show,
615 .stop = mdt_hsm_active_requests_proc_stop,
619 * public function called at open of /proc file to get
622 static int lprocfs_open_hsm_active_requests(struct inode *inode,
629 rc = seq_open(file, &mdt_hsm_active_requests_proc_ops);
633 s = file->private_data;
634 s->private = PDE_DATA(inode);
639 /* methods to access hsm request list */
640 const struct file_operations mdt_hsm_active_requests_fops = {
641 .owner = THIS_MODULE,
642 .open = lprocfs_open_hsm_active_requests,
645 .release = lprocfs_seq_release,