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