ANDROID: fuse-bpf: Fix readdir for getdents
If you call getdents with a buffer size less than a page, entries can be skipped. This correctly sets the point to continue from. Bug: 325550828 Test: getdents with low buffer size Signed-off-by: Daniel Rosenberg <drosen@google.com> (cherry picked from https://android-review.googlesource.com/q/commit:506cf3f0742432c1995117f83b2528a23944989b) Merged-In: I324e7e815d31742bd4e2d70c5d07c2b09a67a7c2 Change-Id: I324e7e815d31742bd4e2d70c5d07c2b09a67a7c2
This commit is contained in:
committed by
Todd Kjos
parent
599c52e842
commit
3bd1e69c2c
@@ -2366,8 +2366,11 @@ static bool filldir(struct dir_context *ctx, const char *name, int namelen,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_dirfile(char *buf, size_t nbytes, struct dir_context *ctx)
|
static int parse_dirfile(char *buf, size_t nbytes, struct dir_context *ctx,
|
||||||
|
loff_t next_offset)
|
||||||
{
|
{
|
||||||
|
char *buffstart = buf;
|
||||||
|
|
||||||
while (nbytes >= FUSE_NAME_OFFSET) {
|
while (nbytes >= FUSE_NAME_OFFSET) {
|
||||||
struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
|
struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
|
||||||
size_t reclen = FUSE_DIRENT_SIZE(dirent);
|
size_t reclen = FUSE_DIRENT_SIZE(dirent);
|
||||||
@@ -2381,12 +2384,18 @@ static int parse_dirfile(char *buf, size_t nbytes, struct dir_context *ctx)
|
|||||||
|
|
||||||
ctx->pos = dirent->off;
|
ctx->pos = dirent->off;
|
||||||
if (!dir_emit(ctx, dirent->name, dirent->namelen, dirent->ino,
|
if (!dir_emit(ctx, dirent->name, dirent->namelen, dirent->ino,
|
||||||
dirent->type))
|
dirent->type)) {
|
||||||
break;
|
// If we can't make any progress, user buffer is too small
|
||||||
|
if (buf == buffstart)
|
||||||
|
return -EINVAL;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
buf += reclen;
|
buf += reclen;
|
||||||
nbytes -= reclen;
|
nbytes -= reclen;
|
||||||
}
|
}
|
||||||
|
ctx->pos = next_offset;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -2433,13 +2442,12 @@ void *fuse_readdir_finalize(struct fuse_bpf_args *fa,
|
|||||||
struct file *backing_dir = ff->backing_file;
|
struct file *backing_dir = ff->backing_file;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
err = parse_dirfile(fa->out_args[1].value, fa->out_args[1].size, ctx);
|
err = parse_dirfile(fa->out_args[1].value, fa->out_args[1].size, ctx, fro->offset);
|
||||||
*force_again = !!fro->again;
|
*force_again = !!fro->again;
|
||||||
if (*force_again && !*allow_force)
|
if (*force_again && !*allow_force)
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
|
|
||||||
ctx->pos = fro->offset;
|
backing_dir->f_pos = ctx->pos;
|
||||||
backing_dir->f_pos = fro->offset;
|
|
||||||
|
|
||||||
free_page((unsigned long) fa->out_args[1].value);
|
free_page((unsigned long) fa->out_args[1].value);
|
||||||
return ERR_PTR(err);
|
return ERR_PTR(err);
|
||||||
|
Reference in New Issue
Block a user