aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfs/nfs4_fs.h1
-rw-r--r--fs/nfs/nfs4proc.c161
-rw-r--r--fs/nfs/nfs4state.c2
-rw-r--r--fs/nfs/nfs4xdr.c9
-rw-r--r--include/linux/nfs_xdr.h2
5 files changed, 116 insertions, 59 deletions
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index d4fcb5d0ce6c..2215cdee43ae 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -249,6 +249,7 @@ extern void nfs4_put_open_state(struct nfs4_state *);
249extern void nfs4_close_state(struct nfs4_state *, mode_t); 249extern void nfs4_close_state(struct nfs4_state *, mode_t);
250extern struct nfs4_state *nfs4_find_state(struct inode *, struct rpc_cred *, mode_t mode); 250extern struct nfs4_state *nfs4_find_state(struct inode *, struct rpc_cred *, mode_t mode);
251extern void nfs4_schedule_state_recovery(struct nfs4_client *); 251extern void nfs4_schedule_state_recovery(struct nfs4_client *);
252extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp);
252extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); 253extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl);
253extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t); 254extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t);
254 255
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index f57dba815099..612a9a14aed3 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -58,9 +58,9 @@
58 58
59static int _nfs4_proc_open_confirm(struct rpc_clnt *clnt, const struct nfs_fh *fh, struct nfs4_state_owner *sp, nfs4_stateid *stateid, struct nfs_seqid *seqid); 59static int _nfs4_proc_open_confirm(struct rpc_clnt *clnt, const struct nfs_fh *fh, struct nfs4_state_owner *sp, nfs4_stateid *stateid, struct nfs_seqid *seqid);
60static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); 60static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
61static int nfs4_async_handle_error(struct rpc_task *, struct nfs_server *); 61static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *);
62static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry); 62static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry);
63static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_exception *exception); 63static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception);
64extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); 64extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus);
65extern struct rpc_procinfo nfs4_procedures[]; 65extern struct rpc_procinfo nfs4_procedures[];
66 66
@@ -2422,7 +2422,7 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen
2422} 2422}
2423 2423
2424static int 2424static int
2425nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server) 2425nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server)
2426{ 2426{
2427 struct nfs4_client *clp = server->nfs4_state; 2427 struct nfs4_client *clp = server->nfs4_state;
2428 2428
@@ -2500,7 +2500,7 @@ static int nfs4_delay(struct rpc_clnt *clnt, long *timeout)
2500/* This is the error handling routine for processes that are allowed 2500/* This is the error handling routine for processes that are allowed
2501 * to sleep. 2501 * to sleep.
2502 */ 2502 */
2503int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_exception *exception) 2503int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception)
2504{ 2504{
2505 struct nfs4_client *clp = server->nfs4_state; 2505 struct nfs4_client *clp = server->nfs4_state;
2506 int ret = errorcode; 2506 int ret = errorcode;
@@ -2763,68 +2763,127 @@ static int do_vfs_lock(struct file *file, struct file_lock *fl)
2763 return res; 2763 return res;
2764} 2764}
2765 2765
2766static int _nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request) 2766struct nfs4_unlockdata {
2767 struct nfs_lockargs arg;
2768 struct nfs_locku_opargs luargs;
2769 struct nfs_lockres res;
2770 struct nfs4_lock_state *lsp;
2771 struct nfs_open_context *ctx;
2772 atomic_t refcount;
2773 struct completion completion;
2774};
2775
2776static void nfs4_locku_release_calldata(struct nfs4_unlockdata *calldata)
2767{ 2777{
2768 struct inode *inode = state->inode; 2778 if (atomic_dec_and_test(&calldata->refcount)) {
2769 struct nfs_server *server = NFS_SERVER(inode); 2779 nfs_free_seqid(calldata->luargs.seqid);
2770 struct nfs_lockargs arg = { 2780 nfs4_put_lock_state(calldata->lsp);
2771 .fh = NFS_FH(inode), 2781 put_nfs_open_context(calldata->ctx);
2772 .type = nfs4_lck_type(cmd, request), 2782 kfree(calldata);
2773 .offset = request->fl_start, 2783 }
2774 .length = nfs4_lck_length(request), 2784}
2775 }; 2785
2776 struct nfs_lockres res = { 2786static void nfs4_locku_complete(struct nfs4_unlockdata *calldata)
2777 .server = server, 2787{
2778 }; 2788 complete(&calldata->completion);
2789 nfs4_locku_release_calldata(calldata);
2790}
2791
2792static void nfs4_locku_done(struct rpc_task *task)
2793{
2794 struct nfs4_unlockdata *calldata = (struct nfs4_unlockdata *)task->tk_calldata;
2795
2796 nfs_increment_lock_seqid(task->tk_status, calldata->luargs.seqid);
2797 switch (task->tk_status) {
2798 case 0:
2799 memcpy(calldata->lsp->ls_stateid.data,
2800 calldata->res.u.stateid.data,
2801 sizeof(calldata->lsp->ls_stateid.data));
2802 break;
2803 case -NFS4ERR_STALE_STATEID:
2804 case -NFS4ERR_EXPIRED:
2805 nfs4_schedule_state_recovery(calldata->res.server->nfs4_state);
2806 break;
2807 default:
2808 if (nfs4_async_handle_error(task, calldata->res.server) == -EAGAIN) {
2809 rpc_restart_call(task);
2810 return;
2811 }
2812 }
2813 nfs4_locku_complete(calldata);
2814}
2815
2816static void nfs4_locku_begin(struct rpc_task *task)
2817{
2818 struct nfs4_unlockdata *calldata = (struct nfs4_unlockdata *)task->tk_calldata;
2779 struct rpc_message msg = { 2819 struct rpc_message msg = {
2780 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCKU], 2820 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCKU],
2781 .rpc_argp = &arg, 2821 .rpc_argp = &calldata->arg,
2782 .rpc_resp = &res, 2822 .rpc_resp = &calldata->res,
2783 .rpc_cred = state->owner->so_cred, 2823 .rpc_cred = calldata->lsp->ls_state->owner->so_cred,
2784 }; 2824 };
2825 int status;
2826
2827 status = nfs_wait_on_sequence(calldata->luargs.seqid, task);
2828 if (status != 0)
2829 return;
2830 if ((calldata->lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0) {
2831 nfs4_locku_complete(calldata);
2832 task->tk_exit = NULL;
2833 rpc_exit(task, 0);
2834 return;
2835 }
2836 rpc_call_setup(task, &msg, 0);
2837}
2838
2839static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request)
2840{
2841 struct nfs4_unlockdata *calldata;
2842 struct inode *inode = state->inode;
2843 struct nfs_server *server = NFS_SERVER(inode);
2785 struct nfs4_lock_state *lsp; 2844 struct nfs4_lock_state *lsp;
2786 struct nfs_locku_opargs luargs;
2787 int status; 2845 int status;
2788 2846
2789 status = nfs4_set_lock_state(state, request); 2847 status = nfs4_set_lock_state(state, request);
2790 if (status != 0) 2848 if (status != 0)
2791 goto out; 2849 return status;
2792 lsp = request->fl_u.nfs4_fl.owner; 2850 lsp = request->fl_u.nfs4_fl.owner;
2793 /* We might have lost the locks! */ 2851 /* We might have lost the locks! */
2794 if ((lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0) 2852 if ((lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0)
2795 goto out; 2853 return 0;
2796 luargs.seqid = nfs_alloc_seqid(&lsp->ls_seqid); 2854 calldata = kmalloc(sizeof(*calldata), GFP_KERNEL);
2797 status = -ENOMEM; 2855 if (calldata == NULL)
2798 if (luargs.seqid == NULL) 2856 return -ENOMEM;
2799 goto out; 2857 calldata->luargs.seqid = nfs_alloc_seqid(&lsp->ls_seqid);
2800 memcpy(luargs.stateid.data, lsp->ls_stateid.data, sizeof(luargs.stateid.data)); 2858 if (calldata->luargs.seqid == NULL) {
2801 arg.u.locku = &luargs; 2859 kfree(calldata);
2802 status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); 2860 return -ENOMEM;
2803 nfs_increment_lock_seqid(status, luargs.seqid); 2861 }
2804 2862 calldata->luargs.stateid = &lsp->ls_stateid;
2805 if (status == 0) 2863 calldata->arg.fh = NFS_FH(inode);
2806 memcpy(lsp->ls_stateid.data, res.u.stateid.data, 2864 calldata->arg.type = nfs4_lck_type(cmd, request);
2807 sizeof(lsp->ls_stateid.data)); 2865 calldata->arg.offset = request->fl_start;
2808 nfs_free_seqid(luargs.seqid); 2866 calldata->arg.length = nfs4_lck_length(request);
2809out: 2867 calldata->arg.u.locku = &calldata->luargs;
2868 calldata->res.server = server;
2869 calldata->lsp = lsp;
2870 atomic_inc(&lsp->ls_count);
2871
2872 /* Ensure we don't close file until we're done freeing locks! */
2873 calldata->ctx = get_nfs_open_context((struct nfs_open_context*)request->fl_file->private_data);
2874
2875 atomic_set(&calldata->refcount, 2);
2876 init_completion(&calldata->completion);
2877
2878 status = nfs4_call_async(NFS_SERVER(inode)->client, nfs4_locku_begin,
2879 nfs4_locku_done, calldata);
2810 if (status == 0) 2880 if (status == 0)
2811 do_vfs_lock(request->fl_file, request); 2881 wait_for_completion_interruptible(&calldata->completion);
2882 do_vfs_lock(request->fl_file, request);
2883 nfs4_locku_release_calldata(calldata);
2812 return status; 2884 return status;
2813} 2885}
2814 2886
2815static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request)
2816{
2817 struct nfs4_exception exception = { };
2818 int err;
2819
2820 do {
2821 err = nfs4_handle_exception(NFS_SERVER(state->inode),
2822 _nfs4_proc_unlck(state, cmd, request),
2823 &exception);
2824 } while (exception.retry);
2825 return err;
2826}
2827
2828static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *request, int reclaim) 2887static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *request, int reclaim)
2829{ 2888{
2830 struct inode *inode = state->inode; 2889 struct inode *inode = state->inode;
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index bb3574361958..23834c8fb740 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -600,7 +600,7 @@ static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_
600 * Release reference to lock_state, and free it if we see that 600 * Release reference to lock_state, and free it if we see that
601 * it is no longer in use 601 * it is no longer in use
602 */ 602 */
603static void nfs4_put_lock_state(struct nfs4_lock_state *lsp) 603void nfs4_put_lock_state(struct nfs4_lock_state *lsp)
604{ 604{
605 struct nfs4_state *state; 605 struct nfs4_state *state;
606 606
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 934ec50ea6bf..4706192cfb07 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -776,7 +776,7 @@ static int encode_locku(struct xdr_stream *xdr, const struct nfs_lockargs *arg)
776 WRITE32(OP_LOCKU); 776 WRITE32(OP_LOCKU);
777 WRITE32(arg->type); 777 WRITE32(arg->type);
778 WRITE32(opargs->seqid->sequence->counter); 778 WRITE32(opargs->seqid->sequence->counter);
779 WRITEMEM(&opargs->stateid, sizeof(opargs->stateid)); 779 WRITEMEM(opargs->stateid->data, sizeof(opargs->stateid->data));
780 WRITE64(arg->offset); 780 WRITE64(arg->offset);
781 WRITE64(arg->length); 781 WRITE64(arg->length);
782 782
@@ -1587,9 +1587,6 @@ static int nfs4_xdr_enc_locku(struct rpc_rqst *req, uint32_t *p, struct nfs_lock
1587 }; 1587 };
1588 int status; 1588 int status;
1589 1589
1590 status = nfs_wait_on_sequence(args->u.locku->seqid, req->rq_task);
1591 if (status != 0)
1592 goto out;
1593 xdr_init_encode(&xdr, &req->rq_snd_buf, p); 1590 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1594 encode_compound_hdr(&xdr, &hdr); 1591 encode_compound_hdr(&xdr, &hdr);
1595 status = encode_putfh(&xdr, args->fh); 1592 status = encode_putfh(&xdr, args->fh);
@@ -2934,8 +2931,8 @@ static int decode_locku(struct xdr_stream *xdr, struct nfs_lockres *res)
2934 2931
2935 status = decode_op_hdr(xdr, OP_LOCKU); 2932 status = decode_op_hdr(xdr, OP_LOCKU);
2936 if (status == 0) { 2933 if (status == 0) {
2937 READ_BUF(sizeof(nfs4_stateid)); 2934 READ_BUF(sizeof(res->u.stateid.data));
2938 COPYMEM(&res->u.stateid, sizeof(res->u.stateid)); 2935 COPYMEM(res->u.stateid.data, sizeof(res->u.stateid.data));
2939 } 2936 }
2940 return status; 2937 return status;
2941} 2938}
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index cac0df950c66..849f95c5fae4 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -188,7 +188,7 @@ struct nfs_lock_opargs {
188 188
189struct nfs_locku_opargs { 189struct nfs_locku_opargs {
190 struct nfs_seqid * seqid; 190 struct nfs_seqid * seqid;
191 nfs4_stateid stateid; 191 nfs4_stateid * stateid;
192}; 192};
193 193
194struct nfs_lockargs { 194struct nfs_lockargs {