diff options
author | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2011-05-18 07:53:05 -0400 |
---|---|---|
committer | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2011-06-01 04:21:47 -0400 |
commit | 2a734bb8d502b645c061fa329e87c5d651498e68 (patch) | |
tree | d87ee3ddd7c5ccee224044e2178aaf131407b91a /drivers/mtd/ubi/debug.c | |
parent | d99383b00eba9c6ac3dea462d718b2849012ee03 (diff) |
UBI: use debugfs for the extra checks knobs
This patch introduces debugfs support to UBI. All the UBI stuff is kept in the
"ubi" debugfs directory, which contains per-UBI device "ubi/ubiX"
sub-directories, containing debugging files. This file also creates
"ubi/ubiX/chk_gen" and "ubi/ubiX/chk_io" knobs for switching general and I/O
extra checks on and off. And it removes the 'debug_chks' UBI module parameters.
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Diffstat (limited to 'drivers/mtd/ubi/debug.c')
-rw-r--r-- | drivers/mtd/ubi/debug.c | 231 |
1 files changed, 227 insertions, 4 deletions
diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c index 2224cbe41ddf..dce1227929f1 100644 --- a/drivers/mtd/ubi/debug.c +++ b/drivers/mtd/ubi/debug.c | |||
@@ -27,16 +27,15 @@ | |||
27 | #ifdef CONFIG_MTD_UBI_DEBUG | 27 | #ifdef CONFIG_MTD_UBI_DEBUG |
28 | 28 | ||
29 | #include "ubi.h" | 29 | #include "ubi.h" |
30 | #include <linux/debugfs.h> | ||
31 | #include <linux/uaccess.h> | ||
30 | #include <linux/module.h> | 32 | #include <linux/module.h> |
31 | #include <linux/moduleparam.h> | 33 | #include <linux/moduleparam.h> |
32 | 34 | ||
33 | unsigned int ubi_chk_flags; | ||
34 | unsigned int ubi_tst_flags; | 35 | unsigned int ubi_tst_flags; |
35 | 36 | ||
36 | module_param_named(debug_chks, ubi_chk_flags, uint, S_IRUGO | S_IWUSR); | 37 | module_param_named(debug_tsts, ubi_tst_flags, uint, S_IRUGO | S_IWUSR); |
37 | module_param_named(debug_tsts, ubi_chk_flags, uint, S_IRUGO | S_IWUSR); | ||
38 | 38 | ||
39 | MODULE_PARM_DESC(debug_chks, "Debug check flags"); | ||
40 | MODULE_PARM_DESC(debug_tsts, "Debug special test flags"); | 39 | MODULE_PARM_DESC(debug_tsts, "Debug special test flags"); |
41 | 40 | ||
42 | /** | 41 | /** |
@@ -239,4 +238,228 @@ out: | |||
239 | return; | 238 | return; |
240 | } | 239 | } |
241 | 240 | ||
241 | /** | ||
242 | * ubi_debugging_init_dev - initialize debugging for an UBI device. | ||
243 | * @ubi: UBI device description object | ||
244 | * | ||
245 | * This function initializes debugging-related data for UBI device @ubi. | ||
246 | * Returns zero in case of success and a negative error code in case of | ||
247 | * failure. | ||
248 | */ | ||
249 | int ubi_debugging_init_dev(struct ubi_device *ubi) | ||
250 | { | ||
251 | ubi->dbg = kzalloc(sizeof(struct ubi_debug_info), GFP_KERNEL); | ||
252 | if (!ubi->dbg) | ||
253 | return -ENOMEM; | ||
254 | |||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | /** | ||
259 | * ubi_debugging_exit_dev - free debugging data for an UBI device. | ||
260 | * @ubi: UBI device description object | ||
261 | */ | ||
262 | void ubi_debugging_exit_dev(struct ubi_device *ubi) | ||
263 | { | ||
264 | kfree(ubi->dbg); | ||
265 | } | ||
266 | |||
267 | /* | ||
268 | * Root directory for UBI stuff in debugfs. Contains sub-directories which | ||
269 | * contain the stuff specific to particular UBI devices. | ||
270 | */ | ||
271 | static struct dentry *dfs_rootdir; | ||
272 | |||
273 | /** | ||
274 | * ubi_debugfs_init - create UBI debugfs directory. | ||
275 | * | ||
276 | * Create UBI debugfs directory. Returns zero in case of success and a negative | ||
277 | * error code in case of failure. | ||
278 | */ | ||
279 | int ubi_debugfs_init(void) | ||
280 | { | ||
281 | dfs_rootdir = debugfs_create_dir("ubi", NULL); | ||
282 | if (IS_ERR_OR_NULL(dfs_rootdir)) { | ||
283 | int err = dfs_rootdir ? -ENODEV : PTR_ERR(dfs_rootdir); | ||
284 | |||
285 | ubi_err("cannot create \"ubi\" debugfs directory, error %d\n", | ||
286 | err); | ||
287 | return err; | ||
288 | } | ||
289 | |||
290 | return 0; | ||
291 | } | ||
292 | |||
293 | /** | ||
294 | * ubi_debugfs_exit - remove UBI debugfs directory. | ||
295 | */ | ||
296 | void ubi_debugfs_exit(void) | ||
297 | { | ||
298 | debugfs_remove(dfs_rootdir); | ||
299 | } | ||
300 | |||
301 | /* Read an UBI debugfs file */ | ||
302 | static ssize_t dfs_file_read(struct file *file, char __user *user_buf, | ||
303 | size_t count, loff_t *ppos) | ||
304 | { | ||
305 | unsigned long ubi_num = (unsigned long)file->private_data; | ||
306 | struct dentry *dent = file->f_path.dentry; | ||
307 | struct ubi_device *ubi; | ||
308 | struct ubi_debug_info *d; | ||
309 | char buf[3]; | ||
310 | int val; | ||
311 | |||
312 | ubi = ubi_get_device(ubi_num); | ||
313 | if (!ubi) | ||
314 | return -ENODEV; | ||
315 | d = ubi->dbg; | ||
316 | |||
317 | if (dent == d->dfs_chk_gen) | ||
318 | val = d->chk_gen; | ||
319 | else if (dent == d->dfs_chk_io) | ||
320 | val = d->chk_io; | ||
321 | else { | ||
322 | count = -EINVAL; | ||
323 | goto out; | ||
324 | } | ||
325 | |||
326 | if (val) | ||
327 | buf[0] = '1'; | ||
328 | else | ||
329 | buf[0] = '0'; | ||
330 | buf[1] = '\n'; | ||
331 | buf[2] = 0x00; | ||
332 | |||
333 | count = simple_read_from_buffer(user_buf, count, ppos, buf, 2); | ||
334 | |||
335 | out: | ||
336 | ubi_put_device(ubi); | ||
337 | return count; | ||
338 | } | ||
339 | |||
340 | /* Write an UBI debugfs file */ | ||
341 | static ssize_t dfs_file_write(struct file *file, const char __user *user_buf, | ||
342 | size_t count, loff_t *ppos) | ||
343 | { | ||
344 | unsigned long ubi_num = (unsigned long)file->private_data; | ||
345 | struct dentry *dent = file->f_path.dentry; | ||
346 | struct ubi_device *ubi; | ||
347 | struct ubi_debug_info *d; | ||
348 | size_t buf_size; | ||
349 | char buf[8]; | ||
350 | int val; | ||
351 | |||
352 | ubi = ubi_get_device(ubi_num); | ||
353 | if (!ubi) | ||
354 | return -ENODEV; | ||
355 | d = ubi->dbg; | ||
356 | |||
357 | buf_size = min_t(size_t, count, (sizeof(buf) - 1)); | ||
358 | if (copy_from_user(buf, user_buf, buf_size)) { | ||
359 | count = -EFAULT; | ||
360 | goto out; | ||
361 | } | ||
362 | |||
363 | if (buf[0] == '1') | ||
364 | val = 1; | ||
365 | else if (buf[0] == '0') | ||
366 | val = 0; | ||
367 | else { | ||
368 | count = -EINVAL; | ||
369 | goto out; | ||
370 | } | ||
371 | |||
372 | if (dent == d->dfs_chk_gen) | ||
373 | d->chk_gen = val; | ||
374 | else if (dent == d->dfs_chk_io) | ||
375 | d->chk_io = val; | ||
376 | else | ||
377 | count = -EINVAL; | ||
378 | |||
379 | out: | ||
380 | ubi_put_device(ubi); | ||
381 | return count; | ||
382 | } | ||
383 | |||
384 | static int default_open(struct inode *inode, struct file *file) | ||
385 | { | ||
386 | if (inode->i_private) | ||
387 | file->private_data = inode->i_private; | ||
388 | |||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | /* File operations for all UBI debugfs files */ | ||
393 | static const struct file_operations dfs_fops = { | ||
394 | .read = dfs_file_read, | ||
395 | .write = dfs_file_write, | ||
396 | .open = default_open, | ||
397 | .llseek = no_llseek, | ||
398 | .owner = THIS_MODULE, | ||
399 | }; | ||
400 | |||
401 | /** | ||
402 | * ubi_debugfs_init_dev - initialize debugfs for an UBI device. | ||
403 | * @ubi: UBI device description object | ||
404 | * | ||
405 | * This function creates all debugfs files for UBI device @ubi. Returns zero in | ||
406 | * case of success and a negative error code in case of failure. | ||
407 | */ | ||
408 | int ubi_debugfs_init_dev(struct ubi_device *ubi) | ||
409 | { | ||
410 | int err, n; | ||
411 | unsigned long ubi_num = ubi->ubi_num; | ||
412 | const char *fname; | ||
413 | struct dentry *dent; | ||
414 | struct ubi_debug_info *d = ubi->dbg; | ||
415 | |||
416 | n = snprintf(d->dfs_dir_name, UBI_DFS_DIR_LEN + 1, UBI_DFS_DIR_NAME, | ||
417 | ubi->ubi_num); | ||
418 | if (n == UBI_DFS_DIR_LEN) { | ||
419 | /* The array size is too small */ | ||
420 | fname = UBI_DFS_DIR_NAME; | ||
421 | dent = ERR_PTR(-EINVAL); | ||
422 | goto out; | ||
423 | } | ||
424 | |||
425 | fname = d->dfs_dir_name; | ||
426 | dent = debugfs_create_dir(fname, dfs_rootdir); | ||
427 | if (IS_ERR_OR_NULL(dent)) | ||
428 | goto out; | ||
429 | d->dfs_dir = dent; | ||
430 | |||
431 | fname = "chk_gen"; | ||
432 | dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num, | ||
433 | &dfs_fops); | ||
434 | if (IS_ERR_OR_NULL(dent)) | ||
435 | goto out_remove; | ||
436 | d->dfs_chk_gen = dent; | ||
437 | |||
438 | fname = "chk_io"; | ||
439 | dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num, | ||
440 | &dfs_fops); | ||
441 | if (IS_ERR_OR_NULL(dent)) | ||
442 | goto out_remove; | ||
443 | d->dfs_chk_io = dent; | ||
444 | |||
445 | return 0; | ||
446 | |||
447 | out_remove: | ||
448 | debugfs_remove_recursive(d->dfs_dir); | ||
449 | out: | ||
450 | err = dent ? PTR_ERR(dent) : -ENODEV; | ||
451 | ubi_err("cannot create \"%s\" debugfs file or directory, error %d\n", | ||
452 | fname, err); | ||
453 | return err; | ||
454 | } | ||
455 | |||
456 | /** | ||
457 | * dbg_debug_exit_dev - free all debugfs files corresponding to device @ubi | ||
458 | * @ubi: UBI device description object | ||
459 | */ | ||
460 | void ubi_debugfs_exit_dev(struct ubi_device *ubi) | ||
461 | { | ||
462 | debugfs_remove_recursive(ubi->dbg->dfs_dir); | ||
463 | } | ||
464 | |||
242 | #endif /* CONFIG_MTD_UBI_DEBUG */ | 465 | #endif /* CONFIG_MTD_UBI_DEBUG */ |