]> Pileus Git - ~andy/linux/blob - drivers/staging/lustre/lustre/obdclass/llog_ioctl.c
Linux 3.14
[~andy/linux] / drivers / staging / lustre / lustre / obdclass / llog_ioctl.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.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2011, 2012, Intel Corporation.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  */
36
37 #define DEBUG_SUBSYSTEM S_LOG
38
39 #include <obd_class.h>
40 #include <lustre_log.h>
41 #include "llog_internal.h"
42
43 static int str2logid(struct llog_logid *logid, char *str, int len)
44 {
45         char *start, *end, *endp;
46         __u64 id, seq;
47
48         start = str;
49         if (*start != '#')
50                 return -EINVAL;
51
52         start++;
53         if (start - str >= len - 1)
54                 return -EINVAL;
55         end = strchr(start, '#');
56         if (end == NULL || end == start)
57                 return -EINVAL;
58
59         *end = '\0';
60         id = simple_strtoull(start, &endp, 0);
61         if (endp != end)
62                 return -EINVAL;
63
64         start = ++end;
65         if (start - str >= len - 1)
66                 return -EINVAL;
67         end = strchr(start, '#');
68         if (end == NULL || end == start)
69                 return -EINVAL;
70
71         *end = '\0';
72         seq = simple_strtoull(start, &endp, 0);
73         if (endp != end)
74                 return -EINVAL;
75
76         ostid_set_seq(&logid->lgl_oi, seq);
77         ostid_set_id(&logid->lgl_oi, id);
78
79         start = ++end;
80         if (start - str >= len - 1)
81                 return -EINVAL;
82         logid->lgl_ogen = simple_strtoul(start, &endp, 16);
83         if (*endp != '\0')
84                 return -EINVAL;
85
86         return 0;
87 }
88
89 static int llog_check_cb(const struct lu_env *env, struct llog_handle *handle,
90                          struct llog_rec_hdr *rec, void *data)
91 {
92         struct obd_ioctl_data *ioc_data = (struct obd_ioctl_data *)data;
93         static int l, remains, from, to;
94         static char *out;
95         char *endp;
96         int cur_index, rc = 0;
97
98         if (ioc_data && ioc_data->ioc_inllen1 > 0) {
99                 l = 0;
100                 remains = ioc_data->ioc_inllen4 +
101                         cfs_size_round(ioc_data->ioc_inllen1) +
102                         cfs_size_round(ioc_data->ioc_inllen2) +
103                         cfs_size_round(ioc_data->ioc_inllen3);
104                 from = simple_strtol(ioc_data->ioc_inlbuf2, &endp, 0);
105                 if (*endp != '\0')
106                         return -EINVAL;
107                 to = simple_strtol(ioc_data->ioc_inlbuf3, &endp, 0);
108                 if (*endp != '\0')
109                         return -EINVAL;
110                 ioc_data->ioc_inllen1 = 0;
111                 out = ioc_data->ioc_bulk;
112         }
113
114         cur_index = rec->lrh_index;
115         if (cur_index < from)
116                 return 0;
117         if (to > 0 && cur_index > to)
118                 return -LLOG_EEMPTY;
119
120         if (handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT) {
121                 struct llog_logid_rec   *lir = (struct llog_logid_rec *)rec;
122                 struct llog_handle      *loghandle;
123
124                 if (rec->lrh_type != LLOG_LOGID_MAGIC) {
125                         l = snprintf(out, remains, "[index]: %05d  [type]: "
126                                      "%02x  [len]: %04d failed\n",
127                                      cur_index, rec->lrh_type,
128                                      rec->lrh_len);
129                 }
130                 if (handle->lgh_ctxt == NULL)
131                         return -EOPNOTSUPP;
132                 rc = llog_cat_id2handle(env, handle, &loghandle, &lir->lid_id);
133                 if (rc) {
134                         CDEBUG(D_IOCTL, "cannot find log #"DOSTID"#%08x\n",
135                                POSTID(&lir->lid_id.lgl_oi),
136                                lir->lid_id.lgl_ogen);
137                         return rc;
138                 }
139                 rc = llog_process(env, loghandle, llog_check_cb, NULL, NULL);
140                 llog_handle_put(loghandle);
141         } else {
142                 bool ok;
143
144                 switch (rec->lrh_type) {
145                 case OST_SZ_REC:
146                 case MDS_UNLINK_REC:
147                 case MDS_UNLINK64_REC:
148                 case MDS_SETATTR64_REC:
149                 case OBD_CFG_REC:
150                 case LLOG_GEN_REC:
151                 case LLOG_HDR_MAGIC:
152                         ok = true;
153                         break;
154                 default:
155                         ok = false;
156                 }
157
158                 l = snprintf(out, remains, "[index]: %05d  [type]: "
159                              "%02x  [len]: %04d %s\n",
160                              cur_index, rec->lrh_type, rec->lrh_len,
161                              ok ? "ok" : "failed");
162                 out += l;
163                 remains -= l;
164                 if (remains <= 0) {
165                         CERROR("%s: no space to print log records\n",
166                                handle->lgh_ctxt->loc_obd->obd_name);
167                         return -LLOG_EEMPTY;
168                 }
169         }
170         return rc;
171 }
172
173 static int llog_print_cb(const struct lu_env *env, struct llog_handle *handle,
174                          struct llog_rec_hdr *rec, void *data)
175 {
176         struct obd_ioctl_data *ioc_data = (struct obd_ioctl_data *)data;
177         static int l, remains, from, to;
178         static char *out;
179         char *endp;
180         int cur_index;
181
182         if (ioc_data != NULL && ioc_data->ioc_inllen1 > 0) {
183                 l = 0;
184                 remains = ioc_data->ioc_inllen4 +
185                         cfs_size_round(ioc_data->ioc_inllen1) +
186                         cfs_size_round(ioc_data->ioc_inllen2) +
187                         cfs_size_round(ioc_data->ioc_inllen3);
188                 from = simple_strtol(ioc_data->ioc_inlbuf2, &endp, 0);
189                 if (*endp != '\0')
190                         return -EINVAL;
191                 to = simple_strtol(ioc_data->ioc_inlbuf3, &endp, 0);
192                 if (*endp != '\0')
193                         return -EINVAL;
194                 out = ioc_data->ioc_bulk;
195                 ioc_data->ioc_inllen1 = 0;
196         }
197
198         cur_index = rec->lrh_index;
199         if (cur_index < from)
200                 return 0;
201         if (to > 0 && cur_index > to)
202                 return -LLOG_EEMPTY;
203
204         if (handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT) {
205                 struct llog_logid_rec *lir = (struct llog_logid_rec *)rec;
206
207                 if (rec->lrh_type != LLOG_LOGID_MAGIC) {
208                         CERROR("invalid record in catalog\n");
209                         return -EINVAL;
210                 }
211
212                 l = snprintf(out, remains,
213                              "[index]: %05d  [logid]: #"DOSTID"#%08x\n",
214                              cur_index, POSTID(&lir->lid_id.lgl_oi),
215                              lir->lid_id.lgl_ogen);
216         } else if (rec->lrh_type == OBD_CFG_REC) {
217                 int rc;
218
219                 rc = class_config_parse_rec(rec, out, remains);
220                 if (rc < 0)
221                         return rc;
222                 l = rc;
223         } else {
224                 l = snprintf(out, remains,
225                              "[index]: %05d  [type]: %02x  [len]: %04d\n",
226                              cur_index, rec->lrh_type, rec->lrh_len);
227         }
228         out += l;
229         remains -= l;
230         if (remains <= 0) {
231                 CERROR("not enough space for print log records\n");
232                 return -LLOG_EEMPTY;
233         }
234
235         return 0;
236 }
237 static int llog_remove_log(const struct lu_env *env, struct llog_handle *cat,
238                            struct llog_logid *logid)
239 {
240         struct llog_handle      *log;
241         int                      rc;
242
243         rc = llog_cat_id2handle(env, cat, &log, logid);
244         if (rc) {
245                 CDEBUG(D_IOCTL, "cannot find log #"DOSTID"#%08x\n",
246                        POSTID(&logid->lgl_oi), logid->lgl_ogen);
247                 return -ENOENT;
248         }
249
250         rc = llog_destroy(env, log);
251         if (rc) {
252                 CDEBUG(D_IOCTL, "cannot destroy log\n");
253                 GOTO(out, rc);
254         }
255         llog_cat_cleanup(env, cat, log, log->u.phd.phd_cookie.lgc_index);
256 out:
257         llog_handle_put(log);
258         return rc;
259
260 }
261
262 static int llog_delete_cb(const struct lu_env *env, struct llog_handle *handle,
263                           struct llog_rec_hdr *rec, void *data)
264 {
265         struct llog_logid_rec   *lir = (struct llog_logid_rec *)rec;
266         int                      rc;
267
268         if (rec->lrh_type != LLOG_LOGID_MAGIC)
269                 return -EINVAL;
270         rc = llog_remove_log(env, handle, &lir->lid_id);
271
272         return rc;
273 }
274
275
276 int llog_ioctl(const struct lu_env *env, struct llog_ctxt *ctxt, int cmd,
277                struct obd_ioctl_data *data)
278 {
279         struct llog_logid        logid;
280         int                      rc = 0;
281         struct llog_handle      *handle = NULL;
282
283         if (*data->ioc_inlbuf1 == '#') {
284                 rc = str2logid(&logid, data->ioc_inlbuf1, data->ioc_inllen1);
285                 if (rc)
286                         return rc;
287                 rc = llog_open(env, ctxt, &handle, &logid, NULL,
288                                LLOG_OPEN_EXISTS);
289                 if (rc)
290                         return rc;
291         } else if (*data->ioc_inlbuf1 == '$') {
292                 char *name = data->ioc_inlbuf1 + 1;
293
294                 rc = llog_open(env, ctxt, &handle, NULL, name,
295                                LLOG_OPEN_EXISTS);
296                 if (rc)
297                         return rc;
298         } else {
299                 return -EINVAL;
300         }
301
302         rc = llog_init_handle(env, handle, 0, NULL);
303         if (rc)
304                 GOTO(out_close, rc = -ENOENT);
305
306         switch (cmd) {
307         case OBD_IOC_LLOG_INFO: {
308                 int      l;
309                 int      remains = data->ioc_inllen2 +
310                                    cfs_size_round(data->ioc_inllen1);
311                 char    *out = data->ioc_bulk;
312
313                 l = snprintf(out, remains,
314                              "logid:        #"DOSTID"#%08x\n"
315                              "flags:        %x (%s)\n"
316                              "records count:    %d\n"
317                              "last index:       %d\n",
318                              POSTID(&handle->lgh_id.lgl_oi),
319                              handle->lgh_id.lgl_ogen,
320                              handle->lgh_hdr->llh_flags,
321                              handle->lgh_hdr->llh_flags &
322                              LLOG_F_IS_CAT ? "cat" : "plain",
323                              handle->lgh_hdr->llh_count,
324                              handle->lgh_last_idx);
325                 out += l;
326                 remains -= l;
327                 if (remains <= 0) {
328                         CERROR("%s: not enough space for log header info\n",
329                                ctxt->loc_obd->obd_name);
330                         rc = -ENOSPC;
331                 }
332                 break;
333         }
334         case OBD_IOC_LLOG_CHECK:
335                 LASSERT(data->ioc_inllen1 > 0);
336                 rc = llog_process(env, handle, llog_check_cb, data, NULL);
337                 if (rc == -LLOG_EEMPTY)
338                         rc = 0;
339                 else if (rc)
340                         GOTO(out_close, rc);
341                 break;
342         case OBD_IOC_LLOG_PRINT:
343                 LASSERT(data->ioc_inllen1 > 0);
344                 rc = llog_process(env, handle, llog_print_cb, data, NULL);
345                 if (rc == -LLOG_EEMPTY)
346                         rc = 0;
347                 else if (rc)
348                         GOTO(out_close, rc);
349                 break;
350         case OBD_IOC_LLOG_CANCEL: {
351                 struct llog_cookie cookie;
352                 struct llog_logid plain;
353                 char *endp;
354
355                 cookie.lgc_index = simple_strtoul(data->ioc_inlbuf3, &endp, 0);
356                 if (*endp != '\0')
357                         GOTO(out_close, rc = -EINVAL);
358
359                 if (handle->lgh_hdr->llh_flags & LLOG_F_IS_PLAIN) {
360                         rc = llog_cancel_rec(NULL, handle, cookie.lgc_index);
361                         GOTO(out_close, rc);
362                 } else if (!(handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT)) {
363                         GOTO(out_close, rc = -EINVAL);
364                 }
365
366                 if (data->ioc_inlbuf2 == NULL) /* catalog but no logid */
367                         GOTO(out_close, rc = -ENOTTY);
368
369                 rc = str2logid(&plain, data->ioc_inlbuf2, data->ioc_inllen2);
370                 if (rc)
371                         GOTO(out_close, rc);
372                 cookie.lgc_lgl = plain;
373                 rc = llog_cat_cancel_records(env, handle, 1, &cookie);
374                 if (rc)
375                         GOTO(out_close, rc);
376                 break;
377         }
378         case OBD_IOC_LLOG_REMOVE: {
379                 struct llog_logid plain;
380
381                 if (handle->lgh_hdr->llh_flags & LLOG_F_IS_PLAIN) {
382                         rc = llog_destroy(env, handle);
383                         GOTO(out_close, rc);
384                 } else if (!(handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT)) {
385                         GOTO(out_close, rc = -EINVAL);
386                 }
387
388                 if (data->ioc_inlbuf2 > 0) {
389                         /* remove indicate log from the catalog */
390                         rc = str2logid(&plain, data->ioc_inlbuf2,
391                                        data->ioc_inllen2);
392                         if (rc)
393                                 GOTO(out_close, rc);
394                         rc = llog_remove_log(env, handle, &plain);
395                 } else {
396                         /* remove all the log of the catalog */
397                         rc = llog_process(env, handle, llog_delete_cb, NULL,
398                                           NULL);
399                         if (rc)
400                                 GOTO(out_close, rc);
401                 }
402                 break;
403         }
404         default:
405                 CERROR("%s: Unknown ioctl cmd %#x\n",
406                        ctxt->loc_obd->obd_name, cmd);
407                 GOTO(out_close, rc = -ENOTTY);
408         }
409
410 out_close:
411         if (handle->lgh_hdr &&
412             handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT)
413                 llog_cat_close(env, handle);
414         else
415                 llog_close(env, handle);
416         return rc;
417 }
418 EXPORT_SYMBOL(llog_ioctl);