diff options
Diffstat (limited to 'fs/debugfs')
-rw-r--r-- | fs/debugfs/inode.c | 149 |
1 files changed, 148 insertions, 1 deletions
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 956d5ddddf6e..b80bc846a15a 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c | |||
@@ -23,9 +23,13 @@ | |||
23 | #include <linux/debugfs.h> | 23 | #include <linux/debugfs.h> |
24 | #include <linux/fsnotify.h> | 24 | #include <linux/fsnotify.h> |
25 | #include <linux/string.h> | 25 | #include <linux/string.h> |
26 | #include <linux/seq_file.h> | ||
27 | #include <linux/parser.h> | ||
26 | #include <linux/magic.h> | 28 | #include <linux/magic.h> |
27 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
28 | 30 | ||
31 | #define DEBUGFS_DEFAULT_MODE 0755 | ||
32 | |||
29 | static struct vfsmount *debugfs_mount; | 33 | static struct vfsmount *debugfs_mount; |
30 | static int debugfs_mount_count; | 34 | static int debugfs_mount_count; |
31 | static bool debugfs_registered; | 35 | static bool debugfs_registered; |
@@ -125,11 +129,154 @@ static inline int debugfs_positive(struct dentry *dentry) | |||
125 | return dentry->d_inode && !d_unhashed(dentry); | 129 | return dentry->d_inode && !d_unhashed(dentry); |
126 | } | 130 | } |
127 | 131 | ||
132 | struct debugfs_mount_opts { | ||
133 | uid_t uid; | ||
134 | gid_t gid; | ||
135 | umode_t mode; | ||
136 | }; | ||
137 | |||
138 | enum { | ||
139 | Opt_uid, | ||
140 | Opt_gid, | ||
141 | Opt_mode, | ||
142 | Opt_err | ||
143 | }; | ||
144 | |||
145 | static const match_table_t tokens = { | ||
146 | {Opt_uid, "uid=%u"}, | ||
147 | {Opt_gid, "gid=%u"}, | ||
148 | {Opt_mode, "mode=%o"}, | ||
149 | {Opt_err, NULL} | ||
150 | }; | ||
151 | |||
152 | struct debugfs_fs_info { | ||
153 | struct debugfs_mount_opts mount_opts; | ||
154 | }; | ||
155 | |||
156 | static int debugfs_parse_options(char *data, struct debugfs_mount_opts *opts) | ||
157 | { | ||
158 | substring_t args[MAX_OPT_ARGS]; | ||
159 | int option; | ||
160 | int token; | ||
161 | char *p; | ||
162 | |||
163 | opts->mode = DEBUGFS_DEFAULT_MODE; | ||
164 | |||
165 | while ((p = strsep(&data, ",")) != NULL) { | ||
166 | if (!*p) | ||
167 | continue; | ||
168 | |||
169 | token = match_token(p, tokens, args); | ||
170 | switch (token) { | ||
171 | case Opt_uid: | ||
172 | if (match_int(&args[0], &option)) | ||
173 | return -EINVAL; | ||
174 | opts->uid = option; | ||
175 | break; | ||
176 | case Opt_gid: | ||
177 | if (match_octal(&args[0], &option)) | ||
178 | return -EINVAL; | ||
179 | opts->gid = option; | ||
180 | break; | ||
181 | case Opt_mode: | ||
182 | if (match_octal(&args[0], &option)) | ||
183 | return -EINVAL; | ||
184 | opts->mode = option & S_IALLUGO; | ||
185 | break; | ||
186 | /* | ||
187 | * We might like to report bad mount options here; | ||
188 | * but traditionally debugfs has ignored all mount options | ||
189 | */ | ||
190 | } | ||
191 | } | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | static int debugfs_apply_options(struct super_block *sb) | ||
197 | { | ||
198 | struct debugfs_fs_info *fsi = sb->s_fs_info; | ||
199 | struct inode *inode = sb->s_root->d_inode; | ||
200 | struct debugfs_mount_opts *opts = &fsi->mount_opts; | ||
201 | |||
202 | inode->i_mode &= ~S_IALLUGO; | ||
203 | inode->i_mode |= opts->mode; | ||
204 | |||
205 | inode->i_uid = opts->uid; | ||
206 | inode->i_gid = opts->gid; | ||
207 | |||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | static int debugfs_remount(struct super_block *sb, int *flags, char *data) | ||
212 | { | ||
213 | int err; | ||
214 | struct debugfs_fs_info *fsi = sb->s_fs_info; | ||
215 | |||
216 | err = debugfs_parse_options(data, &fsi->mount_opts); | ||
217 | if (err) | ||
218 | goto fail; | ||
219 | |||
220 | debugfs_apply_options(sb); | ||
221 | |||
222 | fail: | ||
223 | return err; | ||
224 | } | ||
225 | |||
226 | static int debugfs_show_options(struct seq_file *m, struct dentry *root) | ||
227 | { | ||
228 | struct debugfs_fs_info *fsi = root->d_sb->s_fs_info; | ||
229 | struct debugfs_mount_opts *opts = &fsi->mount_opts; | ||
230 | |||
231 | if (opts->uid != 0) | ||
232 | seq_printf(m, ",uid=%u", opts->uid); | ||
233 | if (opts->gid != 0) | ||
234 | seq_printf(m, ",gid=%u", opts->gid); | ||
235 | if (opts->mode != DEBUGFS_DEFAULT_MODE) | ||
236 | seq_printf(m, ",mode=%o", opts->mode); | ||
237 | |||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | static const struct super_operations debugfs_super_operations = { | ||
242 | .statfs = simple_statfs, | ||
243 | .remount_fs = debugfs_remount, | ||
244 | .show_options = debugfs_show_options, | ||
245 | }; | ||
246 | |||
128 | static int debug_fill_super(struct super_block *sb, void *data, int silent) | 247 | static int debug_fill_super(struct super_block *sb, void *data, int silent) |
129 | { | 248 | { |
130 | static struct tree_descr debug_files[] = {{""}}; | 249 | static struct tree_descr debug_files[] = {{""}}; |
250 | struct debugfs_fs_info *fsi; | ||
251 | int err; | ||
252 | |||
253 | save_mount_options(sb, data); | ||
254 | |||
255 | fsi = kzalloc(sizeof(struct debugfs_fs_info), GFP_KERNEL); | ||
256 | sb->s_fs_info = fsi; | ||
257 | if (!fsi) { | ||
258 | err = -ENOMEM; | ||
259 | goto fail; | ||
260 | } | ||
261 | |||
262 | err = debugfs_parse_options(data, &fsi->mount_opts); | ||
263 | if (err) | ||
264 | goto fail; | ||
265 | |||
266 | err = simple_fill_super(sb, DEBUGFS_MAGIC, debug_files); | ||
267 | if (err) | ||
268 | goto fail; | ||
269 | |||
270 | sb->s_op = &debugfs_super_operations; | ||
271 | |||
272 | debugfs_apply_options(sb); | ||
273 | |||
274 | return 0; | ||
131 | 275 | ||
132 | return simple_fill_super(sb, DEBUGFS_MAGIC, debug_files); | 276 | fail: |
277 | kfree(fsi); | ||
278 | sb->s_fs_info = NULL; | ||
279 | return err; | ||
133 | } | 280 | } |
134 | 281 | ||
135 | static struct dentry *debug_mount(struct file_system_type *fs_type, | 282 | static struct dentry *debug_mount(struct file_system_type *fs_type, |