Whamcloud - gitweb
0ba8622da5314423bfbbcad9fc90f15cfc588204
[fs/lustre-release.git] / lustre / quota / qsd_lib.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, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 021110-1307, USA
20  *
21  * GPL HEADER END
22  */
23 /*
24  * Copyright (c) 2012 Whamcloud, Inc.
25  * Use is subject to license terms.
26  *
27  * Author: Johann Lombardi <johann@whamcloud.com>
28  * Author: Niu    Yawei    <niu@whamcloud.com>
29  */
30
31 /*
32  * Quota Slave Driver (QSD) management.
33  */
34
35 #ifndef EXPORT_SYMTAB
36 # define EXPORT_SYMTAB
37 #endif
38
39 #define DEBUG_SUBSYSTEM S_LQUOTA
40
41 #include "qsd_internal.h"
42
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)
46 {
47         struct qsd_instance     *qsd = (struct qsd_instance *)data;
48
49         LASSERT(qsd != NULL);
50
51         return snprintf(page, count,
52                         "target name:    %s\n"
53                         "quota enabled:  none\n",
54                         qsd->qsd_svname);
55 }
56
57 static struct lprocfs_vars lprocfs_quota_qsd_vars[] = {
58         { "info", lprocfs_qsd_rd_state, 0, 0},
59         { NULL }
60 };
61
62 /*
63  * Release qsd_qtype_info structure which contains data associated with a
64  * given quota type. This releases the accounting objects.
65  * It's called on OSD cleanup when the qsd instance is released.
66  *
67  * \param env - is the environment passed by the caller
68  * \param qsd - is the qsd instance managing the qsd_qtype_info structure
69  *              to be released
70  * \param qtype - is the quota type to be shutdown
71  */
72 static void qsd_qtype_fini(const struct lu_env *env, struct qsd_instance *qsd,
73                            int qtype)
74 {
75         struct qsd_qtype_info   *qqi;
76         ENTRY;
77
78         if (qsd->qsd_type_array[qtype] == NULL)
79                 RETURN_EXIT;
80         qqi = qsd->qsd_type_array[qtype];
81         qsd->qsd_type_array[qtype] = NULL;
82
83         /* release accounting object */
84         if (qqi->qqi_acct_obj != NULL && !IS_ERR(qqi->qqi_acct_obj)) {
85                 lu_object_put(env, &qqi->qqi_acct_obj->do_lu);
86                 qqi->qqi_acct_obj = NULL;
87         }
88
89         OBD_FREE_PTR(qqi);
90         EXIT;
91 }
92
93 /*
94  * Allocate and initialize a qsd_qtype_info structure for quota type \qtype.
95  * This opens the accounting object and initializes the proc file.
96  * It's called on OSD start when the qsd instance is created.
97  *
98  * \param env  - the environment passed by the caller
99  * \param qsd  - is the qsd instance which will be in charge of the new
100  *               qsd_qtype_info instance.
101  * \param qtype - is quota type to set up
102  *
103  * \retval - 0 on success and qsd->qsd_type_array[qtype] is allocated,
104  *           appropriate error on failure
105  */
106 static int qsd_qtype_init(const struct lu_env *env, struct qsd_instance *qsd,
107                           int qtype)
108 {
109         struct qsd_qtype_info   *qqi;
110         int                      rc;
111         ENTRY;
112
113         LASSERT(qsd->qsd_type_array[qtype] == NULL);
114
115         /* allocate structure for this quota type */
116         OBD_ALLOC_PTR(qqi);
117         if (qqi == NULL)
118                 RETURN(-ENOMEM);
119         qsd->qsd_type_array[qtype] = qqi;
120
121         /* set backpointer and other parameters */
122         qqi->qqi_qsd   = qsd;
123         qqi->qqi_qtype = qtype;
124
125         /* open accounting object */
126         LASSERT(qqi->qqi_acct_obj == NULL);
127         qqi->qqi_acct_obj = acct_obj_lookup(env, qsd->qsd_dev,
128                                             qtype == USRQUOTA ? ACCT_USER_OID
129                                                               : ACCT_GROUP_OID);
130         /* don't print any error message on failure in order not to confuse
131          * non-OFD user (e.g. 2.3 MDT stack) */
132         if (IS_ERR(qqi->qqi_acct_obj))
133                 qqi->qqi_acct_obj = NULL;
134
135         /* register proc entry for accounting object */
136         rc = lprocfs_seq_create(qsd->qsd_proc,
137                                 qtype == USRQUOTA ? "acct_user" : "acct_group",
138                                 0444, &lprocfs_quota_seq_fops,
139                                 qqi->qqi_acct_obj);
140         if (rc) {
141                 CWARN("%s: can't add procfs entry for accounting file %d\n",
142                       qsd->qsd_svname, rc);
143                 GOTO(out, rc);
144         }
145
146         EXIT;
147 out:
148         if (rc)
149                 qsd_qtype_fini(env, qsd, qtype);
150         return rc;
151 }
152
153 /*
154  * Release a qsd_instance. Companion of qsd_init(). This releases all data
155  * structures associated with the quota slave.
156  * This function should be called when the OSD is shutting down.
157  *
158  * \param env - is the environment passed by the caller
159  * \param qsd - is the qsd instance to shutdown
160  */
161 void qsd_fini(const struct lu_env *env, struct qsd_instance *qsd)
162 {
163         int     qtype;
164         ENTRY;
165
166         /* remove qsd proc entry */
167         if (qsd->qsd_proc != NULL && !IS_ERR(qsd->qsd_proc)) {
168                 lprocfs_remove(&qsd->qsd_proc);
169                 qsd->qsd_proc = NULL;
170         }
171
172         /* free per-quota type data */
173         for (qtype = USRQUOTA; qtype < MAXQUOTAS; qtype++)
174                 qsd_qtype_fini(env, qsd, qtype);
175
176         /* release reference on dt_device */
177         if (qsd->qsd_dev != NULL) {
178                 lu_ref_del(&qsd->qsd_dev->dd_lu_dev.ld_reference, "qsd", qsd);
179                 lu_device_put(&qsd->qsd_dev->dd_lu_dev);
180                 qsd->qsd_dev = NULL;
181         }
182
183         OBD_FREE_PTR(qsd);
184         EXIT;
185 }
186 EXPORT_SYMBOL(qsd_fini);
187
188 /*
189  * Create a new qsd_instance to be associated with backend osd device
190  * identified by \dev. For now, this function just create procfs files which
191  * dumps the accounting information
192  *
193  * \param env    - the environment passed by the caller
194  * \param svname - is the service name of the OSD device creating this instance
195  * \param dev    - is the dt_device where to store quota index files
196  * \param osd_proc - is the procfs parent directory where to create procfs file
197  *                   related to this new qsd instance
198  *
199  * \retval - pointer to new qsd_instance associated with dev \dev on success,
200  *           appropriate error on failure
201  */
202 struct qsd_instance *qsd_init(const struct lu_env *env, char *svname,
203                               struct dt_device *dev,
204                               cfs_proc_dir_entry_t *osd_proc)
205 {
206         struct qsd_instance     *qsd;
207         int                      rc, qtype;
208         ENTRY;
209
210         /* allocate qsd instance */
211         OBD_ALLOC_PTR(qsd);
212         if (qsd == NULL)
213                 RETURN(ERR_PTR(-ENOMEM));
214
215         /* copy service name */
216         strncpy(qsd->qsd_svname, svname, MAX_OBD_NAME);
217
218         /* grab reference on osd device */
219         lu_device_get(&dev->dd_lu_dev);
220         lu_ref_add(&dev->dd_lu_dev.ld_reference, "qsd", qsd);
221         qsd->qsd_dev = dev;
222
223         /* register procfs directory */
224         qsd->qsd_proc = lprocfs_register(QSD_DIR, osd_proc,
225                                          lprocfs_quota_qsd_vars, qsd);
226         if (IS_ERR(qsd->qsd_proc)) {
227                 rc = PTR_ERR(qsd->qsd_proc);
228                 CERROR("%s: fail to create quota slave proc entry (%d)\n",
229                        svname, rc);
230                 GOTO(out, rc);
231         }
232
233         /* initialize per-quota type data */
234         for (qtype = USRQUOTA; qtype < MAXQUOTAS; qtype++) {
235                 rc = qsd_qtype_init(env, qsd, qtype);
236                 if (rc)
237                         GOTO(out, rc);
238         }
239 out:
240         if (rc) {
241                 qsd_fini(env, qsd);
242                 return ERR_PTR(rc);
243         }
244         RETURN(qsd);
245 }
246 EXPORT_SYMBOL(qsd_init);