13bce94fdSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * file.c - part of debugfs, a tiny little debug file system 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Copyright (C) 2004 Greg Kroah-Hartman <[email protected]> 61da177e4SLinus Torvalds * Copyright (C) 2004 IBM Inc. 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * debugfs is for people to use instead of /proc or /sys. 9e1b4fc7aSMauro Carvalho Chehab * See Documentation/filesystems/ for more details. 101da177e4SLinus Torvalds */ 111da177e4SLinus Torvalds 121da177e4SLinus Torvalds #include <linux/module.h> 131da177e4SLinus Torvalds #include <linux/fs.h> 141a087c6aSAlessandro Rubini #include <linux/seq_file.h> 151da177e4SLinus Torvalds #include <linux/pagemap.h> 161da177e4SLinus Torvalds #include <linux/debugfs.h> 1703e099fbSAlessandro Rubini #include <linux/io.h> 189fe2a701SSrivatsa Vaddagiri #include <linux/slab.h> 193a76e5e0SSeth Jennings #include <linux/atomic.h> 2098210b7fSArend van Spriel #include <linux/device.h> 2130332eeeSGeert Uytterhoeven #include <linux/pm_runtime.h> 22cfe39442SAl Viro #include <linux/poll.h> 235496197fSDavid Howells #include <linux/security.h> 249fd4dcecSNicolai Stange 259fd4dcecSNicolai Stange #include "internal.h" 261da177e4SLinus Torvalds 2749d200deSNicolai Stange struct poll_table_struct; 2849d200deSNicolai Stange 291da177e4SLinus Torvalds static ssize_t default_read_file(struct file *file, char __user *buf, 301da177e4SLinus Torvalds size_t count, loff_t *ppos) 311da177e4SLinus Torvalds { 321da177e4SLinus Torvalds return 0; 331da177e4SLinus Torvalds } 341da177e4SLinus Torvalds 351da177e4SLinus Torvalds static ssize_t default_write_file(struct file *file, const char __user *buf, 361da177e4SLinus Torvalds size_t count, loff_t *ppos) 371da177e4SLinus Torvalds { 381da177e4SLinus Torvalds return count; 391da177e4SLinus Torvalds } 401da177e4SLinus Torvalds 419fd4dcecSNicolai Stange const struct file_operations debugfs_noop_file_operations = { 421da177e4SLinus Torvalds .read = default_read_file, 431da177e4SLinus Torvalds .write = default_write_file, 44234e3405SStephen Boyd .open = simple_open, 456038f373SArnd Bergmann .llseek = noop_llseek, 461da177e4SLinus Torvalds }; 471da177e4SLinus Torvalds 489fd4dcecSNicolai Stange #define F_DENTRY(filp) ((filp)->f_path.dentry) 499fd4dcecSNicolai Stange 507c8d4698SNicolai Stange const struct file_operations *debugfs_real_fops(const struct file *filp) 517c8d4698SNicolai Stange { 527c8d4698SNicolai Stange struct debugfs_fsdata *fsd = F_DENTRY(filp)->d_fsdata; 53055ab8e3SNicolai Stange 547d39bc50SNicolai Stange if ((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT) { 557d39bc50SNicolai Stange /* 567d39bc50SNicolai Stange * Urgh, we've been called w/o a protecting 577d39bc50SNicolai Stange * debugfs_file_get(). 587d39bc50SNicolai Stange */ 597d39bc50SNicolai Stange WARN_ON(1); 607d39bc50SNicolai Stange return NULL; 617d39bc50SNicolai Stange } 627d39bc50SNicolai Stange 637c8d4698SNicolai Stange return fsd->real_fops; 647c8d4698SNicolai Stange } 657c8d4698SNicolai Stange EXPORT_SYMBOL_GPL(debugfs_real_fops); 667c8d4698SNicolai Stange 67f8f25893SJohannes Berg enum dbgfs_get_mode { 68f8f25893SJohannes Berg DBGFS_GET_ALREADY, 69f8f25893SJohannes Berg DBGFS_GET_REGULAR, 70f8f25893SJohannes Berg DBGFS_GET_SHORT, 71f8f25893SJohannes Berg }; 72f8f25893SJohannes Berg 73f8f25893SJohannes Berg static int __debugfs_file_get(struct dentry *dentry, enum dbgfs_get_mode mode) 74e9117a5aSNicolai Stange { 757d39bc50SNicolai Stange struct debugfs_fsdata *fsd; 767d39bc50SNicolai Stange void *d_fsd; 77e9117a5aSNicolai Stange 780ed04a18SJohannes Berg /* 790ed04a18SJohannes Berg * This could only happen if some debugfs user erroneously calls 800ed04a18SJohannes Berg * debugfs_file_get() on a dentry that isn't even a file, let 810ed04a18SJohannes Berg * them know about it. 820ed04a18SJohannes Berg */ 830ed04a18SJohannes Berg if (WARN_ON(!d_is_reg(dentry))) 840ed04a18SJohannes Berg return -EINVAL; 850ed04a18SJohannes Berg 867d39bc50SNicolai Stange d_fsd = READ_ONCE(dentry->d_fsdata); 877d39bc50SNicolai Stange if (!((unsigned long)d_fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT)) { 887d39bc50SNicolai Stange fsd = d_fsd; 897d39bc50SNicolai Stange } else { 90f8f25893SJohannes Berg if (WARN_ON(mode == DBGFS_GET_ALREADY)) 91f8f25893SJohannes Berg return -EINVAL; 92f8f25893SJohannes Berg 937d39bc50SNicolai Stange fsd = kmalloc(sizeof(*fsd), GFP_KERNEL); 947d39bc50SNicolai Stange if (!fsd) 957d39bc50SNicolai Stange return -ENOMEM; 967d39bc50SNicolai Stange 97f8f25893SJohannes Berg if (mode == DBGFS_GET_SHORT) { 98*41a0ecc0SAl Viro const struct debugfs_short_fops *ops; 99*41a0ecc0SAl Viro ops = (void *)((unsigned long)d_fsd & 100f8f25893SJohannes Berg ~DEBUGFS_FSDATA_IS_REAL_FOPS_BIT); 101*41a0ecc0SAl Viro fsd->short_fops = ops; 102*41a0ecc0SAl Viro if (ops->llseek) 103*41a0ecc0SAl Viro fsd->methods |= HAS_LSEEK; 104*41a0ecc0SAl Viro if (ops->read) 105*41a0ecc0SAl Viro fsd->methods |= HAS_READ; 106*41a0ecc0SAl Viro if (ops->write) 107*41a0ecc0SAl Viro fsd->methods |= HAS_WRITE; 1088dc6d81cSJohannes Berg } else { 109*41a0ecc0SAl Viro const struct file_operations *ops; 110*41a0ecc0SAl Viro ops = (void *)((unsigned long)d_fsd & 1117d39bc50SNicolai Stange ~DEBUGFS_FSDATA_IS_REAL_FOPS_BIT); 112*41a0ecc0SAl Viro fsd->real_fops = ops; 113*41a0ecc0SAl Viro if (ops->llseek) 114*41a0ecc0SAl Viro fsd->methods |= HAS_LSEEK; 115*41a0ecc0SAl Viro if (ops->read) 116*41a0ecc0SAl Viro fsd->methods |= HAS_READ; 117*41a0ecc0SAl Viro if (ops->write) 118*41a0ecc0SAl Viro fsd->methods |= HAS_WRITE; 119*41a0ecc0SAl Viro if (ops->unlocked_ioctl) 120*41a0ecc0SAl Viro fsd->methods |= HAS_IOCTL; 121*41a0ecc0SAl Viro if (ops->poll) 122*41a0ecc0SAl Viro fsd->methods |= HAS_POLL; 1238dc6d81cSJohannes Berg } 1247d39bc50SNicolai Stange refcount_set(&fsd->active_users, 1); 1257d39bc50SNicolai Stange init_completion(&fsd->active_users_drained); 126159f5bdaSJohannes Berg INIT_LIST_HEAD(&fsd->cancellations); 127159f5bdaSJohannes Berg mutex_init(&fsd->cancellations_mtx); 128159f5bdaSJohannes Berg 1297d39bc50SNicolai Stange if (cmpxchg(&dentry->d_fsdata, d_fsd, fsd) != d_fsd) { 130159f5bdaSJohannes Berg mutex_destroy(&fsd->cancellations_mtx); 1317d39bc50SNicolai Stange kfree(fsd); 1327d39bc50SNicolai Stange fsd = READ_ONCE(dentry->d_fsdata); 1337d39bc50SNicolai Stange } 1347d39bc50SNicolai Stange } 1357d39bc50SNicolai Stange 1367d39bc50SNicolai Stange /* 1377d39bc50SNicolai Stange * In case of a successful cmpxchg() above, this check is 1387d39bc50SNicolai Stange * strictly necessary and must follow it, see the comment in 1397d39bc50SNicolai Stange * __debugfs_remove_file(). 1407d39bc50SNicolai Stange * OTOH, if the cmpxchg() hasn't been executed or wasn't 1417d39bc50SNicolai Stange * successful, this serves the purpose of not starving 1427d39bc50SNicolai Stange * removers. 1437d39bc50SNicolai Stange */ 144e9117a5aSNicolai Stange if (d_unlinked(dentry)) 145e9117a5aSNicolai Stange return -EIO; 146e9117a5aSNicolai Stange 147e9117a5aSNicolai Stange if (!refcount_inc_not_zero(&fsd->active_users)) 148e9117a5aSNicolai Stange return -EIO; 149e9117a5aSNicolai Stange 150e9117a5aSNicolai Stange return 0; 151e9117a5aSNicolai Stange } 152f8f25893SJohannes Berg 153f8f25893SJohannes Berg /** 154f8f25893SJohannes Berg * debugfs_file_get - mark the beginning of file data access 155f8f25893SJohannes Berg * @dentry: the dentry object whose data is being accessed. 156f8f25893SJohannes Berg * 157f8f25893SJohannes Berg * Up to a matching call to debugfs_file_put(), any successive call 158f8f25893SJohannes Berg * into the file removing functions debugfs_remove() and 159f8f25893SJohannes Berg * debugfs_remove_recursive() will block. Since associated private 160f8f25893SJohannes Berg * file data may only get freed after a successful return of any of 161f8f25893SJohannes Berg * the removal functions, you may safely access it after a successful 162f8f25893SJohannes Berg * call to debugfs_file_get() without worrying about lifetime issues. 163f8f25893SJohannes Berg * 164f8f25893SJohannes Berg * If -%EIO is returned, the file has already been removed and thus, 165f8f25893SJohannes Berg * it is not safe to access any of its data. If, on the other hand, 166f8f25893SJohannes Berg * it is allowed to access the file data, zero is returned. 167f8f25893SJohannes Berg */ 168f8f25893SJohannes Berg int debugfs_file_get(struct dentry *dentry) 169f8f25893SJohannes Berg { 170f8f25893SJohannes Berg return __debugfs_file_get(dentry, DBGFS_GET_ALREADY); 171f8f25893SJohannes Berg } 172e9117a5aSNicolai Stange EXPORT_SYMBOL_GPL(debugfs_file_get); 173e9117a5aSNicolai Stange 174e9117a5aSNicolai Stange /** 175e9117a5aSNicolai Stange * debugfs_file_put - mark the end of file data access 176e9117a5aSNicolai Stange * @dentry: the dentry object formerly passed to 177e9117a5aSNicolai Stange * debugfs_file_get(). 178e9117a5aSNicolai Stange * 179e9117a5aSNicolai Stange * Allow any ongoing concurrent call into debugfs_remove() or 180e9117a5aSNicolai Stange * debugfs_remove_recursive() blocked by a former call to 181e9117a5aSNicolai Stange * debugfs_file_get() to proceed and return to its caller. 182e9117a5aSNicolai Stange */ 183e9117a5aSNicolai Stange void debugfs_file_put(struct dentry *dentry) 184e9117a5aSNicolai Stange { 1857d39bc50SNicolai Stange struct debugfs_fsdata *fsd = READ_ONCE(dentry->d_fsdata); 186e9117a5aSNicolai Stange 187e9117a5aSNicolai Stange if (refcount_dec_and_test(&fsd->active_users)) 188e9117a5aSNicolai Stange complete(&fsd->active_users_drained); 189e9117a5aSNicolai Stange } 190e9117a5aSNicolai Stange EXPORT_SYMBOL_GPL(debugfs_file_put); 191e9117a5aSNicolai Stange 1928c88a474SJohannes Berg /** 1938c88a474SJohannes Berg * debugfs_enter_cancellation - enter a debugfs cancellation 1948c88a474SJohannes Berg * @file: the file being accessed 1958c88a474SJohannes Berg * @cancellation: the cancellation object, the cancel callback 1968c88a474SJohannes Berg * inside of it must be initialized 1978c88a474SJohannes Berg * 1988c88a474SJohannes Berg * When a debugfs file is removed it needs to wait for all active 1998c88a474SJohannes Berg * operations to complete. However, the operation itself may need 2008c88a474SJohannes Berg * to wait for hardware or completion of some asynchronous process 2018c88a474SJohannes Berg * or similar. As such, it may need to be cancelled to avoid long 2028c88a474SJohannes Berg * waits or even deadlocks. 2038c88a474SJohannes Berg * 2048c88a474SJohannes Berg * This function can be used inside a debugfs handler that may 2058c88a474SJohannes Berg * need to be cancelled. As soon as this function is called, the 2068c88a474SJohannes Berg * cancellation's 'cancel' callback may be called, at which point 2078c88a474SJohannes Berg * the caller should proceed to call debugfs_leave_cancellation() 2088c88a474SJohannes Berg * and leave the debugfs handler function as soon as possible. 2098c88a474SJohannes Berg * Note that the 'cancel' callback is only ever called in the 2108c88a474SJohannes Berg * context of some kind of debugfs_remove(). 2118c88a474SJohannes Berg * 2128c88a474SJohannes Berg * This function must be paired with debugfs_leave_cancellation(). 2138c88a474SJohannes Berg */ 2148c88a474SJohannes Berg void debugfs_enter_cancellation(struct file *file, 2158c88a474SJohannes Berg struct debugfs_cancellation *cancellation) 2168c88a474SJohannes Berg { 2178c88a474SJohannes Berg struct debugfs_fsdata *fsd; 2188c88a474SJohannes Berg struct dentry *dentry = F_DENTRY(file); 2198c88a474SJohannes Berg 2208c88a474SJohannes Berg INIT_LIST_HEAD(&cancellation->list); 2218c88a474SJohannes Berg 2228c88a474SJohannes Berg if (WARN_ON(!d_is_reg(dentry))) 2238c88a474SJohannes Berg return; 2248c88a474SJohannes Berg 2258c88a474SJohannes Berg if (WARN_ON(!cancellation->cancel)) 2268c88a474SJohannes Berg return; 2278c88a474SJohannes Berg 2288c88a474SJohannes Berg fsd = READ_ONCE(dentry->d_fsdata); 2298c88a474SJohannes Berg if (WARN_ON(!fsd || 2308c88a474SJohannes Berg ((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT))) 2318c88a474SJohannes Berg return; 2328c88a474SJohannes Berg 2338c88a474SJohannes Berg mutex_lock(&fsd->cancellations_mtx); 2348c88a474SJohannes Berg list_add(&cancellation->list, &fsd->cancellations); 2358c88a474SJohannes Berg mutex_unlock(&fsd->cancellations_mtx); 2368c88a474SJohannes Berg 2378c88a474SJohannes Berg /* if we're already removing wake it up to cancel */ 2388c88a474SJohannes Berg if (d_unlinked(dentry)) 2398c88a474SJohannes Berg complete(&fsd->active_users_drained); 2408c88a474SJohannes Berg } 2418c88a474SJohannes Berg EXPORT_SYMBOL_GPL(debugfs_enter_cancellation); 2428c88a474SJohannes Berg 2438c88a474SJohannes Berg /** 2448c88a474SJohannes Berg * debugfs_leave_cancellation - leave cancellation section 2458c88a474SJohannes Berg * @file: the file being accessed 2468c88a474SJohannes Berg * @cancellation: the cancellation previously registered with 2478c88a474SJohannes Berg * debugfs_enter_cancellation() 2488c88a474SJohannes Berg * 2498c88a474SJohannes Berg * See the documentation of debugfs_enter_cancellation(). 2508c88a474SJohannes Berg */ 2518c88a474SJohannes Berg void debugfs_leave_cancellation(struct file *file, 2528c88a474SJohannes Berg struct debugfs_cancellation *cancellation) 2538c88a474SJohannes Berg { 2548c88a474SJohannes Berg struct debugfs_fsdata *fsd; 2558c88a474SJohannes Berg struct dentry *dentry = F_DENTRY(file); 2568c88a474SJohannes Berg 2578c88a474SJohannes Berg if (WARN_ON(!d_is_reg(dentry))) 2588c88a474SJohannes Berg return; 2598c88a474SJohannes Berg 2608c88a474SJohannes Berg fsd = READ_ONCE(dentry->d_fsdata); 2618c88a474SJohannes Berg if (WARN_ON(!fsd || 2628c88a474SJohannes Berg ((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT))) 2638c88a474SJohannes Berg return; 2648c88a474SJohannes Berg 2658c88a474SJohannes Berg mutex_lock(&fsd->cancellations_mtx); 2668c88a474SJohannes Berg if (!list_empty(&cancellation->list)) 2678c88a474SJohannes Berg list_del(&cancellation->list); 2688c88a474SJohannes Berg mutex_unlock(&fsd->cancellations_mtx); 2698c88a474SJohannes Berg } 2708c88a474SJohannes Berg EXPORT_SYMBOL_GPL(debugfs_leave_cancellation); 2718c88a474SJohannes Berg 2725496197fSDavid Howells /* 2735496197fSDavid Howells * Only permit access to world-readable files when the kernel is locked down. 2745496197fSDavid Howells * We also need to exclude any file that has ways to write or alter it as root 2755496197fSDavid Howells * can bypass the permissions check. 2765496197fSDavid Howells */ 277a37f4958SEric Snowberg static int debugfs_locked_down(struct inode *inode, 2785496197fSDavid Howells struct file *filp, 2795496197fSDavid Howells const struct file_operations *real_fops) 2805496197fSDavid Howells { 281358fcf5dSMichal Suchanek if ((inode->i_mode & 07777 & ~0444) == 0 && 2825496197fSDavid Howells !(filp->f_mode & FMODE_WRITE) && 2838dc6d81cSJohannes Berg (!real_fops || 2848dc6d81cSJohannes Berg (!real_fops->unlocked_ioctl && 2855496197fSDavid Howells !real_fops->compat_ioctl && 2868dc6d81cSJohannes Berg !real_fops->mmap))) 287a37f4958SEric Snowberg return 0; 2885496197fSDavid Howells 289a37f4958SEric Snowberg if (security_locked_down(LOCKDOWN_DEBUGFS)) 290a37f4958SEric Snowberg return -EPERM; 291a37f4958SEric Snowberg 292a37f4958SEric Snowberg return 0; 2935496197fSDavid Howells } 2945496197fSDavid Howells 2959fd4dcecSNicolai Stange static int open_proxy_open(struct inode *inode, struct file *filp) 2969fd4dcecSNicolai Stange { 29769d29f9eSNicolai Stange struct dentry *dentry = F_DENTRY(filp); 2989fd4dcecSNicolai Stange const struct file_operations *real_fops = NULL; 2997d39bc50SNicolai Stange int r; 3009fd4dcecSNicolai Stange 30167510d7eSJohannes Berg r = __debugfs_file_get(dentry, DBGFS_GET_REGULAR); 3027d39bc50SNicolai Stange if (r) 3037d39bc50SNicolai Stange return r == -EIO ? -ENOENT : r; 3049fd4dcecSNicolai Stange 30586f0e067SChristian Lamparter real_fops = debugfs_real_fops(filp); 3065496197fSDavid Howells 307a37f4958SEric Snowberg r = debugfs_locked_down(inode, filp, real_fops); 3085496197fSDavid Howells if (r) 3095496197fSDavid Howells goto out; 3105496197fSDavid Howells 311275678e7STaehee Yoo if (!fops_get(real_fops)) { 312e3b9fc7eSVladis Dronov #ifdef CONFIG_MODULES 313275678e7STaehee Yoo if (real_fops->owner && 314112cedc8SSven Eckelmann real_fops->owner->state == MODULE_STATE_GOING) { 315112cedc8SSven Eckelmann r = -ENXIO; 316275678e7STaehee Yoo goto out; 317112cedc8SSven Eckelmann } 318275678e7STaehee Yoo #endif 319275678e7STaehee Yoo 3209fd4dcecSNicolai Stange /* Huh? Module did not clean up after itself at exit? */ 3219fd4dcecSNicolai Stange WARN(1, "debugfs file owner did not clean up at exit: %pd", 3229fd4dcecSNicolai Stange dentry); 3239fd4dcecSNicolai Stange r = -ENXIO; 3249fd4dcecSNicolai Stange goto out; 3259fd4dcecSNicolai Stange } 3269fd4dcecSNicolai Stange replace_fops(filp, real_fops); 3279fd4dcecSNicolai Stange 3289fd4dcecSNicolai Stange if (real_fops->open) 3299fd4dcecSNicolai Stange r = real_fops->open(inode, filp); 3309fd4dcecSNicolai Stange 3319fd4dcecSNicolai Stange out: 33269d29f9eSNicolai Stange debugfs_file_put(dentry); 3339fd4dcecSNicolai Stange return r; 3349fd4dcecSNicolai Stange } 3359fd4dcecSNicolai Stange 3369fd4dcecSNicolai Stange const struct file_operations debugfs_open_proxy_file_operations = { 3379fd4dcecSNicolai Stange .open = open_proxy_open, 3389fd4dcecSNicolai Stange }; 3399fd4dcecSNicolai Stange 34049d200deSNicolai Stange #define PROTO(args...) args 34149d200deSNicolai Stange #define ARGS(args...) args 34249d200deSNicolai Stange 343*41a0ecc0SAl Viro #define FULL_PROXY_FUNC(name, ret_type, filp, proto, args, bit, ret) \ 34449d200deSNicolai Stange static ret_type full_proxy_ ## name(proto) \ 34549d200deSNicolai Stange { \ 34669d29f9eSNicolai Stange struct dentry *dentry = F_DENTRY(filp); \ 347*41a0ecc0SAl Viro struct debugfs_fsdata *fsd = dentry->d_fsdata; \ 348154b9d75SNicolai Stange const struct file_operations *real_fops; \ 34949d200deSNicolai Stange ret_type r; \ 35049d200deSNicolai Stange \ 351*41a0ecc0SAl Viro if (!(fsd->methods & bit)) \ 352*41a0ecc0SAl Viro return ret; \ 35369d29f9eSNicolai Stange r = debugfs_file_get(dentry); \ 35469d29f9eSNicolai Stange if (unlikely(r)) \ 35569d29f9eSNicolai Stange return r; \ 356154b9d75SNicolai Stange real_fops = debugfs_real_fops(filp); \ 35749d200deSNicolai Stange r = real_fops->name(args); \ 35869d29f9eSNicolai Stange debugfs_file_put(dentry); \ 35949d200deSNicolai Stange return r; \ 36049d200deSNicolai Stange } 36149d200deSNicolai Stange 362*41a0ecc0SAl Viro #define FULL_PROXY_FUNC_BOTH(name, ret_type, filp, proto, args, bit, ret) \ 3638dc6d81cSJohannes Berg static ret_type full_proxy_ ## name(proto) \ 3648dc6d81cSJohannes Berg { \ 3658dc6d81cSJohannes Berg struct dentry *dentry = F_DENTRY(filp); \ 366*41a0ecc0SAl Viro struct debugfs_fsdata *fsd = dentry->d_fsdata; \ 3678dc6d81cSJohannes Berg ret_type r; \ 3688dc6d81cSJohannes Berg \ 369*41a0ecc0SAl Viro if (!(fsd->methods & bit)) \ 370*41a0ecc0SAl Viro return ret; \ 3718dc6d81cSJohannes Berg r = debugfs_file_get(dentry); \ 3728dc6d81cSJohannes Berg if (unlikely(r)) \ 3738dc6d81cSJohannes Berg return r; \ 3748dc6d81cSJohannes Berg if (fsd->real_fops) \ 3758dc6d81cSJohannes Berg r = fsd->real_fops->name(args); \ 3768dc6d81cSJohannes Berg else \ 3778dc6d81cSJohannes Berg r = fsd->short_fops->name(args); \ 3788dc6d81cSJohannes Berg debugfs_file_put(dentry); \ 3798dc6d81cSJohannes Berg return r; \ 3808dc6d81cSJohannes Berg } 3818dc6d81cSJohannes Berg 3828dc6d81cSJohannes Berg FULL_PROXY_FUNC_BOTH(llseek, loff_t, filp, 38349d200deSNicolai Stange PROTO(struct file *filp, loff_t offset, int whence), 384*41a0ecc0SAl Viro ARGS(filp, offset, whence), HAS_LSEEK, -ESPIPE); 38549d200deSNicolai Stange 3868dc6d81cSJohannes Berg FULL_PROXY_FUNC_BOTH(read, ssize_t, filp, 38749d200deSNicolai Stange PROTO(struct file *filp, char __user *buf, size_t size, 38849d200deSNicolai Stange loff_t *ppos), 389*41a0ecc0SAl Viro ARGS(filp, buf, size, ppos), HAS_READ, -EINVAL); 39049d200deSNicolai Stange 3918dc6d81cSJohannes Berg FULL_PROXY_FUNC_BOTH(write, ssize_t, filp, 3928dc6d81cSJohannes Berg PROTO(struct file *filp, const char __user *buf, 3938dc6d81cSJohannes Berg size_t size, loff_t *ppos), 394*41a0ecc0SAl Viro ARGS(filp, buf, size, ppos), HAS_WRITE, -EINVAL); 39549d200deSNicolai Stange 39649d200deSNicolai Stange FULL_PROXY_FUNC(unlocked_ioctl, long, filp, 39749d200deSNicolai Stange PROTO(struct file *filp, unsigned int cmd, unsigned long arg), 398*41a0ecc0SAl Viro ARGS(filp, cmd, arg), HAS_IOCTL, -ENOTTY); 39949d200deSNicolai Stange 400076ccb76SAl Viro static __poll_t full_proxy_poll(struct file *filp, 40149d200deSNicolai Stange struct poll_table_struct *wait) 40249d200deSNicolai Stange { 40369d29f9eSNicolai Stange struct dentry *dentry = F_DENTRY(filp); 404*41a0ecc0SAl Viro struct debugfs_fsdata *fsd = dentry->d_fsdata; 405e6c8adcaSAl Viro __poll_t r = 0; 406154b9d75SNicolai Stange const struct file_operations *real_fops; 40749d200deSNicolai Stange 408*41a0ecc0SAl Viro if (!(fsd->methods & HAS_POLL)) 409*41a0ecc0SAl Viro return DEFAULT_POLLMASK; 41069d29f9eSNicolai Stange if (debugfs_file_get(dentry)) 411a9a08845SLinus Torvalds return EPOLLHUP; 41249d200deSNicolai Stange 413154b9d75SNicolai Stange real_fops = debugfs_real_fops(filp); 41449d200deSNicolai Stange r = real_fops->poll(filp, wait); 41569d29f9eSNicolai Stange debugfs_file_put(dentry); 41649d200deSNicolai Stange return r; 41749d200deSNicolai Stange } 41849d200deSNicolai Stange 41949d200deSNicolai Stange static int full_proxy_release(struct inode *inode, struct file *filp) 42049d200deSNicolai Stange { 42186f0e067SChristian Lamparter const struct file_operations *real_fops = debugfs_real_fops(filp); 42249d200deSNicolai Stange int r = 0; 42349d200deSNicolai Stange 42449d200deSNicolai Stange /* 42549d200deSNicolai Stange * We must not protect this against removal races here: the 42649d200deSNicolai Stange * original releaser should be called unconditionally in order 42749d200deSNicolai Stange * not to leak any resources. Releasers must not assume that 42849d200deSNicolai Stange * ->i_private is still being meaningful here. 42949d200deSNicolai Stange */ 4308dc6d81cSJohannes Berg if (real_fops && real_fops->release) 43149d200deSNicolai Stange r = real_fops->release(inode, filp); 43249d200deSNicolai Stange 43349d200deSNicolai Stange fops_put(real_fops); 434a1a9e5d2SEric Engestrom return r; 43549d200deSNicolai Stange } 43649d200deSNicolai Stange 437f8f25893SJohannes Berg static int full_proxy_open(struct inode *inode, struct file *filp, 438f8f25893SJohannes Berg enum dbgfs_get_mode mode) 43949d200deSNicolai Stange { 44069d29f9eSNicolai Stange struct dentry *dentry = F_DENTRY(filp); 4418dc6d81cSJohannes Berg const struct file_operations *real_fops; 4428dc6d81cSJohannes Berg struct debugfs_fsdata *fsd; 4437d39bc50SNicolai Stange int r; 44449d200deSNicolai Stange 445f8f25893SJohannes Berg r = __debugfs_file_get(dentry, mode); 4467d39bc50SNicolai Stange if (r) 4477d39bc50SNicolai Stange return r == -EIO ? -ENOENT : r; 44849d200deSNicolai Stange 4498dc6d81cSJohannes Berg fsd = dentry->d_fsdata; 4508dc6d81cSJohannes Berg real_fops = fsd->real_fops; 451a37f4958SEric Snowberg r = debugfs_locked_down(inode, filp, real_fops); 4525496197fSDavid Howells if (r) 4535496197fSDavid Howells goto out; 4545496197fSDavid Howells 4558dc6d81cSJohannes Berg if (real_fops && !fops_get(real_fops)) { 456e3b9fc7eSVladis Dronov #ifdef CONFIG_MODULES 457275678e7STaehee Yoo if (real_fops->owner && 458112cedc8SSven Eckelmann real_fops->owner->state == MODULE_STATE_GOING) { 459112cedc8SSven Eckelmann r = -ENXIO; 460275678e7STaehee Yoo goto out; 461112cedc8SSven Eckelmann } 462275678e7STaehee Yoo #endif 463275678e7STaehee Yoo 46449d200deSNicolai Stange /* Huh? Module did not cleanup after itself at exit? */ 46549d200deSNicolai Stange WARN(1, "debugfs file owner did not clean up at exit: %pd", 46649d200deSNicolai Stange dentry); 46749d200deSNicolai Stange r = -ENXIO; 46849d200deSNicolai Stange goto out; 46949d200deSNicolai Stange } 47049d200deSNicolai Stange 4718dc6d81cSJohannes Berg if (!real_fops || real_fops->open) { 4728dc6d81cSJohannes Berg if (real_fops) 47349d200deSNicolai Stange r = real_fops->open(inode, filp); 4748dc6d81cSJohannes Berg else 4758dc6d81cSJohannes Berg r = simple_open(inode, filp); 476b10e3e90SNicolai Stange if (r) { 477*41a0ecc0SAl Viro fops_put(real_fops); 478*41a0ecc0SAl Viro } else if (filp->f_op != &debugfs_full_proxy_file_operations) { 47949d200deSNicolai Stange /* No protection against file removal anymore. */ 48049d200deSNicolai Stange WARN(1, "debugfs file owner replaced proxy fops: %pd", 48149d200deSNicolai Stange dentry); 48249d200deSNicolai Stange fops_put(real_fops); 483*41a0ecc0SAl Viro } 484*41a0ecc0SAl Viro } 48549d200deSNicolai Stange out: 48669d29f9eSNicolai Stange debugfs_file_put(dentry); 48749d200deSNicolai Stange return r; 48849d200deSNicolai Stange } 48949d200deSNicolai Stange 490f8f25893SJohannes Berg static int full_proxy_open_regular(struct inode *inode, struct file *filp) 491f8f25893SJohannes Berg { 492f8f25893SJohannes Berg return full_proxy_open(inode, filp, DBGFS_GET_REGULAR); 493f8f25893SJohannes Berg } 494f8f25893SJohannes Berg 49549d200deSNicolai Stange const struct file_operations debugfs_full_proxy_file_operations = { 496f8f25893SJohannes Berg .open = full_proxy_open_regular, 497*41a0ecc0SAl Viro .release = full_proxy_release, 498*41a0ecc0SAl Viro .llseek = full_proxy_llseek, 499*41a0ecc0SAl Viro .read = full_proxy_read, 500*41a0ecc0SAl Viro .write = full_proxy_write, 501*41a0ecc0SAl Viro .poll = full_proxy_poll, 502*41a0ecc0SAl Viro .unlocked_ioctl = full_proxy_unlocked_ioctl 503f8f25893SJohannes Berg }; 504f8f25893SJohannes Berg 505f8f25893SJohannes Berg static int full_proxy_open_short(struct inode *inode, struct file *filp) 506f8f25893SJohannes Berg { 507f8f25893SJohannes Berg return full_proxy_open(inode, filp, DBGFS_GET_SHORT); 508f8f25893SJohannes Berg } 509f8f25893SJohannes Berg 510f8f25893SJohannes Berg const struct file_operations debugfs_full_short_proxy_file_operations = { 511f8f25893SJohannes Berg .open = full_proxy_open_short, 512*41a0ecc0SAl Viro .llseek = full_proxy_llseek, 513*41a0ecc0SAl Viro .read = full_proxy_read, 514*41a0ecc0SAl Viro .write = full_proxy_write, 51549d200deSNicolai Stange }; 51649d200deSNicolai Stange 517c6468808SNicolai Stange ssize_t debugfs_attr_read(struct file *file, char __user *buf, 518c6468808SNicolai Stange size_t len, loff_t *ppos) 519c6468808SNicolai Stange { 52069d29f9eSNicolai Stange struct dentry *dentry = F_DENTRY(file); 521c6468808SNicolai Stange ssize_t ret; 522c6468808SNicolai Stange 52369d29f9eSNicolai Stange ret = debugfs_file_get(dentry); 52469d29f9eSNicolai Stange if (unlikely(ret)) 52569d29f9eSNicolai Stange return ret; 526c6468808SNicolai Stange ret = simple_attr_read(file, buf, len, ppos); 52769d29f9eSNicolai Stange debugfs_file_put(dentry); 528c6468808SNicolai Stange return ret; 529c6468808SNicolai Stange } 530c6468808SNicolai Stange EXPORT_SYMBOL_GPL(debugfs_attr_read); 531c6468808SNicolai Stange 532d472cf79SAkinobu Mita static ssize_t debugfs_attr_write_xsigned(struct file *file, const char __user *buf, 533d472cf79SAkinobu Mita size_t len, loff_t *ppos, bool is_signed) 534c6468808SNicolai Stange { 53569d29f9eSNicolai Stange struct dentry *dentry = F_DENTRY(file); 536c6468808SNicolai Stange ssize_t ret; 537c6468808SNicolai Stange 53869d29f9eSNicolai Stange ret = debugfs_file_get(dentry); 53969d29f9eSNicolai Stange if (unlikely(ret)) 54069d29f9eSNicolai Stange return ret; 541d472cf79SAkinobu Mita if (is_signed) 542d472cf79SAkinobu Mita ret = simple_attr_write_signed(file, buf, len, ppos); 543d472cf79SAkinobu Mita else 544c6468808SNicolai Stange ret = simple_attr_write(file, buf, len, ppos); 54569d29f9eSNicolai Stange debugfs_file_put(dentry); 546c6468808SNicolai Stange return ret; 547c6468808SNicolai Stange } 548d472cf79SAkinobu Mita 549d472cf79SAkinobu Mita ssize_t debugfs_attr_write(struct file *file, const char __user *buf, 550d472cf79SAkinobu Mita size_t len, loff_t *ppos) 551d472cf79SAkinobu Mita { 552d472cf79SAkinobu Mita return debugfs_attr_write_xsigned(file, buf, len, ppos, false); 553d472cf79SAkinobu Mita } 554c6468808SNicolai Stange EXPORT_SYMBOL_GPL(debugfs_attr_write); 555c6468808SNicolai Stange 556d472cf79SAkinobu Mita ssize_t debugfs_attr_write_signed(struct file *file, const char __user *buf, 557d472cf79SAkinobu Mita size_t len, loff_t *ppos) 558d472cf79SAkinobu Mita { 559d472cf79SAkinobu Mita return debugfs_attr_write_xsigned(file, buf, len, ppos, true); 560d472cf79SAkinobu Mita } 561d472cf79SAkinobu Mita EXPORT_SYMBOL_GPL(debugfs_attr_write_signed); 562d472cf79SAkinobu Mita 5634909f168SNicolai Stange static struct dentry *debugfs_create_mode_unsafe(const char *name, umode_t mode, 5644909f168SNicolai Stange struct dentry *parent, void *value, 5654909f168SNicolai Stange const struct file_operations *fops, 5664909f168SNicolai Stange const struct file_operations *fops_ro, 5674909f168SNicolai Stange const struct file_operations *fops_wo) 5684909f168SNicolai Stange { 5694909f168SNicolai Stange /* if there are no write bits set, make read only */ 5704909f168SNicolai Stange if (!(mode & S_IWUGO)) 5714909f168SNicolai Stange return debugfs_create_file_unsafe(name, mode, parent, value, 5724909f168SNicolai Stange fops_ro); 5734909f168SNicolai Stange /* if there are no read bits set, make write only */ 5744909f168SNicolai Stange if (!(mode & S_IRUGO)) 5754909f168SNicolai Stange return debugfs_create_file_unsafe(name, mode, parent, value, 5764909f168SNicolai Stange fops_wo); 5774909f168SNicolai Stange 5784909f168SNicolai Stange return debugfs_create_file_unsafe(name, mode, parent, value, fops); 5794909f168SNicolai Stange } 5804909f168SNicolai Stange 5818b88b099SChristoph Hellwig static int debugfs_u8_set(void *data, u64 val) 582acaefc25SArnd Bergmann { 583acaefc25SArnd Bergmann *(u8 *)data = val; 5848b88b099SChristoph Hellwig return 0; 585acaefc25SArnd Bergmann } 5868b88b099SChristoph Hellwig static int debugfs_u8_get(void *data, u64 *val) 587acaefc25SArnd Bergmann { 5888b88b099SChristoph Hellwig *val = *(u8 *)data; 5898b88b099SChristoph Hellwig return 0; 590acaefc25SArnd Bergmann } 5914909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_u8, debugfs_u8_get, debugfs_u8_set, "%llu\n"); 5924909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_u8_ro, debugfs_u8_get, NULL, "%llu\n"); 5934909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_u8_wo, NULL, debugfs_u8_set, "%llu\n"); 5941da177e4SLinus Torvalds 5951da177e4SLinus Torvalds /** 5966468b3afSRandy Dunlap * debugfs_create_u8 - create a debugfs file that is used to read and write an unsigned 8-bit value 5971da177e4SLinus Torvalds * @name: a pointer to a string containing the name of the file to create. 5981da177e4SLinus Torvalds * @mode: the permission that the file should have 5991da177e4SLinus Torvalds * @parent: a pointer to the parent dentry for this file. This should be a 6006468b3afSRandy Dunlap * directory dentry if set. If this parameter is %NULL, then the 6011da177e4SLinus Torvalds * file will be created in the root of the debugfs filesystem. 6021da177e4SLinus Torvalds * @value: a pointer to the variable that the file should read to and write 6031da177e4SLinus Torvalds * from. 6041da177e4SLinus Torvalds * 6051da177e4SLinus Torvalds * This function creates a file in debugfs with the given name that 6061da177e4SLinus Torvalds * contains the value of the variable @value. If the @mode variable is so 6071da177e4SLinus Torvalds * set, it can be read from, and written to. 6081da177e4SLinus Torvalds */ 6099655ac4aSGreg Kroah-Hartman void debugfs_create_u8(const char *name, umode_t mode, struct dentry *parent, 6109655ac4aSGreg Kroah-Hartman u8 *value) 6111da177e4SLinus Torvalds { 6129655ac4aSGreg Kroah-Hartman debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u8, 613b97f6799SStephen Boyd &fops_u8_ro, &fops_u8_wo); 6141da177e4SLinus Torvalds } 6151da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(debugfs_create_u8); 6161da177e4SLinus Torvalds 6178b88b099SChristoph Hellwig static int debugfs_u16_set(void *data, u64 val) 618acaefc25SArnd Bergmann { 619acaefc25SArnd Bergmann *(u16 *)data = val; 6208b88b099SChristoph Hellwig return 0; 621acaefc25SArnd Bergmann } 6228b88b099SChristoph Hellwig static int debugfs_u16_get(void *data, u64 *val) 623acaefc25SArnd Bergmann { 6248b88b099SChristoph Hellwig *val = *(u16 *)data; 6258b88b099SChristoph Hellwig return 0; 626acaefc25SArnd Bergmann } 6274909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_u16, debugfs_u16_get, debugfs_u16_set, "%llu\n"); 6284909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_u16_ro, debugfs_u16_get, NULL, "%llu\n"); 6294909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_u16_wo, NULL, debugfs_u16_set, "%llu\n"); 630acaefc25SArnd Bergmann 6311da177e4SLinus Torvalds /** 6326468b3afSRandy Dunlap * debugfs_create_u16 - create a debugfs file that is used to read and write an unsigned 16-bit value 6331da177e4SLinus Torvalds * @name: a pointer to a string containing the name of the file to create. 6341da177e4SLinus Torvalds * @mode: the permission that the file should have 6351da177e4SLinus Torvalds * @parent: a pointer to the parent dentry for this file. This should be a 6366468b3afSRandy Dunlap * directory dentry if set. If this parameter is %NULL, then the 6371da177e4SLinus Torvalds * file will be created in the root of the debugfs filesystem. 6381da177e4SLinus Torvalds * @value: a pointer to the variable that the file should read to and write 6391da177e4SLinus Torvalds * from. 6401da177e4SLinus Torvalds * 6411da177e4SLinus Torvalds * This function creates a file in debugfs with the given name that 6421da177e4SLinus Torvalds * contains the value of the variable @value. If the @mode variable is so 6431da177e4SLinus Torvalds * set, it can be read from, and written to. 6441da177e4SLinus Torvalds */ 645313f5dbbSGreg Kroah-Hartman void debugfs_create_u16(const char *name, umode_t mode, struct dentry *parent, 646313f5dbbSGreg Kroah-Hartman u16 *value) 6471da177e4SLinus Torvalds { 648313f5dbbSGreg Kroah-Hartman debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u16, 649b97f6799SStephen Boyd &fops_u16_ro, &fops_u16_wo); 6501da177e4SLinus Torvalds } 6511da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(debugfs_create_u16); 6521da177e4SLinus Torvalds 6538b88b099SChristoph Hellwig static int debugfs_u32_set(void *data, u64 val) 654acaefc25SArnd Bergmann { 655acaefc25SArnd Bergmann *(u32 *)data = val; 6568b88b099SChristoph Hellwig return 0; 657acaefc25SArnd Bergmann } 6588b88b099SChristoph Hellwig static int debugfs_u32_get(void *data, u64 *val) 659acaefc25SArnd Bergmann { 6608b88b099SChristoph Hellwig *val = *(u32 *)data; 6618b88b099SChristoph Hellwig return 0; 662acaefc25SArnd Bergmann } 6634909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_u32, debugfs_u32_get, debugfs_u32_set, "%llu\n"); 6644909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_u32_ro, debugfs_u32_get, NULL, "%llu\n"); 6654909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_u32_wo, NULL, debugfs_u32_set, "%llu\n"); 666acaefc25SArnd Bergmann 6671da177e4SLinus Torvalds /** 6686468b3afSRandy Dunlap * debugfs_create_u32 - create a debugfs file that is used to read and write an unsigned 32-bit value 6691da177e4SLinus Torvalds * @name: a pointer to a string containing the name of the file to create. 6701da177e4SLinus Torvalds * @mode: the permission that the file should have 6711da177e4SLinus Torvalds * @parent: a pointer to the parent dentry for this file. This should be a 6726468b3afSRandy Dunlap * directory dentry if set. If this parameter is %NULL, then the 6731da177e4SLinus Torvalds * file will be created in the root of the debugfs filesystem. 6741da177e4SLinus Torvalds * @value: a pointer to the variable that the file should read to and write 6751da177e4SLinus Torvalds * from. 6761da177e4SLinus Torvalds * 6771da177e4SLinus Torvalds * This function creates a file in debugfs with the given name that 6781da177e4SLinus Torvalds * contains the value of the variable @value. If the @mode variable is so 6791da177e4SLinus Torvalds * set, it can be read from, and written to. 6801da177e4SLinus Torvalds */ 6812b07021aSGreg Kroah-Hartman void debugfs_create_u32(const char *name, umode_t mode, struct dentry *parent, 6822b07021aSGreg Kroah-Hartman u32 *value) 6831da177e4SLinus Torvalds { 6842b07021aSGreg Kroah-Hartman debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u32, 685b97f6799SStephen Boyd &fops_u32_ro, &fops_u32_wo); 6861da177e4SLinus Torvalds } 6871da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(debugfs_create_u32); 6881da177e4SLinus Torvalds 6898b88b099SChristoph Hellwig static int debugfs_u64_set(void *data, u64 val) 6908447891fSMichael Ellerman { 6918447891fSMichael Ellerman *(u64 *)data = val; 6928b88b099SChristoph Hellwig return 0; 6938447891fSMichael Ellerman } 6948447891fSMichael Ellerman 6958b88b099SChristoph Hellwig static int debugfs_u64_get(void *data, u64 *val) 6968447891fSMichael Ellerman { 6978b88b099SChristoph Hellwig *val = *(u64 *)data; 6988b88b099SChristoph Hellwig return 0; 6998447891fSMichael Ellerman } 7004909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_u64, debugfs_u64_get, debugfs_u64_set, "%llu\n"); 7014909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_u64_ro, debugfs_u64_get, NULL, "%llu\n"); 7024909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_u64_wo, NULL, debugfs_u64_set, "%llu\n"); 7038447891fSMichael Ellerman 7048447891fSMichael Ellerman /** 7058447891fSMichael Ellerman * debugfs_create_u64 - create a debugfs file that is used to read and write an unsigned 64-bit value 7068447891fSMichael Ellerman * @name: a pointer to a string containing the name of the file to create. 7078447891fSMichael Ellerman * @mode: the permission that the file should have 7088447891fSMichael Ellerman * @parent: a pointer to the parent dentry for this file. This should be a 7098447891fSMichael Ellerman * directory dentry if set. If this parameter is %NULL, then the 7108447891fSMichael Ellerman * file will be created in the root of the debugfs filesystem. 7118447891fSMichael Ellerman * @value: a pointer to the variable that the file should read to and write 7128447891fSMichael Ellerman * from. 7138447891fSMichael Ellerman * 7148447891fSMichael Ellerman * This function creates a file in debugfs with the given name that 7158447891fSMichael Ellerman * contains the value of the variable @value. If the @mode variable is so 7168447891fSMichael Ellerman * set, it can be read from, and written to. 7178447891fSMichael Ellerman */ 718ad26221fSGreg Kroah-Hartman void debugfs_create_u64(const char *name, umode_t mode, struct dentry *parent, 719ad26221fSGreg Kroah-Hartman u64 *value) 7208447891fSMichael Ellerman { 721ad26221fSGreg Kroah-Hartman debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u64, 722b97f6799SStephen Boyd &fops_u64_ro, &fops_u64_wo); 7238447891fSMichael Ellerman } 7248447891fSMichael Ellerman EXPORT_SYMBOL_GPL(debugfs_create_u64); 7258447891fSMichael Ellerman 726c23fe831SViresh Kumar static int debugfs_ulong_set(void *data, u64 val) 727c23fe831SViresh Kumar { 728c23fe831SViresh Kumar *(unsigned long *)data = val; 729c23fe831SViresh Kumar return 0; 730c23fe831SViresh Kumar } 731c23fe831SViresh Kumar 732c23fe831SViresh Kumar static int debugfs_ulong_get(void *data, u64 *val) 733c23fe831SViresh Kumar { 734c23fe831SViresh Kumar *val = *(unsigned long *)data; 735c23fe831SViresh Kumar return 0; 736c23fe831SViresh Kumar } 7374909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong, debugfs_ulong_get, debugfs_ulong_set, 7384909f168SNicolai Stange "%llu\n"); 7394909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong_ro, debugfs_ulong_get, NULL, "%llu\n"); 7404909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong_wo, NULL, debugfs_ulong_set, "%llu\n"); 741c23fe831SViresh Kumar 742c23fe831SViresh Kumar /** 743c23fe831SViresh Kumar * debugfs_create_ulong - create a debugfs file that is used to read and write 744c23fe831SViresh Kumar * an unsigned long value. 745c23fe831SViresh Kumar * @name: a pointer to a string containing the name of the file to create. 746c23fe831SViresh Kumar * @mode: the permission that the file should have 747c23fe831SViresh Kumar * @parent: a pointer to the parent dentry for this file. This should be a 748c23fe831SViresh Kumar * directory dentry if set. If this parameter is %NULL, then the 749c23fe831SViresh Kumar * file will be created in the root of the debugfs filesystem. 750c23fe831SViresh Kumar * @value: a pointer to the variable that the file should read to and write 751c23fe831SViresh Kumar * from. 752c23fe831SViresh Kumar * 753c23fe831SViresh Kumar * This function creates a file in debugfs with the given name that 754c23fe831SViresh Kumar * contains the value of the variable @value. If the @mode variable is so 755c23fe831SViresh Kumar * set, it can be read from, and written to. 756c23fe831SViresh Kumar */ 757fb05b14cSGreg Kroah-Hartman void debugfs_create_ulong(const char *name, umode_t mode, struct dentry *parent, 758fb05b14cSGreg Kroah-Hartman unsigned long *value) 759c23fe831SViresh Kumar { 760fb05b14cSGreg Kroah-Hartman debugfs_create_mode_unsafe(name, mode, parent, value, &fops_ulong, 761fb05b14cSGreg Kroah-Hartman &fops_ulong_ro, &fops_ulong_wo); 762c23fe831SViresh Kumar } 763c23fe831SViresh Kumar EXPORT_SYMBOL_GPL(debugfs_create_ulong); 764c23fe831SViresh Kumar 7654909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_x8, debugfs_u8_get, debugfs_u8_set, "0x%02llx\n"); 7664909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_x8_ro, debugfs_u8_get, NULL, "0x%02llx\n"); 7674909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_x8_wo, NULL, debugfs_u8_set, "0x%02llx\n"); 7682ebefc50SRobin Getz 7694909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_x16, debugfs_u16_get, debugfs_u16_set, 7704909f168SNicolai Stange "0x%04llx\n"); 7714909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_x16_ro, debugfs_u16_get, NULL, "0x%04llx\n"); 7724909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_x16_wo, NULL, debugfs_u16_set, "0x%04llx\n"); 7732ebefc50SRobin Getz 7744909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_x32, debugfs_u32_get, debugfs_u32_set, 7754909f168SNicolai Stange "0x%08llx\n"); 7764909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_x32_ro, debugfs_u32_get, NULL, "0x%08llx\n"); 7774909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_x32_wo, NULL, debugfs_u32_set, "0x%08llx\n"); 7782ebefc50SRobin Getz 7794909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_x64, debugfs_u64_get, debugfs_u64_set, 7804909f168SNicolai Stange "0x%016llx\n"); 7814909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_x64_ro, debugfs_u64_get, NULL, "0x%016llx\n"); 7824909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_x64_wo, NULL, debugfs_u64_set, "0x%016llx\n"); 78315b0beaaSHuang Ying 784e6716b87SRandy Dunlap /* 78515b0beaaSHuang Ying * debugfs_create_x{8,16,32,64} - create a debugfs file that is used to read and write an unsigned {8,16,32,64}-bit value 786e6716b87SRandy Dunlap * 787e6716b87SRandy Dunlap * These functions are exactly the same as the above functions (but use a hex 788e6716b87SRandy Dunlap * output for the decimal challenged). For details look at the above unsigned 789e6716b87SRandy Dunlap * decimal functions. 790e6716b87SRandy Dunlap */ 791e6716b87SRandy Dunlap 7922ebefc50SRobin Getz /** 7932ebefc50SRobin Getz * debugfs_create_x8 - create a debugfs file that is used to read and write an unsigned 8-bit value 794e6716b87SRandy Dunlap * @name: a pointer to a string containing the name of the file to create. 795e6716b87SRandy Dunlap * @mode: the permission that the file should have 796e6716b87SRandy Dunlap * @parent: a pointer to the parent dentry for this file. This should be a 797e6716b87SRandy Dunlap * directory dentry if set. If this parameter is %NULL, then the 798e6716b87SRandy Dunlap * file will be created in the root of the debugfs filesystem. 799e6716b87SRandy Dunlap * @value: a pointer to the variable that the file should read to and write 800e6716b87SRandy Dunlap * from. 8012ebefc50SRobin Getz */ 802c7c11689SGreg Kroah-Hartman void debugfs_create_x8(const char *name, umode_t mode, struct dentry *parent, 803c7c11689SGreg Kroah-Hartman u8 *value) 8042ebefc50SRobin Getz { 805c7c11689SGreg Kroah-Hartman debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x8, 806b97f6799SStephen Boyd &fops_x8_ro, &fops_x8_wo); 8072ebefc50SRobin Getz } 8082ebefc50SRobin Getz EXPORT_SYMBOL_GPL(debugfs_create_x8); 8092ebefc50SRobin Getz 810e6716b87SRandy Dunlap /** 811e6716b87SRandy Dunlap * debugfs_create_x16 - create a debugfs file that is used to read and write an unsigned 16-bit value 812e6716b87SRandy Dunlap * @name: a pointer to a string containing the name of the file to create. 813e6716b87SRandy Dunlap * @mode: the permission that the file should have 814e6716b87SRandy Dunlap * @parent: a pointer to the parent dentry for this file. This should be a 815e6716b87SRandy Dunlap * directory dentry if set. If this parameter is %NULL, then the 816e6716b87SRandy Dunlap * file will be created in the root of the debugfs filesystem. 817e6716b87SRandy Dunlap * @value: a pointer to the variable that the file should read to and write 818e6716b87SRandy Dunlap * from. 819e6716b87SRandy Dunlap */ 820e40d38f2SGreg Kroah-Hartman void debugfs_create_x16(const char *name, umode_t mode, struct dentry *parent, 821e40d38f2SGreg Kroah-Hartman u16 *value) 8222ebefc50SRobin Getz { 823e40d38f2SGreg Kroah-Hartman debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x16, 824b97f6799SStephen Boyd &fops_x16_ro, &fops_x16_wo); 8252ebefc50SRobin Getz } 8262ebefc50SRobin Getz EXPORT_SYMBOL_GPL(debugfs_create_x16); 8272ebefc50SRobin Getz 828e6716b87SRandy Dunlap /** 829e6716b87SRandy Dunlap * debugfs_create_x32 - create a debugfs file that is used to read and write an unsigned 32-bit value 830e6716b87SRandy Dunlap * @name: a pointer to a string containing the name of the file to create. 831e6716b87SRandy Dunlap * @mode: the permission that the file should have 832e6716b87SRandy Dunlap * @parent: a pointer to the parent dentry for this file. This should be a 833e6716b87SRandy Dunlap * directory dentry if set. If this parameter is %NULL, then the 834e6716b87SRandy Dunlap * file will be created in the root of the debugfs filesystem. 835e6716b87SRandy Dunlap * @value: a pointer to the variable that the file should read to and write 836e6716b87SRandy Dunlap * from. 837e6716b87SRandy Dunlap */ 838f5cb0a7eSGreg Kroah-Hartman void debugfs_create_x32(const char *name, umode_t mode, struct dentry *parent, 839f5cb0a7eSGreg Kroah-Hartman u32 *value) 8402ebefc50SRobin Getz { 841f5cb0a7eSGreg Kroah-Hartman debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x32, 842b97f6799SStephen Boyd &fops_x32_ro, &fops_x32_wo); 8432ebefc50SRobin Getz } 8442ebefc50SRobin Getz EXPORT_SYMBOL_GPL(debugfs_create_x32); 8452ebefc50SRobin Getz 84615b0beaaSHuang Ying /** 84715b0beaaSHuang Ying * debugfs_create_x64 - create a debugfs file that is used to read and write an unsigned 64-bit value 84815b0beaaSHuang Ying * @name: a pointer to a string containing the name of the file to create. 84915b0beaaSHuang Ying * @mode: the permission that the file should have 85015b0beaaSHuang Ying * @parent: a pointer to the parent dentry for this file. This should be a 85115b0beaaSHuang Ying * directory dentry if set. If this parameter is %NULL, then the 85215b0beaaSHuang Ying * file will be created in the root of the debugfs filesystem. 85315b0beaaSHuang Ying * @value: a pointer to the variable that the file should read to and write 85415b0beaaSHuang Ying * from. 85515b0beaaSHuang Ying */ 8560864c408SGreg Kroah-Hartman void debugfs_create_x64(const char *name, umode_t mode, struct dentry *parent, 8570864c408SGreg Kroah-Hartman u64 *value) 85815b0beaaSHuang Ying { 8590864c408SGreg Kroah-Hartman debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x64, 86082b7d4fbSStephen Boyd &fops_x64_ro, &fops_x64_wo); 86115b0beaaSHuang Ying } 86215b0beaaSHuang Ying EXPORT_SYMBOL_GPL(debugfs_create_x64); 86315b0beaaSHuang Ying 8645e078787SInaky Perez-Gonzalez 8655e078787SInaky Perez-Gonzalez static int debugfs_size_t_set(void *data, u64 val) 8665e078787SInaky Perez-Gonzalez { 8675e078787SInaky Perez-Gonzalez *(size_t *)data = val; 8685e078787SInaky Perez-Gonzalez return 0; 8695e078787SInaky Perez-Gonzalez } 8705e078787SInaky Perez-Gonzalez static int debugfs_size_t_get(void *data, u64 *val) 8715e078787SInaky Perez-Gonzalez { 8725e078787SInaky Perez-Gonzalez *val = *(size_t *)data; 8735e078787SInaky Perez-Gonzalez return 0; 8745e078787SInaky Perez-Gonzalez } 8754909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_size_t, debugfs_size_t_get, debugfs_size_t_set, 8765e078787SInaky Perez-Gonzalez "%llu\n"); /* %llu and %zu are more or less the same */ 8774909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_size_t_ro, debugfs_size_t_get, NULL, "%llu\n"); 8784909f168SNicolai Stange DEFINE_DEBUGFS_ATTRIBUTE(fops_size_t_wo, NULL, debugfs_size_t_set, "%llu\n"); 8795e078787SInaky Perez-Gonzalez 8805e078787SInaky Perez-Gonzalez /** 8815e078787SInaky Perez-Gonzalez * debugfs_create_size_t - create a debugfs file that is used to read and write an size_t value 8825e078787SInaky Perez-Gonzalez * @name: a pointer to a string containing the name of the file to create. 8835e078787SInaky Perez-Gonzalez * @mode: the permission that the file should have 8845e078787SInaky Perez-Gonzalez * @parent: a pointer to the parent dentry for this file. This should be a 8855e078787SInaky Perez-Gonzalez * directory dentry if set. If this parameter is %NULL, then the 8865e078787SInaky Perez-Gonzalez * file will be created in the root of the debugfs filesystem. 8875e078787SInaky Perez-Gonzalez * @value: a pointer to the variable that the file should read to and write 8885e078787SInaky Perez-Gonzalez * from. 8895e078787SInaky Perez-Gonzalez */ 8908e580263SGreg Kroah-Hartman void debugfs_create_size_t(const char *name, umode_t mode, 8915e078787SInaky Perez-Gonzalez struct dentry *parent, size_t *value) 8925e078787SInaky Perez-Gonzalez { 8938e580263SGreg Kroah-Hartman debugfs_create_mode_unsafe(name, mode, parent, value, &fops_size_t, 8948e580263SGreg Kroah-Hartman &fops_size_t_ro, &fops_size_t_wo); 8955e078787SInaky Perez-Gonzalez } 8965e078787SInaky Perez-Gonzalez EXPORT_SYMBOL_GPL(debugfs_create_size_t); 8975e078787SInaky Perez-Gonzalez 8983a76e5e0SSeth Jennings static int debugfs_atomic_t_set(void *data, u64 val) 8993a76e5e0SSeth Jennings { 9003a76e5e0SSeth Jennings atomic_set((atomic_t *)data, val); 9013a76e5e0SSeth Jennings return 0; 9023a76e5e0SSeth Jennings } 9033a76e5e0SSeth Jennings static int debugfs_atomic_t_get(void *data, u64 *val) 9043a76e5e0SSeth Jennings { 9053a76e5e0SSeth Jennings *val = atomic_read((atomic_t *)data); 9063a76e5e0SSeth Jennings return 0; 9073a76e5e0SSeth Jennings } 908d472cf79SAkinobu Mita DEFINE_DEBUGFS_ATTRIBUTE_SIGNED(fops_atomic_t, debugfs_atomic_t_get, 9093a76e5e0SSeth Jennings debugfs_atomic_t_set, "%lld\n"); 910d472cf79SAkinobu Mita DEFINE_DEBUGFS_ATTRIBUTE_SIGNED(fops_atomic_t_ro, debugfs_atomic_t_get, NULL, 9114909f168SNicolai Stange "%lld\n"); 912d472cf79SAkinobu Mita DEFINE_DEBUGFS_ATTRIBUTE_SIGNED(fops_atomic_t_wo, NULL, debugfs_atomic_t_set, 9134909f168SNicolai Stange "%lld\n"); 9143a76e5e0SSeth Jennings 9153a76e5e0SSeth Jennings /** 9163a76e5e0SSeth Jennings * debugfs_create_atomic_t - create a debugfs file that is used to read and 9173a76e5e0SSeth Jennings * write an atomic_t value 9183a76e5e0SSeth Jennings * @name: a pointer to a string containing the name of the file to create. 9193a76e5e0SSeth Jennings * @mode: the permission that the file should have 9203a76e5e0SSeth Jennings * @parent: a pointer to the parent dentry for this file. This should be a 9213a76e5e0SSeth Jennings * directory dentry if set. If this parameter is %NULL, then the 9223a76e5e0SSeth Jennings * file will be created in the root of the debugfs filesystem. 9233a76e5e0SSeth Jennings * @value: a pointer to the variable that the file should read to and write 9243a76e5e0SSeth Jennings * from. 9253a76e5e0SSeth Jennings */ 9269927c6faSGreg Kroah-Hartman void debugfs_create_atomic_t(const char *name, umode_t mode, 9273a76e5e0SSeth Jennings struct dentry *parent, atomic_t *value) 9283a76e5e0SSeth Jennings { 9299927c6faSGreg Kroah-Hartman debugfs_create_mode_unsafe(name, mode, parent, value, &fops_atomic_t, 9309927c6faSGreg Kroah-Hartman &fops_atomic_t_ro, &fops_atomic_t_wo); 9313a76e5e0SSeth Jennings } 9323a76e5e0SSeth Jennings EXPORT_SYMBOL_GPL(debugfs_create_atomic_t); 9335e078787SInaky Perez-Gonzalez 9340642ef6fSRichard Fitzgerald ssize_t debugfs_read_file_bool(struct file *file, char __user *user_buf, 9351da177e4SLinus Torvalds size_t count, loff_t *ppos) 9361da177e4SLinus Torvalds { 937c8a9c285SRasmus Villemoes char buf[2]; 9384d45f797SNicolai Stange bool val; 93969d29f9eSNicolai Stange int r; 94069d29f9eSNicolai Stange struct dentry *dentry = F_DENTRY(file); 9411da177e4SLinus Torvalds 94269d29f9eSNicolai Stange r = debugfs_file_get(dentry); 94369d29f9eSNicolai Stange if (unlikely(r)) 9444d45f797SNicolai Stange return r; 94569d29f9eSNicolai Stange val = *(bool *)file->private_data; 94669d29f9eSNicolai Stange debugfs_file_put(dentry); 9474d45f797SNicolai Stange 9484d45f797SNicolai Stange if (val) 9491da177e4SLinus Torvalds buf[0] = 'Y'; 9501da177e4SLinus Torvalds else 9511da177e4SLinus Torvalds buf[0] = 'N'; 9521da177e4SLinus Torvalds buf[1] = '\n'; 9531da177e4SLinus Torvalds return simple_read_from_buffer(user_buf, count, ppos, buf, 2); 9541da177e4SLinus Torvalds } 9550642ef6fSRichard Fitzgerald EXPORT_SYMBOL_GPL(debugfs_read_file_bool); 9561da177e4SLinus Torvalds 9570642ef6fSRichard Fitzgerald ssize_t debugfs_write_file_bool(struct file *file, const char __user *user_buf, 9581da177e4SLinus Torvalds size_t count, loff_t *ppos) 9591da177e4SLinus Torvalds { 9608705b48eSJonathan Cameron bool bv; 96169d29f9eSNicolai Stange int r; 962621a5f7aSViresh Kumar bool *val = file->private_data; 96369d29f9eSNicolai Stange struct dentry *dentry = F_DENTRY(file); 9641da177e4SLinus Torvalds 965964f8363SAndy Shevchenko r = kstrtobool_from_user(user_buf, count, &bv); 966964f8363SAndy Shevchenko if (!r) { 96769d29f9eSNicolai Stange r = debugfs_file_get(dentry); 96869d29f9eSNicolai Stange if (unlikely(r)) 9694d45f797SNicolai Stange return r; 97069d29f9eSNicolai Stange *val = bv; 97169d29f9eSNicolai Stange debugfs_file_put(dentry); 9724d45f797SNicolai Stange } 9731da177e4SLinus Torvalds 9741da177e4SLinus Torvalds return count; 9751da177e4SLinus Torvalds } 9760642ef6fSRichard Fitzgerald EXPORT_SYMBOL_GPL(debugfs_write_file_bool); 9771da177e4SLinus Torvalds 9784b6f5d20SArjan van de Ven static const struct file_operations fops_bool = { 9790642ef6fSRichard Fitzgerald .read = debugfs_read_file_bool, 9800642ef6fSRichard Fitzgerald .write = debugfs_write_file_bool, 981234e3405SStephen Boyd .open = simple_open, 9826038f373SArnd Bergmann .llseek = default_llseek, 9831da177e4SLinus Torvalds }; 9841da177e4SLinus Torvalds 9856713e8fbSStephen Boyd static const struct file_operations fops_bool_ro = { 9866713e8fbSStephen Boyd .read = debugfs_read_file_bool, 9876713e8fbSStephen Boyd .open = simple_open, 9886713e8fbSStephen Boyd .llseek = default_llseek, 9896713e8fbSStephen Boyd }; 9906713e8fbSStephen Boyd 9916713e8fbSStephen Boyd static const struct file_operations fops_bool_wo = { 9926713e8fbSStephen Boyd .write = debugfs_write_file_bool, 9936713e8fbSStephen Boyd .open = simple_open, 9946713e8fbSStephen Boyd .llseek = default_llseek, 9956713e8fbSStephen Boyd }; 9966713e8fbSStephen Boyd 9971da177e4SLinus Torvalds /** 9986468b3afSRandy Dunlap * debugfs_create_bool - create a debugfs file that is used to read and write a boolean value 9991da177e4SLinus Torvalds * @name: a pointer to a string containing the name of the file to create. 10001da177e4SLinus Torvalds * @mode: the permission that the file should have 10011da177e4SLinus Torvalds * @parent: a pointer to the parent dentry for this file. This should be a 10026468b3afSRandy Dunlap * directory dentry if set. If this parameter is %NULL, then the 10031da177e4SLinus Torvalds * file will be created in the root of the debugfs filesystem. 10041da177e4SLinus Torvalds * @value: a pointer to the variable that the file should read to and write 10051da177e4SLinus Torvalds * from. 10061da177e4SLinus Torvalds * 10071da177e4SLinus Torvalds * This function creates a file in debugfs with the given name that 10081da177e4SLinus Torvalds * contains the value of the variable @value. If the @mode variable is so 10091da177e4SLinus Torvalds * set, it can be read from, and written to. 10101da177e4SLinus Torvalds */ 1011393b0638SGreg Kroah-Hartman void debugfs_create_bool(const char *name, umode_t mode, struct dentry *parent, 1012393b0638SGreg Kroah-Hartman bool *value) 10131da177e4SLinus Torvalds { 1014393b0638SGreg Kroah-Hartman debugfs_create_mode_unsafe(name, mode, parent, value, &fops_bool, 10156713e8fbSStephen Boyd &fops_bool_ro, &fops_bool_wo); 10161da177e4SLinus Torvalds } 10171da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(debugfs_create_bool); 10181da177e4SLinus Torvalds 10199af0440eSPeter Zijlstra ssize_t debugfs_read_file_str(struct file *file, char __user *user_buf, 10209af0440eSPeter Zijlstra size_t count, loff_t *ppos) 10219af0440eSPeter Zijlstra { 10229af0440eSPeter Zijlstra struct dentry *dentry = F_DENTRY(file); 10239af0440eSPeter Zijlstra char *str, *copy = NULL; 10249af0440eSPeter Zijlstra int copy_len, len; 10259af0440eSPeter Zijlstra ssize_t ret; 10269af0440eSPeter Zijlstra 10279af0440eSPeter Zijlstra ret = debugfs_file_get(dentry); 10289af0440eSPeter Zijlstra if (unlikely(ret)) 10299af0440eSPeter Zijlstra return ret; 10309af0440eSPeter Zijlstra 10319af0440eSPeter Zijlstra str = *(char **)file->private_data; 10329af0440eSPeter Zijlstra len = strlen(str) + 1; 10339af0440eSPeter Zijlstra copy = kmalloc(len, GFP_KERNEL); 10349af0440eSPeter Zijlstra if (!copy) { 10359af0440eSPeter Zijlstra debugfs_file_put(dentry); 10369af0440eSPeter Zijlstra return -ENOMEM; 10379af0440eSPeter Zijlstra } 10389af0440eSPeter Zijlstra 10399af0440eSPeter Zijlstra copy_len = strscpy(copy, str, len); 10409af0440eSPeter Zijlstra debugfs_file_put(dentry); 10419af0440eSPeter Zijlstra if (copy_len < 0) { 10429af0440eSPeter Zijlstra kfree(copy); 10439af0440eSPeter Zijlstra return copy_len; 10449af0440eSPeter Zijlstra } 10459af0440eSPeter Zijlstra 10469af0440eSPeter Zijlstra copy[copy_len] = '\n'; 10479af0440eSPeter Zijlstra 1048f501b6a2SDietmar Eggemann ret = simple_read_from_buffer(user_buf, count, ppos, copy, len); 10499af0440eSPeter Zijlstra kfree(copy); 10509af0440eSPeter Zijlstra 10519af0440eSPeter Zijlstra return ret; 10529af0440eSPeter Zijlstra } 1053d60b59b9SCristian Marussi EXPORT_SYMBOL_GPL(debugfs_create_str); 10549af0440eSPeter Zijlstra 10559af0440eSPeter Zijlstra static ssize_t debugfs_write_file_str(struct file *file, const char __user *user_buf, 10569af0440eSPeter Zijlstra size_t count, loff_t *ppos) 10579af0440eSPeter Zijlstra { 105886b54881SMike Tipton struct dentry *dentry = F_DENTRY(file); 105986b54881SMike Tipton char *old, *new = NULL; 106086b54881SMike Tipton int pos = *ppos; 106186b54881SMike Tipton int r; 106286b54881SMike Tipton 106386b54881SMike Tipton r = debugfs_file_get(dentry); 106486b54881SMike Tipton if (unlikely(r)) 106586b54881SMike Tipton return r; 106686b54881SMike Tipton 106786b54881SMike Tipton old = *(char **)file->private_data; 106886b54881SMike Tipton 106986b54881SMike Tipton /* only allow strict concatenation */ 107086b54881SMike Tipton r = -EINVAL; 107186b54881SMike Tipton if (pos && pos != strlen(old)) 107286b54881SMike Tipton goto error; 107386b54881SMike Tipton 107486b54881SMike Tipton r = -E2BIG; 107586b54881SMike Tipton if (pos + count + 1 > PAGE_SIZE) 107686b54881SMike Tipton goto error; 107786b54881SMike Tipton 107886b54881SMike Tipton r = -ENOMEM; 107986b54881SMike Tipton new = kmalloc(pos + count + 1, GFP_KERNEL); 108086b54881SMike Tipton if (!new) 108186b54881SMike Tipton goto error; 108286b54881SMike Tipton 108386b54881SMike Tipton if (pos) 108486b54881SMike Tipton memcpy(new, old, pos); 108586b54881SMike Tipton 108686b54881SMike Tipton r = -EFAULT; 108786b54881SMike Tipton if (copy_from_user(new + pos, user_buf, count)) 108886b54881SMike Tipton goto error; 108986b54881SMike Tipton 109086b54881SMike Tipton new[pos + count] = '\0'; 109186b54881SMike Tipton strim(new); 109286b54881SMike Tipton 10937360a48bSMike Tipton rcu_assign_pointer(*(char __rcu **)file->private_data, new); 109486b54881SMike Tipton synchronize_rcu(); 109586b54881SMike Tipton kfree(old); 109686b54881SMike Tipton 109786b54881SMike Tipton debugfs_file_put(dentry); 109886b54881SMike Tipton return count; 109986b54881SMike Tipton 110086b54881SMike Tipton error: 110186b54881SMike Tipton kfree(new); 110286b54881SMike Tipton debugfs_file_put(dentry); 110386b54881SMike Tipton return r; 11049af0440eSPeter Zijlstra } 11059af0440eSPeter Zijlstra 11069af0440eSPeter Zijlstra static const struct file_operations fops_str = { 11079af0440eSPeter Zijlstra .read = debugfs_read_file_str, 11089af0440eSPeter Zijlstra .write = debugfs_write_file_str, 11099af0440eSPeter Zijlstra .open = simple_open, 11109af0440eSPeter Zijlstra .llseek = default_llseek, 11119af0440eSPeter Zijlstra }; 11129af0440eSPeter Zijlstra 11139af0440eSPeter Zijlstra static const struct file_operations fops_str_ro = { 11149af0440eSPeter Zijlstra .read = debugfs_read_file_str, 11159af0440eSPeter Zijlstra .open = simple_open, 11169af0440eSPeter Zijlstra .llseek = default_llseek, 11179af0440eSPeter Zijlstra }; 11189af0440eSPeter Zijlstra 11199af0440eSPeter Zijlstra static const struct file_operations fops_str_wo = { 11209af0440eSPeter Zijlstra .write = debugfs_write_file_str, 11219af0440eSPeter Zijlstra .open = simple_open, 11229af0440eSPeter Zijlstra .llseek = default_llseek, 11239af0440eSPeter Zijlstra }; 11249af0440eSPeter Zijlstra 11259af0440eSPeter Zijlstra /** 11269af0440eSPeter Zijlstra * debugfs_create_str - create a debugfs file that is used to read and write a string value 11279af0440eSPeter Zijlstra * @name: a pointer to a string containing the name of the file to create. 11289af0440eSPeter Zijlstra * @mode: the permission that the file should have 11299af0440eSPeter Zijlstra * @parent: a pointer to the parent dentry for this file. This should be a 11309af0440eSPeter Zijlstra * directory dentry if set. If this parameter is %NULL, then the 11319af0440eSPeter Zijlstra * file will be created in the root of the debugfs filesystem. 11329af0440eSPeter Zijlstra * @value: a pointer to the variable that the file should read to and write 11339af0440eSPeter Zijlstra * from. 11349af0440eSPeter Zijlstra * 11359af0440eSPeter Zijlstra * This function creates a file in debugfs with the given name that 11369af0440eSPeter Zijlstra * contains the value of the variable @value. If the @mode variable is so 11379af0440eSPeter Zijlstra * set, it can be read from, and written to. 11389af0440eSPeter Zijlstra */ 11399af0440eSPeter Zijlstra void debugfs_create_str(const char *name, umode_t mode, 11409af0440eSPeter Zijlstra struct dentry *parent, char **value) 11419af0440eSPeter Zijlstra { 11429af0440eSPeter Zijlstra debugfs_create_mode_unsafe(name, mode, parent, value, &fops_str, 11439af0440eSPeter Zijlstra &fops_str_ro, &fops_str_wo); 11449af0440eSPeter Zijlstra } 11459af0440eSPeter Zijlstra 1146dd308bc3SMichael Ellerman static ssize_t read_file_blob(struct file *file, char __user *user_buf, 1147dd308bc3SMichael Ellerman size_t count, loff_t *ppos) 1148dd308bc3SMichael Ellerman { 1149dd308bc3SMichael Ellerman struct debugfs_blob_wrapper *blob = file->private_data; 115069d29f9eSNicolai Stange struct dentry *dentry = F_DENTRY(file); 115183b711cbSNicolai Stange ssize_t r; 115283b711cbSNicolai Stange 115369d29f9eSNicolai Stange r = debugfs_file_get(dentry); 115469d29f9eSNicolai Stange if (unlikely(r)) 115569d29f9eSNicolai Stange return r; 115683b711cbSNicolai Stange r = simple_read_from_buffer(user_buf, count, ppos, blob->data, 1157dd308bc3SMichael Ellerman blob->size); 115869d29f9eSNicolai Stange debugfs_file_put(dentry); 115983b711cbSNicolai Stange return r; 1160dd308bc3SMichael Ellerman } 1161dd308bc3SMichael Ellerman 116271cd3c63SAvadhut Naik static ssize_t write_file_blob(struct file *file, const char __user *user_buf, 116371cd3c63SAvadhut Naik size_t count, loff_t *ppos) 116471cd3c63SAvadhut Naik { 116571cd3c63SAvadhut Naik struct debugfs_blob_wrapper *blob = file->private_data; 116671cd3c63SAvadhut Naik struct dentry *dentry = F_DENTRY(file); 116771cd3c63SAvadhut Naik ssize_t r; 116871cd3c63SAvadhut Naik 116971cd3c63SAvadhut Naik r = debugfs_file_get(dentry); 117071cd3c63SAvadhut Naik if (unlikely(r)) 117171cd3c63SAvadhut Naik return r; 117271cd3c63SAvadhut Naik r = simple_write_to_buffer(blob->data, blob->size, ppos, user_buf, 117371cd3c63SAvadhut Naik count); 117471cd3c63SAvadhut Naik 117571cd3c63SAvadhut Naik debugfs_file_put(dentry); 117671cd3c63SAvadhut Naik return r; 117771cd3c63SAvadhut Naik } 117871cd3c63SAvadhut Naik 117900977a59SArjan van de Ven static const struct file_operations fops_blob = { 1180dd308bc3SMichael Ellerman .read = read_file_blob, 118171cd3c63SAvadhut Naik .write = write_file_blob, 1182234e3405SStephen Boyd .open = simple_open, 11836038f373SArnd Bergmann .llseek = default_llseek, 1184dd308bc3SMichael Ellerman }; 1185dd308bc3SMichael Ellerman 1186dd308bc3SMichael Ellerman /** 118771cd3c63SAvadhut Naik * debugfs_create_blob - create a debugfs file that is used to read and write 118871cd3c63SAvadhut Naik * a binary blob 1189dd308bc3SMichael Ellerman * @name: a pointer to a string containing the name of the file to create. 119071cd3c63SAvadhut Naik * @mode: the permission that the file should have 1191dd308bc3SMichael Ellerman * @parent: a pointer to the parent dentry for this file. This should be a 11926468b3afSRandy Dunlap * directory dentry if set. If this parameter is %NULL, then the 1193dd308bc3SMichael Ellerman * file will be created in the root of the debugfs filesystem. 1194dd308bc3SMichael Ellerman * @blob: a pointer to a struct debugfs_blob_wrapper which contains a pointer 1195dd308bc3SMichael Ellerman * to the blob data and the size of the data. 1196dd308bc3SMichael Ellerman * 1197dd308bc3SMichael Ellerman * This function creates a file in debugfs with the given name that exports 1198dd308bc3SMichael Ellerman * @blob->data as a binary blob. If the @mode variable is so set it can be 119971cd3c63SAvadhut Naik * read from and written to. 1200dd308bc3SMichael Ellerman * 1201dd308bc3SMichael Ellerman * This function will return a pointer to a dentry if it succeeds. This 1202dd308bc3SMichael Ellerman * pointer must be passed to the debugfs_remove() function when the file is 1203dd308bc3SMichael Ellerman * to be removed (no automatic cleanup happens if your module is unloaded, 1204adc92dd4SDaniel W. S. Almeida * you are responsible here.) If an error occurs, ERR_PTR(-ERROR) will be 12059abb2499SRonald Tschalär * returned. 1206dd308bc3SMichael Ellerman * 1207adc92dd4SDaniel W. S. Almeida * If debugfs is not enabled in the kernel, the value ERR_PTR(-ENODEV) will 12089abb2499SRonald Tschalär * be returned. 1209dd308bc3SMichael Ellerman */ 1210f4ae40a6SAl Viro struct dentry *debugfs_create_blob(const char *name, umode_t mode, 1211dd308bc3SMichael Ellerman struct dentry *parent, 1212dd308bc3SMichael Ellerman struct debugfs_blob_wrapper *blob) 1213dd308bc3SMichael Ellerman { 121471cd3c63SAvadhut Naik return debugfs_create_file_unsafe(name, mode & 0644, parent, blob, &fops_blob); 1215dd308bc3SMichael Ellerman } 1216dd308bc3SMichael Ellerman EXPORT_SYMBOL_GPL(debugfs_create_blob); 12171a087c6aSAlessandro Rubini 1218e05e279eSLinus Torvalds static size_t u32_format_array(char *buf, size_t bufsize, 1219e05e279eSLinus Torvalds u32 *array, int array_size) 12209fe2a701SSrivatsa Vaddagiri { 12219fe2a701SSrivatsa Vaddagiri size_t ret = 0; 12229fe2a701SSrivatsa Vaddagiri 1223e05e279eSLinus Torvalds while (--array_size >= 0) { 12249fe2a701SSrivatsa Vaddagiri size_t len; 1225e05e279eSLinus Torvalds char term = array_size ? ' ' : '\n'; 12269fe2a701SSrivatsa Vaddagiri 1227e05e279eSLinus Torvalds len = snprintf(buf, bufsize, "%u%c", *array++, term); 12289fe2a701SSrivatsa Vaddagiri ret += len; 12299fe2a701SSrivatsa Vaddagiri 12309fe2a701SSrivatsa Vaddagiri buf += len; 12319fe2a701SSrivatsa Vaddagiri bufsize -= len; 12329fe2a701SSrivatsa Vaddagiri } 12339fe2a701SSrivatsa Vaddagiri return ret; 12349fe2a701SSrivatsa Vaddagiri } 12359fe2a701SSrivatsa Vaddagiri 123636048853SDavid Rientjes static int u32_array_open(struct inode *inode, struct file *file) 12379fe2a701SSrivatsa Vaddagiri { 1238a2b992c8SJakub Kicinski struct debugfs_u32_array *data = inode->i_private; 1239a2b992c8SJakub Kicinski int size, elements = data->n_elements; 1240e05e279eSLinus Torvalds char *buf; 12419fe2a701SSrivatsa Vaddagiri 1242e05e279eSLinus Torvalds /* 1243e05e279eSLinus Torvalds * Max size: 1244e05e279eSLinus Torvalds * - 10 digits + ' '/'\n' = 11 bytes per number 1245e05e279eSLinus Torvalds * - terminating NUL character 1246e05e279eSLinus Torvalds */ 1247e05e279eSLinus Torvalds size = elements*11; 1248e05e279eSLinus Torvalds buf = kmalloc(size+1, GFP_KERNEL); 1249e05e279eSLinus Torvalds if (!buf) 125036048853SDavid Rientjes return -ENOMEM; 1251e05e279eSLinus Torvalds buf[size] = 0; 1252e05e279eSLinus Torvalds 1253e05e279eSLinus Torvalds file->private_data = buf; 1254a2b992c8SJakub Kicinski u32_format_array(buf, size, data->array, data->n_elements); 1255e05e279eSLinus Torvalds 125636048853SDavid Rientjes return nonseekable_open(inode, file); 12579fe2a701SSrivatsa Vaddagiri } 12589fe2a701SSrivatsa Vaddagiri 125936048853SDavid Rientjes static ssize_t u32_array_read(struct file *file, char __user *buf, size_t len, 126036048853SDavid Rientjes loff_t *ppos) 126136048853SDavid Rientjes { 126236048853SDavid Rientjes size_t size = strlen(file->private_data); 12639fe2a701SSrivatsa Vaddagiri 12649fe2a701SSrivatsa Vaddagiri return simple_read_from_buffer(buf, len, ppos, 12659fe2a701SSrivatsa Vaddagiri file->private_data, size); 12669fe2a701SSrivatsa Vaddagiri } 12679fe2a701SSrivatsa Vaddagiri 12689fe2a701SSrivatsa Vaddagiri static int u32_array_release(struct inode *inode, struct file *file) 12699fe2a701SSrivatsa Vaddagiri { 12709fe2a701SSrivatsa Vaddagiri kfree(file->private_data); 12719fe2a701SSrivatsa Vaddagiri 12729fe2a701SSrivatsa Vaddagiri return 0; 12739fe2a701SSrivatsa Vaddagiri } 12749fe2a701SSrivatsa Vaddagiri 12759fe2a701SSrivatsa Vaddagiri static const struct file_operations u32_array_fops = { 12769fe2a701SSrivatsa Vaddagiri .owner = THIS_MODULE, 12779fe2a701SSrivatsa Vaddagiri .open = u32_array_open, 12789fe2a701SSrivatsa Vaddagiri .release = u32_array_release, 12799fe2a701SSrivatsa Vaddagiri .read = u32_array_read, 12809fe2a701SSrivatsa Vaddagiri }; 12819fe2a701SSrivatsa Vaddagiri 12829fe2a701SSrivatsa Vaddagiri /** 12839fe2a701SSrivatsa Vaddagiri * debugfs_create_u32_array - create a debugfs file that is used to read u32 12849fe2a701SSrivatsa Vaddagiri * array. 12859fe2a701SSrivatsa Vaddagiri * @name: a pointer to a string containing the name of the file to create. 12869fe2a701SSrivatsa Vaddagiri * @mode: the permission that the file should have. 12879fe2a701SSrivatsa Vaddagiri * @parent: a pointer to the parent dentry for this file. This should be a 12889fe2a701SSrivatsa Vaddagiri * directory dentry if set. If this parameter is %NULL, then the 12899fe2a701SSrivatsa Vaddagiri * file will be created in the root of the debugfs filesystem. 1290a2b992c8SJakub Kicinski * @array: wrapper struct containing data pointer and size of the array. 12919fe2a701SSrivatsa Vaddagiri * 12929fe2a701SSrivatsa Vaddagiri * This function creates a file in debugfs with the given name that exports 12939fe2a701SSrivatsa Vaddagiri * @array as data. If the @mode variable is so set it can be read from. 12949fe2a701SSrivatsa Vaddagiri * Writing is not supported. Seek within the file is also not supported. 12959fe2a701SSrivatsa Vaddagiri * Once array is created its size can not be changed. 12969fe2a701SSrivatsa Vaddagiri */ 1297c9c2c27dSGreg Kroah-Hartman void debugfs_create_u32_array(const char *name, umode_t mode, 1298a2b992c8SJakub Kicinski struct dentry *parent, 1299a2b992c8SJakub Kicinski struct debugfs_u32_array *array) 13009fe2a701SSrivatsa Vaddagiri { 1301a2b992c8SJakub Kicinski debugfs_create_file_unsafe(name, mode, parent, array, &u32_array_fops); 13029fe2a701SSrivatsa Vaddagiri } 13039fe2a701SSrivatsa Vaddagiri EXPORT_SYMBOL_GPL(debugfs_create_u32_array); 13049fe2a701SSrivatsa Vaddagiri 13053b85e4abSHeiko Carstens #ifdef CONFIG_HAS_IOMEM 13063b85e4abSHeiko Carstens 13071a087c6aSAlessandro Rubini /* 13081a087c6aSAlessandro Rubini * The regset32 stuff is used to print 32-bit registers using the 13091a087c6aSAlessandro Rubini * seq_file utilities. We offer printing a register set in an already-opened 13101a087c6aSAlessandro Rubini * sequential file or create a debugfs file that only prints a regset32. 13111a087c6aSAlessandro Rubini */ 13121a087c6aSAlessandro Rubini 13131a087c6aSAlessandro Rubini /** 13141a087c6aSAlessandro Rubini * debugfs_print_regs32 - use seq_print to describe a set of registers 13151a087c6aSAlessandro Rubini * @s: the seq_file structure being used to generate output 13161a087c6aSAlessandro Rubini * @regs: an array if struct debugfs_reg32 structures 1317b5763accSRandy Dunlap * @nregs: the length of the above array 13181a087c6aSAlessandro Rubini * @base: the base address to be used in reading the registers 13191a087c6aSAlessandro Rubini * @prefix: a string to be prefixed to every output line 13201a087c6aSAlessandro Rubini * 13211a087c6aSAlessandro Rubini * This function outputs a text block describing the current values of 13221a087c6aSAlessandro Rubini * some 32-bit hardware registers. It is meant to be used within debugfs 13231a087c6aSAlessandro Rubini * files based on seq_file that need to show registers, intermixed with other 13241a087c6aSAlessandro Rubini * information. The prefix argument may be used to specify a leading string, 13251a087c6aSAlessandro Rubini * because some peripherals have several blocks of identical registers, 13261a087c6aSAlessandro Rubini * for example configuration of dma channels 13271a087c6aSAlessandro Rubini */ 13289761536eSJoe Perches void debugfs_print_regs32(struct seq_file *s, const struct debugfs_reg32 *regs, 13291a087c6aSAlessandro Rubini int nregs, void __iomem *base, char *prefix) 13301a087c6aSAlessandro Rubini { 13319761536eSJoe Perches int i; 13321a087c6aSAlessandro Rubini 13331a087c6aSAlessandro Rubini for (i = 0; i < nregs; i++, regs++) { 13341a087c6aSAlessandro Rubini if (prefix) 13359761536eSJoe Perches seq_printf(s, "%s", prefix); 13369761536eSJoe Perches seq_printf(s, "%s = 0x%08x\n", regs->name, 13375858441cSDan Carpenter readl(base + regs->offset)); 13389761536eSJoe Perches if (seq_has_overflowed(s)) 13399761536eSJoe Perches break; 13401a087c6aSAlessandro Rubini } 13411a087c6aSAlessandro Rubini } 13421a087c6aSAlessandro Rubini EXPORT_SYMBOL_GPL(debugfs_print_regs32); 13431a087c6aSAlessandro Rubini 134419029f3fSChenXiaoSong static int debugfs_regset32_show(struct seq_file *s, void *data) 13451a087c6aSAlessandro Rubini { 13461a087c6aSAlessandro Rubini struct debugfs_regset32 *regset = s->private; 13471a087c6aSAlessandro Rubini 134830332eeeSGeert Uytterhoeven if (regset->dev) 134930332eeeSGeert Uytterhoeven pm_runtime_get_sync(regset->dev); 135030332eeeSGeert Uytterhoeven 13511a087c6aSAlessandro Rubini debugfs_print_regs32(s, regset->regs, regset->nregs, regset->base, ""); 135230332eeeSGeert Uytterhoeven 135330332eeeSGeert Uytterhoeven if (regset->dev) 135430332eeeSGeert Uytterhoeven pm_runtime_put(regset->dev); 135530332eeeSGeert Uytterhoeven 13561a087c6aSAlessandro Rubini return 0; 13571a087c6aSAlessandro Rubini } 13581a087c6aSAlessandro Rubini 135919029f3fSChenXiaoSong DEFINE_SHOW_ATTRIBUTE(debugfs_regset32); 13601a087c6aSAlessandro Rubini 13611a087c6aSAlessandro Rubini /** 13621a087c6aSAlessandro Rubini * debugfs_create_regset32 - create a debugfs file that returns register values 13631a087c6aSAlessandro Rubini * @name: a pointer to a string containing the name of the file to create. 13641a087c6aSAlessandro Rubini * @mode: the permission that the file should have 13651a087c6aSAlessandro Rubini * @parent: a pointer to the parent dentry for this file. This should be a 13661a087c6aSAlessandro Rubini * directory dentry if set. If this parameter is %NULL, then the 13671a087c6aSAlessandro Rubini * file will be created in the root of the debugfs filesystem. 13681a087c6aSAlessandro Rubini * @regset: a pointer to a struct debugfs_regset32, which contains a pointer 13691a087c6aSAlessandro Rubini * to an array of register definitions, the array size and the base 13701a087c6aSAlessandro Rubini * address where the register bank is to be found. 13711a087c6aSAlessandro Rubini * 13721a087c6aSAlessandro Rubini * This function creates a file in debugfs with the given name that reports 13731a087c6aSAlessandro Rubini * the names and values of a set of 32-bit registers. If the @mode variable 13741a087c6aSAlessandro Rubini * is so set it can be read from. Writing is not supported. 13751a087c6aSAlessandro Rubini */ 1376ae91c925SGreg Kroah-Hartman void debugfs_create_regset32(const char *name, umode_t mode, 13771a087c6aSAlessandro Rubini struct dentry *parent, 13781a087c6aSAlessandro Rubini struct debugfs_regset32 *regset) 13791a087c6aSAlessandro Rubini { 138019029f3fSChenXiaoSong debugfs_create_file(name, mode, parent, regset, &debugfs_regset32_fops); 13811a087c6aSAlessandro Rubini } 13821a087c6aSAlessandro Rubini EXPORT_SYMBOL_GPL(debugfs_create_regset32); 13833b85e4abSHeiko Carstens 13843b85e4abSHeiko Carstens #endif /* CONFIG_HAS_IOMEM */ 138598210b7fSArend van Spriel 138698210b7fSArend van Spriel struct debugfs_devm_entry { 138798210b7fSArend van Spriel int (*read)(struct seq_file *seq, void *data); 138898210b7fSArend van Spriel struct device *dev; 138998210b7fSArend van Spriel }; 139098210b7fSArend van Spriel 139198210b7fSArend van Spriel static int debugfs_devm_entry_open(struct inode *inode, struct file *f) 139298210b7fSArend van Spriel { 139398210b7fSArend van Spriel struct debugfs_devm_entry *entry = inode->i_private; 139498210b7fSArend van Spriel 139598210b7fSArend van Spriel return single_open(f, entry->read, entry->dev); 139698210b7fSArend van Spriel } 139798210b7fSArend van Spriel 139898210b7fSArend van Spriel static const struct file_operations debugfs_devm_entry_ops = { 139998210b7fSArend van Spriel .owner = THIS_MODULE, 140098210b7fSArend van Spriel .open = debugfs_devm_entry_open, 140198210b7fSArend van Spriel .release = single_release, 140298210b7fSArend van Spriel .read = seq_read, 140398210b7fSArend van Spriel .llseek = seq_lseek 140498210b7fSArend van Spriel }; 140598210b7fSArend van Spriel 140698210b7fSArend van Spriel /** 140798210b7fSArend van Spriel * debugfs_create_devm_seqfile - create a debugfs file that is bound to device. 140898210b7fSArend van Spriel * 140998210b7fSArend van Spriel * @dev: device related to this debugfs file. 141098210b7fSArend van Spriel * @name: name of the debugfs file. 141198210b7fSArend van Spriel * @parent: a pointer to the parent dentry for this file. This should be a 141298210b7fSArend van Spriel * directory dentry if set. If this parameter is %NULL, then the 141398210b7fSArend van Spriel * file will be created in the root of the debugfs filesystem. 141498210b7fSArend van Spriel * @read_fn: function pointer called to print the seq_file content. 141598210b7fSArend van Spriel */ 14160d519cbfSGreg Kroah-Hartman void debugfs_create_devm_seqfile(struct device *dev, const char *name, 141798210b7fSArend van Spriel struct dentry *parent, 14180d519cbfSGreg Kroah-Hartman int (*read_fn)(struct seq_file *s, void *data)) 141998210b7fSArend van Spriel { 142098210b7fSArend van Spriel struct debugfs_devm_entry *entry; 142198210b7fSArend van Spriel 142298210b7fSArend van Spriel if (IS_ERR(parent)) 14230d519cbfSGreg Kroah-Hartman return; 142498210b7fSArend van Spriel 142598210b7fSArend van Spriel entry = devm_kzalloc(dev, sizeof(*entry), GFP_KERNEL); 142698210b7fSArend van Spriel if (!entry) 14270d519cbfSGreg Kroah-Hartman return; 142898210b7fSArend van Spriel 142998210b7fSArend van Spriel entry->read = read_fn; 143098210b7fSArend van Spriel entry->dev = dev; 143198210b7fSArend van Spriel 14320d519cbfSGreg Kroah-Hartman debugfs_create_file(name, S_IRUGO, parent, entry, 143398210b7fSArend van Spriel &debugfs_devm_entry_ops); 143498210b7fSArend van Spriel } 143598210b7fSArend van Spriel EXPORT_SYMBOL_GPL(debugfs_create_devm_seqfile); 1436