From: Greg Kroah-Hartman Date: Sun, 9 Jun 2019 16:39:25 +0000 (+0200) Subject: 4.14-stable patches X-Git-Tag: v5.1.9~11 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8258bdcc21c3255ba547d91b20980ba679c5d158;p=thirdparty%2Fkernel%2Fstable-queue.git 4.14-stable patches added patches: fs-stream_open-opener-for-stream-like-files-so-that-read-and-write-can-run-simultaneously-without-deadlock.patch fuse-add-fopen_stream-to-use-stream_open.patch qmi_wwan-add-quirk-for-quectel-dynamic-config.patch --- diff --git a/queue-4.14/fs-stream_open-opener-for-stream-like-files-so-that-read-and-write-can-run-simultaneously-without-deadlock.patch b/queue-4.14/fs-stream_open-opener-for-stream-like-files-so-that-read-and-write-can-run-simultaneously-without-deadlock.patch new file mode 100644 index 00000000000..78b7b7f3447 --- /dev/null +++ b/queue-4.14/fs-stream_open-opener-for-stream-like-files-so-that-read-and-write-can-run-simultaneously-without-deadlock.patch @@ -0,0 +1,645 @@ +From 10dce8af34226d90fa56746a934f8da5dcdba3df Mon Sep 17 00:00:00 2001 +From: Kirill Smelkov +Date: Tue, 26 Mar 2019 22:20:43 +0000 +Subject: fs: stream_open - opener for stream-like files so that read and write can run simultaneously without deadlock + +From: Kirill Smelkov + +commit 10dce8af34226d90fa56746a934f8da5dcdba3df upstream. + +Commit 9c225f2655e3 ("vfs: atomic f_pos accesses as per POSIX") added +locking for file.f_pos access and in particular made concurrent read and +write not possible - now both those functions take f_pos lock for the +whole run, and so if e.g. a read is blocked waiting for data, write will +deadlock waiting for that read to complete. + +This caused regression for stream-like files where previously read and +write could run simultaneously, but after that patch could not do so +anymore. See e.g. commit 581d21a2d02a ("xenbus: fix deadlock on writes +to /proc/xen/xenbus") which fixes such regression for particular case of +/proc/xen/xenbus. + +The patch that added f_pos lock in 2014 did so to guarantee POSIX thread +safety for read/write/lseek and added the locking to file descriptors of +all regular files. In 2014 that thread-safety problem was not new as it +was already discussed earlier in 2006. + +However even though 2006'th version of Linus's patch was adding f_pos +locking "only for files that are marked seekable with FMODE_LSEEK (thus +avoiding the stream-like objects like pipes and sockets)", the 2014 +version - the one that actually made it into the tree as 9c225f2655e3 - +is doing so irregardless of whether a file is seekable or not. + +See + + https://lore.kernel.org/lkml/53022DB1.4070805@gmail.com/ + https://lwn.net/Articles/180387 + https://lwn.net/Articles/180396 + +for historic context. + +The reason that it did so is, probably, that there are many files that +are marked non-seekable, but e.g. their read implementation actually +depends on knowing current position to correctly handle the read. Some +examples: + + kernel/power/user.c snapshot_read + fs/debugfs/file.c u32_array_read + fs/fuse/control.c fuse_conn_waiting_read + ... + drivers/hwmon/asus_atk0110.c atk_debugfs_ggrp_read + arch/s390/hypfs/inode.c hypfs_read_iter + ... + +Despite that, many nonseekable_open users implement read and write with +pure stream semantics - they don't depend on passed ppos at all. And for +those cases where read could wait for something inside, it creates a +situation similar to xenbus - the write could be never made to go until +read is done, and read is waiting for some, potentially external, event, +for potentially unbounded time -> deadlock. + +Besides xenbus, there are 14 such places in the kernel that I've found +with semantic patch (see below): + + drivers/xen/evtchn.c:667:8-24: ERROR: evtchn_fops: .read() can deadlock .write() + drivers/isdn/capi/capi.c:963:8-24: ERROR: capi_fops: .read() can deadlock .write() + drivers/input/evdev.c:527:1-17: ERROR: evdev_fops: .read() can deadlock .write() + drivers/char/pcmcia/cm4000_cs.c:1685:7-23: ERROR: cm4000_fops: .read() can deadlock .write() + net/rfkill/core.c:1146:8-24: ERROR: rfkill_fops: .read() can deadlock .write() + drivers/s390/char/fs3270.c:488:1-17: ERROR: fs3270_fops: .read() can deadlock .write() + drivers/usb/misc/ldusb.c:310:1-17: ERROR: ld_usb_fops: .read() can deadlock .write() + drivers/hid/uhid.c:635:1-17: ERROR: uhid_fops: .read() can deadlock .write() + net/batman-adv/icmp_socket.c:80:1-17: ERROR: batadv_fops: .read() can deadlock .write() + drivers/media/rc/lirc_dev.c:198:1-17: ERROR: lirc_fops: .read() can deadlock .write() + drivers/leds/uleds.c:77:1-17: ERROR: uleds_fops: .read() can deadlock .write() + drivers/input/misc/uinput.c:400:1-17: ERROR: uinput_fops: .read() can deadlock .write() + drivers/infiniband/core/user_mad.c:985:7-23: ERROR: umad_fops: .read() can deadlock .write() + drivers/gnss/core.c:45:1-17: ERROR: gnss_fops: .read() can deadlock .write() + +In addition to the cases above another regression caused by f_pos +locking is that now FUSE filesystems that implement open with +FOPEN_NONSEEKABLE flag, can no longer implement bidirectional +stream-like files - for the same reason as above e.g. read can deadlock +write locking on file.f_pos in the kernel. + +FUSE's FOPEN_NONSEEKABLE was added in 2008 in a7c1b990f715 ("fuse: +implement nonseekable open") to support OSSPD. OSSPD implements /dev/dsp +in userspace with FOPEN_NONSEEKABLE flag, with corresponding read and +write routines not depending on current position at all, and with both +read and write being potentially blocking operations: + +See + + https://github.com/libfuse/osspd + https://lwn.net/Articles/308445 + + https://github.com/libfuse/osspd/blob/14a9cff0/osspd.c#L1406 + https://github.com/libfuse/osspd/blob/14a9cff0/osspd.c#L1438-L1477 + https://github.com/libfuse/osspd/blob/14a9cff0/osspd.c#L1479-L1510 + +Corresponding libfuse example/test also describes FOPEN_NONSEEKABLE as +"somewhat pipe-like files ..." with read handler not using offset. +However that test implements only read without write and cannot exercise +the deadlock scenario: + + https://github.com/libfuse/libfuse/blob/fuse-3.4.2-3-ga1bff7d/example/poll.c#L124-L131 + https://github.com/libfuse/libfuse/blob/fuse-3.4.2-3-ga1bff7d/example/poll.c#L146-L163 + https://github.com/libfuse/libfuse/blob/fuse-3.4.2-3-ga1bff7d/example/poll.c#L209-L216 + +I've actually hit the read vs write deadlock for real while implementing +my FUSE filesystem where there is /head/watch file, for which open +creates separate bidirectional socket-like stream in between filesystem +and its user with both read and write being later performed +simultaneously. And there it is semantically not easy to split the +stream into two separate read-only and write-only channels: + + https://lab.nexedi.com/kirr/wendelin.core/blob/f13aa600/wcfs/wcfs.go#L88-169 + +Let's fix this regression. The plan is: + +1. We can't change nonseekable_open to include &~FMODE_ATOMIC_POS - + doing so would break many in-kernel nonseekable_open users which + actually use ppos in read/write handlers. + +2. Add stream_open() to kernel to open stream-like non-seekable file + descriptors. Read and write on such file descriptors would never use + nor change ppos. And with that property on stream-like files read and + write will be running without taking f_pos lock - i.e. read and write + could be running simultaneously. + +3. With semantic patch search and convert to stream_open all in-kernel + nonseekable_open users for which read and write actually do not + depend on ppos and where there is no other methods in file_operations + which assume @offset access. + +4. Add FOPEN_STREAM to fs/fuse/ and open in-kernel file-descriptors via + steam_open if that bit is present in filesystem open reply. + + It was tempting to change fs/fuse/ open handler to use stream_open + instead of nonseekable_open on just FOPEN_NONSEEKABLE flags, but + grepping through Debian codesearch shows users of FOPEN_NONSEEKABLE, + and in particular GVFS which actually uses offset in its read and + write handlers + + https://codesearch.debian.net/search?q=-%3Enonseekable+%3D + https://gitlab.gnome.org/GNOME/gvfs/blob/1.40.0-6-gcbc54396/client/gvfsfusedaemon.c#L1080 + https://gitlab.gnome.org/GNOME/gvfs/blob/1.40.0-6-gcbc54396/client/gvfsfusedaemon.c#L1247-1346 + https://gitlab.gnome.org/GNOME/gvfs/blob/1.40.0-6-gcbc54396/client/gvfsfusedaemon.c#L1399-1481 + + so if we would do such a change it will break a real user. + +5. Add stream_open and FOPEN_STREAM handling to stable kernels starting + from v3.14+ (the kernel where 9c225f2655 first appeared). + + This will allow to patch OSSPD and other FUSE filesystems that + provide stream-like files to return FOPEN_STREAM | FOPEN_NONSEEKABLE + in their open handler and this way avoid the deadlock on all kernel + versions. This should work because fs/fuse/ ignores unknown open + flags returned from a filesystem and so passing FOPEN_STREAM to a + kernel that is not aware of this flag cannot hurt. In turn the kernel + that is not aware of FOPEN_STREAM will be < v3.14 where just + FOPEN_NONSEEKABLE is sufficient to implement streams without read vs + write deadlock. + +This patch adds stream_open, converts /proc/xen/xenbus to it and adds +semantic patch to automatically locate in-kernel places that are either +required to be converted due to read vs write deadlock, or that are just +safe to be converted because read and write do not use ppos and there +are no other funky methods in file_operations. + +Regarding semantic patch I've verified each generated change manually - +that it is correct to convert - and each other nonseekable_open instance +left - that it is either not correct to convert there, or that it is not +converted due to current stream_open.cocci limitations. + +The script also does not convert files that should be valid to convert, +but that currently have .llseek = noop_llseek or generic_file_llseek for +unknown reason despite file being opened with nonseekable_open (e.g. +drivers/input/mousedev.c) + +Cc: Michael Kerrisk +Cc: Yongzhi Pan +Cc: Jonathan Corbet +Cc: David Vrabel +Cc: Juergen Gross +Cc: Miklos Szeredi +Cc: Tejun Heo +Cc: Kirill Tkhai +Cc: Arnd Bergmann +Cc: Christoph Hellwig +Cc: Greg Kroah-Hartman +Cc: Julia Lawall +Cc: Nikolaus Rath +Cc: Han-Wen Nienhuys +Signed-off-by: Kirill Smelkov +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/xen/xenbus/xenbus_dev_frontend.c | 4 + fs/open.c | 18 + + fs/read_write.c | 5 + include/linux/fs.h | 4 + scripts/coccinelle/api/stream_open.cocci | 363 +++++++++++++++++++++++++++++++ + 5 files changed, 389 insertions(+), 5 deletions(-) + +--- a/drivers/xen/xenbus/xenbus_dev_frontend.c ++++ b/drivers/xen/xenbus/xenbus_dev_frontend.c +@@ -614,9 +614,7 @@ static int xenbus_file_open(struct inode + if (xen_store_evtchn == 0) + return -ENOENT; + +- nonseekable_open(inode, filp); +- +- filp->f_mode &= ~FMODE_ATOMIC_POS; /* cdev-style semantics */ ++ stream_open(inode, filp); + + u = kzalloc(sizeof(*u), GFP_KERNEL); + if (u == NULL) +--- a/fs/open.c ++++ b/fs/open.c +@@ -1212,3 +1212,21 @@ int nonseekable_open(struct inode *inode + } + + EXPORT_SYMBOL(nonseekable_open); ++ ++/* ++ * stream_open is used by subsystems that want stream-like file descriptors. ++ * Such file descriptors are not seekable and don't have notion of position ++ * (file.f_pos is always 0). Contrary to file descriptors of other regular ++ * files, .read() and .write() can run simultaneously. ++ * ++ * stream_open never fails and is marked to return int so that it could be ++ * directly used as file_operations.open . ++ */ ++int stream_open(struct inode *inode, struct file *filp) ++{ ++ filp->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE | FMODE_ATOMIC_POS); ++ filp->f_mode |= FMODE_STREAM; ++ return 0; ++} ++ ++EXPORT_SYMBOL(stream_open); +--- a/fs/read_write.c ++++ b/fs/read_write.c +@@ -555,12 +555,13 @@ ssize_t vfs_write(struct file *file, con + + static inline loff_t file_pos_read(struct file *file) + { +- return file->f_pos; ++ return file->f_mode & FMODE_STREAM ? 0 : file->f_pos; + } + + static inline void file_pos_write(struct file *file, loff_t pos) + { +- file->f_pos = pos; ++ if ((file->f_mode & FMODE_STREAM) == 0) ++ file->f_pos = pos; + } + + SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count) +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -148,6 +148,9 @@ typedef int (dio_iodone_t)(struct kiocb + /* Has write method(s) */ + #define FMODE_CAN_WRITE ((__force fmode_t)0x40000) + ++/* File is stream-like */ ++#define FMODE_STREAM ((__force fmode_t)0x200000) ++ + /* File was opened by fanotify and shouldn't generate fanotify events */ + #define FMODE_NONOTIFY ((__force fmode_t)0x4000000) + +@@ -2945,6 +2948,7 @@ extern loff_t no_seek_end_llseek_size(st + extern loff_t no_seek_end_llseek(struct file *, loff_t, int); + extern int generic_file_open(struct inode * inode, struct file * filp); + extern int nonseekable_open(struct inode * inode, struct file * filp); ++extern int stream_open(struct inode * inode, struct file * filp); + + #ifdef CONFIG_BLOCK + typedef void (dio_submit_t)(struct bio *bio, struct inode *inode, +--- /dev/null ++++ b/scripts/coccinelle/api/stream_open.cocci +@@ -0,0 +1,363 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Author: Kirill Smelkov (kirr@nexedi.com) ++// ++// Search for stream-like files that are using nonseekable_open and convert ++// them to stream_open. A stream-like file is a file that does not use ppos in ++// its read and write. Rationale for the conversion is to avoid deadlock in ++// between read and write. ++ ++virtual report ++virtual patch ++virtual explain // explain decisions in the patch (SPFLAGS="-D explain") ++ ++// stream-like reader & writer - ones that do not depend on f_pos. ++@ stream_reader @ ++identifier readstream, ppos; ++identifier f, buf, len; ++type loff_t; ++@@ ++ ssize_t readstream(struct file *f, char *buf, size_t len, loff_t *ppos) ++ { ++ ... when != ppos ++ } ++ ++@ stream_writer @ ++identifier writestream, ppos; ++identifier f, buf, len; ++type loff_t; ++@@ ++ ssize_t writestream(struct file *f, const char *buf, size_t len, loff_t *ppos) ++ { ++ ... when != ppos ++ } ++ ++ ++// a function that blocks ++@ blocks @ ++identifier block_f; ++identifier wait_event =~ "^wait_event_.*"; ++@@ ++ block_f(...) { ++ ... when exists ++ wait_event(...) ++ ... when exists ++ } ++ ++// stream_reader that can block inside. ++// ++// XXX wait_* can be called not directly from current function (e.g. func -> f -> g -> wait()) ++// XXX currently reader_blocks supports only direct and 1-level indirect cases. ++@ reader_blocks_direct @ ++identifier stream_reader.readstream; ++identifier wait_event =~ "^wait_event_.*"; ++@@ ++ readstream(...) ++ { ++ ... when exists ++ wait_event(...) ++ ... when exists ++ } ++ ++@ reader_blocks_1 @ ++identifier stream_reader.readstream; ++identifier blocks.block_f; ++@@ ++ readstream(...) ++ { ++ ... when exists ++ block_f(...) ++ ... when exists ++ } ++ ++@ reader_blocks depends on reader_blocks_direct || reader_blocks_1 @ ++identifier stream_reader.readstream; ++@@ ++ readstream(...) { ++ ... ++ } ++ ++ ++// file_operations + whether they have _any_ .read, .write, .llseek ... at all. ++// ++// XXX add support for file_operations xxx[N] = ... (sound/core/pcm_native.c) ++@ fops0 @ ++identifier fops; ++@@ ++ struct file_operations fops = { ++ ... ++ }; ++ ++@ has_read @ ++identifier fops0.fops; ++identifier read_f; ++@@ ++ struct file_operations fops = { ++ .read = read_f, ++ }; ++ ++@ has_read_iter @ ++identifier fops0.fops; ++identifier read_iter_f; ++@@ ++ struct file_operations fops = { ++ .read_iter = read_iter_f, ++ }; ++ ++@ has_write @ ++identifier fops0.fops; ++identifier write_f; ++@@ ++ struct file_operations fops = { ++ .write = write_f, ++ }; ++ ++@ has_write_iter @ ++identifier fops0.fops; ++identifier write_iter_f; ++@@ ++ struct file_operations fops = { ++ .write_iter = write_iter_f, ++ }; ++ ++@ has_llseek @ ++identifier fops0.fops; ++identifier llseek_f; ++@@ ++ struct file_operations fops = { ++ .llseek = llseek_f, ++ }; ++ ++@ has_no_llseek @ ++identifier fops0.fops; ++@@ ++ struct file_operations fops = { ++ .llseek = no_llseek, ++ }; ++ ++@ has_mmap @ ++identifier fops0.fops; ++identifier mmap_f; ++@@ ++ struct file_operations fops = { ++ .mmap = mmap_f, ++ }; ++ ++@ has_copy_file_range @ ++identifier fops0.fops; ++identifier copy_file_range_f; ++@@ ++ struct file_operations fops = { ++ .copy_file_range = copy_file_range_f, ++ }; ++ ++@ has_remap_file_range @ ++identifier fops0.fops; ++identifier remap_file_range_f; ++@@ ++ struct file_operations fops = { ++ .remap_file_range = remap_file_range_f, ++ }; ++ ++@ has_splice_read @ ++identifier fops0.fops; ++identifier splice_read_f; ++@@ ++ struct file_operations fops = { ++ .splice_read = splice_read_f, ++ }; ++ ++@ has_splice_write @ ++identifier fops0.fops; ++identifier splice_write_f; ++@@ ++ struct file_operations fops = { ++ .splice_write = splice_write_f, ++ }; ++ ++ ++// file_operations that is candidate for stream_open conversion - it does not ++// use mmap and other methods that assume @offset access to file. ++// ++// XXX for simplicity require no .{read/write}_iter and no .splice_{read/write} for now. ++// XXX maybe_steam.fops cannot be used in other rules - it gives "bad rule maybe_stream or bad variable fops". ++@ maybe_stream depends on (!has_llseek || has_no_llseek) && !has_mmap && !has_copy_file_range && !has_remap_file_range && !has_read_iter && !has_write_iter && !has_splice_read && !has_splice_write @ ++identifier fops0.fops; ++@@ ++ struct file_operations fops = { ++ }; ++ ++ ++// ---- conversions ---- ++ ++// XXX .open = nonseekable_open -> .open = stream_open ++// XXX .open = func -> openfunc -> nonseekable_open ++ ++// read & write ++// ++// if both are used in the same file_operations together with an opener - ++// under that conditions we can use stream_open instead of nonseekable_open. ++@ fops_rw depends on maybe_stream @ ++identifier fops0.fops, openfunc; ++identifier stream_reader.readstream; ++identifier stream_writer.writestream; ++@@ ++ struct file_operations fops = { ++ .open = openfunc, ++ .read = readstream, ++ .write = writestream, ++ }; ++ ++@ report_rw depends on report @ ++identifier fops_rw.openfunc; ++position p1; ++@@ ++ openfunc(...) { ++ <... ++ nonseekable_open@p1 ++ ...> ++ } ++ ++@ script:python depends on report && reader_blocks @ ++fops << fops0.fops; ++p << report_rw.p1; ++@@ ++coccilib.report.print_report(p[0], ++ "ERROR: %s: .read() can deadlock .write(); change nonseekable_open -> stream_open to fix." % (fops,)) ++ ++@ script:python depends on report && !reader_blocks @ ++fops << fops0.fops; ++p << report_rw.p1; ++@@ ++coccilib.report.print_report(p[0], ++ "WARNING: %s: .read() and .write() have stream semantic; safe to change nonseekable_open -> stream_open." % (fops,)) ++ ++ ++@ explain_rw_deadlocked depends on explain && reader_blocks @ ++identifier fops_rw.openfunc; ++@@ ++ openfunc(...) { ++ <... ++- nonseekable_open +++ nonseekable_open /* read & write (was deadlock) */ ++ ...> ++ } ++ ++ ++@ explain_rw_nodeadlock depends on explain && !reader_blocks @ ++identifier fops_rw.openfunc; ++@@ ++ openfunc(...) { ++ <... ++- nonseekable_open +++ nonseekable_open /* read & write (no direct deadlock) */ ++ ...> ++ } ++ ++@ patch_rw depends on patch @ ++identifier fops_rw.openfunc; ++@@ ++ openfunc(...) { ++ <... ++- nonseekable_open +++ stream_open ++ ...> ++ } ++ ++ ++// read, but not write ++@ fops_r depends on maybe_stream && !has_write @ ++identifier fops0.fops, openfunc; ++identifier stream_reader.readstream; ++@@ ++ struct file_operations fops = { ++ .open = openfunc, ++ .read = readstream, ++ }; ++ ++@ report_r depends on report @ ++identifier fops_r.openfunc; ++position p1; ++@@ ++ openfunc(...) { ++ <... ++ nonseekable_open@p1 ++ ...> ++ } ++ ++@ script:python depends on report @ ++fops << fops0.fops; ++p << report_r.p1; ++@@ ++coccilib.report.print_report(p[0], ++ "WARNING: %s: .read() has stream semantic; safe to change nonseekable_open -> stream_open." % (fops,)) ++ ++@ explain_r depends on explain @ ++identifier fops_r.openfunc; ++@@ ++ openfunc(...) { ++ <... ++- nonseekable_open +++ nonseekable_open /* read only */ ++ ...> ++ } ++ ++@ patch_r depends on patch @ ++identifier fops_r.openfunc; ++@@ ++ openfunc(...) { ++ <... ++- nonseekable_open +++ stream_open ++ ...> ++ } ++ ++ ++// write, but not read ++@ fops_w depends on maybe_stream && !has_read @ ++identifier fops0.fops, openfunc; ++identifier stream_writer.writestream; ++@@ ++ struct file_operations fops = { ++ .open = openfunc, ++ .write = writestream, ++ }; ++ ++@ report_w depends on report @ ++identifier fops_w.openfunc; ++position p1; ++@@ ++ openfunc(...) { ++ <... ++ nonseekable_open@p1 ++ ...> ++ } ++ ++@ script:python depends on report @ ++fops << fops0.fops; ++p << report_w.p1; ++@@ ++coccilib.report.print_report(p[0], ++ "WARNING: %s: .write() has stream semantic; safe to change nonseekable_open -> stream_open." % (fops,)) ++ ++@ explain_w depends on explain @ ++identifier fops_w.openfunc; ++@@ ++ openfunc(...) { ++ <... ++- nonseekable_open +++ nonseekable_open /* write only */ ++ ...> ++ } ++ ++@ patch_w depends on patch @ ++identifier fops_w.openfunc; ++@@ ++ openfunc(...) { ++ <... ++- nonseekable_open +++ stream_open ++ ...> ++ } ++ ++ ++// no read, no write - don't change anything diff --git a/queue-4.14/fuse-add-fopen_stream-to-use-stream_open.patch b/queue-4.14/fuse-add-fopen_stream-to-use-stream_open.patch new file mode 100644 index 00000000000..6d9959079fe --- /dev/null +++ b/queue-4.14/fuse-add-fopen_stream-to-use-stream_open.patch @@ -0,0 +1,87 @@ +From bbd84f33652f852ce5992d65db4d020aba21f882 Mon Sep 17 00:00:00 2001 +From: Kirill Smelkov +Date: Wed, 24 Apr 2019 07:13:57 +0000 +Subject: fuse: Add FOPEN_STREAM to use stream_open() + +From: Kirill Smelkov + +commit bbd84f33652f852ce5992d65db4d020aba21f882 upstream. + +Starting from commit 9c225f2655e3 ("vfs: atomic f_pos accesses as per +POSIX") files opened even via nonseekable_open gate read and write via lock +and do not allow them to be run simultaneously. This can create read vs +write deadlock if a filesystem is trying to implement a socket-like file +which is intended to be simultaneously used for both read and write from +filesystem client. See commit 10dce8af3422 ("fs: stream_open - opener for +stream-like files so that read and write can run simultaneously without +deadlock") for details and e.g. commit 581d21a2d02a ("xenbus: fix deadlock +on writes to /proc/xen/xenbus") for a similar deadlock example on +/proc/xen/xenbus. + +To avoid such deadlock it was tempting to adjust fuse_finish_open to use +stream_open instead of nonseekable_open on just FOPEN_NONSEEKABLE flags, +but grepping through Debian codesearch shows users of FOPEN_NONSEEKABLE, +and in particular GVFS which actually uses offset in its read and write +handlers + + https://codesearch.debian.net/search?q=-%3Enonseekable+%3D + https://gitlab.gnome.org/GNOME/gvfs/blob/1.40.0-6-gcbc54396/client/gvfsfusedaemon.c#L1080 + https://gitlab.gnome.org/GNOME/gvfs/blob/1.40.0-6-gcbc54396/client/gvfsfusedaemon.c#L1247-1346 + https://gitlab.gnome.org/GNOME/gvfs/blob/1.40.0-6-gcbc54396/client/gvfsfusedaemon.c#L1399-1481 + +so if we would do such a change it will break a real user. + +Add another flag (FOPEN_STREAM) for filesystem servers to indicate that the +opened handler is having stream-like semantics; does not use file position +and thus the kernel is free to issue simultaneous read and write request on +opened file handle. + +This patch together with stream_open() should be added to stable kernels +starting from v3.14+. This will allow to patch OSSPD and other FUSE +filesystems that provide stream-like files to return FOPEN_STREAM | +FOPEN_NONSEEKABLE in open handler and this way avoid the deadlock on all +kernel versions. This should work because fuse_finish_open ignores unknown +open flags returned from a filesystem and so passing FOPEN_STREAM to a +kernel that is not aware of this flag cannot hurt. In turn the kernel that +is not aware of FOPEN_STREAM will be < v3.14 where just FOPEN_NONSEEKABLE +is sufficient to implement streams without read vs write deadlock. + +Cc: stable@vger.kernel.org # v3.14+ +Signed-off-by: Kirill Smelkov +Signed-off-by: Miklos Szeredi +Signed-off-by: Greg Kroah-Hartman + + +--- + fs/fuse/file.c | 4 +++- + include/uapi/linux/fuse.h | 2 ++ + 2 files changed, 5 insertions(+), 1 deletion(-) + +--- a/fs/fuse/file.c ++++ b/fs/fuse/file.c +@@ -178,7 +178,9 @@ void fuse_finish_open(struct inode *inod + file->f_op = &fuse_direct_io_file_operations; + if (!(ff->open_flags & FOPEN_KEEP_CACHE)) + invalidate_inode_pages2(inode->i_mapping); +- if (ff->open_flags & FOPEN_NONSEEKABLE) ++ if (ff->open_flags & FOPEN_STREAM) ++ stream_open(inode, file); ++ else if (ff->open_flags & FOPEN_NONSEEKABLE) + nonseekable_open(inode, file); + if (fc->atomic_o_trunc && (file->f_flags & O_TRUNC)) { + struct fuse_inode *fi = get_fuse_inode(inode); +--- a/include/uapi/linux/fuse.h ++++ b/include/uapi/linux/fuse.h +@@ -216,10 +216,12 @@ struct fuse_file_lock { + * FOPEN_DIRECT_IO: bypass page cache for this open file + * FOPEN_KEEP_CACHE: don't invalidate the data cache on open + * FOPEN_NONSEEKABLE: the file is not seekable ++ * FOPEN_STREAM: the file is stream-like (no file position at all) + */ + #define FOPEN_DIRECT_IO (1 << 0) + #define FOPEN_KEEP_CACHE (1 << 1) + #define FOPEN_NONSEEKABLE (1 << 2) ++#define FOPEN_STREAM (1 << 4) + + /** + * INIT request/reply flags diff --git a/queue-4.14/qmi_wwan-add-quirk-for-quectel-dynamic-config.patch b/queue-4.14/qmi_wwan-add-quirk-for-quectel-dynamic-config.patch new file mode 100644 index 00000000000..e250db0208a --- /dev/null +++ b/queue-4.14/qmi_wwan-add-quirk-for-quectel-dynamic-config.patch @@ -0,0 +1,145 @@ +From e4bf63482c309287ca84d91770ffa7dcc18e37eb Mon Sep 17 00:00:00 2001 +From: Kristian Evensen +Date: Sun, 7 Apr 2019 15:39:09 +0200 +Subject: qmi_wwan: Add quirk for Quectel dynamic config +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Kristian Evensen + +commit e4bf63482c309287ca84d91770ffa7dcc18e37eb upstream. + +Most, if not all, Quectel devices use dynamic interface numbers, and +users are able to change the USB configuration at will. Matching on for +example interface number is therefore not possible. + +Instead, the QMI device can be identified by looking at the interface +class, subclass and protocol (all 0xff), as well as the number of +endpoints. The reason we need to look at the number of endpoints, is +that the diagnostic port interface has the same class, subclass and +protocol as QMI. However, the diagnostic port only has two endpoints, +while QMI has three. + +Until now, we have identified the QMI device by combining a match on +class, subclass and protocol, with a call to the function +quectel_diag_detect(). In quectel_diag_detect(), we check if the number +of endpoints matches for known Quectel vendor/product ids. + +Adding new vendor/product ids to quectel_diag_detect() is not a good +long-term solution. This commit replaces the function with a quirk, and +applies the quirk to affected Quectel devices that I have been able to +test the change with (EP06, EM12 and EC25). If the quirk is set and the +number of endpoints equal two, we return from qmi_wwan_probe() with +-ENODEV. + +[In order for this patch to apply cleanly to 4.14, two minor changes had +to be made. First, the original work-around (quectel_diag_detect()) for +the dynamic interface numbers was never backported to 4.14, so there is +no need to remove this code. Second, support for the EM12 was also not +backported to 4.14. Since supporting EM12 is a trivial change (just +another VID/PID match), and the match for EM12 is changed by this patch, +I chose to not submit adding EM12-support as a separate patch.] + +Signed-off-by: Kristian Evensen +Acked-by: Bjørn Mork +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/usb/qmi_wwan.c | 39 +++++++++++++++++++++++++++++++++++++-- + 1 file changed, 37 insertions(+), 2 deletions(-) + +--- a/drivers/net/usb/qmi_wwan.c ++++ b/drivers/net/usb/qmi_wwan.c +@@ -63,6 +63,7 @@ enum qmi_wwan_flags { + + enum qmi_wwan_quirks { + QMI_WWAN_QUIRK_DTR = 1 << 0, /* needs "set DTR" request */ ++ QMI_WWAN_QUIRK_QUECTEL_DYNCFG = 1 << 1, /* check num. endpoints */ + }; + + struct qmimux_hdr { +@@ -845,6 +846,16 @@ static const struct driver_info qmi_wwan + .data = QMI_WWAN_QUIRK_DTR, + }; + ++static const struct driver_info qmi_wwan_info_quirk_quectel_dyncfg = { ++ .description = "WWAN/QMI device", ++ .flags = FLAG_WWAN | FLAG_SEND_ZLP, ++ .bind = qmi_wwan_bind, ++ .unbind = qmi_wwan_unbind, ++ .manage_power = qmi_wwan_manage_power, ++ .rx_fixup = qmi_wwan_rx_fixup, ++ .data = QMI_WWAN_QUIRK_DTR | QMI_WWAN_QUIRK_QUECTEL_DYNCFG, ++}; ++ + #define HUAWEI_VENDOR_ID 0x12D1 + + /* map QMI/wwan function by a fixed interface number */ +@@ -865,6 +876,15 @@ static const struct driver_info qmi_wwan + #define QMI_GOBI_DEVICE(vend, prod) \ + QMI_FIXED_INTF(vend, prod, 0) + ++/* Quectel does not use fixed interface numbers on at least some of their ++ * devices. We need to check the number of endpoints to ensure that we bind to ++ * the correct interface. ++ */ ++#define QMI_QUIRK_QUECTEL_DYNCFG(vend, prod) \ ++ USB_DEVICE_AND_INTERFACE_INFO(vend, prod, USB_CLASS_VENDOR_SPEC, \ ++ USB_SUBCLASS_VENDOR_SPEC, 0xff), \ ++ .driver_info = (unsigned long)&qmi_wwan_info_quirk_quectel_dyncfg ++ + static const struct usb_device_id products[] = { + /* 1. CDC ECM like devices match on the control interface */ + { /* Huawei E392, E398 and possibly others sharing both device id and more... */ +@@ -969,6 +989,9 @@ static const struct usb_device_id produc + USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0x581d, USB_CLASS_VENDOR_SPEC, 1, 7), + .driver_info = (unsigned long)&qmi_wwan_info, + }, ++ {QMI_QUIRK_QUECTEL_DYNCFG(0x2c7c, 0x0125)}, /* Quectel EC25, EC20 R2.0 Mini PCIe */ ++ {QMI_QUIRK_QUECTEL_DYNCFG(0x2c7c, 0x0306)}, /* Quectel EP06/EG06/EM06 */ ++ {QMI_QUIRK_QUECTEL_DYNCFG(0x2c7c, 0x0512)}, /* Quectel EG12/EM12 */ + + /* 3. Combined interface devices matching on interface number */ + {QMI_FIXED_INTF(0x0408, 0xea42, 4)}, /* Yota / Megafon M100-1 */ +@@ -1258,11 +1281,9 @@ static const struct usb_device_id produc + {QMI_FIXED_INTF(0x03f0, 0x9d1d, 1)}, /* HP lt4120 Snapdragon X5 LTE */ + {QMI_FIXED_INTF(0x22de, 0x9061, 3)}, /* WeTelecom WPD-600N */ + {QMI_QUIRK_SET_DTR(0x1e0e, 0x9001, 5)}, /* SIMCom 7100E, 7230E, 7600E ++ */ +- {QMI_QUIRK_SET_DTR(0x2c7c, 0x0125, 4)}, /* Quectel EC25, EC20 R2.0 Mini PCIe */ + {QMI_QUIRK_SET_DTR(0x2c7c, 0x0121, 4)}, /* Quectel EC21 Mini PCIe */ + {QMI_QUIRK_SET_DTR(0x2c7c, 0x0191, 4)}, /* Quectel EG91 */ + {QMI_FIXED_INTF(0x2c7c, 0x0296, 4)}, /* Quectel BG96 */ +- {QMI_QUIRK_SET_DTR(0x2c7c, 0x0306, 4)}, /* Quectel EP06 Mini PCIe */ + {QMI_QUIRK_SET_DTR(0x2cb7, 0x0104, 4)}, /* Fibocom NL678 series */ + + /* 4. Gobi 1000 devices */ +@@ -1344,6 +1365,7 @@ static int qmi_wwan_probe(struct usb_int + { + struct usb_device_id *id = (struct usb_device_id *)prod; + struct usb_interface_descriptor *desc = &intf->cur_altsetting->desc; ++ const struct driver_info *info; + + /* Workaround to enable dynamic IDs. This disables usbnet + * blacklisting functionality. Which, if required, can be +@@ -1373,6 +1395,19 @@ static int qmi_wwan_probe(struct usb_int + return -ENODEV; + } + ++ info = (void *)&id->driver_info; ++ ++ /* Several Quectel modems supports dynamic interface configuration, so ++ * we need to match on class/subclass/protocol. These values are ++ * identical for the diagnostic- and QMI-interface, but bNumEndpoints is ++ * different. Ignore the current interface if the number of endpoints ++ * equals the number for the diag interface (two). ++ */ ++ if (info->data & QMI_WWAN_QUIRK_QUECTEL_DYNCFG) { ++ if (desc->bNumEndpoints == 2) ++ return -ENODEV; ++ } ++ + return usbnet_probe(intf, id); + } + diff --git a/queue-4.14/series b/queue-4.14/series index 775a1e4b9a7..5f55829a548 100644 --- a/queue-4.14/series +++ b/queue-4.14/series @@ -30,3 +30,6 @@ drm-radeon-prefer-lower-reference-dividers.patch drm-i915-fix-i915_exec_ring_mask.patch drm-i915-fbc-disable-framebuffer-compression-on-geminilake.patch tty-serial_core-add-install.patch +qmi_wwan-add-quirk-for-quectel-dynamic-config.patch +fs-stream_open-opener-for-stream-like-files-so-that-read-and-write-can-run-simultaneously-without-deadlock.patch +fuse-add-fopen_stream-to-use-stream_open.patch