On 4/16/25 11:07, Miklos Szeredi wrote: > When getting the directory contents, the entries are fist fetched to a > kernel buffer, then they are copied to userspace with dir_emit(). This > second phase is non-blocking as long as the userspace buffer is not paged > out, making it interruptible makes zero sense. > > Overload d_type as flags, since it only uses 4 bits from 32. > > Signed-off-by: Miklos Szeredi <mszeredi@xxxxxxxxxx> > --- > fs/fuse/readdir.c | 4 ++-- > fs/readdir.c | 15 ++++++++++++--- > include/linux/fs.h | 3 +++ > 3 files changed, 17 insertions(+), 5 deletions(-) > > diff --git a/fs/fuse/readdir.c b/fs/fuse/readdir.c > index 17ce9636a2b1..edcd6f18a8a8 100644 > --- a/fs/fuse/readdir.c > +++ b/fs/fuse/readdir.c > @@ -120,7 +120,7 @@ static bool fuse_emit(struct file *file, struct dir_context *ctx, > fuse_add_dirent_to_cache(file, dirent, ctx->pos); > > return dir_emit(ctx, dirent->name, dirent->namelen, dirent->ino, > - dirent->type); > + dirent->type | FILLDIR_FLAG_NOINTR); > } > > static int parse_dirfile(char *buf, size_t nbytes, struct file *file, > @@ -419,7 +419,7 @@ static enum fuse_parse_result fuse_parse_cache(struct fuse_file *ff, > if (ff->readdir.pos == ctx->pos) { > res = FOUND_SOME; > if (!dir_emit(ctx, dirent->name, dirent->namelen, > - dirent->ino, dirent->type)) > + dirent->ino, dirent->type | FILLDIR_FLAG_NOINTR)) > return FOUND_ALL; > ctx->pos = dirent->off; > } > diff --git a/fs/readdir.c b/fs/readdir.c > index 0038efda417b..00ceae3fc2e3 100644 > --- a/fs/readdir.c > +++ b/fs/readdir.c > @@ -266,6 +266,9 @@ static bool filldir(struct dir_context *ctx, const char *name, int namlen, > int reclen = ALIGN(offsetof(struct linux_dirent, d_name) + namlen + 2, > sizeof(long)); > int prev_reclen; > + unsigned int flags = d_type; > + > + d_type &= S_DT_MASK; > > buf->error = verify_dirent_name(name, namlen); > if (unlikely(buf->error)) > @@ -279,7 +282,7 @@ static bool filldir(struct dir_context *ctx, const char *name, int namlen, > return false; > } > prev_reclen = buf->prev_reclen; > - if (prev_reclen && signal_pending(current)) > + if (!(flags & FILLDIR_FLAG_NOINTR) && prev_reclen && signal_pending(current)) > return false; > dirent = buf->current_dir; > prev = (void __user *) dirent - prev_reclen; > @@ -351,6 +354,9 @@ static bool filldir64(struct dir_context *ctx, const char *name, int namlen, > int reclen = ALIGN(offsetof(struct linux_dirent64, d_name) + namlen + 1, > sizeof(u64)); > int prev_reclen; > + unsigned int flags = d_type; > + > + d_type &= S_DT_MASK; > > buf->error = verify_dirent_name(name, namlen); > if (unlikely(buf->error)) > @@ -359,7 +365,7 @@ static bool filldir64(struct dir_context *ctx, const char *name, int namlen, > if (reclen > buf->count) > return false; > prev_reclen = buf->prev_reclen; > - if (prev_reclen && signal_pending(current)) > + if (!(flags & FILLDIR_FLAG_NOINTR) && prev_reclen && signal_pending(current)) > return false; > dirent = buf->current_dir; > prev = (void __user *)dirent - prev_reclen; > @@ -513,6 +519,9 @@ static bool compat_filldir(struct dir_context *ctx, const char *name, int namlen > int reclen = ALIGN(offsetof(struct compat_linux_dirent, d_name) + > namlen + 2, sizeof(compat_long_t)); > int prev_reclen; > + unsigned int flags = d_type; > + > + d_type &= S_DT_MASK; > > buf->error = verify_dirent_name(name, namlen); > if (unlikely(buf->error)) > @@ -526,7 +535,7 @@ static bool compat_filldir(struct dir_context *ctx, const char *name, int namlen > return false; > } > prev_reclen = buf->prev_reclen; > - if (prev_reclen && signal_pending(current)) > + if (!(flags & FILLDIR_FLAG_NOINTR) && prev_reclen && signal_pending(current)) > return false; > dirent = buf->current_dir; > prev = (void __user *) dirent - prev_reclen; > diff --git a/include/linux/fs.h b/include/linux/fs.h > index 016b0fe1536e..0f2a1a572e3a 100644 > --- a/include/linux/fs.h > +++ b/include/linux/fs.h > @@ -2073,6 +2073,9 @@ struct dir_context { > loff_t pos; > }; > > +/* If OR-ed with d_type, pending signals are not checked */ > +#define FILLDIR_FLAG_NOINTR 0x1000 This is the part that might be confusing - it is in another file than DT_MAX / S_DT_MASK - it might be hard to know about FILLDIR_FLAG_NOINTR and possible other future flags? But then it is certainly not a file type, having it in fs.h makes sense from that point of view. Reviewed-by: Bernd Schubert <bschubert@xxxxxxx>