diff options
-rw-r--r-- | Documentation/filesystems/ubifs.txt | 26 | ||||
-rw-r--r-- | fs/ubifs/debug.c | 140 | ||||
-rw-r--r-- | fs/ubifs/debug.h | 72 |
3 files changed, 159 insertions, 79 deletions
diff --git a/Documentation/filesystems/ubifs.txt b/Documentation/filesystems/ubifs.txt index 91ef07652cd..a0a61d2f389 100644 --- a/Documentation/filesystems/ubifs.txt +++ b/Documentation/filesystems/ubifs.txt | |||
@@ -111,32 +111,6 @@ The following is an example of the kernel boot arguments to attach mtd0 | |||
111 | to UBI and mount volume "rootfs": | 111 | to UBI and mount volume "rootfs": |
112 | ubi.mtd=0 root=ubi0:rootfs rootfstype=ubifs | 112 | ubi.mtd=0 root=ubi0:rootfs rootfstype=ubifs |
113 | 113 | ||
114 | |||
115 | Module Parameters for Debugging | ||
116 | =============================== | ||
117 | |||
118 | When UBIFS has been compiled with debugging enabled, there are 2 module | ||
119 | parameters that are available to control aspects of testing and debugging. | ||
120 | |||
121 | debug_chks Selects extra checks that UBIFS can do while running: | ||
122 | |||
123 | Check Flag value | ||
124 | |||
125 | General checks 1 | ||
126 | Check the index 2 | ||
127 | Check orphan area 8 | ||
128 | Check LEB properties (lprops) 32 | ||
129 | Check leaf nodes and inodes 64 | ||
130 | |||
131 | debug_tsts Selects a mode of testing, as follows: | ||
132 | |||
133 | Test mode Flag value | ||
134 | |||
135 | Failure mode for recovery testing 4 | ||
136 | |||
137 | For example, set debug_chks to 3 to enable general and TNC checks. | ||
138 | |||
139 | |||
140 | References | 114 | References |
141 | ========== | 115 | ========== |
142 | 116 | ||
diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index a967d6800ea..fdfa5dea5b9 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c | |||
@@ -31,9 +31,9 @@ | |||
31 | 31 | ||
32 | #include "ubifs.h" | 32 | #include "ubifs.h" |
33 | #include <linux/module.h> | 33 | #include <linux/module.h> |
34 | #include <linux/moduleparam.h> | ||
35 | #include <linux/debugfs.h> | 34 | #include <linux/debugfs.h> |
36 | #include <linux/math64.h> | 35 | #include <linux/math64.h> |
36 | #include <linux/uaccess.h> | ||
37 | 37 | ||
38 | #ifdef CONFIG_UBIFS_FS_DEBUG | 38 | #ifdef CONFIG_UBIFS_FS_DEBUG |
39 | 39 | ||
@@ -42,15 +42,6 @@ DEFINE_SPINLOCK(dbg_lock); | |||
42 | static char dbg_key_buf0[128]; | 42 | static char dbg_key_buf0[128]; |
43 | static char dbg_key_buf1[128]; | 43 | static char dbg_key_buf1[128]; |
44 | 44 | ||
45 | unsigned int ubifs_chk_flags; | ||
46 | unsigned int ubifs_tst_flags; | ||
47 | |||
48 | module_param_named(debug_chks, ubifs_chk_flags, uint, S_IRUGO | S_IWUSR); | ||
49 | module_param_named(debug_tsts, ubifs_tst_flags, uint, S_IRUGO | S_IWUSR); | ||
50 | |||
51 | MODULE_PARM_DESC(debug_chks, "Debug check flags"); | ||
52 | MODULE_PARM_DESC(debug_tsts, "Debug special test flags"); | ||
53 | |||
54 | static const char *get_key_fmt(int fmt) | 45 | static const char *get_key_fmt(int fmt) |
55 | { | 46 | { |
56 | switch (fmt) { | 47 | switch (fmt) { |
@@ -2886,21 +2877,93 @@ static int open_debugfs_file(struct inode *inode, struct file *file) | |||
2886 | return nonseekable_open(inode, file); | 2877 | return nonseekable_open(inode, file); |
2887 | } | 2878 | } |
2888 | 2879 | ||
2889 | static ssize_t write_debugfs_file(struct file *file, const char __user *buf, | 2880 | static ssize_t dfs_file_read(struct file *file, char __user *u, size_t count, |
2890 | size_t count, loff_t *ppos) | 2881 | loff_t *ppos) |
2882 | { | ||
2883 | struct dentry *dent = file->f_path.dentry; | ||
2884 | struct ubifs_info *c = file->private_data; | ||
2885 | struct ubifs_debug_info *d = c->dbg; | ||
2886 | char buf[3]; | ||
2887 | int val; | ||
2888 | |||
2889 | if (dent == d->dfs_chk_gen) | ||
2890 | val = d->chk_gen; | ||
2891 | else if (dent == d->dfs_chk_index) | ||
2892 | val = d->chk_index; | ||
2893 | else if (dent == d->dfs_chk_orph) | ||
2894 | val = d->chk_orph; | ||
2895 | else if (dent == d->dfs_chk_lprops) | ||
2896 | val = d->chk_lprops; | ||
2897 | else if (dent == d->dfs_chk_fs) | ||
2898 | val = d->chk_fs; | ||
2899 | else if (dent == d->dfs_tst_rcvry) | ||
2900 | val = d->tst_rcvry; | ||
2901 | else | ||
2902 | return -EINVAL; | ||
2903 | |||
2904 | if (val) | ||
2905 | buf[0] = '1'; | ||
2906 | else | ||
2907 | buf[0] = '0'; | ||
2908 | buf[1] = '\n'; | ||
2909 | buf[2] = 0x00; | ||
2910 | |||
2911 | return simple_read_from_buffer(u, count, ppos, buf, 2); | ||
2912 | } | ||
2913 | |||
2914 | static ssize_t dfs_file_write(struct file *file, const char __user *u, | ||
2915 | size_t count, loff_t *ppos) | ||
2891 | { | 2916 | { |
2892 | struct ubifs_info *c = file->private_data; | 2917 | struct ubifs_info *c = file->private_data; |
2893 | struct ubifs_debug_info *d = c->dbg; | 2918 | struct ubifs_debug_info *d = c->dbg; |
2919 | struct dentry *dent = file->f_path.dentry; | ||
2920 | size_t buf_size; | ||
2921 | char buf[8]; | ||
2922 | int val; | ||
2894 | 2923 | ||
2895 | if (file->f_path.dentry == d->dfs_dump_lprops) | 2924 | /* |
2925 | * FIXME: this is racy - the file-system might have already been | ||
2926 | * unmounted and we'd oops in this case. | ||
2927 | */ | ||
2928 | if (file->f_path.dentry == d->dfs_dump_lprops) { | ||
2896 | dbg_dump_lprops(c); | 2929 | dbg_dump_lprops(c); |
2897 | else if (file->f_path.dentry == d->dfs_dump_budg) | 2930 | return count; |
2931 | } | ||
2932 | if (file->f_path.dentry == d->dfs_dump_budg) { | ||
2898 | dbg_dump_budg(c, &c->bi); | 2933 | dbg_dump_budg(c, &c->bi); |
2899 | else if (file->f_path.dentry == d->dfs_dump_tnc) { | 2934 | return count; |
2935 | } | ||
2936 | if (file->f_path.dentry == d->dfs_dump_tnc) { | ||
2900 | mutex_lock(&c->tnc_mutex); | 2937 | mutex_lock(&c->tnc_mutex); |
2901 | dbg_dump_tnc(c); | 2938 | dbg_dump_tnc(c); |
2902 | mutex_unlock(&c->tnc_mutex); | 2939 | mutex_unlock(&c->tnc_mutex); |
2903 | } else | 2940 | return count; |
2941 | } | ||
2942 | |||
2943 | buf_size = min_t(size_t, count, (sizeof(buf) - 1)); | ||
2944 | if (copy_from_user(buf, u, buf_size)) | ||
2945 | return -EFAULT; | ||
2946 | |||
2947 | if (buf[0] == '1') | ||
2948 | val = 1; | ||
2949 | else if (buf[0] == '0') | ||
2950 | val = 0; | ||
2951 | else | ||
2952 | return -EINVAL; | ||
2953 | |||
2954 | if (dent == d->dfs_chk_gen) | ||
2955 | d->chk_gen = val; | ||
2956 | else if (dent == d->dfs_chk_index) | ||
2957 | d->chk_index = val; | ||
2958 | else if (dent == d->dfs_chk_orph) | ||
2959 | d->chk_orph = val; | ||
2960 | else if (dent == d->dfs_chk_lprops) | ||
2961 | d->chk_lprops = val; | ||
2962 | else if (dent == d->dfs_chk_fs) | ||
2963 | d->chk_fs = val; | ||
2964 | else if (dent == d->dfs_tst_rcvry) | ||
2965 | d->tst_rcvry = val; | ||
2966 | else | ||
2904 | return -EINVAL; | 2967 | return -EINVAL; |
2905 | 2968 | ||
2906 | return count; | 2969 | return count; |
@@ -2908,7 +2971,8 @@ static ssize_t write_debugfs_file(struct file *file, const char __user *buf, | |||
2908 | 2971 | ||
2909 | static const struct file_operations dfs_fops = { | 2972 | static const struct file_operations dfs_fops = { |
2910 | .open = open_debugfs_file, | 2973 | .open = open_debugfs_file, |
2911 | .write = write_debugfs_file, | 2974 | .read = dfs_file_read, |
2975 | .write = dfs_file_write, | ||
2912 | .owner = THIS_MODULE, | 2976 | .owner = THIS_MODULE, |
2913 | .llseek = no_llseek, | 2977 | .llseek = no_llseek, |
2914 | }; | 2978 | }; |
@@ -2965,6 +3029,48 @@ int dbg_debugfs_init_fs(struct ubifs_info *c) | |||
2965 | goto out_remove; | 3029 | goto out_remove; |
2966 | d->dfs_dump_tnc = dent; | 3030 | d->dfs_dump_tnc = dent; |
2967 | 3031 | ||
3032 | fname = "chk_general"; | ||
3033 | dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c, | ||
3034 | &dfs_fops); | ||
3035 | if (IS_ERR_OR_NULL(dent)) | ||
3036 | goto out_remove; | ||
3037 | d->dfs_chk_gen = dent; | ||
3038 | |||
3039 | fname = "chk_index"; | ||
3040 | dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c, | ||
3041 | &dfs_fops); | ||
3042 | if (IS_ERR_OR_NULL(dent)) | ||
3043 | goto out_remove; | ||
3044 | d->dfs_chk_index = dent; | ||
3045 | |||
3046 | fname = "chk_orphans"; | ||
3047 | dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c, | ||
3048 | &dfs_fops); | ||
3049 | if (IS_ERR_OR_NULL(dent)) | ||
3050 | goto out_remove; | ||
3051 | d->dfs_chk_orph = dent; | ||
3052 | |||
3053 | fname = "chk_lprops"; | ||
3054 | dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c, | ||
3055 | &dfs_fops); | ||
3056 | if (IS_ERR_OR_NULL(dent)) | ||
3057 | goto out_remove; | ||
3058 | d->dfs_chk_lprops = dent; | ||
3059 | |||
3060 | fname = "chk_fs"; | ||
3061 | dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c, | ||
3062 | &dfs_fops); | ||
3063 | if (IS_ERR_OR_NULL(dent)) | ||
3064 | goto out_remove; | ||
3065 | d->dfs_chk_fs = dent; | ||
3066 | |||
3067 | fname = "tst_recovery"; | ||
3068 | dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c, | ||
3069 | &dfs_fops); | ||
3070 | if (IS_ERR_OR_NULL(dent)) | ||
3071 | goto out_remove; | ||
3072 | d->dfs_tst_rcvry = dent; | ||
3073 | |||
2968 | return 0; | 3074 | return 0; |
2969 | 3075 | ||
2970 | out_remove: | 3076 | out_remove: |
diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h index 44265a3a08c..8c3bdd37803 100644 --- a/fs/ubifs/debug.h +++ b/fs/ubifs/debug.h | |||
@@ -43,11 +43,13 @@ typedef int (*dbg_znode_callback)(struct ubifs_info *c, | |||
43 | * @old_zroot: old index root - used by 'dbg_check_old_index()' | 43 | * @old_zroot: old index root - used by 'dbg_check_old_index()' |
44 | * @old_zroot_level: old index root level - used by 'dbg_check_old_index()' | 44 | * @old_zroot_level: old index root level - used by 'dbg_check_old_index()' |
45 | * @old_zroot_sqnum: old index root sqnum - used by 'dbg_check_old_index()' | 45 | * @old_zroot_sqnum: old index root sqnum - used by 'dbg_check_old_index()' |
46 | * | ||
46 | * @failure_mode: failure mode for recovery testing | 47 | * @failure_mode: failure mode for recovery testing |
47 | * @fail_delay: 0=>don't delay, 1=>delay a time, 2=>delay a number of calls | 48 | * @fail_delay: 0=>don't delay, 1=>delay a time, 2=>delay a number of calls |
48 | * @fail_timeout: time in jiffies when delay of failure mode expires | 49 | * @fail_timeout: time in jiffies when delay of failure mode expires |
49 | * @fail_cnt: current number of calls to failure mode I/O functions | 50 | * @fail_cnt: current number of calls to failure mode I/O functions |
50 | * @fail_cnt_max: number of calls by which to delay failure mode | 51 | * @fail_cnt_max: number of calls by which to delay failure mode |
52 | * | ||
51 | * @chk_lpt_sz: used by LPT tree size checker | 53 | * @chk_lpt_sz: used by LPT tree size checker |
52 | * @chk_lpt_sz2: used by LPT tree size checker | 54 | * @chk_lpt_sz2: used by LPT tree size checker |
53 | * @chk_lpt_wastage: used by LPT tree size checker | 55 | * @chk_lpt_wastage: used by LPT tree size checker |
@@ -61,21 +63,36 @@ typedef int (*dbg_znode_callback)(struct ubifs_info *c, | |||
61 | * @saved_free: saved amount of free space | 63 | * @saved_free: saved amount of free space |
62 | * @saved_idx_gc_cnt: saved value of @c->idx_gc_cnt | 64 | * @saved_idx_gc_cnt: saved value of @c->idx_gc_cnt |
63 | * | 65 | * |
66 | * @chk_gen: if general extra checks are enabled | ||
67 | * @chk_index: if index xtra checks are enabled | ||
68 | * @chk_orph: if orphans extra checks are enabled | ||
69 | * @chk_lprops: if lprops extra checks are enabled | ||
70 | * @chk_fs: if UBIFS contents extra checks are enabled | ||
71 | * @tst_rcvry: if UBIFS recovery testing mode enabled | ||
72 | * | ||
64 | * @dfs_dir_name: name of debugfs directory containing this file-system's files | 73 | * @dfs_dir_name: name of debugfs directory containing this file-system's files |
65 | * @dfs_dir: direntry object of the file-system debugfs directory | 74 | * @dfs_dir: direntry object of the file-system debugfs directory |
66 | * @dfs_dump_lprops: "dump lprops" debugfs knob | 75 | * @dfs_dump_lprops: "dump lprops" debugfs knob |
67 | * @dfs_dump_budg: "dump budgeting information" debugfs knob | 76 | * @dfs_dump_budg: "dump budgeting information" debugfs knob |
68 | * @dfs_dump_tnc: "dump TNC" debugfs knob | 77 | * @dfs_dump_tnc: "dump TNC" debugfs knob |
78 | * @dfs_chk_gen: debugfs knob to enable UBIFS general extra checks | ||
79 | * @dfs_chk_index: debugfs knob to enable UBIFS index extra checks | ||
80 | * @dfs_chk_orph: debugfs knob to enable UBIFS orphans extra checks | ||
81 | * @dfs_chk_lprops: debugfs knob to enable UBIFS LEP properties extra checks | ||
82 | * @dfs_chk_fs: debugfs knob to enable UBIFS contents extra checks | ||
83 | * @dfs_tst_rcvry: debugfs knob to enable UBIFS recovery testing | ||
69 | */ | 84 | */ |
70 | struct ubifs_debug_info { | 85 | struct ubifs_debug_info { |
71 | struct ubifs_zbranch old_zroot; | 86 | struct ubifs_zbranch old_zroot; |
72 | int old_zroot_level; | 87 | int old_zroot_level; |
73 | unsigned long long old_zroot_sqnum; | 88 | unsigned long long old_zroot_sqnum; |
89 | |||
74 | int failure_mode; | 90 | int failure_mode; |
75 | int fail_delay; | 91 | int fail_delay; |
76 | unsigned long fail_timeout; | 92 | unsigned long fail_timeout; |
77 | unsigned int fail_cnt; | 93 | unsigned int fail_cnt; |
78 | unsigned int fail_cnt_max; | 94 | unsigned int fail_cnt_max; |
95 | |||
79 | long long chk_lpt_sz; | 96 | long long chk_lpt_sz; |
80 | long long chk_lpt_sz2; | 97 | long long chk_lpt_sz2; |
81 | long long chk_lpt_wastage; | 98 | long long chk_lpt_wastage; |
@@ -89,11 +106,24 @@ struct ubifs_debug_info { | |||
89 | long long saved_free; | 106 | long long saved_free; |
90 | int saved_idx_gc_cnt; | 107 | int saved_idx_gc_cnt; |
91 | 108 | ||
109 | unsigned int chk_gen:1; | ||
110 | unsigned int chk_index:1; | ||
111 | unsigned int chk_orph:1; | ||
112 | unsigned int chk_lprops:1; | ||
113 | unsigned int chk_fs:1; | ||
114 | unsigned int tst_rcvry:1; | ||
115 | |||
92 | char dfs_dir_name[UBIFS_DFS_DIR_LEN + 1]; | 116 | char dfs_dir_name[UBIFS_DFS_DIR_LEN + 1]; |
93 | struct dentry *dfs_dir; | 117 | struct dentry *dfs_dir; |
94 | struct dentry *dfs_dump_lprops; | 118 | struct dentry *dfs_dump_lprops; |
95 | struct dentry *dfs_dump_budg; | 119 | struct dentry *dfs_dump_budg; |
96 | struct dentry *dfs_dump_tnc; | 120 | struct dentry *dfs_dump_tnc; |
121 | struct dentry *dfs_chk_gen; | ||
122 | struct dentry *dfs_chk_index; | ||
123 | struct dentry *dfs_chk_orph; | ||
124 | struct dentry *dfs_chk_lprops; | ||
125 | struct dentry *dfs_chk_fs; | ||
126 | struct dentry *dfs_tst_rcvry; | ||
97 | }; | 127 | }; |
98 | 128 | ||
99 | #define ubifs_assert(expr) do { \ | 129 | #define ubifs_assert(expr) do { \ |
@@ -169,59 +199,29 @@ const char *dbg_key_str1(const struct ubifs_info *c, | |||
169 | 199 | ||
170 | extern spinlock_t dbg_lock; | 200 | extern spinlock_t dbg_lock; |
171 | 201 | ||
172 | /* | ||
173 | * Debugging check flags. | ||
174 | * | ||
175 | * UBIFS_CHK_GEN: general checks | ||
176 | * UBIFS_CHK_INDEX: check the index | ||
177 | * UBIFS_CHK_ORPH: check orphans | ||
178 | * UBIFS_CHK_LPROPS: check lprops | ||
179 | * UBIFS_CHK_FS: check the file-system | ||
180 | */ | ||
181 | enum { | ||
182 | UBIFS_CHK_GEN = 0x1, | ||
183 | UBIFS_CHK_INDEX = 0x2, | ||
184 | UBIFS_CHK_ORPH = 0x8, | ||
185 | UBIFS_CHK_LPROPS = 0x20, | ||
186 | UBIFS_CHK_FS = 0x40, | ||
187 | }; | ||
188 | |||
189 | /* | ||
190 | * Special testing flags. | ||
191 | * | ||
192 | * UBIFS_TST_RCVRY: failure mode for recovery testing | ||
193 | */ | ||
194 | enum { | ||
195 | UBIFS_TST_RCVRY = 0x4, | ||
196 | }; | ||
197 | |||
198 | extern unsigned int ubifs_msg_flags; | ||
199 | extern unsigned int ubifs_chk_flags; | ||
200 | extern unsigned int ubifs_tst_flags; | ||
201 | |||
202 | static inline int dbg_is_chk_gen(const struct ubifs_info *c) | 202 | static inline int dbg_is_chk_gen(const struct ubifs_info *c) |
203 | { | 203 | { |
204 | return !!(ubifs_chk_flags & UBIFS_CHK_GEN); | 204 | return c->dbg->chk_gen; |
205 | } | 205 | } |
206 | static inline int dbg_is_chk_index(const struct ubifs_info *c) | 206 | static inline int dbg_is_chk_index(const struct ubifs_info *c) |
207 | { | 207 | { |
208 | return !!(ubifs_chk_flags & UBIFS_CHK_INDEX); | 208 | return c->dbg->chk_index; |
209 | } | 209 | } |
210 | static inline int dbg_is_chk_orph(const struct ubifs_info *c) | 210 | static inline int dbg_is_chk_orph(const struct ubifs_info *c) |
211 | { | 211 | { |
212 | return !!(ubifs_chk_flags & UBIFS_CHK_ORPH); | 212 | return c->dbg->chk_orph; |
213 | } | 213 | } |
214 | static inline int dbg_is_chk_lprops(const struct ubifs_info *c) | 214 | static inline int dbg_is_chk_lprops(const struct ubifs_info *c) |
215 | { | 215 | { |
216 | return !!(ubifs_chk_flags & UBIFS_CHK_LPROPS); | 216 | return c->dbg->chk_lprops; |
217 | } | 217 | } |
218 | static inline int dbg_is_chk_fs(const struct ubifs_info *c) | 218 | static inline int dbg_is_chk_fs(const struct ubifs_info *c) |
219 | { | 219 | { |
220 | return !!(ubifs_chk_flags & UBIFS_CHK_FS); | 220 | return c->dbg->chk_fs; |
221 | } | 221 | } |
222 | static inline int dbg_is_tst_rcvry(const struct ubifs_info *c) | 222 | static inline int dbg_is_tst_rcvry(const struct ubifs_info *c) |
223 | { | 223 | { |
224 | return !!(ubifs_tst_flags & UBIFS_TST_RCVRY); | 224 | return c->dbg->tst_rcvry; |
225 | } | 225 | } |
226 | 226 | ||
227 | int ubifs_debugging_init(struct ubifs_info *c); | 227 | int ubifs_debugging_init(struct ubifs_info *c); |