Source-Changes-D archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: CVS commit: src/sys/ufs/ufs
On Mon, Feb 25, 2019 at 06:07:23AM +0000, David Holland wrote:
> that one doesn't set dropend correctly for small buffers, outsmarted
> myself while writing it.
Better change (still against 1.242) that makes the logic much
simpler. Will test this overnight...
Index: ufs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ufs/ufs_vnops.c,v
retrieving revision 1.239
diff -u -p -r1.239 ufs_vnops.c
--- ufs_vnops.c 28 Oct 2017 00:37:13 -0000 1.239
+++ ufs_vnops.c 25 Feb 2019 06:58:52 -0000
@@ -1233,7 +1233,7 @@ ufs_readdir(void *v)
#endif
/* caller's buffer */
struct uio *calleruio = ap->a_uio;
- off_t startoffset, endoffset;
+ off_t startoffset;
size_t callerbytes;
off_t curoffset;
/* dirent production buffer */
@@ -1244,8 +1244,8 @@ ufs_readdir(void *v)
off_t *cookies;
size_t numcookies, maxcookies;
/* disk buffer */
- off_t physstart, physend;
- size_t skipstart, dropend;
+ off_t physstart;
+ size_t skipstart;
char *rawbuf;
size_t rawbufmax, rawbytes;
struct uio rawuio;
@@ -1256,29 +1256,60 @@ ufs_readdir(void *v)
KASSERT(VOP_ISLOCKED(vp));
- /* figure out where we want to read */
+#define UFS_READDIR_ARBITRARY_MAX (1024*1024)
callerbytes = calleruio->uio_resid;
- startoffset = calleruio->uio_offset;
- endoffset = startoffset + callerbytes;
-
if (callerbytes < _DIRENT_MINSIZE(dirent)) {
/* no room for even one struct dirent */
return EINVAL;
}
+ if (callerbytes > UFS_READDIR_ARBITRARY_MAX) {
+ callerbytes = UFS_READDIR_ARBITRARY_MAX;
+ }
- /* round start and end down to block boundaries */
+ /*
+ * Figure out where to start reading. Round the start down to
+ * a block boundary: we need to start at the beginning of a
+ * block in order to read the directory correctly.
+ *
+ * skipstart is the number of bytes we need to read in
+ * (because we need to start at the beginning of a block) but
+ * not transfer to the user.
+ */
+ startoffset = calleruio->uio_offset;
physstart = startoffset & ~(off_t)(ump->um_dirblksiz - 1);
- physend = endoffset & ~(off_t)(ump->um_dirblksiz - 1);
skipstart = startoffset - physstart;
- dropend = endoffset - physend;
- if (callerbytes - dropend < _DIRENT_MINSIZE(rawdp)) {
- /* no room for even one struct direct */
- return EINVAL;
- }
+ /*
+ * Now figure out how much to read.
+ *
+ * callerbytes tells us how much data we can send back to the
+ * user. Assume as a starting point that we want to read
+ * roughly the same volume of struct directs from disk as the
+ * volume of struct dirents we want to send to the user; this
+ * is not super accurate for large numbers of small names but
+ * will serve well enough. It's ok to underpopulate the user's
+ * buffer, and most directories are only a couple blocks
+ * anyway.
+ *
+ * However much we decide we want, stop on a block boundary.
+ * That way the copying code below doesn't need to worry about
+ * finding partial entries in the transfer buffer.
+ *
+ * Do this by rounding down (not up) by default as that will
+ * with luck avoid needing to scan the next block twice; but
+ * always read in at least one block.
+ */
- /* how much to actually read */
- rawbufmax = callerbytes + skipstart - dropend;
+ /* Base buffer space for CALLERBYTES of new data */
+ rawbufmax = callerbytes + skipstart;
+
+ /* Round down to an integral number of blocks */
+ rawbufmax &= ~(off_t)(ump->um_dirblksiz - 1);
+
+ /* but always at least one block */
+ if (rawbufmax == 0) {
+ rawbufmax = ump->um_dirblksiz;
+ }
/* read it */
rawbuf = kmem_alloc(rawbufmax, KM_SLEEP);
--
David A. Holland
dholland%netbsd.org@localhost
Home |
Main Index |
Thread Index |
Old Index