diff options
author | Peter Oberparleiter <peter.oberparleiter@de.ibm.com> | 2007-02-13 06:13:54 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-02-16 18:19:17 -0500 |
commit | 66f5496393dcc9f9d05c46f00ed93d5040d6035b (patch) | |
tree | d5952a691e346b2715252d8b8cd2100d6c804a39 /fs/debugfs | |
parent | b92be9f1ecd3c8b16e9bb22d55bb97b3d89f091a (diff) |
debugfs: implement symbolic links
debugfs: implement symbolic links
Implement a new function debugfs_create_symlink() which can be used
to create symbolic links in debugfs. This function can be useful
for people moving functionality from /proc to debugfs (e.g. the
gcov-kernel patch).
Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'fs/debugfs')
-rw-r--r-- | fs/debugfs/file.c | 12 | ||||
-rw-r--r-- | fs/debugfs/inode.c | 76 |
2 files changed, 84 insertions, 4 deletions
diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 8d130cc85322..682f928b7f4d 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/fs.h> | 17 | #include <linux/fs.h> |
18 | #include <linux/pagemap.h> | 18 | #include <linux/pagemap.h> |
19 | #include <linux/namei.h> | ||
19 | #include <linux/debugfs.h> | 20 | #include <linux/debugfs.h> |
20 | 21 | ||
21 | static ssize_t default_read_file(struct file *file, char __user *buf, | 22 | static ssize_t default_read_file(struct file *file, char __user *buf, |
@@ -44,6 +45,17 @@ const struct file_operations debugfs_file_operations = { | |||
44 | .open = default_open, | 45 | .open = default_open, |
45 | }; | 46 | }; |
46 | 47 | ||
48 | static void *debugfs_follow_link(struct dentry *dentry, struct nameidata *nd) | ||
49 | { | ||
50 | nd_set_link(nd, dentry->d_inode->i_private); | ||
51 | return NULL; | ||
52 | } | ||
53 | |||
54 | const struct inode_operations debugfs_link_operations = { | ||
55 | .readlink = generic_readlink, | ||
56 | .follow_link = debugfs_follow_link, | ||
57 | }; | ||
58 | |||
47 | static void debugfs_u8_set(void *data, u64 val) | 59 | static void debugfs_u8_set(void *data, u64 val) |
48 | { | 60 | { |
49 | *(u8 *)data = val; | 61 | *(u8 *)data = val; |
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index c692487346ea..9c51a9f630a1 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c | |||
@@ -25,11 +25,13 @@ | |||
25 | #include <linux/namei.h> | 25 | #include <linux/namei.h> |
26 | #include <linux/debugfs.h> | 26 | #include <linux/debugfs.h> |
27 | #include <linux/fsnotify.h> | 27 | #include <linux/fsnotify.h> |
28 | #include <linux/string.h> | ||
28 | 29 | ||
29 | #define DEBUGFS_MAGIC 0x64626720 | 30 | #define DEBUGFS_MAGIC 0x64626720 |
30 | 31 | ||
31 | /* declared over in file.c */ | 32 | /* declared over in file.c */ |
32 | extern struct file_operations debugfs_file_operations; | 33 | extern struct file_operations debugfs_file_operations; |
34 | extern struct inode_operations debugfs_link_operations; | ||
33 | 35 | ||
34 | static struct vfsmount *debugfs_mount; | 36 | static struct vfsmount *debugfs_mount; |
35 | static int debugfs_mount_count; | 37 | static int debugfs_mount_count; |
@@ -51,6 +53,9 @@ static struct inode *debugfs_get_inode(struct super_block *sb, int mode, dev_t d | |||
51 | case S_IFREG: | 53 | case S_IFREG: |
52 | inode->i_fop = &debugfs_file_operations; | 54 | inode->i_fop = &debugfs_file_operations; |
53 | break; | 55 | break; |
56 | case S_IFLNK: | ||
57 | inode->i_op = &debugfs_link_operations; | ||
58 | break; | ||
54 | case S_IFDIR: | 59 | case S_IFDIR: |
55 | inode->i_op = &simple_dir_inode_operations; | 60 | inode->i_op = &simple_dir_inode_operations; |
56 | inode->i_fop = &simple_dir_operations; | 61 | inode->i_fop = &simple_dir_operations; |
@@ -96,6 +101,12 @@ static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
96 | return res; | 101 | return res; |
97 | } | 102 | } |
98 | 103 | ||
104 | static int debugfs_link(struct inode *dir, struct dentry *dentry, int mode) | ||
105 | { | ||
106 | mode = (mode & S_IALLUGO) | S_IFLNK; | ||
107 | return debugfs_mknod(dir, dentry, mode, 0); | ||
108 | } | ||
109 | |||
99 | static int debugfs_create(struct inode *dir, struct dentry *dentry, int mode) | 110 | static int debugfs_create(struct inode *dir, struct dentry *dentry, int mode) |
100 | { | 111 | { |
101 | int res; | 112 | int res; |
@@ -158,10 +169,17 @@ static int debugfs_create_by_name(const char *name, mode_t mode, | |||
158 | mutex_lock(&parent->d_inode->i_mutex); | 169 | mutex_lock(&parent->d_inode->i_mutex); |
159 | *dentry = lookup_one_len(name, parent, strlen(name)); | 170 | *dentry = lookup_one_len(name, parent, strlen(name)); |
160 | if (!IS_ERR(*dentry)) { | 171 | if (!IS_ERR(*dentry)) { |
161 | if ((mode & S_IFMT) == S_IFDIR) | 172 | switch (mode & S_IFMT) { |
173 | case S_IFDIR: | ||
162 | error = debugfs_mkdir(parent->d_inode, *dentry, mode); | 174 | error = debugfs_mkdir(parent->d_inode, *dentry, mode); |
163 | else | 175 | break; |
176 | case S_IFLNK: | ||
177 | error = debugfs_link(parent->d_inode, *dentry, mode); | ||
178 | break; | ||
179 | default: | ||
164 | error = debugfs_create(parent->d_inode, *dentry, mode); | 180 | error = debugfs_create(parent->d_inode, *dentry, mode); |
181 | break; | ||
182 | } | ||
165 | dput(*dentry); | 183 | dput(*dentry); |
166 | } else | 184 | } else |
167 | error = PTR_ERR(*dentry); | 185 | error = PTR_ERR(*dentry); |
@@ -259,6 +277,49 @@ struct dentry *debugfs_create_dir(const char *name, struct dentry *parent) | |||
259 | EXPORT_SYMBOL_GPL(debugfs_create_dir); | 277 | EXPORT_SYMBOL_GPL(debugfs_create_dir); |
260 | 278 | ||
261 | /** | 279 | /** |
280 | * debugfs_create_symlink- create a symbolic link in the debugfs filesystem | ||
281 | * @name: a pointer to a string containing the name of the symbolic link to | ||
282 | * create. | ||
283 | * @parent: a pointer to the parent dentry for this symbolic link. This | ||
284 | * should be a directory dentry if set. If this paramater is NULL, | ||
285 | * then the symbolic link will be created in the root of the debugfs | ||
286 | * filesystem. | ||
287 | * @target: a pointer to a string containing the path to the target of the | ||
288 | * symbolic link. | ||
289 | * | ||
290 | * This function creates a symbolic link with the given name in debugfs that | ||
291 | * links to the given target path. | ||
292 | * | ||
293 | * This function will return a pointer to a dentry if it succeeds. This | ||
294 | * pointer must be passed to the debugfs_remove() function when the symbolic | ||
295 | * link is to be removed (no automatic cleanup happens if your module is | ||
296 | * unloaded, you are responsible here.) If an error occurs, %NULL will be | ||
297 | * returned. | ||
298 | * | ||
299 | * If debugfs is not enabled in the kernel, the value -%ENODEV will be | ||
300 | * returned. It is not wise to check for this value, but rather, check for | ||
301 | * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling | ||
302 | * code. | ||
303 | */ | ||
304 | struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent, | ||
305 | const char *target) | ||
306 | { | ||
307 | struct dentry *result; | ||
308 | char *link; | ||
309 | |||
310 | link = kstrdup(target, GFP_KERNEL); | ||
311 | if (!link) | ||
312 | return NULL; | ||
313 | |||
314 | result = debugfs_create_file(name, S_IFLNK | S_IRWXUGO, parent, link, | ||
315 | NULL); | ||
316 | if (!result) | ||
317 | kfree(link); | ||
318 | return result; | ||
319 | } | ||
320 | EXPORT_SYMBOL_GPL(debugfs_create_symlink); | ||
321 | |||
322 | /** | ||
262 | * debugfs_remove - removes a file or directory from the debugfs filesystem | 323 | * debugfs_remove - removes a file or directory from the debugfs filesystem |
263 | * @dentry: a pointer to a the dentry of the file or directory to be | 324 | * @dentry: a pointer to a the dentry of the file or directory to be |
264 | * removed. | 325 | * removed. |
@@ -287,15 +348,22 @@ void debugfs_remove(struct dentry *dentry) | |||
287 | if (debugfs_positive(dentry)) { | 348 | if (debugfs_positive(dentry)) { |
288 | if (dentry->d_inode) { | 349 | if (dentry->d_inode) { |
289 | dget(dentry); | 350 | dget(dentry); |
290 | if (S_ISDIR(dentry->d_inode->i_mode)) { | 351 | switch (dentry->d_inode->i_mode & S_IFMT) { |
352 | case S_IFDIR: | ||
291 | ret = simple_rmdir(parent->d_inode, dentry); | 353 | ret = simple_rmdir(parent->d_inode, dentry); |
292 | if (ret) | 354 | if (ret) |
293 | printk(KERN_ERR | 355 | printk(KERN_ERR |
294 | "DebugFS rmdir on %s failed : " | 356 | "DebugFS rmdir on %s failed : " |
295 | "directory not empty.\n", | 357 | "directory not empty.\n", |
296 | dentry->d_name.name); | 358 | dentry->d_name.name); |
297 | } else | 359 | break; |
360 | case S_IFLNK: | ||
361 | kfree(dentry->d_inode->i_private); | ||
362 | /* fall through */ | ||
363 | default: | ||
298 | simple_unlink(parent->d_inode, dentry); | 364 | simple_unlink(parent->d_inode, dentry); |
365 | break; | ||
366 | } | ||
299 | if (!ret) | 367 | if (!ret) |
300 | d_delete(dentry); | 368 | d_delete(dentry); |
301 | dput(dentry); | 369 | dput(dentry); |