Skip to content

Commit 467e245

Browse files
author
Miklos Szeredi
committed
readdir: supply dir_context.count as readdir buffer size hint
This is a preparation for large readdir buffers in fuse. Simply setting the fuse buffer size to the userspace buffer size should work, the record sizes are similar (fuse's is slightly larger than libc's, so no overflow should ever happen). Signed-off-by: Miklos Szeredi <[email protected]> Signed-off-by: Jaco Kroon <[email protected]>
1 parent c31f91c commit 467e245

File tree

4 files changed

+33
-16
lines changed

4 files changed

+33
-16
lines changed

fs/exportfs/expfs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ static int get_name(const struct path *path, char *name, struct dentry *child)
284284
};
285285
struct getdents_callback buffer = {
286286
.ctx.actor = filldir_one,
287+
.ctx.count = INT_MAX,
287288
.name = name,
288289
};
289290

fs/overlayfs/readdir.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,7 @@ static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list,
351351
struct path realpath;
352352
struct ovl_readdir_data rdd = {
353353
.ctx.actor = ovl_fill_merge,
354+
.ctx.count = INT_MAX,
354355
.dentry = dentry,
355356
.list = list,
356357
.root = root,
@@ -571,6 +572,7 @@ static int ovl_dir_read_impure(const struct path *path, struct list_head *list,
571572
struct ovl_cache_entry *p, *n;
572573
struct ovl_readdir_data rdd = {
573574
.ctx.actor = ovl_fill_plain,
575+
.ctx.count = INT_MAX,
574576
.list = list,
575577
.root = root,
576578
};
@@ -672,6 +674,7 @@ static bool ovl_fill_real(struct dir_context *ctx, const char *name,
672674
struct ovl_readdir_translate *rdt =
673675
container_of(ctx, struct ovl_readdir_translate, ctx);
674676
struct dir_context *orig_ctx = rdt->orig_ctx;
677+
bool res;
675678

676679
if (rdt->parent_ino && strcmp(name, "..") == 0) {
677680
ino = rdt->parent_ino;
@@ -686,7 +689,10 @@ static bool ovl_fill_real(struct dir_context *ctx, const char *name,
686689
name, namelen, rdt->xinowarn);
687690
}
688691

689-
return orig_ctx->actor(orig_ctx, name, namelen, offset, ino, d_type);
692+
res = orig_ctx->actor(orig_ctx, name, namelen, offset, ino, d_type);
693+
ctx->count = orig_ctx->count;
694+
695+
return res;
690696
}
691697

692698
static bool ovl_is_impure_dir(struct file *file)
@@ -713,6 +719,7 @@ static int ovl_iterate_real(struct file *file, struct dir_context *ctx)
713719
const struct ovl_layer *lower_layer = ovl_layer_lower(dir);
714720
struct ovl_readdir_translate rdt = {
715721
.ctx.actor = ovl_fill_real,
722+
.ctx.count = ctx->count,
716723
.orig_ctx = ctx,
717724
.xinobits = ovl_xino_bits(ofs),
718725
.xinowarn = ovl_xino_warn(ofs),
@@ -1073,6 +1080,7 @@ int ovl_check_d_type_supported(const struct path *realpath)
10731080
int err;
10741081
struct ovl_readdir_data rdd = {
10751082
.ctx.actor = ovl_check_d_type,
1083+
.ctx.count = INT_MAX,
10761084
.d_type_supported = false,
10771085
};
10781086

@@ -1094,6 +1102,7 @@ static int ovl_workdir_cleanup_recurse(struct ovl_fs *ofs, const struct path *pa
10941102
struct ovl_cache_entry *p;
10951103
struct ovl_readdir_data rdd = {
10961104
.ctx.actor = ovl_fill_plain,
1105+
.ctx.count = INT_MAX,
10971106
.list = &list,
10981107
};
10991108
bool incompat = false;
@@ -1178,6 +1187,7 @@ int ovl_indexdir_cleanup(struct ovl_fs *ofs)
11781187
struct ovl_cache_entry *p;
11791188
struct ovl_readdir_data rdd = {
11801189
.ctx.actor = ovl_fill_plain,
1190+
.ctx.count = INT_MAX,
11811191
.list = &list,
11821192
};
11831193

fs/readdir.c

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
222222
CLASS(fd_pos, f)(fd);
223223
struct readdir_callback buf = {
224224
.ctx.actor = fillonedir,
225+
.ctx.count = 1, /* Hint to fs: just one entry. */
225226
.dirent = dirent
226227
};
227228

@@ -252,7 +253,6 @@ struct getdents_callback {
252253
struct dir_context ctx;
253254
struct linux_dirent __user * current_dir;
254255
int prev_reclen;
255-
int count;
256256
int error;
257257
};
258258

@@ -275,7 +275,7 @@ static bool filldir(struct dir_context *ctx, const char *name, int namlen,
275275
if (unlikely(buf->error))
276276
return false;
277277
buf->error = -EINVAL; /* only used if we fail.. */
278-
if (reclen > buf->count)
278+
if (reclen > ctx->count)
279279
return false;
280280
d_ino = ino;
281281
if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
@@ -300,7 +300,7 @@ static bool filldir(struct dir_context *ctx, const char *name, int namlen,
300300

301301
buf->current_dir = (void __user *)dirent + reclen;
302302
buf->prev_reclen = reclen;
303-
buf->count -= reclen;
303+
ctx->count -= reclen;
304304
return true;
305305
efault_end:
306306
user_write_access_end();
@@ -315,7 +315,7 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd,
315315
CLASS(fd_pos, f)(fd);
316316
struct getdents_callback buf = {
317317
.ctx.actor = filldir,
318-
.count = count,
318+
.ctx.count = count,
319319
.current_dir = dirent
320320
};
321321
int error;
@@ -333,7 +333,7 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd,
333333
if (put_user(buf.ctx.pos, &lastdirent->d_off))
334334
error = -EFAULT;
335335
else
336-
error = count - buf.count;
336+
error = count - buf.ctx.count;
337337
}
338338
return error;
339339
}
@@ -342,7 +342,6 @@ struct getdents_callback64 {
342342
struct dir_context ctx;
343343
struct linux_dirent64 __user * current_dir;
344344
int prev_reclen;
345-
int count;
346345
int error;
347346
};
348347

@@ -364,7 +363,7 @@ static bool filldir64(struct dir_context *ctx, const char *name, int namlen,
364363
if (unlikely(buf->error))
365364
return false;
366365
buf->error = -EINVAL; /* only used if we fail.. */
367-
if (reclen > buf->count)
366+
if (reclen > ctx->count)
368367
return false;
369368
prev_reclen = buf->prev_reclen;
370369
if (!(flags & FILLDIR_FLAG_NOINTR) && prev_reclen && signal_pending(current))
@@ -384,7 +383,7 @@ static bool filldir64(struct dir_context *ctx, const char *name, int namlen,
384383

385384
buf->prev_reclen = reclen;
386385
buf->current_dir = (void __user *)dirent + reclen;
387-
buf->count -= reclen;
386+
ctx->count -= reclen;
388387
return true;
389388

390389
efault_end:
@@ -400,7 +399,7 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd,
400399
CLASS(fd_pos, f)(fd);
401400
struct getdents_callback64 buf = {
402401
.ctx.actor = filldir64,
403-
.count = count,
402+
.ctx.count = count,
404403
.current_dir = dirent
405404
};
406405
int error;
@@ -419,7 +418,7 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd,
419418
if (put_user(d_off, &lastdirent->d_off))
420419
error = -EFAULT;
421420
else
422-
error = count - buf.count;
421+
error = count - buf.ctx.count;
423422
}
424423
return error;
425424
}
@@ -483,6 +482,7 @@ COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
483482
CLASS(fd_pos, f)(fd);
484483
struct compat_readdir_callback buf = {
485484
.ctx.actor = compat_fillonedir,
485+
.ctx.count = 1, /* Hint to fs: just one entry. */
486486
.dirent = dirent
487487
};
488488

@@ -507,7 +507,6 @@ struct compat_getdents_callback {
507507
struct dir_context ctx;
508508
struct compat_linux_dirent __user *current_dir;
509509
int prev_reclen;
510-
int count;
511510
int error;
512511
};
513512

@@ -530,7 +529,7 @@ static bool compat_filldir(struct dir_context *ctx, const char *name, int namlen
530529
if (unlikely(buf->error))
531530
return false;
532531
buf->error = -EINVAL; /* only used if we fail.. */
533-
if (reclen > buf->count)
532+
if (reclen > ctx->count)
534533
return false;
535534
d_ino = ino;
536535
if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
@@ -554,7 +553,7 @@ static bool compat_filldir(struct dir_context *ctx, const char *name, int namlen
554553

555554
buf->prev_reclen = reclen;
556555
buf->current_dir = (void __user *)dirent + reclen;
557-
buf->count -= reclen;
556+
ctx->count -= reclen;
558557
return true;
559558
efault_end:
560559
user_write_access_end();
@@ -569,8 +568,8 @@ COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd,
569568
CLASS(fd_pos, f)(fd);
570569
struct compat_getdents_callback buf = {
571570
.ctx.actor = compat_filldir,
571+
.ctx.count = count,
572572
.current_dir = dirent,
573-
.count = count
574573
};
575574
int error;
576575

@@ -587,7 +586,7 @@ COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd,
587586
if (put_user(buf.ctx.pos, &lastdirent->d_off))
588587
error = -EFAULT;
589588
else
590-
error = count - buf.count;
589+
error = count - buf.ctx.count;
591590
}
592591
return error;
593592
}

include/linux/fs.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2071,6 +2071,13 @@ typedef bool (*filldir_t)(struct dir_context *, const char *, int, loff_t, u64,
20712071
struct dir_context {
20722072
filldir_t actor;
20732073
loff_t pos;
2074+
/*
2075+
* Filesystems MUST NOT MODIFY count, but may use as a hint:
2076+
* 0 unknown
2077+
* > 0 space in buffer (assume at least one entry)
2078+
* INT_MAX unlimited
2079+
*/
2080+
int count;
20742081
};
20752082

20762083
/* If OR-ed with d_type, pending signals are not checked */

0 commit comments

Comments
 (0)