--- /dev/null
+From 40fc81027f892284ce31f8b6de1e497f5b47e71f Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Sat, 11 Apr 2020 08:50:45 +0100
+Subject: afs: Fix afs_d_validate() to set the right directory version
+
+From: David Howells <dhowells@redhat.com>
+
+commit 40fc81027f892284ce31f8b6de1e497f5b47e71f upstream.
+
+If a dentry's version is somewhere between invalid_before and the current
+directory version, we should be setting it forward to the current version,
+not backwards to the invalid_before version. Note that we're only doing
+this at all because dentry::d_fsdata isn't large enough on a 32-bit system.
+
+Fix this by using a separate variable for invalid_before so that we don't
+accidentally clobber the current dir version.
+
+Fixes: a4ff7401fbfa ("afs: Keep track of invalid-before version for dentry coherency")
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/afs/dir.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/fs/afs/dir.c
++++ b/fs/afs/dir.c
+@@ -1032,7 +1032,7 @@ static int afs_d_revalidate(struct dentr
+ struct dentry *parent;
+ struct inode *inode;
+ struct key *key;
+- afs_dataversion_t dir_version;
++ afs_dataversion_t dir_version, invalid_before;
+ long de_version;
+ int ret;
+
+@@ -1084,8 +1084,8 @@ static int afs_d_revalidate(struct dentr
+ if (de_version == (long)dir_version)
+ goto out_valid_noupdate;
+
+- dir_version = dir->invalid_before;
+- if (de_version - (long)dir_version >= 0)
++ invalid_before = dir->invalid_before;
++ if (de_version - (long)invalid_before >= 0)
+ goto out_valid;
+
+ _debug("dir modified");
--- /dev/null
+From 3e0d9892c0e7fa426ca6bf921cb4b543ca265714 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Wed, 8 Apr 2020 17:32:10 +0100
+Subject: afs: Fix decoding of inline abort codes from version 1 status records
+
+From: David Howells <dhowells@redhat.com>
+
+commit 3e0d9892c0e7fa426ca6bf921cb4b543ca265714 upstream.
+
+If we're decoding an AFSFetchStatus record and we see that the version is 1
+and the abort code is set and we're expecting inline errors, then we store
+the abort code and ignore the remaining status record (which is correct),
+but we don't set the flag to say we got a valid abort code.
+
+This can affect operation of YFS.RemoveFile2 when removing a file and the
+operation of {,Y}FS.InlineBulkStatus when prospectively constructing or
+updating of a set of inodes during a lookup.
+
+Fix this to indicate the reception of a valid abort code.
+
+Fixes: a38a75581e6e ("afs: Fix unlink to handle YFS.RemoveFile2 better")
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/afs/fsclient.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/fs/afs/fsclient.c
++++ b/fs/afs/fsclient.c
+@@ -88,6 +88,7 @@ static int xdr_decode_AFSFetchStatus(con
+
+ if (abort_code != 0 && inline_error) {
+ status->abort_code = abort_code;
++ scb->have_error = true;
+ goto good;
+ }
+
--- /dev/null
+From c72057b56f7e24865840a6961d801a7f21d30a5f Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Wed, 8 Apr 2020 16:13:20 +0100
+Subject: afs: Fix missing XDR advance in xdr_decode_{AFS,YFS}FSFetchStatus()
+
+From: David Howells <dhowells@redhat.com>
+
+commit c72057b56f7e24865840a6961d801a7f21d30a5f upstream.
+
+If we receive a status record that has VNOVNODE set in the abort field,
+xdr_decode_AFSFetchStatus() and xdr_decode_YFSFetchStatus() don't advance
+the XDR pointer, thereby corrupting anything subsequent decodes from the
+same block of data.
+
+This has the potential to affect AFS.InlineBulkStatus and
+YFS.InlineBulkStatus operation, but probably doesn't since the status
+records are extracted as individual blocks of data and the buffer pointer
+is reset between blocks.
+
+It does affect YFS.RemoveFile2 operation, corrupting the volsync record -
+though that is not currently used.
+
+Other operations abort the entire operation rather than returning an error
+inline, in which case there is no decoding to be done.
+
+Fix this by unconditionally advancing the xdr pointer.
+
+Fixes: 684b0f68cf1c ("afs: Fix AFSFetchStatus decoder to provide OpenAFS compatibility")
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/afs/fsclient.c | 14 +++++++++-----
+ fs/afs/yfsclient.c | 12 ++++++++----
+ 2 files changed, 17 insertions(+), 9 deletions(-)
+
+--- a/fs/afs/fsclient.c
++++ b/fs/afs/fsclient.c
+@@ -65,6 +65,7 @@ static int xdr_decode_AFSFetchStatus(con
+ bool inline_error = (call->operation_ID == afs_FS_InlineBulkStatus);
+ u64 data_version, size;
+ u32 type, abort_code;
++ int ret;
+
+ abort_code = ntohl(xdr->abort_code);
+
+@@ -78,7 +79,7 @@ static int xdr_decode_AFSFetchStatus(con
+ */
+ status->abort_code = abort_code;
+ scb->have_error = true;
+- return 0;
++ goto good;
+ }
+
+ pr_warn("Unknown AFSFetchStatus version %u\n", ntohl(xdr->if_version));
+@@ -87,7 +88,7 @@ static int xdr_decode_AFSFetchStatus(con
+
+ if (abort_code != 0 && inline_error) {
+ status->abort_code = abort_code;
+- return 0;
++ goto good;
+ }
+
+ type = ntohl(xdr->type);
+@@ -123,13 +124,16 @@ static int xdr_decode_AFSFetchStatus(con
+ data_version |= (u64)ntohl(xdr->data_version_hi) << 32;
+ status->data_version = data_version;
+ scb->have_status = true;
+-
++good:
++ ret = 0;
++advance:
+ *_bp = (const void *)*_bp + sizeof(*xdr);
+- return 0;
++ return ret;
+
+ bad:
+ xdr_dump_bad(*_bp);
+- return afs_protocol_error(call, -EBADMSG, afs_eproto_bad_status);
++ ret = afs_protocol_error(call, -EBADMSG, afs_eproto_bad_status);
++ goto advance;
+ }
+
+ static time64_t xdr_decode_expiry(struct afs_call *call, u32 expiry)
+--- a/fs/afs/yfsclient.c
++++ b/fs/afs/yfsclient.c
+@@ -186,13 +186,14 @@ static int xdr_decode_YFSFetchStatus(con
+ const struct yfs_xdr_YFSFetchStatus *xdr = (const void *)*_bp;
+ struct afs_file_status *status = &scb->status;
+ u32 type;
++ int ret;
+
+ status->abort_code = ntohl(xdr->abort_code);
+ if (status->abort_code != 0) {
+ if (status->abort_code == VNOVNODE)
+ status->nlink = 0;
+ scb->have_error = true;
+- return 0;
++ goto good;
+ }
+
+ type = ntohl(xdr->type);
+@@ -220,13 +221,16 @@ static int xdr_decode_YFSFetchStatus(con
+ status->size = xdr_to_u64(xdr->size);
+ status->data_version = xdr_to_u64(xdr->data_version);
+ scb->have_status = true;
+-
++good:
++ ret = 0;
++advance:
+ *_bp += xdr_size(xdr);
+- return 0;
++ return ret;
+
+ bad:
+ xdr_dump_bad(*_bp);
+- return afs_protocol_error(call, -EBADMSG, afs_eproto_bad_status);
++ ret = afs_protocol_error(call, -EBADMSG, afs_eproto_bad_status);
++ goto advance;
+ }
+
+ /*
--- /dev/null
+From 2105c2820d366b76f38e6ad61c75771881ecc532 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Fri, 10 Apr 2020 15:23:27 +0100
+Subject: afs: Fix race between post-modification dir edit and readdir/d_revalidate
+
+From: David Howells <dhowells@redhat.com>
+
+commit 2105c2820d366b76f38e6ad61c75771881ecc532 upstream.
+
+AFS directories are retained locally as a structured file, with lookup
+being effected by a local search of the file contents. When a modification
+(such as mkdir) happens, the dir file content is modified locally rather
+than redownloading the directory.
+
+The directory contents are accessed in a number of ways, with a number of
+different locks schemes:
+
+ (1) Download of contents - dvnode->validate_lock/write in afs_read_dir().
+
+ (2) Lookup and readdir - dvnode->validate_lock/read in afs_dir_iterate(),
+ downgrading from (1) if necessary.
+
+ (3) d_revalidate of child dentry - dvnode->validate_lock/read in
+ afs_do_lookup_one() downgrading from (1) if necessary.
+
+ (4) Edit of dir after modification - page locks on individual dir pages.
+
+Unfortunately, because (4) uses different locking scheme to (1) - (3),
+nothing protects against the page being scanned whilst the edit is
+underway. Even download is not safe as it doesn't lock the pages - relying
+instead on the validate_lock to serialise as a whole (the theory being that
+directory contents are treated as a block and always downloaded as a
+block).
+
+Fix this by write-locking dvnode->validate_lock around the edits. Care
+must be taken in the rename case as there may be two different dirs - but
+they need not be locked at the same time. In any case, once the lock is
+taken, the directory version must be rechecked, and the edit skipped if a
+later version has been downloaded by revalidation (there can't have been
+any local changes because the VFS holds the inode lock, but there can have
+been remote changes).
+
+Fixes: 63a4681ff39c ("afs: Locally edit directory data for mkdir/create/unlink/...")
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/afs/dir.c | 91 ++++++++++++++++++++++++++++++++++++-----------------
+ fs/afs/dir_silly.c | 22 ++++++++----
+ 2 files changed, 77 insertions(+), 36 deletions(-)
+
+--- a/fs/afs/dir.c
++++ b/fs/afs/dir.c
+@@ -1275,6 +1275,7 @@ static int afs_mkdir(struct inode *dir,
+ struct afs_fs_cursor fc;
+ struct afs_vnode *dvnode = AFS_FS_I(dir);
+ struct key *key;
++ afs_dataversion_t data_version;
+ int ret;
+
+ mode |= S_IFDIR;
+@@ -1295,7 +1296,7 @@ static int afs_mkdir(struct inode *dir,
+
+ ret = -ERESTARTSYS;
+ if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
+- afs_dataversion_t data_version = dvnode->status.data_version + 1;
++ data_version = dvnode->status.data_version + 1;
+
+ while (afs_select_fileserver(&fc)) {
+ fc.cb_break = afs_calc_vnode_cb_break(dvnode);
+@@ -1316,10 +1317,14 @@ static int afs_mkdir(struct inode *dir,
+ goto error_key;
+ }
+
+- if (ret == 0 &&
+- test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
+- afs_edit_dir_add(dvnode, &dentry->d_name, &iget_data.fid,
+- afs_edit_dir_for_create);
++ if (ret == 0) {
++ down_write(&dvnode->validate_lock);
++ if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) &&
++ dvnode->status.data_version == data_version)
++ afs_edit_dir_add(dvnode, &dentry->d_name, &iget_data.fid,
++ afs_edit_dir_for_create);
++ up_write(&dvnode->validate_lock);
++ }
+
+ key_put(key);
+ kfree(scb);
+@@ -1360,6 +1365,7 @@ static int afs_rmdir(struct inode *dir,
+ struct afs_fs_cursor fc;
+ struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode = NULL;
+ struct key *key;
++ afs_dataversion_t data_version;
+ int ret;
+
+ _enter("{%llx:%llu},{%pd}",
+@@ -1391,7 +1397,7 @@ static int afs_rmdir(struct inode *dir,
+
+ ret = -ERESTARTSYS;
+ if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
+- afs_dataversion_t data_version = dvnode->status.data_version + 1;
++ data_version = dvnode->status.data_version + 1;
+
+ while (afs_select_fileserver(&fc)) {
+ fc.cb_break = afs_calc_vnode_cb_break(dvnode);
+@@ -1404,9 +1410,12 @@ static int afs_rmdir(struct inode *dir,
+ ret = afs_end_vnode_operation(&fc);
+ if (ret == 0) {
+ afs_dir_remove_subdir(dentry);
+- if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
++ down_write(&dvnode->validate_lock);
++ if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) &&
++ dvnode->status.data_version == data_version)
+ afs_edit_dir_remove(dvnode, &dentry->d_name,
+ afs_edit_dir_for_rmdir);
++ up_write(&dvnode->validate_lock);
+ }
+ }
+
+@@ -1544,10 +1553,15 @@ static int afs_unlink(struct inode *dir,
+ ret = afs_end_vnode_operation(&fc);
+ if (ret == 0 && !(scb[1].have_status || scb[1].have_error))
+ ret = afs_dir_remove_link(dvnode, dentry, key);
+- if (ret == 0 &&
+- test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
+- afs_edit_dir_remove(dvnode, &dentry->d_name,
+- afs_edit_dir_for_unlink);
++
++ if (ret == 0) {
++ down_write(&dvnode->validate_lock);
++ if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) &&
++ dvnode->status.data_version == data_version)
++ afs_edit_dir_remove(dvnode, &dentry->d_name,
++ afs_edit_dir_for_unlink);
++ up_write(&dvnode->validate_lock);
++ }
+ }
+
+ if (need_rehash && ret < 0 && ret != -ENOENT)
+@@ -1573,6 +1587,7 @@ static int afs_create(struct inode *dir,
+ struct afs_status_cb *scb;
+ struct afs_vnode *dvnode = AFS_FS_I(dir);
+ struct key *key;
++ afs_dataversion_t data_version;
+ int ret;
+
+ mode |= S_IFREG;
+@@ -1597,7 +1612,7 @@ static int afs_create(struct inode *dir,
+
+ ret = -ERESTARTSYS;
+ if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
+- afs_dataversion_t data_version = dvnode->status.data_version + 1;
++ data_version = dvnode->status.data_version + 1;
+
+ while (afs_select_fileserver(&fc)) {
+ fc.cb_break = afs_calc_vnode_cb_break(dvnode);
+@@ -1618,9 +1633,12 @@ static int afs_create(struct inode *dir,
+ goto error_key;
+ }
+
+- if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
++ down_write(&dvnode->validate_lock);
++ if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) &&
++ dvnode->status.data_version == data_version)
+ afs_edit_dir_add(dvnode, &dentry->d_name, &iget_data.fid,
+ afs_edit_dir_for_create);
++ up_write(&dvnode->validate_lock);
+
+ kfree(scb);
+ key_put(key);
+@@ -1648,6 +1666,7 @@ static int afs_link(struct dentry *from,
+ struct afs_vnode *dvnode = AFS_FS_I(dir);
+ struct afs_vnode *vnode = AFS_FS_I(d_inode(from));
+ struct key *key;
++ afs_dataversion_t data_version;
+ int ret;
+
+ _enter("{%llx:%llu},{%llx:%llu},{%pd}",
+@@ -1672,7 +1691,7 @@ static int afs_link(struct dentry *from,
+
+ ret = -ERESTARTSYS;
+ if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
+- afs_dataversion_t data_version = dvnode->status.data_version + 1;
++ data_version = dvnode->status.data_version + 1;
+
+ if (mutex_lock_interruptible_nested(&vnode->io_lock, 1) < 0) {
+ afs_end_vnode_operation(&fc);
+@@ -1702,9 +1721,12 @@ static int afs_link(struct dentry *from,
+ goto error_key;
+ }
+
+- if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
++ down_write(&dvnode->validate_lock);
++ if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) &&
++ dvnode->status.data_version == data_version)
+ afs_edit_dir_add(dvnode, &dentry->d_name, &vnode->fid,
+ afs_edit_dir_for_link);
++ up_write(&dvnode->validate_lock);
+
+ key_put(key);
+ kfree(scb);
+@@ -1732,6 +1754,7 @@ static int afs_symlink(struct inode *dir
+ struct afs_status_cb *scb;
+ struct afs_vnode *dvnode = AFS_FS_I(dir);
+ struct key *key;
++ afs_dataversion_t data_version;
+ int ret;
+
+ _enter("{%llx:%llu},{%pd},%s",
+@@ -1759,7 +1782,7 @@ static int afs_symlink(struct inode *dir
+
+ ret = -ERESTARTSYS;
+ if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
+- afs_dataversion_t data_version = dvnode->status.data_version + 1;
++ data_version = dvnode->status.data_version + 1;
+
+ while (afs_select_fileserver(&fc)) {
+ fc.cb_break = afs_calc_vnode_cb_break(dvnode);
+@@ -1780,9 +1803,12 @@ static int afs_symlink(struct inode *dir
+ goto error_key;
+ }
+
+- if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
++ down_write(&dvnode->validate_lock);
++ if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) &&
++ dvnode->status.data_version == data_version)
+ afs_edit_dir_add(dvnode, &dentry->d_name, &iget_data.fid,
+ afs_edit_dir_for_symlink);
++ up_write(&dvnode->validate_lock);
+
+ key_put(key);
+ kfree(scb);
+@@ -1812,6 +1838,8 @@ static int afs_rename(struct inode *old_
+ struct dentry *tmp = NULL, *rehash = NULL;
+ struct inode *new_inode;
+ struct key *key;
++ afs_dataversion_t orig_data_version;
++ afs_dataversion_t new_data_version;
+ bool new_negative = d_is_negative(new_dentry);
+ int ret;
+
+@@ -1890,9 +1918,6 @@ static int afs_rename(struct inode *old_
+
+ ret = -ERESTARTSYS;
+ if (afs_begin_vnode_operation(&fc, orig_dvnode, key, true)) {
+- afs_dataversion_t orig_data_version;
+- afs_dataversion_t new_data_version;
+-
+ orig_data_version = orig_dvnode->status.data_version + 1;
+
+ if (orig_dvnode != new_dvnode) {
+@@ -1928,18 +1953,25 @@ static int afs_rename(struct inode *old_
+ if (ret == 0) {
+ if (rehash)
+ d_rehash(rehash);
+- if (test_bit(AFS_VNODE_DIR_VALID, &orig_dvnode->flags))
+- afs_edit_dir_remove(orig_dvnode, &old_dentry->d_name,
+- afs_edit_dir_for_rename_0);
+-
+- if (!new_negative &&
+- test_bit(AFS_VNODE_DIR_VALID, &new_dvnode->flags))
+- afs_edit_dir_remove(new_dvnode, &new_dentry->d_name,
+- afs_edit_dir_for_rename_1);
++ down_write(&orig_dvnode->validate_lock);
++ if (test_bit(AFS_VNODE_DIR_VALID, &orig_dvnode->flags) &&
++ orig_dvnode->status.data_version == orig_data_version)
++ afs_edit_dir_remove(orig_dvnode, &old_dentry->d_name,
++ afs_edit_dir_for_rename_0);
++ if (orig_dvnode != new_dvnode) {
++ up_write(&orig_dvnode->validate_lock);
++
++ down_write(&new_dvnode->validate_lock);
++ }
++ if (test_bit(AFS_VNODE_DIR_VALID, &new_dvnode->flags) &&
++ orig_dvnode->status.data_version == new_data_version) {
++ if (!new_negative)
++ afs_edit_dir_remove(new_dvnode, &new_dentry->d_name,
++ afs_edit_dir_for_rename_1);
+
+- if (test_bit(AFS_VNODE_DIR_VALID, &new_dvnode->flags))
+ afs_edit_dir_add(new_dvnode, &new_dentry->d_name,
+ &vnode->fid, afs_edit_dir_for_rename_2);
++ }
+
+ new_inode = d_inode(new_dentry);
+ if (new_inode) {
+@@ -1958,6 +1990,7 @@ static int afs_rename(struct inode *old_
+ afs_update_dentry_version(&fc, old_dentry, &scb[1]);
+ afs_update_dentry_version(&fc, new_dentry, &scb[1]);
+ d_move(old_dentry, new_dentry);
++ up_write(&new_dvnode->validate_lock);
+ goto error_tmp;
+ }
+
+--- a/fs/afs/dir_silly.c
++++ b/fs/afs/dir_silly.c
+@@ -21,6 +21,7 @@ static int afs_do_silly_rename(struct af
+ {
+ struct afs_fs_cursor fc;
+ struct afs_status_cb *scb;
++ afs_dataversion_t dir_data_version;
+ int ret = -ERESTARTSYS;
+
+ _enter("%pd,%pd", old, new);
+@@ -31,7 +32,7 @@ static int afs_do_silly_rename(struct af
+
+ trace_afs_silly_rename(vnode, false);
+ if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
+- afs_dataversion_t dir_data_version = dvnode->status.data_version + 1;
++ dir_data_version = dvnode->status.data_version + 1;
+
+ while (afs_select_fileserver(&fc)) {
+ fc.cb_break = afs_calc_vnode_cb_break(dvnode);
+@@ -54,12 +55,15 @@ static int afs_do_silly_rename(struct af
+ dvnode->silly_key = key_get(key);
+ }
+
+- if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
++ down_write(&dvnode->validate_lock);
++ if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) &&
++ dvnode->status.data_version == dir_data_version) {
+ afs_edit_dir_remove(dvnode, &old->d_name,
+ afs_edit_dir_for_silly_0);
+- if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
+ afs_edit_dir_add(dvnode, &new->d_name,
+ &vnode->fid, afs_edit_dir_for_silly_1);
++ }
++ up_write(&dvnode->validate_lock);
+ }
+
+ kfree(scb);
+@@ -181,10 +185,14 @@ static int afs_do_silly_unlink(struct af
+ clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
+ }
+ }
+- if (ret == 0 &&
+- test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
+- afs_edit_dir_remove(dvnode, &dentry->d_name,
+- afs_edit_dir_for_unlink);
++ if (ret == 0) {
++ down_write(&dvnode->validate_lock);
++ if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) &&
++ dvnode->status.data_version == dir_data_version)
++ afs_edit_dir_remove(dvnode, &dentry->d_name,
++ afs_edit_dir_for_unlink);
++ up_write(&dvnode->validate_lock);
++ }
+ }
+
+ kfree(scb);
--- /dev/null
+From b98f0ec91c42d87a70da42726b852ac8d78a3257 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Wed, 8 Apr 2020 20:56:20 +0100
+Subject: afs: Fix rename operation status delivery
+
+From: David Howells <dhowells@redhat.com>
+
+commit b98f0ec91c42d87a70da42726b852ac8d78a3257 upstream.
+
+The afs_deliver_fs_rename() and yfs_deliver_fs_rename() functions both only
+decode the second file status returned unless the parent directories are
+different - unfortunately, this means that the xdr pointer isn't advanced
+and the volsync record will be read incorrectly in such an instance.
+
+Fix this by always decoding the second status into the second
+status/callback block which wasn't being used if the dirs were the same.
+
+The afs_update_dentry_version() calls that update the directory data
+version numbers on the dentries can then unconditionally use the second
+status record as this will always reflect the state of the destination dir
+(the two records will be identical if the destination dir is the same as
+the source dir)
+
+Fixes: 260a980317da ("[AFS]: Add "directory write" support.")
+Fixes: 30062bd13e36 ("afs: Implement YFS support in the fs client")
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/afs/dir.c | 13 +++----------
+ fs/afs/fsclient.c | 12 ++++++------
+ fs/afs/yfsclient.c | 8 +++-----
+ 3 files changed, 12 insertions(+), 21 deletions(-)
+
+--- a/fs/afs/dir.c
++++ b/fs/afs/dir.c
+@@ -1892,7 +1892,6 @@ static int afs_rename(struct inode *old_
+ if (afs_begin_vnode_operation(&fc, orig_dvnode, key, true)) {
+ afs_dataversion_t orig_data_version;
+ afs_dataversion_t new_data_version;
+- struct afs_status_cb *new_scb = &scb[1];
+
+ orig_data_version = orig_dvnode->status.data_version + 1;
+
+@@ -1904,7 +1903,6 @@ static int afs_rename(struct inode *old_
+ new_data_version = new_dvnode->status.data_version + 1;
+ } else {
+ new_data_version = orig_data_version;
+- new_scb = &scb[0];
+ }
+
+ while (afs_select_fileserver(&fc)) {
+@@ -1912,7 +1910,7 @@ static int afs_rename(struct inode *old_
+ fc.cb_break_2 = afs_calc_vnode_cb_break(new_dvnode);
+ afs_fs_rename(&fc, old_dentry->d_name.name,
+ new_dvnode, new_dentry->d_name.name,
+- &scb[0], new_scb);
++ &scb[0], &scb[1]);
+ }
+
+ afs_vnode_commit_status(&fc, orig_dvnode, fc.cb_break,
+@@ -1957,13 +1955,8 @@ static int afs_rename(struct inode *old_
+ * Note that if we ever implement RENAME_EXCHANGE, we'll have
+ * to update both dentries with opposing dir versions.
+ */
+- if (new_dvnode != orig_dvnode) {
+- afs_update_dentry_version(&fc, old_dentry, &scb[1]);
+- afs_update_dentry_version(&fc, new_dentry, &scb[1]);
+- } else {
+- afs_update_dentry_version(&fc, old_dentry, &scb[0]);
+- afs_update_dentry_version(&fc, new_dentry, &scb[0]);
+- }
++ afs_update_dentry_version(&fc, old_dentry, &scb[1]);
++ afs_update_dentry_version(&fc, new_dentry, &scb[1]);
+ d_move(old_dentry, new_dentry);
+ goto error_tmp;
+ }
+--- a/fs/afs/fsclient.c
++++ b/fs/afs/fsclient.c
+@@ -986,16 +986,16 @@ static int afs_deliver_fs_rename(struct
+ if (ret < 0)
+ return ret;
+
+- /* unmarshall the reply once we've received all of it */
++ /* If the two dirs are the same, we have two copies of the same status
++ * report, so we just decode it twice.
++ */
+ bp = call->buffer;
+ ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_dir_scb);
+ if (ret < 0)
+ return ret;
+- if (call->out_dir_scb != call->out_scb) {
+- ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
+- if (ret < 0)
+- return ret;
+- }
++ ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
++ if (ret < 0)
++ return ret;
+ xdr_decode_AFSVolSync(&bp, call->out_volsync);
+
+ _leave(" = 0 [done]");
+--- a/fs/afs/yfsclient.c
++++ b/fs/afs/yfsclient.c
+@@ -1157,11 +1157,9 @@ static int yfs_deliver_fs_rename(struct
+ ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_dir_scb);
+ if (ret < 0)
+ return ret;
+- if (call->out_dir_scb != call->out_scb) {
+- ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_scb);
+- if (ret < 0)
+- return ret;
+- }
++ ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_scb);
++ if (ret < 0)
++ return ret;
+
+ xdr_decode_YFSVolSync(&bp, call->out_volsync);
+ _leave(" = 0 [done]");
--- /dev/null
+From 25faa4bd37c10f19e4b848b9032a17a3d44c6f09 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Mon, 13 Apr 2020 10:20:29 +0200
+Subject: ALSA: hda: Don't release card at firmware loading error
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit 25faa4bd37c10f19e4b848b9032a17a3d44c6f09 upstream.
+
+At the error path of the firmware loading error, the driver tries to
+release the card object and set NULL to drvdata. This may be referred
+badly at the possible PM action, as the driver itself is still bound
+and the PM callbacks read the card object.
+
+Instead, we continue the probing as if it were no option set. This is
+often a better choice than the forced abort, too.
+
+Fixes: 5cb543dba986 ("ALSA: hda - Deferred probing with request_firmware_nowait()")
+BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=207043
+Link: https://lore.kernel.org/r/20200413082034.25166-2-tiwai@suse.de
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/pci/hda/hda_intel.c | 19 +++++--------------
+ 1 file changed, 5 insertions(+), 14 deletions(-)
+
+--- a/sound/pci/hda/hda_intel.c
++++ b/sound/pci/hda/hda_intel.c
+@@ -2031,24 +2031,15 @@ static void azx_firmware_cb(const struct
+ {
+ struct snd_card *card = context;
+ struct azx *chip = card->private_data;
+- struct pci_dev *pci = chip->pci;
+
+- if (!fw) {
+- dev_err(card->dev, "Cannot load firmware, aborting\n");
+- goto error;
+- }
+-
+- chip->fw = fw;
++ if (fw)
++ chip->fw = fw;
++ else
++ dev_err(card->dev, "Cannot load firmware, continue without patching\n");
+ if (!chip->disabled) {
+ /* continue probing */
+- if (azx_probe_continue(chip))
+- goto error;
++ azx_probe_continue(chip);
+ }
+- return; /* OK */
+-
+- error:
+- snd_card_free(card);
+- pci_set_drvdata(pci, NULL);
+ }
+ #endif
+
--- /dev/null
+From 4141f1a40fc0789f6fd4330e171e1edf155426aa Mon Sep 17 00:00:00 2001
+From: Martin Fuzzey <martin.fuzzey@flowbird.group>
+Date: Thu, 2 Apr 2020 15:51:28 +0200
+Subject: ARM: dts: imx6: Use gpc for FEC interrupt controller to fix wake on LAN.
+
+From: Martin Fuzzey <martin.fuzzey@flowbird.group>
+
+commit 4141f1a40fc0789f6fd4330e171e1edf155426aa upstream.
+
+In order to wake from suspend by ethernet magic packets the GPC
+must be used as intc does not have wakeup functionality.
+
+But the FEC DT node currently uses interrupt-extended,
+specificying intc, thus breaking WoL.
+
+This problem is probably fallout from the stacked domain conversion
+as intc used to chain to GPC.
+
+So replace "interrupts-extended" by "interrupts" to use the default
+parent which is GPC.
+
+Fixes: b923ff6af0d5 ("ARM: imx6: convert GPC to stacked domains")
+
+Signed-off-by: Martin Fuzzey <martin.fuzzey@flowbird.group>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/arm/boot/dts/imx6qdl.dtsi | 5 ++---
+ arch/arm/boot/dts/imx6qp.dtsi | 1 -
+ 2 files changed, 2 insertions(+), 4 deletions(-)
+
+--- a/arch/arm/boot/dts/imx6qdl.dtsi
++++ b/arch/arm/boot/dts/imx6qdl.dtsi
+@@ -1039,9 +1039,8 @@
+ compatible = "fsl,imx6q-fec";
+ reg = <0x02188000 0x4000>;
+ interrupt-names = "int0", "pps";
+- interrupts-extended =
+- <&intc 0 118 IRQ_TYPE_LEVEL_HIGH>,
+- <&intc 0 119 IRQ_TYPE_LEVEL_HIGH>;
++ interrupts = <0 118 IRQ_TYPE_LEVEL_HIGH>,
++ <0 119 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX6QDL_CLK_ENET>,
+ <&clks IMX6QDL_CLK_ENET>,
+ <&clks IMX6QDL_CLK_ENET_REF>;
+--- a/arch/arm/boot/dts/imx6qp.dtsi
++++ b/arch/arm/boot/dts/imx6qp.dtsi
+@@ -77,7 +77,6 @@
+ };
+
+ &fec {
+- /delete-property/interrupts-extended;
+ interrupts = <0 118 IRQ_TYPE_LEVEL_HIGH>,
+ <0 119 IRQ_TYPE_LEVEL_HIGH>;
+ };
--- /dev/null
+From edfc23f6f9fdbd7825d50ac1f380243cde19b679 Mon Sep 17 00:00:00 2001
+From: Zenghui Yu <yuzenghui@huawei.com>
+Date: Wed, 8 Apr 2020 19:43:52 +0800
+Subject: irqchip/mbigen: Free msi_desc on device teardown
+
+From: Zenghui Yu <yuzenghui@huawei.com>
+
+commit edfc23f6f9fdbd7825d50ac1f380243cde19b679 upstream.
+
+Using irq_domain_free_irqs_common() on the irqdomain free path will
+leave the MSI descriptor unfreed when platform devices get removed.
+Properly free it by MSI domain free function.
+
+Fixes: 9650c60ebfec0 ("irqchip/mbigen: Create irq domain for each mbigen device")
+Signed-off-by: Zenghui Yu <yuzenghui@huawei.com>
+Signed-off-by: Marc Zyngier <maz@kernel.org>
+Link: https://lore.kernel.org/r/20200408114352.1604-1-yuzenghui@huawei.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/irqchip/irq-mbigen.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/drivers/irqchip/irq-mbigen.c
++++ b/drivers/irqchip/irq-mbigen.c
+@@ -220,10 +220,16 @@ static int mbigen_irq_domain_alloc(struc
+ return 0;
+ }
+
++static void mbigen_irq_domain_free(struct irq_domain *domain, unsigned int virq,
++ unsigned int nr_irqs)
++{
++ platform_msi_domain_free(domain, virq, nr_irqs);
++}
++
+ static const struct irq_domain_ops mbigen_domain_ops = {
+ .translate = mbigen_domain_translate,
+ .alloc = mbigen_irq_domain_alloc,
+- .free = irq_domain_free_irqs_common,
++ .free = mbigen_irq_domain_free,
+ };
+
+ static int mbigen_of_create_domain(struct platform_device *pdev,
--- /dev/null
+From 7d32e69310d67e6b04af04f26193f79dfc2f05c7 Mon Sep 17 00:00:00 2001
+From: Slava Bacherikov <slava@bacher09.org>
+Date: Thu, 2 Apr 2020 23:41:39 +0300
+Subject: kbuild, btf: Fix dependencies for DEBUG_INFO_BTF
+
+From: Slava Bacherikov <slava@bacher09.org>
+
+commit 7d32e69310d67e6b04af04f26193f79dfc2f05c7 upstream.
+
+Currently turning on DEBUG_INFO_SPLIT when DEBUG_INFO_BTF is also
+enabled will produce invalid btf file, since gen_btf function in
+link-vmlinux.sh script doesn't handle *.dwo files.
+
+Enabling DEBUG_INFO_REDUCED will also produce invalid btf file,
+and using GCC_PLUGIN_RANDSTRUCT with BTF makes no sense.
+
+Fixes: e83b9f55448a ("kbuild: add ability to generate BTF type info for vmlinux")
+Reported-by: Jann Horn <jannh@google.com>
+Reported-by: Liu Yiding <liuyd.fnst@cn.fujitsu.com>
+Signed-off-by: Slava Bacherikov <slava@bacher09.org>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Reviewed-by: Kees Cook <keescook@chromium.org>
+Acked-by: KP Singh <kpsingh@google.com>
+Acked-by: Andrii Nakryiko <andriin@fb.com>
+Link: https://lore.kernel.org/bpf/20200402204138.408021-1-slava@bacher09.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ lib/Kconfig.debug | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/lib/Kconfig.debug
++++ b/lib/Kconfig.debug
+@@ -241,6 +241,8 @@ config DEBUG_INFO_DWARF4
+ config DEBUG_INFO_BTF
+ bool "Generate BTF typeinfo"
+ depends on DEBUG_INFO
++ depends on !DEBUG_INFO_SPLIT && !DEBUG_INFO_REDUCED
++ depends on !GCC_PLUGIN_RANDSTRUCT || COMPILE_TEST
+ help
+ Generate deduplicated BTF type information from DWARF debug info.
+ Turning this on expects presence of pahole tool, which will convert
--- /dev/null
+From d9583cdf2f38d0f526d9a8c8564dd2e35e649bc7 Mon Sep 17 00:00:00 2001
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Tue, 7 Apr 2020 14:10:11 +0200
+Subject: netfilter: nf_tables: report EOPNOTSUPP on unsupported flags/object type
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+commit d9583cdf2f38d0f526d9a8c8564dd2e35e649bc7 upstream.
+
+EINVAL should be used for malformed netlink messages. New userspace
+utility and old kernels might easily result in EINVAL when exercising
+new set features, which is misleading.
+
+Fixes: 8aeff920dcc9 ("netfilter: nf_tables: add stateful object reference to set elements")
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/netfilter/nf_tables_api.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -3950,7 +3950,7 @@ static int nf_tables_newset(struct net *
+ NFT_SET_INTERVAL | NFT_SET_TIMEOUT |
+ NFT_SET_MAP | NFT_SET_EVAL |
+ NFT_SET_OBJECT))
+- return -EINVAL;
++ return -EOPNOTSUPP;
+ /* Only one of these operations is supported */
+ if ((flags & (NFT_SET_MAP | NFT_SET_OBJECT)) ==
+ (NFT_SET_MAP | NFT_SET_OBJECT))
+@@ -3988,7 +3988,7 @@ static int nf_tables_newset(struct net *
+ objtype = ntohl(nla_get_be32(nla[NFTA_SET_OBJ_TYPE]));
+ if (objtype == NFT_OBJECT_UNSPEC ||
+ objtype > NFT_OBJECT_MAX)
+- return -EINVAL;
++ return -EOPNOTSUPP;
+ } else if (flags & NFT_SET_OBJECT)
+ return -EINVAL;
+ else
--- /dev/null
+From 478ff649b1c8eb2409b1a54fb75eb46f7c29f140 Mon Sep 17 00:00:00 2001
+From: Frank Rowand <frank.rowand@sony.com>
+Date: Thu, 16 Apr 2020 16:42:49 -0500
+Subject: of: overlay: kmemleak in dup_and_fixup_symbol_prop()
+
+From: Frank Rowand <frank.rowand@sony.com>
+
+commit 478ff649b1c8eb2409b1a54fb75eb46f7c29f140 upstream.
+
+kmemleak reports several memory leaks from devicetree unittest.
+This is the fix for problem 4 of 5.
+
+target_path was not freed in the non-error path.
+
+Fixes: e0a58f3e08d4 ("of: overlay: remove a dependency on device node full_name")
+Reported-by: Erhard F. <erhard_f@mailbox.org>
+Signed-off-by: Frank Rowand <frank.rowand@sony.com>
+Signed-off-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/of/overlay.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/of/overlay.c
++++ b/drivers/of/overlay.c
+@@ -261,6 +261,8 @@ static struct property *dup_and_fixup_sy
+
+ of_property_set_flag(new_prop, OF_DYNAMIC);
+
++ kfree(target_path);
++
+ return new_prop;
+
+ err_free_new_prop:
--- /dev/null
+From 145fc138f9aae4f9e1331352e301df28e16aed35 Mon Sep 17 00:00:00 2001
+From: Frank Rowand <frank.rowand@sony.com>
+Date: Thu, 16 Apr 2020 16:42:48 -0500
+Subject: of: unittest: kmemleak in of_unittest_overlay_high_level()
+
+From: Frank Rowand <frank.rowand@sony.com>
+
+commit 145fc138f9aae4f9e1331352e301df28e16aed35 upstream.
+
+kmemleak reports several memory leaks from devicetree unittest.
+This is the fix for problem 3 of 5.
+
+of_unittest_overlay_high_level() failed to kfree the newly created
+property when the property named 'name' is skipped.
+
+Fixes: 39a751a4cb7e ("of: change overlay apply input data from unflattened to FDT")
+Reported-by: Erhard F. <erhard_f@mailbox.org>
+Signed-off-by: Frank Rowand <frank.rowand@sony.com>
+Signed-off-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/of/unittest.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/of/unittest.c
++++ b/drivers/of/unittest.c
+@@ -2571,8 +2571,11 @@ static __init void of_unittest_overlay_h
+ goto err_unlock;
+ }
+ if (__of_add_property(of_symbols, new_prop)) {
++ kfree(new_prop->name);
++ kfree(new_prop->value);
++ kfree(new_prop);
+ /* "name" auto-generated by unflatten */
+- if (!strcmp(new_prop->name, "name"))
++ if (!strcmp(prop->name, "name"))
+ continue;
+ unittest(0, "duplicate property '%s' in overlay_base node __symbols__",
+ prop->name);
--- /dev/null
+From 216830d2413cc61be3f76bc02ffd905e47d2439e Mon Sep 17 00:00:00 2001
+From: Frank Rowand <frank.rowand@sony.com>
+Date: Thu, 16 Apr 2020 16:42:47 -0500
+Subject: of: unittest: kmemleak in of_unittest_platform_populate()
+
+From: Frank Rowand <frank.rowand@sony.com>
+
+commit 216830d2413cc61be3f76bc02ffd905e47d2439e upstream.
+
+kmemleak reports several memory leaks from devicetree unittest.
+This is the fix for problem 2 of 5.
+
+of_unittest_platform_populate() left an elevated reference count for
+grandchild nodes (which are platform devices). Fix the platform
+device reference counts so that the memory will be freed.
+
+Fixes: fb2caa50fbac ("of/selftest: add testcase for nodes with same name and address")
+Reported-by: Erhard F. <erhard_f@mailbox.org>
+Signed-off-by: Frank Rowand <frank.rowand@sony.com>
+Signed-off-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/of/unittest.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+--- a/drivers/of/unittest.c
++++ b/drivers/of/unittest.c
+@@ -1155,10 +1155,13 @@ static void __init of_unittest_platform_
+
+ of_platform_populate(np, match, NULL, &test_bus->dev);
+ for_each_child_of_node(np, child) {
+- for_each_child_of_node(child, grandchild)
+- unittest(of_find_device_by_node(grandchild),
++ for_each_child_of_node(child, grandchild) {
++ pdev = of_find_device_by_node(grandchild);
++ unittest(pdev,
+ "Could not create device for node '%pOFn'\n",
+ grandchild);
++ of_dev_put(pdev);
++ }
+ }
+
+ of_platform_depopulate(&test_bus->dev);
--- /dev/null
+From b3fb36ed694b05738d45218ea72cf7feb10ce2b1 Mon Sep 17 00:00:00 2001
+From: Frank Rowand <frank.rowand@sony.com>
+Date: Thu, 16 Apr 2020 16:42:46 -0500
+Subject: of: unittest: kmemleak on changeset destroy
+
+From: Frank Rowand <frank.rowand@sony.com>
+
+commit b3fb36ed694b05738d45218ea72cf7feb10ce2b1 upstream.
+
+kmemleak reports several memory leaks from devicetree unittest.
+This is the fix for problem 1 of 5.
+
+of_unittest_changeset() reaches deeply into the dynamic devicetree
+functions. Several nodes were left with an elevated reference
+count and thus were not properly cleaned up. Fix the reference
+counts so that the memory will be freed.
+
+Fixes: 201c910bd689 ("of: Transactional DT support.")
+Reported-by: Erhard F. <erhard_f@mailbox.org>
+Signed-off-by: Frank Rowand <frank.rowand@sony.com>
+Signed-off-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/of/unittest.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/of/unittest.c
++++ b/drivers/of/unittest.c
+@@ -777,6 +777,10 @@ static void __init of_unittest_changeset
+ unittest(!of_changeset_revert(&chgset), "revert failed\n");
+
+ of_changeset_destroy(&chgset);
++
++ of_node_put(n1);
++ of_node_put(n2);
++ of_node_put(n21);
+ #endif
+ }
+
--- /dev/null
+From 0e4e1de5b63fa423b13593337a27fd2d2b0bcf77 Mon Sep 17 00:00:00 2001
+From: Ilya Dryomov <idryomov@gmail.com>
+Date: Fri, 13 Mar 2020 11:20:51 +0100
+Subject: rbd: avoid a deadlock on header_rwsem when flushing notifies
+
+From: Ilya Dryomov <idryomov@gmail.com>
+
+commit 0e4e1de5b63fa423b13593337a27fd2d2b0bcf77 upstream.
+
+rbd_unregister_watch() flushes notifies and therefore cannot be called
+under header_rwsem because a header update notify takes header_rwsem to
+synchronize with "rbd map". If mapping an image fails after the watch
+is established and a header update notify sneaks in, we deadlock when
+erroring out from rbd_dev_image_probe().
+
+Move watch registration and unregistration out of the critical section.
+The only reason they were put there was to make header_rwsem management
+slightly more obvious.
+
+Fixes: 811c66887746 ("rbd: fix rbd map vs notify races")
+Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
+Reviewed-by: Jason Dillaman <dillaman@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/block/rbd.c | 17 +++++++++++++----
+ 1 file changed, 13 insertions(+), 4 deletions(-)
+
+--- a/drivers/block/rbd.c
++++ b/drivers/block/rbd.c
+@@ -4554,6 +4554,10 @@ static void cancel_tasks_sync(struct rbd
+ cancel_work_sync(&rbd_dev->unlock_work);
+ }
+
++/*
++ * header_rwsem must not be held to avoid a deadlock with
++ * rbd_dev_refresh() when flushing notifies.
++ */
+ static void rbd_unregister_watch(struct rbd_device *rbd_dev)
+ {
+ cancel_tasks_sync(rbd_dev);
+@@ -6964,6 +6968,9 @@ static void rbd_dev_image_release(struct
+ * device. If this image is the one being mapped (i.e., not a
+ * parent), initiate a watch on its header object before using that
+ * object to get detailed information about the rbd image.
++ *
++ * On success, returns with header_rwsem held for write if called
++ * with @depth == 0.
+ */
+ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth)
+ {
+@@ -6993,6 +7000,9 @@ static int rbd_dev_image_probe(struct rb
+ }
+ }
+
++ if (!depth)
++ down_write(&rbd_dev->header_rwsem);
++
+ ret = rbd_dev_header_info(rbd_dev);
+ if (ret) {
+ if (ret == -ENOENT && !need_watch)
+@@ -7044,6 +7054,8 @@ static int rbd_dev_image_probe(struct rb
+ err_out_probe:
+ rbd_dev_unprobe(rbd_dev);
+ err_out_watch:
++ if (!depth)
++ up_write(&rbd_dev->header_rwsem);
+ if (need_watch)
+ rbd_unregister_watch(rbd_dev);
+ err_out_format:
+@@ -7107,12 +7119,9 @@ static ssize_t do_rbd_add(struct bus_typ
+ goto err_out_rbd_dev;
+ }
+
+- down_write(&rbd_dev->header_rwsem);
+ rc = rbd_dev_image_probe(rbd_dev, 0);
+- if (rc < 0) {
+- up_write(&rbd_dev->header_rwsem);
++ if (rc < 0)
+ goto err_out_rbd_dev;
+- }
+
+ if (rbd_dev->opts->alloc_size > rbd_dev->layout.object_size) {
+ rbd_warn(rbd_dev, "alloc_size adjusted to %u",
--- /dev/null
+From 952c48b0ed18919bff7528501e9a3fff8a24f8cd Mon Sep 17 00:00:00 2001
+From: Ilya Dryomov <idryomov@gmail.com>
+Date: Mon, 16 Mar 2020 15:52:54 +0100
+Subject: rbd: call rbd_dev_unprobe() after unwatching and flushing notifies
+
+From: Ilya Dryomov <idryomov@gmail.com>
+
+commit 952c48b0ed18919bff7528501e9a3fff8a24f8cd upstream.
+
+rbd_dev_unprobe() is supposed to undo most of rbd_dev_image_probe(),
+including rbd_dev_header_info(), which means that rbd_dev_header_info()
+isn't supposed to be called after rbd_dev_unprobe().
+
+However, rbd_dev_image_release() calls rbd_dev_unprobe() before
+rbd_unregister_watch(). This is racy because a header update notify
+can sneak in:
+
+ "rbd unmap" thread ceph-watch-notify worker
+
+ rbd_dev_image_release()
+ rbd_dev_unprobe()
+ free and zero out header
+ rbd_watch_cb()
+ rbd_dev_refresh()
+ rbd_dev_header_info()
+ read in header
+
+The same goes for "rbd map" because rbd_dev_image_probe() calls
+rbd_dev_unprobe() on errors. In both cases this results in a memory
+leak.
+
+Fixes: fd22aef8b47c ("rbd: move rbd_unregister_watch() call into rbd_dev_image_release()")
+Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
+Reviewed-by: Jason Dillaman <dillaman@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/block/rbd.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/block/rbd.c
++++ b/drivers/block/rbd.c
+@@ -6955,9 +6955,10 @@ static void rbd_print_dne(struct rbd_dev
+
+ static void rbd_dev_image_release(struct rbd_device *rbd_dev)
+ {
+- rbd_dev_unprobe(rbd_dev);
+ if (rbd_dev->opts)
+ rbd_unregister_watch(rbd_dev);
++
++ rbd_dev_unprobe(rbd_dev);
+ rbd_dev->image_format = 0;
+ kfree(rbd_dev->spec->image_id);
+ rbd_dev->spec->image_id = NULL;
+@@ -7007,7 +7008,7 @@ static int rbd_dev_image_probe(struct rb
+ if (ret) {
+ if (ret == -ENOENT && !need_watch)
+ rbd_print_dne(rbd_dev, false);
+- goto err_out_watch;
++ goto err_out_probe;
+ }
+
+ /*
+@@ -7052,12 +7053,11 @@ static int rbd_dev_image_probe(struct rb
+ return 0;
+
+ err_out_probe:
+- rbd_dev_unprobe(rbd_dev);
+-err_out_watch:
+ if (!depth)
+ up_write(&rbd_dev->header_rwsem);
+ if (need_watch)
+ rbd_unregister_watch(rbd_dev);
++ rbd_dev_unprobe(rbd_dev);
+ err_out_format:
+ rbd_dev->image_format = 0;
+ kfree(rbd_dev->spec->image_id);
--- /dev/null
+From b8776051529230f76e464d5ffc5d1cf8465576bf Mon Sep 17 00:00:00 2001
+From: Ilya Dryomov <idryomov@gmail.com>
+Date: Mon, 16 Mar 2020 17:16:28 +0100
+Subject: rbd: don't test rbd_dev->opts in rbd_dev_image_release()
+
+From: Ilya Dryomov <idryomov@gmail.com>
+
+commit b8776051529230f76e464d5ffc5d1cf8465576bf upstream.
+
+rbd_dev->opts is used to distinguish between the image that is being
+mapped and a parent. However, because we no longer establish watch for
+read-only mappings, this test is imprecise and results in unnecessary
+rbd_unregister_watch() calls.
+
+Make it consistent with need_watch in rbd_dev_image_probe().
+
+Fixes: b9ef2b8858a0 ("rbd: don't establish watch for read-only mappings")
+Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
+Reviewed-by: Jason Dillaman <dillaman@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/block/rbd.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/block/rbd.c
++++ b/drivers/block/rbd.c
+@@ -6955,7 +6955,7 @@ static void rbd_print_dne(struct rbd_dev
+
+ static void rbd_dev_image_release(struct rbd_device *rbd_dev)
+ {
+- if (rbd_dev->opts)
++ if (!rbd_is_ro(rbd_dev))
+ rbd_unregister_watch(rbd_dev);
+
+ rbd_dev_unprobe(rbd_dev);
libbpf-fix-bpf_get_link_xdp_id-flags-handling.patch
arm-bpf-fix-bugs-with-alu64-rsh-arsh-bpf_k-shift-by-0.patch
bpf-prevent-re-mmap-ing-bpf-map-as-writable-for-initially-r-o-mapping.patch
+arm-dts-imx6-use-gpc-for-fec-interrupt-controller-to-fix-wake-on-lan.patch
+kbuild-btf-fix-dependencies-for-debug_info_btf.patch
+netfilter-nf_tables-report-eopnotsupp-on-unsupported-flags-object-type.patch
+irqchip-mbigen-free-msi_desc-on-device-teardown.patch
+rbd-avoid-a-deadlock-on-header_rwsem-when-flushing-notifies.patch
+rbd-call-rbd_dev_unprobe-after-unwatching-and-flushing-notifies.patch
+rbd-don-t-test-rbd_dev-opts-in-rbd_dev_image_release.patch
+alsa-hda-don-t-release-card-at-firmware-loading-error.patch
+xsk-add-missing-check-on-user-supplied-headroom-size.patch
+of-unittest-kmemleak-on-changeset-destroy.patch
+of-unittest-kmemleak-in-of_unittest_platform_populate.patch
+of-unittest-kmemleak-in-of_unittest_overlay_high_level.patch
+of-overlay-kmemleak-in-dup_and_fixup_symbol_prop.patch
+x86-hyper-v-unload-vmbus-channel-in-hv-panic-callback.patch
+x86-hyper-v-free-hv_panic_page-when-fail-to-register-kmsg-dump.patch
+x86-hyper-v-trigger-crash-enlightenment-only-once-during-system-crash.patch
+x86-hyper-v-report-crash-register-data-or-kmsg-before-running-crash-kernel.patch
+x86-hyper-v-report-crash-register-data-when-sysctl_record_panic_msg-is-not-set.patch
+x86-hyper-v-report-crash-data-in-die-when-panic_on_oops-is-set.patch
+afs-fix-missing-xdr-advance-in-xdr_decode_-afs-yfs-fsfetchstatus.patch
+afs-fix-decoding-of-inline-abort-codes-from-version-1-status-records.patch
+afs-fix-rename-operation-status-delivery.patch
+afs-fix-afs_d_validate-to-set-the-right-directory-version.patch
+afs-fix-race-between-post-modification-dir-edit-and-readdir-d_revalidate.patch
--- /dev/null
+From 7f11a2cc10a4ae3a70e2c73361f4a9a33503539b Mon Sep 17 00:00:00 2001
+From: Tianyu Lan <Tianyu.Lan@microsoft.com>
+Date: Mon, 6 Apr 2020 08:53:27 -0700
+Subject: x86/Hyper-V: Free hv_panic_page when fail to register kmsg dump
+
+From: Tianyu Lan <Tianyu.Lan@microsoft.com>
+
+commit 7f11a2cc10a4ae3a70e2c73361f4a9a33503539b upstream.
+
+If kmsg_dump_register() fails, hv_panic_page will not be used
+anywhere. So free and reset it.
+
+Fixes: 81b18bce48af ("Drivers: HV: Send one page worth of kmsg dump over Hyper-V during panic")
+Reviewed-by: Michael Kelley <mikelley@microsoft.com>
+Signed-off-by: Tianyu Lan <Tianyu.Lan@microsoft.com>
+Link: https://lore.kernel.org/r/20200406155331.2105-3-Tianyu.Lan@microsoft.com
+Signed-off-by: Wei Liu <wei.liu@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/hv/vmbus_drv.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+--- a/drivers/hv/vmbus_drv.c
++++ b/drivers/hv/vmbus_drv.c
+@@ -1385,9 +1385,13 @@ static int vmbus_bus_init(void)
+ hv_panic_page = (void *)hv_alloc_hyperv_zeroed_page();
+ if (hv_panic_page) {
+ ret = kmsg_dump_register(&hv_kmsg_dumper);
+- if (ret)
++ if (ret) {
+ pr_err("Hyper-V: kmsg dump register "
+ "error 0x%x\n", ret);
++ hv_free_hyperv_page(
++ (unsigned long)hv_panic_page);
++ hv_panic_page = NULL;
++ }
+ } else
+ pr_err("Hyper-V: panic message page memory "
+ "allocation failed");
+@@ -1416,7 +1420,6 @@ err_alloc:
+ hv_remove_vmbus_irq();
+
+ bus_unregister(&hv_bus);
+- hv_free_hyperv_page((unsigned long)hv_panic_page);
+ unregister_sysctl_table(hv_ctl_table_hdr);
+ hv_ctl_table_hdr = NULL;
+ return ret;
--- /dev/null
+From f3a99e761efa616028b255b4de58e9b5b87c5545 Mon Sep 17 00:00:00 2001
+From: Tianyu Lan <Tianyu.Lan@microsoft.com>
+Date: Mon, 6 Apr 2020 08:53:31 -0700
+Subject: x86/Hyper-V: Report crash data in die() when panic_on_oops is set
+
+From: Tianyu Lan <Tianyu.Lan@microsoft.com>
+
+commit f3a99e761efa616028b255b4de58e9b5b87c5545 upstream.
+
+When oops happens with panic_on_oops unset, the oops
+thread is killed by die() and system continues to run.
+In such case, guest should not report crash register
+data to host since system still runs. Check panic_on_oops
+and return directly in hyperv_report_panic() when the function
+is called in the die() and panic_on_oops is unset. Fix it.
+
+Fixes: 7ed4325a44ea ("Drivers: hv: vmbus: Make panic reporting to be more useful")
+Signed-off-by: Tianyu Lan <Tianyu.Lan@microsoft.com>
+Reviewed-by: Michael Kelley <mikelley@microsoft.com>
+Link: https://lore.kernel.org/r/20200406155331.2105-7-Tianyu.Lan@microsoft.com
+Signed-off-by: Wei Liu <wei.liu@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/hyperv/hv_init.c | 6 +++++-
+ drivers/hv/vmbus_drv.c | 5 +++--
+ include/asm-generic/mshyperv.h | 2 +-
+ 3 files changed, 9 insertions(+), 4 deletions(-)
+
+--- a/arch/x86/hyperv/hv_init.c
++++ b/arch/x86/hyperv/hv_init.c
+@@ -20,6 +20,7 @@
+ #include <linux/mm.h>
+ #include <linux/hyperv.h>
+ #include <linux/slab.h>
++#include <linux/kernel.h>
+ #include <linux/cpuhotplug.h>
+ #include <linux/syscore_ops.h>
+ #include <clocksource/hyperv_timer.h>
+@@ -419,11 +420,14 @@ void hyperv_cleanup(void)
+ }
+ EXPORT_SYMBOL_GPL(hyperv_cleanup);
+
+-void hyperv_report_panic(struct pt_regs *regs, long err)
++void hyperv_report_panic(struct pt_regs *regs, long err, bool in_die)
+ {
+ static bool panic_reported;
+ u64 guest_id;
+
++ if (in_die && !panic_on_oops)
++ return;
++
+ /*
+ * We prefer to report panic on 'die' chain as we have proper
+ * registers to report, but if we miss it (e.g. on BUG()) we need
+--- a/drivers/hv/vmbus_drv.c
++++ b/drivers/hv/vmbus_drv.c
+@@ -31,6 +31,7 @@
+ #include <linux/kdebug.h>
+ #include <linux/efi.h>
+ #include <linux/random.h>
++#include <linux/kernel.h>
+ #include <linux/syscore_ops.h>
+ #include <clocksource/hyperv_timer.h>
+ #include "hyperv_vmbus.h"
+@@ -75,7 +76,7 @@ static int hyperv_panic_event(struct not
+ if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE
+ && hyperv_report_reg()) {
+ regs = current_pt_regs();
+- hyperv_report_panic(regs, val);
++ hyperv_report_panic(regs, val, false);
+ }
+ return NOTIFY_DONE;
+ }
+@@ -92,7 +93,7 @@ static int hyperv_die_event(struct notif
+ * the notification here.
+ */
+ if (hyperv_report_reg())
+- hyperv_report_panic(regs, val);
++ hyperv_report_panic(regs, val, true);
+ return NOTIFY_DONE;
+ }
+
+--- a/include/asm-generic/mshyperv.h
++++ b/include/asm-generic/mshyperv.h
+@@ -163,7 +163,7 @@ static inline int cpumask_to_vpset(struc
+ return nr_bank;
+ }
+
+-void hyperv_report_panic(struct pt_regs *regs, long err);
++void hyperv_report_panic(struct pt_regs *regs, long err, bool in_die);
+ void hyperv_report_panic_msg(phys_addr_t pa, size_t size);
+ bool hv_is_hyperv_initialized(void);
+ bool hv_is_hibernation_supported(void);
--- /dev/null
+From a11589563e96bf262767294b89b25a9d44e7303b Mon Sep 17 00:00:00 2001
+From: Tianyu Lan <Tianyu.Lan@microsoft.com>
+Date: Mon, 6 Apr 2020 08:53:29 -0700
+Subject: x86/Hyper-V: Report crash register data or kmsg before running crash kernel
+
+From: Tianyu Lan <Tianyu.Lan@microsoft.com>
+
+commit a11589563e96bf262767294b89b25a9d44e7303b upstream.
+
+We want to notify Hyper-V when a Linux guest VM crash occurs, so
+there is a record of the crash even when kdump is enabled. But
+crash_kexec_post_notifiers defaults to "false", so the kdump kernel
+runs before the notifiers and Hyper-V never gets notified. Fix this by
+always setting crash_kexec_post_notifiers to be true for Hyper-V VMs.
+
+Fixes: 81b18bce48af ("Drivers: HV: Send one page worth of kmsg dump over Hyper-V during panic")
+Reviewed-by: Michael Kelley <mikelley@microsoft.com>
+Signed-off-by: Tianyu Lan <Tianyu.Lan@microsoft.com>
+Link: https://lore.kernel.org/r/20200406155331.2105-5-Tianyu.Lan@microsoft.com
+Signed-off-by: Wei Liu <wei.liu@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/kernel/cpu/mshyperv.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/arch/x86/kernel/cpu/mshyperv.c
++++ b/arch/x86/kernel/cpu/mshyperv.c
+@@ -263,6 +263,16 @@ static void __init ms_hyperv_init_platfo
+ cpuid_eax(HYPERV_CPUID_NESTED_FEATURES);
+ }
+
++ /*
++ * Hyper-V expects to get crash register data or kmsg when
++ * crash enlightment is available and system crashes. Set
++ * crash_kexec_post_notifiers to be true to make sure that
++ * calling crash enlightment interface before running kdump
++ * kernel.
++ */
++ if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE)
++ crash_kexec_post_notifiers = true;
++
+ #ifdef CONFIG_X86_LOCAL_APIC
+ if (ms_hyperv.features & HV_X64_ACCESS_FREQUENCY_MSRS &&
+ ms_hyperv.misc_features & HV_FEATURE_FREQUENCY_MSRS_AVAILABLE) {
--- /dev/null
+From 040026df7088c56ccbad28f7042308f67bde63df Mon Sep 17 00:00:00 2001
+From: Tianyu Lan <Tianyu.Lan@microsoft.com>
+Date: Mon, 6 Apr 2020 08:53:30 -0700
+Subject: x86/Hyper-V: Report crash register data when sysctl_record_panic_msg is not set
+
+From: Tianyu Lan <Tianyu.Lan@microsoft.com>
+
+commit 040026df7088c56ccbad28f7042308f67bde63df upstream.
+
+When sysctl_record_panic_msg is not set, the panic will
+not be reported to Hyper-V via hyperv_report_panic_msg().
+So the crash should be reported via hyperv_report_panic().
+
+Fixes: 81b18bce48af ("Drivers: HV: Send one page worth of kmsg dump over Hyper-V during panic")
+Reviewed-by: Michael Kelley <mikelley@microsoft.com>
+Signed-off-by: Tianyu Lan <Tianyu.Lan@microsoft.com>
+Link: https://lore.kernel.org/r/20200406155331.2105-6-Tianyu.Lan@microsoft.com
+Signed-off-by: Wei Liu <wei.liu@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/hv/vmbus_drv.c | 23 ++++++++++++++---------
+ 1 file changed, 14 insertions(+), 9 deletions(-)
+
+--- a/drivers/hv/vmbus_drv.c
++++ b/drivers/hv/vmbus_drv.c
+@@ -48,6 +48,18 @@ static int hyperv_cpuhp_online;
+
+ static void *hv_panic_page;
+
++/*
++ * Boolean to control whether to report panic messages over Hyper-V.
++ *
++ * It can be set via /proc/sys/kernel/hyperv/record_panic_msg
++ */
++static int sysctl_record_panic_msg = 1;
++
++static int hyperv_report_reg(void)
++{
++ return !sysctl_record_panic_msg || !hv_panic_page;
++}
++
+ static int hyperv_panic_event(struct notifier_block *nb, unsigned long val,
+ void *args)
+ {
+@@ -61,7 +73,7 @@ static int hyperv_panic_event(struct not
+ * the notification here.
+ */
+ if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE
+- && !hv_panic_page) {
++ && hyperv_report_reg()) {
+ regs = current_pt_regs();
+ hyperv_report_panic(regs, val);
+ }
+@@ -79,7 +91,7 @@ static int hyperv_die_event(struct notif
+ * doing hyperv_report_panic_msg() later with kmsg data, don't do
+ * the notification here.
+ */
+- if (!hv_panic_page)
++ if (hyperv_report_reg())
+ hyperv_report_panic(regs, val);
+ return NOTIFY_DONE;
+ }
+@@ -1268,13 +1280,6 @@ static void vmbus_isr(void)
+ }
+
+ /*
+- * Boolean to control whether to report panic messages over Hyper-V.
+- *
+- * It can be set via /proc/sys/kernel/hyperv/record_panic_msg
+- */
+-static int sysctl_record_panic_msg = 1;
+-
+-/*
+ * Callback from kmsg_dump. Grab as much as possible from the end of the kmsg
+ * buffer and call into Hyper-V to transfer the data.
+ */
--- /dev/null
+From 73f26e526f19afb3a06b76b970a76bcac2cafd05 Mon Sep 17 00:00:00 2001
+From: Tianyu Lan <Tianyu.Lan@microsoft.com>
+Date: Mon, 6 Apr 2020 08:53:28 -0700
+Subject: x86/Hyper-V: Trigger crash enlightenment only once during system crash.
+
+From: Tianyu Lan <Tianyu.Lan@microsoft.com>
+
+commit 73f26e526f19afb3a06b76b970a76bcac2cafd05 upstream.
+
+When a guest VM panics, Hyper-V should be notified only once via the
+crash synthetic MSRs. Current Linux code might write these crash MSRs
+twice during a system panic:
+1) hyperv_panic/die_event() calling hyperv_report_panic()
+2) hv_kmsg_dump() calling hyperv_report_panic_msg()
+
+Fix this by not calling hyperv_report_panic() if a kmsg dump has been
+successfully registered. The notification will happen later via
+hyperv_report_panic_msg().
+
+Fixes: 7ed4325a44ea ("Drivers: hv: vmbus: Make panic reporting to be more useful")
+Reviewed-by: Michael Kelley <mikelley@microsoft.com>
+Signed-off-by: Tianyu Lan <Tianyu.Lan@microsoft.com>
+Link: https://lore.kernel.org/r/20200406155331.2105-4-Tianyu.Lan@microsoft.com
+Signed-off-by: Wei Liu <wei.liu@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/hv/vmbus_drv.c | 16 ++++++++++++++--
+ 1 file changed, 14 insertions(+), 2 deletions(-)
+
+--- a/drivers/hv/vmbus_drv.c
++++ b/drivers/hv/vmbus_drv.c
+@@ -55,7 +55,13 @@ static int hyperv_panic_event(struct not
+
+ vmbus_initiate_unload(true);
+
+- if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE) {
++ /*
++ * Hyper-V should be notified only once about a panic. If we will be
++ * doing hyperv_report_panic_msg() later with kmsg data, don't do
++ * the notification here.
++ */
++ if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE
++ && !hv_panic_page) {
+ regs = current_pt_regs();
+ hyperv_report_panic(regs, val);
+ }
+@@ -68,7 +74,13 @@ static int hyperv_die_event(struct notif
+ struct die_args *die = (struct die_args *)args;
+ struct pt_regs *regs = die->regs;
+
+- hyperv_report_panic(regs, val);
++ /*
++ * Hyper-V should be notified only once about a panic. If we will be
++ * doing hyperv_report_panic_msg() later with kmsg data, don't do
++ * the notification here.
++ */
++ if (!hv_panic_page)
++ hyperv_report_panic(regs, val);
+ return NOTIFY_DONE;
+ }
+
--- /dev/null
+From 74347a99e73ae00b8385f1209aaea193c670f901 Mon Sep 17 00:00:00 2001
+From: Tianyu Lan <Tianyu.Lan@microsoft.com>
+Date: Mon, 6 Apr 2020 08:53:26 -0700
+Subject: x86/Hyper-V: Unload vmbus channel in hv panic callback
+
+From: Tianyu Lan <Tianyu.Lan@microsoft.com>
+
+commit 74347a99e73ae00b8385f1209aaea193c670f901 upstream.
+
+When kdump is not configured, a Hyper-V VM might still respond to
+network traffic after a kernel panic when kernel parameter panic=0.
+The panic CPU goes into an infinite loop with interrupts enabled,
+and the VMbus driver interrupt handler still works because the
+VMbus connection is unloaded only in the kdump path. The network
+responses make the other end of the connection think the VM is
+still functional even though it has panic'ed, which could affect any
+failover actions that should be taken.
+
+Fix this by unloading the VMbus connection during the panic process.
+vmbus_initiate_unload() could then be called twice (e.g., by
+hyperv_panic_event() and hv_crash_handler(), so reset the connection
+state in vmbus_initiate_unload() to ensure the unload is done only
+once.
+
+Fixes: 81b18bce48af ("Drivers: HV: Send one page worth of kmsg dump over Hyper-V during panic")
+Reviewed-by: Michael Kelley <mikelley@microsoft.com>
+Signed-off-by: Tianyu Lan <Tianyu.Lan@microsoft.com>
+Link: https://lore.kernel.org/r/20200406155331.2105-2-Tianyu.Lan@microsoft.com
+Signed-off-by: Wei Liu <wei.liu@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/hv/channel_mgmt.c | 3 +++
+ drivers/hv/vmbus_drv.c | 21 +++++++++++++--------
+ 2 files changed, 16 insertions(+), 8 deletions(-)
+
+--- a/drivers/hv/channel_mgmt.c
++++ b/drivers/hv/channel_mgmt.c
+@@ -839,6 +839,9 @@ void vmbus_initiate_unload(bool crash)
+ {
+ struct vmbus_channel_message_header hdr;
+
++ if (xchg(&vmbus_connection.conn_state, DISCONNECTED) == DISCONNECTED)
++ return;
++
+ /* Pre-Win2012R2 hosts don't support reconnect */
+ if (vmbus_proto_version < VERSION_WIN8_1)
+ return;
+--- a/drivers/hv/vmbus_drv.c
++++ b/drivers/hv/vmbus_drv.c
+@@ -53,9 +53,12 @@ static int hyperv_panic_event(struct not
+ {
+ struct pt_regs *regs;
+
+- regs = current_pt_regs();
++ vmbus_initiate_unload(true);
+
+- hyperv_report_panic(regs, val);
++ if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE) {
++ regs = current_pt_regs();
++ hyperv_report_panic(regs, val);
++ }
+ return NOTIFY_DONE;
+ }
+
+@@ -1391,10 +1394,16 @@ static int vmbus_bus_init(void)
+ }
+
+ register_die_notifier(&hyperv_die_block);
+- atomic_notifier_chain_register(&panic_notifier_list,
+- &hyperv_panic_block);
+ }
+
++ /*
++ * Always register the panic notifier because we need to unload
++ * the VMbus channel connection to prevent any VMbus
++ * activity after the VM panics.
++ */
++ atomic_notifier_chain_register(&panic_notifier_list,
++ &hyperv_panic_block);
++
+ vmbus_request_offers();
+
+ return 0;
+@@ -2204,8 +2213,6 @@ static int vmbus_bus_suspend(struct devi
+
+ vmbus_initiate_unload(false);
+
+- vmbus_connection.conn_state = DISCONNECTED;
+-
+ /* Reset the event for the next resume. */
+ reinit_completion(&vmbus_connection.ready_for_resume_event);
+
+@@ -2289,7 +2296,6 @@ static void hv_kexec_handler(void)
+ {
+ hv_stimer_global_cleanup();
+ vmbus_initiate_unload(false);
+- vmbus_connection.conn_state = DISCONNECTED;
+ /* Make sure conn_state is set as hv_synic_cleanup checks for it */
+ mb();
+ cpuhp_remove_state(hyperv_cpuhp_online);
+@@ -2306,7 +2312,6 @@ static void hv_crash_handler(struct pt_r
+ * doing the cleanup for current CPU only. This should be sufficient
+ * for kdump.
+ */
+- vmbus_connection.conn_state = DISCONNECTED;
+ cpu = smp_processor_id();
+ hv_stimer_cleanup(cpu);
+ hv_synic_disable_regs(cpu);
--- /dev/null
+From 99e3a236dd43d06c65af0a2ef9cb44306aef6e02 Mon Sep 17 00:00:00 2001
+From: Magnus Karlsson <magnus.karlsson@intel.com>
+Date: Tue, 14 Apr 2020 09:35:15 +0200
+Subject: xsk: Add missing check on user supplied headroom size
+
+From: Magnus Karlsson <magnus.karlsson@intel.com>
+
+commit 99e3a236dd43d06c65af0a2ef9cb44306aef6e02 upstream.
+
+Add a check that the headroom cannot be larger than the available
+space in the chunk. In the current code, a malicious user can set the
+headroom to a value larger than the chunk size minus the fixed XDP
+headroom. That way packets with a length larger than the supported
+size in the umem could get accepted and result in an out-of-bounds
+write.
+
+Fixes: c0c77d8fb787 ("xsk: add user memory registration support sockopt")
+Reported-by: Bui Quang Minh <minhquangbui99@gmail.com>
+Signed-off-by: Magnus Karlsson <magnus.karlsson@intel.com>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=207225
+Link: https://lore.kernel.org/bpf/1586849715-23490-1-git-send-email-magnus.karlsson@intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/xdp/xdp_umem.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+--- a/net/xdp/xdp_umem.c
++++ b/net/xdp/xdp_umem.c
+@@ -343,7 +343,7 @@ static int xdp_umem_reg(struct xdp_umem
+ u32 chunk_size = mr->chunk_size, headroom = mr->headroom;
+ unsigned int chunks, chunks_per_page;
+ u64 addr = mr->addr, size = mr->len;
+- int size_chk, err;
++ int err;
+
+ if (chunk_size < XDP_UMEM_MIN_CHUNK_SIZE || chunk_size > PAGE_SIZE) {
+ /* Strictly speaking we could support this, if:
+@@ -382,8 +382,7 @@ static int xdp_umem_reg(struct xdp_umem
+ return -EINVAL;
+ }
+
+- size_chk = chunk_size - headroom - XDP_PACKET_HEADROOM;
+- if (size_chk < 0)
++ if (headroom >= chunk_size - XDP_PACKET_HEADROOM)
+ return -EINVAL;
+
+ umem->address = (unsigned long)addr;