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