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
28 * lustre/mdt/mdt_hsm_cdt_requests.c
30 * Lustre HSM Coordinator
32 * Author: Jacques-Charles Lafoucriere <jacques-charles.lafoucriere@cea.fr>
33 * Author: Aurelien Degremont <aurelien.degremont@cea.fr>
36 #define DEBUG_SUBSYSTEM S_MDS
38 #include <obd_support.h>
39 #include <lustre/lustre_user.h>
40 #include <lprocfs_status.h>
41 #include "mdt_internal.h"
45 * \param cdt [IN] coordinator
47 void dump_requests(char *prefix, struct coordinator *cdt)
50 struct cdt_agent_req *car;
52 down_read(&cdt->cdt_request_lock);
53 cfs_list_for_each(pos, &cdt->cdt_requests) {
54 car = cfs_list_entry(pos, struct cdt_agent_req,
56 CDEBUG(D_HSM, "%s fid="DFID" dfid="DFID
57 " compound/cookie="LPX64"/"LPX64
58 " action=%s archive#=%d flags="LPX64
59 " extent="LPX64"-"LPX64
60 " gid="LPX64" refcount=%d canceled=%d\n",
61 prefix, PFID(&car->car_hai->hai_fid),
62 PFID(&car->car_hai->hai_dfid),
63 car->car_compound_id, car->car_hai->hai_cookie,
64 hsm_copytool_action2name(car->car_hai->hai_action),
65 car->car_archive_id, car->car_flags,
66 car->car_hai->hai_extent.offset,
67 car->car_hai->hai_extent.length,
68 car->car_hai->hai_gid,
69 cfs_atomic_read(&car->car_refcount),
72 up_read(&cdt->cdt_request_lock);
75 struct req_interval_data {
76 struct cdt_req_progress *crp;
81 * interval tree cb, used to go through all the tree of extent done
83 static enum interval_iter req_interval_cb(struct interval_node *node,
86 struct req_interval_data *data;
90 data->done_sz += node->in_extent.end - node->in_extent.start;
91 RETURN(INTERVAL_ITER_CONT);
95 * scan the interval tree associated to a request
96 * to compute the amount of work done
97 * \param car [IN] request
98 * \param done_sz [OUT] will be set to the size of work done
100 void mdt_cdt_get_work_done(struct cdt_agent_req *car, __u64 *done_sz)
102 struct req_interval_data rid;
103 struct cdt_req_progress *crp = &car->car_progress;
105 mutex_lock(&crp->crp_lock);
109 interval_iterate(crp->crp_root, req_interval_cb, &rid);
110 *done_sz = rid.done_sz;
112 mutex_unlock(&crp->crp_lock);
115 #define NODE_VECTOR_SZ 256
117 * free the interval tree associated to a request
119 static void mdt_cdt_free_request_tree(struct cdt_req_progress *crp)
121 struct interval_node *node, *vn;
125 mutex_lock(&crp->crp_lock);
127 if (crp->crp_max == 0)
130 /* remove all nodes from tree */
131 for (i = 0 ; i < crp->crp_cnt ; i++) {
132 vn = crp->crp_node[i / NODE_VECTOR_SZ];
133 node = &vn[i % NODE_VECTOR_SZ];
134 interval_erase(node, &crp->crp_root);
136 /* free all sub vectors */
137 for (i = 0 ; i <= crp->crp_max / NODE_VECTOR_SZ ; i++)
138 OBD_FREE(crp->crp_node[i],
139 NODE_VECTOR_SZ * sizeof(crp->crp_node[i][0]));
141 /* free main vector */
142 OBD_FREE(crp->crp_node,
143 sizeof(crp->crp_node[0]) *
144 (crp->crp_max / NODE_VECTOR_SZ + 1));
149 mutex_unlock(&crp->crp_lock);
154 * update data moved information during a request
156 static int mdt_cdt_update_work(struct cdt_req_progress *crp,
157 struct hsm_extent *extent)
160 struct interval_node **new_vv;
161 struct interval_node *v, *node;
164 mutex_lock(&crp->crp_lock);
167 if (crp->crp_cnt >= crp->crp_max) {
169 /* allocate a new vector */
170 OBD_ALLOC(v, NODE_VECTOR_SZ * sizeof(v[0]));
172 GOTO(out, rc = -ENOMEM);
174 if (crp->crp_max == 0)
177 osz = sizeof(new_vv[0]) *
178 (crp->crp_max / NODE_VECTOR_SZ + 1);
180 nsz = osz + sizeof(new_vv[0]);
181 /* increase main vector size */
182 OBD_ALLOC(new_vv, nsz);
183 if (new_vv == NULL) {
184 OBD_FREE(v, NODE_VECTOR_SZ * sizeof(v[0]));
185 GOTO(out, rc = -ENOMEM);
189 crp->crp_max = NODE_VECTOR_SZ - 1;
191 memcpy(new_vv, crp->crp_node, osz);
192 OBD_FREE(crp->crp_node, osz);
193 crp->crp_max += NODE_VECTOR_SZ;
196 crp->crp_node = new_vv;
197 crp->crp_node[crp->crp_max / NODE_VECTOR_SZ] = v;
200 v = crp->crp_node[crp->crp_cnt / NODE_VECTOR_SZ];
201 node = &v[crp->crp_cnt % NODE_VECTOR_SZ];
202 interval_set(node, extent->offset, extent->offset + extent->length);
203 /* try to insert, if entry already exist ignore the new one
204 * it can happen if ct sends 2 times the same progress */
205 if (interval_insert(node, &crp->crp_root) == NULL)
210 mutex_unlock(&crp->crp_lock);
215 * init the interval tree associated to a request
217 static void mdt_cdt_init_request_tree(struct cdt_req_progress *crp)
219 mutex_init(&crp->crp_lock);
220 crp->crp_root = NULL;
225 /** Allocate/init a agent request and its sub-structures.
227 * \param compound_id [IN]
228 * \param archive_id [IN]
232 * \retval car [OUT] success valid structure
235 struct cdt_agent_req *mdt_cdt_alloc_request(__u64 compound_id, __u32 archive_id,
236 __u64 flags, struct obd_uuid *uuid,
237 struct hsm_action_item *hai)
239 struct cdt_agent_req *car;
244 RETURN(ERR_PTR(-ENOMEM));
246 cfs_atomic_set(&car->car_refcount, 0);
247 car->car_compound_id = compound_id;
248 car->car_archive_id = archive_id;
249 car->car_flags = flags;
250 car->car_canceled = 0;
251 car->car_req_start = cfs_time_current_sec();
252 car->car_req_update = car->car_req_start;
253 car->car_uuid = *uuid;
254 OBD_ALLOC(car->car_hai, hai->hai_len);
255 if (car->car_hai == NULL) {
257 RETURN(ERR_PTR(-ENOMEM));
259 memcpy(car->car_hai, hai, hai->hai_len);
260 mdt_cdt_init_request_tree(&car->car_progress);
266 * Free a agent request and its sub-structures.
268 * \param car [IN] Request to be freed.
270 void mdt_cdt_free_request(struct cdt_agent_req *car)
272 mdt_cdt_free_request_tree(&car->car_progress);
273 OBD_FREE(car->car_hai, car->car_hai->hai_len);
278 * inc refcount of a request
279 * \param car [IN] request
281 void mdt_cdt_get_request(struct cdt_agent_req *car)
283 cfs_atomic_inc(&car->car_refcount);
287 * dec refcount of a request
288 * free if no more refcount
289 * \param car [IN] request
291 void mdt_cdt_put_request(struct cdt_agent_req *car)
293 if (cfs_atomic_dec_and_test(&car->car_refcount))
294 mdt_cdt_free_request(car);
298 * find request in the list by cookie or by fid
299 * lock cdt_request_lock needs to be hold by caller
300 * \param cdt [IN] coordinator
301 * \param cookie [IN] request cookie
302 * \param fid [IN] fid
303 * \retval request pointer
305 static struct cdt_agent_req *cdt_find_request_nolock(struct coordinator *cdt,
307 const struct lu_fid *fid)
310 struct cdt_agent_req *car;
313 if (cfs_list_empty(&cdt->cdt_requests))
316 cfs_list_for_each(pos, &cdt->cdt_requests) {
317 car = cfs_list_entry(pos, struct cdt_agent_req,
319 if ((car->car_hai->hai_cookie == cookie) ||
320 ((fid != NULL) && lu_fid_eq(fid, &car->car_hai->hai_fid))) {
321 mdt_cdt_get_request(car);
327 RETURN(ERR_PTR(-ENOENT));
331 * add a request to the list
332 * \param cdt [IN] coordinator
333 * \param car [IN] request
335 * \retval -ve failure
337 int mdt_cdt_add_request(struct coordinator *cdt, struct cdt_agent_req *new_car)
339 struct cdt_agent_req *car;
342 /* cancel requests are not kept in memory */
343 LASSERT(new_car->car_hai->hai_action != HSMA_CANCEL);
345 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 mdt_cdt_get_request(new_car);
355 cfs_list_add_tail(&new_car->car_request_list, &cdt->cdt_requests);
356 up_write(&cdt->cdt_request_lock);
358 mdt_hsm_agent_update_statistics(cdt, 0, 0, 1, &new_car->car_uuid);
360 down(&cdt->cdt_counter_lock);
361 cdt->cdt_request_count++;
362 up(&cdt->cdt_counter_lock);
368 * find request in the list by cookie or by fid
369 * \param cdt [IN] coordinator
370 * \param cookie [IN] request cookie
371 * \param fid [IN] fid
372 * \retval request pointer
374 struct cdt_agent_req *mdt_cdt_find_request(struct coordinator *cdt,
376 const struct lu_fid *fid)
378 struct cdt_agent_req *car;
381 down_read(&cdt->cdt_request_lock);
383 car = cdt_find_request_nolock(cdt, cookie, fid);
385 up_read(&cdt->cdt_request_lock);
391 * remove request from the list
392 * \param cdt [IN] coordinator
393 * \param cookie [IN] request cookie
394 * \retval request pointer
396 int mdt_cdt_remove_request(struct coordinator *cdt, __u64 cookie)
398 struct cdt_agent_req *car;
401 down_write(&cdt->cdt_request_lock);
403 car = cdt_find_request_nolock(cdt, cookie, NULL);
405 cfs_list_del(&car->car_request_list);
406 mdt_cdt_put_request(car);
407 up_write(&cdt->cdt_request_lock);
409 down(&cdt->cdt_counter_lock);
410 cdt->cdt_request_count--;
411 up(&cdt->cdt_counter_lock);
415 up_write(&cdt->cdt_request_lock);
421 * update a request in the list
422 * on success, add a ref to the request returned
423 * \param cdt [IN] coordinator
424 * \param pgs [IN] progression (cookie + extent + err)
425 * \retval request pointer
426 * \retval -ve failure
428 struct cdt_agent_req *mdt_cdt_update_request(struct coordinator *cdt,
429 struct hsm_progress_kernel *pgs)
431 struct cdt_agent_req *car;
435 car = mdt_cdt_find_request(cdt, pgs->hpk_cookie, NULL);
439 car->car_req_update = cfs_time_current_sec();
441 /* update progress done by copy tool */
442 if (pgs->hpk_errval == 0 && pgs->hpk_extent.length != 0) {
443 rc = mdt_cdt_update_work(&car->car_progress, &pgs->hpk_extent);
445 mdt_cdt_put_request(car);
450 if (pgs->hpk_flags & HP_FLAG_COMPLETED) {
451 if (pgs->hpk_errval != 0)
452 mdt_hsm_agent_update_statistics(cdt, 0, 1, 0,
455 mdt_hsm_agent_update_statistics(cdt, 1, 0, 0,
462 * seq_file method called to start access to /proc file
464 static void *mdt_hsm_request_proc_start(struct seq_file *s, loff_t *p)
466 struct mdt_device *mdt = s->private;
467 struct coordinator *cdt = &mdt->mdt_coordinator;
472 down_read(&cdt->cdt_request_lock);
474 if (cfs_list_empty(&cdt->cdt_requests))
478 RETURN(SEQ_START_TOKEN);
481 cfs_list_for_each(pos, &cdt->cdt_requests) {
490 * seq_file method called to get next item
491 * just returns NULL at eof
493 static void *mdt_hsm_request_proc_next(struct seq_file *s, void *v, loff_t *p)
495 struct mdt_device *mdt = s->private;
496 struct coordinator *cdt = &mdt->mdt_coordinator;
500 if (pos == SEQ_START_TOKEN)
501 pos = cdt->cdt_requests.next;
506 if (pos != &cdt->cdt_requests)
513 * display request data
515 static int mdt_hsm_request_proc_show(struct seq_file *s, void *v)
518 struct cdt_agent_req *car;
523 if (pos == SEQ_START_TOKEN)
526 car = cfs_list_entry(pos, struct cdt_agent_req, car_request_list);
527 mdt_cdt_get_work_done(car, &data_moved);
529 seq_printf(s, "fid="DFID" dfid="DFID
530 " compound/cookie="LPX64"/"LPX64
531 " action=%s archive#=%d flags="LPX64
532 " extent="LPX64"-"LPX64" gid="LPX64
533 " data=[%s] canceled=%d uuid=%s done="LPU64"%%\n",
534 PFID(&car->car_hai->hai_fid),
535 PFID(&car->car_hai->hai_dfid),
536 car->car_compound_id, car->car_hai->hai_cookie,
537 hsm_copytool_action2name(car->car_hai->hai_action),
538 car->car_archive_id, car->car_flags,
539 car->car_hai->hai_extent.offset,
540 car->car_hai->hai_extent.length,
541 car->car_hai->hai_gid,
542 hai_dump_data_field(car->car_hai, buf, sizeof(buf)),
543 car->car_canceled, obd_uuid2str(&car->car_uuid),
549 * seq_file method called to stop access to /proc file
551 static void mdt_hsm_request_proc_stop(struct seq_file *s, void *v)
553 struct mdt_device *mdt = s->private;
554 struct coordinator *cdt = &mdt->mdt_coordinator;
557 up_read(&cdt->cdt_request_lock);
562 /* hsm agent list proc functions */
563 static const struct seq_operations mdt_hsm_request_proc_ops = {
564 .start = mdt_hsm_request_proc_start,
565 .next = mdt_hsm_request_proc_next,
566 .show = mdt_hsm_request_proc_show,
567 .stop = mdt_hsm_request_proc_stop,
571 * public function called at open of /proc file to get
574 static int lprocfs_open_hsm_request(struct inode *inode, struct file *file)
580 if (LPROCFS_ENTRY_AND_CHECK(PDE(inode)))
583 rc = seq_open(file, &mdt_hsm_request_proc_ops);
588 s = file->private_data;
589 s->private = PDE(inode)->data;
594 /* methods to access hsm request list */
595 const struct file_operations mdt_hsm_request_fops = {
596 .owner = THIS_MODULE,
597 .open = lprocfs_open_hsm_request,
600 .release = lprocfs_seq_release,