@@ -369,33 +369,52 @@ nfsd_reply_cache_scan(struct shrinker *shrink, struct shrink_control *sc)
369
369
return freed ;
370
370
}
371
371
372
- /*
373
- * Walk an xdr_buf and get a CRC for at most the first RC_CSUMLEN bytes
372
+ /**
373
+ * nfsd_cache_csum - Checksum incoming NFS Call arguments
374
+ * @buf: buffer containing a whole RPC Call message
375
+ * @start: starting byte of the NFS Call header
376
+ * @remaining: size of the NFS Call header, in bytes
377
+ *
378
+ * Compute a weak checksum of the leading bytes of an NFS procedure
379
+ * call header to help verify that a retransmitted Call matches an
380
+ * entry in the duplicate reply cache.
381
+ *
382
+ * To avoid assumptions about how the RPC message is laid out in
383
+ * @buf and what else it might contain (eg, a GSS MIC suffix), the
384
+ * caller passes us the exact location and length of the NFS Call
385
+ * header.
386
+ *
387
+ * Returns a 32-bit checksum value, as defined in RFC 793.
374
388
*/
375
- static __wsum
376
- nfsd_cache_csum ( struct svc_rqst * rqstp )
389
+ static __wsum nfsd_cache_csum ( struct xdr_buf * buf , unsigned int start ,
390
+ unsigned int remaining )
377
391
{
392
+ unsigned int base , len ;
393
+ struct xdr_buf subbuf ;
394
+ __wsum csum = 0 ;
395
+ void * p ;
378
396
int idx ;
379
- unsigned int base ;
380
- __wsum csum ;
381
- struct xdr_buf * buf = & rqstp -> rq_arg ;
382
- const unsigned char * p = buf -> head [0 ].iov_base ;
383
- size_t csum_len = min_t (size_t , buf -> head [0 ].iov_len + buf -> page_len ,
384
- RC_CSUMLEN );
385
- size_t len = min (buf -> head [0 ].iov_len , csum_len );
397
+
398
+ if (remaining > RC_CSUMLEN )
399
+ remaining = RC_CSUMLEN ;
400
+ if (xdr_buf_subsegment (buf , & subbuf , start , remaining ))
401
+ return csum ;
386
402
387
403
/* rq_arg.head first */
388
- csum = csum_partial (p , len , 0 );
389
- csum_len -= len ;
404
+ if (subbuf .head [0 ].iov_len ) {
405
+ len = min_t (unsigned int , subbuf .head [0 ].iov_len , remaining );
406
+ csum = csum_partial (subbuf .head [0 ].iov_base , len , csum );
407
+ remaining -= len ;
408
+ }
390
409
391
410
/* Continue into page array */
392
- idx = buf -> page_base / PAGE_SIZE ;
393
- base = buf -> page_base & ~PAGE_MASK ;
394
- while (csum_len ) {
395
- p = page_address (buf -> pages [idx ]) + base ;
396
- len = min_t (size_t , PAGE_SIZE - base , csum_len );
411
+ idx = subbuf . page_base / PAGE_SIZE ;
412
+ base = subbuf . page_base & ~PAGE_MASK ;
413
+ while (remaining ) {
414
+ p = page_address (subbuf . pages [idx ]) + base ;
415
+ len = min_t (unsigned int , PAGE_SIZE - base , remaining );
397
416
csum = csum_partial (p , len , csum );
398
- csum_len -= len ;
417
+ remaining -= len ;
399
418
base = 0 ;
400
419
++ idx ;
401
420
}
@@ -466,6 +485,8 @@ nfsd_cache_insert(struct nfsd_drc_bucket *b, struct nfsd_cacherep *key,
466
485
/**
467
486
* nfsd_cache_lookup - Find an entry in the duplicate reply cache
468
487
* @rqstp: Incoming Call to find
488
+ * @start: starting byte in @rqstp->rq_arg of the NFS Call header
489
+ * @len: size of the NFS Call header, in bytes
469
490
* @cacherep: OUT: DRC entry for this request
470
491
*
471
492
* Try to find an entry matching the current call in the cache. When none
@@ -479,7 +500,8 @@ nfsd_cache_insert(struct nfsd_drc_bucket *b, struct nfsd_cacherep *key,
479
500
* %RC_REPLY: Reply from cache
480
501
* %RC_DROPIT: Do not process the request further
481
502
*/
482
- int nfsd_cache_lookup (struct svc_rqst * rqstp , struct nfsd_cacherep * * cacherep )
503
+ int nfsd_cache_lookup (struct svc_rqst * rqstp , unsigned int start ,
504
+ unsigned int len , struct nfsd_cacherep * * cacherep )
483
505
{
484
506
struct nfsd_net * nn ;
485
507
struct nfsd_cacherep * rp , * found ;
@@ -495,7 +517,7 @@ int nfsd_cache_lookup(struct svc_rqst *rqstp, struct nfsd_cacherep **cacherep)
495
517
goto out ;
496
518
}
497
519
498
- csum = nfsd_cache_csum (rqstp );
520
+ csum = nfsd_cache_csum (& rqstp -> rq_arg , start , len );
499
521
500
522
/*
501
523
* Since the common case is a cache miss followed by an insert,
@@ -641,24 +663,17 @@ void nfsd_cache_update(struct svc_rqst *rqstp, struct nfsd_cacherep *rp,
641
663
return ;
642
664
}
643
665
644
- /*
645
- * Copy cached reply to current reply buffer. Should always fit.
646
- * FIXME as reply is in a page, we should just attach the page, and
647
- * keep a refcount....
648
- */
649
666
static int
650
667
nfsd_cache_append (struct svc_rqst * rqstp , struct kvec * data )
651
668
{
652
- struct kvec * vec = & rqstp -> rq_res .head [0 ];
653
-
654
- if (vec -> iov_len + data -> iov_len > PAGE_SIZE ) {
655
- printk (KERN_WARNING "nfsd: cached reply too large (%zd).\n" ,
656
- data -> iov_len );
657
- return 0 ;
658
- }
659
- memcpy ((char * )vec -> iov_base + vec -> iov_len , data -> iov_base , data -> iov_len );
660
- vec -> iov_len += data -> iov_len ;
661
- return 1 ;
669
+ __be32 * p ;
670
+
671
+ p = xdr_reserve_space (& rqstp -> rq_res_stream , data -> iov_len );
672
+ if (unlikely (!p ))
673
+ return false;
674
+ memcpy (p , data -> iov_base , data -> iov_len );
675
+ xdr_commit_encode (& rqstp -> rq_res_stream );
676
+ return true;
662
677
}
663
678
664
679
/*
0 commit comments