diff options
| author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
| commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
| tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /fs/debugfs | |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'fs/debugfs')
| -rw-r--r-- | fs/debugfs/Makefile | 4 | ||||
| -rw-r--r-- | fs/debugfs/file.c | 262 | ||||
| -rw-r--r-- | fs/debugfs/inode.c | 328 |
3 files changed, 594 insertions, 0 deletions
diff --git a/fs/debugfs/Makefile b/fs/debugfs/Makefile new file mode 100644 index 000000000000..840c45696668 --- /dev/null +++ b/fs/debugfs/Makefile | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | debugfs-objs := inode.o file.o | ||
| 2 | |||
| 3 | obj-$(CONFIG_DEBUG_FS) += debugfs.o | ||
| 4 | |||
diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c new file mode 100644 index 000000000000..548556ff2506 --- /dev/null +++ b/fs/debugfs/file.c | |||
| @@ -0,0 +1,262 @@ | |||
| 1 | /* | ||
| 2 | * file.c - part of debugfs, a tiny little debug file system | ||
| 3 | * | ||
| 4 | * Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com> | ||
| 5 | * Copyright (C) 2004 IBM Inc. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public License version | ||
| 9 | * 2 as published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * debugfs is for people to use instead of /proc or /sys. | ||
| 12 | * See Documentation/DocBook/kernel-api for more details. | ||
| 13 | * | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <linux/config.h> | ||
| 17 | #include <linux/module.h> | ||
| 18 | #include <linux/fs.h> | ||
| 19 | #include <linux/pagemap.h> | ||
| 20 | #include <linux/debugfs.h> | ||
| 21 | |||
| 22 | static ssize_t default_read_file(struct file *file, char __user *buf, | ||
| 23 | size_t count, loff_t *ppos) | ||
| 24 | { | ||
| 25 | return 0; | ||
| 26 | } | ||
| 27 | |||
| 28 | static ssize_t default_write_file(struct file *file, const char __user *buf, | ||
| 29 | size_t count, loff_t *ppos) | ||
| 30 | { | ||
| 31 | return count; | ||
| 32 | } | ||
| 33 | |||
| 34 | static int default_open(struct inode *inode, struct file *file) | ||
| 35 | { | ||
| 36 | if (inode->u.generic_ip) | ||
| 37 | file->private_data = inode->u.generic_ip; | ||
| 38 | |||
| 39 | return 0; | ||
| 40 | } | ||
| 41 | |||
| 42 | struct file_operations debugfs_file_operations = { | ||
| 43 | .read = default_read_file, | ||
| 44 | .write = default_write_file, | ||
| 45 | .open = default_open, | ||
| 46 | }; | ||
| 47 | |||
| 48 | #define simple_type(type, format, temptype, strtolfn) \ | ||
| 49 | static ssize_t read_file_##type(struct file *file, char __user *user_buf, \ | ||
| 50 | size_t count, loff_t *ppos) \ | ||
| 51 | { \ | ||
| 52 | char buf[32]; \ | ||
| 53 | type *val = file->private_data; \ | ||
| 54 | \ | ||
| 55 | snprintf(buf, sizeof(buf), format "\n", *val); \ | ||
| 56 | return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));\ | ||
| 57 | } \ | ||
| 58 | static ssize_t write_file_##type(struct file *file, const char __user *user_buf,\ | ||
| 59 | size_t count, loff_t *ppos) \ | ||
| 60 | { \ | ||
| 61 | char *endp; \ | ||
| 62 | char buf[32]; \ | ||
| 63 | int buf_size; \ | ||
| 64 | type *val = file->private_data; \ | ||
| 65 | temptype tmp; \ | ||
| 66 | \ | ||
| 67 | memset(buf, 0x00, sizeof(buf)); \ | ||
| 68 | buf_size = min(count, (sizeof(buf)-1)); \ | ||
| 69 | if (copy_from_user(buf, user_buf, buf_size)) \ | ||
| 70 | return -EFAULT; \ | ||
| 71 | \ | ||
| 72 | tmp = strtolfn(buf, &endp, 0); \ | ||
| 73 | if ((endp == buf) || ((type)tmp != tmp)) \ | ||
| 74 | return -EINVAL; \ | ||
| 75 | *val = tmp; \ | ||
| 76 | return count; \ | ||
| 77 | } \ | ||
| 78 | static struct file_operations fops_##type = { \ | ||
| 79 | .read = read_file_##type, \ | ||
| 80 | .write = write_file_##type, \ | ||
| 81 | .open = default_open, \ | ||
| 82 | }; | ||
| 83 | simple_type(u8, "%c", unsigned long, simple_strtoul); | ||
| 84 | simple_type(u16, "%hi", unsigned long, simple_strtoul); | ||
| 85 | simple_type(u32, "%i", unsigned long, simple_strtoul); | ||
| 86 | |||
| 87 | /** | ||
| 88 | * debugfs_create_u8 - create a file in the debugfs filesystem that is used to read and write a unsigned 8 bit value. | ||
| 89 | * | ||
| 90 | * @name: a pointer to a string containing the name of the file to create. | ||
| 91 | * @mode: the permission that the file should have | ||
| 92 | * @parent: a pointer to the parent dentry for this file. This should be a | ||
| 93 | * directory dentry if set. If this paramater is NULL, then the | ||
| 94 | * file will be created in the root of the debugfs filesystem. | ||
| 95 | * @value: a pointer to the variable that the file should read to and write | ||
| 96 | * from. | ||
| 97 | * | ||
| 98 | * This function creates a file in debugfs with the given name that | ||
| 99 | * contains the value of the variable @value. If the @mode variable is so | ||
| 100 | * set, it can be read from, and written to. | ||
| 101 | * | ||
| 102 | * This function will return a pointer to a dentry if it succeeds. This | ||
| 103 | * pointer must be passed to the debugfs_remove() function when the file is | ||
| 104 | * to be removed (no automatic cleanup happens if your module is unloaded, | ||
| 105 | * you are responsible here.) If an error occurs, NULL will be returned. | ||
| 106 | * | ||
| 107 | * If debugfs is not enabled in the kernel, the value -ENODEV will be | ||
| 108 | * returned. It is not wise to check for this value, but rather, check for | ||
| 109 | * NULL or !NULL instead as to eliminate the need for #ifdef in the calling | ||
| 110 | * code. | ||
| 111 | */ | ||
| 112 | struct dentry *debugfs_create_u8(const char *name, mode_t mode, | ||
| 113 | struct dentry *parent, u8 *value) | ||
| 114 | { | ||
| 115 | return debugfs_create_file(name, mode, parent, value, &fops_u8); | ||
| 116 | } | ||
| 117 | EXPORT_SYMBOL_GPL(debugfs_create_u8); | ||
| 118 | |||
| 119 | /** | ||
| 120 | * debugfs_create_u16 - create a file in the debugfs filesystem that is used to read and write a unsigned 8 bit value. | ||
| 121 | * | ||
| 122 | * @name: a pointer to a string containing the name of the file to create. | ||
| 123 | * @mode: the permission that the file should have | ||
| 124 | * @parent: a pointer to the parent dentry for this file. This should be a | ||
| 125 | * directory dentry if set. If this paramater is NULL, then the | ||
| 126 | * file will be created in the root of the debugfs filesystem. | ||
| 127 | * @value: a pointer to the variable that the file should read to and write | ||
| 128 | * from. | ||
| 129 | * | ||
| 130 | * This function creates a file in debugfs with the given name that | ||
| 131 | * contains the value of the variable @value. If the @mode variable is so | ||
| 132 | * set, it can be read from, and written to. | ||
| 133 | * | ||
| 134 | * This function will return a pointer to a dentry if it succeeds. This | ||
| 135 | * pointer must be passed to the debugfs_remove() function when the file is | ||
| 136 | * to be removed (no automatic cleanup happens if your module is unloaded, | ||
| 137 | * you are responsible here.) If an error occurs, NULL will be returned. | ||
| 138 | * | ||
| 139 | * If debugfs is not enabled in the kernel, the value -ENODEV will be | ||
| 140 | * returned. It is not wise to check for this value, but rather, check for | ||
| 141 | * NULL or !NULL instead as to eliminate the need for #ifdef in the calling | ||
| 142 | * code. | ||
| 143 | */ | ||
| 144 | struct dentry *debugfs_create_u16(const char *name, mode_t mode, | ||
| 145 | struct dentry *parent, u16 *value) | ||
| 146 | { | ||
| 147 | return debugfs_create_file(name, mode, parent, value, &fops_u16); | ||
| 148 | } | ||
| 149 | EXPORT_SYMBOL_GPL(debugfs_create_u16); | ||
| 150 | |||
| 151 | /** | ||
| 152 | * debugfs_create_u32 - create a file in the debugfs filesystem that is used to read and write a unsigned 8 bit value. | ||
| 153 | * | ||
| 154 | * @name: a pointer to a string containing the name of the file to create. | ||
| 155 | * @mode: the permission that the file should have | ||
| 156 | * @parent: a pointer to the parent dentry for this file. This should be a | ||
| 157 | * directory dentry if set. If this paramater is NULL, then the | ||
| 158 | * file will be created in the root of the debugfs filesystem. | ||
| 159 | * @value: a pointer to the variable that the file should read to and write | ||
| 160 | * from. | ||
| 161 | * | ||
| 162 | * This function creates a file in debugfs with the given name that | ||
| 163 | * contains the value of the variable @value. If the @mode variable is so | ||
| 164 | * set, it can be read from, and written to. | ||
| 165 | * | ||
| 166 | * This function will return a pointer to a dentry if it succeeds. This | ||
| 167 | * pointer must be passed to the debugfs_remove() function when the file is | ||
| 168 | * to be removed (no automatic cleanup happens if your module is unloaded, | ||
| 169 | * you are responsible here.) If an error occurs, NULL will be returned. | ||
| 170 | * | ||
| 171 | * If debugfs is not enabled in the kernel, the value -ENODEV will be | ||
| 172 | * returned. It is not wise to check for this value, but rather, check for | ||
| 173 | * NULL or !NULL instead as to eliminate the need for #ifdef in the calling | ||
| 174 | * code. | ||
| 175 | */ | ||
| 176 | struct dentry *debugfs_create_u32(const char *name, mode_t mode, | ||
| 177 | struct dentry *parent, u32 *value) | ||
| 178 | { | ||
| 179 | return debugfs_create_file(name, mode, parent, value, &fops_u32); | ||
| 180 | } | ||
| 181 | EXPORT_SYMBOL_GPL(debugfs_create_u32); | ||
| 182 | |||
| 183 | static ssize_t read_file_bool(struct file *file, char __user *user_buf, | ||
| 184 | size_t count, loff_t *ppos) | ||
| 185 | { | ||
| 186 | char buf[3]; | ||
| 187 | u32 *val = file->private_data; | ||
| 188 | |||
| 189 | if (*val) | ||
| 190 | buf[0] = 'Y'; | ||
| 191 | else | ||
| 192 | buf[0] = 'N'; | ||
| 193 | buf[1] = '\n'; | ||
| 194 | buf[2] = 0x00; | ||
| 195 | return simple_read_from_buffer(user_buf, count, ppos, buf, 2); | ||
| 196 | } | ||
| 197 | |||
| 198 | static ssize_t write_file_bool(struct file *file, const char __user *user_buf, | ||
| 199 | size_t count, loff_t *ppos) | ||
| 200 | { | ||
| 201 | char buf[32]; | ||
| 202 | int buf_size; | ||
| 203 | u32 *val = file->private_data; | ||
| 204 | |||
| 205 | buf_size = min(count, (sizeof(buf)-1)); | ||
| 206 | if (copy_from_user(buf, user_buf, buf_size)) | ||
| 207 | return -EFAULT; | ||
| 208 | |||
| 209 | switch (buf[0]) { | ||
| 210 | case 'y': | ||
| 211 | case 'Y': | ||
| 212 | case '1': | ||
| 213 | *val = 1; | ||
| 214 | break; | ||
| 215 | case 'n': | ||
| 216 | case 'N': | ||
| 217 | case '0': | ||
| 218 | *val = 0; | ||
| 219 | break; | ||
| 220 | } | ||
| 221 | |||
| 222 | return count; | ||
| 223 | } | ||
| 224 | |||
| 225 | static struct file_operations fops_bool = { | ||
| 226 | .read = read_file_bool, | ||
| 227 | .write = write_file_bool, | ||
| 228 | .open = default_open, | ||
| 229 | }; | ||
| 230 | |||
| 231 | /** | ||
| 232 | * debugfs_create_bool - create a file in the debugfs filesystem that is used to read and write a boolean value. | ||
| 233 | * | ||
| 234 | * @name: a pointer to a string containing the name of the file to create. | ||
| 235 | * @mode: the permission that the file should have | ||
| 236 | * @parent: a pointer to the parent dentry for this file. This should be a | ||
| 237 | * directory dentry if set. If this paramater is NULL, then the | ||
| 238 | * file will be created in the root of the debugfs filesystem. | ||
| 239 | * @value: a pointer to the variable that the file should read to and write | ||
| 240 | * from. | ||
| 241 | * | ||
| 242 | * This function creates a file in debugfs with the given name that | ||
| 243 | * contains the value of the variable @value. If the @mode variable is so | ||
| 244 | * set, it can be read from, and written to. | ||
| 245 | * | ||
| 246 | * This function will return a pointer to a dentry if it succeeds. This | ||
| 247 | * pointer must be passed to the debugfs_remove() function when the file is | ||
| 248 | * to be removed (no automatic cleanup happens if your module is unloaded, | ||
| 249 | * you are responsible here.) If an error occurs, NULL will be returned. | ||
| 250 | * | ||
| 251 | * If debugfs is not enabled in the kernel, the value -ENODEV will be | ||
| 252 | * returned. It is not wise to check for this value, but rather, check for | ||
| 253 | * NULL or !NULL instead as to eliminate the need for #ifdef in the calling | ||
| 254 | * code. | ||
| 255 | */ | ||
| 256 | struct dentry *debugfs_create_bool(const char *name, mode_t mode, | ||
| 257 | struct dentry *parent, u32 *value) | ||
| 258 | { | ||
| 259 | return debugfs_create_file(name, mode, parent, value, &fops_bool); | ||
| 260 | } | ||
| 261 | EXPORT_SYMBOL_GPL(debugfs_create_bool); | ||
| 262 | |||
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c new file mode 100644 index 000000000000..b529786699e7 --- /dev/null +++ b/fs/debugfs/inode.c | |||
| @@ -0,0 +1,328 @@ | |||
| 1 | /* | ||
| 2 | * file.c - part of debugfs, a tiny little debug file system | ||
| 3 | * | ||
| 4 | * Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com> | ||
| 5 | * Copyright (C) 2004 IBM Inc. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public License version | ||
| 9 | * 2 as published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * debugfs is for people to use instead of /proc or /sys. | ||
| 12 | * See Documentation/DocBook/kernel-api for more details. | ||
| 13 | * | ||
| 14 | */ | ||
| 15 | |||
| 16 | /* uncomment to get debug messages from the debug filesystem, ah the irony. */ | ||
| 17 | /* #define DEBUG */ | ||
| 18 | |||
| 19 | #include <linux/config.h> | ||
| 20 | #include <linux/module.h> | ||
| 21 | #include <linux/fs.h> | ||
| 22 | #include <linux/mount.h> | ||
| 23 | #include <linux/pagemap.h> | ||
| 24 | #include <linux/init.h> | ||
| 25 | #include <linux/namei.h> | ||
| 26 | #include <linux/debugfs.h> | ||
| 27 | |||
| 28 | #define DEBUGFS_MAGIC 0x64626720 | ||
| 29 | |||
| 30 | /* declared over in file.c */ | ||
| 31 | extern struct file_operations debugfs_file_operations; | ||
| 32 | |||
| 33 | static struct vfsmount *debugfs_mount; | ||
| 34 | static int debugfs_mount_count; | ||
| 35 | |||
| 36 | static struct inode *debugfs_get_inode(struct super_block *sb, int mode, dev_t dev) | ||
| 37 | { | ||
| 38 | struct inode *inode = new_inode(sb); | ||
| 39 | |||
| 40 | if (inode) { | ||
| 41 | inode->i_mode = mode; | ||
| 42 | inode->i_uid = 0; | ||
| 43 | inode->i_gid = 0; | ||
| 44 | inode->i_blksize = PAGE_CACHE_SIZE; | ||
| 45 | inode->i_blocks = 0; | ||
| 46 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | ||
| 47 | switch (mode & S_IFMT) { | ||
| 48 | default: | ||
| 49 | init_special_inode(inode, mode, dev); | ||
| 50 | break; | ||
| 51 | case S_IFREG: | ||
| 52 | inode->i_fop = &debugfs_file_operations; | ||
| 53 | break; | ||
| 54 | case S_IFDIR: | ||
| 55 | inode->i_op = &simple_dir_inode_operations; | ||
| 56 | inode->i_fop = &simple_dir_operations; | ||
| 57 | |||
| 58 | /* directory inodes start off with i_nlink == 2 (for "." entry) */ | ||
| 59 | inode->i_nlink++; | ||
| 60 | break; | ||
| 61 | } | ||
| 62 | } | ||
| 63 | return inode; | ||
| 64 | } | ||
| 65 | |||
| 66 | /* SMP-safe */ | ||
| 67 | static int debugfs_mknod(struct inode *dir, struct dentry *dentry, | ||
| 68 | int mode, dev_t dev) | ||
| 69 | { | ||
| 70 | struct inode *inode = debugfs_get_inode(dir->i_sb, mode, dev); | ||
| 71 | int error = -EPERM; | ||
| 72 | |||
| 73 | if (dentry->d_inode) | ||
| 74 | return -EEXIST; | ||
| 75 | |||
| 76 | if (inode) { | ||
| 77 | d_instantiate(dentry, inode); | ||
| 78 | dget(dentry); | ||
| 79 | error = 0; | ||
| 80 | } | ||
| 81 | return error; | ||
| 82 | } | ||
| 83 | |||
| 84 | static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | ||
| 85 | { | ||
| 86 | int res; | ||
| 87 | |||
| 88 | mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR; | ||
| 89 | res = debugfs_mknod(dir, dentry, mode, 0); | ||
| 90 | if (!res) | ||
| 91 | dir->i_nlink++; | ||
| 92 | return res; | ||
| 93 | } | ||
| 94 | |||
| 95 | static int debugfs_create(struct inode *dir, struct dentry *dentry, int mode) | ||
| 96 | { | ||
| 97 | mode = (mode & S_IALLUGO) | S_IFREG; | ||
| 98 | return debugfs_mknod(dir, dentry, mode, 0); | ||
| 99 | } | ||
| 100 | |||
| 101 | static inline int debugfs_positive(struct dentry *dentry) | ||
| 102 | { | ||
| 103 | return dentry->d_inode && !d_unhashed(dentry); | ||
| 104 | } | ||
| 105 | |||
| 106 | static int debug_fill_super(struct super_block *sb, void *data, int silent) | ||
| 107 | { | ||
| 108 | static struct tree_descr debug_files[] = {{""}}; | ||
| 109 | |||
| 110 | return simple_fill_super(sb, DEBUGFS_MAGIC, debug_files); | ||
| 111 | } | ||
| 112 | |||
| 113 | static struct dentry * get_dentry(struct dentry *parent, const char *name) | ||
| 114 | { | ||
| 115 | struct qstr qstr; | ||
| 116 | |||
| 117 | qstr.name = name; | ||
| 118 | qstr.len = strlen(name); | ||
| 119 | qstr.hash = full_name_hash(name,qstr.len); | ||
| 120 | return lookup_hash(&qstr,parent); | ||
| 121 | } | ||
| 122 | |||
| 123 | static struct super_block *debug_get_sb(struct file_system_type *fs_type, | ||
| 124 | int flags, const char *dev_name, | ||
| 125 | void *data) | ||
| 126 | { | ||
| 127 | return get_sb_single(fs_type, flags, data, debug_fill_super); | ||
| 128 | } | ||
| 129 | |||
| 130 | static struct file_system_type debug_fs_type = { | ||
| 131 | .owner = THIS_MODULE, | ||
| 132 | .name = "debugfs", | ||
| 133 | .get_sb = debug_get_sb, | ||
| 134 | .kill_sb = kill_litter_super, | ||
| 135 | }; | ||
| 136 | |||
| 137 | static int debugfs_create_by_name(const char *name, mode_t mode, | ||
| 138 | struct dentry *parent, | ||
| 139 | struct dentry **dentry) | ||
| 140 | { | ||
| 141 | int error = 0; | ||
| 142 | |||
| 143 | /* If the parent is not specified, we create it in the root. | ||
| 144 | * We need the root dentry to do this, which is in the super | ||
| 145 | * block. A pointer to that is in the struct vfsmount that we | ||
| 146 | * have around. | ||
| 147 | */ | ||
| 148 | if (!parent ) { | ||
| 149 | if (debugfs_mount && debugfs_mount->mnt_sb) { | ||
| 150 | parent = debugfs_mount->mnt_sb->s_root; | ||
| 151 | } | ||
| 152 | } | ||
| 153 | if (!parent) { | ||
| 154 | pr_debug("debugfs: Ah! can not find a parent!\n"); | ||
| 155 | return -EFAULT; | ||
| 156 | } | ||
| 157 | |||
| 158 | *dentry = NULL; | ||
| 159 | down(&parent->d_inode->i_sem); | ||
| 160 | *dentry = get_dentry (parent, name); | ||
| 161 | if (!IS_ERR(dentry)) { | ||
| 162 | if ((mode & S_IFMT) == S_IFDIR) | ||
| 163 | error = debugfs_mkdir(parent->d_inode, *dentry, mode); | ||
| 164 | else | ||
| 165 | error = debugfs_create(parent->d_inode, *dentry, mode); | ||
| 166 | } else | ||
| 167 | error = PTR_ERR(dentry); | ||
| 168 | up(&parent->d_inode->i_sem); | ||
| 169 | |||
| 170 | return error; | ||
| 171 | } | ||
| 172 | |||
| 173 | /** | ||
| 174 | * debugfs_create_file - create a file in the debugfs filesystem | ||
| 175 | * | ||
| 176 | * @name: a pointer to a string containing the name of the file to create. | ||
| 177 | * @mode: the permission that the file should have | ||
| 178 | * @parent: a pointer to the parent dentry for this file. This should be a | ||
| 179 | * directory dentry if set. If this paramater is NULL, then the | ||
| 180 | * file will be created in the root of the debugfs filesystem. | ||
| 181 | * @data: a pointer to something that the caller will want to get to later | ||
| 182 | * on. The inode.u.generic_ip pointer will point to this value on | ||
| 183 | * the open() call. | ||
| 184 | * @fops: a pointer to a struct file_operations that should be used for | ||
| 185 | * this file. | ||
| 186 | * | ||
| 187 | * This is the basic "create a file" function for debugfs. It allows for a | ||
| 188 | * wide range of flexibility in createing a file, or a directory (if you | ||
| 189 | * want to create a directory, the debugfs_create_dir() function is | ||
| 190 | * recommended to be used instead.) | ||
| 191 | * | ||
| 192 | * This function will return a pointer to a dentry if it succeeds. This | ||
| 193 | * pointer must be passed to the debugfs_remove() function when the file is | ||
| 194 | * to be removed (no automatic cleanup happens if your module is unloaded, | ||
| 195 | * you are responsible here.) If an error occurs, NULL will be returned. | ||
| 196 | * | ||
| 197 | * If debugfs is not enabled in the kernel, the value -ENODEV will be | ||
| 198 | * returned. It is not wise to check for this value, but rather, check for | ||
| 199 | * NULL or !NULL instead as to eliminate the need for #ifdef in the calling | ||
| 200 | * code. | ||
| 201 | */ | ||
| 202 | struct dentry *debugfs_create_file(const char *name, mode_t mode, | ||
| 203 | struct dentry *parent, void *data, | ||
| 204 | struct file_operations *fops) | ||
| 205 | { | ||
| 206 | struct dentry *dentry = NULL; | ||
| 207 | int error; | ||
| 208 | |||
| 209 | pr_debug("debugfs: creating file '%s'\n",name); | ||
| 210 | |||
| 211 | error = simple_pin_fs("debugfs", &debugfs_mount, &debugfs_mount_count); | ||
| 212 | if (error) | ||
| 213 | goto exit; | ||
| 214 | |||
| 215 | error = debugfs_create_by_name(name, mode, parent, &dentry); | ||
| 216 | if (error) { | ||
| 217 | dentry = NULL; | ||
| 218 | goto exit; | ||
| 219 | } | ||
| 220 | |||
| 221 | if (dentry->d_inode) { | ||
| 222 | if (data) | ||
| 223 | dentry->d_inode->u.generic_ip = data; | ||
| 224 | if (fops) | ||
| 225 | dentry->d_inode->i_fop = fops; | ||
| 226 | } | ||
| 227 | exit: | ||
| 228 | return dentry; | ||
| 229 | } | ||
| 230 | EXPORT_SYMBOL_GPL(debugfs_create_file); | ||
| 231 | |||
| 232 | /** | ||
| 233 | * debugfs_create_dir - create a directory in the debugfs filesystem | ||
| 234 | * | ||
| 235 | * @name: a pointer to a string containing the name of the directory to | ||
| 236 | * create. | ||
| 237 | * @parent: a pointer to the parent dentry for this file. This should be a | ||
| 238 | * directory dentry if set. If this paramater is NULL, then the | ||
| 239 | * directory will be created in the root of the debugfs filesystem. | ||
| 240 | * | ||
| 241 | * This function creates a directory in debugfs with the given name. | ||
| 242 | * | ||
| 243 | * This function will return a pointer to a dentry if it succeeds. This | ||
| 244 | * pointer must be passed to the debugfs_remove() function when the file is | ||
| 245 | * to be removed (no automatic cleanup happens if your module is unloaded, | ||
| 246 | * you are responsible here.) If an error occurs, NULL will be returned. | ||
| 247 | * | ||
| 248 | * If debugfs is not enabled in the kernel, the value -ENODEV will be | ||
| 249 | * returned. It is not wise to check for this value, but rather, check for | ||
| 250 | * NULL or !NULL instead as to eliminate the need for #ifdef in the calling | ||
| 251 | * code. | ||
| 252 | */ | ||
| 253 | struct dentry *debugfs_create_dir(const char *name, struct dentry *parent) | ||
| 254 | { | ||
| 255 | return debugfs_create_file(name, | ||
| 256 | S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO, | ||
| 257 | parent, NULL, NULL); | ||
| 258 | } | ||
| 259 | EXPORT_SYMBOL_GPL(debugfs_create_dir); | ||
| 260 | |||
| 261 | /** | ||
| 262 | * debugfs_remove - removes a file or directory from the debugfs filesystem | ||
| 263 | * | ||
| 264 | * @dentry: a pointer to a the dentry of the file or directory to be | ||
| 265 | * removed. | ||
| 266 | * | ||
| 267 | * This function removes a file or directory in debugfs that was previously | ||
| 268 | * created with a call to another debugfs function (like | ||
| 269 | * debufs_create_file() or variants thereof.) | ||
| 270 | * | ||
| 271 | * This function is required to be called in order for the file to be | ||
| 272 | * removed, no automatic cleanup of files will happen when a module is | ||
| 273 | * removed, you are responsible here. | ||
| 274 | */ | ||
| 275 | void debugfs_remove(struct dentry *dentry) | ||
| 276 | { | ||
| 277 | struct dentry *parent; | ||
| 278 | |||
| 279 | if (!dentry) | ||
| 280 | return; | ||
| 281 | |||
| 282 | parent = dentry->d_parent; | ||
| 283 | if (!parent || !parent->d_inode) | ||
| 284 | return; | ||
| 285 | |||
| 286 | down(&parent->d_inode->i_sem); | ||
| 287 | if (debugfs_positive(dentry)) { | ||
| 288 | if (dentry->d_inode) { | ||
| 289 | if (S_ISDIR(dentry->d_inode->i_mode)) | ||
| 290 | simple_rmdir(parent->d_inode, dentry); | ||
| 291 | else | ||
| 292 | simple_unlink(parent->d_inode, dentry); | ||
| 293 | dput(dentry); | ||
| 294 | } | ||
| 295 | } | ||
| 296 | up(&parent->d_inode->i_sem); | ||
| 297 | simple_release_fs(&debugfs_mount, &debugfs_mount_count); | ||
| 298 | } | ||
| 299 | EXPORT_SYMBOL_GPL(debugfs_remove); | ||
| 300 | |||
| 301 | static decl_subsys(debug, NULL, NULL); | ||
| 302 | |||
| 303 | static int __init debugfs_init(void) | ||
| 304 | { | ||
| 305 | int retval; | ||
| 306 | |||
| 307 | kset_set_kset_s(&debug_subsys, kernel_subsys); | ||
| 308 | retval = subsystem_register(&debug_subsys); | ||
| 309 | if (retval) | ||
| 310 | return retval; | ||
| 311 | |||
| 312 | retval = register_filesystem(&debug_fs_type); | ||
| 313 | if (retval) | ||
| 314 | subsystem_unregister(&debug_subsys); | ||
| 315 | return retval; | ||
| 316 | } | ||
| 317 | |||
| 318 | static void __exit debugfs_exit(void) | ||
| 319 | { | ||
| 320 | simple_release_fs(&debugfs_mount, &debugfs_mount_count); | ||
| 321 | unregister_filesystem(&debug_fs_type); | ||
| 322 | subsystem_unregister(&debug_subsys); | ||
| 323 | } | ||
| 324 | |||
| 325 | core_initcall(debugfs_init); | ||
| 326 | module_exit(debugfs_exit); | ||
| 327 | MODULE_LICENSE("GPL"); | ||
| 328 | |||
