.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * fs/kernfs/file.c - kernfs file implementation |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (c) 2001-3 Patrick Mochel |
---|
5 | 6 | * Copyright (c) 2007 SUSE Linux Products GmbH |
---|
6 | 7 | * Copyright (c) 2007, 2013 Tejun Heo <tj@kernel.org> |
---|
7 | | - * |
---|
8 | | - * This file is released under the GPLv2. |
---|
9 | 8 | */ |
---|
10 | 9 | |
---|
11 | 10 | #include <linux/fs.h> |
---|
.. | .. |
---|
15 | 14 | #include <linux/pagemap.h> |
---|
16 | 15 | #include <linux/sched/mm.h> |
---|
17 | 16 | #include <linux/fsnotify.h> |
---|
| 17 | +#include <linux/uio.h> |
---|
18 | 18 | |
---|
19 | 19 | #include "kernfs-internal.h" |
---|
20 | 20 | |
---|
.. | .. |
---|
181 | 181 | * it difficult to use seq_file. Implement simplistic custom buffering for |
---|
182 | 182 | * bin files. |
---|
183 | 183 | */ |
---|
184 | | -static ssize_t kernfs_file_direct_read(struct kernfs_open_file *of, |
---|
185 | | - char __user *user_buf, size_t count, |
---|
186 | | - loff_t *ppos) |
---|
| 184 | +static ssize_t kernfs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter) |
---|
187 | 185 | { |
---|
188 | | - ssize_t len = min_t(size_t, count, PAGE_SIZE); |
---|
| 186 | + struct kernfs_open_file *of = kernfs_of(iocb->ki_filp); |
---|
| 187 | + ssize_t len = min_t(size_t, iov_iter_count(iter), PAGE_SIZE); |
---|
189 | 188 | const struct kernfs_ops *ops; |
---|
190 | 189 | char *buf; |
---|
191 | 190 | |
---|
.. | .. |
---|
211 | 210 | of->event = atomic_read(&of->kn->attr.open->event); |
---|
212 | 211 | ops = kernfs_ops(of->kn); |
---|
213 | 212 | if (ops->read) |
---|
214 | | - len = ops->read(of, buf, len, *ppos); |
---|
| 213 | + len = ops->read(of, buf, len, iocb->ki_pos); |
---|
215 | 214 | else |
---|
216 | 215 | len = -EINVAL; |
---|
217 | 216 | |
---|
.. | .. |
---|
221 | 220 | if (len < 0) |
---|
222 | 221 | goto out_free; |
---|
223 | 222 | |
---|
224 | | - if (copy_to_user(user_buf, buf, len)) { |
---|
| 223 | + if (copy_to_iter(buf, len, iter) != len) { |
---|
225 | 224 | len = -EFAULT; |
---|
226 | 225 | goto out_free; |
---|
227 | 226 | } |
---|
228 | 227 | |
---|
229 | | - *ppos += len; |
---|
| 228 | + iocb->ki_pos += len; |
---|
230 | 229 | |
---|
231 | 230 | out_free: |
---|
232 | 231 | if (buf == of->prealloc_buf) |
---|
.. | .. |
---|
236 | 235 | return len; |
---|
237 | 236 | } |
---|
238 | 237 | |
---|
239 | | -/** |
---|
240 | | - * kernfs_fop_read - kernfs vfs read callback |
---|
241 | | - * @file: file pointer |
---|
242 | | - * @user_buf: data to write |
---|
243 | | - * @count: number of bytes |
---|
244 | | - * @ppos: starting offset |
---|
245 | | - */ |
---|
246 | | -static ssize_t kernfs_fop_read(struct file *file, char __user *user_buf, |
---|
247 | | - size_t count, loff_t *ppos) |
---|
| 238 | +static ssize_t kernfs_fop_read_iter(struct kiocb *iocb, struct iov_iter *iter) |
---|
248 | 239 | { |
---|
249 | | - struct kernfs_open_file *of = kernfs_of(file); |
---|
250 | | - |
---|
251 | | - if (of->kn->flags & KERNFS_HAS_SEQ_SHOW) |
---|
252 | | - return seq_read(file, user_buf, count, ppos); |
---|
253 | | - else |
---|
254 | | - return kernfs_file_direct_read(of, user_buf, count, ppos); |
---|
| 240 | + if (kernfs_of(iocb->ki_filp)->kn->flags & KERNFS_HAS_SEQ_SHOW) |
---|
| 241 | + return seq_read_iter(iocb, iter); |
---|
| 242 | + return kernfs_file_read_iter(iocb, iter); |
---|
255 | 243 | } |
---|
256 | 244 | |
---|
257 | | -/** |
---|
258 | | - * kernfs_fop_write - kernfs vfs write callback |
---|
259 | | - * @file: file pointer |
---|
260 | | - * @user_buf: data to write |
---|
261 | | - * @count: number of bytes |
---|
262 | | - * @ppos: starting offset |
---|
263 | | - * |
---|
| 245 | +/* |
---|
264 | 246 | * Copy data in from userland and pass it to the matching kernfs write |
---|
265 | 247 | * operation. |
---|
266 | 248 | * |
---|
.. | .. |
---|
270 | 252 | * modify only the the value you're changing, then write entire buffer |
---|
271 | 253 | * back. |
---|
272 | 254 | */ |
---|
273 | | -static ssize_t kernfs_fop_write(struct file *file, const char __user *user_buf, |
---|
274 | | - size_t count, loff_t *ppos) |
---|
| 255 | +static ssize_t kernfs_fop_write_iter(struct kiocb *iocb, struct iov_iter *iter) |
---|
275 | 256 | { |
---|
276 | | - struct kernfs_open_file *of = kernfs_of(file); |
---|
| 257 | + struct kernfs_open_file *of = kernfs_of(iocb->ki_filp); |
---|
| 258 | + ssize_t len = iov_iter_count(iter); |
---|
277 | 259 | const struct kernfs_ops *ops; |
---|
278 | | - ssize_t len; |
---|
279 | 260 | char *buf; |
---|
280 | 261 | |
---|
281 | 262 | if (of->atomic_write_len) { |
---|
282 | | - len = count; |
---|
283 | 263 | if (len > of->atomic_write_len) |
---|
284 | 264 | return -E2BIG; |
---|
285 | 265 | } else { |
---|
286 | | - len = min_t(size_t, count, PAGE_SIZE); |
---|
| 266 | + len = min_t(size_t, len, PAGE_SIZE); |
---|
287 | 267 | } |
---|
288 | 268 | |
---|
289 | 269 | buf = of->prealloc_buf; |
---|
.. | .. |
---|
294 | 274 | if (!buf) |
---|
295 | 275 | return -ENOMEM; |
---|
296 | 276 | |
---|
297 | | - if (copy_from_user(buf, user_buf, len)) { |
---|
| 277 | + if (copy_from_iter(buf, len, iter) != len) { |
---|
298 | 278 | len = -EFAULT; |
---|
299 | 279 | goto out_free; |
---|
300 | 280 | } |
---|
.. | .. |
---|
313 | 293 | |
---|
314 | 294 | ops = kernfs_ops(of->kn); |
---|
315 | 295 | if (ops->write) |
---|
316 | | - len = ops->write(of, buf, len, *ppos); |
---|
| 296 | + len = ops->write(of, buf, len, iocb->ki_pos); |
---|
317 | 297 | else |
---|
318 | 298 | len = -EINVAL; |
---|
319 | 299 | |
---|
.. | .. |
---|
321 | 301 | mutex_unlock(&of->mutex); |
---|
322 | 302 | |
---|
323 | 303 | if (len > 0) |
---|
324 | | - *ppos += len; |
---|
| 304 | + iocb->ki_pos += len; |
---|
325 | 305 | |
---|
326 | 306 | out_free: |
---|
327 | 307 | if (buf == of->prealloc_buf) |
---|
.. | .. |
---|
653 | 633 | * The following is done to give a different lockdep key to |
---|
654 | 634 | * @of->mutex for files which implement mmap. This is a rather |
---|
655 | 635 | * crude way to avoid false positive lockdep warning around |
---|
656 | | - * mm->mmap_sem - mmap nests @of->mutex under mm->mmap_sem and |
---|
| 636 | + * mm->mmap_lock - mmap nests @of->mutex under mm->mmap_lock and |
---|
657 | 637 | * reading /sys/block/sda/trace/act_mask grabs sr_mutex, under |
---|
658 | | - * which mm->mmap_sem nests, while holding @of->mutex. As each |
---|
| 638 | + * which mm->mmap_lock nests, while holding @of->mutex. As each |
---|
659 | 639 | * open file has a separate mutex, it's okay as long as those don't |
---|
660 | 640 | * happen on the same file. At this point, we can't easily give |
---|
661 | 641 | * each file a separate locking class. Let's differentiate on |
---|
.. | .. |
---|
674 | 654 | |
---|
675 | 655 | /* |
---|
676 | 656 | * Write path needs to atomic_write_len outside active reference. |
---|
677 | | - * Cache it in open_file. See kernfs_fop_write() for details. |
---|
| 657 | + * Cache it in open_file. See kernfs_fop_write_iter() for details. |
---|
678 | 658 | */ |
---|
679 | 659 | of->atomic_write_len = ops->atomic_write_len; |
---|
680 | 660 | |
---|
.. | .. |
---|
884 | 864 | |
---|
885 | 865 | list_for_each_entry(info, &kernfs_root(kn)->supers, node) { |
---|
886 | 866 | struct kernfs_node *parent; |
---|
| 867 | + struct inode *p_inode = NULL; |
---|
887 | 868 | struct inode *inode; |
---|
| 869 | + struct qstr name; |
---|
888 | 870 | |
---|
889 | 871 | /* |
---|
890 | 872 | * We want fsnotify_modify() on @kn but as the |
---|
.. | .. |
---|
892 | 874 | * have the matching @file available. Look up the inodes |
---|
893 | 875 | * and generate the events manually. |
---|
894 | 876 | */ |
---|
895 | | - inode = ilookup(info->sb, kn->id.ino); |
---|
| 877 | + inode = ilookup(info->sb, kernfs_ino(kn)); |
---|
896 | 878 | if (!inode) |
---|
897 | 879 | continue; |
---|
898 | 880 | |
---|
| 881 | + name = (struct qstr)QSTR_INIT(kn->name, strlen(kn->name)); |
---|
899 | 882 | parent = kernfs_get_parent(kn); |
---|
900 | 883 | if (parent) { |
---|
901 | | - struct inode *p_inode; |
---|
902 | | - |
---|
903 | | - p_inode = ilookup(info->sb, parent->id.ino); |
---|
| 884 | + p_inode = ilookup(info->sb, kernfs_ino(parent)); |
---|
904 | 885 | if (p_inode) { |
---|
905 | | - fsnotify(p_inode, FS_MODIFY | FS_EVENT_ON_CHILD, |
---|
906 | | - inode, FSNOTIFY_EVENT_INODE, kn->name, 0); |
---|
| 886 | + fsnotify(FS_MODIFY | FS_EVENT_ON_CHILD, |
---|
| 887 | + inode, FSNOTIFY_EVENT_INODE, |
---|
| 888 | + p_inode, &name, inode, 0); |
---|
907 | 889 | iput(p_inode); |
---|
908 | 890 | } |
---|
909 | 891 | |
---|
910 | 892 | kernfs_put(parent); |
---|
911 | 893 | } |
---|
912 | 894 | |
---|
913 | | - fsnotify(inode, FS_MODIFY, inode, FSNOTIFY_EVENT_INODE, |
---|
914 | | - kn->name, 0); |
---|
| 895 | + if (!p_inode) |
---|
| 896 | + fsnotify_inode(inode, FS_MODIFY); |
---|
| 897 | + |
---|
915 | 898 | iput(inode); |
---|
916 | 899 | } |
---|
917 | 900 | |
---|
.. | .. |
---|
958 | 941 | EXPORT_SYMBOL_GPL(kernfs_notify); |
---|
959 | 942 | |
---|
960 | 943 | const struct file_operations kernfs_file_fops = { |
---|
961 | | - .read = kernfs_fop_read, |
---|
962 | | - .write = kernfs_fop_write, |
---|
| 944 | + .read_iter = kernfs_fop_read_iter, |
---|
| 945 | + .write_iter = kernfs_fop_write_iter, |
---|
963 | 946 | .llseek = generic_file_llseek, |
---|
964 | 947 | .mmap = kernfs_fop_mmap, |
---|
965 | 948 | .open = kernfs_fop_open, |
---|
966 | 949 | .release = kernfs_fop_release, |
---|
967 | 950 | .poll = kernfs_fop_poll, |
---|
968 | 951 | .fsync = noop_fsync, |
---|
| 952 | + .splice_read = generic_file_splice_read, |
---|
| 953 | + .splice_write = iter_file_splice_write, |
---|
969 | 954 | }; |
---|
970 | 955 | |
---|
971 | 956 | /** |
---|
.. | .. |
---|
1009 | 994 | |
---|
1010 | 995 | #ifdef CONFIG_DEBUG_LOCK_ALLOC |
---|
1011 | 996 | if (key) { |
---|
1012 | | - lockdep_init_map(&kn->dep_map, "kn->count", key, 0); |
---|
| 997 | + lockdep_init_map(&kn->dep_map, "kn->active", key, 0); |
---|
1013 | 998 | kn->flags |= KERNFS_LOCKDEP; |
---|
1014 | 999 | } |
---|
1015 | 1000 | #endif |
---|