Whamcloud - gitweb
land v0.9.1 on HEAD, in preparation for a 1.0.x branch
[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 <portals/list.h>
19 #include "llog_internal.h"
20
21 static int str2logid(struct llog_logid *logid, char *str, int len)
22 {
23         char *start, *end, *endp;
24         
25         start = str;
26         if (*start != '#')
27                 RETURN(-EINVAL);
28         
29         start++;
30         if (start - str >= len - 1)
31                 RETURN(-EINVAL);
32         end = strchr(start, '#');
33         if (end == NULL || end == start)
34                 RETURN(-EINVAL);
35
36         *end = '\0';
37         logid->lgl_oid = simple_strtoull(start, &endp, 16); 
38         if (endp != end)
39                 RETURN(-EINVAL);
40
41         start = ++end;
42         if (start - str >= len - 1)
43                 RETURN(-EINVAL);
44         end = strchr(start, '#');
45         if (end == NULL || end == start)
46                 RETURN(-EINVAL);
47
48         *end = '\0';
49         logid->lgl_ogr = simple_strtoull(start, &endp, 16);
50         if (endp != end)
51                 RETURN(-EINVAL);
52
53         start = ++end;
54         if (start - str >= len - 1)
55                 RETURN(-EINVAL);
56         logid->lgl_ogen = simple_strtoul(start, &endp, 16);
57         if (*endp != '\0')
58                 RETURN(-EINVAL);
59
60         RETURN(0);
61 }
62
63 static int llog_print_cb(struct llog_handle *handle, struct llog_rec_hdr *rec, 
64                          void *data)
65 {
66         struct obd_ioctl_data *ioc_data = (struct obd_ioctl_data *)data;
67         static int l, remains, from, to;
68         static char *out;
69         char *endp;
70         int cur_index;
71         
72         if (ioc_data->ioc_inllen1) {
73                 l = 0;
74                 remains = ioc_data->ioc_inllen4 + 
75                         size_round(ioc_data->ioc_inllen1) +
76                         size_round(ioc_data->ioc_inllen2) +
77                         size_round(ioc_data->ioc_inllen3);
78                 from = simple_strtol(ioc_data->ioc_inlbuf2, &endp, 0);
79                 if (*endp != '\0')
80                         RETURN(-EINVAL);
81                 to = simple_strtol(ioc_data->ioc_inlbuf3, &endp, 0);
82                 if (*endp != '\0')
83                         RETURN(-EINVAL);
84                 out = ioc_data->ioc_bulk;
85                 ioc_data->ioc_inllen1 = 0;
86         }
87
88         cur_index = le32_to_cpu(rec->lrh_index);
89         if (cur_index < from)
90                 RETURN(0);
91         if (to > 0 && cur_index > to)
92                 RETURN(-LLOG_EEMPTY);
93
94         if (le32_to_cpu(handle->lgh_hdr->llh_flags) & LLOG_F_IS_CAT) {
95                 struct llog_logid_rec *lir = (struct llog_logid_rec *)rec;
96                 if (le32_to_cpu(rec->lrh_type) != LLOG_LOGID_MAGIC) {
97                         CERROR("invalid record in catalog\n");
98                         RETURN(-EINVAL);
99                 }
100
101                 l = snprintf(out, remains,
102                              "[index]: %05d  [logid]: #%llx#%llx#%08x\n",
103                              cur_index, lir->lid_id.lgl_oid, 
104                              lir->lid_id.lgl_ogr, lir->lid_id.lgl_ogen);
105         } else {
106                 l = snprintf(out, remains,
107                              "[index]: %05d  [type]: %02x  [len]: %04d\n", 
108                              cur_index, le32_to_cpu(rec->lrh_type),
109                              le32_to_cpu(rec->lrh_len));
110         }
111         out += l;
112         remains -= l;
113         if (remains <= 0) {
114                 CERROR("not enough space for print log records\n");
115                 RETURN(-LLOG_EEMPTY);
116         }
117
118         RETURN(0);
119 }
120
121 static int llog_remove_log(struct llog_handle *cat, struct llog_logid *logid)
122 {
123         struct llog_handle *log;
124         int rc, index = 0;
125         
126         down_write(&cat->lgh_lock);
127         rc = llog_cat_id2handle(cat, &log, logid);
128         if (rc) {
129                 CDEBUG(D_IOCTL, "cannot find log #%0llx#%0llx#%08x\n",
130                        logid->lgl_oid, logid->lgl_ogr, logid->lgl_ogen);
131                 GOTO(out, rc = -ENOENT);
132         }
133         
134         index = log->u.phd.phd_cookie.lgc_index;
135         LASSERT(index);
136         rc = llog_destroy(log);
137         if (rc) {
138                 CDEBUG(D_IOCTL, "cannot destroy log\n");
139                 GOTO(out, rc);
140         }
141         rc = llog_cancel_rec(cat, index);
142 out:
143         up_write(&cat->lgh_lock);
144         RETURN(rc);
145
146 }
147
148 int llog_ioctl(struct llog_ctxt *ctxt, int cmd, struct obd_ioctl_data *data)
149 {
150         struct llog_logid logid;
151         int err = 0;
152         struct llog_handle *handle = NULL;
153  
154         if (*data->ioc_inlbuf1 == '#') {
155                 err = str2logid(&logid, data->ioc_inlbuf1, data->ioc_inllen1);
156                 if (err)
157                         GOTO(out, err);
158                 err = llog_create(ctxt, &handle, &logid, NULL);
159                 if (err)
160                         GOTO(out, err);        
161         } else if (*data->ioc_inlbuf1 == '$') {
162                 char *name = data->ioc_inlbuf1 + 1;
163                 err = llog_create(ctxt, &handle, NULL, name);
164                 if (err)
165                         GOTO(out, err);
166         } else {
167                 GOTO(out, err = -EINVAL);
168         }
169
170         err = llog_init_handle(handle, 0, NULL);
171         if (err) 
172                 GOTO(out_close, err = -ENOENT);
173        
174         switch (cmd) {
175         case OBD_IOC_LLOG_INFO: {
176                 int l;
177                 int remains = data->ioc_inllen2 + 
178                         size_round(data->ioc_inllen1);
179                 char *out = data->ioc_bulk;
180
181                 l = snprintf(out, remains, 
182                              "logid:            #%llx#%llx#%08x\n"
183                              "flags:            %x (%s)\n"
184                              "records count:    %d\n"
185                              "last index:       %d\n",
186                              handle->lgh_id.lgl_oid, handle->lgh_id.lgl_ogr,
187                              handle->lgh_id.lgl_ogen,
188                              le32_to_cpu(handle->lgh_hdr->llh_flags),
189                              le32_to_cpu(handle->lgh_hdr->llh_flags) & 
190                              LLOG_F_IS_CAT ? "cat" : "plain",
191                              le32_to_cpu(handle->lgh_hdr->llh_count),
192                              handle->lgh_last_idx);
193                 out += l;
194                 remains -= l;
195                 if (remains <= 0) 
196                         CERROR("not enough space for log header info\n");
197
198                 GOTO(out_close, err);
199         }
200         case OBD_IOC_LLOG_PRINT: {
201                 LASSERT(data->ioc_inllen1);
202                 err = llog_process(handle, llog_print_cb, data);
203                 if (err == -LLOG_EEMPTY)
204                         err = 0;
205
206                 GOTO(out_close, err);
207         }
208         case OBD_IOC_LLOG_CANCEL: {
209                 struct llog_cookie cookie;
210                 struct llog_logid plain;
211                 char *endp;
212                 
213                 if (!le32_to_cpu(handle->lgh_hdr->llh_flags) & LLOG_F_IS_CAT)
214                         GOTO(out_close, err = -EINVAL);
215         
216                 err = str2logid(&plain, data->ioc_inlbuf2, data->ioc_inllen2);
217                 if (err)
218                         GOTO(out_close, err);
219                 cookie.lgc_lgl = plain;
220                 cookie.lgc_index = simple_strtoul(data->ioc_inlbuf3, 
221                                                   &endp, 0);
222                 if (*endp != '\0')
223                         GOTO(out_close, err = -EINVAL);
224
225                 err = llog_cat_cancel_records(handle, 1, &cookie);
226                 GOTO(out_close, err);
227         }
228         case OBD_IOC_LLOG_REMOVE: {
229                 struct llog_logid plain;
230                 
231                 if (!le32_to_cpu(handle->lgh_hdr->llh_flags) & LLOG_F_IS_CAT)
232                         GOTO(out_close, err = -EINVAL);
233         
234                 err = str2logid(&plain, data->ioc_inlbuf2, data->ioc_inllen2);
235                 if (err)
236                         GOTO(out_close, err);
237                 err = llog_remove_log(handle, &plain);
238                 GOTO(out_close, err);
239         }
240         }
241         
242 out_close:
243         if (handle->lgh_hdr && 
244             le32_to_cpu(handle->lgh_hdr->llh_flags) & LLOG_F_IS_CAT)
245                 llog_cat_put(handle);
246         else
247                 llog_close(handle);
248 out:
249         RETURN(err);
250 }
251 EXPORT_SYMBOL(llog_ioctl);
252
253 int llog_catlog_list(struct obd_device *obd, int count, 
254                      struct obd_ioctl_data *data)
255 {
256         int size, i;
257         struct llog_logid *idarray, *id;
258         char name[32] = "CATLIST";
259         char *out;
260         int l, remains, rc = 0;
261         
262         size = sizeof(*idarray) * count;
263         
264         OBD_ALLOC(idarray, size);
265         if (!idarray)
266                 RETURN(-ENOMEM);
267         memset(idarray, 0, size);
268         
269         rc = llog_get_cat_list(obd, obd, name, count, idarray);
270         if (rc) {
271                 OBD_FREE(idarray, size);
272                 RETURN(rc);
273         }
274         
275         out = data->ioc_bulk;
276         remains = data->ioc_inllen1;
277         id = idarray;
278         for (i = 0; i < count; i++) {
279                 l = snprintf(out, remains, 
280                              "catalog log: #%llx#%llx#%08x\n",
281                              id->lgl_oid, id->lgl_ogr, id->lgl_ogen);
282                 id++;
283                 out += l;
284                 remains -= l;
285                 if (remains <= 0) {
286                         CWARN("not enough memory for catlog list\n");
287                         break;
288                 }
289         }
290         OBD_FREE(idarray, size);
291         RETURN(0);
292
293 }
294 EXPORT_SYMBOL(llog_catlog_list);