mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 23:17:46 +00:00
Kernel+LibC: Make get_dir_entries syscall retriable
The get_dir_entries syscall failed if the serialized form of all the directory entries together was too large to fit in its temporary buffer. Now the kernel uses a fixed size buffer, that is flushed to an output buffer when it is full. If this flushing operation fails because there is not enough space available, the syscall will return -EINVAL. That error code is then used in userspace as a signal to allocate a larger buffer and retry the syscall.
This commit is contained in:
parent
c7b60164ed
commit
b00cdf8ed8
3 changed files with 65 additions and 21 deletions
|
@ -98,15 +98,30 @@ static int allocate_dirp_buffer(DIR* dirp)
|
|||
}
|
||||
size_t size_to_allocate = max(st.st_size, static_cast<off_t>(4096));
|
||||
dirp->buffer = (char*)malloc(size_to_allocate);
|
||||
ssize_t nread = syscall(SC_get_dir_entries, dirp->fd, dirp->buffer, size_to_allocate);
|
||||
if (nread < 0) {
|
||||
// uh-oh, the syscall returned an error
|
||||
free(dirp->buffer);
|
||||
dirp->buffer = nullptr;
|
||||
return -nread;
|
||||
if (!dirp->buffer)
|
||||
return ENOMEM;
|
||||
for (;;) {
|
||||
ssize_t nread = syscall(SC_get_dir_entries, dirp->fd, dirp->buffer, size_to_allocate);
|
||||
if (nread < 0) {
|
||||
if (nread == -EINVAL) {
|
||||
size_to_allocate *= 2;
|
||||
char* new_buffer = (char*)realloc(dirp->buffer, size_to_allocate);
|
||||
if (new_buffer) {
|
||||
dirp->buffer = new_buffer;
|
||||
continue;
|
||||
} else {
|
||||
nread = -ENOMEM;
|
||||
}
|
||||
}
|
||||
// uh-oh, the syscall returned an error
|
||||
free(dirp->buffer);
|
||||
dirp->buffer = nullptr;
|
||||
return -nread;
|
||||
}
|
||||
dirp->buffer_size = nread;
|
||||
dirp->nextptr = dirp->buffer;
|
||||
break;
|
||||
}
|
||||
dirp->buffer_size = nread;
|
||||
dirp->nextptr = dirp->buffer;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue