[readdir] introduce iterate_dir() and dir_context
iterate_dir(): new helper, replacing vfs_readdir(). struct dir_context: contains the readdir callback (and will get more stuff in it), embedded into whatever data that callback wants to deal with; eventually, we'll be passing it to ->readdir() replacement instead of (data,filldir) pair. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Родитель
83a8761142
Коммит
5c0ba4e076
|
@ -445,3 +445,6 @@ object doesn't exist. It's remote/distributed ones that might care...
|
|||
[mandatory]
|
||||
FS_REVAL_DOT is gone; if you used to have it, add ->d_weak_revalidate()
|
||||
in your dentry operations instead.
|
||||
--
|
||||
[mandatory]
|
||||
vfs_readdir() is gone; switch to iterate_dir() instead
|
||||
|
|
|
@ -96,6 +96,7 @@ struct osf_dirent {
|
|||
};
|
||||
|
||||
struct osf_dirent_callback {
|
||||
struct dir_context ctx;
|
||||
struct osf_dirent __user *dirent;
|
||||
long __user *basep;
|
||||
unsigned int count;
|
||||
|
@ -155,8 +156,9 @@ SYSCALL_DEFINE4(osf_getdirentries, unsigned int, fd,
|
|||
buf.basep = basep;
|
||||
buf.count = count;
|
||||
buf.error = 0;
|
||||
buf.ctx.actor = osf_filldir;
|
||||
|
||||
error = vfs_readdir(arg.file, osf_filldir, &buf);
|
||||
error = iterate_dir(arg.file, &buf.ctx);
|
||||
if (error >= 0)
|
||||
error = buf.error;
|
||||
if (count != buf.count)
|
||||
|
|
|
@ -60,6 +60,7 @@ struct hpux_dirent {
|
|||
};
|
||||
|
||||
struct getdents_callback {
|
||||
struct dir_context ctx;
|
||||
struct hpux_dirent __user *current_dir;
|
||||
struct hpux_dirent __user *previous;
|
||||
int count;
|
||||
|
@ -121,8 +122,9 @@ int hpux_getdents(unsigned int fd, struct hpux_dirent __user *dirent, unsigned i
|
|||
buf.previous = NULL;
|
||||
buf.count = count;
|
||||
buf.error = 0;
|
||||
buf.ctx.actor = filldir;
|
||||
|
||||
error = vfs_readdir(arg.file, filldir, &buf);
|
||||
error = iterate_dir(arg.file, &buf.ctx);
|
||||
if (error >= 0)
|
||||
error = buf.error;
|
||||
lastdirent = buf.previous;
|
||||
|
|
12
fs/compat.c
12
fs/compat.c
|
@ -832,6 +832,7 @@ struct compat_old_linux_dirent {
|
|||
};
|
||||
|
||||
struct compat_readdir_callback {
|
||||
struct dir_context ctx;
|
||||
struct compat_old_linux_dirent __user *dirent;
|
||||
int result;
|
||||
};
|
||||
|
@ -880,8 +881,9 @@ asmlinkage long compat_sys_old_readdir(unsigned int fd,
|
|||
|
||||
buf.result = 0;
|
||||
buf.dirent = dirent;
|
||||
buf.ctx.actor = compat_fillonedir;
|
||||
|
||||
error = vfs_readdir(f.file, compat_fillonedir, &buf);
|
||||
error = iterate_dir(f.file, &buf.ctx);
|
||||
if (buf.result)
|
||||
error = buf.result;
|
||||
|
||||
|
@ -897,6 +899,7 @@ struct compat_linux_dirent {
|
|||
};
|
||||
|
||||
struct compat_getdents_callback {
|
||||
struct dir_context ctx;
|
||||
struct compat_linux_dirent __user *current_dir;
|
||||
struct compat_linux_dirent __user *previous;
|
||||
int count;
|
||||
|
@ -965,8 +968,9 @@ asmlinkage long compat_sys_getdents(unsigned int fd,
|
|||
buf.previous = NULL;
|
||||
buf.count = count;
|
||||
buf.error = 0;
|
||||
buf.ctx.actor = compat_filldir;
|
||||
|
||||
error = vfs_readdir(f.file, compat_filldir, &buf);
|
||||
error = iterate_dir(f.file, &buf.ctx);
|
||||
if (error >= 0)
|
||||
error = buf.error;
|
||||
lastdirent = buf.previous;
|
||||
|
@ -983,6 +987,7 @@ asmlinkage long compat_sys_getdents(unsigned int fd,
|
|||
#ifndef __ARCH_OMIT_COMPAT_SYS_GETDENTS64
|
||||
|
||||
struct compat_getdents_callback64 {
|
||||
struct dir_context ctx;
|
||||
struct linux_dirent64 __user *current_dir;
|
||||
struct linux_dirent64 __user *previous;
|
||||
int count;
|
||||
|
@ -1050,8 +1055,9 @@ asmlinkage long compat_sys_getdents64(unsigned int fd,
|
|||
buf.previous = NULL;
|
||||
buf.count = count;
|
||||
buf.error = 0;
|
||||
buf.ctx.actor = compat_filldir64;
|
||||
|
||||
error = vfs_readdir(f.file, compat_filldir64, &buf);
|
||||
error = iterate_dir(f.file, &buf.ctx);
|
||||
if (error >= 0)
|
||||
error = buf.error;
|
||||
lastdirent = buf.previous;
|
||||
|
|
|
@ -68,6 +68,7 @@ static ssize_t ecryptfs_read_update_atime(struct kiocb *iocb,
|
|||
}
|
||||
|
||||
struct ecryptfs_getdents_callback {
|
||||
struct dir_context ctx;
|
||||
void *dirent;
|
||||
struct dentry *dentry;
|
||||
filldir_t filldir;
|
||||
|
@ -126,7 +127,8 @@ static int ecryptfs_readdir(struct file *file, void *dirent, filldir_t filldir)
|
|||
buf.filldir = filldir;
|
||||
buf.filldir_called = 0;
|
||||
buf.entries_written = 0;
|
||||
rc = vfs_readdir(lower_file, ecryptfs_filldir, (void *)&buf);
|
||||
buf.ctx.actor = ecryptfs_filldir;
|
||||
rc = iterate_dir(lower_file, &buf.ctx);
|
||||
file->f_pos = lower_file->f_pos;
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
|
|
@ -212,6 +212,7 @@ reconnect_path(struct vfsmount *mnt, struct dentry *target_dir, char *nbuf)
|
|||
}
|
||||
|
||||
struct getdents_callback {
|
||||
struct dir_context ctx;
|
||||
char *name; /* name that was found. It already points to a
|
||||
buffer NAME_MAX+1 is size */
|
||||
unsigned long ino; /* the inum we are looking for */
|
||||
|
@ -278,10 +279,11 @@ static int get_name(const struct path *path, char *name, struct dentry *child)
|
|||
buffer.ino = child->d_inode->i_ino;
|
||||
buffer.found = 0;
|
||||
buffer.sequence = 0;
|
||||
buffer.ctx.actor = filldir_one;
|
||||
while (1) {
|
||||
int old_seq = buffer.sequence;
|
||||
|
||||
error = vfs_readdir(file, filldir_one, &buffer);
|
||||
error = iterate_dir(file, &buffer.ctx);
|
||||
if (buffer.found) {
|
||||
error = 0;
|
||||
break;
|
||||
|
|
|
@ -263,7 +263,10 @@ nfsd4_list_rec_dir(recdir_func *f, struct nfsd_net *nn)
|
|||
{
|
||||
const struct cred *original_cred;
|
||||
struct dentry *dir = nn->rec_file->f_path.dentry;
|
||||
LIST_HEAD(names);
|
||||
struct {
|
||||
struct dir_context ctx;
|
||||
struct list_head names;
|
||||
} ctx;
|
||||
int status;
|
||||
|
||||
status = nfs4_save_creds(&original_cred);
|
||||
|
@ -276,11 +279,13 @@ nfsd4_list_rec_dir(recdir_func *f, struct nfsd_net *nn)
|
|||
return status;
|
||||
}
|
||||
|
||||
status = vfs_readdir(nn->rec_file, nfsd4_build_namelist, &names);
|
||||
INIT_LIST_HEAD(&ctx.names);
|
||||
ctx.ctx.actor = nfsd4_build_namelist;
|
||||
status = iterate_dir(nn->rec_file, &ctx.ctx);
|
||||
mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
|
||||
while (!list_empty(&names)) {
|
||||
while (!list_empty(&ctx.names)) {
|
||||
struct name_list *entry;
|
||||
entry = list_entry(names.next, struct name_list, list);
|
||||
entry = list_entry(ctx.names.next, struct name_list, list);
|
||||
if (!status) {
|
||||
struct dentry *dentry;
|
||||
dentry = lookup_one_len(entry->name, dir, HEXDIR_LEN-1);
|
||||
|
|
|
@ -1912,6 +1912,7 @@ struct buffered_dirent {
|
|||
};
|
||||
|
||||
struct readdir_data {
|
||||
struct dir_context ctx;
|
||||
char *dirent;
|
||||
size_t used;
|
||||
int full;
|
||||
|
@ -1949,6 +1950,7 @@ static __be32 nfsd_buffered_readdir(struct file *file, filldir_t func,
|
|||
int size;
|
||||
loff_t offset;
|
||||
|
||||
buf.ctx.actor = nfsd_buffered_filldir;
|
||||
buf.dirent = (void *)__get_free_page(GFP_KERNEL);
|
||||
if (!buf.dirent)
|
||||
return nfserrno(-ENOMEM);
|
||||
|
@ -1963,7 +1965,7 @@ static __be32 nfsd_buffered_readdir(struct file *file, filldir_t func,
|
|||
buf.used = 0;
|
||||
buf.full = 0;
|
||||
|
||||
host_err = vfs_readdir(file, nfsd_buffered_filldir, &buf);
|
||||
host_err = iterate_dir(file, &buf.ctx);
|
||||
if (buf.full)
|
||||
host_err = 0;
|
||||
|
||||
|
|
21
fs/readdir.c
21
fs/readdir.c
|
@ -20,7 +20,7 @@
|
|||
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
int vfs_readdir(struct file *file, filldir_t filler, void *buf)
|
||||
int iterate_dir(struct file *file, struct dir_context *ctx)
|
||||
{
|
||||
struct inode *inode = file_inode(file);
|
||||
int res = -ENOTDIR;
|
||||
|
@ -37,15 +37,14 @@ int vfs_readdir(struct file *file, filldir_t filler, void *buf)
|
|||
|
||||
res = -ENOENT;
|
||||
if (!IS_DEADDIR(inode)) {
|
||||
res = file->f_op->readdir(file, buf, filler);
|
||||
res = file->f_op->readdir(file, ctx, ctx->actor);
|
||||
file_accessed(file);
|
||||
}
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vfs_readdir);
|
||||
EXPORT_SYMBOL(iterate_dir);
|
||||
|
||||
/*
|
||||
* Traditional linux readdir() handling..
|
||||
|
@ -66,6 +65,7 @@ struct old_linux_dirent {
|
|||
};
|
||||
|
||||
struct readdir_callback {
|
||||
struct dir_context ctx;
|
||||
struct old_linux_dirent __user * dirent;
|
||||
int result;
|
||||
};
|
||||
|
@ -73,7 +73,7 @@ struct readdir_callback {
|
|||
static int fillonedir(void * __buf, const char * name, int namlen, loff_t offset,
|
||||
u64 ino, unsigned int d_type)
|
||||
{
|
||||
struct readdir_callback * buf = (struct readdir_callback *) __buf;
|
||||
struct readdir_callback *buf = (struct readdir_callback *) __buf;
|
||||
struct old_linux_dirent __user * dirent;
|
||||
unsigned long d_ino;
|
||||
|
||||
|
@ -112,10 +112,11 @@ SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
|
|||
if (!f.file)
|
||||
return -EBADF;
|
||||
|
||||
buf.ctx.actor = fillonedir;
|
||||
buf.result = 0;
|
||||
buf.dirent = dirent;
|
||||
|
||||
error = vfs_readdir(f.file, fillonedir, &buf);
|
||||
error = iterate_dir(f.file, &buf.ctx);
|
||||
if (buf.result)
|
||||
error = buf.result;
|
||||
|
||||
|
@ -137,6 +138,7 @@ struct linux_dirent {
|
|||
};
|
||||
|
||||
struct getdents_callback {
|
||||
struct dir_context ctx;
|
||||
struct linux_dirent __user * current_dir;
|
||||
struct linux_dirent __user * previous;
|
||||
int count;
|
||||
|
@ -205,8 +207,9 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd,
|
|||
buf.previous = NULL;
|
||||
buf.count = count;
|
||||
buf.error = 0;
|
||||
buf.ctx.actor = filldir;
|
||||
|
||||
error = vfs_readdir(f.file, filldir, &buf);
|
||||
error = iterate_dir(f.file, &buf.ctx);
|
||||
if (error >= 0)
|
||||
error = buf.error;
|
||||
lastdirent = buf.previous;
|
||||
|
@ -221,6 +224,7 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd,
|
|||
}
|
||||
|
||||
struct getdents_callback64 {
|
||||
struct dir_context ctx;
|
||||
struct linux_dirent64 __user * current_dir;
|
||||
struct linux_dirent64 __user * previous;
|
||||
int count;
|
||||
|
@ -285,8 +289,9 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd,
|
|||
buf.previous = NULL;
|
||||
buf.count = count;
|
||||
buf.error = 0;
|
||||
buf.ctx.actor = filldir64;
|
||||
|
||||
error = vfs_readdir(f.file, filldir64, &buf);
|
||||
error = iterate_dir(f.file, &buf.ctx);
|
||||
if (error >= 0)
|
||||
error = buf.error;
|
||||
lastdirent = buf.previous;
|
||||
|
|
|
@ -1506,6 +1506,9 @@ int fiemap_check_flags(struct fiemap_extent_info *fieinfo, u32 fs_flags);
|
|||
* to have different dirent layouts depending on the binary type.
|
||||
*/
|
||||
typedef int (*filldir_t)(void *, const char *, int, loff_t, u64, unsigned);
|
||||
struct dir_context {
|
||||
filldir_t actor;
|
||||
};
|
||||
struct block_device_operations;
|
||||
|
||||
/* These macros are for out of kernel modules to test that
|
||||
|
@ -2494,6 +2497,7 @@ loff_t inode_get_bytes(struct inode *inode);
|
|||
void inode_set_bytes(struct inode *inode, loff_t bytes);
|
||||
|
||||
extern int vfs_readdir(struct file *, filldir_t, void *);
|
||||
extern int iterate_dir(struct file *, struct dir_context *);
|
||||
|
||||
extern int vfs_stat(const char __user *, struct kstat *);
|
||||
extern int vfs_lstat(const char __user *, struct kstat *);
|
||||
|
|
Загрузка…
Ссылка в новой задаче