]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 4.9
authorSasha Levin <sashal@kernel.org>
Sat, 1 Aug 2020 01:07:04 +0000 (21:07 -0400)
committerSasha Levin <sashal@kernel.org>
Sat, 1 Aug 2020 01:07:04 +0000 (21:07 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
13 files changed:
queue-4.9/ath9k-release-allocated-buffer-if-timed-out.patch [new file with mode: 0644]
queue-4.9/ath9k_htc-release-allocated-buffer-if-timed-out.patch [new file with mode: 0644]
queue-4.9/crypto-ccp-release-all-allocated-memory-if-sha-type-.patch [new file with mode: 0644]
queue-4.9/f2fs-check-if-file-namelen-exceeds-max-value.patch [new file with mode: 0644]
queue-4.9/f2fs-check-memory-boundary-by-insane-namelen.patch [new file with mode: 0644]
queue-4.9/f2fs-fix-to-avoid-memory-leakage-in-f2fs_listxattr.patch [new file with mode: 0644]
queue-4.9/media-rc-prevent-memory-leak-in-cx23888_ir_probe.patch [new file with mode: 0644]
queue-4.9/net-phy-mdio-bcm-unimac-fix-potential-null-dereferen.patch [new file with mode: 0644]
queue-4.9/scsi-libsas-direct-call-probe-and-destruct.patch [new file with mode: 0644]
queue-4.9/series [new file with mode: 0644]
queue-4.9/xfs-catch-inode-allocation-state-mismatch-corruption.patch [new file with mode: 0644]
queue-4.9/xfs-don-t-call-xfs_da_shrink_inode-with-null-bp.patch [new file with mode: 0644]
queue-4.9/xfs-validate-cached-inodes-are-free-when-allocated.patch [new file with mode: 0644]

diff --git a/queue-4.9/ath9k-release-allocated-buffer-if-timed-out.patch b/queue-4.9/ath9k-release-allocated-buffer-if-timed-out.patch
new file mode 100644 (file)
index 0000000..3970760
--- /dev/null
@@ -0,0 +1,34 @@
+From 5b03b6fdf4a70cc5361b6d654c051dc5d525012a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 6 Sep 2019 13:59:30 -0500
+Subject: ath9k: release allocated buffer if timed out
+
+From: Navid Emamdoost <navid.emamdoost@gmail.com>
+
+[ Upstream commit 728c1e2a05e4b5fc52fab3421dce772a806612a2 ]
+
+In ath9k_wmi_cmd, the allocated network buffer needs to be released
+if timeout happens. Otherwise memory will be leaked.
+
+Signed-off-by: Navid Emamdoost <navid.emamdoost@gmail.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/ath9k/wmi.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c
+index 8f14897ae5a33..f100533eb7adc 100644
+--- a/drivers/net/wireless/ath/ath9k/wmi.c
++++ b/drivers/net/wireless/ath/ath9k/wmi.c
+@@ -340,6 +340,7 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
+               ath_dbg(common, WMI, "Timeout waiting for WMI command: %s\n",
+                       wmi_cmd_to_name(cmd_id));
+               mutex_unlock(&wmi->op_mutex);
++              kfree_skb(skb);
+               return -ETIMEDOUT;
+       }
+-- 
+2.25.1
+
diff --git a/queue-4.9/ath9k_htc-release-allocated-buffer-if-timed-out.patch b/queue-4.9/ath9k_htc-release-allocated-buffer-if-timed-out.patch
new file mode 100644 (file)
index 0000000..5a58466
--- /dev/null
@@ -0,0 +1,51 @@
+From b6f37104af8f8c58e466299a3e6d8b652d88c8a7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 6 Sep 2019 13:26:03 -0500
+Subject: ath9k_htc: release allocated buffer if timed out
+
+From: Navid Emamdoost <navid.emamdoost@gmail.com>
+
+[ Upstream commit 853acf7caf10b828102d92d05b5c101666a6142b ]
+
+In htc_config_pipe_credits, htc_setup_complete, and htc_connect_service
+if time out happens, the allocated buffer needs to be released.
+Otherwise there will be memory leak.
+
+Signed-off-by: Navid Emamdoost <navid.emamdoost@gmail.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/ath9k/htc_hst.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c
+index 257b6ee51e54b..1af216aa5adae 100644
+--- a/drivers/net/wireless/ath/ath9k/htc_hst.c
++++ b/drivers/net/wireless/ath/ath9k/htc_hst.c
+@@ -175,6 +175,7 @@ static int htc_config_pipe_credits(struct htc_target *target)
+       time_left = wait_for_completion_timeout(&target->cmd_wait, HZ);
+       if (!time_left) {
+               dev_err(target->dev, "HTC credit config timeout\n");
++              kfree_skb(skb);
+               return -ETIMEDOUT;
+       }
+@@ -211,6 +212,7 @@ static int htc_setup_complete(struct htc_target *target)
+       time_left = wait_for_completion_timeout(&target->cmd_wait, HZ);
+       if (!time_left) {
+               dev_err(target->dev, "HTC start timeout\n");
++              kfree_skb(skb);
+               return -ETIMEDOUT;
+       }
+@@ -284,6 +286,7 @@ int htc_connect_service(struct htc_target *target,
+       if (!time_left) {
+               dev_err(target->dev, "Service connection timeout for: %d\n",
+                       service_connreq->service_id);
++              kfree_skb(skb);
+               return -ETIMEDOUT;
+       }
+-- 
+2.25.1
+
diff --git a/queue-4.9/crypto-ccp-release-all-allocated-memory-if-sha-type-.patch b/queue-4.9/crypto-ccp-release-all-allocated-memory-if-sha-type-.patch
new file mode 100644 (file)
index 0000000..dae1bb9
--- /dev/null
@@ -0,0 +1,41 @@
+From b59926f166cd343271286aa69c5495b29f50ff6d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 19 Sep 2019 11:04:48 -0500
+Subject: crypto: ccp - Release all allocated memory if sha type is invalid
+
+From: Navid Emamdoost <navid.emamdoost@gmail.com>
+
+[ Upstream commit 128c66429247add5128c03dc1e144ca56f05a4e2 ]
+
+Release all allocated memory if sha type is invalid:
+In ccp_run_sha_cmd, if the type of sha is invalid, the allocated
+hmac_buf should be released.
+
+v2: fix the goto.
+
+Signed-off-by: Navid Emamdoost <navid.emamdoost@gmail.com>
+Acked-by: Gary R Hook <gary.hook@amd.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/crypto/ccp/ccp-ops.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/crypto/ccp/ccp-ops.c b/drivers/crypto/ccp/ccp-ops.c
+index 7d4cd518e6022..723f0a0cb2b5b 100644
+--- a/drivers/crypto/ccp/ccp-ops.c
++++ b/drivers/crypto/ccp/ccp-ops.c
+@@ -1216,8 +1216,9 @@ static int ccp_run_sha_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
+                              digest_size);
+                       break;
+               default:
++                      kfree(hmac_buf);
+                       ret = -EINVAL;
+-                      goto e_ctx;
++                      goto e_data;
+               }
+               memset(&hmac_cmd, 0, sizeof(hmac_cmd));
+-- 
+2.25.1
+
diff --git a/queue-4.9/f2fs-check-if-file-namelen-exceeds-max-value.patch b/queue-4.9/f2fs-check-if-file-namelen-exceeds-max-value.patch
new file mode 100644 (file)
index 0000000..dd04008
--- /dev/null
@@ -0,0 +1,38 @@
+From bbb65221d2ea643cc8f5237a19a488d10e455498 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 7 Jan 2019 15:02:34 +0800
+Subject: f2fs: check if file namelen exceeds max value
+
+From: Sheng Yong <shengyong1@huawei.com>
+
+[ Upstream commit 720db068634c91553a8e1d9a0fcd8c7050e06d2b ]
+
+Dentry bitmap is not enough to detect incorrect dentries. So this patch
+also checks the namelen value of a dentry.
+
+Signed-off-by: Gong Chen <gongchen4@huawei.com>
+Signed-off-by: Sheng Yong <shengyong1@huawei.com>
+Reviewed-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/f2fs/dir.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c
+index c452069b5e644..8dd83f024cf26 100644
+--- a/fs/f2fs/dir.c
++++ b/fs/f2fs/dir.c
+@@ -845,7 +845,8 @@ bool f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d,
+               /* check memory boundary before moving forward */
+               bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
+-              if (unlikely(bit_pos > d->max)) {
++              if (unlikely(bit_pos > d->max ||
++                              le16_to_cpu(de->name_len) > F2FS_NAME_LEN)) {
+                       f2fs_msg(F2FS_I_SB(d->inode)->sb, KERN_WARNING,
+                               "%s: corrupted namelen=%d, run fsck to fix.",
+                               __func__, le16_to_cpu(de->name_len));
+-- 
+2.25.1
+
diff --git a/queue-4.9/f2fs-check-memory-boundary-by-insane-namelen.patch b/queue-4.9/f2fs-check-memory-boundary-by-insane-namelen.patch
new file mode 100644 (file)
index 0000000..162e839
--- /dev/null
@@ -0,0 +1,51 @@
+From 0d565aa43ac4df4d3bf3f0106cec18c108b601e8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 14 Nov 2018 12:40:30 -0800
+Subject: f2fs: check memory boundary by insane namelen
+
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+
+[ Upstream commit 4e240d1bab1ead280ddf5eb05058dba6bbd57d10 ]
+
+If namelen is corrupted to have very long value, fill_dentries can copy
+wrong memory area.
+
+Reviewed-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/f2fs/dir.c | 11 ++++++++++-
+ 1 file changed, 10 insertions(+), 1 deletion(-)
+
+diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c
+index b414892be08b7..c452069b5e644 100644
+--- a/fs/f2fs/dir.c
++++ b/fs/f2fs/dir.c
+@@ -843,6 +843,16 @@ bool f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d,
+               de_name.name = d->filename[bit_pos];
+               de_name.len = le16_to_cpu(de->name_len);
++              /* check memory boundary before moving forward */
++              bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
++              if (unlikely(bit_pos > d->max)) {
++                      f2fs_msg(F2FS_I_SB(d->inode)->sb, KERN_WARNING,
++                              "%s: corrupted namelen=%d, run fsck to fix.",
++                              __func__, le16_to_cpu(de->name_len));
++                      set_sbi_flag(sbi, SBI_NEED_FSCK);
++                      return -EINVAL;
++              }
++
+               if (f2fs_encrypted_inode(d->inode)) {
+                       int save_len = fstr->len;
+                       int err;
+@@ -861,7 +871,6 @@ bool f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d,
+                                       le32_to_cpu(de->ino), d_type))
+                       return true;
+-              bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
+               ctx->pos = start_pos + bit_pos;
+       }
+       return false;
+-- 
+2.25.1
+
diff --git a/queue-4.9/f2fs-fix-to-avoid-memory-leakage-in-f2fs_listxattr.patch b/queue-4.9/f2fs-fix-to-avoid-memory-leakage-in-f2fs_listxattr.patch
new file mode 100644 (file)
index 0000000..77b6ae4
--- /dev/null
@@ -0,0 +1,65 @@
+From bb2b2d2daae30ce2b40049e92bf9331b1fada4a4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 18 Oct 2019 14:56:22 +0800
+Subject: f2fs: fix to avoid memory leakage in f2fs_listxattr
+
+From: Randall Huang <huangrandall@google.com>
+
+[ Upstream commit 688078e7f36c293dae25b338ddc9e0a2790f6e06 ]
+
+In f2fs_listxattr, there is no boundary check before
+memcpy e_name to buffer.
+If the e_name_len is corrupted,
+unexpected memory contents may be returned to the buffer.
+
+Signed-off-by: Randall Huang <huangrandall@google.com>
+Reviewed-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/f2fs/xattr.c | 14 +++++++++++++-
+ 1 file changed, 13 insertions(+), 1 deletion(-)
+
+diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c
+index 3e1c0280f8661..50fe6840d593a 100644
+--- a/fs/f2fs/xattr.c
++++ b/fs/f2fs/xattr.c
+@@ -404,8 +404,9 @@ cleanup:
+ ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
+ {
+       struct inode *inode = d_inode(dentry);
++      nid_t xnid = F2FS_I(inode)->i_xattr_nid;
+       struct f2fs_xattr_entry *entry;
+-      void *base_addr;
++      void *base_addr, *last_base_addr;
+       int error = 0;
+       size_t rest = buffer_size;
+@@ -413,6 +414,8 @@ ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
+       if (error)
+               return error;
++      last_base_addr = (void *)base_addr + XATTR_SIZE(xnid, inode);
++
+       list_for_each_xattr(entry, base_addr) {
+               const struct xattr_handler *handler =
+                       f2fs_xattr_handler(entry->e_name_index);
+@@ -420,6 +423,15 @@ ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
+               size_t prefix_len;
+               size_t size;
++              if ((void *)(entry) + sizeof(__u32) > last_base_addr ||
++                      (void *)XATTR_NEXT_ENTRY(entry) > last_base_addr) {
++                      f2fs_err(F2FS_I_SB(inode), "inode (%lu) has corrupted xattr",
++                                              inode->i_ino);
++                      set_sbi_flag(F2FS_I_SB(inode), SBI_NEED_FSCK);
++                      error = -EFSCORRUPTED;
++                      goto cleanup;
++              }
++
+               if (!handler || (handler->list && !handler->list(dentry)))
+                       continue;
+-- 
+2.25.1
+
diff --git a/queue-4.9/media-rc-prevent-memory-leak-in-cx23888_ir_probe.patch b/queue-4.9/media-rc-prevent-memory-leak-in-cx23888_ir_probe.patch
new file mode 100644 (file)
index 0000000..701ce09
--- /dev/null
@@ -0,0 +1,40 @@
+From 47ea70bc39b7e25d3461eb528c6f080a8712a11c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Sep 2019 12:02:41 -0300
+Subject: media: rc: prevent memory leak in cx23888_ir_probe
+
+From: Navid Emamdoost <navid.emamdoost@gmail.com>
+
+[ Upstream commit a7b2df76b42bdd026e3106cf2ba97db41345a177 ]
+
+In cx23888_ir_probe if kfifo_alloc fails the allocated memory for state
+should be released.
+
+Signed-off-by: Navid Emamdoost <navid.emamdoost@gmail.com>
+Signed-off-by: Sean Young <sean@mess.org>
+Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/pci/cx23885/cx23888-ir.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/media/pci/cx23885/cx23888-ir.c b/drivers/media/pci/cx23885/cx23888-ir.c
+index c1aa888af7054..83864a99d3a66 100644
+--- a/drivers/media/pci/cx23885/cx23888-ir.c
++++ b/drivers/media/pci/cx23885/cx23888-ir.c
+@@ -1179,8 +1179,11 @@ int cx23888_ir_probe(struct cx23885_dev *dev)
+               return -ENOMEM;
+       spin_lock_init(&state->rx_kfifo_lock);
+-      if (kfifo_alloc(&state->rx_kfifo, CX23888_IR_RX_KFIFO_SIZE, GFP_KERNEL))
++      if (kfifo_alloc(&state->rx_kfifo, CX23888_IR_RX_KFIFO_SIZE,
++                      GFP_KERNEL)) {
++              kfree(state);
+               return -ENOMEM;
++      }
+       state->dev = dev;
+       sd = &state->sd;
+-- 
+2.25.1
+
diff --git a/queue-4.9/net-phy-mdio-bcm-unimac-fix-potential-null-dereferen.patch b/queue-4.9/net-phy-mdio-bcm-unimac-fix-potential-null-dereferen.patch
new file mode 100644 (file)
index 0000000..d54d92e
--- /dev/null
@@ -0,0 +1,49 @@
+From 3f952b05f6698a550deac29838daa04c46ff5d8b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 11 Jan 2018 11:21:51 +0000
+Subject: net: phy: mdio-bcm-unimac: fix potential NULL dereference in
+ unimac_mdio_probe()
+
+From: Wei Yongjun <weiyongjun1@huawei.com>
+
+[ Upstream commit 297a6961ffb8ff4dc66c9fbf53b924bd1dda05d5 ]
+
+platform_get_resource() may fail and return NULL, so we should
+better check it's return value to avoid a NULL pointer dereference
+a bit later in the code.
+
+This is detected by Coccinelle semantic patch.
+
+@@
+expression pdev, res, n, t, e, e1, e2;
+@@
+
+res = platform_get_resource(pdev, t, n);
++ if (!res)
++   return -EINVAL;
+... when != res == NULL
+e = devm_ioremap(e1, res->start, e2);
+
+Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/phy/mdio-bcm-unimac.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/net/phy/mdio-bcm-unimac.c b/drivers/net/phy/mdio-bcm-unimac.c
+index 8c73b2e771ddd..e6ff731d753d9 100644
+--- a/drivers/net/phy/mdio-bcm-unimac.c
++++ b/drivers/net/phy/mdio-bcm-unimac.c
+@@ -177,6 +177,8 @@ static int unimac_mdio_probe(struct platform_device *pdev)
+               return -ENOMEM;
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      if (!r)
++              return -EINVAL;
+       /* Just ioremap, as this MDIO block is usually integrated into an
+        * Ethernet MAC controller register range
+-- 
+2.25.1
+
diff --git a/queue-4.9/scsi-libsas-direct-call-probe-and-destruct.patch b/queue-4.9/scsi-libsas-direct-call-probe-and-destruct.patch
new file mode 100644 (file)
index 0000000..4245d54
--- /dev/null
@@ -0,0 +1,304 @@
+From 9854eab640d983890a37e6c2bbb06ffd6219e103 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 8 Dec 2017 17:42:09 +0800
+Subject: scsi: libsas: direct call probe and destruct
+
+From: Jason Yan <yanaijie@huawei.com>
+
+[ Upstream commit 0558f33c06bb910e2879e355192227a8e8f0219d ]
+
+In commit 87c8331fcf72 ("[SCSI] libsas: prevent domain rediscovery
+competing with ata error handling") introduced disco mutex to prevent
+rediscovery competing with ata error handling and put the whole
+revalidation in the mutex. But the rphy add/remove needs to wait for the
+error handling which also grabs the disco mutex. This may leads to dead
+lock.So the probe and destruct event were introduce to do the rphy
+add/remove asynchronously and out of the lock.
+
+The asynchronously processed workers makes the whole discovery process
+not atomic, the other events may interrupt the process. For example,
+if a loss of signal event inserted before the probe event, the
+sas_deform_port() is called and the port will be deleted.
+
+And sas_port_delete() may run before the destruct event, but the
+port-x:x is the top parent of end device or expander. This leads to
+a kernel WARNING such as:
+
+[   82.042979] sysfs group 'power' not found for kobject 'phy-1:0:22'
+[   82.042983] ------------[ cut here ]------------
+[   82.042986] WARNING: CPU: 54 PID: 1714 at fs/sysfs/group.c:237
+sysfs_remove_group+0x94/0xa0
+[   82.043059] Call trace:
+[   82.043082] [<ffff0000082e7624>] sysfs_remove_group+0x94/0xa0
+[   82.043085] [<ffff00000864e320>] dpm_sysfs_remove+0x60/0x70
+[   82.043086] [<ffff00000863ee10>] device_del+0x138/0x308
+[   82.043089] [<ffff00000869a2d0>] sas_phy_delete+0x38/0x60
+[   82.043091] [<ffff00000869a86c>] do_sas_phy_delete+0x6c/0x80
+[   82.043093] [<ffff00000863dc20>] device_for_each_child+0x58/0xa0
+[   82.043095] [<ffff000008696f80>] sas_remove_children+0x40/0x50
+[   82.043100] [<ffff00000869d1bc>] sas_destruct_devices+0x64/0xa0
+[   82.043102] [<ffff0000080e93bc>] process_one_work+0x1fc/0x4b0
+[   82.043104] [<ffff0000080e96c0>] worker_thread+0x50/0x490
+[   82.043105] [<ffff0000080f0364>] kthread+0xfc/0x128
+[   82.043107] [<ffff0000080836c0>] ret_from_fork+0x10/0x50
+
+Make probe and destruct a direct call in the disco and revalidate function,
+but put them outside the lock. The whole discovery or revalidate won't
+be interrupted by other events. And the DISCE_PROBE and DISCE_DESTRUCT
+event are deleted as a result of the direct call.
+
+Introduce a new list to destruct the sas_port and put the port delete after
+the destruct. This makes sure the right order of destroying the sysfs
+kobject and fix the warning above.
+
+In sas_ex_revalidate_domain() have a loop to find all broadcasted
+device, and sometimes we have a chance to find the same expander twice.
+Because the sas_port will be deleted at the end of the whole revalidate
+process, sas_port with the same name cannot be added before this.
+Otherwise the sysfs will complain of creating duplicate filename. Since
+the LLDD will send broadcast for every device change, we can only
+process one expander's revalidation.
+
+[mkp: kbuild test robot warning]
+
+Signed-off-by: Jason Yan <yanaijie@huawei.com>
+CC: John Garry <john.garry@huawei.com>
+CC: Johannes Thumshirn <jthumshirn@suse.de>
+CC: Ewan Milne <emilne@redhat.com>
+CC: Christoph Hellwig <hch@lst.de>
+CC: Tomas Henzl <thenzl@redhat.com>
+CC: Dan Williams <dan.j.williams@intel.com>
+Reviewed-by: Hannes Reinecke <hare@suse.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/libsas/sas_ata.c      |  1 -
+ drivers/scsi/libsas/sas_discover.c | 32 +++++++++++++++++-------------
+ drivers/scsi/libsas/sas_expander.c |  8 +++-----
+ drivers/scsi/libsas/sas_internal.h |  1 +
+ drivers/scsi/libsas/sas_port.c     |  3 +++
+ include/scsi/libsas.h              |  3 +--
+ include/scsi/scsi_transport_sas.h  |  1 +
+ 7 files changed, 27 insertions(+), 22 deletions(-)
+
+diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
+index 87f5e694dbedd..dbe8c5ed4afc2 100644
+--- a/drivers/scsi/libsas/sas_ata.c
++++ b/drivers/scsi/libsas/sas_ata.c
+@@ -729,7 +729,6 @@ int sas_discover_sata(struct domain_device *dev)
+       if (res)
+               return res;
+-      sas_discover_event(dev->port, DISCE_PROBE);
+       return 0;
+ }
+diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c
+index b200edc665a58..d6365e2fcc603 100644
+--- a/drivers/scsi/libsas/sas_discover.c
++++ b/drivers/scsi/libsas/sas_discover.c
+@@ -221,13 +221,9 @@ void sas_notify_lldd_dev_gone(struct domain_device *dev)
+       }
+ }
+-static void sas_probe_devices(struct work_struct *work)
++static void sas_probe_devices(struct asd_sas_port *port)
+ {
+       struct domain_device *dev, *n;
+-      struct sas_discovery_event *ev = to_sas_discovery_event(work);
+-      struct asd_sas_port *port = ev->port;
+-
+-      clear_bit(DISCE_PROBE, &port->disc.pending);
+       /* devices must be domain members before link recovery and probe */
+       list_for_each_entry(dev, &port->disco_list, disco_list_node) {
+@@ -303,7 +299,6 @@ int sas_discover_end_dev(struct domain_device *dev)
+       res = sas_notify_lldd_dev_found(dev);
+       if (res)
+               return res;
+-      sas_discover_event(dev->port, DISCE_PROBE);
+       return 0;
+ }
+@@ -362,13 +357,9 @@ static void sas_unregister_common_dev(struct asd_sas_port *port, struct domain_d
+       sas_put_device(dev);
+ }
+-static void sas_destruct_devices(struct work_struct *work)
++void sas_destruct_devices(struct asd_sas_port *port)
+ {
+       struct domain_device *dev, *n;
+-      struct sas_discovery_event *ev = to_sas_discovery_event(work);
+-      struct asd_sas_port *port = ev->port;
+-
+-      clear_bit(DISCE_DESTRUCT, &port->disc.pending);
+       list_for_each_entry_safe(dev, n, &port->destroy_list, disco_list_node) {
+               list_del_init(&dev->disco_list_node);
+@@ -379,6 +370,16 @@ static void sas_destruct_devices(struct work_struct *work)
+       }
+ }
++static void sas_destruct_ports(struct asd_sas_port *port)
++{
++      struct sas_port *sas_port, *p;
++
++      list_for_each_entry_safe(sas_port, p, &port->sas_port_del_list, del_list) {
++              list_del_init(&sas_port->del_list);
++              sas_port_delete(sas_port);
++      }
++}
++
+ void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev)
+ {
+       if (!test_bit(SAS_DEV_DESTROY, &dev->state) &&
+@@ -393,7 +394,6 @@ void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev)
+       if (!test_and_set_bit(SAS_DEV_DESTROY, &dev->state)) {
+               sas_rphy_unlink(dev->rphy);
+               list_move_tail(&dev->disco_list_node, &port->destroy_list);
+-              sas_discover_event(dev->port, DISCE_DESTRUCT);
+       }
+ }
+@@ -499,6 +499,8 @@ static void sas_discover_domain(struct work_struct *work)
+               port->port_dev = NULL;
+       }
++      sas_probe_devices(port);
++
+       SAS_DPRINTK("DONE DISCOVERY on port %d, pid:%d, result:%d\n", port->id,
+                   task_pid_nr(current), error);
+ }
+@@ -532,6 +534,10 @@ static void sas_revalidate_domain(struct work_struct *work)
+                   port->id, task_pid_nr(current), res);
+  out:
+       mutex_unlock(&ha->disco_mutex);
++
++      sas_destruct_devices(port);
++      sas_destruct_ports(port);
++      sas_probe_devices(port);
+ }
+ /* ---------- Events ---------- */
+@@ -587,10 +593,8 @@ void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *port)
+       static const work_func_t sas_event_fns[DISC_NUM_EVENTS] = {
+               [DISCE_DISCOVER_DOMAIN] = sas_discover_domain,
+               [DISCE_REVALIDATE_DOMAIN] = sas_revalidate_domain,
+-              [DISCE_PROBE] = sas_probe_devices,
+               [DISCE_SUSPEND] = sas_suspend_devices,
+               [DISCE_RESUME] = sas_resume_devices,
+-              [DISCE_DESTRUCT] = sas_destruct_devices,
+       };
+       disc->pending = 0;
+diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
+index 7e8274938a3ee..ff3289a41c157 100644
+--- a/drivers/scsi/libsas/sas_expander.c
++++ b/drivers/scsi/libsas/sas_expander.c
+@@ -1935,7 +1935,8 @@ static void sas_unregister_devs_sas_addr(struct domain_device *parent,
+               sas_port_delete_phy(phy->port, phy->phy);
+               sas_device_set_phy(found, phy->port);
+               if (phy->port->num_phys == 0)
+-                      sas_port_delete(phy->port);
++                      list_add_tail(&phy->port->del_list,
++                              &parent->port->sas_port_del_list);
+               phy->port = NULL;
+       }
+ }
+@@ -2145,7 +2146,7 @@ int sas_ex_revalidate_domain(struct domain_device *port_dev)
+       struct domain_device *dev = NULL;
+       res = sas_find_bcast_dev(port_dev, &dev);
+-      while (res == 0 && dev) {
++      if (res == 0 && dev) {
+               struct expander_device *ex = &dev->ex_dev;
+               int i = 0, phy_id;
+@@ -2157,9 +2158,6 @@ int sas_ex_revalidate_domain(struct domain_device *port_dev)
+                       res = sas_rediscover(dev, phy_id);
+                       i = phy_id + 1;
+               } while (i < ex->num_phys);
+-
+-              dev = NULL;
+-              res = sas_find_bcast_dev(port_dev, &dev);
+       }
+       return res;
+ }
+diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
+index 9cf0bc260b0e7..2cbbd113d8984 100644
+--- a/drivers/scsi/libsas/sas_internal.h
++++ b/drivers/scsi/libsas/sas_internal.h
+@@ -98,6 +98,7 @@ int sas_try_ata_reset(struct asd_sas_phy *phy);
+ void sas_hae_reset(struct work_struct *work);
+ void sas_free_device(struct kref *kref);
++void sas_destruct_devices(struct asd_sas_port *port);
+ #ifdef CONFIG_SCSI_SAS_HOST_SMP
+ extern int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req,
+diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c
+index d3c5297c6c89e..5d3244c8f2801 100644
+--- a/drivers/scsi/libsas/sas_port.c
++++ b/drivers/scsi/libsas/sas_port.c
+@@ -66,6 +66,7 @@ static void sas_resume_port(struct asd_sas_phy *phy)
+               rc = sas_notify_lldd_dev_found(dev);
+               if (rc) {
+                       sas_unregister_dev(port, dev);
++                      sas_destruct_devices(port);
+                       continue;
+               }
+@@ -219,6 +220,7 @@ void sas_deform_port(struct asd_sas_phy *phy, int gone)
+       if (port->num_phys == 1) {
+               sas_unregister_domain_devices(port, gone);
++              sas_destruct_devices(port);
+               sas_port_delete(port->port);
+               port->port = NULL;
+       } else {
+@@ -323,6 +325,7 @@ static void sas_init_port(struct asd_sas_port *port,
+       INIT_LIST_HEAD(&port->dev_list);
+       INIT_LIST_HEAD(&port->disco_list);
+       INIT_LIST_HEAD(&port->destroy_list);
++      INIT_LIST_HEAD(&port->sas_port_del_list);
+       spin_lock_init(&port->phy_list_lock);
+       INIT_LIST_HEAD(&port->phy_list);
+       port->ha = sas_ha;
+diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
+index 706a7017885c2..8a27e35b20803 100644
+--- a/include/scsi/libsas.h
++++ b/include/scsi/libsas.h
+@@ -87,10 +87,8 @@ enum discover_event {
+       DISCE_DISCOVER_DOMAIN   = 0U,
+       DISCE_REVALIDATE_DOMAIN = 1,
+       DISCE_PORT_GONE         = 2,
+-      DISCE_PROBE             = 3,
+       DISCE_SUSPEND           = 4,
+       DISCE_RESUME            = 5,
+-      DISCE_DESTRUCT          = 6,
+       DISC_NUM_EVENTS         = 7,
+ };
+@@ -269,6 +267,7 @@ struct asd_sas_port {
+       struct list_head dev_list;
+       struct list_head disco_list;
+       struct list_head destroy_list;
++      struct list_head sas_port_del_list;
+       enum   sas_linkrate linkrate;
+       struct sas_work work;
+diff --git a/include/scsi/scsi_transport_sas.h b/include/scsi/scsi_transport_sas.h
+index 73d870918939e..2cf88fa91edbb 100644
+--- a/include/scsi/scsi_transport_sas.h
++++ b/include/scsi/scsi_transport_sas.h
+@@ -154,6 +154,7 @@ struct sas_port {
+       struct mutex            phy_list_mutex;
+       struct list_head        phy_list;
++      struct list_head        del_list; /* libsas only */
+ };
+ #define dev_to_sas_port(d) \
+-- 
+2.25.1
+
diff --git a/queue-4.9/series b/queue-4.9/series
new file mode 100644 (file)
index 0000000..6f35880
--- /dev/null
@@ -0,0 +1,12 @@
+xfs-catch-inode-allocation-state-mismatch-corruption.patch
+xfs-validate-cached-inodes-are-free-when-allocated.patch
+xfs-don-t-call-xfs_da_shrink_inode-with-null-bp.patch
+net-phy-mdio-bcm-unimac-fix-potential-null-dereferen.patch
+crypto-ccp-release-all-allocated-memory-if-sha-type-.patch
+media-rc-prevent-memory-leak-in-cx23888_ir_probe.patch
+ath9k_htc-release-allocated-buffer-if-timed-out.patch
+ath9k-release-allocated-buffer-if-timed-out.patch
+f2fs-check-memory-boundary-by-insane-namelen.patch
+f2fs-check-if-file-namelen-exceeds-max-value.patch
+f2fs-fix-to-avoid-memory-leakage-in-f2fs_listxattr.patch
+scsi-libsas-direct-call-probe-and-destruct.patch
diff --git a/queue-4.9/xfs-catch-inode-allocation-state-mismatch-corruption.patch b/queue-4.9/xfs-catch-inode-allocation-state-mismatch-corruption.patch
new file mode 100644 (file)
index 0000000..65a318b
--- /dev/null
@@ -0,0 +1,187 @@
+From edbfe4dee34459bd4414bb0fa15233e771d63dad Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 23 Mar 2018 10:22:53 -0700
+Subject: xfs: catch inode allocation state mismatch corruption
+
+From: Dave Chinner <dchinner@redhat.com>
+
+[ Upstream commit ee457001ed6c6f31ddad69c24c1da8f377d8472d ]
+
+We recently came across a V4 filesystem causing memory corruption
+due to a newly allocated inode being setup twice and being added to
+the superblock inode list twice. From code inspection, the only way
+this could happen is if a newly allocated inode was not marked as
+free on disk (i.e. di_mode wasn't zero).
+
+Running the metadump on an upstream debug kernel fails during inode
+allocation like so:
+
+XFS: Assertion failed: ip->i_d.di_nblocks == 0, file: fs/xfs/xfs_inod=
+e.c, line: 838
+ ------------[ cut here ]------------
+kernel BUG at fs/xfs/xfs_message.c:114!
+invalid opcode: 0000 [#1] PREEMPT SMP
+CPU: 11 PID: 3496 Comm: mkdir Not tainted 4.16.0-rc5-dgc #442
+Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/0=
+1/2014
+RIP: 0010:assfail+0x28/0x30
+RSP: 0018:ffffc9000236fc80 EFLAGS: 00010202
+RAX: 00000000ffffffea RBX: 0000000000004000 RCX: 0000000000000000
+RDX: 00000000ffffffc0 RSI: 000000000000000a RDI: ffffffff8227211b
+RBP: ffffc9000236fce8 R08: 0000000000000000 R09: 0000000000000000
+R10: 0000000000000bec R11: f000000000000000 R12: ffffc9000236fd30
+R13: ffff8805c76bab80 R14: ffff8805c77ac800 R15: ffff88083fb12e10
+FS:  00007fac8cbff040(0000) GS:ffff88083fd00000(0000) knlGS:0000000000000=
+000
+CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+CR2: 00007fffa6783ff8 CR3: 00000005c6e2b003 CR4: 00000000000606e0
+Call Trace:
+ xfs_ialloc+0x383/0x570
+ xfs_dir_ialloc+0x6a/0x2a0
+ xfs_create+0x412/0x670
+ xfs_generic_create+0x1f7/0x2c0
+ ? capable_wrt_inode_uidgid+0x3f/0x50
+ vfs_mkdir+0xfb/0x1b0
+ SyS_mkdir+0xcf/0xf0
+ do_syscall_64+0x73/0x1a0
+ entry_SYSCALL_64_after_hwframe+0x42/0xb7
+
+Extracting the inode number we crashed on from an event trace and
+looking at it with xfs_db:
+
+xfs_db> inode 184452204
+xfs_db> p
+core.magic = 0x494e
+core.mode = 0100644
+core.version = 2
+core.format = 2 (extents)
+core.nlinkv2 = 1
+core.onlink = 0
+.....
+
+Confirms that it is not a free inode on disk. xfs_repair
+also trips over this inode:
+
+.....
+zero length extent (off = 0, fsbno = 0) in ino 184452204
+correcting nextents for inode 184452204
+bad attribute fork in inode 184452204, would clear attr fork
+bad nblocks 1 for inode 184452204, would reset to 0
+bad anextents 1 for inode 184452204, would reset to 0
+imap claims in-use inode 184452204 is free, would correct imap
+would have cleared inode 184452204
+.....
+disconnected inode 184452204, would move to lost+found
+
+And so we have a situation where the directory structure and the
+inobt thinks the inode is free, but the inode on disk thinks it is
+still in use. Where this corruption came from is not possible to
+diagnose, but we can detect it and prevent the kernel from oopsing
+on lookup. The reproducer now results in:
+
+$ sudo mkdir /mnt/scratch/{0,1,2,3,4,5}{0,1,2,3,4,5}
+mkdir: cannot create directory =E2=80=98/mnt/scratch/00=E2=80=99: File ex=
+ists
+mkdir: cannot create directory =E2=80=98/mnt/scratch/01=E2=80=99: File ex=
+ists
+mkdir: cannot create directory =E2=80=98/mnt/scratch/03=E2=80=99: Structu=
+re needs cleaning
+mkdir: cannot create directory =E2=80=98/mnt/scratch/04=E2=80=99: Input/o=
+utput error
+mkdir: cannot create directory =E2=80=98/mnt/scratch/05=E2=80=99: Input/o=
+utput error
+....
+
+And this corruption shutdown:
+
+[   54.843517] XFS (loop0): Corruption detected! Free inode 0xafe846c not=
+ marked free on disk
+[   54.845885] XFS (loop0): Internal error xfs_trans_cancel at line 1023 =
+of file fs/xfs/xfs_trans.c.  Caller xfs_create+0x425/0x670
+[   54.848994] CPU: 10 PID: 3541 Comm: mkdir Not tainted 4.16.0-rc5-dgc #=
+443
+[   54.850753] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIO=
+S 1.10.2-1 04/01/2014
+[   54.852859] Call Trace:
+[   54.853531]  dump_stack+0x85/0xc5
+[   54.854385]  xfs_trans_cancel+0x197/0x1c0
+[   54.855421]  xfs_create+0x425/0x670
+[   54.856314]  xfs_generic_create+0x1f7/0x2c0
+[   54.857390]  ? capable_wrt_inode_uidgid+0x3f/0x50
+[   54.858586]  vfs_mkdir+0xfb/0x1b0
+[   54.859458]  SyS_mkdir+0xcf/0xf0
+[   54.860254]  do_syscall_64+0x73/0x1a0
+[   54.861193]  entry_SYSCALL_64_after_hwframe+0x42/0xb7
+[   54.862492] RIP: 0033:0x7fb73bddf547
+[   54.863358] RSP: 002b:00007ffdaa553338 EFLAGS: 00000246 ORIG_RAX: 0000=
+000000000053
+[   54.865133] RAX: ffffffffffffffda RBX: 00007ffdaa55449a RCX: 00007fb73=
+bddf547
+[   54.866766] RDX: 0000000000000001 RSI: 00000000000001ff RDI: 00007ffda=
+a55449a
+[   54.868432] RBP: 00007ffdaa55449a R08: 00000000000001ff R09: 00005623a=
+8670dd0
+[   54.870110] R10: 00007fb73be72d5b R11: 0000000000000246 R12: 000000000=
+00001ff
+[   54.871752] R13: 00007ffdaa5534b0 R14: 0000000000000000 R15: 00007ffda=
+a553500
+[   54.873429] XFS (loop0): xfs_do_force_shutdown(0x8) called from line 1=
+024 of file fs/xfs/xfs_trans.c.  Return address = ffffffff814cd050
+[   54.882790] XFS (loop0): Corruption of in-memory data detected.  Shutt=
+ing down filesystem
+[   54.884597] XFS (loop0): Please umount the filesystem and rectify the =
+problem(s)
+
+Note that this crash is only possible on v4 filesystemsi or v5
+filesystems mounted with the ikeep mount option. For all other V5
+filesystems, this problem cannot occur because we don't read inodes
+we are allocating from disk - we simply overwrite them with the new
+inode information.
+
+Signed-Off-By: Dave Chinner <dchinner@redhat.com>
+Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>
+Tested-by: Carlos Maiolino <cmaiolino@redhat.com>
+Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
+Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/xfs/xfs_icache.c | 23 ++++++++++++++++++++++-
+ 1 file changed, 22 insertions(+), 1 deletion(-)
+
+diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c
+index 86a4911520cc5..57ec10809f4bf 100644
+--- a/fs/xfs/xfs_icache.c
++++ b/fs/xfs/xfs_icache.c
+@@ -471,7 +471,28 @@ xfs_iget_cache_miss(
+       trace_xfs_iget_miss(ip);
+-      if ((VFS_I(ip)->i_mode == 0) && !(flags & XFS_IGET_CREATE)) {
++
++      /*
++       * If we are allocating a new inode, then check what was returned is
++       * actually a free, empty inode. If we are not allocating an inode,
++       * the check we didn't find a free inode.
++       */
++      if (flags & XFS_IGET_CREATE) {
++              if (VFS_I(ip)->i_mode != 0) {
++                      xfs_warn(mp,
++"Corruption detected! Free inode 0x%llx not marked free on disk",
++                              ino);
++                      error = -EFSCORRUPTED;
++                      goto out_destroy;
++              }
++              if (ip->i_d.di_nblocks != 0) {
++                      xfs_warn(mp,
++"Corruption detected! Free inode 0x%llx has blocks allocated!",
++                              ino);
++                      error = -EFSCORRUPTED;
++                      goto out_destroy;
++              }
++      } else if (VFS_I(ip)->i_mode == 0) {
+               error = -ENOENT;
+               goto out_destroy;
+       }
+-- 
+2.25.1
+
diff --git a/queue-4.9/xfs-don-t-call-xfs_da_shrink_inode-with-null-bp.patch b/queue-4.9/xfs-don-t-call-xfs_da_shrink_inode-with-null-bp.patch
new file mode 100644 (file)
index 0000000..c165c24
--- /dev/null
@@ -0,0 +1,48 @@
+From 7c90bf4b5d92891a3feb7cffaba2d0a26a925805 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 8 Jun 2018 09:53:49 -0700
+Subject: xfs: don't call xfs_da_shrink_inode with NULL bp
+
+From: Eric Sandeen <sandeen@sandeen.net>
+
+[ Upstream commit bb3d48dcf86a97dc25fe9fc2c11938e19cb4399a ]
+
+xfs_attr3_leaf_create may have errored out before instantiating a buffer,
+for example if the blkno is out of range.  In that case there is no work
+to do to remove it, and in fact xfs_da_shrink_inode will lead to an oops
+if we try.
+
+This also seems to fix a flaw where the original error from
+xfs_attr3_leaf_create gets overwritten in the cleanup case, and it
+removes a pointless assignment to bp which isn't used after this.
+
+Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=199969
+Reported-by: Xu, Wen <wen.xu@gatech.edu>
+Tested-by: Xu, Wen <wen.xu@gatech.edu>
+Signed-off-by: Eric Sandeen <sandeen@redhat.com>
+Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
+Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/xfs/libxfs/xfs_attr_leaf.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
+index c6c15e5717e42..70da4113c2baf 100644
+--- a/fs/xfs/libxfs/xfs_attr_leaf.c
++++ b/fs/xfs/libxfs/xfs_attr_leaf.c
+@@ -785,9 +785,8 @@ xfs_attr_shortform_to_leaf(xfs_da_args_t *args)
+       ASSERT(blkno == 0);
+       error = xfs_attr3_leaf_create(args, blkno, &bp);
+       if (error) {
+-              error = xfs_da_shrink_inode(args, 0, bp);
+-              bp = NULL;
+-              if (error)
++              /* xfs_attr3_leaf_create may not have instantiated a block */
++              if (bp && (xfs_da_shrink_inode(args, 0, bp) != 0))
+                       goto out;
+               xfs_idata_realloc(dp, size, XFS_ATTR_FORK);     /* try to put */
+               memcpy(ifp->if_u1.if_data, tmpbuffer, size);    /* it back */
+-- 
+2.25.1
+
diff --git a/queue-4.9/xfs-validate-cached-inodes-are-free-when-allocated.patch b/queue-4.9/xfs-validate-cached-inodes-are-free-when-allocated.patch
new file mode 100644 (file)
index 0000000..7bb59e3
--- /dev/null
@@ -0,0 +1,160 @@
+From dbac2f0f4265973be4a983b7d661eecf6f2e8445 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 17 Apr 2018 17:17:34 -0700
+Subject: xfs: validate cached inodes are free when allocated
+
+From: Dave Chinner <dchinner@redhat.com>
+
+[ Upstream commit afca6c5b2595fc44383919fba740c194b0b76aff ]
+
+A recent fuzzed filesystem image cached random dcache corruption
+when the reproducer was run. This often showed up as panics in
+lookup_slow() on a null inode->i_ops pointer when doing pathwalks.
+
+BUG: unable to handle kernel NULL pointer dereference at 0000000000000000
+....
+Call Trace:
+ lookup_slow+0x44/0x60
+ walk_component+0x3dd/0x9f0
+ link_path_walk+0x4a7/0x830
+ path_lookupat+0xc1/0x470
+ filename_lookup+0x129/0x270
+ user_path_at_empty+0x36/0x40
+ path_listxattr+0x98/0x110
+ SyS_listxattr+0x13/0x20
+ do_syscall_64+0xf5/0x280
+ entry_SYSCALL_64_after_hwframe+0x42/0xb7
+
+but had many different failure modes including deadlocks trying to
+lock the inode that was just allocated or KASAN reports of
+use-after-free violations.
+
+The cause of the problem was a corrupt INOBT on a v4 fs where the
+root inode was marked as free in the inobt record. Hence when we
+allocated an inode, it chose the root inode to allocate, found it in
+the cache and re-initialised it.
+
+We recently fixed a similar inode allocation issue caused by inobt
+record corruption problem in xfs_iget_cache_miss() in commit
+ee457001ed6c ("xfs: catch inode allocation state mismatch
+corruption"). This change adds similar checks to the cache-hit path
+to catch it, and turns the reproducer into a corruption shutdown
+situation.
+
+Reported-by: Wen Xu <wen.xu@gatech.edu>
+Signed-Off-By: Dave Chinner <dchinner@redhat.com>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>
+Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
+[darrick: fix typos in comment]
+Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/xfs/xfs_icache.c | 73 +++++++++++++++++++++++++++++----------------
+ 1 file changed, 48 insertions(+), 25 deletions(-)
+
+diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c
+index 57ec10809f4bf..69c112ddb544d 100644
+--- a/fs/xfs/xfs_icache.c
++++ b/fs/xfs/xfs_icache.c
+@@ -307,6 +307,46 @@ xfs_reinit_inode(
+       return error;
+ }
++/*
++ * If we are allocating a new inode, then check what was returned is
++ * actually a free, empty inode. If we are not allocating an inode,
++ * then check we didn't find a free inode.
++ *
++ * Returns:
++ *    0               if the inode free state matches the lookup context
++ *    -ENOENT         if the inode is free and we are not allocating
++ *    -EFSCORRUPTED   if there is any state mismatch at all
++ */
++static int
++xfs_iget_check_free_state(
++      struct xfs_inode        *ip,
++      int                     flags)
++{
++      if (flags & XFS_IGET_CREATE) {
++              /* should be a free inode */
++              if (VFS_I(ip)->i_mode != 0) {
++                      xfs_warn(ip->i_mount,
++"Corruption detected! Free inode 0x%llx not marked free! (mode 0x%x)",
++                              ip->i_ino, VFS_I(ip)->i_mode);
++                      return -EFSCORRUPTED;
++              }
++
++              if (ip->i_d.di_nblocks != 0) {
++                      xfs_warn(ip->i_mount,
++"Corruption detected! Free inode 0x%llx has blocks allocated!",
++                              ip->i_ino);
++                      return -EFSCORRUPTED;
++              }
++              return 0;
++      }
++
++      /* should be an allocated inode */
++      if (VFS_I(ip)->i_mode == 0)
++              return -ENOENT;
++
++      return 0;
++}
++
+ /*
+  * Check the validity of the inode we just found it the cache
+  */
+@@ -356,12 +396,12 @@ xfs_iget_cache_hit(
+       }
+       /*
+-       * If lookup is racing with unlink return an error immediately.
++       * Check the inode free state is valid. This also detects lookup
++       * racing with unlinks.
+        */
+-      if (VFS_I(ip)->i_mode == 0 && !(flags & XFS_IGET_CREATE)) {
+-              error = -ENOENT;
++      error = xfs_iget_check_free_state(ip, flags);
++      if (error)
+               goto out_error;
+-      }
+       /*
+        * If IRECLAIMABLE is set, we've torn down the VFS inode already.
+@@ -473,29 +513,12 @@ xfs_iget_cache_miss(
+       /*
+-       * If we are allocating a new inode, then check what was returned is
+-       * actually a free, empty inode. If we are not allocating an inode,
+-       * the check we didn't find a free inode.
++       * Check the inode free state is valid. This also detects lookup
++       * racing with unlinks.
+        */
+-      if (flags & XFS_IGET_CREATE) {
+-              if (VFS_I(ip)->i_mode != 0) {
+-                      xfs_warn(mp,
+-"Corruption detected! Free inode 0x%llx not marked free on disk",
+-                              ino);
+-                      error = -EFSCORRUPTED;
+-                      goto out_destroy;
+-              }
+-              if (ip->i_d.di_nblocks != 0) {
+-                      xfs_warn(mp,
+-"Corruption detected! Free inode 0x%llx has blocks allocated!",
+-                              ino);
+-                      error = -EFSCORRUPTED;
+-                      goto out_destroy;
+-              }
+-      } else if (VFS_I(ip)->i_mode == 0) {
+-              error = -ENOENT;
++      error = xfs_iget_check_free_state(ip, flags);
++      if (error)
+               goto out_destroy;
+-      }
+       /*
+        * Preload the radix tree so we can insert safely under the
+-- 
+2.25.1
+