aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfsd/nfs4recover.c2
-rw-r--r--fs/nfsd/nfs4state.c33
-rw-r--r--include/linux/sunrpc/cache.h22
-rw-r--r--include/linux/sunrpc/svc.h1
-rw-r--r--net/sunrpc/auth_gss/gss_rpc_upcall.c26
-rw-r--r--net/sunrpc/auth_gss/gss_rpc_xdr.c41
-rw-r--r--net/sunrpc/auth_gss/gss_rpc_xdr.h5
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 *
368alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svc_fh *current_fh) 368alloc_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, &current_fh->fh_handle); 391 fh_copy_shallow(&dp->dl_fh, &current_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
3047static int nfs4_set_delegation(struct nfs4_delegation *dp) 3043static 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;
3068out_free:
3069 put_nfs4_file(fp);
3070 dp->dl_file = fp;
3071 return status;
3063} 3072}
3064 3073
3065static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status) 3074static 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
267static 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
267static inline time_t get_expiry(char **bpp) 285static 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
216static 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
224static 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
169static int get_s32(void **p, void *max, s32 *res) 169static 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);
787done: 786done:
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
152struct gssx_res_accept_sec_context { 154struct 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 + \