]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 28 Mar 2017 11:32:39 +0000 (13:32 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 28 Mar 2017 11:32:39 +0000 (13:32 +0200)
added patches:
libceph-don-t-set-weight-to-in-when-osd-is-destroyed.patch
nl80211-fix-dumpit-error-path-rtnl-deadlocks.patch
raid10-increment-write-counter-after-bio-is-split.patch
usb-usbtmc-add-missing-endpoint-sanity-check.patch
xfs-don-t-allow-di_size-with-high-bit-set.patch
xfs-fix-up-xfs_swap_extent_forks-inline-extent-handling.patch

queue-4.4/libceph-don-t-set-weight-to-in-when-osd-is-destroyed.patch [new file with mode: 0644]
queue-4.4/nl80211-fix-dumpit-error-path-rtnl-deadlocks.patch [new file with mode: 0644]
queue-4.4/raid10-increment-write-counter-after-bio-is-split.patch [new file with mode: 0644]
queue-4.4/series
queue-4.4/usb-usbtmc-add-missing-endpoint-sanity-check.patch [new file with mode: 0644]
queue-4.4/xfs-don-t-allow-di_size-with-high-bit-set.patch [new file with mode: 0644]
queue-4.4/xfs-fix-up-xfs_swap_extent_forks-inline-extent-handling.patch [new file with mode: 0644]

diff --git a/queue-4.4/libceph-don-t-set-weight-to-in-when-osd-is-destroyed.patch b/queue-4.4/libceph-don-t-set-weight-to-in-when-osd-is-destroyed.patch
new file mode 100644 (file)
index 0000000..07d52b4
--- /dev/null
@@ -0,0 +1,38 @@
+From b581a5854eee4b7851dedb0f8c2ceb54fb902c06 Mon Sep 17 00:00:00 2001
+From: Ilya Dryomov <idryomov@gmail.com>
+Date: Wed, 1 Mar 2017 17:33:27 +0100
+Subject: libceph: don't set weight to IN when OSD is destroyed
+
+From: Ilya Dryomov <idryomov@gmail.com>
+
+commit b581a5854eee4b7851dedb0f8c2ceb54fb902c06 upstream.
+
+Since ceph.git commit 4e28f9e63644 ("osd/OSDMap: clear osd_info,
+osd_xinfo on osd deletion"), weight is set to IN when OSD is deleted.
+This changes the result of applying an incremental for clients, not
+just OSDs.  Because CRUSH computations are obviously affected,
+pre-4e28f9e63644 servers disagree with post-4e28f9e63644 clients on
+object placement, resulting in misdirected requests.
+
+Mirrors ceph.git commit a6009d1039a55e2c77f431662b3d6cc5a8e8e63f.
+
+Fixes: 930c53286977 ("libceph: apply new_state before new_up_client on incrementals")
+Link: http://tracker.ceph.com/issues/19122
+Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
+Reviewed-by: Sage Weil <sage@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/ceph/osdmap.c |    1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/net/ceph/osdmap.c
++++ b/net/ceph/osdmap.c
+@@ -1265,7 +1265,6 @@ static int decode_new_up_state_weight(vo
+               if ((map->osd_state[osd] & CEPH_OSD_EXISTS) &&
+                   (xorstate & CEPH_OSD_EXISTS)) {
+                       pr_info("osd%d does not exist\n", osd);
+-                      map->osd_weight[osd] = CEPH_OSD_IN;
+                       ret = set_primary_affinity(map, osd,
+                                                  CEPH_OSD_DEFAULT_PRIMARY_AFFINITY);
+                       if (ret)
diff --git a/queue-4.4/nl80211-fix-dumpit-error-path-rtnl-deadlocks.patch b/queue-4.4/nl80211-fix-dumpit-error-path-rtnl-deadlocks.patch
new file mode 100644 (file)
index 0000000..9b7d0ce
--- /dev/null
@@ -0,0 +1,330 @@
+From ea90e0dc8cecba6359b481e24d9c37160f6f524f Mon Sep 17 00:00:00 2001
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Wed, 15 Mar 2017 14:26:04 +0100
+Subject: nl80211: fix dumpit error path RTNL deadlocks
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+commit ea90e0dc8cecba6359b481e24d9c37160f6f524f upstream.
+
+Sowmini pointed out Dmitry's RTNL deadlock report to me, and it turns out
+to be perfectly accurate - there are various error paths that miss unlock
+of the RTNL.
+
+To fix those, change the locking a bit to not be conditional in all those
+nl80211_prepare_*_dump() functions, but make those require the RTNL to
+start with, and fix the buggy error paths. This also let me use sparse
+(by appropriately overriding the rtnl_lock/rtnl_unlock functions) to
+validate the changes.
+
+Reported-by: Sowmini Varadhan <sowmini.varadhan@oracle.com>
+Reported-by: Dmitry Vyukov <dvyukov@google.com>
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/wireless/nl80211.c |  121 +++++++++++++++++++++----------------------------
+ 1 file changed, 53 insertions(+), 68 deletions(-)
+
+--- a/net/wireless/nl80211.c
++++ b/net/wireless/nl80211.c
+@@ -492,21 +492,17 @@ static int nl80211_prepare_wdev_dump(str
+ {
+       int err;
+-      rtnl_lock();
+-
+       if (!cb->args[0]) {
+               err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
+                                 nl80211_fam.attrbuf, nl80211_fam.maxattr,
+                                 nl80211_policy);
+               if (err)
+-                      goto out_unlock;
++                      return err;
+               *wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk),
+                                                  nl80211_fam.attrbuf);
+-              if (IS_ERR(*wdev)) {
+-                      err = PTR_ERR(*wdev);
+-                      goto out_unlock;
+-              }
++              if (IS_ERR(*wdev))
++                      return PTR_ERR(*wdev);
+               *rdev = wiphy_to_rdev((*wdev)->wiphy);
+               /* 0 is the first index - add 1 to parse only once */
+               cb->args[0] = (*rdev)->wiphy_idx + 1;
+@@ -516,10 +512,8 @@ static int nl80211_prepare_wdev_dump(str
+               struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
+               struct wireless_dev *tmp;
+-              if (!wiphy) {
+-                      err = -ENODEV;
+-                      goto out_unlock;
+-              }
++              if (!wiphy)
++                      return -ENODEV;
+               *rdev = wiphy_to_rdev(wiphy);
+               *wdev = NULL;
+@@ -530,21 +524,11 @@ static int nl80211_prepare_wdev_dump(str
+                       }
+               }
+-              if (!*wdev) {
+-                      err = -ENODEV;
+-                      goto out_unlock;
+-              }
++              if (!*wdev)
++                      return -ENODEV;
+       }
+       return 0;
+- out_unlock:
+-      rtnl_unlock();
+-      return err;
+-}
+-
+-static void nl80211_finish_wdev_dump(struct cfg80211_registered_device *rdev)
+-{
+-      rtnl_unlock();
+ }
+ /* IE validation */
+@@ -3884,9 +3868,10 @@ static int nl80211_dump_station(struct s
+       int sta_idx = cb->args[2];
+       int err;
++      rtnl_lock();
+       err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
+       if (err)
+-              return err;
++              goto out_err;
+       if (!wdev->netdev) {
+               err = -EINVAL;
+@@ -3922,7 +3907,7 @@ static int nl80211_dump_station(struct s
+       cb->args[2] = sta_idx;
+       err = skb->len;
+  out_err:
+-      nl80211_finish_wdev_dump(rdev);
++      rtnl_unlock();
+       return err;
+ }
+@@ -4639,9 +4624,10 @@ static int nl80211_dump_mpath(struct sk_
+       int path_idx = cb->args[2];
+       int err;
++      rtnl_lock();
+       err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
+       if (err)
+-              return err;
++              goto out_err;
+       if (!rdev->ops->dump_mpath) {
+               err = -EOPNOTSUPP;
+@@ -4675,7 +4661,7 @@ static int nl80211_dump_mpath(struct sk_
+       cb->args[2] = path_idx;
+       err = skb->len;
+  out_err:
+-      nl80211_finish_wdev_dump(rdev);
++      rtnl_unlock();
+       return err;
+ }
+@@ -4835,9 +4821,10 @@ static int nl80211_dump_mpp(struct sk_bu
+       int path_idx = cb->args[2];
+       int err;
++      rtnl_lock();
+       err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
+       if (err)
+-              return err;
++              goto out_err;
+       if (!rdev->ops->dump_mpp) {
+               err = -EOPNOTSUPP;
+@@ -4870,7 +4857,7 @@ static int nl80211_dump_mpp(struct sk_bu
+       cb->args[2] = path_idx;
+       err = skb->len;
+  out_err:
+-      nl80211_finish_wdev_dump(rdev);
++      rtnl_unlock();
+       return err;
+ }
+@@ -6806,9 +6793,12 @@ static int nl80211_dump_scan(struct sk_b
+       int start = cb->args[2], idx = 0;
+       int err;
++      rtnl_lock();
+       err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
+-      if (err)
++      if (err) {
++              rtnl_unlock();
+               return err;
++      }
+       wdev_lock(wdev);
+       spin_lock_bh(&rdev->bss_lock);
+@@ -6831,7 +6821,7 @@ static int nl80211_dump_scan(struct sk_b
+       wdev_unlock(wdev);
+       cb->args[2] = idx;
+-      nl80211_finish_wdev_dump(rdev);
++      rtnl_unlock();
+       return skb->len;
+ }
+@@ -6915,9 +6905,10 @@ static int nl80211_dump_survey(struct sk
+       int res;
+       bool radio_stats;
++      rtnl_lock();
+       res = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
+       if (res)
+-              return res;
++              goto out_err;
+       /* prepare_wdev_dump parsed the attributes */
+       radio_stats = nl80211_fam.attrbuf[NL80211_ATTR_SURVEY_RADIO_STATS];
+@@ -6958,7 +6949,7 @@ static int nl80211_dump_survey(struct sk
+       cb->args[2] = survey_idx;
+       res = skb->len;
+  out_err:
+-      nl80211_finish_wdev_dump(rdev);
++      rtnl_unlock();
+       return res;
+ }
+@@ -10158,17 +10149,13 @@ static int nl80211_prepare_vendor_dump(s
+       void *data = NULL;
+       unsigned int data_len = 0;
+-      rtnl_lock();
+-
+       if (cb->args[0]) {
+               /* subtract the 1 again here */
+               struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
+               struct wireless_dev *tmp;
+-              if (!wiphy) {
+-                      err = -ENODEV;
+-                      goto out_unlock;
+-              }
++              if (!wiphy)
++                      return -ENODEV;
+               *rdev = wiphy_to_rdev(wiphy);
+               *wdev = NULL;
+@@ -10189,13 +10176,11 @@ static int nl80211_prepare_vendor_dump(s
+                         nl80211_fam.attrbuf, nl80211_fam.maxattr,
+                         nl80211_policy);
+       if (err)
+-              goto out_unlock;
++              return err;
+       if (!nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_ID] ||
+-          !nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_SUBCMD]) {
+-              err = -EINVAL;
+-              goto out_unlock;
+-      }
++          !nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_SUBCMD])
++              return -EINVAL;
+       *wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk),
+                                          nl80211_fam.attrbuf);
+@@ -10204,10 +10189,8 @@ static int nl80211_prepare_vendor_dump(s
+       *rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk),
+                                          nl80211_fam.attrbuf);
+-      if (IS_ERR(*rdev)) {
+-              err = PTR_ERR(*rdev);
+-              goto out_unlock;
+-      }
++      if (IS_ERR(*rdev))
++              return PTR_ERR(*rdev);
+       vid = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_ID]);
+       subcmd = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_SUBCMD]);
+@@ -10220,19 +10203,15 @@ static int nl80211_prepare_vendor_dump(s
+               if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
+                       continue;
+-              if (!vcmd->dumpit) {
+-                      err = -EOPNOTSUPP;
+-                      goto out_unlock;
+-              }
++              if (!vcmd->dumpit)
++                      return -EOPNOTSUPP;
+               vcmd_idx = i;
+               break;
+       }
+-      if (vcmd_idx < 0) {
+-              err = -EOPNOTSUPP;
+-              goto out_unlock;
+-      }
++      if (vcmd_idx < 0)
++              return -EOPNOTSUPP;
+       if (nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_DATA]) {
+               data = nla_data(nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_DATA]);
+@@ -10249,9 +10228,6 @@ static int nl80211_prepare_vendor_dump(s
+       /* keep rtnl locked in successful case */
+       return 0;
+- out_unlock:
+-      rtnl_unlock();
+-      return err;
+ }
+ static int nl80211_vendor_cmd_dump(struct sk_buff *skb,
+@@ -10266,9 +10242,10 @@ static int nl80211_vendor_cmd_dump(struc
+       int err;
+       struct nlattr *vendor_data;
++      rtnl_lock();
+       err = nl80211_prepare_vendor_dump(skb, cb, &rdev, &wdev);
+       if (err)
+-              return err;
++              goto out;
+       vcmd_idx = cb->args[2];
+       data = (void *)cb->args[3];
+@@ -10277,18 +10254,26 @@ static int nl80211_vendor_cmd_dump(struc
+       if (vcmd->flags & (WIPHY_VENDOR_CMD_NEED_WDEV |
+                          WIPHY_VENDOR_CMD_NEED_NETDEV)) {
+-              if (!wdev)
+-                      return -EINVAL;
++              if (!wdev) {
++                      err = -EINVAL;
++                      goto out;
++              }
+               if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_NETDEV &&
+-                  !wdev->netdev)
+-                      return -EINVAL;
++                  !wdev->netdev) {
++                      err = -EINVAL;
++                      goto out;
++              }
+               if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
+                       if (wdev->netdev &&
+-                          !netif_running(wdev->netdev))
+-                              return -ENETDOWN;
+-                      if (!wdev->netdev && !wdev->p2p_started)
+-                              return -ENETDOWN;
++                          !netif_running(wdev->netdev)) {
++                              err = -ENETDOWN;
++                              goto out;
++                      }
++                      if (!wdev->netdev && !wdev->p2p_started) {
++                              err = -ENETDOWN;
++                              goto out;
++                      }
+               }
+       }
diff --git a/queue-4.4/raid10-increment-write-counter-after-bio-is-split.patch b/queue-4.4/raid10-increment-write-counter-after-bio-is-split.patch
new file mode 100644 (file)
index 0000000..05a7060
--- /dev/null
@@ -0,0 +1,42 @@
+From 9b622e2bbcf049c82e2550d35fb54ac205965f50 Mon Sep 17 00:00:00 2001
+From: Tomasz Majchrzak <tomasz.majchrzak@intel.com>
+Date: Thu, 28 Jul 2016 10:28:25 +0200
+Subject: raid10: increment write counter after bio is split
+
+From: Tomasz Majchrzak <tomasz.majchrzak@intel.com>
+
+commit 9b622e2bbcf049c82e2550d35fb54ac205965f50 upstream.
+
+md pending write counter must be incremented after bio is split,
+otherwise it gets decremented too many times in end bio callback and
+becomes negative.
+
+Signed-off-by: Tomasz Majchrzak <tomasz.majchrzak@intel.com>
+Reviewed-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com>
+Signed-off-by: Shaohua Li <shli@fb.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/md/raid10.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/md/raid10.c
++++ b/drivers/md/raid10.c
+@@ -1072,6 +1072,8 @@ static void __make_request(struct mddev
+       int max_sectors;
+       int sectors;
++      md_write_start(mddev, bio);
++
+       /*
+        * Register the new request and wait if the reconstruction
+        * thread has put up a bar for new requests.
+@@ -1455,8 +1457,6 @@ static void make_request(struct mddev *m
+               return;
+       }
+-      md_write_start(mddev, bio);
+-
+       do {
+               /*
index 68c9a5a3f5ef19139055d5d95aa44dfc45148290..f5a0fc329fb9f2cd90e625caaf1e8df3938c38bb 100644 (file)
@@ -46,3 +46,9 @@ arm-at91-pm-cpu_idle-switch-ddr-to-power-down-mode.patch
 arm-dts-at91-sama5d2-add-dma-properties-to-uart-nodes.patch
 cpufreq-restore-policy-min-max-limits-on-cpu-online.patch
 libceph-force-gfp_noio-for-socket-allocations.patch
+raid10-increment-write-counter-after-bio-is-split.patch
+libceph-don-t-set-weight-to-in-when-osd-is-destroyed.patch
+xfs-don-t-allow-di_size-with-high-bit-set.patch
+xfs-fix-up-xfs_swap_extent_forks-inline-extent-handling.patch
+nl80211-fix-dumpit-error-path-rtnl-deadlocks.patch
+usb-usbtmc-add-missing-endpoint-sanity-check.patch
diff --git a/queue-4.4/usb-usbtmc-add-missing-endpoint-sanity-check.patch b/queue-4.4/usb-usbtmc-add-missing-endpoint-sanity-check.patch
new file mode 100644 (file)
index 0000000..6b38c5b
--- /dev/null
@@ -0,0 +1,64 @@
+From 687e0687f71ec00e0132a21fef802dee88c2f1ad Mon Sep 17 00:00:00 2001
+From: Johan Hovold <johan@kernel.org>
+Date: Tue, 14 Mar 2017 17:55:45 +0100
+Subject: USB: usbtmc: add missing endpoint sanity check
+
+From: Johan Hovold <johan@kernel.org>
+
+commit 687e0687f71ec00e0132a21fef802dee88c2f1ad upstream.
+
+USBTMC devices are required to have a bulk-in and a bulk-out endpoint,
+but the driver failed to verify this, something which could lead to the
+endpoint addresses being taken from uninitialised memory.
+
+Make sure to zero all private data as part of allocation, and add the
+missing endpoint sanity check.
+
+Note that this also addresses a more recently introduced issue, where
+the interrupt-in-presence flag would also be uninitialised whenever the
+optional interrupt-in endpoint is not present. This in turn could lead
+to an interrupt urb being allocated, initialised and submitted based on
+uninitialised values.
+
+Fixes: dbf3e7f654c0 ("Implement an ioctl to support the USMTMC-USB488 READ_STATUS_BYTE operation.")
+Fixes: 5b775f672cc9 ("USB: add USB test and measurement class driver")
+Signed-off-by: Johan Hovold <johan@kernel.org>
+[ johan: backport to v4.4 ]
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/class/usbtmc.c |    9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/class/usbtmc.c
++++ b/drivers/usb/class/usbtmc.c
+@@ -1105,7 +1105,7 @@ static int usbtmc_probe(struct usb_inter
+       dev_dbg(&intf->dev, "%s called\n", __func__);
+-      data = kmalloc(sizeof(*data), GFP_KERNEL);
++      data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+@@ -1163,6 +1163,12 @@ static int usbtmc_probe(struct usb_inter
+               }
+       }
++      if (!data->bulk_out || !data->bulk_in) {
++              dev_err(&intf->dev, "bulk endpoints not found\n");
++              retcode = -ENODEV;
++              goto err_put;
++      }
++
+       retcode = get_capabilities(data);
+       if (retcode)
+               dev_err(&intf->dev, "can't read capabilities\n");
+@@ -1186,6 +1192,7 @@ static int usbtmc_probe(struct usb_inter
+ error_register:
+       sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp);
+       sysfs_remove_group(&intf->dev.kobj, &data_attr_grp);
++err_put:
+       kref_put(&data->kref, usbtmc_delete);
+       return retcode;
+ }
diff --git a/queue-4.4/xfs-don-t-allow-di_size-with-high-bit-set.patch b/queue-4.4/xfs-don-t-allow-di_size-with-high-bit-set.patch
new file mode 100644 (file)
index 0000000..8f0036b
--- /dev/null
@@ -0,0 +1,42 @@
+From ef388e2054feedaeb05399ed654bdb06f385d294 Mon Sep 17 00:00:00 2001
+From: "Darrick J. Wong" <darrick.wong@oracle.com>
+Date: Mon, 5 Dec 2016 12:38:38 +1100
+Subject: xfs: don't allow di_size with high bit set
+
+From: Darrick J. Wong <darrick.wong@oracle.com>
+
+commit ef388e2054feedaeb05399ed654bdb06f385d294 upstream.
+
+The on-disk field di_size is used to set i_size, which is a signed
+integer of loff_t.  If the high bit of di_size is set, we'll end up with
+a negative i_size, which will cause all sorts of problems.  Since the
+VFS won't let us create a file with such length, we should catch them
+here in the verifier too.
+
+Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
+Reviewed-by: Dave Chinner <dchinner@redhat.com>
+Signed-off-by: Dave Chinner <david@fromorbit.com>
+Cc: Nikolay Borisov <n.borisov.lkml@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/xfs/libxfs/xfs_inode_buf.c |    8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/fs/xfs/libxfs/xfs_inode_buf.c
++++ b/fs/xfs/libxfs/xfs_inode_buf.c
+@@ -299,6 +299,14 @@ xfs_dinode_verify(
+       if (dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC))
+               return false;
++      /* don't allow invalid i_size */
++      if (be64_to_cpu(dip->di_size) & (1ULL << 63))
++              return false;
++
++      /* No zero-length symlinks. */
++      if (S_ISLNK(be16_to_cpu(dip->di_mode)) && dip->di_size == 0)
++              return false;
++
+       /* only version 3 or greater inodes are extensively verified here */
+       if (dip->di_version < 3)
+               return true;
diff --git a/queue-4.4/xfs-fix-up-xfs_swap_extent_forks-inline-extent-handling.patch b/queue-4.4/xfs-fix-up-xfs_swap_extent_forks-inline-extent-handling.patch
new file mode 100644 (file)
index 0000000..e589315
--- /dev/null
@@ -0,0 +1,97 @@
+From 4dfce57db6354603641132fac3c887614e3ebe81 Mon Sep 17 00:00:00 2001
+From: Eric Sandeen <sandeen@sandeen.net>
+Date: Tue, 8 Nov 2016 12:55:18 +1100
+Subject: xfs: fix up xfs_swap_extent_forks inline extent handling
+
+From: Eric Sandeen <sandeen@sandeen.net>
+
+commit 4dfce57db6354603641132fac3c887614e3ebe81 upstream.
+
+There have been several reports over the years of NULL pointer
+dereferences in xfs_trans_log_inode during xfs_fsr processes,
+when the process is doing an fput and tearing down extents
+on the temporary inode, something like:
+
+BUG: unable to handle kernel NULL pointer dereference at 0000000000000018
+PID: 29439  TASK: ffff880550584fa0  CPU: 6   COMMAND: "xfs_fsr"
+    [exception RIP: xfs_trans_log_inode+0x10]
+ #9 [ffff8800a57bbbe0] xfs_bunmapi at ffffffffa037398e [xfs]
+#10 [ffff8800a57bbce8] xfs_itruncate_extents at ffffffffa0391b29 [xfs]
+#11 [ffff8800a57bbd88] xfs_inactive_truncate at ffffffffa0391d0c [xfs]
+#12 [ffff8800a57bbdb8] xfs_inactive at ffffffffa0392508 [xfs]
+#13 [ffff8800a57bbdd8] xfs_fs_evict_inode at ffffffffa035907e [xfs]
+#14 [ffff8800a57bbe00] evict at ffffffff811e1b67
+#15 [ffff8800a57bbe28] iput at ffffffff811e23a5
+#16 [ffff8800a57bbe58] dentry_kill at ffffffff811dcfc8
+#17 [ffff8800a57bbe88] dput at ffffffff811dd06c
+#18 [ffff8800a57bbea8] __fput at ffffffff811c823b
+#19 [ffff8800a57bbef0] ____fput at ffffffff811c846e
+#20 [ffff8800a57bbf00] task_work_run at ffffffff81093b27
+#21 [ffff8800a57bbf30] do_notify_resume at ffffffff81013b0c
+#22 [ffff8800a57bbf50] int_signal at ffffffff8161405d
+
+As it turns out, this is because the i_itemp pointer, along
+with the d_ops pointer, has been overwritten with zeros
+when we tear down the extents during truncate.  When the in-core
+inode fork on the temporary inode used by xfs_fsr was originally
+set up during the extent swap, we mistakenly looked at di_nextents
+to determine whether all extents fit inline, but this misses extents
+generated by speculative preallocation; we should be using if_bytes
+instead.
+
+This mistake corrupts the in-memory inode, and code in
+xfs_iext_remove_inline eventually gets bad inputs, causing
+it to memmove and memset incorrect ranges; this became apparent
+because the two values in ifp->if_u2.if_inline_ext[1] contained
+what should have been in d_ops and i_itemp; they were memmoved due
+to incorrect array indexing and then the original locations
+were zeroed with memset, again due to an array overrun.
+
+Fix this by properly using i_df.if_bytes to determine the number
+of extents, not di_nextents.
+
+Thanks to dchinner for looking at this with me and spotting the
+root cause.
+
+[nborisov: backported to 4.4]
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Eric Sandeen <sandeen@redhat.com>
+Reviewed-by: Brian Foster <bfoster@redhat.com>
+Signed-off-by: Dave Chinner <david@fromorbit.com>
+Signed-off-by: Nikolay Borisov <nborisov@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+--
+ fs/xfs/xfs_bmap_util.c |    7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+--- a/fs/xfs/xfs_bmap_util.c
++++ b/fs/xfs/xfs_bmap_util.c
+@@ -1713,6 +1713,7 @@ xfs_swap_extents(
+       xfs_trans_t     *tp;
+       xfs_bstat_t     *sbp = &sxp->sx_stat;
+       xfs_ifork_t     *tempifp, *ifp, *tifp;
++      xfs_extnum_t    nextents;
+       int             src_log_flags, target_log_flags;
+       int             error = 0;
+       int             aforkblks = 0;
+@@ -1899,7 +1900,8 @@ xfs_swap_extents(
+                * pointer.  Otherwise it's already NULL or
+                * pointing to the extent.
+                */
+-              if (ip->i_d.di_nextents <= XFS_INLINE_EXTS) {
++              nextents = ip->i_df.if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
++              if (nextents <= XFS_INLINE_EXTS) {
+                       ifp->if_u1.if_extents =
+                               ifp->if_u2.if_inline_ext;
+               }
+@@ -1918,7 +1920,8 @@ xfs_swap_extents(
+                * pointer.  Otherwise it's already NULL or
+                * pointing to the extent.
+                */
+-              if (tip->i_d.di_nextents <= XFS_INLINE_EXTS) {
++              nextents = tip->i_df.if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
++              if (nextents <= XFS_INLINE_EXTS) {
+                       tifp->if_u1.if_extents =
+                               tifp->if_u2.if_inline_ext;
+               }