aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4xdr.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-08-09 17:31:18 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-08-09 17:31:18 -0400
commit0d10c2c170e3384dd63f40216d7af4673d5ebb50 (patch)
tree2ce6760501b92ab279677edc3c8d981183ad97f6 /fs/nfsd/nfs4xdr.c
parent023f78b02c729070116fa3a7ebd4107a032d3f5c (diff)
parentd1e458fe671baf1e60afafc88bda090202a412f1 (diff)
Merge branch 'for-3.17' of git://linux-nfs.org/~bfields/linux
Pull nfsd updates from Bruce Fields: "This includes a major rewrite of the NFSv4 state code, which has always depended on a single mutex. As an example, open creates are no longer serialized, fixing a performance regression on NFSv3->NFSv4 upgrades. Thanks to Jeff, Trond, and Benny, and to Christoph for review. Also some RDMA fixes from Chuck Lever and Steve Wise, and miscellaneous fixes from Kinglong Mee and others" * 'for-3.17' of git://linux-nfs.org/~bfields/linux: (167 commits) svcrdma: remove rdma_create_qp() failure recovery logic nfsd: add some comments to the nfsd4 object definitions nfsd: remove the client_mutex and the nfs4_lock/unlock_state wrappers nfsd: remove nfs4_lock_state: nfs4_state_shutdown_net nfsd: remove nfs4_lock_state: nfs4_laundromat nfsd: Remove nfs4_lock_state(): reclaim_complete() nfsd: Remove nfs4_lock_state(): setclientid, setclientid_confirm, renew nfsd: Remove nfs4_lock_state(): exchange_id, create/destroy_session() nfsd: Remove nfs4_lock_state(): nfsd4_open and nfsd4_open_confirm nfsd: Remove nfs4_lock_state(): nfsd4_delegreturn() nfsd: Remove nfs4_lock_state(): nfsd4_open_downgrade + nfsd4_close nfsd: Remove nfs4_lock_state(): nfsd4_lock/locku/lockt() nfsd: Remove nfs4_lock_state(): nfsd4_release_lockowner nfsd: Remove nfs4_lock_state(): nfsd4_test_stateid/nfsd4_free_stateid nfsd: Remove nfs4_lock_state(): nfs4_preprocess_stateid_op() nfsd: remove old fault injection infrastructure nfsd: add more granular locking to *_delegations fault injectors nfsd: add more granular locking to forget_openowners fault injector nfsd: add more granular locking to forget_locks fault injector nfsd: add a list_head arg to nfsd_foreach_client_lock ...
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