Commit 467e245d authored by Miklos Szeredi's avatar Miklos Szeredi
Browse files

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: default avatarMiklos Szeredi <mszeredi@redhat.com>
Signed-off-by: default avatarJaco Kroon <jaco@uls.co.za>
parent c31f91c6
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -284,6 +284,7 @@ static int get_name(const struct path *path, char *name, struct dentry *child)
	};
	struct getdents_callback buffer = {
		.ctx.actor = filldir_one,
		.ctx.count = INT_MAX,
		.name = name,
	};

+11 −1
Original line number Diff line number Diff line
@@ -351,6 +351,7 @@ static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list,
	struct path realpath;
	struct ovl_readdir_data rdd = {
		.ctx.actor = ovl_fill_merge,
		.ctx.count = INT_MAX,
		.dentry = dentry,
		.list = list,
		.root = root,
@@ -571,6 +572,7 @@ static int ovl_dir_read_impure(const struct path *path, struct list_head *list,
	struct ovl_cache_entry *p, *n;
	struct ovl_readdir_data rdd = {
		.ctx.actor = ovl_fill_plain,
		.ctx.count = INT_MAX,
		.list = list,
		.root = root,
	};
@@ -672,6 +674,7 @@ static bool ovl_fill_real(struct dir_context *ctx, const char *name,
	struct ovl_readdir_translate *rdt =
		container_of(ctx, struct ovl_readdir_translate, ctx);
	struct dir_context *orig_ctx = rdt->orig_ctx;
	bool res;

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

	return orig_ctx->actor(orig_ctx, name, namelen, offset, ino, d_type);
	res = orig_ctx->actor(orig_ctx, name, namelen, offset, ino, d_type);
	ctx->count = orig_ctx->count;

	return res;
}

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)
	const struct ovl_layer *lower_layer = ovl_layer_lower(dir);
	struct ovl_readdir_translate rdt = {
		.ctx.actor = ovl_fill_real,
		.ctx.count = ctx->count,
		.orig_ctx = ctx,
		.xinobits = ovl_xino_bits(ofs),
		.xinowarn = ovl_xino_warn(ofs),
@@ -1073,6 +1080,7 @@ int ovl_check_d_type_supported(const struct path *realpath)
	int err;
	struct ovl_readdir_data rdd = {
		.ctx.actor = ovl_check_d_type,
		.ctx.count = INT_MAX,
		.d_type_supported = false,
	};

@@ -1094,6 +1102,7 @@ static int ovl_workdir_cleanup_recurse(struct ovl_fs *ofs, const struct path *pa
	struct ovl_cache_entry *p;
	struct ovl_readdir_data rdd = {
		.ctx.actor = ovl_fill_plain,
		.ctx.count = INT_MAX,
		.list = &list,
	};
	bool incompat = false;
@@ -1178,6 +1187,7 @@ int ovl_indexdir_cleanup(struct ovl_fs *ofs)
	struct ovl_cache_entry *p;
	struct ovl_readdir_data rdd = {
		.ctx.actor = ovl_fill_plain,
		.ctx.count = INT_MAX,
		.list = &list,
	};

+14 −15
Original line number Diff line number Diff line
@@ -222,6 +222,7 @@ SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
	CLASS(fd_pos, f)(fd);
	struct readdir_callback buf = {
		.ctx.actor = fillonedir,
		.ctx.count = 1, /* Hint to fs: just one entry. */
		.dirent = dirent
	};

@@ -252,7 +253,6 @@ struct getdents_callback {
	struct dir_context ctx;
	struct linux_dirent __user * current_dir;
	int prev_reclen;
	int count;
	int error;
};

@@ -275,7 +275,7 @@ static bool filldir(struct dir_context *ctx, const char *name, int namlen,
	if (unlikely(buf->error))
		return false;
	buf->error = -EINVAL;	/* only used if we fail.. */
	if (reclen > buf->count)
	if (reclen > ctx->count)
		return false;
	d_ino = ino;
	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,

	buf->current_dir = (void __user *)dirent + reclen;
	buf->prev_reclen = reclen;
	buf->count -= reclen;
	ctx->count -= reclen;
	return true;
efault_end:
	user_write_access_end();
@@ -315,7 +315,7 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd,
	CLASS(fd_pos, f)(fd);
	struct getdents_callback buf = {
		.ctx.actor = filldir,
		.count = count,
		.ctx.count = count,
		.current_dir = dirent
	};
	int error;
@@ -333,7 +333,7 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd,
		if (put_user(buf.ctx.pos, &lastdirent->d_off))
			error = -EFAULT;
		else
			error = count - buf.count;
			error = count - buf.ctx.count;
	}
	return error;
}
@@ -342,7 +342,6 @@ struct getdents_callback64 {
	struct dir_context ctx;
	struct linux_dirent64 __user * current_dir;
	int prev_reclen;
	int count;
	int error;
};

@@ -364,7 +363,7 @@ static bool filldir64(struct dir_context *ctx, const char *name, int namlen,
	if (unlikely(buf->error))
		return false;
	buf->error = -EINVAL;	/* only used if we fail.. */
	if (reclen > buf->count)
	if (reclen > ctx->count)
		return false;
	prev_reclen = buf->prev_reclen;
	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,

	buf->prev_reclen = reclen;
	buf->current_dir = (void __user *)dirent + reclen;
	buf->count -= reclen;
	ctx->count -= reclen;
	return true;

efault_end:
@@ -400,7 +399,7 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd,
	CLASS(fd_pos, f)(fd);
	struct getdents_callback64 buf = {
		.ctx.actor = filldir64,
		.count = count,
		.ctx.count = count,
		.current_dir = dirent
	};
	int error;
@@ -419,7 +418,7 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd,
		if (put_user(d_off, &lastdirent->d_off))
			error = -EFAULT;
		else
			error = count - buf.count;
			error = count - buf.ctx.count;
	}
	return error;
}
@@ -483,6 +482,7 @@ COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
	CLASS(fd_pos, f)(fd);
	struct compat_readdir_callback buf = {
		.ctx.actor = compat_fillonedir,
		.ctx.count = 1, /* Hint to fs: just one entry. */
		.dirent = dirent
	};

@@ -507,7 +507,6 @@ struct compat_getdents_callback {
	struct dir_context ctx;
	struct compat_linux_dirent __user *current_dir;
	int prev_reclen;
	int count;
	int error;
};

@@ -530,7 +529,7 @@ static bool compat_filldir(struct dir_context *ctx, const char *name, int namlen
	if (unlikely(buf->error))
		return false;
	buf->error = -EINVAL;	/* only used if we fail.. */
	if (reclen > buf->count)
	if (reclen > ctx->count)
		return false;
	d_ino = ino;
	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

	buf->prev_reclen = reclen;
	buf->current_dir = (void __user *)dirent + reclen;
	buf->count -= reclen;
	ctx->count -= reclen;
	return true;
efault_end:
	user_write_access_end();
@@ -569,8 +568,8 @@ COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd,
	CLASS(fd_pos, f)(fd);
	struct compat_getdents_callback buf = {
		.ctx.actor = compat_filldir,
		.ctx.count = count,
		.current_dir = dirent,
		.count = count
	};
	int error;

@@ -587,7 +586,7 @@ COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd,
		if (put_user(buf.ctx.pos, &lastdirent->d_off))
			error = -EFAULT;
		else
			error = count - buf.count;
			error = count - buf.ctx.count;
	}
	return error;
}
+7 −0
Original line number Diff line number Diff line
@@ -2071,6 +2071,13 @@ typedef bool (*filldir_t)(struct dir_context *, const char *, int, loff_t, u64,
struct dir_context {
	filldir_t actor;
	loff_t pos;
	/*
	 * Filesystems MUST NOT MODIFY count, but may use as a hint:
	 * 0	    unknown
	 * > 0      space in buffer (assume at least one entry)
	 * INT_MAX  unlimited
	 */
	int count;
};

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