aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/nfs4proc.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r--fs/nfs/nfs4proc.c192
1 files changed, 80 insertions, 112 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 3ecb7da220f5..857125705b6f 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -2935,43 +2935,17 @@ nfs4_set_lock_task_retry(unsigned long timeout)
2935 return timeout; 2935 return timeout;
2936} 2936}
2937 2937
2938static inline int
2939nfs4_lck_type(int cmd, struct file_lock *request)
2940{
2941 /* set lock type */
2942 switch (request->fl_type) {
2943 case F_RDLCK:
2944 return IS_SETLKW(cmd) ? NFS4_READW_LT : NFS4_READ_LT;
2945 case F_WRLCK:
2946 return IS_SETLKW(cmd) ? NFS4_WRITEW_LT : NFS4_WRITE_LT;
2947 case F_UNLCK:
2948 return NFS4_WRITE_LT;
2949 }
2950 BUG();
2951 return 0;
2952}
2953
2954static inline uint64_t
2955nfs4_lck_length(struct file_lock *request)
2956{
2957 if (request->fl_end == OFFSET_MAX)
2958 return ~(uint64_t)0;
2959 return request->fl_end - request->fl_start + 1;
2960}
2961
2962static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *request) 2938static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *request)
2963{ 2939{
2964 struct inode *inode = state->inode; 2940 struct inode *inode = state->inode;
2965 struct nfs_server *server = NFS_SERVER(inode); 2941 struct nfs_server *server = NFS_SERVER(inode);
2966 struct nfs4_client *clp = server->nfs4_state; 2942 struct nfs4_client *clp = server->nfs4_state;
2967 struct nfs_lockargs arg = { 2943 struct nfs_lockt_args arg = {
2968 .fh = NFS_FH(inode), 2944 .fh = NFS_FH(inode),
2969 .type = nfs4_lck_type(cmd, request), 2945 .fl = request,
2970 .offset = request->fl_start,
2971 .length = nfs4_lck_length(request),
2972 }; 2946 };
2973 struct nfs_lockres res = { 2947 struct nfs_lockt_res res = {
2974 .server = server, 2948 .denied = request,
2975 }; 2949 };
2976 struct rpc_message msg = { 2950 struct rpc_message msg = {
2977 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCKT], 2951 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCKT],
@@ -2979,36 +2953,23 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock
2979 .rpc_resp = &res, 2953 .rpc_resp = &res,
2980 .rpc_cred = state->owner->so_cred, 2954 .rpc_cred = state->owner->so_cred,
2981 }; 2955 };
2982 struct nfs_lowner nlo;
2983 struct nfs4_lock_state *lsp; 2956 struct nfs4_lock_state *lsp;
2984 int status; 2957 int status;
2985 2958
2986 down_read(&clp->cl_sem); 2959 down_read(&clp->cl_sem);
2987 nlo.clientid = clp->cl_clientid; 2960 arg.lock_owner.clientid = clp->cl_clientid;
2988 status = nfs4_set_lock_state(state, request); 2961 status = nfs4_set_lock_state(state, request);
2989 if (status != 0) 2962 if (status != 0)
2990 goto out; 2963 goto out;
2991 lsp = request->fl_u.nfs4_fl.owner; 2964 lsp = request->fl_u.nfs4_fl.owner;
2992 nlo.id = lsp->ls_id; 2965 arg.lock_owner.id = lsp->ls_id;
2993 arg.u.lockt = &nlo;
2994 status = rpc_call_sync(server->client, &msg, 0); 2966 status = rpc_call_sync(server->client, &msg, 0);
2995 if (!status) { 2967 switch (status) {
2996 request->fl_type = F_UNLCK; 2968 case 0:
2997 } else if (status == -NFS4ERR_DENIED) { 2969 request->fl_type = F_UNLCK;
2998 int64_t len, start, end; 2970 break;
2999 start = res.u.denied.offset; 2971 case -NFS4ERR_DENIED:
3000 len = res.u.denied.length; 2972 status = 0;
3001 end = start + len - 1;
3002 if (end < 0 || len == 0)
3003 request->fl_end = OFFSET_MAX;
3004 else
3005 request->fl_end = (loff_t)end;
3006 request->fl_start = (loff_t)start;
3007 request->fl_type = F_WRLCK;
3008 if (res.u.denied.type & 1)
3009 request->fl_type = F_RDLCK;
3010 request->fl_pid = 0;
3011 status = 0;
3012 } 2973 }
3013out: 2974out:
3014 up_read(&clp->cl_sem); 2975 up_read(&clp->cl_sem);
@@ -3048,17 +3009,42 @@ static int do_vfs_lock(struct file *file, struct file_lock *fl)
3048} 3009}
3049 3010
3050struct nfs4_unlockdata { 3011struct nfs4_unlockdata {
3051 struct nfs_lockargs arg; 3012 struct nfs_locku_args arg;
3052 struct nfs_locku_opargs luargs; 3013 struct nfs_locku_res res;
3053 struct nfs_lockres res;
3054 struct nfs4_lock_state *lsp; 3014 struct nfs4_lock_state *lsp;
3055 struct nfs_open_context *ctx; 3015 struct nfs_open_context *ctx;
3016 struct file_lock fl;
3017 const struct nfs_server *server;
3056}; 3018};
3057 3019
3020static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl,
3021 struct nfs_open_context *ctx,
3022 struct nfs4_lock_state *lsp,
3023 struct nfs_seqid *seqid)
3024{
3025 struct nfs4_unlockdata *p;
3026 struct inode *inode = lsp->ls_state->inode;
3027
3028 p = kmalloc(sizeof(*p), GFP_KERNEL);
3029 if (p == NULL)
3030 return NULL;
3031 p->arg.fh = NFS_FH(inode);
3032 p->arg.fl = &p->fl;
3033 p->arg.seqid = seqid;
3034 p->arg.stateid = &lsp->ls_stateid;
3035 p->lsp = lsp;
3036 atomic_inc(&lsp->ls_count);
3037 /* Ensure we don't close file until we're done freeing locks! */
3038 p->ctx = get_nfs_open_context(ctx);
3039 memcpy(&p->fl, fl, sizeof(p->fl));
3040 p->server = NFS_SERVER(inode);
3041 return p;
3042}
3043
3058static void nfs4_locku_release_calldata(void *data) 3044static void nfs4_locku_release_calldata(void *data)
3059{ 3045{
3060 struct nfs4_unlockdata *calldata = data; 3046 struct nfs4_unlockdata *calldata = data;
3061 nfs_free_seqid(calldata->luargs.seqid); 3047 nfs_free_seqid(calldata->arg.seqid);
3062 nfs4_put_lock_state(calldata->lsp); 3048 nfs4_put_lock_state(calldata->lsp);
3063 put_nfs_open_context(calldata->ctx); 3049 put_nfs_open_context(calldata->ctx);
3064 kfree(calldata); 3050 kfree(calldata);
@@ -3070,19 +3056,19 @@ static void nfs4_locku_done(struct rpc_task *task, void *data)
3070 3056
3071 if (RPC_ASSASSINATED(task)) 3057 if (RPC_ASSASSINATED(task))
3072 return; 3058 return;
3073 nfs_increment_lock_seqid(task->tk_status, calldata->luargs.seqid); 3059 nfs_increment_lock_seqid(task->tk_status, calldata->arg.seqid);
3074 switch (task->tk_status) { 3060 switch (task->tk_status) {
3075 case 0: 3061 case 0:
3076 memcpy(calldata->lsp->ls_stateid.data, 3062 memcpy(calldata->lsp->ls_stateid.data,
3077 calldata->res.u.stateid.data, 3063 calldata->res.stateid.data,
3078 sizeof(calldata->lsp->ls_stateid.data)); 3064 sizeof(calldata->lsp->ls_stateid.data));
3079 break; 3065 break;
3080 case -NFS4ERR_STALE_STATEID: 3066 case -NFS4ERR_STALE_STATEID:
3081 case -NFS4ERR_EXPIRED: 3067 case -NFS4ERR_EXPIRED:
3082 nfs4_schedule_state_recovery(calldata->res.server->nfs4_state); 3068 nfs4_schedule_state_recovery(calldata->server->nfs4_state);
3083 break; 3069 break;
3084 default: 3070 default:
3085 if (nfs4_async_handle_error(task, calldata->res.server) == -EAGAIN) { 3071 if (nfs4_async_handle_error(task, calldata->server) == -EAGAIN) {
3086 rpc_restart_call(task); 3072 rpc_restart_call(task);
3087 } 3073 }
3088 } 3074 }
@@ -3097,10 +3083,8 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data)
3097 .rpc_resp = &calldata->res, 3083 .rpc_resp = &calldata->res,
3098 .rpc_cred = calldata->lsp->ls_state->owner->so_cred, 3084 .rpc_cred = calldata->lsp->ls_state->owner->so_cred,
3099 }; 3085 };
3100 int status;
3101 3086
3102 status = nfs_wait_on_sequence(calldata->luargs.seqid, task); 3087 if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0)
3103 if (status != 0)
3104 return; 3088 return;
3105 if ((calldata->lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0) { 3089 if ((calldata->lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0) {
3106 /* Note: exit _without_ running nfs4_locku_done */ 3090 /* Note: exit _without_ running nfs4_locku_done */
@@ -3121,43 +3105,32 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *
3121 struct nfs4_unlockdata *calldata; 3105 struct nfs4_unlockdata *calldata;
3122 struct inode *inode = state->inode; 3106 struct inode *inode = state->inode;
3123 struct nfs_server *server = NFS_SERVER(inode); 3107 struct nfs_server *server = NFS_SERVER(inode);
3108 struct nfs_seqid *seqid;
3124 struct nfs4_lock_state *lsp; 3109 struct nfs4_lock_state *lsp;
3125 struct rpc_task *task; 3110 struct rpc_task *task;
3126 int status = 0; 3111 int status = 0;
3127 3112
3128 /* Is this a delegated lock? */ 3113 /* Is this a delegated lock? */
3129 if (test_bit(NFS_DELEGATED_STATE, &state->flags)) 3114 if (test_bit(NFS_DELEGATED_STATE, &state->flags))
3130 goto out; 3115 goto out_unlock;
3116 /* Is this open_owner holding any locks on the server? */
3117 if (test_bit(LK_STATE_IN_USE, &state->flags) == 0)
3118 goto out_unlock;
3131 3119
3132 status = nfs4_set_lock_state(state, request); 3120 status = nfs4_set_lock_state(state, request);
3133 if (status != 0) 3121 if (status != 0)
3134 goto out; 3122 goto out_unlock;
3135 lsp = request->fl_u.nfs4_fl.owner; 3123 lsp = request->fl_u.nfs4_fl.owner;
3136 /* We might have lost the locks! */
3137 if ((lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0)
3138 goto out;
3139 status = -ENOMEM; 3124 status = -ENOMEM;
3140 calldata = kmalloc(sizeof(*calldata), GFP_KERNEL); 3125 seqid = nfs_alloc_seqid(&lsp->ls_seqid);
3126 if (seqid == NULL)
3127 goto out_unlock;
3128 calldata = nfs4_alloc_unlockdata(request, request->fl_file->private_data,
3129 lsp, seqid);
3141 if (calldata == NULL) 3130 if (calldata == NULL)
3142 goto out; 3131 goto out_free_seqid;
3143 calldata->luargs.seqid = nfs_alloc_seqid(&lsp->ls_seqid); 3132 /* Unlock _before_ we do the RPC call */
3144 if (calldata->luargs.seqid == NULL) { 3133 do_vfs_lock(request->fl_file, request);
3145 kfree(calldata);
3146 goto out;
3147 }
3148 calldata->luargs.stateid = &lsp->ls_stateid;
3149 calldata->arg.fh = NFS_FH(inode);
3150 calldata->arg.type = nfs4_lck_type(cmd, request);
3151 calldata->arg.offset = request->fl_start;
3152 calldata->arg.length = nfs4_lck_length(request);
3153 calldata->arg.u.locku = &calldata->luargs;
3154 calldata->res.server = server;
3155 calldata->lsp = lsp;
3156 atomic_inc(&lsp->ls_count);
3157
3158 /* Ensure we don't close file until we're done freeing locks! */
3159 calldata->ctx = get_nfs_open_context((struct nfs_open_context*)request->fl_file->private_data);
3160
3161 task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_locku_ops, calldata); 3134 task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_locku_ops, calldata);
3162 if (!IS_ERR(task)) { 3135 if (!IS_ERR(task)) {
3163 status = nfs4_wait_for_completion_rpc_task(task); 3136 status = nfs4_wait_for_completion_rpc_task(task);
@@ -3166,7 +3139,10 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *
3166 status = PTR_ERR(task); 3139 status = PTR_ERR(task);
3167 nfs4_locku_release_calldata(calldata); 3140 nfs4_locku_release_calldata(calldata);
3168 } 3141 }
3169out: 3142 return status;
3143out_free_seqid:
3144 nfs_free_seqid(seqid);
3145out_unlock:
3170 do_vfs_lock(request->fl_file, request); 3146 do_vfs_lock(request->fl_file, request);
3171 return status; 3147 return status;
3172} 3148}
@@ -3176,27 +3152,19 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *r
3176 struct inode *inode = state->inode; 3152 struct inode *inode = state->inode;
3177 struct nfs_server *server = NFS_SERVER(inode); 3153 struct nfs_server *server = NFS_SERVER(inode);
3178 struct nfs4_lock_state *lsp = request->fl_u.nfs4_fl.owner; 3154 struct nfs4_lock_state *lsp = request->fl_u.nfs4_fl.owner;
3179 struct nfs_lock_opargs largs = { 3155 struct nfs_lock_args arg = {
3156 .fh = NFS_FH(inode),
3157 .fl = request,
3180 .lock_stateid = &lsp->ls_stateid, 3158 .lock_stateid = &lsp->ls_stateid,
3181 .open_stateid = &state->stateid, 3159 .open_stateid = &state->stateid,
3182 .lock_owner = { 3160 .lock_owner = {
3183 .clientid = server->nfs4_state->cl_clientid, 3161 .clientid = server->nfs4_state->cl_clientid,
3184 .id = lsp->ls_id, 3162 .id = lsp->ls_id,
3185 }, 3163 },
3164 .block = (IS_SETLKW(cmd)) ? 1 : 0,
3186 .reclaim = reclaim, 3165 .reclaim = reclaim,
3187 }; 3166 };
3188 struct nfs_lockargs arg = { 3167 struct nfs_lock_res res;
3189 .fh = NFS_FH(inode),
3190 .type = nfs4_lck_type(cmd, request),
3191 .offset = request->fl_start,
3192 .length = nfs4_lck_length(request),
3193 .u = {
3194 .lock = &largs,
3195 },
3196 };
3197 struct nfs_lockres res = {
3198 .server = server,
3199 };
3200 struct rpc_message msg = { 3168 struct rpc_message msg = {
3201 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCK], 3169 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCK],
3202 .rpc_argp = &arg, 3170 .rpc_argp = &arg,
@@ -3205,37 +3173,37 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *r
3205 }; 3173 };
3206 int status = -ENOMEM; 3174 int status = -ENOMEM;
3207 3175
3208 largs.lock_seqid = nfs_alloc_seqid(&lsp->ls_seqid); 3176 arg.lock_seqid = nfs_alloc_seqid(&lsp->ls_seqid);
3209 if (largs.lock_seqid == NULL) 3177 if (arg.lock_seqid == NULL)
3210 return -ENOMEM; 3178 return -ENOMEM;
3211 if (!(lsp->ls_seqid.flags & NFS_SEQID_CONFIRMED)) { 3179 if (!(lsp->ls_seqid.flags & NFS_SEQID_CONFIRMED)) {
3212 struct nfs4_state_owner *owner = state->owner; 3180 struct nfs4_state_owner *owner = state->owner;
3213 3181
3214 largs.open_seqid = nfs_alloc_seqid(&owner->so_seqid); 3182 arg.open_seqid = nfs_alloc_seqid(&owner->so_seqid);
3215 if (largs.open_seqid == NULL) 3183 if (arg.open_seqid == NULL)
3216 goto out; 3184 goto out;
3217 largs.new_lock_owner = 1; 3185 arg.new_lock_owner = 1;
3218 status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); 3186 status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR);
3219 /* increment open seqid on success, and seqid mutating errors */ 3187 /* increment open seqid on success, and seqid mutating errors */
3220 if (largs.new_lock_owner != 0) { 3188 if (arg.new_lock_owner != 0) {
3221 nfs_increment_open_seqid(status, largs.open_seqid); 3189 nfs_increment_open_seqid(status, arg.open_seqid);
3222 if (status == 0) 3190 if (status == 0)
3223 nfs_confirm_seqid(&lsp->ls_seqid, 0); 3191 nfs_confirm_seqid(&lsp->ls_seqid, 0);
3224 } 3192 }
3225 nfs_free_seqid(largs.open_seqid); 3193 nfs_free_seqid(arg.open_seqid);
3226 } else 3194 } else
3227 status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); 3195 status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR);
3228 /* increment lock seqid on success, and seqid mutating errors*/ 3196 /* increment lock seqid on success, and seqid mutating errors*/
3229 nfs_increment_lock_seqid(status, largs.lock_seqid); 3197 nfs_increment_lock_seqid(status, arg.lock_seqid);
3230 /* save the returned stateid. */ 3198 /* save the returned stateid. */
3231 if (status == 0) { 3199 if (status == 0) {
3232 memcpy(lsp->ls_stateid.data, res.u.stateid.data, 3200 memcpy(lsp->ls_stateid.data, res.stateid.data,
3233 sizeof(lsp->ls_stateid.data)); 3201 sizeof(lsp->ls_stateid.data));
3234 lsp->ls_flags |= NFS_LOCK_INITIALIZED; 3202 lsp->ls_flags |= NFS_LOCK_INITIALIZED;
3235 } else if (status == -NFS4ERR_DENIED) 3203 } else if (status == -NFS4ERR_DENIED)
3236 status = -EAGAIN; 3204 status = -EAGAIN;
3237out: 3205out:
3238 nfs_free_seqid(largs.lock_seqid); 3206 nfs_free_seqid(arg.lock_seqid);
3239 return status; 3207 return status;
3240} 3208}
3241 3209