@@ -3823,6 +3823,7 @@ nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp, struct nfsd4_read *r
*p++ = cpu_to_be32(maxcount);
read->rd_offset += maxcount;
+ read->rd_length -= maxcount;
return err;
}
@@ -3839,6 +3840,10 @@ nfsd4_encode_read_plus_hole(struct nfsd4_compoundres *resp, struct nfsd4_read *r
p = xdr_encode_hyper(p, maxcount);
read->rd_offset += maxcount;
+ if (maxcount > read->rd_length)
+ read->rd_length = 0;
+ else
+ read->rd_length -= maxcount;
return nfs_ok;
}
@@ -3871,23 +3876,26 @@ nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr,
goto err_truncate;
}
- hole_pos = vfs_llseek(read->rd_filp, read->rd_offset, SEEK_HOLE);
- if (hole_pos == -ENXIO)
- goto out_encode;
+ do {
+ hole_pos = vfs_llseek(read->rd_filp, read->rd_offset, SEEK_HOLE);
+ if (hole_pos == -ENXIO)
+ break;
- data_pos = vfs_llseek(read->rd_filp, read->rd_offset, SEEK_DATA);
- if (data_pos == -ENXIO)
- data_pos = i_size_read(file_inode(file));
+ data_pos = vfs_llseek(read->rd_filp, read->rd_offset, SEEK_DATA);
+ if (data_pos == -ENXIO)
+ data_pos = i_size_read(file_inode(file));
- if ((data_pos == read->rd_offset) && (hole_pos > data_pos))
- err = nfsd4_encode_read_plus_data(resp, read, file, hole_pos);
- else if ((hole_pos == read->rd_offset) && (data_pos > hole_pos))
- err = nfsd4_encode_read_plus_hole(resp, read, file, data_pos);
- else /* The file probably changed on us between seeks. */
- err = nfsd4_encode_read_plus_data(resp, read, file, i_size_read(file_inode(file)));
- segments++;
+ if ((data_pos == read->rd_offset) && (hole_pos > data_pos))
+ err = nfsd4_encode_read_plus_data(resp, read, file, hole_pos);
+ else if ((hole_pos == read->rd_offset) && (data_pos > hole_pos))
+ err = nfsd4_encode_read_plus_hole(resp, read, file, data_pos);
+ else /* The file probably changed on us between seeks. */
+ err = nfsd4_encode_read_plus_data(resp, read, file, i_size_read(file_inode(file)));
+ if (err)
+ break;
+ segments++;
+ } while (read->rd_length > 0);
-out_encode:
eof = (read->rd_offset >= i_size_read(file_inode(file)));
*p++ = cpu_to_be32(eof);
*p++ = cpu_to_be32(segments);