if (host->h_rpcclnt == NULL && nlm_bind_host(host) == NULL)
                goto out_nobind;
 
+       host->h_nlmclnt_ops = nlm_init->nlmclnt_ops;
        return host;
 out_nobind:
        nlmclnt_release_host(host);
 
  * @host: address of a valid nlm_host context representing the NLM server
  * @cmd: fcntl-style file lock operation to perform
  * @fl: address of arguments for the lock operation
+ * @data: address of data to be sent to callback operations
  *
  */
-int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl)
+int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl, void *data)
 {
        struct nlm_rqst         *call;
        int                     status;
+       const struct nlmclnt_operations *nlmclnt_ops = host->h_nlmclnt_ops;
 
        call = nlm_alloc_call(host);
        if (call == NULL)
                return -ENOMEM;
 
+       if (nlmclnt_ops && nlmclnt_ops->nlmclnt_alloc_call)
+               nlmclnt_ops->nlmclnt_alloc_call(data);
+
        nlmclnt_locks_init_private(fl, host);
        if (!fl->fl_u.nfs_fl.owner) {
                /* lockowner allocation has failed */
        }
        /* Set up the argument struct */
        nlmclnt_setlockargs(call, fl);
+       call->a_callback_data = data;
 
        if (IS_SETLK(cmd) || IS_SETLKW(cmd)) {
                if (fl->fl_type != F_UNLCK) {
 
 void nlmclnt_release_call(struct nlm_rqst *call)
 {
+       const struct nlmclnt_operations *nlmclnt_ops = call->a_host->h_nlmclnt_ops;
+
        if (!atomic_dec_and_test(&call->a_count))
                return;
+       if (nlmclnt_ops && nlmclnt_ops->nlmclnt_release_call)
+               nlmclnt_ops->nlmclnt_release_call(call->a_callback_data);
        nlmclnt_release_host(call->a_host);
        nlmclnt_release_lockargs(call);
        kfree(call);
        return status;
 }
 
+static void nlmclnt_unlock_prepare(struct rpc_task *task, void *data)
+{
+       struct nlm_rqst *req = data;
+       const struct nlmclnt_operations *nlmclnt_ops = req->a_host->h_nlmclnt_ops;
+       bool defer_call = false;
+
+       if (nlmclnt_ops && nlmclnt_ops->nlmclnt_unlock_prepare)
+               defer_call = nlmclnt_ops->nlmclnt_unlock_prepare(task, req->a_callback_data);
+
+       if (!defer_call)
+               rpc_call_start(task);
+}
+
 static void nlmclnt_unlock_callback(struct rpc_task *task, void *data)
 {
        struct nlm_rqst *req = data;
 }
 
 static const struct rpc_call_ops nlmclnt_unlock_ops = {
+       .rpc_call_prepare = nlmclnt_unlock_prepare,
        .rpc_call_done = nlmclnt_unlock_callback,
        .rpc_release = nlmclnt_rpc_release,
 };
 
                .noresvport     = server->flags & NFS_MOUNT_NORESVPORT ?
                                        1 : 0,
                .net            = clp->cl_net,
+               .nlmclnt_ops    = clp->cl_nfs_mod->rpc_ops->nlmclnt_ops,
        };
 
        if (nlm_init.nfs_version > 3)
 
 {
        struct inode *inode = file_inode(filp);
 
-       return nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl);
+       return nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl, NULL);
 }
 
 static int nfs3_have_delegation(struct inode *inode, fmode_t flags)
 
 {
        struct inode *inode = file_inode(filp);
 
-       return nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl);
+       return nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl, NULL);
 }
 
 /* Helper functions for NFS lock bounds checking */
 
 
 /* Dummy declarations */
 struct svc_rqst;
+struct rpc_task;
 
 /*
  * This is the set of functions for lockd->nfsd communication
        u32                     nfs_version;
        int                     noresvport;
        struct net              *net;
+       const struct nlmclnt_operations *nlmclnt_ops;
 };
 
 /*
 extern struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init);
 extern void    nlmclnt_done(struct nlm_host *host);
 
-extern int     nlmclnt_proc(struct nlm_host *host, int cmd,
-                                       struct file_lock *fl);
+/*
+ * NLM client operations provide a means to modify RPC processing of NLM
+ * requests.  Callbacks receive a pointer to data passed into the call to
+ * nlmclnt_proc().
+ */
+struct nlmclnt_operations {
+       /* Called on successful allocation of nlm_rqst, use for allocation or
+        * reference counting. */
+       void (*nlmclnt_alloc_call)(void *);
+
+       /* Called in rpc_task_prepare for unlock.  A return value of true
+        * indicates the callback has put the task to sleep on a waitqueue
+        * and NLM should not call rpc_call_start(). */
+       bool (*nlmclnt_unlock_prepare)(struct rpc_task*, void *);
+
+       /* Called when the nlm_rqst is freed, callbacks should clean up here */
+       void (*nlmclnt_release_call)(void *);
+};
+
+extern int     nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl, void *data);
 extern int     lockd_up(struct net *net);
 extern void    lockd_down(struct net *net);
 
 
        char                    *h_addrbuf;     /* address eyecatcher */
        struct net              *net;           /* host net */
        char                    nodename[UNX_MAXNODENAME + 1];
+       const struct nlmclnt_operations *h_nlmclnt_ops; /* Callback ops for NLM users */
 };
 
 /*
        struct nlm_block *      a_block;
        unsigned int            a_retries;      /* Retry count */
        u8                      a_owner[NLMCLNT_OHSIZE];
+       void *  a_callback_data; /* sent to nlmclnt_operations callbacks */
 };
 
 /*
 
        const struct inode_operations *dir_inode_ops;
        const struct inode_operations *file_inode_ops;
        const struct file_operations *file_ops;
+       const struct nlmclnt_operations *nlmclnt_ops;
 
        int     (*getroot) (struct nfs_server *, struct nfs_fh *,
                            struct nfs_fsinfo *);