|  | @@ -41,6 +41,7 @@ static uint32_t table_base[] =
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #define BARREL_SHIFT(v, shift) ( ((v) << shift) | ((v) >> (32 - shift)) )
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +size_t pagemask;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static uint32_t *
 | 
	
		
			
				|  |  |  buzhash_init_table(uint32_t seed)
 | 
	
	
		
			
				|  | @@ -130,6 +131,7 @@ chunker_fill(Chunker *c)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      ssize_t n;
 | 
	
		
			
				|  |  |      off_t offset, length;
 | 
	
		
			
				|  |  | +    int overshoot;
 | 
	
		
			
				|  |  |      PyObject *data;
 | 
	
		
			
				|  |  |      memmove(c->data, c->data + c->last, c->position + c->remaining - c->last);
 | 
	
		
			
				|  |  |      c->position -= c->last;
 | 
	
	
		
			
				|  | @@ -157,14 +159,33 @@ chunker_fill(Chunker *c)
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          length = c->bytes_read - offset;
 | 
	
		
			
				|  |  |          #if ( ( _XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L ) && defined(POSIX_FADV_DONTNEED) )
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	// Only do it once per run.
 | 
	
		
			
				|  |  | +	if (pagemask == 0)
 | 
	
		
			
				|  |  | +		pagemask = getpagesize() - 1;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          // We tell the OS that we do not need the data that we just have read any
 | 
	
		
			
				|  |  |          // more (that it maybe has in the cache). This avoids that we spoil the
 | 
	
		
			
				|  |  |          // complete cache with data that we only read once and (due to cache
 | 
	
		
			
				|  |  |          // size limit) kick out data from the cache that might be still useful
 | 
	
		
			
				|  |  |          // for the OS or other processes.
 | 
	
		
			
				|  |  | +        // We rollback the initial offset back to the start of the page,
 | 
	
		
			
				|  |  | +        // to avoid it not being truncated as a partial page request.
 | 
	
		
			
				|  |  |          if (length > 0) {
 | 
	
		
			
				|  |  | -            posix_fadvise(c->fh, offset, length, POSIX_FADV_DONTNEED);
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | +            // Linux kernels prior to 4.7 have a bug where they truncate
 | 
	
		
			
				|  |  | +            // last partial page of POSIX_FADV_DONTNEED request, so we need
 | 
	
		
			
				|  |  | +            // to page-align it ourselves. We'll need the rest of this page
 | 
	
		
			
				|  |  | +            // on the next read (assuming this was not EOF)
 | 
	
		
			
				|  |  | +            overshoot = (offset + length) & pagemask;
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +            // For length == 0 we set overshoot 0, so the below
 | 
	
		
			
				|  |  | +            // length - overshoot is 0, which means till end of file for
 | 
	
		
			
				|  |  | +            // fadvise. This will cancel the final page and is not part
 | 
	
		
			
				|  |  | +            // of the above workaround.
 | 
	
		
			
				|  |  | +            overshoot = 0;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        posix_fadvise(c->fh, offset & ~pagemask, length - overshoot, POSIX_FADV_DONTNEED);
 | 
	
		
			
				|  |  |          #endif
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      else {
 |