*/
 static DECLARE_WAIT_QUEUE_HEAD(close_wq);
 
+/*
+ * A waitqueue where a writer to clients/#/ctl destroying a client can
+ * wait for cl_rpc_users to drop to 0 and then for the client to be
+ * unhashed.
+ */
+static DECLARE_WAIT_QUEUE_HEAD(expiry_wq);
+
 static struct kmem_cache *client_slab;
 static struct kmem_cache *openowner_slab;
 static struct kmem_cache *lockowner_slab;
                return;
        if (!is_client_expired(clp))
                renew_client_locked(clp);
+       else
+               wake_up_all(&expiry_wq);
 }
 
 static void put_client_renew(struct nfs4_client *clp)
                return;
        if (!is_client_expired(clp))
                renew_client_locked(clp);
+       else
+               wake_up_all(&expiry_wq);
        spin_unlock(&nn->client_lock);
 }
 
                free_session(ses);
        }
        rpc_destroy_wait_queue(&clp->cl_cb_waitq);
-       if (clp->cl_nfsd_dentry)
+       if (clp->cl_nfsd_dentry) {
                nfsd_client_rmdir(clp->cl_nfsd_dentry);
+               clp->cl_nfsd_dentry = NULL;
+               wake_up_all(&expiry_wq);
+       }
        drop_client(clp);
 }
 
        if (clp->cl_cb_conn.cb_xprt)
                svc_xprt_put(clp->cl_cb_conn.cb_xprt);
        free_client(clp);
+       wake_up_all(&expiry_wq);
 }
 
 static void
        .release        = client_opens_release,
 };
 
+/*
+ * Normally we refuse to destroy clients that are in use, but here the
+ * administrator is telling us to just do it.  We also want to wait
+ * so the caller has a guarantee that the client's locks are gone by
+ * the time the write returns:
+ */
+void force_expire_client(struct nfs4_client *clp)
+{
+       struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
+       bool already_expired;
+
+       spin_lock(&clp->cl_lock);
+       clp->cl_time = 0;
+       spin_unlock(&clp->cl_lock);
+
+       wait_event(expiry_wq, atomic_read(&clp->cl_rpc_users) == 0);
+       spin_lock(&nn->client_lock);
+       already_expired = list_empty(&clp->cl_lru);
+       if (!already_expired)
+               unhash_client_locked(clp);
+       spin_unlock(&nn->client_lock);
+
+       if (!already_expired)
+               expire_client(clp);
+       else
+               wait_event(expiry_wq, clp->cl_nfsd_dentry == NULL);
+}
+
+static ssize_t client_ctl_write(struct file *file, const char __user *buf,
+                                  size_t size, loff_t *pos)
+{
+       char *data;
+       struct nfs4_client *clp;
+
+       data = simple_transaction_get(file, buf, size);
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+       if (size != 7 || 0 != memcmp(data, "expire\n", 7))
+               return -EINVAL;
+       clp = get_nfsdfs_clp(file_inode(file));
+       if (!clp)
+               return -ENXIO;
+       force_expire_client(clp);
+       drop_client(clp);
+       return 7;
+}
+
+static const struct file_operations client_ctl_fops = {
+       .write          = client_ctl_write,
+       .release        = simple_transaction_release,
+};
+
 static const struct tree_descr client_files[] = {
        [0] = {"info", &client_info_fops, S_IRUSR},
        [1] = {"states", &client_states_fops, S_IRUSR},
+       [2] = {"ctl", &client_ctl_fops, S_IRUSR|S_IWUSR},
        [3] = {""},
 };