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