|
@@ -27,16 +27,15 @@
|
|
|
#ifdef CONFIG_MTD_UBI_DEBUG
|
|
|
|
|
|
#include "ubi.h"
|
|
|
+#include <linux/debugfs.h>
|
|
|
+#include <linux/uaccess.h>
|
|
|
#include <linux/module.h>
|
|
|
#include <linux/moduleparam.h>
|
|
|
|
|
|
-unsigned int ubi_chk_flags;
|
|
|
unsigned int ubi_tst_flags;
|
|
|
|
|
|
-module_param_named(debug_chks, ubi_chk_flags, uint, S_IRUGO | S_IWUSR);
|
|
|
-module_param_named(debug_tsts, ubi_chk_flags, uint, S_IRUGO | S_IWUSR);
|
|
|
+module_param_named(debug_tsts, ubi_tst_flags, uint, S_IRUGO | S_IWUSR);
|
|
|
|
|
|
-MODULE_PARM_DESC(debug_chks, "Debug check flags");
|
|
|
MODULE_PARM_DESC(debug_tsts, "Debug special test flags");
|
|
|
|
|
|
/**
|
|
@@ -239,4 +238,228 @@ out:
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * ubi_debugging_init_dev - initialize debugging for an UBI device.
|
|
|
+ * @ubi: UBI device description object
|
|
|
+ *
|
|
|
+ * This function initializes debugging-related data for UBI device @ubi.
|
|
|
+ * Returns zero in case of success and a negative error code in case of
|
|
|
+ * failure.
|
|
|
+ */
|
|
|
+int ubi_debugging_init_dev(struct ubi_device *ubi)
|
|
|
+{
|
|
|
+ ubi->dbg = kzalloc(sizeof(struct ubi_debug_info), GFP_KERNEL);
|
|
|
+ if (!ubi->dbg)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * ubi_debugging_exit_dev - free debugging data for an UBI device.
|
|
|
+ * @ubi: UBI device description object
|
|
|
+ */
|
|
|
+void ubi_debugging_exit_dev(struct ubi_device *ubi)
|
|
|
+{
|
|
|
+ kfree(ubi->dbg);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Root directory for UBI stuff in debugfs. Contains sub-directories which
|
|
|
+ * contain the stuff specific to particular UBI devices.
|
|
|
+ */
|
|
|
+static struct dentry *dfs_rootdir;
|
|
|
+
|
|
|
+/**
|
|
|
+ * ubi_debugfs_init - create UBI debugfs directory.
|
|
|
+ *
|
|
|
+ * Create UBI debugfs directory. Returns zero in case of success and a negative
|
|
|
+ * error code in case of failure.
|
|
|
+ */
|
|
|
+int ubi_debugfs_init(void)
|
|
|
+{
|
|
|
+ dfs_rootdir = debugfs_create_dir("ubi", NULL);
|
|
|
+ if (IS_ERR_OR_NULL(dfs_rootdir)) {
|
|
|
+ int err = dfs_rootdir ? -ENODEV : PTR_ERR(dfs_rootdir);
|
|
|
+
|
|
|
+ ubi_err("cannot create \"ubi\" debugfs directory, error %d\n",
|
|
|
+ err);
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * ubi_debugfs_exit - remove UBI debugfs directory.
|
|
|
+ */
|
|
|
+void ubi_debugfs_exit(void)
|
|
|
+{
|
|
|
+ debugfs_remove(dfs_rootdir);
|
|
|
+}
|
|
|
+
|
|
|
+/* Read an UBI debugfs file */
|
|
|
+static ssize_t dfs_file_read(struct file *file, char __user *user_buf,
|
|
|
+ size_t count, loff_t *ppos)
|
|
|
+{
|
|
|
+ unsigned long ubi_num = (unsigned long)file->private_data;
|
|
|
+ struct dentry *dent = file->f_path.dentry;
|
|
|
+ struct ubi_device *ubi;
|
|
|
+ struct ubi_debug_info *d;
|
|
|
+ char buf[3];
|
|
|
+ int val;
|
|
|
+
|
|
|
+ ubi = ubi_get_device(ubi_num);
|
|
|
+ if (!ubi)
|
|
|
+ return -ENODEV;
|
|
|
+ d = ubi->dbg;
|
|
|
+
|
|
|
+ if (dent == d->dfs_chk_gen)
|
|
|
+ val = d->chk_gen;
|
|
|
+ else if (dent == d->dfs_chk_io)
|
|
|
+ val = d->chk_io;
|
|
|
+ else {
|
|
|
+ count = -EINVAL;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (val)
|
|
|
+ buf[0] = '1';
|
|
|
+ else
|
|
|
+ buf[0] = '0';
|
|
|
+ buf[1] = '\n';
|
|
|
+ buf[2] = 0x00;
|
|
|
+
|
|
|
+ count = simple_read_from_buffer(user_buf, count, ppos, buf, 2);
|
|
|
+
|
|
|
+out:
|
|
|
+ ubi_put_device(ubi);
|
|
|
+ return count;
|
|
|
+}
|
|
|
+
|
|
|
+/* Write an UBI debugfs file */
|
|
|
+static ssize_t dfs_file_write(struct file *file, const char __user *user_buf,
|
|
|
+ size_t count, loff_t *ppos)
|
|
|
+{
|
|
|
+ unsigned long ubi_num = (unsigned long)file->private_data;
|
|
|
+ struct dentry *dent = file->f_path.dentry;
|
|
|
+ struct ubi_device *ubi;
|
|
|
+ struct ubi_debug_info *d;
|
|
|
+ size_t buf_size;
|
|
|
+ char buf[8];
|
|
|
+ int val;
|
|
|
+
|
|
|
+ ubi = ubi_get_device(ubi_num);
|
|
|
+ if (!ubi)
|
|
|
+ return -ENODEV;
|
|
|
+ d = ubi->dbg;
|
|
|
+
|
|
|
+ buf_size = min_t(size_t, count, (sizeof(buf) - 1));
|
|
|
+ if (copy_from_user(buf, user_buf, buf_size)) {
|
|
|
+ count = -EFAULT;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (buf[0] == '1')
|
|
|
+ val = 1;
|
|
|
+ else if (buf[0] == '0')
|
|
|
+ val = 0;
|
|
|
+ else {
|
|
|
+ count = -EINVAL;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (dent == d->dfs_chk_gen)
|
|
|
+ d->chk_gen = val;
|
|
|
+ else if (dent == d->dfs_chk_io)
|
|
|
+ d->chk_io = val;
|
|
|
+ else
|
|
|
+ count = -EINVAL;
|
|
|
+
|
|
|
+out:
|
|
|
+ ubi_put_device(ubi);
|
|
|
+ return count;
|
|
|
+}
|
|
|
+
|
|
|
+static int default_open(struct inode *inode, struct file *file)
|
|
|
+{
|
|
|
+ if (inode->i_private)
|
|
|
+ file->private_data = inode->i_private;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/* File operations for all UBI debugfs files */
|
|
|
+static const struct file_operations dfs_fops = {
|
|
|
+ .read = dfs_file_read,
|
|
|
+ .write = dfs_file_write,
|
|
|
+ .open = default_open,
|
|
|
+ .llseek = no_llseek,
|
|
|
+ .owner = THIS_MODULE,
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * ubi_debugfs_init_dev - initialize debugfs for an UBI device.
|
|
|
+ * @ubi: UBI device description object
|
|
|
+ *
|
|
|
+ * This function creates all debugfs files for UBI device @ubi. Returns zero in
|
|
|
+ * case of success and a negative error code in case of failure.
|
|
|
+ */
|
|
|
+int ubi_debugfs_init_dev(struct ubi_device *ubi)
|
|
|
+{
|
|
|
+ int err, n;
|
|
|
+ unsigned long ubi_num = ubi->ubi_num;
|
|
|
+ const char *fname;
|
|
|
+ struct dentry *dent;
|
|
|
+ struct ubi_debug_info *d = ubi->dbg;
|
|
|
+
|
|
|
+ n = snprintf(d->dfs_dir_name, UBI_DFS_DIR_LEN + 1, UBI_DFS_DIR_NAME,
|
|
|
+ ubi->ubi_num);
|
|
|
+ if (n == UBI_DFS_DIR_LEN) {
|
|
|
+ /* The array size is too small */
|
|
|
+ fname = UBI_DFS_DIR_NAME;
|
|
|
+ dent = ERR_PTR(-EINVAL);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ fname = d->dfs_dir_name;
|
|
|
+ dent = debugfs_create_dir(fname, dfs_rootdir);
|
|
|
+ if (IS_ERR_OR_NULL(dent))
|
|
|
+ goto out;
|
|
|
+ d->dfs_dir = dent;
|
|
|
+
|
|
|
+ fname = "chk_gen";
|
|
|
+ dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
|
|
|
+ &dfs_fops);
|
|
|
+ if (IS_ERR_OR_NULL(dent))
|
|
|
+ goto out_remove;
|
|
|
+ d->dfs_chk_gen = dent;
|
|
|
+
|
|
|
+ fname = "chk_io";
|
|
|
+ dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
|
|
|
+ &dfs_fops);
|
|
|
+ if (IS_ERR_OR_NULL(dent))
|
|
|
+ goto out_remove;
|
|
|
+ d->dfs_chk_io = dent;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+
|
|
|
+out_remove:
|
|
|
+ debugfs_remove_recursive(d->dfs_dir);
|
|
|
+out:
|
|
|
+ err = dent ? PTR_ERR(dent) : -ENODEV;
|
|
|
+ ubi_err("cannot create \"%s\" debugfs file or directory, error %d\n",
|
|
|
+ fname, err);
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * dbg_debug_exit_dev - free all debugfs files corresponding to device @ubi
|
|
|
+ * @ubi: UBI device description object
|
|
|
+ */
|
|
|
+void ubi_debugfs_exit_dev(struct ubi_device *ubi)
|
|
|
+{
|
|
|
+ debugfs_remove_recursive(ubi->dbg->dfs_dir);
|
|
|
+}
|
|
|
+
|
|
|
#endif /* CONFIG_MTD_UBI_DEBUG */
|