Read all dirents in directfs.

Earlier we were only reading upto 64*1024 bytes and assuming that was all.
Lisafs uses that count to make *multiple* Getdents RPCs until it encounters
EOF. But directfs was only attempting the 64*1024 read one time.

The count limit is not relevant for directfs. Make that lisafs specific.
Make directfs read dirents until EOF is encountered.

This this change, the nodejs test parallel/test-repl-tab-complete-import passes
on ubuntu-1804-lts machine now.

PiperOrigin-RevId: 532522376
This commit is contained in:
Ayush Ranjan
2023-05-16 11:33:13 -07:00
committed by gVisor bot
parent 243aeddd59
commit 27809081d4
4 changed files with 15 additions and 25 deletions
+3 -3
View File
@@ -379,12 +379,12 @@ func (d *dentry) openCreate(ctx context.Context, name string, accessFlags uint32
// - d.isDir().
// - d.handleMu must be locked.
// - !d.isSynthetic().
func (d *dentry) getDirentsLocked(ctx context.Context, count int, recordDirent func(name string, key inoKey, dType uint8)) error {
func (d *dentry) getDirentsLocked(ctx context.Context, recordDirent func(name string, key inoKey, dType uint8)) error {
switch dt := d.impl.(type) {
case *lisafsDentry:
return dt.getDirentsLocked(ctx, count, recordDirent)
return dt.getDirentsLocked(ctx, recordDirent)
case *directfsDentry:
return dt.getDirentsLocked(count, recordDirent)
return dt.getDirentsLocked(recordDirent)
default:
panic("unknown dentry implementation")
}
+3 -16
View File
@@ -558,27 +558,16 @@ func (d *directfsDentry) openCreate(name string, accessFlags uint32, mode linux.
return child, handle{fd: int32(childHandleFD)}, nil
}
func (d *directfsDentry) getDirentsLocked(count int, recordDirent func(name string, key inoKey, dType uint8)) error {
func (d *directfsDentry) getDirentsLocked(recordDirent func(name string, key inoKey, dType uint8)) error {
readFD := int(d.readFD.RacyLoad())
if _, err := unix.Seek(readFD, 0, 0); err != nil {
return err
}
var direntsBuf [8192]byte
for bytesRead := 0; bytesRead < count; {
bufEnd := len(direntsBuf)
if remaining := int(count) - bytesRead; remaining < bufEnd {
bufEnd = remaining
}
n, err := unix.Getdents(readFD, direntsBuf[:bufEnd])
for {
n, err := unix.Getdents(readFD, direntsBuf[:])
if err != nil {
if err == unix.EINVAL && bufEnd < fsutil.UnixDirentMaxSize {
// getdents64(2) returns EINVAL is returned when the result
// buffer is too small. If bufEnd is smaller than the max
// size of unix.Dirent, then just break here to return all
// dirents collected till now.
return nil
}
return err
}
if n <= 0 {
@@ -594,12 +583,10 @@ func (d *directfsDentry) getDirentsLocked(count int, recordDirent func(name stri
log.Warningf("Getdent64: skipping file %q with failed stat, err: %v", path.Join(genericDebugPathname(&d.dentry), name), err)
return true
}
bytesRead += int(reclen)
recordDirent(name, inoKeyFromStat(&stat), ftype)
return true
})
}
return nil
}
// Precondition: fs.renameMu is locked.
+1 -2
View File
@@ -272,8 +272,7 @@ func (d *dentry) getDirents(ctx context.Context) ([]vfs.Dirent, error) {
// have been opened when the calling directoryFD was opened.
panic("gofer.dentry.getDirents called without a readable handle")
}
const count = 64 * 1024 // for consistency with the vfs1 client
err := d.getDirentsLocked(ctx, count, func(name string, key inoKey, dType uint8) {
err := d.getDirentsLocked(ctx, func(name string, key inoKey, dType uint8) {
dirent := vfs.Dirent{
Name: name,
Ino: d.fs.inoFromKey(key),
+8 -4
View File
@@ -462,20 +462,24 @@ func (d *lisafsDentry) openCreate(ctx context.Context, name string, flags uint32
return child, h, nil
}
// lisafsGetdentsCount is the number of bytes of dirents to read from the
// server in each Getdents RPC. This value is consistent with vfs1 client.
const lisafsGetdentsCount = int32(64 * 1024)
// Preconditions:
// - getDirents may not be called concurrently with another getDirents call.
func (d *lisafsDentry) getDirentsLocked(ctx context.Context, count int, recordDirent func(name string, key inoKey, dType uint8)) error {
func (d *lisafsDentry) getDirentsLocked(ctx context.Context, recordDirent func(name string, key inoKey, dType uint8)) error {
// shouldSeek0 indicates whether the server should SEEK to 0 before reading
// directory entries.
shouldSeek0 := true
for {
countLisa := int32(count)
count := lisafsGetdentsCount
if shouldSeek0 {
// See lisafs.Getdents64Req.Count.
countLisa = -countLisa
count = -count
shouldSeek0 = false
}
dirents, err := d.readFDLisa.Getdents64(ctx, countLisa)
dirents, err := d.readFDLisa.Getdents64(ctx, count)
if err != nil {
return err
}