Whamcloud - gitweb
* updates to HEAD lustre since landing b_port_step on portals
[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  *   You should have received a copy of the GNU General Public License
5  *   along with Lustre; if not, write to the Free Software
6  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
7  */
8
9 #define DEBUG_SUBSYSTEM S_LOG
10
11 #ifndef EXPORT_SYMTAB
12 #define EXPORT_SYMTAB
13 #endif
14
15 #include <linux/fs.h>
16 #include <linux/obd_class.h>
17 #include <linux/lustre_log.h>
18 #include <libcfs/list.h>
19
20 static int str2logid(struct llog_logid *logid, char *str, int len)
21 {
22         char *start, *end, *endp;
23
24         start = str;
25         if (*start != '#')
26                 RETURN(-EINVAL);
27
28         start++;
29         if (start - str >= len - 1)
30                 RETURN(-EINVAL);
31         end = strchr(start, '#');
32         if (end == NULL || end == start)
33                 RETURN(-EINVAL);
34
35         *end = '\0';
36         logid->lgl_oid = simple_strtoull(start, &endp, 0);
37         if (endp != end)
38                 RETURN(-EINVAL);
39
40         start = ++end;
41         if (start - str >= len - 1)
42                 RETURN(-EINVAL);
43         end = strchr(start, '#');
44         if (end == NULL || end == start)
45                 RETURN(-EINVAL);
46
47         *end = '\0';
48         logid->lgl_ogr = simple_strtoull(start, &endp, 0);
49         if (endp != end)
50                 RETURN(-EINVAL);
51
52         start = ++end;
53         if (start - str >= len - 1)
54                 RETURN(-EINVAL);
55         logid->lgl_ogen = simple_strtoul(start, &endp, 16);
56         if (*endp != '\0')
57                 RETURN(-EINVAL);
58
59         RETURN(0);
60 }
61
62 static int llog_check_cb(struct llog_handle *handle, struct llog_rec_hdr *rec,
63                          void *data)
64 {
65         struct obd_ioctl_data *ioc_data = (struct obd_ioctl_data *)data;
66         static int l, remains, from, to;
67         static char *out;
68         char *endp;
69         int cur_index, rc = 0;
70
71         cur_index = rec->lrh_index;
72
73         if (ioc_data && (ioc_data->ioc_inllen1)) {
74                 l = 0;
75                 remains = ioc_data->ioc_inllen4 +
76                         size_round(ioc_data->ioc_inllen1) +
77                         size_round(ioc_data->ioc_inllen2) +
78                         size_round(ioc_data->ioc_inllen3);
79                 from = simple_strtol(ioc_data->ioc_inlbuf2, &endp, 0);
80                 if (*endp != '\0')
81                         RETURN(-EINVAL);
82                 to = simple_strtol(ioc_data->ioc_inlbuf3, &endp, 0);
83                 if (*endp != '\0')
84                         RETURN(-EINVAL);
85                 ioc_data->ioc_inllen1 = 0;
86                 out = ioc_data->ioc_bulk;
87                 if (cur_index < from)
88                         RETURN(0);
89                 if (to > 0 && cur_index > to)
90                         RETURN(-LLOG_EEMPTY);
91         }
92         if (handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT) {
93                 struct llog_logid_rec *lir = (struct llog_logid_rec *)rec;
94                 struct llog_handle *log_handle;
95
96                 if (rec->lrh_type != LLOG_LOGID_MAGIC) {
97                         l = snprintf(out, remains, "[index]: %05d  [type]: "
98                                      "%02x  [len]: %04d failed\n",
99                                      cur_index, rec->lrh_type,
100                                      rec->lrh_len);
101                 }
102                 if (handle->lgh_ctxt == NULL)
103                         RETURN(-EOPNOTSUPP);
104                 llog_cat_id2handle(handle, &log_handle, &lir->lid_id);
105                 rc = llog_process(log_handle, llog_check_cb, NULL, NULL);
106                 llog_close(log_handle);
107         } else {
108                 switch (rec->lrh_type) {
109                 case OST_SZ_REC:
110                 case OST_RAID1_REC:
111                 case MDS_UNLINK_REC:
112                 case OBD_CFG_REC:
113                 case PTL_CFG_REC:
114                 case LLOG_HDR_MAGIC: {
115                          l = snprintf(out, remains, "[index]: %05d  [type]: "
116                                       "%02x  [len]: %04d ok\n",
117                                       cur_index, rec->lrh_type,
118                                       rec->lrh_len);
119                          out += l;
120                          remains -= l;
121                          if (remains <= 0) {
122                                 CERROR("no space to print log records\n");
123                                 RETURN(-LLOG_EEMPTY);
124                          }
125                          RETURN(0);
126                 }
127                 default: {
128                          l = snprintf(out, remains, "[index]: %05d  [type]: "
129                                       "%02x  [len]: %04d failed\n",
130                                       cur_index, rec->lrh_type,
131                                       rec->lrh_len);
132                          out += l;
133                          remains -= l;
134                          if (remains <= 0) {
135                                 CERROR("no space to print log records\n");
136                                 RETURN(-LLOG_EEMPTY);
137                          }
138                          RETURN(0);
139                 }
140                 }
141         }
142         RETURN(rc);
143 }
144
145 static int llog_print_cb(struct llog_handle *handle, struct llog_rec_hdr *rec,
146                          void *data)
147 {
148         struct obd_ioctl_data *ioc_data = (struct obd_ioctl_data *)data;
149         static int l, remains, from, to;
150         static char *out;
151         char *endp;
152         int cur_index;
153
154         if (ioc_data->ioc_inllen1) {
155                 l = 0;
156                 remains = ioc_data->ioc_inllen4 +
157                         size_round(ioc_data->ioc_inllen1) +
158                         size_round(ioc_data->ioc_inllen2) +
159                         size_round(ioc_data->ioc_inllen3);
160                 from = simple_strtol(ioc_data->ioc_inlbuf2, &endp, 0);
161                 if (*endp != '\0')
162                         RETURN(-EINVAL);
163                 to = simple_strtol(ioc_data->ioc_inlbuf3, &endp, 0);
164                 if (*endp != '\0')
165                         RETURN(-EINVAL);
166                 out = ioc_data->ioc_bulk;
167                 ioc_data->ioc_inllen1 = 0;
168         }
169
170         cur_index = rec->lrh_index;
171         if (cur_index < from)
172                 RETURN(0);
173         if (to > 0 && cur_index > to)
174                 RETURN(-LLOG_EEMPTY);
175
176         if (handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT) {
177                 struct llog_logid_rec *lir = (struct llog_logid_rec *)rec;
178                 if (rec->lrh_type != LLOG_LOGID_MAGIC) {
179                         CERROR("invalid record in catalog\n");
180                         RETURN(-EINVAL);
181                 }
182
183                 l = snprintf(out, remains,
184                              "[index]: %05d  [logid]: #"LPX64"#"LPX64"#%08x\n",
185                              cur_index, lir->lid_id.lgl_oid,
186                              lir->lid_id.lgl_ogr, lir->lid_id.lgl_ogen);
187         } else {
188                 l = snprintf(out, remains,
189                              "[index]: %05d  [type]: %02x  [len]: %04d\n",
190                              cur_index, rec->lrh_type,
191                              rec->lrh_len);
192         }
193         out += l;
194         remains -= l;
195         if (remains <= 0) {
196                 CERROR("not enough space for print log records\n");
197                 RETURN(-LLOG_EEMPTY);
198         }
199
200         RETURN(0);
201 }
202 static int llog_remove_log(struct llog_handle *cat, struct llog_logid *logid)
203 {
204         struct llog_handle *log;
205         int rc, index = 0;
206
207         down_write(&cat->lgh_lock);
208         rc = llog_cat_id2handle(cat, &log, logid);
209         if (rc) {
210                 CDEBUG(D_IOCTL, "cannot find log #"LPX64"#"LPX64"#%08x\n",
211                        logid->lgl_oid, logid->lgl_ogr, logid->lgl_ogen);
212                 GOTO(out, rc = -ENOENT);
213         }
214
215         index = log->u.phd.phd_cookie.lgc_index;
216         LASSERT(index);
217         rc = llog_destroy(log);
218         if (rc) {
219                 CDEBUG(D_IOCTL, "cannot destroy log\n");
220                 GOTO(out, rc);
221         }
222         llog_cat_set_first_idx(cat, index);
223         rc = llog_cancel_rec(cat, index);
224 out:
225         llog_free_handle(log);
226         up_write(&cat->lgh_lock);
227         RETURN(rc);
228
229 }
230
231 static int llog_delete_cb(struct llog_handle *handle, struct llog_rec_hdr *rec,
232                           void *data)
233 {
234         struct  llog_logid_rec *lir = (struct llog_logid_rec*)rec;
235         int     rc;
236
237         if (rec->lrh_type != LLOG_LOGID_MAGIC)
238               return (-EINVAL);
239         rc = llog_remove_log(handle, &lir->lid_id);
240
241         RETURN(rc);
242 }
243
244
245 int llog_ioctl(struct llog_ctxt *ctxt, int cmd, struct obd_ioctl_data *data)
246 {
247         struct llog_logid logid;
248         int err = 0;
249         struct llog_handle *handle = NULL;
250
251         if (*data->ioc_inlbuf1 == '#') {
252                 err = str2logid(&logid, data->ioc_inlbuf1, data->ioc_inllen1);
253                 if (err)
254                         GOTO(out, err);
255                 err = llog_open(ctxt, &handle, &logid, NULL, 0);
256                 if (err)
257                         GOTO(out, err);
258         } else if (*data->ioc_inlbuf1 == '$') {
259                 char *name = data->ioc_inlbuf1 + 1;
260                 err = llog_open(ctxt, &handle, NULL, name, 0);
261                 if (err)
262                         GOTO(out, err);
263         } else {
264                 GOTO(out, err = -EINVAL);
265         }
266
267         err = llog_init_handle(handle, 0, NULL);
268         if (err)
269                 GOTO(out_close, err = -ENOENT);
270
271         switch (cmd) {
272         case OBD_IOC_LLOG_INFO: {
273                 int l;
274                 int remains = data->ioc_inllen2 +
275                         size_round(data->ioc_inllen1);
276                 char *out = data->ioc_bulk;
277
278                 l = snprintf(out, remains,
279                              "logid:            #"LPX64"#"LPX64"#%08x\n"
280                              "flags:            %x (%s)\n"
281                              "records count:    %d\n"
282                              "last index:       %d\n",
283                              handle->lgh_id.lgl_oid, handle->lgh_id.lgl_ogr,
284                              handle->lgh_id.lgl_ogen,
285                              handle->lgh_hdr->llh_flags,
286                              handle->lgh_hdr->llh_flags &
287                              LLOG_F_IS_CAT ? "cat" : "plain",
288                              handle->lgh_hdr->llh_count,
289                              handle->lgh_last_idx);
290                 out += l;
291                 remains -= l;
292                 if (remains <= 0)
293                         CERROR("not enough space for log header info\n");
294
295                 GOTO(out_close, err);
296         }
297         case OBD_IOC_LLOG_CHECK: {
298                 LASSERT(data->ioc_inllen1);
299                 err = llog_process(handle, llog_check_cb, data, NULL);
300                 if (err == -LLOG_EEMPTY)
301                         err = 0;
302                 GOTO(out_close, err);
303         }
304
305         case OBD_IOC_LLOG_PRINT: {
306                 LASSERT(data->ioc_inllen1);
307                 err = llog_process(handle, llog_print_cb, data, NULL);
308                 if (err == -LLOG_EEMPTY)
309                         err = 0;
310
311                 GOTO(out_close, err);
312         }
313         case OBD_IOC_LLOG_CANCEL: {
314                 struct llog_cookie cookie;
315                 struct llog_logid plain;
316                 char *endp;
317
318                 cookie.lgc_index = simple_strtoul(data->ioc_inlbuf3, &endp, 0);
319                 if (*endp != '\0')
320                         GOTO(out_close, err = -EINVAL);
321
322                 if (handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT) {
323                         down_write(&handle->lgh_lock);
324                         err = llog_cancel_rec(handle, cookie.lgc_index);
325                         up_write(&handle->lgh_lock);
326                         GOTO(out_close, err);
327                 }
328
329                 err = str2logid(&plain, data->ioc_inlbuf2, data->ioc_inllen2);
330                 if (err)
331                         GOTO(out_close, err);
332                 cookie.lgc_lgl = plain;
333
334                 if (!(handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT))
335                         GOTO(out_close, err = -EINVAL);
336
337                 err = llog_cat_cancel_records(handle, 1, &cookie);
338                 GOTO(out_close, err);
339         }
340         case OBD_IOC_LLOG_REMOVE: {
341                 struct llog_logid plain;
342
343                 if (handle->lgh_hdr->llh_flags & LLOG_F_IS_PLAIN) {
344                         err = llog_destroy(handle);
345                         if (!err)
346                                 llog_free_handle(handle);
347                         GOTO(out, err);
348                 }
349
350                 if (!(handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT))
351                         GOTO(out_close, err = -EINVAL);
352
353                 if (data->ioc_inlbuf2) {
354                         /*remove indicate log from the catalog*/
355                         err = str2logid(&plain, data->ioc_inlbuf2,
356                                         data->ioc_inllen2);
357                         if (err)
358                                 GOTO(out_close, err);
359                         err = llog_remove_log(handle, &plain);
360                 } else {
361                         /*remove all the log of the catalog*/
362                         llog_process(handle, llog_delete_cb, NULL, NULL);
363                 }
364                 GOTO(out_close, err);
365         }
366         }
367
368 out_close:
369         if (handle->lgh_hdr &&
370             handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT)
371                 llog_cat_put(handle);
372         else
373                 llog_close(handle);
374 out:
375         RETURN(err);
376 }
377 EXPORT_SYMBOL(llog_ioctl);
378
379 int llog_catalog_list(struct obd_device *obd, int count,
380                       struct obd_ioctl_data *data)
381 {
382         int size, i;
383         struct llog_catid *idarray;
384         struct llog_logid *id;
385         char name[32] = CATLIST;
386         char *out;
387         int l, remains, rc = 0;
388
389         size = sizeof(*idarray) * count;
390
391         OBD_ALLOC(idarray, size);
392         if (!idarray)
393                 RETURN(-ENOMEM);
394         memset(idarray, 0, size);
395
396         rc = llog_get_cat_list(&obd->obd_lvfs_ctxt, obd->obd_fsops,
397                                name, count, idarray);
398         if (rc) {
399                 OBD_FREE(idarray, size);
400                 RETURN(rc);
401         }
402
403         out = data->ioc_bulk;
404         remains = data->ioc_inllen1;
405         for (i = 0; i < count; i++) {
406                 id = &idarray[i].lci_logid;
407                 l = snprintf(out, remains,
408                              "catalog log: #"LPX64"#"LPX64"#%08x\n",
409                              id->lgl_oid, id->lgl_ogr, id->lgl_ogen);
410                 out += l;
411                 remains -= l;
412                 if (remains <= 0) {
413                         CWARN("not enough memory for catlog list\n");
414                         break;
415                 }
416         }
417         OBD_FREE(idarray, size);
418         RETURN(0);
419
420 }
421 EXPORT_SYMBOL(llog_catalog_list);