aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4xdr.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd/nfs4xdr.c')
-rw-r--r--fs/nfsd/nfs4xdr.c128
1 files changed, 50 insertions, 78 deletions
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 944275c8f56d..f9821ce6658a 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -181,28 +181,43 @@ static int zero_clientid(clientid_t *clid)
181} 181}
182 182
183/** 183/**
184 * defer_free - mark an allocation as deferred freed 184 * svcxdr_tmpalloc - allocate memory to be freed after compound processing
185 * @argp: NFSv4 compound argument structure to be freed with 185 * @argp: NFSv4 compound argument structure
186 * @release: release callback to free @p, typically kfree() 186 * @p: pointer to be freed (with kfree())
187 * @p: pointer to be freed
188 * 187 *
189 * Marks @p to be freed when processing the compound operation 188 * Marks @p to be freed when processing the compound operation
190 * described in @argp finishes. 189 * described in @argp finishes.
191 */ 190 */
192static int 191static void *
193defer_free(struct nfsd4_compoundargs *argp, 192svcxdr_tmpalloc(struct nfsd4_compoundargs *argp, u32 len)
194 void (*release)(const void *), void *p)
195{ 193{
196 struct tmpbuf *tb; 194 struct svcxdr_tmpbuf *tb;
197 195
198 tb = kmalloc(sizeof(*tb), GFP_KERNEL); 196 tb = kmalloc(sizeof(*tb) + len, GFP_KERNEL);
199 if (!tb) 197 if (!tb)
200 return -ENOMEM; 198 return NULL;
201 tb->buf = p;
202 tb->release = release;
203 tb->next = argp->to_free; 199 tb->next = argp->to_free;
204 argp->to_free = tb; 200 argp->to_free = tb;
205 return 0; 201 return tb->buf;
202}
203
204/*
205 * For xdr strings that need to be passed to other kernel api's
206 * as null-terminated strings.
207 *
208 * Note null-terminating in place usually isn't safe since the
209 * buffer might end on a page boundary.
210 */
211static char *
212svcxdr_dupstr(struct nfsd4_compoundargs *argp, void *buf, u32 len)
213{
214 char *p = svcxdr_tmpalloc(argp, len + 1);
215
216 if (!p)
217 return NULL;
218 memcpy(p, buf, len);
219 p[len] = '\0';
220 return p;
206} 221}
207 222
208/** 223/**
@@ -217,19 +232,13 @@ defer_free(struct nfsd4_compoundargs *argp,
217 */ 232 */
218static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes) 233static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes)
219{ 234{
220 if (p == argp->tmp) { 235 void *ret;
221 p = kmemdup(argp->tmp, nbytes, GFP_KERNEL); 236
222 if (!p) 237 ret = svcxdr_tmpalloc(argp, nbytes);
223 return NULL; 238 if (!ret)
224 } else {
225 BUG_ON(p != argp->tmpp);
226 argp->tmpp = NULL;
227 }
228 if (defer_free(argp, kfree, p)) {
229 kfree(p);
230 return NULL; 239 return NULL;
231 } else 240 memcpy(ret, p, nbytes);
232 return (char *)p; 241 return ret;
233} 242}
234 243
235static __be32 244static __be32
@@ -292,12 +301,10 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
292 if (nace > NFS4_ACL_MAX) 301 if (nace > NFS4_ACL_MAX)
293 return nfserr_fbig; 302 return nfserr_fbig;
294 303
295 *acl = nfs4_acl_new(nace); 304 *acl = svcxdr_tmpalloc(argp, nfs4_acl_bytes(nace));
296 if (*acl == NULL) 305 if (*acl == NULL)
297 return nfserr_jukebox; 306 return nfserr_jukebox;
298 307
299 defer_free(argp, kfree, *acl);
300
301 (*acl)->naces = nace; 308 (*acl)->naces = nace;
302 for (ace = (*acl)->aces; ace < (*acl)->aces + nace; ace++) { 309 for (ace = (*acl)->aces; ace < (*acl)->aces + nace; ace++) {
303 READ_BUF(16); len += 16; 310 READ_BUF(16); len += 16;
@@ -418,12 +425,10 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
418 return nfserr_badlabel; 425 return nfserr_badlabel;
419 len += (XDR_QUADLEN(dummy32) << 2); 426 len += (XDR_QUADLEN(dummy32) << 2);
420 READMEM(buf, dummy32); 427 READMEM(buf, dummy32);
421 label->data = kzalloc(dummy32 + 1, GFP_KERNEL); 428 label->len = dummy32;
429 label->data = svcxdr_dupstr(argp, buf, dummy32);
422 if (!label->data) 430 if (!label->data)
423 return nfserr_jukebox; 431 return nfserr_jukebox;
424 label->len = dummy32;
425 defer_free(argp, kfree, label->data);
426 memcpy(label->data, buf, dummy32);
427 } 432 }
428#endif 433#endif
429 434
@@ -598,20 +603,11 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create
598 switch (create->cr_type) { 603 switch (create->cr_type) {
599 case NF4LNK: 604 case NF4LNK:
600 READ_BUF(4); 605 READ_BUF(4);
601 create->cr_linklen = be32_to_cpup(p++); 606 create->cr_datalen = be32_to_cpup(p++);
602 READ_BUF(create->cr_linklen); 607 READ_BUF(create->cr_datalen);
603 /* 608 create->cr_data = svcxdr_dupstr(argp, p, create->cr_datalen);
604 * The VFS will want a null-terminated string, and 609 if (!create->cr_data)
605 * null-terminating in place isn't safe since this might
606 * end on a page boundary:
607 */
608 create->cr_linkname =
609 kmalloc(create->cr_linklen + 1, GFP_KERNEL);
610 if (!create->cr_linkname)
611 return nfserr_jukebox; 610 return nfserr_jukebox;
612 memcpy(create->cr_linkname, p, create->cr_linklen);
613 create->cr_linkname[create->cr_linklen] = '\0';
614 defer_free(argp, kfree, create->cr_linkname);
615 break; 611 break;
616 case NF4BLK: 612 case NF4BLK:
617 case NF4CHR: 613 case NF4CHR:
@@ -1481,13 +1477,12 @@ nfsd4_decode_test_stateid(struct nfsd4_compoundargs *argp, struct nfsd4_test_sta
1481 INIT_LIST_HEAD(&test_stateid->ts_stateid_list); 1477 INIT_LIST_HEAD(&test_stateid->ts_stateid_list);
1482 1478
1483 for (i = 0; i < test_stateid->ts_num_ids; i++) { 1479 for (i = 0; i < test_stateid->ts_num_ids; i++) {
1484 stateid = kmalloc(sizeof(struct nfsd4_test_stateid_id), GFP_KERNEL); 1480 stateid = svcxdr_tmpalloc(argp, sizeof(*stateid));
1485 if (!stateid) { 1481 if (!stateid) {
1486 status = nfserrno(-ENOMEM); 1482 status = nfserrno(-ENOMEM);
1487 goto out; 1483 goto out;
1488 } 1484 }
1489 1485
1490 defer_free(argp, kfree, stateid);
1491 INIT_LIST_HEAD(&stateid->ts_id_list); 1486 INIT_LIST_HEAD(&stateid->ts_id_list);
1492 list_add_tail(&stateid->ts_id_list, &test_stateid->ts_stateid_list); 1487 list_add_tail(&stateid->ts_id_list, &test_stateid->ts_stateid_list);
1493 1488
@@ -1640,7 +1635,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
1640 goto xdr_error; 1635 goto xdr_error;
1641 1636
1642 if (argp->opcnt > ARRAY_SIZE(argp->iops)) { 1637 if (argp->opcnt > ARRAY_SIZE(argp->iops)) {
1643 argp->ops = kmalloc(argp->opcnt * sizeof(*argp->ops), GFP_KERNEL); 1638 argp->ops = kzalloc(argp->opcnt * sizeof(*argp->ops), GFP_KERNEL);
1644 if (!argp->ops) { 1639 if (!argp->ops) {
1645 argp->ops = argp->iops; 1640 argp->ops = argp->iops;
1646 dprintk("nfsd: couldn't allocate room for COMPOUND\n"); 1641 dprintk("nfsd: couldn't allocate room for COMPOUND\n");
@@ -3077,11 +3072,8 @@ static __be32 nfsd4_encode_splice_read(
3077 __be32 nfserr; 3072 __be32 nfserr;
3078 __be32 *p = xdr->p - 2; 3073 __be32 *p = xdr->p - 2;
3079 3074
3080 /* 3075 /* Make sure there will be room for padding if needed */
3081 * Don't inline pages unless we know there's room for eof, 3076 if (xdr->end - xdr->p < 1)
3082 * count, and possible padding:
3083 */
3084 if (xdr->end - xdr->p < 3)
3085 return nfserr_resource; 3077 return nfserr_resource;
3086 3078
3087 nfserr = nfsd_splice_read(read->rd_rqstp, file, 3079 nfserr = nfsd_splice_read(read->rd_rqstp, file,
@@ -3147,9 +3139,7 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
3147 len = maxcount; 3139 len = maxcount;
3148 v = 0; 3140 v = 0;
3149 3141
3150 thislen = (void *)xdr->end - (void *)xdr->p; 3142 thislen = min_t(long, len, ((void *)xdr->end - (void *)xdr->p));
3151 if (len < thislen)
3152 thislen = len;
3153 p = xdr_reserve_space(xdr, (thislen+3)&~3); 3143 p = xdr_reserve_space(xdr, (thislen+3)&~3);
3154 WARN_ON_ONCE(!p); 3144 WARN_ON_ONCE(!p);
3155 resp->rqstp->rq_vec[v].iov_base = p; 3145 resp->rqstp->rq_vec[v].iov_base = p;
@@ -3216,10 +3206,8 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
3216 xdr_commit_encode(xdr); 3206 xdr_commit_encode(xdr);
3217 3207
3218 maxcount = svc_max_payload(resp->rqstp); 3208 maxcount = svc_max_payload(resp->rqstp);
3219 if (maxcount > xdr->buf->buflen - xdr->buf->len) 3209 maxcount = min_t(unsigned long, maxcount, (xdr->buf->buflen - xdr->buf->len));
3220 maxcount = xdr->buf->buflen - xdr->buf->len; 3210 maxcount = min_t(unsigned long, maxcount, read->rd_length);
3221 if (maxcount > read->rd_length)
3222 maxcount = read->rd_length;
3223 3211
3224 if (!read->rd_filp) { 3212 if (!read->rd_filp) {
3225 err = nfsd_get_tmp_read_open(resp->rqstp, read->rd_fhp, 3213 err = nfsd_get_tmp_read_open(resp->rqstp, read->rd_fhp,
@@ -3937,8 +3925,6 @@ status:
3937 * 3925 *
3938 * XDR note: do not encode rp->rp_buflen: the buffer contains the 3926 * XDR note: do not encode rp->rp_buflen: the buffer contains the
3939 * previously sent already encoded operation. 3927 * previously sent already encoded operation.
3940 *
3941 * called with nfs4_lock_state() held
3942 */ 3928 */
3943void 3929void
3944nfsd4_encode_replay(struct xdr_stream *xdr, struct nfsd4_op *op) 3930nfsd4_encode_replay(struct xdr_stream *xdr, struct nfsd4_op *op)
@@ -3977,9 +3963,8 @@ int nfsd4_release_compoundargs(void *rq, __be32 *p, void *resp)
3977 kfree(args->tmpp); 3963 kfree(args->tmpp);
3978 args->tmpp = NULL; 3964 args->tmpp = NULL;
3979 while (args->to_free) { 3965 while (args->to_free) {
3980 struct tmpbuf *tb = args->to_free; 3966 struct svcxdr_tmpbuf *tb = args->to_free;
3981 args->to_free = tb->next; 3967 args->to_free = tb->next;
3982 tb->release(tb->buf);
3983 kfree(tb); 3968 kfree(tb);
3984 } 3969 }
3985 return 1; 3970 return 1;
@@ -4012,7 +3997,6 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compo
4012 /* 3997 /*
4013 * All that remains is to write the tag and operation count... 3998 * All that remains is to write the tag and operation count...
4014 */ 3999 */
4015 struct nfsd4_compound_state *cs = &resp->cstate;
4016 struct xdr_buf *buf = resp->xdr.buf; 4000 struct xdr_buf *buf = resp->xdr.buf;
4017 4001
4018 WARN_ON_ONCE(buf->len != buf->head[0].iov_len + buf->page_len + 4002 WARN_ON_ONCE(buf->len != buf->head[0].iov_len + buf->page_len +
@@ -4026,19 +4010,7 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compo
4026 p += XDR_QUADLEN(resp->taglen); 4010 p += XDR_QUADLEN(resp->taglen);
4027 *p++ = htonl(resp->opcnt); 4011 *p++ = htonl(resp->opcnt);
4028 4012
4029 if (nfsd4_has_session(cs)) { 4013 nfsd4_sequence_done(resp);
4030 struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
4031 struct nfs4_client *clp = cs->session->se_client;
4032 if (cs->status != nfserr_replay_cache) {
4033 nfsd4_store_cache_entry(resp);
4034 cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE;
4035 }
4036 /* Renew the clientid on success and on replay */
4037 spin_lock(&nn->client_lock);
4038 nfsd4_put_session(cs->session);
4039 spin_unlock(&nn->client_lock);
4040 put_client_renew(clp);
4041 }
4042 return 1; 4014 return 1;
4043} 4015}
4044 4016