From: Greg Kroah-Hartman Date: Mon, 1 Apr 2013 21:39:29 +0000 (-0700) Subject: 3.8-stable patches X-Git-Tag: v3.8.6~43 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5032c5c6bcfb5cc033b1b4983b3a4677dde1a40f;p=thirdparty%2Fkernel%2Fstable-queue.git 3.8-stable patches added patches: mwifiex-cancel-cmd-timer-and-free-curr_cmd-in-shutdown-process.patch mwifiex-fix-race-when-queuing-commands.patch mwifiex-skip-pending-commands-after-function-shutdown.patch nest-rename_lock-inside-vfsmount_lock.patch net-irda-add-missing-error-path-release_sock-call.patch nfsv4.1-always-clear-the-nfs_ino_layoutcommit-in-layoutreturn.patch nfsv4.1-fix-a-race-in-pnfs-layoutcommit.patch nfsv4-fix-the-string-length-returned-by-the-idmapper.patch pnfs-block-removing-dm-device-maybe-cause-oops-when-call-dev_remove.patch tty-atmel_serial_probe-index-of-atmel_ports-fix.patch usb-ehci-fix-bug-in-itd-sitd-dma-pool-allocation.patch usb-ftdi_sio-add-support-for-mitsubishi-fx-usb-aw-bd.patch usb-xhci-fix-trb-transfer-length-macro-used-for-event-trb.patch vt-synchronize_rcu-under-spinlock-is-not-nice.patch xen-blkback-correctly-respond-to-unknown-non-native-requests.patch xen-blkback-fix-dispatch_rw_block_io-error-path.patch xen-blkfront-switch-from-llist-to-list.patch xen-pciback-notify-hypervisor-about-devices-intended-to-be-assigned-to-guests.patch --- diff --git a/queue-3.8/mwifiex-cancel-cmd-timer-and-free-curr_cmd-in-shutdown-process.patch b/queue-3.8/mwifiex-cancel-cmd-timer-and-free-curr_cmd-in-shutdown-process.patch new file mode 100644 index 00000000000..8b827e25d6a --- /dev/null +++ b/queue-3.8/mwifiex-cancel-cmd-timer-and-free-curr_cmd-in-shutdown-process.patch @@ -0,0 +1,40 @@ +From 084c7189acb3f969c855536166042e27f5dd703f Mon Sep 17 00:00:00 2001 +From: Bing Zhao +Date: Fri, 15 Mar 2013 18:47:07 -0700 +Subject: mwifiex: cancel cmd timer and free curr_cmd in shutdown process + +From: Bing Zhao + +commit 084c7189acb3f969c855536166042e27f5dd703f upstream. + +curr_cmd points to the command that is in processing or waiting +for its command response from firmware. If the function shutdown +happens to occur at this time we should cancel the cmd timer and +put the command back to free queue. + +Tested-by: Marco Cesarano +Signed-off-by: Bing Zhao +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/mwifiex/init.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/drivers/net/wireless/mwifiex/init.c ++++ b/drivers/net/wireless/mwifiex/init.c +@@ -707,6 +707,14 @@ mwifiex_shutdown_drv(struct mwifiex_adap + return ret; + } + ++ /* cancel current command */ ++ if (adapter->curr_cmd) { ++ dev_warn(adapter->dev, "curr_cmd is still in processing\n"); ++ del_timer(&adapter->cmd_timer); ++ mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd); ++ adapter->curr_cmd = NULL; ++ } ++ + /* shut down mwifiex */ + dev_dbg(adapter->dev, "info: shutdown mwifiex...\n"); + diff --git a/queue-3.8/mwifiex-fix-race-when-queuing-commands.patch b/queue-3.8/mwifiex-fix-race-when-queuing-commands.patch new file mode 100644 index 00000000000..d426b2a77ee --- /dev/null +++ b/queue-3.8/mwifiex-fix-race-when-queuing-commands.patch @@ -0,0 +1,138 @@ +From 00d7ea11ff0783e24fe70778f3141270b561aaa1 Mon Sep 17 00:00:00 2001 +From: Amitkumar Karwar +Date: Fri, 15 Mar 2013 18:47:05 -0700 +Subject: mwifiex: fix race when queuing commands + +From: Amitkumar Karwar + +commit 00d7ea11ff0783e24fe70778f3141270b561aaa1 upstream. + +Running the following script repeatedly on XO-4 with SD8787 +produces command timeout and system lockup. + +insmod mwifiex_sdio.ko +sleep 1 +ifconfig eth0 up +iwlist eth0 scan & +sleep 0.5 +rmmod mwifiex_sdio + +mwifiex_send_cmd_async() is called for sync as well as async +commands. (mwifiex_send_cmd_sync() internally calls it for +sync command.) + +"adapter->cmd_queued" gets filled inside mwifiex_send_cmd_async() +routine for both types of commands. But it is used only for sync +commands in mwifiex_wait_queue_complete(). This could lead to a +race when two threads try to queue a sync command with another +sync/async command simultaneously. + +Get rid of global variable and pass command node as a parameter +to mwifiex_wait_queue_complete() to fix the problem. + +Reported-by: Daniel Drake +Tested-by: Daniel Drake +Tested-by: Marco Cesarano +Signed-off-by: Amitkumar Karwar +Signed-off-by: Bing Zhao +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/mwifiex/cmdevt.c | 5 ++--- + drivers/net/wireless/mwifiex/main.h | 4 ++-- + drivers/net/wireless/mwifiex/scan.c | 8 ++++---- + drivers/net/wireless/mwifiex/sta_ioctl.c | 10 ++-------- + 4 files changed, 10 insertions(+), 17 deletions(-) + +--- a/drivers/net/wireless/mwifiex/cmdevt.c ++++ b/drivers/net/wireless/mwifiex/cmdevt.c +@@ -488,8 +488,6 @@ int mwifiex_send_cmd_sync(struct mwifiex + + ret = mwifiex_send_cmd_async(priv, cmd_no, cmd_action, cmd_oid, + data_buf); +- if (!ret) +- ret = mwifiex_wait_queue_complete(adapter); + + return ret; + } +@@ -592,9 +590,10 @@ int mwifiex_send_cmd_async(struct mwifie + if (cmd_no == HostCmd_CMD_802_11_SCAN) { + mwifiex_queue_scan_cmd(priv, cmd_node); + } else { +- adapter->cmd_queued = cmd_node; + mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true); + queue_work(adapter->workqueue, &adapter->main_work); ++ if (cmd_node->wait_q_enabled) ++ ret = mwifiex_wait_queue_complete(adapter, cmd_node); + } + + return ret; +--- a/drivers/net/wireless/mwifiex/main.h ++++ b/drivers/net/wireless/mwifiex/main.h +@@ -714,7 +714,6 @@ struct mwifiex_adapter { + u16 cmd_wait_q_required; + struct mwifiex_wait_queue cmd_wait_q; + u8 scan_wait_q_woken; +- struct cmd_ctrl_node *cmd_queued; + spinlock_t queue_lock; /* lock for tx queues */ + struct completion fw_load; + u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; +@@ -994,7 +993,8 @@ int mwifiex_request_set_multicast_list(s + struct mwifiex_multicast_list *mcast_list); + int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist, + struct net_device *dev); +-int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter); ++int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter, ++ struct cmd_ctrl_node *cmd_queued); + int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, + struct cfg80211_ssid *req_ssid); + int mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type); +--- a/drivers/net/wireless/mwifiex/scan.c ++++ b/drivers/net/wireless/mwifiex/scan.c +@@ -1366,10 +1366,13 @@ int mwifiex_scan_networks(struct mwifiex + list_del(&cmd_node->list); + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, + flags); +- adapter->cmd_queued = cmd_node; + mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, + true); + queue_work(adapter->workqueue, &adapter->main_work); ++ ++ /* Perform internal scan synchronously */ ++ if (!priv->scan_request) ++ mwifiex_wait_queue_complete(adapter, cmd_node); + } else { + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, + flags); +@@ -1923,9 +1926,6 @@ int mwifiex_request_scan(struct mwifiex_ + /* Normal scan */ + ret = mwifiex_scan_networks(priv, NULL); + +- if (!ret) +- ret = mwifiex_wait_queue_complete(priv->adapter); +- + up(&priv->async_sem); + + return ret; +--- a/drivers/net/wireless/mwifiex/sta_ioctl.c ++++ b/drivers/net/wireless/mwifiex/sta_ioctl.c +@@ -54,16 +54,10 @@ int mwifiex_copy_mcast_addr(struct mwifi + * This function waits on a cmd wait queue. It also cancels the pending + * request after waking up, in case of errors. + */ +-int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter) ++int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter, ++ struct cmd_ctrl_node *cmd_queued) + { + int status; +- struct cmd_ctrl_node *cmd_queued; +- +- if (!adapter->cmd_queued) +- return 0; +- +- cmd_queued = adapter->cmd_queued; +- adapter->cmd_queued = NULL; + + dev_dbg(adapter->dev, "cmd pending\n"); + atomic_inc(&adapter->cmd_pending); diff --git a/queue-3.8/mwifiex-skip-pending-commands-after-function-shutdown.patch b/queue-3.8/mwifiex-skip-pending-commands-after-function-shutdown.patch new file mode 100644 index 00000000000..0a9d29adabf --- /dev/null +++ b/queue-3.8/mwifiex-skip-pending-commands-after-function-shutdown.patch @@ -0,0 +1,60 @@ +From a3e240cacc93a06bff3313e28938e980d01a2160 Mon Sep 17 00:00:00 2001 +From: Bing Zhao +Date: Fri, 15 Mar 2013 18:47:06 -0700 +Subject: mwifiex: skip pending commands after function shutdown + +From: Bing Zhao + +commit a3e240cacc93a06bff3313e28938e980d01a2160 upstream. + +During rmmod mwifiex_sdio processing FUNC_SHUTDOWN command is +sent to firmware. Firmware expcets only FUNC_INIT once WLAN +function is shut down. + +Any command pending in the command queue should be ignored and +freed. + +Tested-by: Daniel Drake +Tested-by: Marco Cesarano +Signed-off-by: Bing Zhao +Signed-off-by: Amitkumar Karwar +Signed-off-by: John W. Linville +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/mwifiex/cmdevt.c | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +--- a/drivers/net/wireless/mwifiex/cmdevt.c ++++ b/drivers/net/wireless/mwifiex/cmdevt.c +@@ -156,6 +156,20 @@ static int mwifiex_dnld_cmd_to_fw(struct + return -1; + } + ++ cmd_code = le16_to_cpu(host_cmd->command); ++ cmd_size = le16_to_cpu(host_cmd->size); ++ ++ if (adapter->hw_status == MWIFIEX_HW_STATUS_RESET && ++ cmd_code != HostCmd_CMD_FUNC_SHUTDOWN && ++ cmd_code != HostCmd_CMD_FUNC_INIT) { ++ dev_err(adapter->dev, ++ "DNLD_CMD: FW in reset state, ignore cmd %#x\n", ++ cmd_code); ++ mwifiex_complete_cmd(adapter, cmd_node); ++ mwifiex_insert_cmd_to_free_q(adapter, cmd_node); ++ return -1; ++ } ++ + /* Set command sequence number */ + adapter->seq_num++; + host_cmd->seq_num = cpu_to_le16(HostCmd_SET_SEQ_NO_BSS_INFO +@@ -167,9 +181,6 @@ static int mwifiex_dnld_cmd_to_fw(struct + adapter->curr_cmd = cmd_node; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + +- cmd_code = le16_to_cpu(host_cmd->command); +- cmd_size = le16_to_cpu(host_cmd->size); +- + /* Adjust skb length */ + if (cmd_node->cmd_skb->len > cmd_size) + /* diff --git a/queue-3.8/nest-rename_lock-inside-vfsmount_lock.patch b/queue-3.8/nest-rename_lock-inside-vfsmount_lock.patch new file mode 100644 index 00000000000..09b06ce7931 --- /dev/null +++ b/queue-3.8/nest-rename_lock-inside-vfsmount_lock.patch @@ -0,0 +1,119 @@ +From 7ea600b5314529f9d1b9d6d3c41cb26fce6a7a4a Mon Sep 17 00:00:00 2001 +From: Al Viro +Date: Tue, 26 Mar 2013 18:25:57 -0400 +Subject: Nest rename_lock inside vfsmount_lock + +From: Al Viro + +commit 7ea600b5314529f9d1b9d6d3c41cb26fce6a7a4a upstream. + +... lest we get livelocks between path_is_under() and d_path() and friends. + +The thing is, wrt fairness lglocks are more similar to rwsems than to rwlocks; +it is possible to have thread B spin on attempt to take lock shared while thread +A is already holding it shared, if B is on lower-numbered CPU than A and there's +a thread C spinning on attempt to take the same lock exclusive. + +As the result, we need consistent ordering between vfsmount_lock (lglock) and +rename_lock (seq_lock), even though everything that takes both is going to take +vfsmount_lock only shared. + +Spotted-by: Brad Spengler +Signed-off-by: Al Viro +Signed-off-by: Greg Kroah-Hartman + +--- + fs/dcache.c | 16 +++++++++++----- + 1 file changed, 11 insertions(+), 5 deletions(-) + +--- a/fs/dcache.c ++++ b/fs/dcache.c +@@ -2552,7 +2552,6 @@ static int prepend_path(const struct pat + bool slash = false; + int error = 0; + +- br_read_lock(&vfsmount_lock); + while (dentry != root->dentry || vfsmnt != root->mnt) { + struct dentry * parent; + +@@ -2582,8 +2581,6 @@ static int prepend_path(const struct pat + if (!error && !slash) + error = prepend(buffer, buflen, "/", 1); + +-out: +- br_read_unlock(&vfsmount_lock); + return error; + + global_root: +@@ -2600,7 +2597,7 @@ global_root: + error = prepend(buffer, buflen, "/", 1); + if (!error) + error = is_mounted(vfsmnt) ? 1 : 2; +- goto out; ++ return error; + } + + /** +@@ -2627,9 +2624,11 @@ char *__d_path(const struct path *path, + int error; + + prepend(&res, &buflen, "\0", 1); ++ br_read_lock(&vfsmount_lock); + write_seqlock(&rename_lock); + error = prepend_path(path, root, &res, &buflen); + write_sequnlock(&rename_lock); ++ br_read_unlock(&vfsmount_lock); + + if (error < 0) + return ERR_PTR(error); +@@ -2646,9 +2645,11 @@ char *d_absolute_path(const struct path + int error; + + prepend(&res, &buflen, "\0", 1); ++ br_read_lock(&vfsmount_lock); + write_seqlock(&rename_lock); + error = prepend_path(path, &root, &res, &buflen); + write_sequnlock(&rename_lock); ++ br_read_unlock(&vfsmount_lock); + + if (error > 1) + error = -EINVAL; +@@ -2712,11 +2713,13 @@ char *d_path(const struct path *path, ch + return path->dentry->d_op->d_dname(path->dentry, buf, buflen); + + get_fs_root(current->fs, &root); ++ br_read_lock(&vfsmount_lock); + write_seqlock(&rename_lock); + error = path_with_deleted(path, &root, &res, &buflen); ++ write_sequnlock(&rename_lock); ++ br_read_unlock(&vfsmount_lock); + if (error < 0) + res = ERR_PTR(error); +- write_sequnlock(&rename_lock); + path_put(&root); + return res; + } +@@ -2871,6 +2874,7 @@ SYSCALL_DEFINE2(getcwd, char __user *, b + get_fs_root_and_pwd(current->fs, &root, &pwd); + + error = -ENOENT; ++ br_read_lock(&vfsmount_lock); + write_seqlock(&rename_lock); + if (!d_unlinked(pwd.dentry)) { + unsigned long len; +@@ -2880,6 +2884,7 @@ SYSCALL_DEFINE2(getcwd, char __user *, b + prepend(&cwd, &buflen, "\0", 1); + error = prepend_path(&pwd, &root, &cwd, &buflen); + write_sequnlock(&rename_lock); ++ br_read_unlock(&vfsmount_lock); + + if (error < 0) + goto out; +@@ -2900,6 +2905,7 @@ SYSCALL_DEFINE2(getcwd, char __user *, b + } + } else { + write_sequnlock(&rename_lock); ++ br_read_unlock(&vfsmount_lock); + } + + out: diff --git a/queue-3.8/net-irda-add-missing-error-path-release_sock-call.patch b/queue-3.8/net-irda-add-missing-error-path-release_sock-call.patch new file mode 100644 index 00000000000..3db28376475 --- /dev/null +++ b/queue-3.8/net-irda-add-missing-error-path-release_sock-call.patch @@ -0,0 +1,36 @@ +From 896ee0eee6261e30c3623be931c3f621428947df Mon Sep 17 00:00:00 2001 +From: Kees Cook +Date: Wed, 20 Mar 2013 05:19:24 +0000 +Subject: net/irda: add missing error path release_sock call + +From: Kees Cook + +commit 896ee0eee6261e30c3623be931c3f621428947df upstream. + +This makes sure that release_sock is called for all error conditions in +irda_getsockopt. + +Signed-off-by: Kees Cook +Reported-by: Brad Spengler +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + net/irda/af_irda.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/net/irda/af_irda.c ++++ b/net/irda/af_irda.c +@@ -2584,8 +2584,10 @@ bed: + NULL, NULL, NULL); + + /* Check if the we got some results */ +- if (!self->cachedaddr) +- return -EAGAIN; /* Didn't find any devices */ ++ if (!self->cachedaddr) { ++ err = -EAGAIN; /* Didn't find any devices */ ++ goto out; ++ } + daddr = self->cachedaddr; + /* Cleanup */ + self->cachedaddr = 0; diff --git a/queue-3.8/nfsv4-fix-the-string-length-returned-by-the-idmapper.patch b/queue-3.8/nfsv4-fix-the-string-length-returned-by-the-idmapper.patch new file mode 100644 index 00000000000..82cc2cd8173 --- /dev/null +++ b/queue-3.8/nfsv4-fix-the-string-length-returned-by-the-idmapper.patch @@ -0,0 +1,64 @@ +From cf4ab538f1516606d3ae730dce15d6f33d96b7e1 Mon Sep 17 00:00:00 2001 +From: Trond Myklebust +Date: Fri, 8 Mar 2013 12:56:37 -0500 +Subject: NFSv4: Fix the string length returned by the idmapper + +From: Trond Myklebust + +commit cf4ab538f1516606d3ae730dce15d6f33d96b7e1 upstream. + +Functions like nfs_map_uid_to_name() and nfs_map_gid_to_group() are +expected to return a string without any terminating NUL character. +Regression introduced by commit 57e62324e469e092ecc6c94a7a86fe4bd6ac5172 +(NFS: Store the legacy idmapper result in the keyring). + +Reported-by: Dave Chiluk +Signed-off-by: Trond Myklebust +Cc: Bryan Schumaker +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfs/idmap.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +--- a/fs/nfs/idmap.c ++++ b/fs/nfs/idmap.c +@@ -725,9 +725,9 @@ out1: + return ret; + } + +-static int nfs_idmap_instantiate(struct key *key, struct key *authkey, char *data) ++static int nfs_idmap_instantiate(struct key *key, struct key *authkey, char *data, size_t datalen) + { +- return key_instantiate_and_link(key, data, strlen(data) + 1, ++ return key_instantiate_and_link(key, data, datalen, + id_resolver_cache->thread_keyring, + authkey); + } +@@ -737,6 +737,7 @@ static int nfs_idmap_read_and_verify_mes + struct key *key, struct key *authkey) + { + char id_str[NFS_UINT_MAXLEN]; ++ size_t len; + int ret = -ENOKEY; + + /* ret = -ENOKEY */ +@@ -746,13 +747,15 @@ static int nfs_idmap_read_and_verify_mes + case IDMAP_CONV_NAMETOID: + if (strcmp(upcall->im_name, im->im_name) != 0) + break; +- sprintf(id_str, "%d", im->im_id); +- ret = nfs_idmap_instantiate(key, authkey, id_str); ++ /* Note: here we store the NUL terminator too */ ++ len = sprintf(id_str, "%d", im->im_id) + 1; ++ ret = nfs_idmap_instantiate(key, authkey, id_str, len); + break; + case IDMAP_CONV_IDTONAME: + if (upcall->im_id != im->im_id) + break; +- ret = nfs_idmap_instantiate(key, authkey, im->im_name); ++ len = strlen(im->im_name); ++ ret = nfs_idmap_instantiate(key, authkey, im->im_name, len); + break; + default: + ret = -EINVAL; diff --git a/queue-3.8/nfsv4.1-always-clear-the-nfs_ino_layoutcommit-in-layoutreturn.patch b/queue-3.8/nfsv4.1-always-clear-the-nfs_ino_layoutcommit-in-layoutreturn.patch new file mode 100644 index 00000000000..39d8a22f11e --- /dev/null +++ b/queue-3.8/nfsv4.1-always-clear-the-nfs_ino_layoutcommit-in-layoutreturn.patch @@ -0,0 +1,121 @@ +From 24956804349ca0eadcdde032d65e8c00b4214096 Mon Sep 17 00:00:00 2001 +From: Trond Myklebust +Date: Wed, 20 Mar 2013 13:03:00 -0400 +Subject: NFSv4.1: Always clear the NFS_INO_LAYOUTCOMMIT in layoutreturn + +From: Trond Myklebust + +commit 24956804349ca0eadcdde032d65e8c00b4214096 upstream. + +Note that clearing NFS_INO_LAYOUTCOMMIT is tricky, since it requires +you to also clear the NFS_LSEG_LAYOUTCOMMIT bits from the layout +segments. +The only two sites that need to do this are the ones that call +pnfs_return_layout() without first doing a layout commit. + +Signed-off-by: Trond Myklebust +Acked-by: Benny Halevy +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfs/nfs4filelayout.c | 1 - + fs/nfs/pnfs.c | 35 +++++++++++++++++++++++++++-------- + 2 files changed, 27 insertions(+), 9 deletions(-) + +--- a/fs/nfs/nfs4filelayout.c ++++ b/fs/nfs/nfs4filelayout.c +@@ -129,7 +129,6 @@ static void filelayout_fenceme(struct in + { + if (!test_and_clear_bit(NFS_LAYOUT_RETURN, &lo->plh_flags)) + return; +- clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(inode)->flags); + pnfs_return_layout(inode); + } + +--- a/fs/nfs/pnfs.c ++++ b/fs/nfs/pnfs.c +@@ -417,6 +417,16 @@ should_free_lseg(struct pnfs_layout_rang + lo_seg_intersecting(lseg_range, recall_range); + } + ++static bool pnfs_lseg_dec_and_remove_zero(struct pnfs_layout_segment *lseg, ++ struct list_head *tmp_list) ++{ ++ if (!atomic_dec_and_test(&lseg->pls_refcount)) ++ return false; ++ pnfs_layout_remove_lseg(lseg->pls_layout, lseg); ++ list_add(&lseg->pls_list, tmp_list); ++ return true; ++} ++ + /* Returns 1 if lseg is removed from list, 0 otherwise */ + static int mark_lseg_invalid(struct pnfs_layout_segment *lseg, + struct list_head *tmp_list) +@@ -430,11 +440,8 @@ static int mark_lseg_invalid(struct pnfs + */ + dprintk("%s: lseg %p ref %d\n", __func__, lseg, + atomic_read(&lseg->pls_refcount)); +- if (atomic_dec_and_test(&lseg->pls_refcount)) { +- pnfs_layout_remove_lseg(lseg->pls_layout, lseg); +- list_add(&lseg->pls_list, tmp_list); ++ if (pnfs_lseg_dec_and_remove_zero(lseg, tmp_list)) + rv = 1; +- } + } + return rv; + } +@@ -777,6 +784,21 @@ send_layoutget(struct pnfs_layout_hdr *l + return lseg; + } + ++static void pnfs_clear_layoutcommit(struct inode *inode, ++ struct list_head *head) ++{ ++ struct nfs_inode *nfsi = NFS_I(inode); ++ struct pnfs_layout_segment *lseg, *tmp; ++ ++ if (!test_and_clear_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) ++ return; ++ list_for_each_entry_safe(lseg, tmp, &nfsi->layout->plh_segs, pls_list) { ++ if (!test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags)) ++ continue; ++ pnfs_lseg_dec_and_remove_zero(lseg, head); ++ } ++} ++ + /* + * Initiates a LAYOUTRETURN(FILE), and removes the pnfs_layout_hdr + * when the layout segment list is empty. +@@ -808,6 +830,7 @@ _pnfs_return_layout(struct inode *ino) + /* Reference matched in nfs4_layoutreturn_release */ + pnfs_get_layout_hdr(lo); + empty = list_empty(&lo->plh_segs); ++ pnfs_clear_layoutcommit(ino, &tmp_list); + pnfs_mark_matching_lsegs_invalid(lo, &tmp_list, NULL); + /* Don't send a LAYOUTRETURN if list was initially empty */ + if (empty) { +@@ -820,8 +843,6 @@ _pnfs_return_layout(struct inode *ino) + spin_unlock(&ino->i_lock); + pnfs_free_lseg_list(&tmp_list); + +- WARN_ON(test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)); +- + lrp = kzalloc(sizeof(*lrp), GFP_KERNEL); + if (unlikely(lrp == NULL)) { + status = -ENOMEM; +@@ -1459,7 +1480,6 @@ static void pnfs_ld_handle_write_error(s + dprintk("pnfs write error = %d\n", hdr->pnfs_error); + if (NFS_SERVER(hdr->inode)->pnfs_curr_ld->flags & + PNFS_LAYOUTRET_ON_ERROR) { +- clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(hdr->inode)->flags); + pnfs_return_layout(hdr->inode); + } + if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) +@@ -1614,7 +1634,6 @@ static void pnfs_ld_handle_read_error(st + dprintk("pnfs read error = %d\n", hdr->pnfs_error); + if (NFS_SERVER(hdr->inode)->pnfs_curr_ld->flags & + PNFS_LAYOUTRET_ON_ERROR) { +- clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(hdr->inode)->flags); + pnfs_return_layout(hdr->inode); + } + if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) diff --git a/queue-3.8/nfsv4.1-fix-a-race-in-pnfs-layoutcommit.patch b/queue-3.8/nfsv4.1-fix-a-race-in-pnfs-layoutcommit.patch new file mode 100644 index 00000000000..d05e2f9d112 --- /dev/null +++ b/queue-3.8/nfsv4.1-fix-a-race-in-pnfs-layoutcommit.patch @@ -0,0 +1,92 @@ +From a073dbff359f4741013ae4b8395f5364c5e00b48 Mon Sep 17 00:00:00 2001 +From: Trond Myklebust +Date: Wed, 20 Mar 2013 12:34:32 -0400 +Subject: NFSv4.1: Fix a race in pNFS layoutcommit + +From: Trond Myklebust + +commit a073dbff359f4741013ae4b8395f5364c5e00b48 upstream. + +We need to clear the NFS_LSEG_LAYOUTCOMMIT bits atomically with the +NFS_INO_LAYOUTCOMMIT bit, otherwise we may end up with situations +where the two are out of sync. +The first half of the problem is to ensure that pnfs_layoutcommit_inode +clears the NFS_LSEG_LAYOUTCOMMIT bit through pnfs_list_write_lseg. +We still need to keep the reference to those segments until the RPC call +is finished, so in order to make it clear _where_ those references come +from, we add a helper pnfs_list_write_lseg_done() that cleans up after +pnfs_list_write_lseg. + +Signed-off-by: Trond Myklebust +Acked-by: Benny Halevy +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfs/nfs4proc.c | 14 -------------- + fs/nfs/pnfs.c | 19 ++++++++++++++++++- + 2 files changed, 18 insertions(+), 15 deletions(-) + +--- a/fs/nfs/nfs4proc.c ++++ b/fs/nfs/nfs4proc.c +@@ -6366,22 +6366,8 @@ nfs4_layoutcommit_done(struct rpc_task * + static void nfs4_layoutcommit_release(void *calldata) + { + struct nfs4_layoutcommit_data *data = calldata; +- struct pnfs_layout_segment *lseg, *tmp; +- unsigned long *bitlock = &NFS_I(data->args.inode)->flags; + + pnfs_cleanup_layoutcommit(data); +- /* Matched by references in pnfs_set_layoutcommit */ +- list_for_each_entry_safe(lseg, tmp, &data->lseg_list, pls_lc_list) { +- list_del_init(&lseg->pls_lc_list); +- if (test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT, +- &lseg->pls_flags)) +- pnfs_put_lseg(lseg); +- } +- +- clear_bit_unlock(NFS_INO_LAYOUTCOMMITTING, bitlock); +- smp_mb__after_clear_bit(); +- wake_up_bit(bitlock, NFS_INO_LAYOUTCOMMITTING); +- + put_rpccred(data->cred); + kfree(data); + } +--- a/fs/nfs/pnfs.c ++++ b/fs/nfs/pnfs.c +@@ -1747,11 +1747,27 @@ static void pnfs_list_write_lseg(struct + + list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) { + if (lseg->pls_range.iomode == IOMODE_RW && +- test_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags)) ++ test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags)) + list_add(&lseg->pls_lc_list, listp); + } + } + ++static void pnfs_list_write_lseg_done(struct inode *inode, struct list_head *listp) ++{ ++ struct pnfs_layout_segment *lseg, *tmp; ++ unsigned long *bitlock = &NFS_I(inode)->flags; ++ ++ /* Matched by references in pnfs_set_layoutcommit */ ++ list_for_each_entry_safe(lseg, tmp, listp, pls_lc_list) { ++ list_del_init(&lseg->pls_lc_list); ++ pnfs_put_lseg(lseg); ++ } ++ ++ clear_bit_unlock(NFS_INO_LAYOUTCOMMITTING, bitlock); ++ smp_mb__after_clear_bit(); ++ wake_up_bit(bitlock, NFS_INO_LAYOUTCOMMITTING); ++} ++ + void pnfs_set_lo_fail(struct pnfs_layout_segment *lseg) + { + pnfs_layout_io_set_failed(lseg->pls_layout, lseg->pls_range.iomode); +@@ -1796,6 +1812,7 @@ void pnfs_cleanup_layoutcommit(struct nf + + if (nfss->pnfs_curr_ld->cleanup_layoutcommit) + nfss->pnfs_curr_ld->cleanup_layoutcommit(data); ++ pnfs_list_write_lseg_done(data->args.inode, &data->lseg_list); + } + + /* diff --git a/queue-3.8/pnfs-block-removing-dm-device-maybe-cause-oops-when-call-dev_remove.patch b/queue-3.8/pnfs-block-removing-dm-device-maybe-cause-oops-when-call-dev_remove.patch new file mode 100644 index 00000000000..fc340d97090 --- /dev/null +++ b/queue-3.8/pnfs-block-removing-dm-device-maybe-cause-oops-when-call-dev_remove.patch @@ -0,0 +1,43 @@ +From 4376c94618c26225e69e17b7c91169c45a90b292 Mon Sep 17 00:00:00 2001 +From: fanchaoting +Date: Thu, 21 Mar 2013 09:15:30 +0800 +Subject: pnfs-block: removing DM device maybe cause oops when call dev_remove + +From: fanchaoting + +commit 4376c94618c26225e69e17b7c91169c45a90b292 upstream. + +when pnfs block using device mapper,if umounting later,it maybe +cause oops. we apply "1 + sizeof(bl_umount_request)" memory for +msg->data, the memory maybe overflow when we do "memcpy(&dataptr +[sizeof(bl_msg)], &bl_umount_request, sizeof(bl_umount_request))", +because the size of bl_msg is more than 1 byte. + +Signed-off-by: fanchaoting +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfs/blocklayout/blocklayoutdm.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/fs/nfs/blocklayout/blocklayoutdm.c ++++ b/fs/nfs/blocklayout/blocklayoutdm.c +@@ -55,7 +55,8 @@ static void dev_remove(struct net *net, + + bl_pipe_msg.bl_wq = &nn->bl_wq; + memset(msg, 0, sizeof(*msg)); +- msg->data = kzalloc(1 + sizeof(bl_umount_request), GFP_NOFS); ++ msg->len = sizeof(bl_msg) + bl_msg.totallen; ++ msg->data = kzalloc(msg->len, GFP_NOFS); + if (!msg->data) + goto out; + +@@ -66,7 +67,6 @@ static void dev_remove(struct net *net, + memcpy(msg->data, &bl_msg, sizeof(bl_msg)); + dataptr = (uint8_t *) msg->data; + memcpy(&dataptr[sizeof(bl_msg)], &bl_umount_request, sizeof(bl_umount_request)); +- msg->len = sizeof(bl_msg) + bl_msg.totallen; + + add_wait_queue(&nn->bl_wq, &wq); + if (rpc_queue_upcall(nn->bl_device_pipe, msg) < 0) { diff --git a/queue-3.8/series b/queue-3.8/series index 92796c6dd14..82d1382e97e 100644 --- a/queue-3.8/series +++ b/queue-3.8/series @@ -23,3 +23,21 @@ b43-n-phy-use-more-bits-for-offset-in-rssi-calibration.patch tg3-fix-length-overflow-in-vpd-firmware-parsing.patch mac80211-always-synchronize_net-during-station-removal.patch iommu-amd-make-sure-dma_ops-are-set-for-hotplug-devices.patch +xen-pciback-notify-hypervisor-about-devices-intended-to-be-assigned-to-guests.patch +xen-blkback-correctly-respond-to-unknown-non-native-requests.patch +xen-blkback-fix-dispatch_rw_block_io-error-path.patch +xen-blkfront-switch-from-llist-to-list.patch +tty-atmel_serial_probe-index-of-atmel_ports-fix.patch +usb-ftdi_sio-add-support-for-mitsubishi-fx-usb-aw-bd.patch +vt-synchronize_rcu-under-spinlock-is-not-nice.patch +mwifiex-fix-race-when-queuing-commands.patch +mwifiex-skip-pending-commands-after-function-shutdown.patch +mwifiex-cancel-cmd-timer-and-free-curr_cmd-in-shutdown-process.patch +pnfs-block-removing-dm-device-maybe-cause-oops-when-call-dev_remove.patch +nfsv4-fix-the-string-length-returned-by-the-idmapper.patch +nfsv4.1-fix-a-race-in-pnfs-layoutcommit.patch +nfsv4.1-always-clear-the-nfs_ino_layoutcommit-in-layoutreturn.patch +net-irda-add-missing-error-path-release_sock-call.patch +nest-rename_lock-inside-vfsmount_lock.patch +usb-ehci-fix-bug-in-itd-sitd-dma-pool-allocation.patch +usb-xhci-fix-trb-transfer-length-macro-used-for-event-trb.patch diff --git a/queue-3.8/tty-atmel_serial_probe-index-of-atmel_ports-fix.patch b/queue-3.8/tty-atmel_serial_probe-index-of-atmel_ports-fix.patch new file mode 100644 index 00000000000..84e5558d878 --- /dev/null +++ b/queue-3.8/tty-atmel_serial_probe-index-of-atmel_ports-fix.patch @@ -0,0 +1,59 @@ +From 503bded92da283b2f31d87e054c4c6d30c3c2340 Mon Sep 17 00:00:00 2001 +From: Pawel Wieczorkiewicz +Date: Wed, 20 Feb 2013 17:26:20 +0100 +Subject: tty: atmel_serial_probe(): index of atmel_ports[] fix + +From: Pawel Wieczorkiewicz + +commit 503bded92da283b2f31d87e054c4c6d30c3c2340 upstream. + +Index of atmel_ports[ATMEL_MAX_UART] should be smaller +than ATMEL_MAX_UART. + +Signed-off-by: Pawel Wieczorkiewicz +Acked-by: Nicolas Ferre +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/tty/serial/atmel_serial.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +--- a/drivers/tty/serial/atmel_serial.c ++++ b/drivers/tty/serial/atmel_serial.c +@@ -158,7 +158,7 @@ struct atmel_uart_port { + }; + + static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART]; +-static unsigned long atmel_ports_in_use; ++static DECLARE_BITMAP(atmel_ports_in_use, ATMEL_MAX_UART); + + #ifdef SUPPORT_SYSRQ + static struct console atmel_console; +@@ -1768,15 +1768,14 @@ static int atmel_serial_probe(struct pla + if (ret < 0) + /* port id not found in platform data nor device-tree aliases: + * auto-enumerate it */ +- ret = find_first_zero_bit(&atmel_ports_in_use, +- sizeof(atmel_ports_in_use)); ++ ret = find_first_zero_bit(atmel_ports_in_use, ATMEL_MAX_UART); + +- if (ret > ATMEL_MAX_UART) { ++ if (ret >= ATMEL_MAX_UART) { + ret = -ENODEV; + goto err; + } + +- if (test_and_set_bit(ret, &atmel_ports_in_use)) { ++ if (test_and_set_bit(ret, atmel_ports_in_use)) { + /* port already in use */ + ret = -EBUSY; + goto err; +@@ -1856,7 +1855,7 @@ static int atmel_serial_remove(struct pl + + /* "port" is allocated statically, so we shouldn't free it */ + +- clear_bit(port->line, &atmel_ports_in_use); ++ clear_bit(port->line, atmel_ports_in_use); + + clk_put(atmel_port->clk); + diff --git a/queue-3.8/usb-ehci-fix-bug-in-itd-sitd-dma-pool-allocation.patch b/queue-3.8/usb-ehci-fix-bug-in-itd-sitd-dma-pool-allocation.patch new file mode 100644 index 00000000000..dc853344351 --- /dev/null +++ b/queue-3.8/usb-ehci-fix-bug-in-itd-sitd-dma-pool-allocation.patch @@ -0,0 +1,86 @@ +From 85ecd0322b9a1a9f451d9150e9460ab42fd17219 Mon Sep 17 00:00:00 2001 +From: Soeren Moch +Date: Fri, 22 Mar 2013 12:16:52 -0400 +Subject: USB: EHCI: fix bug in iTD/siTD DMA pool allocation + +From: Soeren Moch + +commit 85ecd0322b9a1a9f451d9150e9460ab42fd17219 upstream. + +[Description written by Alan Stern] + +Soeren tracked down a very difficult bug in ehci-hcd's DMA pool +management of iTD and siTD structures. Some background: ehci-hcd +gives each isochronous endpoint its own set of active and free itd's +(or sitd's for full-speed devices). When a new itd is needed, it is +taken from the head of the free list, if possible. However, itd's +must not be used twice in a single frame because the hardware +continues to access the data structure for the entire duration of a +frame. Therefore if the itd at the head of the free list has its +"frame" member equal to the current value of ehci->now_frame, it +cannot be reused and instead a new itd is allocated from the DMA pool. +The entries on the free list are not released back to the pool until +the endpoint is no longer in use. + +The bug arises from the fact that sometimes an itd can be moved back +onto the free list before itd->frame has been set properly. In +Soeren's case, this happened because ehci-hcd can allocate one more +itd than it actually needs for an URB; the extra itd may or may not be +required depending on how the transfer aligns with a frame boundary. +For example, an URB with 8 isochronous packets will cause two itd's to +be allocated. If the URB is scheduled to start in microframe 3 of +frame N then it will require both itds: one for microframes 3 - 7 of +frame N and one for microframes 0 - 2 of frame N+1. But if the URB +had been scheduled to start in microframe 0 then it would require only +the first itd, which could cover microframes 0 - 7 of frame N. The +second itd would be returned to the end of the free list. + +The itd allocation routine initializes the entire structure to 0, so +the extra itd ends up on the free list with itd->frame set to 0 +instead of a meaningful value. After a while the itd reaches the head +of the list, and occasionally this happens when ehci->now_frame is +equal to 0. Then, even though it would be okay to reuse this itd, the +driver thinks it must get another itd from the DMA pool. + +For as long as the isochronous endpoint remains in use, this flaw in +the mechanism causes more and more itd's to be taken slowly from the +DMA pool. Since none are released back, the pool eventually becomes +exhausted. + +This reuslts in memory allocation failures, which typically show up +during a long-running audio stream. Video might suffer the same +effect. + +The fix is very simple. To prevent allocations from the pool when +they aren't needed, make sure that itd's sent back to the free list +prematurely have itd->frame set to an invalid value which can never be +equal to ehci->now_frame. + +This should be applied to -stable kernels going back to 3.6. + +Signed-off-by: Soeren Moch +Signed-off-by: Alan Stern +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/host/ehci-sched.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/usb/host/ehci-sched.c ++++ b/drivers/usb/host/ehci-sched.c +@@ -1214,6 +1214,7 @@ itd_urb_transaction ( + + memset (itd, 0, sizeof *itd); + itd->itd_dma = itd_dma; ++ itd->frame = 9999; /* an invalid value */ + list_add (&itd->itd_list, &sched->td_list); + } + spin_unlock_irqrestore (&ehci->lock, flags); +@@ -1915,6 +1916,7 @@ sitd_urb_transaction ( + + memset (sitd, 0, sizeof *sitd); + sitd->sitd_dma = sitd_dma; ++ sitd->frame = 9999; /* an invalid value */ + list_add (&sitd->sitd_list, &iso_sched->td_list); + } + diff --git a/queue-3.8/usb-ftdi_sio-add-support-for-mitsubishi-fx-usb-aw-bd.patch b/queue-3.8/usb-ftdi_sio-add-support-for-mitsubishi-fx-usb-aw-bd.patch new file mode 100644 index 00000000000..fd647a4b97f --- /dev/null +++ b/queue-3.8/usb-ftdi_sio-add-support-for-mitsubishi-fx-usb-aw-bd.patch @@ -0,0 +1,49 @@ +From 482b0b5d82bd916cc0c55a2abf65bdc69023b843 Mon Sep 17 00:00:00 2001 +From: Konstantin Holoborodko +Date: Fri, 29 Mar 2013 00:06:13 +0900 +Subject: usb: ftdi_sio: Add support for Mitsubishi FX-USB-AW/-BD + +From: Konstantin Holoborodko + +commit 482b0b5d82bd916cc0c55a2abf65bdc69023b843 upstream. + +It enhances the driver for FTDI-based USB serial adapters +to recognize Mitsubishi Electric Corp. USB/RS422 Converters +as FT232BM chips and support them. +https://search.meau.com/?q=FX-USB-AW + +Signed-off-by: Konstantin Holoborodko +Tested-by: Konstantin Holoborodko +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/serial/ftdi_sio.c | 1 + + drivers/usb/serial/ftdi_sio_ids.h | 7 +++++++ + 2 files changed, 8 insertions(+) + +--- a/drivers/usb/serial/ftdi_sio.c ++++ b/drivers/usb/serial/ftdi_sio.c +@@ -642,6 +642,7 @@ static struct usb_device_id id_table_com + { USB_DEVICE(FTDI_VID, FTDI_RM_CANVIEW_PID) }, + { USB_DEVICE(ACTON_VID, ACTON_SPECTRAPRO_PID) }, + { USB_DEVICE(CONTEC_VID, CONTEC_COM1USBH_PID) }, ++ { USB_DEVICE(MITSUBISHI_VID, MITSUBISHI_FXUSB_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) }, +--- a/drivers/usb/serial/ftdi_sio_ids.h ++++ b/drivers/usb/serial/ftdi_sio_ids.h +@@ -584,6 +584,13 @@ + #define CONTEC_COM1USBH_PID 0x8311 /* COM-1(USB)H */ + + /* ++ * Mitsubishi Electric Corp. (http://www.meau.com) ++ * Submitted by Konstantin Holoborodko ++ */ ++#define MITSUBISHI_VID 0x06D3 ++#define MITSUBISHI_FXUSB_PID 0x0284 /* USB/RS422 converters: FX-USB-AW/-BD */ ++ ++/* + * Definitions for B&B Electronics products. + */ + #define BANDB_VID 0x0856 /* B&B Electronics Vendor ID */ diff --git a/queue-3.8/usb-xhci-fix-trb-transfer-length-macro-used-for-event-trb.patch b/queue-3.8/usb-xhci-fix-trb-transfer-length-macro-used-for-event-trb.patch new file mode 100644 index 00000000000..365eeb89c8e --- /dev/null +++ b/queue-3.8/usb-xhci-fix-trb-transfer-length-macro-used-for-event-trb.patch @@ -0,0 +1,131 @@ +From 1c11a172cb30492f5f6a82c6e118fdcd9946c34f Mon Sep 17 00:00:00 2001 +From: Vivek Gautam +Date: Thu, 21 Mar 2013 12:06:48 +0530 +Subject: usb: xhci: Fix TRB transfer length macro used for Event TRB. + +From: Vivek Gautam + +commit 1c11a172cb30492f5f6a82c6e118fdcd9946c34f upstream. + +Use proper macro while extracting TRB transfer length from +Transfer event TRBs. Adding a macro EVENT_TRB_LEN (bits 0:23) +for the same, and use it instead of TRB_LEN (bits 0:16) in +case of event TRBs. + +This patch should be backported to kernels as old as 2.6.31, that +contain the commit b10de142119a676552df3f0d2e3a9d647036c26a "USB: xhci: +Bulk transfer support". This patch will have issues applying to older +kernels. + +Signed-off-by: Vivek gautam +Signed-off-by: Sarah Sharp +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/host/xhci-ring.c | 24 ++++++++++++------------ + drivers/usb/host/xhci.h | 4 ++++ + 2 files changed, 16 insertions(+), 12 deletions(-) + +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -2027,8 +2027,8 @@ static int process_ctrl_td(struct xhci_h + if (event_trb != ep_ring->dequeue && + event_trb != td->last_trb) + td->urb->actual_length = +- td->urb->transfer_buffer_length +- - TRB_LEN(le32_to_cpu(event->transfer_len)); ++ td->urb->transfer_buffer_length - ++ EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); + else + td->urb->actual_length = 0; + +@@ -2060,7 +2060,7 @@ static int process_ctrl_td(struct xhci_h + /* Maybe the event was for the data stage? */ + td->urb->actual_length = + td->urb->transfer_buffer_length - +- TRB_LEN(le32_to_cpu(event->transfer_len)); ++ EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); + xhci_dbg(xhci, "Waiting for status " + "stage event\n"); + return 0; +@@ -2096,7 +2096,7 @@ static int process_isoc_td(struct xhci_h + /* handle completion code */ + switch (trb_comp_code) { + case COMP_SUCCESS: +- if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) { ++ if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) { + frame->status = 0; + break; + } +@@ -2141,7 +2141,7 @@ static int process_isoc_td(struct xhci_h + len += TRB_LEN(le32_to_cpu(cur_trb->generic.field[2])); + } + len += TRB_LEN(le32_to_cpu(cur_trb->generic.field[2])) - +- TRB_LEN(le32_to_cpu(event->transfer_len)); ++ EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); + + if (trb_comp_code != COMP_STOP_INVAL) { + frame->actual_length = len; +@@ -2199,7 +2199,7 @@ static int process_bulk_intr_td(struct x + case COMP_SUCCESS: + /* Double check that the HW transferred everything. */ + if (event_trb != td->last_trb || +- TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) { ++ EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) { + xhci_warn(xhci, "WARN Successful completion " + "on short TX\n"); + if (td->urb->transfer_flags & URB_SHORT_NOT_OK) +@@ -2227,18 +2227,18 @@ static int process_bulk_intr_td(struct x + "%d bytes untransferred\n", + td->urb->ep->desc.bEndpointAddress, + td->urb->transfer_buffer_length, +- TRB_LEN(le32_to_cpu(event->transfer_len))); ++ EVENT_TRB_LEN(le32_to_cpu(event->transfer_len))); + /* Fast path - was this the last TRB in the TD for this URB? */ + if (event_trb == td->last_trb) { +- if (TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) { ++ if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) { + td->urb->actual_length = + td->urb->transfer_buffer_length - +- TRB_LEN(le32_to_cpu(event->transfer_len)); ++ EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); + if (td->urb->transfer_buffer_length < + td->urb->actual_length) { + xhci_warn(xhci, "HC gave bad length " + "of %d bytes left\n", +- TRB_LEN(le32_to_cpu(event->transfer_len))); ++ EVENT_TRB_LEN(le32_to_cpu(event->transfer_len))); + td->urb->actual_length = 0; + if (td->urb->transfer_flags & URB_SHORT_NOT_OK) + *status = -EREMOTEIO; +@@ -2280,7 +2280,7 @@ static int process_bulk_intr_td(struct x + if (trb_comp_code != COMP_STOP_INVAL) + td->urb->actual_length += + TRB_LEN(le32_to_cpu(cur_trb->generic.field[2])) - +- TRB_LEN(le32_to_cpu(event->transfer_len)); ++ EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); + } + + return finish_td(xhci, td, event_trb, event, ep, status, false); +@@ -2368,7 +2368,7 @@ static int handle_tx_event(struct xhci_h + * transfer type + */ + case COMP_SUCCESS: +- if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) ++ if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) + break; + if (xhci->quirks & XHCI_TRUST_TX_LENGTH) + trb_comp_code = COMP_SHORT_TX; +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -972,6 +972,10 @@ struct xhci_transfer_event { + __le32 flags; + }; + ++/* Transfer event TRB length bit mask */ ++/* bits 0:23 */ ++#define EVENT_TRB_LEN(p) ((p) & 0xffffff) ++ + /** Transfer Event bit fields **/ + #define TRB_TO_EP_ID(p) (((p) >> 16) & 0x1f) + diff --git a/queue-3.8/vt-synchronize_rcu-under-spinlock-is-not-nice.patch b/queue-3.8/vt-synchronize_rcu-under-spinlock-is-not-nice.patch new file mode 100644 index 00000000000..7085ea7cecd --- /dev/null +++ b/queue-3.8/vt-synchronize_rcu-under-spinlock-is-not-nice.patch @@ -0,0 +1,45 @@ +From e8cd81693bbbb15db57d3c9aa7dd90eda4842874 Mon Sep 17 00:00:00 2001 +From: Al Viro +Date: Tue, 26 Mar 2013 20:30:17 -0400 +Subject: vt: synchronize_rcu() under spinlock is not nice... + +From: Al Viro + +commit e8cd81693bbbb15db57d3c9aa7dd90eda4842874 upstream. + +vcs_poll_data_free() calls unregister_vt_notifier(), which calls +atomic_notifier_chain_unregister(), which calls synchronize_rcu(). +Do it *after* we'd dropped ->f_lock. + +Signed-off-by: Al Viro +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/tty/vt/vc_screen.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/tty/vt/vc_screen.c ++++ b/drivers/tty/vt/vc_screen.c +@@ -93,7 +93,7 @@ vcs_poll_data_free(struct vcs_poll_data + static struct vcs_poll_data * + vcs_poll_data_get(struct file *file) + { +- struct vcs_poll_data *poll = file->private_data; ++ struct vcs_poll_data *poll = file->private_data, *kill = NULL; + + if (poll) + return poll; +@@ -122,10 +122,12 @@ vcs_poll_data_get(struct file *file) + file->private_data = poll; + } else { + /* someone else raced ahead of us */ +- vcs_poll_data_free(poll); ++ kill = poll; + poll = file->private_data; + } + spin_unlock(&file->f_lock); ++ if (kill) ++ vcs_poll_data_free(kill); + + return poll; + } diff --git a/queue-3.8/xen-blkback-correctly-respond-to-unknown-non-native-requests.patch b/queue-3.8/xen-blkback-correctly-respond-to-unknown-non-native-requests.patch new file mode 100644 index 00000000000..798eefa1637 --- /dev/null +++ b/queue-3.8/xen-blkback-correctly-respond-to-unknown-non-native-requests.patch @@ -0,0 +1,177 @@ +From 0e367ae46503cfe7791460c8ba8434a5d60b2bd5 Mon Sep 17 00:00:00 2001 +From: David Vrabel +Date: Thu, 7 Mar 2013 17:32:01 +0000 +Subject: xen/blkback: correctly respond to unknown, non-native requests + +From: David Vrabel + +commit 0e367ae46503cfe7791460c8ba8434a5d60b2bd5 upstream. + +If the frontend is using a non-native protocol (e.g., a 64-bit +frontend with a 32-bit backend) and it sent an unrecognized request, +the request was not translated and the response would have the +incorrect ID. This may cause the frontend driver to behave +incorrectly or crash. + +Since the ID field in the request is always in the same place, +regardless of the request type we can get the correct ID and make a +valid response (which will report BLKIF_RSP_EOPNOTSUPP). + +This bug affected 64-bit SLES 11 guests when using a 32-bit backend. +This guest does a BLKIF_OP_RESERVED_1 (BLKIF_OP_PACKET in the SLES +source) and would crash in blkif_int() as the ID in the response would +be invalid. + +Signed-off-by: David Vrabel +Signed-off-by: Konrad Rzeszutek Wilk +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/block/xen-blkback/blkback.c | 31 +++++++++++++++++++++++++++---- + drivers/block/xen-blkback/common.h | 25 +++++++++++++++++++++++++ + include/xen/interface/io/blkif.h | 10 ++++++++++ + 3 files changed, 62 insertions(+), 4 deletions(-) + +--- a/drivers/block/xen-blkback/blkback.c ++++ b/drivers/block/xen-blkback/blkback.c +@@ -679,6 +679,16 @@ static int dispatch_discard_io(struct xe + return err; + } + ++static int dispatch_other_io(struct xen_blkif *blkif, ++ struct blkif_request *req, ++ struct pending_req *pending_req) ++{ ++ free_req(pending_req); ++ make_response(blkif, req->u.other.id, req->operation, ++ BLKIF_RSP_EOPNOTSUPP); ++ return -EIO; ++} ++ + static void xen_blk_drain_io(struct xen_blkif *blkif) + { + atomic_set(&blkif->drain, 1); +@@ -800,17 +810,30 @@ __do_block_io_op(struct xen_blkif *blkif + + /* Apply all sanity checks to /private copy/ of request. */ + barrier(); +- if (unlikely(req.operation == BLKIF_OP_DISCARD)) { ++ ++ switch (req.operation) { ++ case BLKIF_OP_READ: ++ case BLKIF_OP_WRITE: ++ case BLKIF_OP_WRITE_BARRIER: ++ case BLKIF_OP_FLUSH_DISKCACHE: ++ if (dispatch_rw_block_io(blkif, &req, pending_req)) ++ goto done; ++ break; ++ case BLKIF_OP_DISCARD: + free_req(pending_req); + if (dispatch_discard_io(blkif, &req)) +- break; +- } else if (dispatch_rw_block_io(blkif, &req, pending_req)) ++ goto done; + break; ++ default: ++ if (dispatch_other_io(blkif, &req, pending_req)) ++ goto done; ++ break; ++ } + + /* Yield point for this unbounded loop. */ + cond_resched(); + } +- ++done: + return more_to_do; + } + +--- a/drivers/block/xen-blkback/common.h ++++ b/drivers/block/xen-blkback/common.h +@@ -77,11 +77,18 @@ struct blkif_x86_32_request_discard { + uint64_t nr_sectors; + } __attribute__((__packed__)); + ++struct blkif_x86_32_request_other { ++ uint8_t _pad1; ++ blkif_vdev_t _pad2; ++ uint64_t id; /* private guest value, echoed in resp */ ++} __attribute__((__packed__)); ++ + struct blkif_x86_32_request { + uint8_t operation; /* BLKIF_OP_??? */ + union { + struct blkif_x86_32_request_rw rw; + struct blkif_x86_32_request_discard discard; ++ struct blkif_x86_32_request_other other; + } u; + } __attribute__((__packed__)); + +@@ -113,11 +120,19 @@ struct blkif_x86_64_request_discard { + uint64_t nr_sectors; + } __attribute__((__packed__)); + ++struct blkif_x86_64_request_other { ++ uint8_t _pad1; ++ blkif_vdev_t _pad2; ++ uint32_t _pad3; /* offsetof(blkif_..,u.discard.id)==8 */ ++ uint64_t id; /* private guest value, echoed in resp */ ++} __attribute__((__packed__)); ++ + struct blkif_x86_64_request { + uint8_t operation; /* BLKIF_OP_??? */ + union { + struct blkif_x86_64_request_rw rw; + struct blkif_x86_64_request_discard discard; ++ struct blkif_x86_64_request_other other; + } u; + } __attribute__((__packed__)); + +@@ -278,6 +293,11 @@ static inline void blkif_get_x86_32_req( + dst->u.discard.nr_sectors = src->u.discard.nr_sectors; + break; + default: ++ /* ++ * Don't know how to translate this op. Only get the ++ * ID so failure can be reported to the frontend. ++ */ ++ dst->u.other.id = src->u.other.id; + break; + } + } +@@ -309,6 +329,11 @@ static inline void blkif_get_x86_64_req( + dst->u.discard.nr_sectors = src->u.discard.nr_sectors; + break; + default: ++ /* ++ * Don't know how to translate this op. Only get the ++ * ID so failure can be reported to the frontend. ++ */ ++ dst->u.other.id = src->u.other.id; + break; + } + } +--- a/include/xen/interface/io/blkif.h ++++ b/include/xen/interface/io/blkif.h +@@ -138,11 +138,21 @@ struct blkif_request_discard { + uint8_t _pad3; + } __attribute__((__packed__)); + ++struct blkif_request_other { ++ uint8_t _pad1; ++ blkif_vdev_t _pad2; /* only for read/write requests */ ++#ifdef CONFIG_X86_64 ++ uint32_t _pad3; /* offsetof(blkif_req..,u.other.id)==8*/ ++#endif ++ uint64_t id; /* private guest value, echoed in resp */ ++} __attribute__((__packed__)); ++ + struct blkif_request { + uint8_t operation; /* BLKIF_OP_??? */ + union { + struct blkif_request_rw rw; + struct blkif_request_discard discard; ++ struct blkif_request_other other; + } u; + } __attribute__((__packed__)); + diff --git a/queue-3.8/xen-blkback-fix-dispatch_rw_block_io-error-path.patch b/queue-3.8/xen-blkback-fix-dispatch_rw_block_io-error-path.patch new file mode 100644 index 00000000000..6f06558f0da --- /dev/null +++ b/queue-3.8/xen-blkback-fix-dispatch_rw_block_io-error-path.patch @@ -0,0 +1,49 @@ +From 0e5e098ac22dae38f957e951b70d3cf73beff0f7 Mon Sep 17 00:00:00 2001 +From: Jan Beulich +Date: Mon, 11 Mar 2013 09:39:55 +0000 +Subject: xen-blkback: fix dispatch_rw_block_io() error path + +From: Jan Beulich + +commit 0e5e098ac22dae38f957e951b70d3cf73beff0f7 upstream. + +Commit 7708992 ("xen/blkback: Seperate the bio allocation and the bio +submission") consolidated the pendcnt updates to just a single write, +neglecting the fact that the error path relied on it getting set to 1 +up front (such that the decrement in __end_block_io_op() would actually +drop the count to zero, triggering the necessary cleanup actions). + +Also remove a misleading and a stale (after said commit) comment. + +Signed-off-by: Jan Beulich +Signed-off-by: Konrad Rzeszutek Wilk +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/block/xen-blkback/blkback.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +--- a/drivers/block/xen-blkback/blkback.c ++++ b/drivers/block/xen-blkback/blkback.c +@@ -1001,13 +1001,7 @@ static int dispatch_rw_block_io(struct x + bio->bi_end_io = end_block_io_op; + } + +- /* +- * We set it one so that the last submit_bio does not have to call +- * atomic_inc. +- */ + atomic_set(&pending_req->pendcnt, nbio); +- +- /* Get a reference count for the disk queue and start sending I/O */ + blk_start_plug(&plug); + + for (i = 0; i < nbio; i++) +@@ -1035,6 +1029,7 @@ static int dispatch_rw_block_io(struct x + fail_put_bio: + for (i = 0; i < nbio; i++) + bio_put(biolist[i]); ++ atomic_set(&pending_req->pendcnt, 1); + __end_block_io_op(pending_req, -EINVAL); + msleep(1); /* back off a bit */ + return -EIO; diff --git a/queue-3.8/xen-blkfront-switch-from-llist-to-list.patch b/queue-3.8/xen-blkfront-switch-from-llist-to-list.patch new file mode 100644 index 00000000000..8d35a7e9a25 --- /dev/null +++ b/queue-3.8/xen-blkfront-switch-from-llist-to-list.patch @@ -0,0 +1,133 @@ +From 155b7edb51430a280f86c1e21b7be308b0d219d4 Mon Sep 17 00:00:00 2001 +From: Roger Pau Monne +Date: Mon, 18 Mar 2013 17:49:34 +0100 +Subject: xen-blkfront: switch from llist to list + +From: Roger Pau Monne + +commit 155b7edb51430a280f86c1e21b7be308b0d219d4 upstream. + +The git commit f84adf4921ae3115502f44ff467b04bf2f88cf04 +(xen-blkfront: drop the use of llist_for_each_entry_safe) + +was a stop-gate to fix a GCC4.1 bug. The appropiate way +is to actually use an list instead of using an llist. + +As such this patch replaces the usage of llist with an +list. + +Since we always manipulate the list while holding the io_lock, there's +no need for additional locking (llist used previously is safe to use +concurrently without additional locking). + +Signed-off-by: Roger Pau Monné +[v1: Redid the git commit description] +Signed-off-by: Konrad Rzeszutek Wilk +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/block/xen-blkfront.c | 41 ++++++++++++++++++----------------------- + 1 file changed, 18 insertions(+), 23 deletions(-) + +--- a/drivers/block/xen-blkfront.c ++++ b/drivers/block/xen-blkfront.c +@@ -44,7 +44,7 @@ + #include + #include + #include +-#include ++#include + + #include + #include +@@ -68,7 +68,7 @@ enum blkif_state { + struct grant { + grant_ref_t gref; + unsigned long pfn; +- struct llist_node node; ++ struct list_head node; + }; + + struct blk_shadow { +@@ -105,7 +105,7 @@ struct blkfront_info + struct work_struct work; + struct gnttab_free_callback callback; + struct blk_shadow shadow[BLK_RING_SIZE]; +- struct llist_head persistent_gnts; ++ struct list_head persistent_gnts; + unsigned int persistent_gnts_c; + unsigned long shadow_free; + unsigned int feature_flush; +@@ -371,10 +371,11 @@ static int blkif_queue_request(struct re + lsect = fsect + (sg->length >> 9) - 1; + + if (info->persistent_gnts_c) { +- BUG_ON(llist_empty(&info->persistent_gnts)); +- gnt_list_entry = llist_entry( +- llist_del_first(&info->persistent_gnts), +- struct grant, node); ++ BUG_ON(list_empty(&info->persistent_gnts)); ++ gnt_list_entry = list_first_entry( ++ &info->persistent_gnts, ++ struct grant, node); ++ list_del(&gnt_list_entry->node); + + ref = gnt_list_entry->gref; + buffer_mfn = pfn_to_mfn(gnt_list_entry->pfn); +@@ -790,9 +791,8 @@ static void blkif_restart_queue(struct w + + static void blkif_free(struct blkfront_info *info, int suspend) + { +- struct llist_node *all_gnts; +- struct grant *persistent_gnt, *tmp; +- struct llist_node *n; ++ struct grant *persistent_gnt; ++ struct grant *n; + + /* Prevent new requests being issued until we fix things up. */ + spin_lock_irq(&info->io_lock); +@@ -804,20 +804,15 @@ static void blkif_free(struct blkfront_i + + /* Remove all persistent grants */ + if (info->persistent_gnts_c) { +- all_gnts = llist_del_all(&info->persistent_gnts); +- persistent_gnt = llist_entry(all_gnts, typeof(*(persistent_gnt)), node); +- while (persistent_gnt) { ++ list_for_each_entry_safe(persistent_gnt, n, ++ &info->persistent_gnts, node) { ++ list_del(&persistent_gnt->node); + gnttab_end_foreign_access(persistent_gnt->gref, 0, 0UL); + __free_page(pfn_to_page(persistent_gnt->pfn)); +- tmp = persistent_gnt; +- n = persistent_gnt->node.next; +- if (n) +- persistent_gnt = llist_entry(n, typeof(*(persistent_gnt)), node); +- else +- persistent_gnt = NULL; +- kfree(tmp); ++ kfree(persistent_gnt); ++ info->persistent_gnts_c--; + } +- info->persistent_gnts_c = 0; ++ BUG_ON(info->persistent_gnts_c != 0); + } + + /* No more gnttab callback work. */ +@@ -875,7 +870,7 @@ static void blkif_completion(struct blk_ + } + /* Add the persistent grant into the list of free grants */ + for (i = 0; i < s->req.u.rw.nr_segments; i++) { +- llist_add(&s->grants_used[i]->node, &info->persistent_gnts); ++ list_add(&s->grants_used[i]->node, &info->persistent_gnts); + info->persistent_gnts_c++; + } + } +@@ -1171,7 +1166,7 @@ static int blkfront_probe(struct xenbus_ + spin_lock_init(&info->io_lock); + info->xbdev = dev; + info->vdevice = vdevice; +- init_llist_head(&info->persistent_gnts); ++ INIT_LIST_HEAD(&info->persistent_gnts); + info->persistent_gnts_c = 0; + info->connected = BLKIF_STATE_DISCONNECTED; + INIT_WORK(&info->work, blkif_restart_queue); diff --git a/queue-3.8/xen-pciback-notify-hypervisor-about-devices-intended-to-be-assigned-to-guests.patch b/queue-3.8/xen-pciback-notify-hypervisor-about-devices-intended-to-be-assigned-to-guests.patch new file mode 100644 index 00000000000..32fc28ca8b1 --- /dev/null +++ b/queue-3.8/xen-pciback-notify-hypervisor-about-devices-intended-to-be-assigned-to-guests.patch @@ -0,0 +1,178 @@ +From 909b3fdb0dd4f3db07b2d75425a00a2adb551383 Mon Sep 17 00:00:00 2001 +From: Jan Beulich +Date: Tue, 12 Mar 2013 15:06:23 +0000 +Subject: xen-pciback: notify hypervisor about devices intended to be assigned to guests + +From: Jan Beulich + +commit 909b3fdb0dd4f3db07b2d75425a00a2adb551383 upstream. + +For MSI-X capable devices the hypervisor wants to write protect the +MSI-X table and PBA, yet it can't assume that resources have been +assigned to their final values at device enumeration time. Thus have +pciback do that notification, as having the device controlled by it is +a prerequisite to assigning the device to guests anyway. + +This is the kernel part of hypervisor side commit 4245d33 ("x86/MSI: +add mechanism to fully protect MSI-X table from PV guest accesses") on +the master branch of git://xenbits.xen.org/xen.git. + +Signed-off-by: Jan Beulich +Signed-off-by: Konrad Rzeszutek Wilk +Signed-off-by: Greg Kroah-Hartman + +--- + arch/x86/include/asm/xen/hypercall.h | 4 +- + drivers/xen/fallback.c | 3 + + drivers/xen/xen-pciback/pci_stub.c | 59 ++++++++++++++++++++++++++--------- + include/xen/interface/physdev.h | 6 +++ + 4 files changed, 54 insertions(+), 18 deletions(-) + +--- a/arch/x86/include/asm/xen/hypercall.h ++++ b/arch/x86/include/asm/xen/hypercall.h +@@ -382,14 +382,14 @@ HYPERVISOR_console_io(int cmd, int count + return _hypercall3(int, console_io, cmd, count, str); + } + +-extern int __must_check HYPERVISOR_physdev_op_compat(int, void *); ++extern int __must_check xen_physdev_op_compat(int, void *); + + static inline int + HYPERVISOR_physdev_op(int cmd, void *arg) + { + int rc = _hypercall2(int, physdev_op, cmd, arg); + if (unlikely(rc == -ENOSYS)) +- rc = HYPERVISOR_physdev_op_compat(cmd, arg); ++ rc = xen_physdev_op_compat(cmd, arg); + return rc; + } + +--- a/drivers/xen/fallback.c ++++ b/drivers/xen/fallback.c +@@ -44,7 +44,7 @@ int xen_event_channel_op_compat(int cmd, + } + EXPORT_SYMBOL_GPL(xen_event_channel_op_compat); + +-int HYPERVISOR_physdev_op_compat(int cmd, void *arg) ++int xen_physdev_op_compat(int cmd, void *arg) + { + struct physdev_op op; + int rc; +@@ -78,3 +78,4 @@ int HYPERVISOR_physdev_op_compat(int cmd + + return rc; + } ++EXPORT_SYMBOL_GPL(xen_physdev_op_compat); +--- a/drivers/xen/xen-pciback/pci_stub.c ++++ b/drivers/xen/xen-pciback/pci_stub.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include "pciback.h" + #include "conf_space.h" + #include "conf_space_quirks.h" +@@ -85,37 +86,52 @@ static struct pcistub_device *pcistub_de + static void pcistub_device_release(struct kref *kref) + { + struct pcistub_device *psdev; ++ struct pci_dev *dev; + struct xen_pcibk_dev_data *dev_data; + + psdev = container_of(kref, struct pcistub_device, kref); +- dev_data = pci_get_drvdata(psdev->dev); ++ dev = psdev->dev; ++ dev_data = pci_get_drvdata(dev); + +- dev_dbg(&psdev->dev->dev, "pcistub_device_release\n"); ++ dev_dbg(&dev->dev, "pcistub_device_release\n"); + +- xen_unregister_device_domain_owner(psdev->dev); ++ xen_unregister_device_domain_owner(dev); + + /* Call the reset function which does not take lock as this + * is called from "unbind" which takes a device_lock mutex. + */ +- __pci_reset_function_locked(psdev->dev); +- if (pci_load_and_free_saved_state(psdev->dev, +- &dev_data->pci_saved_state)) { +- dev_dbg(&psdev->dev->dev, "Could not reload PCI state\n"); +- } else +- pci_restore_state(psdev->dev); ++ __pci_reset_function_locked(dev); ++ if (pci_load_and_free_saved_state(dev, &dev_data->pci_saved_state)) ++ dev_dbg(&dev->dev, "Could not reload PCI state\n"); ++ else ++ pci_restore_state(dev); ++ ++ if (pci_find_capability(dev, PCI_CAP_ID_MSIX)) { ++ struct physdev_pci_device ppdev = { ++ .seg = pci_domain_nr(dev->bus), ++ .bus = dev->bus->number, ++ .devfn = dev->devfn ++ }; ++ int err = HYPERVISOR_physdev_op(PHYSDEVOP_release_msix, ++ &ppdev); ++ ++ if (err) ++ dev_warn(&dev->dev, "MSI-X release failed (%d)\n", ++ err); ++ } + + /* Disable the device */ +- xen_pcibk_reset_device(psdev->dev); ++ xen_pcibk_reset_device(dev); + + kfree(dev_data); +- pci_set_drvdata(psdev->dev, NULL); ++ pci_set_drvdata(dev, NULL); + + /* Clean-up the device */ +- xen_pcibk_config_free_dyn_fields(psdev->dev); +- xen_pcibk_config_free_dev(psdev->dev); ++ xen_pcibk_config_free_dyn_fields(dev); ++ xen_pcibk_config_free_dev(dev); + +- psdev->dev->dev_flags &= ~PCI_DEV_FLAGS_ASSIGNED; +- pci_dev_put(psdev->dev); ++ dev->dev_flags &= ~PCI_DEV_FLAGS_ASSIGNED; ++ pci_dev_put(dev); + + kfree(psdev); + } +@@ -355,6 +371,19 @@ static int pcistub_init_device(struct pc + if (err) + goto config_release; + ++ if (pci_find_capability(dev, PCI_CAP_ID_MSIX)) { ++ struct physdev_pci_device ppdev = { ++ .seg = pci_domain_nr(dev->bus), ++ .bus = dev->bus->number, ++ .devfn = dev->devfn ++ }; ++ ++ err = HYPERVISOR_physdev_op(PHYSDEVOP_prepare_msix, &ppdev); ++ if (err) ++ dev_err(&dev->dev, "MSI-X preparation failed (%d)\n", ++ err); ++ } ++ + /* We need the device active to save the state. */ + dev_dbg(&dev->dev, "save state of device\n"); + pci_save_state(dev); +--- a/include/xen/interface/physdev.h ++++ b/include/xen/interface/physdev.h +@@ -251,6 +251,12 @@ struct physdev_pci_device_add { + + #define PHYSDEVOP_pci_device_remove 26 + #define PHYSDEVOP_restore_msi_ext 27 ++/* ++ * Dom0 should use these two to announce MMIO resources assigned to ++ * MSI-X capable devices won't (prepare) or may (release) change. ++ */ ++#define PHYSDEVOP_prepare_msix 30 ++#define PHYSDEVOP_release_msix 31 + struct physdev_pci_device { + /* IN */ + uint16_t seg;