Whamcloud - gitweb
New tag 2.12.56
[fs/lustre-release.git] / lustre / obdclass / lu_qos.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
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.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * This file is part of Lustre, http://www.lustre.org/
24  *
25  * lustre/obdclass/lu_qos.c
26  *
27  * Lustre QoS.
28  * These are the only exported functions, they provide some generic
29  * infrastructure for object allocation QoS
30  *
31  */
32
33 #define DEBUG_SUBSYSTEM S_CLASS
34
35 #include <linux/module.h>
36 #include <linux/list.h>
37 #include <linux/random.h>
38 #include <libcfs/libcfs.h>
39 #include <libcfs/libcfs_hash.h> /* hash_long() */
40 #include <libcfs/linux/linux-mem.h>
41 #include <obd_class.h>
42 #include <obd_support.h>
43 #include <lustre_disk.h>
44 #include <lustre_fid.h>
45 #include <lu_object.h>
46
47 /**
48  * Add a new target to Quality of Service (QoS) target table.
49  *
50  * Add a new MDT/OST target to the structure representing an OSS. Resort the
51  * list of known MDSs/OSSs by the number of MDTs/OSTs attached to each MDS/OSS.
52  * The MDS/OSS list is protected internally and no external locking is required.
53  *
54  * \param[in] qos               lu_qos data
55  * \param[in] ltd               target description
56  *
57  * \retval 0                    on success
58  * \retval -ENOMEM              on error
59  */
60 int lqos_add_tgt(struct lu_qos *qos, struct lu_tgt_desc *ltd)
61 {
62         struct lu_svr_qos *svr = NULL;
63         struct lu_svr_qos *tempsvr;
64         struct obd_export *exp = ltd->ltd_exp;
65         int found = 0;
66         __u32 id = 0;
67         int rc = 0;
68
69         ENTRY;
70
71         down_write(&qos->lq_rw_sem);
72         /*
73          * a bit hacky approach to learn NID of corresponding connection
74          * but there is no official API to access information like this
75          * with OSD API.
76          */
77         list_for_each_entry(svr, &qos->lq_svr_list, lsq_svr_list) {
78                 if (obd_uuid_equals(&svr->lsq_uuid,
79                                     &exp->exp_connection->c_remote_uuid)) {
80                         found++;
81                         break;
82                 }
83                 if (svr->lsq_id > id)
84                         id = svr->lsq_id;
85         }
86
87         if (!found) {
88                 OBD_ALLOC_PTR(svr);
89                 if (!svr)
90                         GOTO(out, rc = -ENOMEM);
91                 memcpy(&svr->lsq_uuid, &exp->exp_connection->c_remote_uuid,
92                        sizeof(svr->lsq_uuid));
93                 ++id;
94                 svr->lsq_id = id;
95         } else {
96                 /* Assume we have to move this one */
97                 list_del(&svr->lsq_svr_list);
98         }
99
100         svr->lsq_tgt_count++;
101         ltd->ltd_qos.ltq_svr = svr;
102
103         CDEBUG(D_OTHER, "add tgt %s to server %s (%d targets)\n",
104                obd_uuid2str(&ltd->ltd_uuid), obd_uuid2str(&svr->lsq_uuid),
105                svr->lsq_tgt_count);
106
107         /*
108          * Add sorted by # of tgts.  Find the first entry that we're
109          * bigger than...
110          */
111         list_for_each_entry(tempsvr, &qos->lq_svr_list, lsq_svr_list) {
112                 if (svr->lsq_tgt_count > tempsvr->lsq_tgt_count)
113                         break;
114         }
115         /*
116          * ...and add before it.  If we're the first or smallest, tempsvr
117          * points to the list head, and we add to the end.
118          */
119         list_add_tail(&svr->lsq_svr_list, &tempsvr->lsq_svr_list);
120
121         qos->lq_dirty = 1;
122         qos->lq_rr.lqr_dirty = 1;
123
124 out:
125         up_write(&qos->lq_rw_sem);
126         RETURN(rc);
127 }
128 EXPORT_SYMBOL(lqos_add_tgt);
129
130 /**
131  * Remove MDT/OST target from QoS table.
132  *
133  * Removes given MDT/OST target from QoS table and releases related
134  * MDS/OSS structure if no target remain on the MDS/OSS.
135  *
136  * \param[in] qos               lu_qos data
137  * \param[in] ltd               target description
138  *
139  * \retval 0                    on success
140  * \retval -ENOENT              if no server was found
141  */
142 int lqos_del_tgt(struct lu_qos *qos, struct lu_tgt_desc *ltd)
143 {
144         struct lu_svr_qos *svr;
145         int rc = 0;
146
147         ENTRY;
148
149         down_write(&qos->lq_rw_sem);
150         svr = ltd->ltd_qos.ltq_svr;
151         if (!svr)
152                 GOTO(out, rc = -ENOENT);
153
154         svr->lsq_tgt_count--;
155         if (svr->lsq_tgt_count == 0) {
156                 CDEBUG(D_OTHER, "removing server %s\n",
157                        obd_uuid2str(&svr->lsq_uuid));
158                 list_del(&svr->lsq_svr_list);
159                 ltd->ltd_qos.ltq_svr = NULL;
160                 OBD_FREE_PTR(svr);
161         }
162
163         qos->lq_dirty = 1;
164         qos->lq_rr.lqr_dirty = 1;
165 out:
166         up_write(&qos->lq_rw_sem);
167         RETURN(rc);
168 }
169 EXPORT_SYMBOL(lqos_del_tgt);
170
171 /**
172  * lu_prandom_u64_max - returns a pseudo-random u64 number in interval
173  * [0, ep_ro)
174  *
175  * \param[in] ep_ro     right open interval endpoint
176  *
177  * \retval a pseudo-random 64-bit number that is in interval [0, ep_ro).
178  */
179 u64 lu_prandom_u64_max(u64 ep_ro)
180 {
181         u64 rand = 0;
182
183         if (ep_ro) {
184 #if BITS_PER_LONG == 32
185                 /*
186                  * If ep_ro > 32-bit, first generate the high
187                  * 32 bits of the random number, then add in the low
188                  * 32 bits (truncated to the upper limit, if needed)
189                  */
190                 if (ep_ro > 0xffffffffULL)
191                         rand = prandom_u32_max((u32)(ep_ro >> 32)) << 32;
192
193                 if (rand == (ep_ro & 0xffffffff00000000ULL))
194                         rand |= prandom_u32_max((u32)ep_ro);
195                 else
196                         rand |= prandom_u32();
197 #else
198                 rand = ((u64)prandom_u32() << 32 | prandom_u32()) % ep_ro;
199 #endif
200         }
201
202         return rand;
203 }
204 EXPORT_SYMBOL(lu_prandom_u64_max);