| From | Jens Axboe <> | Subject | [PATCH 039/437] libfs: switch to read iter and add copy helpers | Date | Thu, 11 Apr 2024 09:12:59 -0600 |
| |
Signed-off-by: Jens Axboe <axboe@kernel.dk> --- fs/debugfs/file.c | 44 +++++++++++++++++++++ fs/libfs.c | 87 +++++++++++++++++++++++++++++++++++++++++ include/linux/debugfs.h | 25 +++++++++++- include/linux/fs.h | 7 +++- 4 files changed, 159 insertions(+), 4 deletions(-)
diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index c6ff9084bc0f..31749d8c35f8 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -468,6 +468,20 @@ ssize_t debugfs_attr_read(struct file *file, char __user *buf, } EXPORT_SYMBOL_GPL(debugfs_attr_read); +ssize_t debugfs_attr_read_iter(struct kiocb *iocb, struct iov_iter *to) +{ + struct dentry *dentry = F_DENTRY(iocb->ki_filp); + ssize_t ret; + + ret = debugfs_file_get(dentry); + if (unlikely(ret)) + return ret; + ret = simple_attr_read_iter(iocb, to); + debugfs_file_put(dentry); + return ret; +} +EXPORT_SYMBOL_GPL(debugfs_attr_read_iter); + static ssize_t debugfs_attr_write_xsigned(struct file *file, const char __user *buf, size_t len, loff_t *ppos, bool is_signed) { @@ -499,6 +513,36 @@ ssize_t debugfs_attr_write_signed(struct file *file, const char __user *buf, } EXPORT_SYMBOL_GPL(debugfs_attr_write_signed); +static ssize_t debugfs_attr_write_iter_xsigned(struct kiocb *iocb, + struct iov_iter *from, + bool is_signed) +{ + struct dentry *dentry = F_DENTRY(iocb->ki_filp); + ssize_t ret; + + ret = debugfs_file_get(dentry); + if (unlikely(ret)) + return ret; + if (is_signed) + ret = simple_attr_write_iter_signed(iocb, from); + else + ret = simple_attr_write_iter(iocb, from); + debugfs_file_put(dentry); + return ret; +} + +ssize_t debugfs_attr_write_iter(struct kiocb *iocb, struct iov_iter *from) +{ + return debugfs_attr_write_iter_xsigned(iocb, from, false); +} +EXPORT_SYMBOL_GPL(debugfs_attr_write_iter); + +ssize_t debugfs_attr_write_iter_signed(struct kiocb *iocb, struct iov_iter *from) +{ + return debugfs_attr_write_iter_xsigned(iocb, from, true); +} +EXPORT_SYMBOL_GPL(debugfs_attr_write_iter_signed); + static struct dentry *debugfs_create_mode_unsafe(const char *name, umode_t mode, struct dentry *parent, void *value, const struct file_operations *fops, diff --git a/fs/libfs.c b/fs/libfs.c index 074cfacc377f..90f79113e48b 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -1365,6 +1365,93 @@ ssize_t simple_attr_read(struct file *file, char __user *buf, } EXPORT_SYMBOL_GPL(simple_attr_read); +/* read from the buffer that is filled with the get function */ +ssize_t simple_attr_read_iter(struct kiocb *iocb, struct iov_iter *to) +{ + struct simple_attr *attr; + size_t size; + ssize_t ret; + + attr = iocb->ki_filp->private_data; + + if (!attr->get) + return -EACCES; + + ret = mutex_lock_interruptible(&attr->mutex); + if (ret) + return ret; + + if (iocb->ki_pos && attr->get_buf[0]) { + /* continued read */ + size = strlen(attr->get_buf); + } else { + /* first read */ + u64 val; + ret = attr->get(attr->data, &val); + if (ret) + goto out; + + size = scnprintf(attr->get_buf, sizeof(attr->get_buf), + attr->fmt, (unsigned long long)val); + } + + ret = simple_copy_to_iter(attr->get_buf, &iocb->ki_pos, size, to); +out: + mutex_unlock(&attr->mutex); + return ret; +} +EXPORT_SYMBOL_GPL(simple_attr_read_iter); + +static ssize_t __simple_write_iter(struct kiocb *iocb, struct iov_iter *from, + bool is_signed) +{ + struct simple_attr *attr; + unsigned long long val; + size_t len = iov_iter_count(from); + size_t size; + ssize_t ret; + + attr = iocb->ki_filp->private_data; + if (!attr->set) + return -EACCES; + + ret = mutex_lock_interruptible(&attr->mutex); + if (ret) + return ret; + + ret = -EFAULT; + size = min(sizeof(attr->set_buf) - 1, len); + if (!copy_from_iter(attr->set_buf, size, from)) + goto out; + + attr->set_buf[size] = '\0'; + if (is_signed) + ret = kstrtoll(attr->set_buf, 0, &val); + else + ret = kstrtoull(attr->set_buf, 0, &val); + if (ret) + goto out; + ret = attr->set(attr->data, val); + if (ret == 0) + ret = len; /* on success, claim we got the whole input */ +out: + mutex_unlock(&attr->mutex); + return ret; +} + +ssize_t simple_attr_write_iter(struct kiocb *iocb, struct iov_iter *from) +{ + return __simple_write_iter(iocb, from, false); +} +EXPORT_SYMBOL_GPL(simple_attr_write_iter); + +ssize_t simple_attr_write_iter_signed(struct kiocb *iocb, struct iov_iter *from) + +{ + return __simple_write_iter(iocb, from, true); +} +EXPORT_SYMBOL_GPL(simple_attr_write_iter_signed); + /* interpret the buffer as a number to call the set function with */ static ssize_t simple_attr_write_xsigned(struct file *file, const char __user *buf, size_t len, loff_t *ppos, bool is_signed) diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h index ad417d079ec9..c6d189059d3d 100644 --- a/include/linux/debugfs.h +++ b/include/linux/debugfs.h @@ -55,8 +55,8 @@ static const struct file_operations __fops = { \ .owner = THIS_MODULE, \ .open = __fops ## _open, \ .release = simple_attr_release, \ - .read = debugfs_attr_read, \ - .write = (__is_signed) ? debugfs_attr_write_signed : debugfs_attr_write, \ + .read_iter = debugfs_attr_read_iter, \ + .write_iter= (__is_signed) ? debugfs_attr_write_iter_signed : debugfs_attr_write_iter, \ .llseek = no_llseek, \ } @@ -106,10 +106,13 @@ void debugfs_file_put(struct dentry *dentry); ssize_t debugfs_attr_read(struct file *file, char __user *buf, size_t len, loff_t *ppos); +ssize_t debugfs_attr_read_iter(struct kiocb *iocb, struct iov_iter *to); ssize_t debugfs_attr_write(struct file *file, const char __user *buf, size_t len, loff_t *ppos); +ssize_t debugfs_attr_write_iter(struct kiocb *iocb, struct iov_iter *from); ssize_t debugfs_attr_write_signed(struct file *file, const char __user *buf, size_t len, loff_t *ppos); +ssize_t debugfs_attr_write_iter_signed(struct kiocb *iocb, struct iov_iter *from); struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry, struct dentry *new_dir, const char *new_name); @@ -271,6 +274,12 @@ static inline ssize_t debugfs_attr_read(struct file *file, char __user *buf, return -ENODEV; } +static inline ssize_t debugfs_attr_read_iter(struct kiocb *iocb, + struct iov_iter *to) +{ + return -ENODEV; +} + static inline ssize_t debugfs_attr_write(struct file *file, const char __user *buf, size_t len, loff_t *ppos) @@ -278,6 +287,12 @@ static inline ssize_t debugfs_attr_write(struct file *file, return -ENODEV; } +static inline ssize_t debugfs_attr_write_iter(struct kiocb *iocb, + struct iov_iter *from) +{ + return -ENODEV; +} + static inline ssize_t debugfs_attr_write_signed(struct file *file, const char __user *buf, size_t len, loff_t *ppos) @@ -285,6 +300,12 @@ static inline ssize_t debugfs_attr_write_signed(struct file *file, return -ENODEV; } +static inline ssize_t debugfs_attr_write_iter_signed(struct kiocb *iocb, + struct iov_iter *from) +{ + return -ENODEV; +} + static inline struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry, struct dentry *new_dir, char *new_name) { diff --git a/include/linux/fs.h b/include/linux/fs.h index 5806cea7a3ac..d15a79020efa 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -3528,8 +3528,8 @@ static const struct file_operations __fops = { \ .owner = THIS_MODULE, \ .open = __fops ## _open, \ .release = simple_attr_release, \ - .read = simple_attr_read, \ - .write = (__is_signed) ? simple_attr_write_signed : simple_attr_write, \ + .read_iter = simple_attr_read_iter, \ + .write_iter = (__is_signed) ? simple_attr_write_iter_signed : simple_attr_write_iter, \ .llseek = generic_file_llseek, \ } @@ -3555,6 +3555,9 @@ ssize_t simple_attr_write(struct file *file, const char __user *buf, size_t len, loff_t *ppos); ssize_t simple_attr_write_signed(struct file *file, const char __user *buf, size_t len, loff_t *ppos); +ssize_t simple_attr_read_iter(struct kiocb *iocb, struct iov_iter *to); +ssize_t simple_attr_write_iter(struct kiocb *iocb, struct iov_iter *from); +ssize_t simple_attr_write_iter_signed(struct kiocb *iocb, struct iov_iter *from); struct ctl_table; int __init list_bdev_fs_names(char *buf, size_t size); -- 2.43.0
|