[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]
|
[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;
|
||||||
|
|
12
fs/compat.c
12
fs/compat.c
|
@ -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;
|
||||||
|
|
||||||
|
|
21
fs/readdir.c
21
fs/readdir.c
|
@ -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 *);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче