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, 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).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 021110-1307, USA
24 * Copyright (c) 2012 Whamcloud, Inc.
25 * Use is subject to license terms.
27 * Author: Johann Lombardi <johann@whamcloud.com>
28 * Author: Niu Yawei <niu@whamcloud.com>
32 * Quota Slave Driver (QSD) management.
36 # define EXPORT_SYMTAB
39 #define DEBUG_SUBSYSTEM S_LQUOTA
41 #include "qsd_internal.h"
43 /* some procfs helpers */
44 static int lprocfs_qsd_rd_state(char *page, char **start, off_t off,
45 int count, int *eof, void *data)
47 struct qsd_instance *qsd = (struct qsd_instance *)data;
51 return snprintf(page, count,
55 "quota enabled: none\n",
56 qsd->qsd_svname, qsd->qsd_pool_id,
57 qsd->qsd_is_md ? "md" : "dt");
60 static struct lprocfs_vars lprocfs_quota_qsd_vars[] = {
61 { "info", lprocfs_qsd_rd_state, 0, 0},
66 * Release qsd_qtype_info structure which contains data associated with a
67 * given quota type. This releases the accounting objects.
68 * It's called on OSD cleanup when the qsd instance is released.
70 * \param env - is the environment passed by the caller
71 * \param qsd - is the qsd instance managing the qsd_qtype_info structure
73 * \param qtype - is the quota type to be shutdown
75 static void qsd_qtype_fini(const struct lu_env *env, struct qsd_instance *qsd,
78 struct qsd_qtype_info *qqi;
81 if (qsd->qsd_type_array[qtype] == NULL)
83 qqi = qsd->qsd_type_array[qtype];
84 qsd->qsd_type_array[qtype] = NULL;
86 /* release accounting object */
87 if (qqi->qqi_acct_obj != NULL && !IS_ERR(qqi->qqi_acct_obj)) {
88 lu_object_put(env, &qqi->qqi_acct_obj->do_lu);
89 qqi->qqi_acct_obj = NULL;
92 /* release slv index */
93 if (qqi->qqi_slv_obj != NULL && !IS_ERR(qqi->qqi_slv_obj)) {
94 lu_object_put(env, &qqi->qqi_slv_obj->do_lu);
95 qqi->qqi_slv_obj = NULL;
99 /* release global index */
100 if (qqi->qqi_glb_obj != NULL && !IS_ERR(qqi->qqi_glb_obj)) {
101 lu_object_put(env, &qqi->qqi_glb_obj->do_lu);
102 qqi->qqi_glb_obj = NULL;
103 qqi->qqi_glb_ver = 0;
111 * Allocate and initialize a qsd_qtype_info structure for quota type \qtype.
112 * This opens the accounting object and initializes the proc file.
113 * It's called on OSD start when the qsd instance is created.
115 * \param env - the environment passed by the caller
116 * \param qsd - is the qsd instance which will be in charge of the new
117 * qsd_qtype_info instance.
118 * \param qtype - is quota type to set up
120 * \retval - 0 on success and qsd->qsd_type_array[qtype] is allocated,
121 * appropriate error on failure
123 static int qsd_qtype_init(const struct lu_env *env, struct qsd_instance *qsd,
126 struct qsd_qtype_info *qqi;
128 struct obd_uuid uuid;
131 LASSERT(qsd->qsd_type_array[qtype] == NULL);
133 /* allocate structure for this quota type */
137 qsd->qsd_type_array[qtype] = qqi;
139 /* set backpointer and other parameters */
141 qqi->qqi_qtype = qtype;
142 lquota_generate_fid(&qqi->qqi_fid, qsd->qsd_pool_id, QSD_RES_TYPE(qsd),
145 /* open accounting object */
146 LASSERT(qqi->qqi_acct_obj == NULL);
147 qqi->qqi_acct_obj = acct_obj_lookup(env, qsd->qsd_dev,
148 qtype == USRQUOTA ? ACCT_USER_OID
150 /* don't print any error message on failure in order not to confuse
151 * non-OFD user (e.g. 2.3 MDT stack) */
152 if (IS_ERR(qqi->qqi_acct_obj))
153 qqi->qqi_acct_obj = NULL;
155 /* open global index copy */
156 LASSERT(qqi->qqi_glb_obj == NULL);
157 qqi->qqi_glb_obj = lquota_disk_glb_find_create(env, qsd->qsd_dev,
159 &qqi->qqi_fid, true);
160 if (IS_ERR(qqi->qqi_glb_obj)) {
161 CERROR("%s: can't open global index copy "DFID" %ld\n",
162 qsd->qsd_svname, PFID(&qqi->qqi_fid),
163 PTR_ERR(qqi->qqi_glb_obj));
164 GOTO(out, rc = PTR_ERR(qqi->qqi_glb_obj));
166 qqi->qqi_glb_ver = dt_version_get(env, qqi->qqi_glb_obj);
168 /* open slave index copy */
169 LASSERT(qqi->qqi_slv_obj == NULL);
170 obd_str2uuid(&uuid, qsd->qsd_svname);
171 qqi->qqi_slv_obj = lquota_disk_slv_find_create(env, qsd->qsd_dev,
173 &qqi->qqi_fid, &uuid,
175 if (IS_ERR(qqi->qqi_slv_obj)) {
176 CERROR("%s: can't open slave index copy "DFID" %ld\n",
177 qsd->qsd_svname, PFID(&qqi->qqi_fid),
178 PTR_ERR(qqi->qqi_slv_obj));
179 GOTO(out, rc = PTR_ERR(qqi->qqi_slv_obj));
181 qqi->qqi_slv_ver = dt_version_get(env, qqi->qqi_slv_obj);
183 /* register proc entry for accounting object */
184 rc = lprocfs_seq_create(qsd->qsd_proc,
185 qtype == USRQUOTA ? "acct_user" : "acct_group",
186 0444, &lprocfs_quota_seq_fops,
189 CWARN("%s: can't add procfs entry for accounting file %d\n",
190 qsd->qsd_svname, rc);
197 qsd_qtype_fini(env, qsd, qtype);
202 * Release a qsd_instance. Companion of qsd_init(). This releases all data
203 * structures associated with the quota slave.
204 * This function should be called when the OSD is shutting down.
206 * \param env - is the environment passed by the caller
207 * \param qsd - is the qsd instance to shutdown
209 void qsd_fini(const struct lu_env *env, struct qsd_instance *qsd)
214 CDEBUG(D_QUOTA, "%s: initiating QSD shutdown\n", qsd->qsd_svname);
215 qsd->qsd_stopping = true;
217 /* remove qsd proc entry */
218 if (qsd->qsd_proc != NULL && !IS_ERR(qsd->qsd_proc)) {
219 lprocfs_remove(&qsd->qsd_proc);
220 qsd->qsd_proc = NULL;
223 /* free per-quota type data */
224 for (qtype = USRQUOTA; qtype < MAXQUOTAS; qtype++)
225 qsd_qtype_fini(env, qsd, qtype);
227 /* release quota root directory */
228 if (qsd->qsd_root != NULL && !IS_ERR(qsd->qsd_root)) {
229 lu_object_put(env, &qsd->qsd_root->do_lu);
230 qsd->qsd_root = NULL;
233 /* release reference on dt_device */
234 if (qsd->qsd_dev != NULL) {
235 lu_ref_del(&qsd->qsd_dev->dd_lu_dev.ld_reference, "qsd", qsd);
236 lu_device_put(&qsd->qsd_dev->dd_lu_dev);
243 EXPORT_SYMBOL(qsd_fini);
246 * Create a new qsd_instance to be associated with backend osd device
247 * identified by \dev. For now, this function just create procfs files which
248 * dumps the accounting information
250 * \param env - the environment passed by the caller
251 * \param svname - is the service name of the OSD device creating this instance
252 * \param dev - is the dt_device where to store quota index files
253 * \param osd_proc - is the procfs parent directory where to create procfs file
254 * related to this new qsd instance
256 * \retval - pointer to new qsd_instance associated with dev \dev on success,
257 * appropriate error on failure
259 struct qsd_instance *qsd_init(const struct lu_env *env, char *svname,
260 struct dt_device *dev,
261 cfs_proc_dir_entry_t *osd_proc)
263 struct qsd_instance *qsd;
267 /* allocate qsd instance */
270 RETURN(ERR_PTR(-ENOMEM));
272 /* copy service name */
273 strncpy(qsd->qsd_svname, svname, MAX_OBD_NAME);
275 /* grab reference on osd device */
276 lu_device_get(&dev->dd_lu_dev);
277 lu_ref_add(&dev->dd_lu_dev.ld_reference, "qsd", qsd);
280 /* we only support pool ID 0 (default data or metadata pool) for the
281 * time being. A different pool ID could be assigned to this target via
282 * the configuration log in the future */
283 qsd->qsd_pool_id = 0;
285 /* Record whether this qsd instance is managing quota enforcement for a
286 * MDT (i.e. inode quota) or OST (block quota) */
287 qsd->qsd_is_md = lu_device_is_md(dev->dd_lu_dev.ld_site->ls_top_dev);
289 /* look-up on-disk directory for the quota slave */
290 qsd->qsd_root = lquota_disk_dir_find_create(env, dev, NULL, QSD_DIR);
291 if (IS_ERR(qsd->qsd_root)) {
292 rc = PTR_ERR(qsd->qsd_root);
293 CERROR("%s: failed to create quota slave root dir (%d)\n",
298 /* register procfs directory */
299 qsd->qsd_proc = lprocfs_register(QSD_DIR, osd_proc,
300 lprocfs_quota_qsd_vars, qsd);
301 if (IS_ERR(qsd->qsd_proc)) {
302 rc = PTR_ERR(qsd->qsd_proc);
303 CERROR("%s: fail to create quota slave proc entry (%d)\n",
308 /* initialize per-quota type data */
309 for (qtype = USRQUOTA; qtype < MAXQUOTAS; qtype++) {
310 rc = qsd_qtype_init(env, qsd, qtype);
321 EXPORT_SYMBOL(qsd_init);