if (!IS_ERR(l_ctx)) {
                status = nfs_iocounter_wait(l_ctx);
                nfs_put_lock_context(l_ctx);
-               if (status < 0)
+               /*  NOTE: special case
+                *      If we're signalled while cleaning up locks on process exit, we
+                *      still need to complete the unlock.
+                */
+               if (status < 0 && !(fl->fl_flags & FL_CLOSE))
                        return status;
        }
 
-       /* NOTE: special case
-        *      If we're signalled while cleaning up locks on process exit, we
-        *      still need to complete the unlock.
-        */
        /*
         * Use local locking if mounted with "-onolock" or with appropriate
         * "-olocal_lock="
 
        msg->rpc_proc = &nfs3_procedures[NFS3PROC_COMMIT];
 }
 
+void nfs3_nlm_alloc_call(void *data)
+{
+       struct nfs_lock_context *l_ctx = data;
+       if (l_ctx && test_bit(NFS_CONTEXT_UNLOCK, &l_ctx->open_context->flags)) {
+               get_nfs_open_context(l_ctx->open_context);
+               nfs_get_lock_context(l_ctx->open_context);
+       }
+}
+
+bool nfs3_nlm_unlock_prepare(struct rpc_task *task, void *data)
+{
+       struct nfs_lock_context *l_ctx = data;
+       if (l_ctx && test_bit(NFS_CONTEXT_UNLOCK, &l_ctx->open_context->flags))
+               return nfs_async_iocounter_wait(task, l_ctx);
+       return false;
+
+}
+
+void nfs3_nlm_release_call(void *data)
+{
+       struct nfs_lock_context *l_ctx = data;
+       struct nfs_open_context *ctx;
+       if (l_ctx && test_bit(NFS_CONTEXT_UNLOCK, &l_ctx->open_context->flags)) {
+               ctx = l_ctx->open_context;
+               nfs_put_lock_context(l_ctx);
+               put_nfs_open_context(ctx);
+       }
+}
+
+const struct nlmclnt_operations nlmclnt_fl_close_lock_ops = {
+       .nlmclnt_alloc_call = nfs3_nlm_alloc_call,
+       .nlmclnt_unlock_prepare = nfs3_nlm_unlock_prepare,
+       .nlmclnt_release_call = nfs3_nlm_release_call,
+};
+
 static int
 nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
 {
        struct inode *inode = file_inode(filp);
+       struct nfs_lock_context *l_ctx = NULL;
+       struct nfs_open_context *ctx = nfs_file_open_context(filp);
+       int status;
 
-       return nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl, NULL);
+       if (fl->fl_flags & FL_CLOSE) {
+               l_ctx = nfs_get_lock_context(ctx);
+               if (IS_ERR(l_ctx))
+                       l_ctx = NULL;
+               else
+                       set_bit(NFS_CONTEXT_UNLOCK, &ctx->flags);
+       }
+
+       status = nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl, l_ctx);
+
+       if (l_ctx)
+               nfs_put_lock_context(l_ctx);
+
+       return status;
 }
 
 static int nfs3_have_delegation(struct inode *inode, fmode_t flags)
        .dir_inode_ops  = &nfs3_dir_inode_operations,
        .file_inode_ops = &nfs3_file_inode_operations,
        .file_ops       = &nfs_file_operations,
+       .nlmclnt_ops    = &nlmclnt_fl_close_lock_ops,
        .getroot        = nfs3_proc_get_root,
        .submount       = nfs_submount,
        .try_mount      = nfs_try_mount,
 
        struct nfs_locku_res res;
        struct nfs4_lock_state *lsp;
        struct nfs_open_context *ctx;
+       struct nfs_lock_context *l_ctx;
        struct file_lock fl;
        struct nfs_server *server;
        unsigned long timestamp;
        atomic_inc(&lsp->ls_count);
        /* Ensure we don't close file until we're done freeing locks! */
        p->ctx = get_nfs_open_context(ctx);
+       p->l_ctx = nfs_get_lock_context(ctx);
        memcpy(&p->fl, fl, sizeof(p->fl));
        p->server = NFS_SERVER(inode);
        return p;
        struct nfs4_unlockdata *calldata = data;
        nfs_free_seqid(calldata->arg.seqid);
        nfs4_put_lock_state(calldata->lsp);
+       nfs_put_lock_context(calldata->l_ctx);
        put_nfs_open_context(calldata->ctx);
        kfree(calldata);
 }
 {
        struct nfs4_unlockdata *calldata = data;
 
+       if (test_bit(NFS_CONTEXT_UNLOCK, &calldata->l_ctx->open_context->flags) &&
+               nfs_async_iocounter_wait(task, calldata->l_ctx))
+               return;
+
        if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0)
                goto out_wait;
        nfs4_stateid_copy(&calldata->arg.stateid, &calldata->lsp->ls_stateid);
         * canceled lock is passed in, and it won't be an unlock.
         */
        fl->fl_type = F_UNLCK;
+       if (fl->fl_flags & FL_CLOSE)
+               set_bit(NFS_CONTEXT_UNLOCK, &ctx->flags);
 
        data = nfs4_alloc_unlockdata(fl, ctx, lsp, seqid);
        if (data == NULL) {