--- /dev/null
+From 10dce8af34226d90fa56746a934f8da5dcdba3df Mon Sep 17 00:00:00 2001
+From: Kirill Smelkov <kirr@nexedi.com>
+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 <kirr@nexedi.com>
+
+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 <mtk.manpages@gmail.com>
+Cc: Yongzhi Pan <panyongzhi@gmail.com>
+Cc: Jonathan Corbet <corbet@lwn.net>
+Cc: David Vrabel <david.vrabel@citrix.com>
+Cc: Juergen Gross <jgross@suse.com>
+Cc: Miklos Szeredi <miklos@szeredi.hu>
+Cc: Tejun Heo <tj@kernel.org>
+Cc: Kirill Tkhai <ktkhai@virtuozzo.com>
+Cc: Arnd Bergmann <arnd@arndb.de>
+Cc: Christoph Hellwig <hch@lst.de>
+Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Cc: Julia Lawall <Julia.Lawall@lip6.fr>
+Cc: Nikolaus Rath <Nikolaus@rath.org>
+Cc: Han-Wen Nienhuys <hanwen@google.com>
+Signed-off-by: Kirill Smelkov <kirr@nexedi.com>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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
--- /dev/null
+From bbd84f33652f852ce5992d65db4d020aba21f882 Mon Sep 17 00:00:00 2001
+From: Kirill Smelkov <kirr@nexedi.com>
+Date: Wed, 24 Apr 2019 07:13:57 +0000
+Subject: fuse: Add FOPEN_STREAM to use stream_open()
+
+From: Kirill Smelkov <kirr@nexedi.com>
+
+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 <kirr@nexedi.com>
+Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+
+---
+ 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
--- /dev/null
+From e4bf63482c309287ca84d91770ffa7dcc18e37eb Mon Sep 17 00:00:00 2001
+From: Kristian Evensen <kristian.evensen@gmail.com>
+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 <kristian.evensen@gmail.com>
+
+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 <kristian.evensen@gmail.com>
+Acked-by: Bjørn Mork <bjorn@mork.no>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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);
+ }
+