]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.14-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 9 Jun 2019 16:39:25 +0000 (18:39 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 9 Jun 2019 16:39:25 +0000 (18:39 +0200)
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

queue-4.14/fs-stream_open-opener-for-stream-like-files-so-that-read-and-write-can-run-simultaneously-without-deadlock.patch [new file with mode: 0644]
queue-4.14/fuse-add-fopen_stream-to-use-stream_open.patch [new file with mode: 0644]
queue-4.14/qmi_wwan-add-quirk-for-quectel-dynamic-config.patch [new file with mode: 0644]
queue-4.14/series

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 (file)
index 0000000..78b7b7f
--- /dev/null
@@ -0,0 +1,645 @@
+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
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 (file)
index 0000000..6d99590
--- /dev/null
@@ -0,0 +1,87 @@
+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
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 (file)
index 0000000..e250db0
--- /dev/null
@@ -0,0 +1,145 @@
+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);
+ }
index 775a1e4b9a7cb8417852e9e2e9603b8bfc588ba0..5f55829a548d52508357b05495d8f1ef6347c146 100644 (file)
@@ -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