Whamcloud - gitweb
aa91695890309719a72eef9a821e3abc3a46da76
[fs/lustre-release.git] / lustre / obdclass / llog_ioctl.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see
20  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
30  * Use is subject to license terms.
31  *
32  * Copyright (c) 2011, Whamcloud, Inc.
33  */
34 /*
35  * This file is part of Lustre, http://www.lustre.org/
36  * Lustre is a trademark of Sun Microsystems, Inc.
37  */
38
39 #define DEBUG_SUBSYSTEM S_LOG
40
41 #ifndef EXPORT_SYMTAB
42 #define EXPORT_SYMTAB
43 #endif
44
45 #include <obd_class.h>
46 #include <lustre_log.h>
47 #include <libcfs/list.h>
48 #include "llog_internal.h"
49
50 static int str2logid(struct llog_logid *logid, char *str, int len)
51 {
52         char *start, *end, *endp;
53
54         ENTRY;
55         start = str;
56         if (*start != '#')
57                 RETURN(-EINVAL);
58
59         start++;
60         if (start - str >= len - 1)
61                 RETURN(-EINVAL);
62         end = strchr(start, '#');
63         if (end == NULL || end == start)
64                 RETURN(-EINVAL);
65
66         *end = '\0';
67         logid->lgl_oid = simple_strtoull(start, &endp, 0);
68         if (endp != end)
69                 RETURN(-EINVAL);
70
71         start = ++end;
72         if (start - str >= len - 1)
73                 RETURN(-EINVAL);
74         end = strchr(start, '#');
75         if (end == NULL || end == start)
76                 RETURN(-EINVAL);
77
78         *end = '\0';
79         logid->lgl_oseq = simple_strtoull(start, &endp, 0);
80         if (endp != end)
81                 RETURN(-EINVAL);
82
83         start = ++end;
84         if (start - str >= len - 1)
85                 RETURN(-EINVAL);
86         logid->lgl_ogen = simple_strtoul(start, &endp, 16);
87         if (*endp != '\0')
88                 RETURN(-EINVAL);
89
90         RETURN(0);
91 }
92
93 static int llog_check_cb(struct llog_handle *handle, struct llog_rec_hdr *rec,
94                          void *data)
95 {
96         struct obd_ioctl_data *ioc_data = (struct obd_ioctl_data *)data;
97         static int l, remains, from, to;
98         static char *out;
99         char *endp;
100         int cur_index, rc = 0;
101
102         ENTRY;
103         cur_index = rec->lrh_index;
104
105         if (ioc_data && (ioc_data->ioc_inllen1)) {
106                 l = 0;
107                 remains = ioc_data->ioc_inllen4 +
108                         cfs_size_round(ioc_data->ioc_inllen1) +
109                         cfs_size_round(ioc_data->ioc_inllen2) +
110                         cfs_size_round(ioc_data->ioc_inllen3);
111                 from = simple_strtol(ioc_data->ioc_inlbuf2, &endp, 0);
112                 if (*endp != '\0')
113                         RETURN(-EINVAL);
114                 to = simple_strtol(ioc_data->ioc_inlbuf3, &endp, 0);
115                 if (*endp != '\0')
116                         RETURN(-EINVAL);
117                 ioc_data->ioc_inllen1 = 0;
118                 out = ioc_data->ioc_bulk;
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 *log_handle;
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(handle, &log_handle, &lir->lid_id);
137                 if (rc) {
138                         CDEBUG(D_IOCTL,
139                                "cannot find log #"LPX64"#"LPX64"#%08x\n",
140                                lir->lid_id.lgl_oid, lir->lid_id.lgl_oseq,
141                                lir->lid_id.lgl_ogen);
142                         RETURN(rc);
143                 }
144                 rc = llog_process(log_handle, llog_check_cb, NULL, NULL);
145                 llog_close(log_handle);
146         } else {
147                 switch (rec->lrh_type) {
148                 case OST_SZ_REC:
149                 case OST_RAID1_REC:
150                 case MDS_UNLINK_REC:
151                 case MDS_SETATTR_REC:
152                 case MDS_SETATTR64_REC:
153                 case OBD_CFG_REC:
154                 case LLOG_HDR_MAGIC: {
155                          l = snprintf(out, remains, "[index]: %05d  [type]: "
156                                       "%02x  [len]: %04d ok\n",
157                                       cur_index, rec->lrh_type,
158                                       rec->lrh_len);
159                          out += l;
160                          remains -= l;
161                          if (remains <= 0) {
162                                 CERROR("no space to print log records\n");
163                                 RETURN(-LLOG_EEMPTY);
164                          }
165                          RETURN(0);
166                 }
167                 default: {
168                          l = snprintf(out, remains, "[index]: %05d  [type]: "
169                                       "%02x  [len]: %04d failed\n",
170                                       cur_index, rec->lrh_type,
171                                       rec->lrh_len);
172                          out += l;
173                          remains -= l;
174                          if (remains <= 0) {
175                                 CERROR("no space to print log records\n");
176                                 RETURN(-LLOG_EEMPTY);
177                          }
178                          RETURN(0);
179                 }
180                 }
181         }
182         RETURN(rc);
183 }
184
185 static int llog_print_cb(struct llog_handle *handle, struct llog_rec_hdr *rec,
186                          void *data)
187 {
188         struct obd_ioctl_data *ioc_data = (struct obd_ioctl_data *)data;
189         static int l, remains, from, to;
190         static char *out;
191         char *endp;
192         int cur_index;
193
194         ENTRY;
195         if (ioc_data->ioc_inllen1) {
196                 l = 0;
197                 remains = ioc_data->ioc_inllen4 +
198                         cfs_size_round(ioc_data->ioc_inllen1) +
199                         cfs_size_round(ioc_data->ioc_inllen2) +
200                         cfs_size_round(ioc_data->ioc_inllen3);
201                 from = simple_strtol(ioc_data->ioc_inlbuf2, &endp, 0);
202                 if (*endp != '\0')
203                         RETURN(-EINVAL);
204                 to = simple_strtol(ioc_data->ioc_inlbuf3, &endp, 0);
205                 if (*endp != '\0')
206                         RETURN(-EINVAL);
207                 out = ioc_data->ioc_bulk;
208                 ioc_data->ioc_inllen1 = 0;
209         }
210
211         cur_index = rec->lrh_index;
212         if (cur_index < from)
213                 RETURN(0);
214         if (to > 0 && cur_index > to)
215                 RETURN(-LLOG_EEMPTY);
216
217         if (handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT) {
218                 struct llog_logid_rec *lir = (struct llog_logid_rec *)rec;
219                 if (rec->lrh_type != LLOG_LOGID_MAGIC) {
220                         CERROR("invalid record in catalog\n");
221                         RETURN(-EINVAL);
222                 }
223
224                 l = snprintf(out, remains,
225                              "[index]: %05d  [logid]: #"LPX64"#"LPX64"#%08x\n",
226                              cur_index, lir->lid_id.lgl_oid,
227                              lir->lid_id.lgl_oseq, lir->lid_id.lgl_ogen);
228         } else {
229                 l = snprintf(out, remains,
230                              "[index]: %05d  [type]: %02x  [len]: %04d\n",
231                              cur_index, rec->lrh_type,
232                              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(struct llog_handle *cat, struct llog_logid *logid)
244 {
245         struct llog_handle *log;
246         int rc, index = 0;
247
248         ENTRY;
249         cfs_down_write(&cat->lgh_lock);
250         rc = llog_cat_id2handle(cat, &log, logid);
251         if (rc) {
252                 CDEBUG(D_IOCTL, "cannot find log #"LPX64"#"LPX64"#%08x\n",
253                        logid->lgl_oid, logid->lgl_oseq, logid->lgl_ogen);
254                 GOTO(out, rc = -ENOENT);
255         }
256
257         index = log->u.phd.phd_cookie.lgc_index;
258         LASSERT(index);
259         rc = llog_destroy(log);
260         if (rc) {
261                 CDEBUG(D_IOCTL, "cannot destroy log\n");
262                 GOTO(out, rc);
263         }
264         llog_cat_set_first_idx(cat, index);
265         rc = llog_cancel_rec(cat, index);
266 out:
267         llog_free_handle(log);
268         cfs_up_write(&cat->lgh_lock);
269         RETURN(rc);
270
271 }
272
273 static int llog_delete_cb(struct llog_handle *handle, struct llog_rec_hdr *rec,
274                           void *data)
275 {
276         struct  llog_logid_rec *lir = (struct llog_logid_rec*)rec;
277         int     rc;
278
279         ENTRY;
280         if (rec->lrh_type != LLOG_LOGID_MAGIC)
281               RETURN (-EINVAL);
282         rc = llog_remove_log(handle, &lir->lid_id);
283
284         RETURN(rc);
285 }
286
287
288 int llog_ioctl(struct llog_ctxt *ctxt, int cmd, struct obd_ioctl_data *data)
289 {
290         struct llog_logid logid;
291         int err = 0;
292         struct llog_handle *handle = NULL;
293
294         ENTRY;
295         if (*data->ioc_inlbuf1 == '#') {
296                 err = str2logid(&logid, data->ioc_inlbuf1, data->ioc_inllen1);
297                 if (err)
298                         GOTO(out, err);
299                 err = llog_create(ctxt, &handle, &logid, NULL);
300                 if (err)
301                         GOTO(out, err);
302         } else if (*data->ioc_inlbuf1 == '$') {
303                 char *name = data->ioc_inlbuf1 + 1;
304                 err = llog_create(ctxt, &handle, NULL, name);
305                 if (err)
306                         GOTO(out, err);
307         } else {
308                 GOTO(out, err = -EINVAL);
309         }
310
311         err = llog_init_handle(handle, 0, NULL);
312         if (err)
313                 GOTO(out_close, err = -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:            #"LPX64"#"LPX64"#%08x\n"
324                              "flags:            %x (%s)\n"
325                              "records count:    %d\n"
326                              "last index:       %d\n",
327                              handle->lgh_id.lgl_oid, handle->lgh_id.lgl_oseq,
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("not enough space for log header info\n");
338
339                 GOTO(out_close, err);
340         }
341         case OBD_IOC_LLOG_CHECK: {
342                 LASSERT(data->ioc_inllen1);
343                 err = llog_process(handle, llog_check_cb, data, NULL);
344                 if (err == -LLOG_EEMPTY)
345                         err = 0;
346                 GOTO(out_close, err);
347         }
348
349         case OBD_IOC_LLOG_PRINT: {
350                 LASSERT(data->ioc_inllen1);
351                 err = llog_process(handle, class_config_dump_handler,data,NULL);
352                 if (err == -LLOG_EEMPTY)
353                         err = 0;
354                 else
355                         err = llog_process(handle, llog_print_cb, data, NULL);
356
357                 GOTO(out_close, err);
358         }
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, err = -EINVAL);
367
368                 if (handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT) {
369                         cfs_down_write(&handle->lgh_lock);
370                         err = llog_cancel_rec(handle, cookie.lgc_index);
371                         cfs_up_write(&handle->lgh_lock);
372                         GOTO(out_close, err);
373                 }
374
375                 err = str2logid(&plain, data->ioc_inlbuf2, data->ioc_inllen2);
376                 if (err)
377                         GOTO(out_close, err);
378                 cookie.lgc_lgl = plain;
379
380                 if (!(handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT))
381                         GOTO(out_close, err = -EINVAL);
382
383                 err = llog_cat_cancel_records(handle, 1, &cookie);
384                 GOTO(out_close, err);
385         }
386         case OBD_IOC_LLOG_REMOVE: {
387                 struct llog_logid plain;
388
389                 if (handle->lgh_hdr->llh_flags & LLOG_F_IS_PLAIN) {
390                         err = llog_destroy(handle);
391                         if (!err)
392                                 llog_free_handle(handle);
393                         GOTO(out, err);
394                 }
395
396                 if (!(handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT))
397                         GOTO(out_close, err = -EINVAL);
398
399                 if (data->ioc_inlbuf2) {
400                         /*remove indicate log from the catalog*/
401                         err = str2logid(&plain, data->ioc_inlbuf2,
402                                         data->ioc_inllen2);
403                         if (err)
404                                 GOTO(out_close, err);
405                         err = llog_remove_log(handle, &plain);
406                 } else {
407                         /*remove all the log of the catalog*/
408                         llog_process(handle, llog_delete_cb, NULL, NULL);
409                 }
410                 GOTO(out_close, err);
411         }
412         }
413
414 out_close:
415         if (handle->lgh_hdr &&
416             handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT)
417                 llog_cat_put(handle);
418         else
419                 llog_close(handle);
420 out:
421         RETURN(err);
422 }
423 EXPORT_SYMBOL(llog_ioctl);
424
425 int llog_catalog_list(struct obd_device *obd, int count,
426                       struct obd_ioctl_data *data)
427 {
428         int size, i;
429         struct llog_catid *idarray;
430         struct llog_logid *id;
431         char name[32] = CATLIST;
432         char *out;
433         int l, remains, rc = 0;
434
435         ENTRY;
436         size = sizeof(*idarray) * count;
437
438         OBD_ALLOC_LARGE(idarray, size);
439         if (!idarray)
440                 RETURN(-ENOMEM);
441
442         cfs_mutex_down(&obd->obd_olg.olg_cat_processing);
443         rc = llog_get_cat_list(obd, name, 0, count, idarray);
444         if (rc)
445                 GOTO(out, rc);
446
447         out = data->ioc_bulk;
448         remains = data->ioc_inllen1;
449         for (i = 0; i < count; i++) {
450                 id = &idarray[i].lci_logid;
451                 l = snprintf(out, remains,
452                              "catalog log: #"LPX64"#"LPX64"#%08x\n",
453                              id->lgl_oid, id->lgl_oseq, id->lgl_ogen);
454                 out += l;
455                 remains -= l;
456                 if (remains <= 0) {
457                         CWARN("not enough memory for catlog list\n");
458                         break;
459                 }
460         }
461 out:
462         /* release semaphore */
463         cfs_mutex_up(&obd->obd_olg.olg_cat_processing);
464
465         OBD_FREE_LARGE(idarray, size);
466         RETURN(rc);
467
468 }
469 EXPORT_SYMBOL(llog_catalog_list);