diff options
-rw-r--r-- | fs/nfsd/nfs4recover.c | 2 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 33 | ||||
-rw-r--r-- | include/linux/sunrpc/cache.h | 22 | ||||
-rw-r--r-- | include/linux/sunrpc/svc.h | 1 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/gss_rpc_upcall.c | 26 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/gss_rpc_xdr.c | 41 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/gss_rpc_xdr.h | 5 |
7 files changed, 91 insertions, 39 deletions
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 105a3b080d12..e0a65a9e37e9 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c | |||
@@ -173,8 +173,6 @@ nfsd4_create_clid_dir(struct nfs4_client *clp) | |||
173 | int status; | 173 | int status; |
174 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); | 174 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); |
175 | 175 | ||
176 | dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname); | ||
177 | |||
178 | if (test_and_set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) | 176 | if (test_and_set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) |
179 | return; | 177 | return; |
180 | if (!nn->rec_file) | 178 | if (!nn->rec_file) |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 43f42290e5df..0874998a49cd 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -368,11 +368,8 @@ static struct nfs4_delegation * | |||
368 | alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svc_fh *current_fh) | 368 | alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svc_fh *current_fh) |
369 | { | 369 | { |
370 | struct nfs4_delegation *dp; | 370 | struct nfs4_delegation *dp; |
371 | struct nfs4_file *fp = stp->st_file; | ||
372 | 371 | ||
373 | dprintk("NFSD alloc_init_deleg\n"); | 372 | dprintk("NFSD alloc_init_deleg\n"); |
374 | if (fp->fi_had_conflict) | ||
375 | return NULL; | ||
376 | if (num_delegations > max_delegations) | 373 | if (num_delegations > max_delegations) |
377 | return NULL; | 374 | return NULL; |
378 | dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab)); | 375 | dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab)); |
@@ -389,8 +386,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct sv | |||
389 | INIT_LIST_HEAD(&dp->dl_perfile); | 386 | INIT_LIST_HEAD(&dp->dl_perfile); |
390 | INIT_LIST_HEAD(&dp->dl_perclnt); | 387 | INIT_LIST_HEAD(&dp->dl_perclnt); |
391 | INIT_LIST_HEAD(&dp->dl_recall_lru); | 388 | INIT_LIST_HEAD(&dp->dl_recall_lru); |
392 | get_nfs4_file(fp); | 389 | dp->dl_file = NULL; |
393 | dp->dl_file = fp; | ||
394 | dp->dl_type = NFS4_OPEN_DELEGATE_READ; | 390 | dp->dl_type = NFS4_OPEN_DELEGATE_READ; |
395 | fh_copy_shallow(&dp->dl_fh, ¤t_fh->fh_handle); | 391 | fh_copy_shallow(&dp->dl_fh, ¤t_fh->fh_handle); |
396 | dp->dl_time = 0; | 392 | dp->dl_time = 0; |
@@ -3035,7 +3031,7 @@ static int nfs4_setlease(struct nfs4_delegation *dp) | |||
3035 | if (status) { | 3031 | if (status) { |
3036 | list_del_init(&dp->dl_perclnt); | 3032 | list_del_init(&dp->dl_perclnt); |
3037 | locks_free_lock(fl); | 3033 | locks_free_lock(fl); |
3038 | return -ENOMEM; | 3034 | return status; |
3039 | } | 3035 | } |
3040 | fp->fi_lease = fl; | 3036 | fp->fi_lease = fl; |
3041 | fp->fi_deleg_file = get_file(fl->fl_file); | 3037 | fp->fi_deleg_file = get_file(fl->fl_file); |
@@ -3044,22 +3040,35 @@ static int nfs4_setlease(struct nfs4_delegation *dp) | |||
3044 | return 0; | 3040 | return 0; |
3045 | } | 3041 | } |
3046 | 3042 | ||
3047 | static int nfs4_set_delegation(struct nfs4_delegation *dp) | 3043 | static int nfs4_set_delegation(struct nfs4_delegation *dp, struct nfs4_file *fp) |
3048 | { | 3044 | { |
3049 | struct nfs4_file *fp = dp->dl_file; | 3045 | int status; |
3050 | 3046 | ||
3051 | if (!fp->fi_lease) | 3047 | if (fp->fi_had_conflict) |
3052 | return nfs4_setlease(dp); | 3048 | return -EAGAIN; |
3049 | get_nfs4_file(fp); | ||
3050 | dp->dl_file = fp; | ||
3051 | if (!fp->fi_lease) { | ||
3052 | status = nfs4_setlease(dp); | ||
3053 | if (status) | ||
3054 | goto out_free; | ||
3055 | return 0; | ||
3056 | } | ||
3053 | spin_lock(&recall_lock); | 3057 | spin_lock(&recall_lock); |
3054 | if (fp->fi_had_conflict) { | 3058 | if (fp->fi_had_conflict) { |
3055 | spin_unlock(&recall_lock); | 3059 | spin_unlock(&recall_lock); |
3056 | return -EAGAIN; | 3060 | status = -EAGAIN; |
3061 | goto out_free; | ||
3057 | } | 3062 | } |
3058 | atomic_inc(&fp->fi_delegees); | 3063 | atomic_inc(&fp->fi_delegees); |
3059 | list_add(&dp->dl_perfile, &fp->fi_delegations); | 3064 | list_add(&dp->dl_perfile, &fp->fi_delegations); |
3060 | spin_unlock(&recall_lock); | 3065 | spin_unlock(&recall_lock); |
3061 | list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations); | 3066 | list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations); |
3062 | return 0; | 3067 | return 0; |
3068 | out_free: | ||
3069 | put_nfs4_file(fp); | ||
3070 | dp->dl_file = fp; | ||
3071 | return status; | ||
3063 | } | 3072 | } |
3064 | 3073 | ||
3065 | static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status) | 3074 | static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status) |
@@ -3134,7 +3143,7 @@ nfs4_open_delegation(struct net *net, struct svc_fh *fh, | |||
3134 | dp = alloc_init_deleg(oo->oo_owner.so_client, stp, fh); | 3143 | dp = alloc_init_deleg(oo->oo_owner.so_client, stp, fh); |
3135 | if (dp == NULL) | 3144 | if (dp == NULL) |
3136 | goto out_no_deleg; | 3145 | goto out_no_deleg; |
3137 | status = nfs4_set_delegation(dp); | 3146 | status = nfs4_set_delegation(dp, stp->st_file); |
3138 | if (status) | 3147 | if (status) |
3139 | goto out_free; | 3148 | goto out_free; |
3140 | 3149 | ||
diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index 6ce690de447f..437ddb6c4aef 100644 --- a/include/linux/sunrpc/cache.h +++ b/include/linux/sunrpc/cache.h | |||
@@ -264,12 +264,30 @@ static inline int get_uint(char **bpp, unsigned int *anint) | |||
264 | return 0; | 264 | return 0; |
265 | } | 265 | } |
266 | 266 | ||
267 | static inline int get_time(char **bpp, time_t *time) | ||
268 | { | ||
269 | char buf[50]; | ||
270 | long long ll; | ||
271 | int len = qword_get(bpp, buf, sizeof(buf)); | ||
272 | |||
273 | if (len < 0) | ||
274 | return -EINVAL; | ||
275 | if (len == 0) | ||
276 | return -ENOENT; | ||
277 | |||
278 | if (kstrtoll(buf, 0, &ll)) | ||
279 | return -EINVAL; | ||
280 | |||
281 | *time = (time_t)ll; | ||
282 | return 0; | ||
283 | } | ||
284 | |||
267 | static inline time_t get_expiry(char **bpp) | 285 | static inline time_t get_expiry(char **bpp) |
268 | { | 286 | { |
269 | int rv; | 287 | time_t rv; |
270 | struct timespec boot; | 288 | struct timespec boot; |
271 | 289 | ||
272 | if (get_int(bpp, &rv)) | 290 | if (get_time(bpp, &rv)) |
273 | return 0; | 291 | return 0; |
274 | if (rv < 0) | 292 | if (rv < 0) |
275 | return 0; | 293 | return 0; |
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 1f0216b9a6c9..6eecfc2e4f98 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h | |||
@@ -243,7 +243,6 @@ struct svc_rqst { | |||
243 | struct xdr_buf rq_res; | 243 | struct xdr_buf rq_res; |
244 | struct page * rq_pages[RPCSVC_MAXPAGES]; | 244 | struct page * rq_pages[RPCSVC_MAXPAGES]; |
245 | struct page * *rq_respages; /* points into rq_pages */ | 245 | struct page * *rq_respages; /* points into rq_pages */ |
246 | int rq_resused; /* number of pages used for result */ | ||
247 | struct page * *rq_next_page; /* next reply page to use */ | 246 | struct page * *rq_next_page; /* next reply page to use */ |
248 | 247 | ||
249 | struct kvec rq_vec[RPCSVC_MAXPAGES]; /* generally useful.. */ | 248 | struct kvec rq_vec[RPCSVC_MAXPAGES]; /* generally useful.. */ |
diff --git a/net/sunrpc/auth_gss/gss_rpc_upcall.c b/net/sunrpc/auth_gss/gss_rpc_upcall.c index af7ffd447fee..f1eb0d16666c 100644 --- a/net/sunrpc/auth_gss/gss_rpc_upcall.c +++ b/net/sunrpc/auth_gss/gss_rpc_upcall.c | |||
@@ -213,6 +213,26 @@ static int gssp_call(struct net *net, struct rpc_message *msg) | |||
213 | return status; | 213 | return status; |
214 | } | 214 | } |
215 | 215 | ||
216 | static void gssp_free_receive_pages(struct gssx_arg_accept_sec_context *arg) | ||
217 | { | ||
218 | int i; | ||
219 | |||
220 | for (i = 0; i < arg->npages && arg->pages[i]; i++) | ||
221 | __free_page(arg->pages[i]); | ||
222 | } | ||
223 | |||
224 | static int gssp_alloc_receive_pages(struct gssx_arg_accept_sec_context *arg) | ||
225 | { | ||
226 | arg->npages = DIV_ROUND_UP(NGROUPS_MAX * 4, PAGE_SIZE); | ||
227 | arg->pages = kzalloc(arg->npages * sizeof(struct page *), GFP_KERNEL); | ||
228 | /* | ||
229 | * XXX: actual pages are allocated by xdr layer in | ||
230 | * xdr_partial_copy_from_skb. | ||
231 | */ | ||
232 | if (!arg->pages) | ||
233 | return -ENOMEM; | ||
234 | return 0; | ||
235 | } | ||
216 | 236 | ||
217 | /* | 237 | /* |
218 | * Public functions | 238 | * Public functions |
@@ -261,10 +281,16 @@ int gssp_accept_sec_context_upcall(struct net *net, | |||
261 | arg.context_handle = &ctxh; | 281 | arg.context_handle = &ctxh; |
262 | res.output_token->len = GSSX_max_output_token_sz; | 282 | res.output_token->len = GSSX_max_output_token_sz; |
263 | 283 | ||
284 | ret = gssp_alloc_receive_pages(&arg); | ||
285 | if (ret) | ||
286 | return ret; | ||
287 | |||
264 | /* use nfs/ for targ_name ? */ | 288 | /* use nfs/ for targ_name ? */ |
265 | 289 | ||
266 | ret = gssp_call(net, &msg); | 290 | ret = gssp_call(net, &msg); |
267 | 291 | ||
292 | gssp_free_receive_pages(&arg); | ||
293 | |||
268 | /* we need to fetch all data even in case of error so | 294 | /* we need to fetch all data even in case of error so |
269 | * that we can free special strctures is they have been allocated */ | 295 | * that we can free special strctures is they have been allocated */ |
270 | data->major_status = res.status.major_status; | 296 | data->major_status = res.status.major_status; |
diff --git a/net/sunrpc/auth_gss/gss_rpc_xdr.c b/net/sunrpc/auth_gss/gss_rpc_xdr.c index 3c85d1c8a028..f0f78c5f1c7d 100644 --- a/net/sunrpc/auth_gss/gss_rpc_xdr.c +++ b/net/sunrpc/auth_gss/gss_rpc_xdr.c | |||
@@ -166,14 +166,15 @@ static int dummy_dec_opt_array(struct xdr_stream *xdr, | |||
166 | return 0; | 166 | return 0; |
167 | } | 167 | } |
168 | 168 | ||
169 | static int get_s32(void **p, void *max, s32 *res) | 169 | static int get_host_u32(struct xdr_stream *xdr, u32 *res) |
170 | { | 170 | { |
171 | void *base = *p; | 171 | __be32 *p; |
172 | void *next = (void *)((char *)base + sizeof(s32)); | 172 | |
173 | if (unlikely(next > max || next < base)) | 173 | p = xdr_inline_decode(xdr, 4); |
174 | if (!p) | ||
174 | return -EINVAL; | 175 | return -EINVAL; |
175 | memcpy(res, base, sizeof(s32)); | 176 | /* Contents of linux creds are all host-endian: */ |
176 | *p = next; | 177 | memcpy(res, p, sizeof(u32)); |
177 | return 0; | 178 | return 0; |
178 | } | 179 | } |
179 | 180 | ||
@@ -182,9 +183,9 @@ static int gssx_dec_linux_creds(struct xdr_stream *xdr, | |||
182 | { | 183 | { |
183 | u32 length; | 184 | u32 length; |
184 | __be32 *p; | 185 | __be32 *p; |
185 | void *q, *end; | 186 | u32 tmp; |
186 | s32 tmp; | 187 | u32 N; |
187 | int N, i, err; | 188 | int i, err; |
188 | 189 | ||
189 | p = xdr_inline_decode(xdr, 4); | 190 | p = xdr_inline_decode(xdr, 4); |
190 | if (unlikely(p == NULL)) | 191 | if (unlikely(p == NULL)) |
@@ -192,33 +193,28 @@ static int gssx_dec_linux_creds(struct xdr_stream *xdr, | |||
192 | 193 | ||
193 | length = be32_to_cpup(p); | 194 | length = be32_to_cpup(p); |
194 | 195 | ||
195 | /* FIXME: we do not want to use the scratch buffer for this one | 196 | if (length > (3 + NGROUPS_MAX) * sizeof(u32)) |
196 | * may need to use functions that allows us to access an io vector | ||
197 | * directly */ | ||
198 | p = xdr_inline_decode(xdr, length); | ||
199 | if (unlikely(p == NULL)) | ||
200 | return -ENOSPC; | 197 | return -ENOSPC; |
201 | 198 | ||
202 | q = p; | ||
203 | end = q + length; | ||
204 | |||
205 | /* uid */ | 199 | /* uid */ |
206 | err = get_s32(&q, end, &tmp); | 200 | err = get_host_u32(xdr, &tmp); |
207 | if (err) | 201 | if (err) |
208 | return err; | 202 | return err; |
209 | creds->cr_uid = make_kuid(&init_user_ns, tmp); | 203 | creds->cr_uid = make_kuid(&init_user_ns, tmp); |
210 | 204 | ||
211 | /* gid */ | 205 | /* gid */ |
212 | err = get_s32(&q, end, &tmp); | 206 | err = get_host_u32(xdr, &tmp); |
213 | if (err) | 207 | if (err) |
214 | return err; | 208 | return err; |
215 | creds->cr_gid = make_kgid(&init_user_ns, tmp); | 209 | creds->cr_gid = make_kgid(&init_user_ns, tmp); |
216 | 210 | ||
217 | /* number of additional gid's */ | 211 | /* number of additional gid's */ |
218 | err = get_s32(&q, end, &tmp); | 212 | err = get_host_u32(xdr, &tmp); |
219 | if (err) | 213 | if (err) |
220 | return err; | 214 | return err; |
221 | N = tmp; | 215 | N = tmp; |
216 | if ((3 + N) * sizeof(u32) != length) | ||
217 | return -EINVAL; | ||
222 | creds->cr_group_info = groups_alloc(N); | 218 | creds->cr_group_info = groups_alloc(N); |
223 | if (creds->cr_group_info == NULL) | 219 | if (creds->cr_group_info == NULL) |
224 | return -ENOMEM; | 220 | return -ENOMEM; |
@@ -226,7 +222,7 @@ static int gssx_dec_linux_creds(struct xdr_stream *xdr, | |||
226 | /* gid's */ | 222 | /* gid's */ |
227 | for (i = 0; i < N; i++) { | 223 | for (i = 0; i < N; i++) { |
228 | kgid_t kgid; | 224 | kgid_t kgid; |
229 | err = get_s32(&q, end, &tmp); | 225 | err = get_host_u32(xdr, &tmp); |
230 | if (err) | 226 | if (err) |
231 | goto out_free_groups; | 227 | goto out_free_groups; |
232 | err = -EINVAL; | 228 | err = -EINVAL; |
@@ -784,6 +780,9 @@ void gssx_enc_accept_sec_context(struct rpc_rqst *req, | |||
784 | /* arg->options */ | 780 | /* arg->options */ |
785 | err = dummy_enc_opt_array(xdr, &arg->options); | 781 | err = dummy_enc_opt_array(xdr, &arg->options); |
786 | 782 | ||
783 | xdr_inline_pages(&req->rq_rcv_buf, | ||
784 | PAGE_SIZE/2 /* pretty arbitrary */, | ||
785 | arg->pages, 0 /* page base */, arg->npages * PAGE_SIZE); | ||
787 | done: | 786 | done: |
788 | if (err) | 787 | if (err) |
789 | dprintk("RPC: gssx_enc_accept_sec_context: %d\n", err); | 788 | dprintk("RPC: gssx_enc_accept_sec_context: %d\n", err); |
diff --git a/net/sunrpc/auth_gss/gss_rpc_xdr.h b/net/sunrpc/auth_gss/gss_rpc_xdr.h index 1c98b27d870c..685a688f3d8a 100644 --- a/net/sunrpc/auth_gss/gss_rpc_xdr.h +++ b/net/sunrpc/auth_gss/gss_rpc_xdr.h | |||
@@ -147,6 +147,8 @@ struct gssx_arg_accept_sec_context { | |||
147 | struct gssx_cb *input_cb; | 147 | struct gssx_cb *input_cb; |
148 | u32 ret_deleg_cred; | 148 | u32 ret_deleg_cred; |
149 | struct gssx_option_array options; | 149 | struct gssx_option_array options; |
150 | struct page **pages; | ||
151 | unsigned int npages; | ||
150 | }; | 152 | }; |
151 | 153 | ||
152 | struct gssx_res_accept_sec_context { | 154 | struct gssx_res_accept_sec_context { |
@@ -240,7 +242,8 @@ int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp, | |||
240 | 2 * GSSX_max_princ_sz + \ | 242 | 2 * GSSX_max_princ_sz + \ |
241 | 8 + 8 + 4 + 4 + 4) | 243 | 8 + 8 + 4 + 4 + 4) |
242 | #define GSSX_max_output_token_sz 1024 | 244 | #define GSSX_max_output_token_sz 1024 |
243 | #define GSSX_max_creds_sz (4 + 4 + 4 + NGROUPS_MAX * 4) | 245 | /* grouplist not included; we allocate separate pages for that: */ |
246 | #define GSSX_max_creds_sz (4 + 4 + 4 /* + NGROUPS_MAX*4 */) | ||
244 | #define GSSX_RES_accept_sec_context_sz (GSSX_default_status_sz + \ | 247 | #define GSSX_RES_accept_sec_context_sz (GSSX_default_status_sz + \ |
245 | GSSX_default_ctx_sz + \ | 248 | GSSX_default_ctx_sz + \ |
246 | GSSX_max_output_token_sz + \ | 249 | GSSX_max_output_token_sz + \ |