Whamcloud - gitweb
LU-1866 lfsck: enhance otable-based iteration
[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, 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
47         ENTRY;
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         logid->lgl_oid = 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         logid->lgl_oseq = simple_strtoull(start, &endp, 0);
73         if (endp != end)
74                 RETURN(-EINVAL);
75
76         start = ++end;
77         if (start - str >= len - 1)
78                 RETURN(-EINVAL);
79         logid->lgl_ogen = simple_strtoul(start, &endp, 16);
80         if (*endp != '\0')
81                 RETURN(-EINVAL);
82
83         RETURN(0);
84 }
85
86 static int llog_check_cb(const struct lu_env *env, struct llog_handle *handle,
87                          struct llog_rec_hdr *rec, void *data)
88 {
89         struct obd_ioctl_data *ioc_data = (struct obd_ioctl_data *)data;
90         static int l, remains, from, to;
91         static char *out;
92         char *endp;
93         int cur_index, rc = 0;
94
95         ENTRY;
96
97         if (ioc_data && ioc_data->ioc_inllen1 > 0) {
98                 l = 0;
99                 remains = ioc_data->ioc_inllen4 +
100                         cfs_size_round(ioc_data->ioc_inllen1) +
101                         cfs_size_round(ioc_data->ioc_inllen2) +
102                         cfs_size_round(ioc_data->ioc_inllen3);
103                 from = simple_strtol(ioc_data->ioc_inlbuf2, &endp, 0);
104                 if (*endp != '\0')
105                         RETURN(-EINVAL);
106                 to = simple_strtol(ioc_data->ioc_inlbuf3, &endp, 0);
107                 if (*endp != '\0')
108                         RETURN(-EINVAL);
109                 ioc_data->ioc_inllen1 = 0;
110                 out = ioc_data->ioc_bulk;
111         }
112
113         cur_index = rec->lrh_index;
114         if (cur_index < from)
115                 RETURN(0);
116         if (to > 0 && cur_index > to)
117                 RETURN(-LLOG_EEMPTY);
118
119         if (handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT) {
120                 struct llog_logid_rec   *lir = (struct llog_logid_rec *)rec;
121                 struct llog_handle      *loghandle;
122
123                 if (rec->lrh_type != LLOG_LOGID_MAGIC) {
124                         l = snprintf(out, remains, "[index]: %05d  [type]: "
125                                      "%02x  [len]: %04d failed\n",
126                                      cur_index, rec->lrh_type,
127                                      rec->lrh_len);
128                 }
129                 if (handle->lgh_ctxt == NULL)
130                         RETURN(-EOPNOTSUPP);
131                 rc = llog_cat_id2handle(env, handle, &loghandle, &lir->lid_id);
132                 if (rc) {
133                         CDEBUG(D_IOCTL,
134                                "cannot find log #"LPX64"#"LPX64"#%08x\n",
135                                lir->lid_id.lgl_oid, lir->lid_id.lgl_oseq,
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         ENTRY;
183         if (ioc_data != NULL && ioc_data->ioc_inllen1 > 0) {
184                 l = 0;
185                 remains = ioc_data->ioc_inllen4 +
186                         cfs_size_round(ioc_data->ioc_inllen1) +
187                         cfs_size_round(ioc_data->ioc_inllen2) +
188                         cfs_size_round(ioc_data->ioc_inllen3);
189                 from = simple_strtol(ioc_data->ioc_inlbuf2, &endp, 0);
190                 if (*endp != '\0')
191                         RETURN(-EINVAL);
192                 to = simple_strtol(ioc_data->ioc_inlbuf3, &endp, 0);
193                 if (*endp != '\0')
194                         RETURN(-EINVAL);
195                 out = ioc_data->ioc_bulk;
196                 ioc_data->ioc_inllen1 = 0;
197         }
198
199         cur_index = rec->lrh_index;
200         if (cur_index < from)
201                 RETURN(0);
202         if (to > 0 && cur_index > to)
203                 RETURN(-LLOG_EEMPTY);
204
205         if (handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT) {
206                 struct llog_logid_rec *lir = (struct llog_logid_rec *)rec;
207
208                 if (rec->lrh_type != LLOG_LOGID_MAGIC) {
209                         CERROR("invalid record in catalog\n");
210                         RETURN(-EINVAL);
211                 }
212
213                 l = snprintf(out, remains,
214                              "[index]: %05d  [logid]: #"LPX64"#"LPX64"#%08x\n",
215                              cur_index, lir->lid_id.lgl_oid,
216                              lir->lid_id.lgl_oseq, lir->lid_id.lgl_ogen);
217         } else if (rec->lrh_type == OBD_CFG_REC) {
218                 int rc;
219
220                 rc = class_config_parse_rec(rec, out, remains);
221                 if (rc < 0)
222                         RETURN(rc);
223                 l = rc;
224         } else {
225                 l = snprintf(out, remains,
226                              "[index]: %05d  [type]: %02x  [len]: %04d\n",
227                              cur_index, rec->lrh_type, rec->lrh_len);
228         }
229         out += l;
230         remains -= l;
231         if (remains <= 0) {
232                 CERROR("not enough space for print log records\n");
233                 RETURN(-LLOG_EEMPTY);
234         }
235
236         RETURN(0);
237 }
238 static int llog_remove_log(const struct lu_env *env, struct llog_handle *cat,
239                            struct llog_logid *logid)
240 {
241         struct llog_handle      *log;
242         int                      rc;
243
244         ENTRY;
245
246         rc = llog_cat_id2handle(env, cat, &log, logid);
247         if (rc) {
248                 CDEBUG(D_IOCTL, "cannot find log #"LPX64"#"LPX64"#%08x\n",
249                        logid->lgl_oid, logid->lgl_oseq, logid->lgl_ogen);
250                 RETURN(-ENOENT);
251         }
252
253         rc = llog_destroy(env, log);
254         if (rc) {
255                 CDEBUG(D_IOCTL, "cannot destroy log\n");
256                 GOTO(out, rc);
257         }
258         llog_cat_cleanup(env, cat, log, log->u.phd.phd_cookie.lgc_index);
259 out:
260         llog_handle_put(log);
261         RETURN(rc);
262
263 }
264
265 static int llog_delete_cb(const struct lu_env *env, struct llog_handle *handle,
266                           struct llog_rec_hdr *rec, void *data)
267 {
268         struct llog_logid_rec   *lir = (struct llog_logid_rec *)rec;
269         int                      rc;
270
271         ENTRY;
272         if (rec->lrh_type != LLOG_LOGID_MAGIC)
273                 RETURN(-EINVAL);
274         rc = llog_remove_log(env, handle, &lir->lid_id);
275
276         RETURN(rc);
277 }
278
279
280 int llog_ioctl(const struct lu_env *env, struct llog_ctxt *ctxt, int cmd,
281                struct obd_ioctl_data *data)
282 {
283         struct llog_logid        logid;
284         int                      rc = 0;
285         struct llog_handle      *handle = NULL;
286
287         ENTRY;
288
289         if (*data->ioc_inlbuf1 == '#') {
290                 rc = str2logid(&logid, data->ioc_inlbuf1, data->ioc_inllen1);
291                 if (rc)
292                         RETURN(rc);
293                 rc = llog_open(env, ctxt, &handle, &logid, NULL,
294                                LLOG_OPEN_EXISTS);
295                 if (rc)
296                         RETURN(rc);
297         } else if (*data->ioc_inlbuf1 == '$') {
298                 char *name = data->ioc_inlbuf1 + 1;
299
300                 rc = llog_open(env, ctxt, &handle, NULL, name,
301                                LLOG_OPEN_EXISTS);
302                 if (rc)
303                         RETURN(rc);
304         } else {
305                 RETURN(-EINVAL);
306         }
307
308         rc = llog_init_handle(env, handle, 0, NULL);
309         if (rc)
310                 GOTO(out_close, rc = -ENOENT);
311
312         switch (cmd) {
313         case OBD_IOC_LLOG_INFO: {
314                 int      l;
315                 int      remains = data->ioc_inllen2 +
316                                    cfs_size_round(data->ioc_inllen1);
317                 char    *out = data->ioc_bulk;
318
319                 l = snprintf(out, remains,
320                              "logid:            #"LPX64"#"LPX64"#%08x\n"
321                              "flags:            %x (%s)\n"
322                              "records count:    %d\n"
323                              "last index:       %d\n",
324                              handle->lgh_id.lgl_oid, handle->lgh_id.lgl_oseq,
325                              handle->lgh_id.lgl_ogen,
326                              handle->lgh_hdr->llh_flags,
327                              handle->lgh_hdr->llh_flags &
328                              LLOG_F_IS_CAT ? "cat" : "plain",
329                              handle->lgh_hdr->llh_count,
330                              handle->lgh_last_idx);
331                 out += l;
332                 remains -= l;
333                 if (remains <= 0) {
334                         CERROR("%s: not enough space for log header info\n",
335                                ctxt->loc_obd->obd_name);
336                         rc = -ENOSPC;
337                 }
338                 break;
339         }
340         case OBD_IOC_LLOG_CHECK:
341                 LASSERT(data->ioc_inllen1 > 0);
342                 rc = llog_process(env, handle, llog_check_cb, data, NULL);
343                 if (rc == -LLOG_EEMPTY)
344                         rc = 0;
345                 else if (rc)
346                         GOTO(out_close, rc);
347                 break;
348         case OBD_IOC_LLOG_PRINT:
349                 LASSERT(data->ioc_inllen1 > 0);
350                 rc = llog_process(env, handle, llog_print_cb, data, NULL);
351                 if (rc == -LLOG_EEMPTY)
352                         rc = 0;
353                 else if (rc)
354                         GOTO(out_close, rc);
355                 break;
356         case OBD_IOC_LLOG_CANCEL: {
357                 struct llog_cookie cookie;
358                 struct llog_logid plain;
359                 char *endp;
360
361                 cookie.lgc_index = simple_strtoul(data->ioc_inlbuf3, &endp, 0);
362                 if (*endp != '\0')
363                         GOTO(out_close, rc = -EINVAL);
364
365                 if (handle->lgh_hdr->llh_flags & LLOG_F_IS_PLAIN) {
366                         rc = llog_cancel_rec(NULL, handle, cookie.lgc_index);
367                         GOTO(out_close, rc);
368                 } else if (!(handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT)) {
369                         GOTO(out_close, rc = -EINVAL);
370                 }
371
372                 if (data->ioc_inlbuf2 == NULL) /* catalog but no logid */
373                         GOTO(out_close, rc = -ENOTTY);
374
375                 rc = str2logid(&plain, data->ioc_inlbuf2, data->ioc_inllen2);
376                 if (rc)
377                         GOTO(out_close, rc);
378                 cookie.lgc_lgl = plain;
379                 rc = llog_cat_cancel_records(env, handle, 1, &cookie);
380                 if (rc)
381                         GOTO(out_close, rc);
382                 break;
383         }
384         case OBD_IOC_LLOG_REMOVE: {
385                 struct llog_logid plain;
386
387                 if (handle->lgh_hdr->llh_flags & LLOG_F_IS_PLAIN) {
388                         rc = llog_destroy(env, handle);
389                         GOTO(out_close, rc);
390                 } else if (!(handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT)) {
391                         GOTO(out_close, rc = -EINVAL);
392                 }
393
394                 if (data->ioc_inlbuf2 > 0) {
395                         /* remove indicate log from the catalog */
396                         rc = str2logid(&plain, data->ioc_inlbuf2,
397                                        data->ioc_inllen2);
398                         if (rc)
399                                 GOTO(out_close, rc);
400                         rc = llog_remove_log(env, handle, &plain);
401                 } else {
402                         /* remove all the log of the catalog */
403                         rc = llog_process(env, handle, llog_delete_cb, NULL,
404                                           NULL);
405                         if (rc)
406                                 GOTO(out_close, rc);
407                 }
408                 break;
409         }
410         default:
411                 CERROR("%s: Unknown ioctl cmd %#x\n",
412                        ctxt->loc_obd->obd_name, cmd);
413                 GOTO(out_close, rc = -ENOTTY);
414         }
415
416 out_close:
417         if (handle->lgh_hdr &&
418             handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT)
419                 llog_cat_close(env, handle);
420         else
421                 llog_close(env, handle);
422         RETURN(rc);
423 }
424 EXPORT_SYMBOL(llog_ioctl);
425
426 #ifdef HAVE_LDISKFS_OSD
427 int llog_catalog_list(struct obd_device *obd, int count,
428                       struct obd_ioctl_data *data)
429 {
430         int size, i;
431         struct llog_catid *idarray;
432         struct llog_logid *id;
433         char name[32] = CATLIST;
434         char *out;
435         int l, remains, rc = 0;
436
437         ENTRY;
438         size = sizeof(*idarray) * count;
439
440         OBD_ALLOC_LARGE(idarray, size);
441         if (!idarray)
442                 RETURN(-ENOMEM);
443
444         mutex_lock(&obd->obd_olg.olg_cat_processing);
445         rc = llog_get_cat_list(obd, name, 0, count, idarray);
446         if (rc)
447                 GOTO(out, rc);
448
449         out = data->ioc_bulk;
450         remains = data->ioc_inllen1;
451         for (i = 0; i < count; i++) {
452                 id = &idarray[i].lci_logid;
453                 l = snprintf(out, remains,
454                              "catalog log: #"LPX64"#"LPX64"#%08x\n",
455                              id->lgl_oid, id->lgl_oseq, id->lgl_ogen);
456                 out += l;
457                 remains -= l;
458                 if (remains <= 0) {
459                         CWARN("not enough memory for catlog list\n");
460                         break;
461                 }
462         }
463 out:
464         /* release semaphore */
465         mutex_unlock(&obd->obd_olg.olg_cat_processing);
466
467         OBD_FREE_LARGE(idarray, size);
468         RETURN(rc);
469
470 }
471 EXPORT_SYMBOL(llog_catalog_list);
472 #endif