diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-10 23:04:59 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-10 23:04:59 -0400 |
| commit | cf596766fc53bbfa0e2b21e3569932aa54f5f9ca (patch) | |
| tree | 6e88bae48c06f5b4a099989abb04178b939d2b24 | |
| parent | 516f7b3f2a7dbe93d3075e76a06bbfcd0c0ee4f7 (diff) | |
| parent | d4a516560fc96a9d486a9939bcb567e3fdce8f49 (diff) | |
Merge branch 'nfsd-next' of git://linux-nfs.org/~bfields/linux
Pull nfsd updates from Bruce Fields:
"This was a very quiet cycle! Just a few bugfixes and some cleanup"
* 'nfsd-next' of git://linux-nfs.org/~bfields/linux:
rpc: let xdr layer allocate gssproxy receieve pages
rpc: fix huge kmalloc's in gss-proxy
rpc: comment on linux_cred encoding, treat all as unsigned
rpc: clean up decoding of gssproxy linux creds
svcrpc: remove unused rq_resused
nfsd4: nfsd4_create_clid_dir prints uninitialized data
nfsd4: fix leak of inode reference on delegation failure
Revert "nfsd: nfs4_file_get_access: need to be more careful with O_RDWR"
sunrpc: prepare NFS for 2038
nfsd4: fix setlease error return
nfsd: nfs4_file_get_access: need to be more careful with O_RDWR
| -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 + \ |
