[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:
Al Viro 2013-05-15 13:52:59 -04:00
Родитель 83a8761142
Коммит 5c0ba4e076
10 изменённых файлов: 53 добавлений и 20 удалений

Просмотреть файл

@ -445,3 +445,6 @@ object doesn't exist. It's remote/distributed ones that might care...
[mandatory] [mandatory]
FS_REVAL_DOT is gone; if you used to have it, add ->d_weak_revalidate() FS_REVAL_DOT is gone; if you used to have it, add ->d_weak_revalidate()
in your dentry operations instead. 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 osf_dirent_callback {
struct dir_context ctx;
struct osf_dirent __user *dirent; struct osf_dirent __user *dirent;
long __user *basep; long __user *basep;
unsigned int count; unsigned int count;
@ -155,8 +156,9 @@ SYSCALL_DEFINE4(osf_getdirentries, unsigned int, fd,
buf.basep = basep; buf.basep = basep;
buf.count = count; buf.count = count;
buf.error = 0; 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) if (error >= 0)
error = buf.error; error = buf.error;
if (count != buf.count) if (count != buf.count)

Просмотреть файл

@ -60,6 +60,7 @@ struct hpux_dirent {
}; };
struct getdents_callback { struct getdents_callback {
struct dir_context ctx;
struct hpux_dirent __user *current_dir; struct hpux_dirent __user *current_dir;
struct hpux_dirent __user *previous; struct hpux_dirent __user *previous;
int count; int count;
@ -121,8 +122,9 @@ int hpux_getdents(unsigned int fd, struct hpux_dirent __user *dirent, unsigned i
buf.previous = NULL; buf.previous = NULL;
buf.count = count; buf.count = count;
buf.error = 0; buf.error = 0;
buf.ctx.actor = filldir;
error = vfs_readdir(arg.file, filldir, &buf); error = iterate_dir(arg.file, &buf.ctx);
if (error >= 0) if (error >= 0)
error = buf.error; error = buf.error;
lastdirent = buf.previous; lastdirent = buf.previous;

Просмотреть файл

@ -832,6 +832,7 @@ struct compat_old_linux_dirent {
}; };
struct compat_readdir_callback { struct compat_readdir_callback {
struct dir_context ctx;
struct compat_old_linux_dirent __user *dirent; struct compat_old_linux_dirent __user *dirent;
int result; int result;
}; };
@ -880,8 +881,9 @@ asmlinkage long compat_sys_old_readdir(unsigned int fd,
buf.result = 0; buf.result = 0;
buf.dirent = dirent; 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) if (buf.result)
error = buf.result; error = buf.result;
@ -897,6 +899,7 @@ struct compat_linux_dirent {
}; };
struct compat_getdents_callback { struct compat_getdents_callback {
struct dir_context ctx;
struct compat_linux_dirent __user *current_dir; struct compat_linux_dirent __user *current_dir;
struct compat_linux_dirent __user *previous; struct compat_linux_dirent __user *previous;
int count; int count;
@ -965,8 +968,9 @@ asmlinkage long compat_sys_getdents(unsigned int fd,
buf.previous = NULL; buf.previous = NULL;
buf.count = count; buf.count = count;
buf.error = 0; 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) if (error >= 0)
error = buf.error; error = buf.error;
lastdirent = buf.previous; lastdirent = buf.previous;
@ -983,6 +987,7 @@ asmlinkage long compat_sys_getdents(unsigned int fd,
#ifndef __ARCH_OMIT_COMPAT_SYS_GETDENTS64 #ifndef __ARCH_OMIT_COMPAT_SYS_GETDENTS64
struct compat_getdents_callback64 { struct compat_getdents_callback64 {
struct dir_context ctx;
struct linux_dirent64 __user *current_dir; struct linux_dirent64 __user *current_dir;
struct linux_dirent64 __user *previous; struct linux_dirent64 __user *previous;
int count; int count;
@ -1050,8 +1055,9 @@ asmlinkage long compat_sys_getdents64(unsigned int fd,
buf.previous = NULL; buf.previous = NULL;
buf.count = count; buf.count = count;
buf.error = 0; 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) if (error >= 0)
error = buf.error; error = buf.error;
lastdirent = buf.previous; lastdirent = buf.previous;

Просмотреть файл

@ -68,6 +68,7 @@ static ssize_t ecryptfs_read_update_atime(struct kiocb *iocb,
} }
struct ecryptfs_getdents_callback { struct ecryptfs_getdents_callback {
struct dir_context ctx;
void *dirent; void *dirent;
struct dentry *dentry; struct dentry *dentry;
filldir_t filldir; filldir_t filldir;
@ -126,7 +127,8 @@ static int ecryptfs_readdir(struct file *file, void *dirent, filldir_t filldir)
buf.filldir = filldir; buf.filldir = filldir;
buf.filldir_called = 0; buf.filldir_called = 0;
buf.entries_written = 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; file->f_pos = lower_file->f_pos;
if (rc < 0) if (rc < 0)
goto out; goto out;

Просмотреть файл

@ -212,6 +212,7 @@ reconnect_path(struct vfsmount *mnt, struct dentry *target_dir, char *nbuf)
} }
struct getdents_callback { struct getdents_callback {
struct dir_context ctx;
char *name; /* name that was found. It already points to a char *name; /* name that was found. It already points to a
buffer NAME_MAX+1 is size */ buffer NAME_MAX+1 is size */
unsigned long ino; /* the inum we are looking for */ 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.ino = child->d_inode->i_ino;
buffer.found = 0; buffer.found = 0;
buffer.sequence = 0; buffer.sequence = 0;
buffer.ctx.actor = filldir_one;
while (1) { while (1) {
int old_seq = buffer.sequence; int old_seq = buffer.sequence;
error = vfs_readdir(file, filldir_one, &buffer); error = iterate_dir(file, &buffer.ctx);
if (buffer.found) { if (buffer.found) {
error = 0; error = 0;
break; break;

Просмотреть файл

@ -263,7 +263,10 @@ nfsd4_list_rec_dir(recdir_func *f, struct nfsd_net *nn)
{ {
const struct cred *original_cred; const struct cred *original_cred;
struct dentry *dir = nn->rec_file->f_path.dentry; struct dentry *dir = nn->rec_file->f_path.dentry;
LIST_HEAD(names); struct {
struct dir_context ctx;
struct list_head names;
} ctx;
int status; int status;
status = nfs4_save_creds(&original_cred); status = nfs4_save_creds(&original_cred);
@ -276,11 +279,13 @@ nfsd4_list_rec_dir(recdir_func *f, struct nfsd_net *nn)
return status; 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); mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
while (!list_empty(&names)) { while (!list_empty(&ctx.names)) {
struct name_list *entry; 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) { if (!status) {
struct dentry *dentry; struct dentry *dentry;
dentry = lookup_one_len(entry->name, dir, HEXDIR_LEN-1); dentry = lookup_one_len(entry->name, dir, HEXDIR_LEN-1);

Просмотреть файл

@ -1912,6 +1912,7 @@ struct buffered_dirent {
}; };
struct readdir_data { struct readdir_data {
struct dir_context ctx;
char *dirent; char *dirent;
size_t used; size_t used;
int full; int full;
@ -1949,6 +1950,7 @@ static __be32 nfsd_buffered_readdir(struct file *file, filldir_t func,
int size; int size;
loff_t offset; loff_t offset;
buf.ctx.actor = nfsd_buffered_filldir;
buf.dirent = (void *)__get_free_page(GFP_KERNEL); buf.dirent = (void *)__get_free_page(GFP_KERNEL);
if (!buf.dirent) if (!buf.dirent)
return nfserrno(-ENOMEM); return nfserrno(-ENOMEM);
@ -1963,7 +1965,7 @@ static __be32 nfsd_buffered_readdir(struct file *file, filldir_t func,
buf.used = 0; buf.used = 0;
buf.full = 0; buf.full = 0;
host_err = vfs_readdir(file, nfsd_buffered_filldir, &buf); host_err = iterate_dir(file, &buf.ctx);
if (buf.full) if (buf.full)
host_err = 0; host_err = 0;

Просмотреть файл

@ -20,7 +20,7 @@
#include <asm/uaccess.h> #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); struct inode *inode = file_inode(file);
int res = -ENOTDIR; int res = -ENOTDIR;
@ -37,15 +37,14 @@ int vfs_readdir(struct file *file, filldir_t filler, void *buf)
res = -ENOENT; res = -ENOENT;
if (!IS_DEADDIR(inode)) { if (!IS_DEADDIR(inode)) {
res = file->f_op->readdir(file, buf, filler); res = file->f_op->readdir(file, ctx, ctx->actor);
file_accessed(file); file_accessed(file);
} }
mutex_unlock(&inode->i_mutex); mutex_unlock(&inode->i_mutex);
out: out:
return res; return res;
} }
EXPORT_SYMBOL(iterate_dir);
EXPORT_SYMBOL(vfs_readdir);
/* /*
* Traditional linux readdir() handling.. * Traditional linux readdir() handling..
@ -66,6 +65,7 @@ struct old_linux_dirent {
}; };
struct readdir_callback { struct readdir_callback {
struct dir_context ctx;
struct old_linux_dirent __user * dirent; struct old_linux_dirent __user * dirent;
int result; int result;
}; };
@ -73,7 +73,7 @@ struct readdir_callback {
static int fillonedir(void * __buf, const char * name, int namlen, loff_t offset, static int fillonedir(void * __buf, const char * name, int namlen, loff_t offset,
u64 ino, unsigned int d_type) 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; struct old_linux_dirent __user * dirent;
unsigned long d_ino; unsigned long d_ino;
@ -112,10 +112,11 @@ SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
if (!f.file) if (!f.file)
return -EBADF; return -EBADF;
buf.ctx.actor = fillonedir;
buf.result = 0; buf.result = 0;
buf.dirent = dirent; buf.dirent = dirent;
error = vfs_readdir(f.file, fillonedir, &buf); error = iterate_dir(f.file, &buf.ctx);
if (buf.result) if (buf.result)
error = buf.result; error = buf.result;
@ -137,6 +138,7 @@ struct linux_dirent {
}; };
struct getdents_callback { struct getdents_callback {
struct dir_context ctx;
struct linux_dirent __user * current_dir; struct linux_dirent __user * current_dir;
struct linux_dirent __user * previous; struct linux_dirent __user * previous;
int count; int count;
@ -205,8 +207,9 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd,
buf.previous = NULL; buf.previous = NULL;
buf.count = count; buf.count = count;
buf.error = 0; buf.error = 0;
buf.ctx.actor = filldir;
error = vfs_readdir(f.file, filldir, &buf); error = iterate_dir(f.file, &buf.ctx);
if (error >= 0) if (error >= 0)
error = buf.error; error = buf.error;
lastdirent = buf.previous; lastdirent = buf.previous;
@ -221,6 +224,7 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd,
} }
struct getdents_callback64 { struct getdents_callback64 {
struct dir_context ctx;
struct linux_dirent64 __user * current_dir; struct linux_dirent64 __user * current_dir;
struct linux_dirent64 __user * previous; struct linux_dirent64 __user * previous;
int count; int count;
@ -285,8 +289,9 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd,
buf.previous = NULL; buf.previous = NULL;
buf.count = count; buf.count = count;
buf.error = 0; buf.error = 0;
buf.ctx.actor = filldir64;
error = vfs_readdir(f.file, filldir64, &buf); error = iterate_dir(f.file, &buf.ctx);
if (error >= 0) if (error >= 0)
error = buf.error; error = buf.error;
lastdirent = buf.previous; 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. * to have different dirent layouts depending on the binary type.
*/ */
typedef int (*filldir_t)(void *, const char *, int, loff_t, u64, unsigned); typedef int (*filldir_t)(void *, const char *, int, loff_t, u64, unsigned);
struct dir_context {
filldir_t actor;
};
struct block_device_operations; struct block_device_operations;
/* These macros are for out of kernel modules to test that /* 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); void inode_set_bytes(struct inode *inode, loff_t bytes);
extern int vfs_readdir(struct file *, filldir_t, void *); 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_stat(const char __user *, struct kstat *);
extern int vfs_lstat(const char __user *, struct kstat *); extern int vfs_lstat(const char __user *, struct kstat *);