]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 11 Jul 2012 21:41:47 +0000 (14:41 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 11 Jul 2012 21:41:47 +0000 (14:41 -0700)
added patches:
ipheth-add-support-for-ipad.patch
iwlwifi-remove-log_event-debugfs-file-debugging-is-disabled.patch
lockd-pass-network-namespace-to-creation-and-destruction-routines.patch
mac80211-fix-queues-stuck-issue-with-ht-bandwidth-change.patch
nfs-hard-code-init_net-for-nfs-callback-transports.patch
sunrpc-move-per-net-operations-from-svc_destroy.patch
sunrpc-new-svc_bind-routine-introduced.patch

queue-3.4/ipheth-add-support-for-ipad.patch [new file with mode: 0644]
queue-3.4/iwlwifi-remove-log_event-debugfs-file-debugging-is-disabled.patch [new file with mode: 0644]
queue-3.4/lockd-pass-network-namespace-to-creation-and-destruction-routines.patch [new file with mode: 0644]
queue-3.4/mac80211-fix-queues-stuck-issue-with-ht-bandwidth-change.patch [new file with mode: 0644]
queue-3.4/nfs-hard-code-init_net-for-nfs-callback-transports.patch [new file with mode: 0644]
queue-3.4/series
queue-3.4/sunrpc-move-per-net-operations-from-svc_destroy.patch [new file with mode: 0644]
queue-3.4/sunrpc-new-svc_bind-routine-introduced.patch [new file with mode: 0644]

diff --git a/queue-3.4/ipheth-add-support-for-ipad.patch b/queue-3.4/ipheth-add-support-for-ipad.patch
new file mode 100644 (file)
index 0000000..5adfe95
--- /dev/null
@@ -0,0 +1,41 @@
+From 6de0298ec9c1edaf330b71b57346241ece8f3346 Mon Sep 17 00:00:00 2001
+From: Davide Gerhard <rainbow@irh.it>
+Date: Mon, 25 Jun 2012 09:04:47 +0200
+Subject: ipheth: add support for iPad
+
+From: Davide Gerhard <rainbow@irh.it>
+
+commit 6de0298ec9c1edaf330b71b57346241ece8f3346 upstream.
+
+This adds support for the iPad to the ipheth driver.
+(product id = 0x129a)
+
+Signed-off-by: Davide Gerhard <rainbow@irh.it>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/net/usb/ipheth.c |    5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/net/usb/ipheth.c
++++ b/drivers/net/usb/ipheth.c
+@@ -59,6 +59,7 @@
+ #define USB_PRODUCT_IPHONE_3G   0x1292
+ #define USB_PRODUCT_IPHONE_3GS  0x1294
+ #define USB_PRODUCT_IPHONE_4  0x1297
++#define USB_PRODUCT_IPAD 0x129a
+ #define USB_PRODUCT_IPHONE_4_VZW 0x129c
+ #define USB_PRODUCT_IPHONE_4S 0x12a0
+@@ -101,6 +102,10 @@ static struct usb_device_id ipheth_table
+               IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
+               IPHETH_USBINTF_PROTO) },
+       { USB_DEVICE_AND_INTERFACE_INFO(
++              USB_VENDOR_APPLE, USB_PRODUCT_IPAD,
++              IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
++              IPHETH_USBINTF_PROTO) },
++      { USB_DEVICE_AND_INTERFACE_INFO(
+               USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_4_VZW,
+               IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
+               IPHETH_USBINTF_PROTO) },
diff --git a/queue-3.4/iwlwifi-remove-log_event-debugfs-file-debugging-is-disabled.patch b/queue-3.4/iwlwifi-remove-log_event-debugfs-file-debugging-is-disabled.patch
new file mode 100644 (file)
index 0000000..692e897
--- /dev/null
@@ -0,0 +1,63 @@
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Wed, 20 Jun 2012 08:46:25 +0200
+Subject: iwlwifi: remove log_event debugfs file debugging is disabled
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+commit 882b7b7d11d65e8eccce738f1ce97cdfdb998f9f upstream.
+
+When debugging is disabled, the event log functions aren't
+functional in the way that the debugfs file expects. This
+leads to the debugfs access crashing. Since the event log
+functions aren't functional then, remove the debugfs file
+when CONFIG_IWLWIFI_DEBUG is not set.
+
+Reported-by: Lekensteyn <lekensteyn@gmail.com>
+Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+[bwh: Backported to 3.2: adjust filename, context]
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/wireless/iwlwifi/iwl-trans-pcie.c |    6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
++++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
+@@ -2000,6 +2000,7 @@ static ssize_t iwl_dbgfs_rx_queue_read(s
+       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ }
++#ifdef CONFIG_IWLWIFI_DEBUG
+ static ssize_t iwl_dbgfs_log_event_read(struct file *file,
+                                        char __user *user_buf,
+                                        size_t count, loff_t *ppos)
+@@ -2037,6 +2038,7 @@ static ssize_t iwl_dbgfs_log_event_write
+       return count;
+ }
++#endif
+ static ssize_t iwl_dbgfs_interrupt_read(struct file *file,
+                                       char __user *user_buf,
+@@ -2164,7 +2166,9 @@ static ssize_t iwl_dbgfs_fh_reg_read(str
+       return ret;
+ }
++#ifdef CONFIG_IWLWIFI_DEBUG
+ DEBUGFS_READ_WRITE_FILE_OPS(log_event);
++#endif
+ DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
+ DEBUGFS_READ_FILE_OPS(fh_reg);
+ DEBUGFS_READ_FILE_OPS(rx_queue);
+@@ -2180,7 +2184,9 @@ static int iwl_trans_pcie_dbgfs_register
+ {
+       DEBUGFS_ADD_FILE(rx_queue, dir, S_IRUSR);
+       DEBUGFS_ADD_FILE(tx_queue, dir, S_IRUSR);
++#ifdef CONFIG_IWLWIFI_DEBUG
+       DEBUGFS_ADD_FILE(log_event, dir, S_IWUSR | S_IRUSR);
++#endif
+       DEBUGFS_ADD_FILE(interrupt, dir, S_IWUSR | S_IRUSR);
+       DEBUGFS_ADD_FILE(csr, dir, S_IWUSR);
+       DEBUGFS_ADD_FILE(fh_reg, dir, S_IRUSR);
diff --git a/queue-3.4/lockd-pass-network-namespace-to-creation-and-destruction-routines.patch b/queue-3.4/lockd-pass-network-namespace-to-creation-and-destruction-routines.patch
new file mode 100644 (file)
index 0000000..ee18dd8
--- /dev/null
@@ -0,0 +1,156 @@
+From bfields@redhat.com  Wed Jul 11 14:38:33 2012
+From: "J. Bruce Fields" <bfields@redhat.com>
+Date: Mon, 25 Jun 2012 16:40:07 -0400
+Subject: Lockd: pass network namespace to creation and destruction routines
+To: stable@vger.kernel.org
+Cc: Stanislav Kinsbursky <skinsbursky@parallels.com>, linux-nfs@vger.kernel.org, "J. Bruce Fields" <bfields@redhat.com>
+Message-ID: <1340656810-13752-1-git-send-email-bfields@redhat.com>
+
+
+From: Stanislav Kinsbursky <skinsbursky@parallels.com>
+
+upstream commit e3f70eadb7dddfb5a2bb9afff7abfc6ee17a29d0.
+
+v2: dereference of most probably already released nlm_host removed in
+nlmclnt_done() and reclaimer().
+
+These routines are called from locks reclaimer() kernel thread. This thread
+works in "init_net" network context and currently relays on persence on lockd
+thread and it's per-net resources. Thus lockd_up() and lockd_down() can't relay
+on current network context. So let's pass corrent one into them.
+
+Signed-off-by: Stanislav Kinsbursky <skinsbursky@parallels.com>
+Signed-off-by: J. Bruce Fields <bfields@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/lockd/clntlock.c        |   13 ++++++++-----
+ fs/lockd/svc.c             |    7 +++----
+ fs/nfsd/nfssvc.c           |    6 +++---
+ include/linux/lockd/bind.h |    4 ++--
+ 4 files changed, 16 insertions(+), 14 deletions(-)
+
+--- a/fs/lockd/clntlock.c
++++ b/fs/lockd/clntlock.c
+@@ -56,7 +56,7 @@ struct nlm_host *nlmclnt_init(const stru
+       u32 nlm_version = (nlm_init->nfs_version == 2) ? 1 : 4;
+       int status;
+-      status = lockd_up();
++      status = lockd_up(nlm_init->net);
+       if (status < 0)
+               return ERR_PTR(status);
+@@ -65,7 +65,7 @@ struct nlm_host *nlmclnt_init(const stru
+                                  nlm_init->hostname, nlm_init->noresvport,
+                                  nlm_init->net);
+       if (host == NULL) {
+-              lockd_down();
++              lockd_down(nlm_init->net);
+               return ERR_PTR(-ENOLCK);
+       }
+@@ -80,8 +80,10 @@ EXPORT_SYMBOL_GPL(nlmclnt_init);
+  */
+ void nlmclnt_done(struct nlm_host *host)
+ {
++      struct net *net = host->net;
++
+       nlmclnt_release_host(host);
+-      lockd_down();
++      lockd_down(net);
+ }
+ EXPORT_SYMBOL_GPL(nlmclnt_done);
+@@ -220,11 +222,12 @@ reclaimer(void *ptr)
+       struct nlm_wait   *block;
+       struct file_lock *fl, *next;
+       u32 nsmstate;
++      struct net *net = host->net;
+       allow_signal(SIGKILL);
+       down_write(&host->h_rwsem);
+-      lockd_up();     /* note: this cannot fail as lockd is already running */
++      lockd_up(net);  /* note: this cannot fail as lockd is already running */
+       dprintk("lockd: reclaiming locks for host %s\n", host->h_name);
+@@ -275,6 +278,6 @@ restart:
+       /* Release host handle after use */
+       nlmclnt_release_host(host);
+-      lockd_down();
++      lockd_down(net);
+       return 0;
+ }
+--- a/fs/lockd/svc.c
++++ b/fs/lockd/svc.c
+@@ -295,11 +295,10 @@ static void lockd_down_net(struct net *n
+ /*
+  * Bring up the lockd process if it's not already up.
+  */
+-int lockd_up(void)
++int lockd_up(struct net *net)
+ {
+       struct svc_serv *serv;
+       int             error = 0;
+-      struct net *net = current->nsproxy->net_ns;
+       mutex_lock(&nlmsvc_mutex);
+       /*
+@@ -378,12 +377,12 @@ EXPORT_SYMBOL_GPL(lockd_up);
+  * Decrement the user count and bring down lockd if we're the last.
+  */
+ void
+-lockd_down(void)
++lockd_down(struct net *net)
+ {
+       mutex_lock(&nlmsvc_mutex);
+       if (nlmsvc_users) {
+               if (--nlmsvc_users) {
+-                      lockd_down_net(current->nsproxy->net_ns);
++                      lockd_down_net(net);
+                       goto out;
+               }
+       } else {
+--- a/fs/nfsd/nfssvc.c
++++ b/fs/nfsd/nfssvc.c
+@@ -220,7 +220,7 @@ static int nfsd_startup(unsigned short p
+       ret = nfsd_init_socks(port);
+       if (ret)
+               goto out_racache;
+-      ret = lockd_up();
++      ret = lockd_up(&init_net);
+       if (ret)
+               goto out_racache;
+       ret = nfs4_state_start();
+@@ -229,7 +229,7 @@ static int nfsd_startup(unsigned short p
+       nfsd_up = true;
+       return 0;
+ out_lockd:
+-      lockd_down();
++      lockd_down(&init_net);
+ out_racache:
+       nfsd_racache_shutdown();
+       return ret;
+@@ -246,7 +246,7 @@ static void nfsd_shutdown(void)
+       if (!nfsd_up)
+               return;
+       nfs4_state_shutdown();
+-      lockd_down();
++      lockd_down(&init_net);
+       nfsd_racache_shutdown();
+       nfsd_up = false;
+ }
+--- a/include/linux/lockd/bind.h
++++ b/include/linux/lockd/bind.h
+@@ -54,7 +54,7 @@ extern void  nlmclnt_done(struct nlm_host
+ extern int    nlmclnt_proc(struct nlm_host *host, int cmd,
+                                       struct file_lock *fl);
+-extern int    lockd_up(void);
+-extern void   lockd_down(void);
++extern int    lockd_up(struct net *net);
++extern void   lockd_down(struct net *net);
+ #endif /* LINUX_LOCKD_BIND_H */
diff --git a/queue-3.4/mac80211-fix-queues-stuck-issue-with-ht-bandwidth-change.patch b/queue-3.4/mac80211-fix-queues-stuck-issue-with-ht-bandwidth-change.patch
new file mode 100644 (file)
index 0000000..ea1e1ea
--- /dev/null
@@ -0,0 +1,84 @@
+From johannes@sipsolutions.net  Wed Jul 11 14:39:54 2012
+From: Johannes Berg <johannes@sipsolutions.net>
+Date: Wed, 27 Jun 2012 18:11:56 +0200
+Subject: mac80211: fix queues stuck issue with HT bandwidth change
+To: stable@vger.kernel.org
+Message-ID: <1340813516.11012.46.camel@jlt3.sipsolutions.net>
+
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+No upstream commit, the buggy code was removed in 3.5 in commit
+7213cf2cb0dfbb4d6b55a1da000d34338f76c0e3 and others.
+
+Rajkumar changed code for handling channel switching in
+mac80211 to stop the queues in
+
+  commit 7cc44ed48d0ec0937c1f098642540b6c9ca38de5
+  Author: Rajkumar Manoharan <rmanohar@qca.qualcomm.com>
+  Date:   Fri Sep 16 15:32:34 2011 +0530
+
+      mac80211: Fix regression on queue stop during 2040 bss change
+
+which went into 3.2. In the 3.4 cycle, Paul's change
+
+  commit 3117bbdb7899d43927c8ce4fe885ab7c1231c121
+  Author: Paul Stewart <pstew@chromium.org>
+  Date:   Tue Mar 13 07:46:18 2012 -0700
+
+      mac80211: Don't let regulatory make us deaf
+
+went in and changed the TX/RX enable logic, but now
+the conditions for stopping and restarting the queues
+were different so that now, if the AP changes between
+20/40 MHz bandwidth, it can happen that we stop but
+never restart the queues. This breaks the connection
+and the module actually has to be reloaded to get it
+back to work.
+
+Fix this by making sure the queues are always started
+when they were stopped.
+
+Reported-by: Florian Manschwetus <manschwetus@googlemail.com>
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/mac80211/mlme.c |   11 ++++++-----
+ 1 file changed, 6 insertions(+), 5 deletions(-)
+
+--- a/net/mac80211/mlme.c
++++ b/net/mac80211/mlme.c
+@@ -187,7 +187,7 @@ static u32 ieee80211_enable_ht(struct ie
+       u32 changed = 0;
+       int hti_cfreq;
+       u16 ht_opmode;
+-      bool enable_ht = true;
++      bool enable_ht = true, queues_stopped = false;
+       enum nl80211_channel_type prev_chantype;
+       enum nl80211_channel_type rx_channel_type = NL80211_CHAN_NO_HT;
+       enum nl80211_channel_type tx_channel_type;
+@@ -254,6 +254,7 @@ static u32 ieee80211_enable_ht(struct ie
+                */
+               ieee80211_stop_queues_by_reason(&sdata->local->hw,
+                               IEEE80211_QUEUE_STOP_REASON_CHTYPE_CHANGE);
++              queues_stopped = true;
+               /* flush out all packets */
+               synchronize_net();
+@@ -272,12 +273,12 @@ static u32 ieee80211_enable_ht(struct ie
+                                                IEEE80211_RC_HT_CHANGED,
+                                                tx_channel_type);
+               rcu_read_unlock();
+-
+-              if (beacon_htcap_ie)
+-                      ieee80211_wake_queues_by_reason(&sdata->local->hw,
+-                              IEEE80211_QUEUE_STOP_REASON_CHTYPE_CHANGE);
+       }
++      if (queues_stopped)
++              ieee80211_wake_queues_by_reason(&sdata->local->hw,
++                      IEEE80211_QUEUE_STOP_REASON_CHTYPE_CHANGE);
++
+       ht_opmode = le16_to_cpu(hti->operation_mode);
+       /* if bss configuration changed store the new one */
diff --git a/queue-3.4/nfs-hard-code-init_net-for-nfs-callback-transports.patch b/queue-3.4/nfs-hard-code-init_net-for-nfs-callback-transports.patch
new file mode 100644 (file)
index 0000000..9da7b80
--- /dev/null
@@ -0,0 +1,81 @@
+From bfields@redhat.com  Wed Jul 11 14:39:26 2012
+From: "J. Bruce Fields" <bfields@redhat.com>
+Date: Mon, 25 Jun 2012 16:40:10 -0400
+Subject: NFS: hard-code init_net for NFS callback transports
+To: stable@vger.kernel.org
+Cc: Stanislav Kinsbursky <skinsbursky@parallels.com>, linux-nfs@vger.kernel.org, "J. Bruce Fields" <bfields@redhat.com>
+Message-ID: <1340656810-13752-4-git-send-email-bfields@redhat.com>
+
+
+From: Stanislav Kinsbursky <skinsbursky@parallels.com>
+
+upstream commit 12918b10d59e975fd5241eef03ef9e6d5ea3dcfe.
+
+In case of destroying mount namespace on child reaper exit, nsproxy is zeroed
+to the point already. So, dereferencing of it is invalid.
+This patch hard-code "init_net" for all network namespace references for NFS
+callback services. This will be fixed with proper NFS callback
+containerization.
+
+Signed-off-by: Stanislav Kinsbursky <skinsbursky@parallels.com>
+Signed-off-by: J. Bruce Fields <bfields@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfs/callback.c |   11 +++++------
+ 1 file changed, 5 insertions(+), 6 deletions(-)
+
+--- a/fs/nfs/callback.c
++++ b/fs/nfs/callback.c
+@@ -17,7 +17,6 @@
+ #include <linux/kthread.h>
+ #include <linux/sunrpc/svcauth_gss.h>
+ #include <linux/sunrpc/bc_xprt.h>
+-#include <linux/nsproxy.h>
+ #include <net/inet_sock.h>
+@@ -107,7 +106,7 @@ nfs4_callback_up(struct svc_serv *serv,
+ {
+       int ret;
+-      ret = svc_create_xprt(serv, "tcp", xprt->xprt_net, PF_INET,
++      ret = svc_create_xprt(serv, "tcp", &init_net, PF_INET,
+                               nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
+       if (ret <= 0)
+               goto out_err;
+@@ -115,7 +114,7 @@ nfs4_callback_up(struct svc_serv *serv,
+       dprintk("NFS: Callback listener port = %u (af %u)\n",
+                       nfs_callback_tcpport, PF_INET);
+-      ret = svc_create_xprt(serv, "tcp", xprt->xprt_net, PF_INET6,
++      ret = svc_create_xprt(serv, "tcp", &init_net, PF_INET6,
+                               nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
+       if (ret > 0) {
+               nfs_callback_tcpport6 = ret;
+@@ -184,7 +183,7 @@ nfs41_callback_up(struct svc_serv *serv,
+        * fore channel connection.
+        * Returns the input port (0) and sets the svc_serv bc_xprt on success
+        */
+-      ret = svc_create_xprt(serv, "tcp-bc", xprt->xprt_net, PF_INET, 0,
++      ret = svc_create_xprt(serv, "tcp-bc", &init_net, PF_INET, 0,
+                             SVC_SOCK_ANONYMOUS);
+       if (ret < 0) {
+               rqstp = ERR_PTR(ret);
+@@ -254,7 +253,7 @@ int nfs_callback_up(u32 minorversion, st
+       char svc_name[12];
+       int ret = 0;
+       int minorversion_setup;
+-      struct net *net = current->nsproxy->net_ns;
++      struct net *net = &init_net;
+       mutex_lock(&nfs_callback_mutex);
+       if (cb_info->users++ || cb_info->task != NULL) {
+@@ -330,7 +329,7 @@ void nfs_callback_down(int minorversion)
+       cb_info->users--;
+       if (cb_info->users == 0 && cb_info->task != NULL) {
+               kthread_stop(cb_info->task);
+-              svc_shutdown_net(cb_info->serv, current->nsproxy->net_ns);
++              svc_shutdown_net(cb_info->serv, &init_net);
+               svc_exit_thread(cb_info->rqst);
+               cb_info->serv = NULL;
+               cb_info->rqst = NULL;
index ab6203ba97f7e0a569f40c076622c33f25b82b5c..8a435f2c7fbaac4e22677ca1078cdc567bf216f0 100644 (file)
@@ -153,3 +153,10 @@ usb-option-add-mediatek-product-ids.patch
 usb-add-support-for-root-hub-port-status-cas.patch
 xhci-fix-hang-on-back-to-back-set-tr-deq-ptr-commands.patch
 pci-ehci-fix-crash-during-suspend-on-asus-computers.patch
+ipheth-add-support-for-ipad.patch
+lockd-pass-network-namespace-to-creation-and-destruction-routines.patch
+sunrpc-new-svc_bind-routine-introduced.patch
+sunrpc-move-per-net-operations-from-svc_destroy.patch
+nfs-hard-code-init_net-for-nfs-callback-transports.patch
+mac80211-fix-queues-stuck-issue-with-ht-bandwidth-change.patch
+iwlwifi-remove-log_event-debugfs-file-debugging-is-disabled.patch
diff --git a/queue-3.4/sunrpc-move-per-net-operations-from-svc_destroy.patch b/queue-3.4/sunrpc-move-per-net-operations-from-svc_destroy.patch
new file mode 100644 (file)
index 0000000..4b394bf
--- /dev/null
@@ -0,0 +1,284 @@
+From bfields@redhat.com  Wed Jul 11 14:39:15 2012
+From: "J. Bruce Fields" <bfields@redhat.com>
+Date: Mon, 25 Jun 2012 16:40:09 -0400
+Subject: SUNRPC: move per-net operations from svc_destroy()
+To: stable@vger.kernel.org
+Cc: Stanislav Kinsbursky <skinsbursky@parallels.com>, linux-nfs@vger.kernel.org, "J. Bruce Fields" <bfields@redhat.com>
+Message-ID: <1340656810-13752-3-git-send-email-bfields@redhat.com>
+
+
+From: Stanislav Kinsbursky <skinsbursky@parallels.com>
+
+upstream commit 786185b5f8abefa6a8a16695bb4a59c164d5a071.
+
+The idea is to separate service destruction and per-net operations,
+because these are two different things and the mix looks ugly.
+
+Notes:
+
+1) For NFS server this patch looks ugly (sorry for that). But these
+place will be rewritten soon during NFSd containerization.
+
+2) LockD per-net counter increase int lockd_up() was moved prior to
+make_socks() to make lockd_down_net() call safe in case of error.
+
+Signed-off-by: Stanislav Kinsbursky <skinsbursky@parallels.com>
+Signed-off-by: J. Bruce Fields <bfields@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/lockd/svc.c    |   27 +++++++++++++++------------
+ fs/nfs/callback.c |    3 +++
+ fs/nfsd/nfsctl.c  |   12 +++++++++---
+ fs/nfsd/nfssvc.c  |   14 ++++++++++++++
+ net/sunrpc/svc.c  |    4 ----
+ 5 files changed, 41 insertions(+), 19 deletions(-)
+
+--- a/fs/lockd/svc.c
++++ b/fs/lockd/svc.c
+@@ -257,7 +257,7 @@ static int lockd_up_net(struct net *net)
+       struct svc_serv *serv = nlmsvc_rqst->rq_server;
+       int error;
+-      if (ln->nlmsvc_users)
++      if (ln->nlmsvc_users++)
+               return 0;
+       error = svc_rpcb_setup(serv, net);
+@@ -272,6 +272,7 @@ static int lockd_up_net(struct net *net)
+ err_socks:
+       svc_rpcb_cleanup(serv, net);
+ err_rpcb:
++      ln->nlmsvc_users--;
+       return error;
+ }
+@@ -299,6 +300,7 @@ int lockd_up(struct net *net)
+ {
+       struct svc_serv *serv;
+       int             error = 0;
++      struct lockd_net *ln = net_generic(net, lockd_net_id);
+       mutex_lock(&nlmsvc_mutex);
+       /*
+@@ -330,9 +332,11 @@ int lockd_up(struct net *net)
+               goto destroy_and_out;
+       }
++      ln->nlmsvc_users++;
++
+       error = make_socks(serv, net);
+       if (error < 0)
+-              goto destroy_and_out;
++              goto err_start;
+       /*
+        * Create the kernel thread and wait for it to start.
+@@ -344,7 +348,7 @@ int lockd_up(struct net *net)
+               printk(KERN_WARNING
+                       "lockd_up: svc_rqst allocation failed, error=%d\n",
+                       error);
+-              goto destroy_and_out;
++              goto err_start;
+       }
+       svc_sock_update_bufs(serv);
+@@ -358,7 +362,7 @@ int lockd_up(struct net *net)
+               nlmsvc_rqst = NULL;
+               printk(KERN_WARNING
+                       "lockd_up: kthread_run failed, error=%d\n", error);
+-              goto destroy_and_out;
++              goto err_start;
+       }
+       /*
+@@ -368,14 +372,14 @@ int lockd_up(struct net *net)
+ destroy_and_out:
+       svc_destroy(serv);
+ out:
+-      if (!error) {
+-              struct lockd_net *ln = net_generic(net, lockd_net_id);
+-
+-              ln->nlmsvc_users++;
++      if (!error)
+               nlmsvc_users++;
+-      }
+       mutex_unlock(&nlmsvc_mutex);
+       return error;
++
++err_start:
++      lockd_down_net(net);
++      goto destroy_and_out;
+ }
+ EXPORT_SYMBOL_GPL(lockd_up);
+@@ -386,11 +390,10 @@ void
+ lockd_down(struct net *net)
+ {
+       mutex_lock(&nlmsvc_mutex);
++      lockd_down_net(net);
+       if (nlmsvc_users) {
+-              if (--nlmsvc_users) {
+-                      lockd_down_net(net);
++              if (--nlmsvc_users)
+                       goto out;
+-              }
+       } else {
+               printk(KERN_ERR "lockd_down: no users! task=%p\n",
+                       nlmsvc_task);
+--- a/fs/nfs/callback.c
++++ b/fs/nfs/callback.c
+@@ -314,6 +314,8 @@ out_err:
+       dprintk("NFS: Couldn't create callback socket or server thread; "
+               "err = %d\n", ret);
+       cb_info->users--;
++      if (serv)
++              svc_shutdown_net(serv, net);
+       goto out;
+ }
+@@ -328,6 +330,7 @@ void nfs_callback_down(int minorversion)
+       cb_info->users--;
+       if (cb_info->users == 0 && cb_info->task != NULL) {
+               kthread_stop(cb_info->task);
++              svc_shutdown_net(cb_info->serv, current->nsproxy->net_ns);
+               svc_exit_thread(cb_info->rqst);
+               cb_info->serv = NULL;
+               cb_info->rqst = NULL;
+--- a/fs/nfsd/nfsctl.c
++++ b/fs/nfsd/nfsctl.c
+@@ -651,6 +651,7 @@ static ssize_t __write_ports_addfd(char
+ {
+       char *mesg = buf;
+       int fd, err;
++      struct net *net = &init_net;
+       err = get_int(&mesg, &fd);
+       if (err != 0 || fd < 0)
+@@ -662,6 +663,8 @@ static ssize_t __write_ports_addfd(char
+       err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT);
+       if (err < 0) {
++              if (nfsd_serv->sv_nrthreads == 1)
++                      svc_shutdown_net(nfsd_serv, net);
+               svc_destroy(nfsd_serv);
+               return err;
+       }
+@@ -699,6 +702,7 @@ static ssize_t __write_ports_addxprt(cha
+       char transport[16];
+       struct svc_xprt *xprt;
+       int port, err;
++      struct net *net = &init_net;
+       if (sscanf(buf, "%15s %4u", transport, &port) != 2)
+               return -EINVAL;
+@@ -710,12 +714,12 @@ static ssize_t __write_ports_addxprt(cha
+       if (err != 0)
+               return err;
+-      err = svc_create_xprt(nfsd_serv, transport, &init_net,
++      err = svc_create_xprt(nfsd_serv, transport, net,
+                               PF_INET, port, SVC_SOCK_ANONYMOUS);
+       if (err < 0)
+               goto out_err;
+-      err = svc_create_xprt(nfsd_serv, transport, &init_net,
++      err = svc_create_xprt(nfsd_serv, transport, net,
+                               PF_INET6, port, SVC_SOCK_ANONYMOUS);
+       if (err < 0 && err != -EAFNOSUPPORT)
+               goto out_close;
+@@ -724,12 +728,14 @@ static ssize_t __write_ports_addxprt(cha
+       nfsd_serv->sv_nrthreads--;
+       return 0;
+ out_close:
+-      xprt = svc_find_xprt(nfsd_serv, transport, &init_net, PF_INET, port);
++      xprt = svc_find_xprt(nfsd_serv, transport, net, PF_INET, port);
+       if (xprt != NULL) {
+               svc_close_xprt(xprt);
+               svc_xprt_put(xprt);
+       }
+ out_err:
++      if (nfsd_serv->sv_nrthreads == 1)
++              svc_shutdown_net(nfsd_serv, net);
+       svc_destroy(nfsd_serv);
+       return err;
+ }
+--- a/fs/nfsd/nfssvc.c
++++ b/fs/nfsd/nfssvc.c
+@@ -382,6 +382,7 @@ int nfsd_set_nrthreads(int n, int *nthre
+       int i = 0;
+       int tot = 0;
+       int err = 0;
++      struct net *net = &init_net;
+       WARN_ON(!mutex_is_locked(&nfsd_mutex));
+@@ -426,6 +427,9 @@ int nfsd_set_nrthreads(int n, int *nthre
+               if (err)
+                       break;
+       }
++
++      if (nfsd_serv->sv_nrthreads == 1)
++              svc_shutdown_net(nfsd_serv, net);
+       svc_destroy(nfsd_serv);
+       return err;
+@@ -441,6 +445,7 @@ nfsd_svc(unsigned short port, int nrserv
+ {
+       int     error;
+       bool    nfsd_up_before;
++      struct net *net = &init_net;
+       mutex_lock(&nfsd_mutex);
+       dprintk("nfsd: creating service\n");
+@@ -473,6 +478,8 @@ out_shutdown:
+       if (error < 0 && !nfsd_up_before)
+               nfsd_shutdown();
+ out_destroy:
++      if (nfsd_serv->sv_nrthreads == 1)
++              svc_shutdown_net(nfsd_serv, net);
+       svc_destroy(nfsd_serv);         /* Release server */
+ out:
+       mutex_unlock(&nfsd_mutex);
+@@ -556,6 +563,9 @@ nfsd(void *vrqstp)
+       nfsdstats.th_cnt --;
+ out:
++      if (rqstp->rq_server->sv_nrthreads == 1)
++              svc_shutdown_net(rqstp->rq_server, &init_net);
++
+       /* Release the thread */
+       svc_exit_thread(rqstp);
+@@ -668,8 +678,12 @@ int nfsd_pool_stats_open(struct inode *i
+ int nfsd_pool_stats_release(struct inode *inode, struct file *file)
+ {
+       int ret = seq_release(inode, file);
++      struct net *net = &init_net;
++
+       mutex_lock(&nfsd_mutex);
+       /* this function really, really should have been called svc_put() */
++      if (nfsd_serv->sv_nrthreads == 1)
++              svc_shutdown_net(nfsd_serv, net);
+       svc_destroy(nfsd_serv);
+       mutex_unlock(&nfsd_mutex);
+       return ret;
+--- a/net/sunrpc/svc.c
++++ b/net/sunrpc/svc.c
+@@ -537,8 +537,6 @@ EXPORT_SYMBOL_GPL(svc_shutdown_net);
+ void
+ svc_destroy(struct svc_serv *serv)
+ {
+-      struct net *net = current->nsproxy->net_ns;
+-
+       dprintk("svc: svc_destroy(%s, %d)\n",
+                               serv->sv_program->pg_name,
+                               serv->sv_nrthreads);
+@@ -553,8 +551,6 @@ svc_destroy(struct svc_serv *serv)
+       del_timer_sync(&serv->sv_temptimer);
+-      svc_shutdown_net(serv, net);
+-
+       /*
+        * The last user is gone and thus all sockets have to be destroyed to
+        * the point. Check this.
diff --git a/queue-3.4/sunrpc-new-svc_bind-routine-introduced.patch b/queue-3.4/sunrpc-new-svc_bind-routine-introduced.patch
new file mode 100644 (file)
index 0000000..93935be
--- /dev/null
@@ -0,0 +1,182 @@
+From bfields@redhat.com  Wed Jul 11 14:39:03 2012
+From: "J. Bruce Fields" <bfields@redhat.com>
+Date: Mon, 25 Jun 2012 16:40:08 -0400
+Subject: SUNRPC: new svc_bind() routine introduced
+To: stable@vger.kernel.org
+Cc: Stanislav Kinsbursky <skinsbursky@parallels.com>, linux-nfs@vger.kernel.org, "J. Bruce Fields" <bfields@redhat.com>
+Message-ID: <1340656810-13752-2-git-send-email-bfields@redhat.com>
+
+
+From: Stanislav Kinsbursky <skinsbursky@parallels.com>
+
+upstream commit 9793f7c88937e7ac07305ab1af1a519225836823.
+
+This new routine is responsible for service registration in a specified
+network context.
+
+The idea is to separate service creation from per-net operations.
+
+Note also: since registering service with svc_bind() can fail, the
+service will be destroyed and during destruction it will try to
+unregister itself from rpcbind. In this case unregistration has to be
+skipped.
+
+Signed-off-by: Stanislav Kinsbursky <skinsbursky@parallels.com>
+Signed-off-by: J. Bruce Fields <bfields@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/lockd/svc.c             |    6 ++++++
+ fs/nfs/callback.c          |    8 ++++++++
+ fs/nfsd/nfssvc.c           |    9 +++++++++
+ include/linux/sunrpc/svc.h |    1 +
+ net/sunrpc/rpcb_clnt.c     |   12 +++++++-----
+ net/sunrpc/svc.c           |   19 ++++++++++---------
+ 6 files changed, 41 insertions(+), 14 deletions(-)
+
+--- a/fs/lockd/svc.c
++++ b/fs/lockd/svc.c
+@@ -324,6 +324,12 @@ int lockd_up(struct net *net)
+               goto out;
+       }
++      error = svc_bind(serv, net);
++      if (error < 0) {
++              printk(KERN_WARNING "lockd_up: bind service failed\n");
++              goto destroy_and_out;
++      }
++
+       error = make_socks(serv, net);
+       if (error < 0)
+               goto destroy_and_out;
+--- a/fs/nfs/callback.c
++++ b/fs/nfs/callback.c
+@@ -17,6 +17,7 @@
+ #include <linux/kthread.h>
+ #include <linux/sunrpc/svcauth_gss.h>
+ #include <linux/sunrpc/bc_xprt.h>
++#include <linux/nsproxy.h>
+ #include <net/inet_sock.h>
+@@ -253,6 +254,7 @@ int nfs_callback_up(u32 minorversion, st
+       char svc_name[12];
+       int ret = 0;
+       int minorversion_setup;
++      struct net *net = current->nsproxy->net_ns;
+       mutex_lock(&nfs_callback_mutex);
+       if (cb_info->users++ || cb_info->task != NULL) {
+@@ -265,6 +267,12 @@ int nfs_callback_up(u32 minorversion, st
+               goto out_err;
+       }
++      ret = svc_bind(serv, net);
++      if (ret < 0) {
++              printk(KERN_WARNING "NFS: bind callback service failed\n");
++              goto out_err;
++      }
++
+       minorversion_setup =  nfs_minorversion_callback_svc_setup(minorversion,
+                                       serv, xprt, &rqstp, &callback_svc);
+       if (!minorversion_setup) {
+--- a/fs/nfsd/nfssvc.c
++++ b/fs/nfsd/nfssvc.c
+@@ -11,6 +11,7 @@
+ #include <linux/module.h>
+ #include <linux/fs_struct.h>
+ #include <linux/swap.h>
++#include <linux/nsproxy.h>
+ #include <linux/sunrpc/stats.h>
+ #include <linux/sunrpc/svcsock.h>
+@@ -330,6 +331,8 @@ static int nfsd_get_default_max_blksize(
+ int nfsd_create_serv(void)
+ {
++      int error;
++
+       WARN_ON(!mutex_is_locked(&nfsd_mutex));
+       if (nfsd_serv) {
+               svc_get(nfsd_serv);
+@@ -343,6 +346,12 @@ int nfsd_create_serv(void)
+       if (nfsd_serv == NULL)
+               return -ENOMEM;
++      error = svc_bind(nfsd_serv, current->nsproxy->net_ns);
++      if (error < 0) {
++              svc_destroy(nfsd_serv);
++              return error;
++      }
++
+       set_max_drc();
+       do_gettimeofday(&nfssvc_boot);          /* record boot time */
+       return 0;
+--- a/include/linux/sunrpc/svc.h
++++ b/include/linux/sunrpc/svc.h
+@@ -416,6 +416,7 @@ struct svc_procedure {
+  */
+ int svc_rpcb_setup(struct svc_serv *serv, struct net *net);
+ void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net);
++int svc_bind(struct svc_serv *serv, struct net *net);
+ struct svc_serv *svc_create(struct svc_program *, unsigned int,
+                           void (*shutdown)(struct svc_serv *, struct net *net));
+ struct svc_rqst *svc_prepare_thread(struct svc_serv *serv,
+--- a/net/sunrpc/rpcb_clnt.c
++++ b/net/sunrpc/rpcb_clnt.c
+@@ -180,14 +180,16 @@ void rpcb_put_local(struct net *net)
+       struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+       struct rpc_clnt *clnt = sn->rpcb_local_clnt;
+       struct rpc_clnt *clnt4 = sn->rpcb_local_clnt4;
+-      int shutdown;
++      int shutdown = 0;
+       spin_lock(&sn->rpcb_clnt_lock);
+-      if (--sn->rpcb_users == 0) {
+-              sn->rpcb_local_clnt = NULL;
+-              sn->rpcb_local_clnt4 = NULL;
++      if (sn->rpcb_users) {
++              if (--sn->rpcb_users == 0) {
++                      sn->rpcb_local_clnt = NULL;
++                      sn->rpcb_local_clnt4 = NULL;
++              }
++              shutdown = !sn->rpcb_users;
+       }
+-      shutdown = !sn->rpcb_users;
+       spin_unlock(&sn->rpcb_clnt_lock);
+       if (shutdown) {
+--- a/net/sunrpc/svc.c
++++ b/net/sunrpc/svc.c
+@@ -407,6 +407,14 @@ static int svc_uses_rpcbind(struct svc_s
+       return 0;
+ }
++int svc_bind(struct svc_serv *serv, struct net *net)
++{
++      if (!svc_uses_rpcbind(serv))
++              return 0;
++      return svc_rpcb_setup(serv, net);
++}
++EXPORT_SYMBOL_GPL(svc_bind);
++
+ /*
+  * Create an RPC service
+  */
+@@ -471,15 +479,8 @@ __svc_create(struct svc_program *prog, u
+               spin_lock_init(&pool->sp_lock);
+       }
+-      if (svc_uses_rpcbind(serv)) {
+-              if (svc_rpcb_setup(serv, current->nsproxy->net_ns) < 0) {
+-                      kfree(serv->sv_pools);
+-                      kfree(serv);
+-                      return NULL;
+-              }
+-              if (!serv->sv_shutdown)
+-                      serv->sv_shutdown = svc_rpcb_cleanup;
+-      }
++      if (svc_uses_rpcbind(serv) && (!serv->sv_shutdown))
++              serv->sv_shutdown = svc_rpcb_cleanup;
+       return serv;
+ }