aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorPeter Oberparleiter <peter.oberparleiter@de.ibm.com>2007-02-13 06:13:54 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2007-02-16 18:19:17 -0500
commit66f5496393dcc9f9d05c46f00ed93d5040d6035b (patch)
treed5952a691e346b2715252d8b8cd2100d6c804a39 /fs
parentb92be9f1ecd3c8b16e9bb22d55bb97b3d89f091a (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')
-rw-r--r--fs/debugfs/file.c12
-rw-r--r--fs/debugfs/inode.c76
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
21static ssize_t default_read_file(struct file *file, char __user *buf, 22static 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
48static 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
54const struct inode_operations debugfs_link_operations = {
55 .readlink = generic_readlink,
56 .follow_link = debugfs_follow_link,
57};
58
47static void debugfs_u8_set(void *data, u64 val) 59static 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 */
32extern struct file_operations debugfs_file_operations; 33extern struct file_operations debugfs_file_operations;
34extern struct inode_operations debugfs_link_operations;
33 35
34static struct vfsmount *debugfs_mount; 36static struct vfsmount *debugfs_mount;
35static int debugfs_mount_count; 37static 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
104static 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
99static int debugfs_create(struct inode *dir, struct dentry *dentry, int mode) 110static 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)
259EXPORT_SYMBOL_GPL(debugfs_create_dir); 277EXPORT_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 */
304struct 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}
320EXPORT_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);