Whamcloud - gitweb
LU-2068 build: Disable obdfilter with osd-zfs
[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, Inc.
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 *log_handle;
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, &log_handle, &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, log_handle, llog_check_cb, NULL, NULL);
140                 llog_close(env, log_handle);
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, index = 0;
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                 GOTO(out, rc = -ENOENT);
251         }
252
253         index = log->u.phd.phd_cookie.lgc_index;
254         LASSERT(index);
255         rc = llog_destroy(env, log);
256         if (rc) {
257                 CDEBUG(D_IOCTL, "cannot destroy log\n");
258                 GOTO(out, rc);
259         }
260         cfs_down_write(&cat->lgh_lock);
261         if (cat->u.chd.chd_current_log == log)
262                 cat->u.chd.chd_current_log = NULL;
263         cfs_up_write(&cat->lgh_lock);
264         llog_cat_set_first_idx(cat, index);
265         rc = llog_cancel_rec(env, cat, index);
266 out:
267         llog_close(env, log);
268         RETURN(rc);
269
270 }
271
272 static int llog_delete_cb(const struct lu_env *env, struct llog_handle *handle,
273                           struct llog_rec_hdr *rec, void *data)
274 {
275         struct llog_logid_rec   *lir = (struct llog_logid_rec *)rec;
276         int                      rc;
277
278         ENTRY;
279         if (rec->lrh_type != LLOG_LOGID_MAGIC)
280                 RETURN(-EINVAL);
281         rc = llog_remove_log(env, handle, &lir->lid_id);
282
283         RETURN(rc);
284 }
285
286
287 int llog_ioctl(const struct lu_env *env, struct llog_ctxt *ctxt, int cmd,
288                struct obd_ioctl_data *data)
289 {
290         struct llog_logid        logid;
291         int                      rc = 0;
292         struct llog_handle      *handle = NULL;
293
294         ENTRY;
295
296         if (*data->ioc_inlbuf1 == '#') {
297                 rc = str2logid(&logid, data->ioc_inlbuf1, data->ioc_inllen1);
298                 if (rc)
299                         RETURN(rc);
300                 rc = llog_open(env, ctxt, &handle, &logid, NULL,
301                                LLOG_OPEN_EXISTS);
302                 if (rc)
303                         RETURN(rc);
304         } else if (*data->ioc_inlbuf1 == '$') {
305                 char *name = data->ioc_inlbuf1 + 1;
306
307                 rc = llog_open(env, ctxt, &handle, NULL, name,
308                                LLOG_OPEN_EXISTS);
309                 if (rc)
310                         RETURN(rc);
311         } else {
312                 RETURN(-EINVAL);
313         }
314
315         rc = llog_init_handle(env, handle, 0, NULL);
316         if (rc)
317                 GOTO(out_close, rc = -ENOENT);
318
319         switch (cmd) {
320         case OBD_IOC_LLOG_INFO: {
321                 int      l;
322                 int      remains = data->ioc_inllen2 +
323                                    cfs_size_round(data->ioc_inllen1);
324                 char    *out = data->ioc_bulk;
325
326                 l = snprintf(out, remains,
327                              "logid:            #"LPX64"#"LPX64"#%08x\n"
328                              "flags:            %x (%s)\n"
329                              "records count:    %d\n"
330                              "last index:       %d\n",
331                              handle->lgh_id.lgl_oid, handle->lgh_id.lgl_oseq,
332                              handle->lgh_id.lgl_ogen,
333                              handle->lgh_hdr->llh_flags,
334                              handle->lgh_hdr->llh_flags &
335                              LLOG_F_IS_CAT ? "cat" : "plain",
336                              handle->lgh_hdr->llh_count,
337                              handle->lgh_last_idx);
338                 out += l;
339                 remains -= l;
340                 if (remains <= 0) {
341                         CERROR("%s: not enough space for log header info\n",
342                                ctxt->loc_obd->obd_name);
343                         rc = -ENOSPC;
344                 }
345                 break;
346         }
347         case OBD_IOC_LLOG_CHECK:
348                 LASSERT(data->ioc_inllen1 > 0);
349                 rc = llog_process(env, handle, llog_check_cb, data, NULL);
350                 if (rc == -LLOG_EEMPTY)
351                         rc = 0;
352                 else if (rc)
353                         GOTO(out_close, rc);
354                 break;
355         case OBD_IOC_LLOG_PRINT:
356                 LASSERT(data->ioc_inllen1 > 0);
357                 rc = llog_process(env, handle, llog_print_cb, data, NULL);
358                 if (rc == -LLOG_EEMPTY)
359                         rc = 0;
360                 else if (rc)
361                         GOTO(out_close, rc);
362                 break;
363         case OBD_IOC_LLOG_CANCEL: {
364                 struct llog_cookie cookie;
365                 struct llog_logid plain;
366                 char *endp;
367
368                 cookie.lgc_index = simple_strtoul(data->ioc_inlbuf3, &endp, 0);
369                 if (*endp != '\0')
370                         GOTO(out_close, rc = -EINVAL);
371
372                 if (handle->lgh_hdr->llh_flags & LLOG_F_IS_PLAIN) {
373                         rc = llog_cancel_rec(NULL, handle, cookie.lgc_index);
374                         GOTO(out_close, rc);
375                 } else if (!(handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT)) {
376                         GOTO(out_close, rc = -EINVAL);
377                 }
378
379                 if (data->ioc_inlbuf2 == NULL) /* catalog but no logid */
380                         GOTO(out_close, rc = -ENOTTY);
381
382                 rc = str2logid(&plain, data->ioc_inlbuf2, data->ioc_inllen2);
383                 if (rc)
384                         GOTO(out_close, rc);
385                 cookie.lgc_lgl = plain;
386                 rc = llog_cat_cancel_records(env, handle, 1, &cookie);
387                 if (rc)
388                         GOTO(out_close, rc);
389                 break;
390         }
391         case OBD_IOC_LLOG_REMOVE: {
392                 struct llog_logid plain;
393
394                 if (handle->lgh_hdr->llh_flags & LLOG_F_IS_PLAIN) {
395                         rc = llog_destroy(env, handle);
396                         GOTO(out_close, rc);
397                 } else if (!(handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT)) {
398                         GOTO(out_close, rc = -EINVAL);
399                 }
400
401                 if (data->ioc_inlbuf2 > 0) {
402                         /* remove indicate log from the catalog */
403                         rc = str2logid(&plain, data->ioc_inlbuf2,
404                                        data->ioc_inllen2);
405                         if (rc)
406                                 GOTO(out_close, rc);
407                         rc = llog_remove_log(env, handle, &plain);
408                 } else {
409                         /* remove all the log of the catalog */
410                         rc = llog_process(env, handle, llog_delete_cb, NULL,
411                                           NULL);
412                         if (rc)
413                                 GOTO(out_close, rc);
414                 }
415                 break;
416         }
417         default:
418                 CERROR("%s: Unknown ioctl cmd %#x\n",
419                        ctxt->loc_obd->obd_name, cmd);
420                 GOTO(out_close, rc = -ENOTTY);
421         }
422
423 out_close:
424         if (handle->lgh_hdr &&
425             handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT)
426                 llog_cat_close(env, handle);
427         else
428                 llog_close(env, handle);
429         RETURN(rc);
430 }
431 EXPORT_SYMBOL(llog_ioctl);
432
433 #ifdef HAVE_LDISKFS_OSD
434 int llog_catalog_list(struct obd_device *obd, int count,
435                       struct obd_ioctl_data *data)
436 {
437         int size, i;
438         struct llog_catid *idarray;
439         struct llog_logid *id;
440         char name[32] = CATLIST;
441         char *out;
442         int l, remains, rc = 0;
443
444         ENTRY;
445         size = sizeof(*idarray) * count;
446
447         OBD_ALLOC_LARGE(idarray, size);
448         if (!idarray)
449                 RETURN(-ENOMEM);
450
451         cfs_mutex_lock(&obd->obd_olg.olg_cat_processing);
452         rc = llog_get_cat_list(obd, name, 0, count, idarray);
453         if (rc)
454                 GOTO(out, rc);
455
456         out = data->ioc_bulk;
457         remains = data->ioc_inllen1;
458         for (i = 0; i < count; i++) {
459                 id = &idarray[i].lci_logid;
460                 l = snprintf(out, remains,
461                              "catalog log: #"LPX64"#"LPX64"#%08x\n",
462                              id->lgl_oid, id->lgl_oseq, id->lgl_ogen);
463                 out += l;
464                 remains -= l;
465                 if (remains <= 0) {
466                         CWARN("not enough memory for catlog list\n");
467                         break;
468                 }
469         }
470 out:
471         /* release semaphore */
472         cfs_mutex_unlock(&obd->obd_olg.olg_cat_processing);
473
474         OBD_FREE_LARGE(idarray, size);
475         RETURN(rc);
476
477 }
478 EXPORT_SYMBOL(llog_catalog_list);
479 #endif