Skip to content

Commit

Permalink
[readdir] introduce iterate_dir() and dir_context
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
Al Viro committed Jun 29, 2013
1 parent 83a8761 commit 5c0ba4e
Show file tree
Hide file tree
Showing 10 changed files with 53 additions and 20 deletions.
3 changes: 3 additions & 0 deletions Documentation/filesystems/porting
Original file line number Diff line number Diff line change
Expand Up @@ -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
4 changes: 3 additions & 1 deletion arch/alpha/kernel/osf_sys.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down
4 changes: 3 additions & 1 deletion arch/parisc/hpux/fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
12 changes: 9 additions & 3 deletions fs/compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand Down Expand Up @@ -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;

Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
4 changes: 3 additions & 1 deletion fs/ecryptfs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
4 changes: 3 additions & 1 deletion fs/exportfs/expfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
Expand Down
13 changes: 9 additions & 4 deletions fs/nfsd/nfs4recover.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down
4 changes: 3 additions & 1 deletion fs/nfsd/vfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1912,6 +1912,7 @@ struct buffered_dirent {
};

struct readdir_data {
struct dir_context ctx;
char *dirent;
size_t used;
int full;
Expand Down Expand Up @@ -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);
Expand All @@ -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;

Expand Down
21 changes: 13 additions & 8 deletions fs/readdir.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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..
Expand All @@ -66,14 +65,15 @@ struct old_linux_dirent {
};

struct readdir_callback {
struct dir_context ctx;
struct old_linux_dirent __user * dirent;
int result;
};

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;

Expand Down Expand Up @@ -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;

Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions include/linux/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 *);
Expand Down

0 comments on commit 5c0ba4e

Please sign in to comment.