[RFC PATCH 1/5] Remove existing directory listing implementation

From: Bharata B Rao
Date: Wed Dec 05 2007 - 09:39:04 EST


Remove the existing readdir implementation.

Signed-off-by: Bharata B Rao <bharata@xxxxxxxxxxxxxxxxxx>
---
fs/readdir.c | 10 +
fs/union.c | 333 --------------------------------------------------
include/linux/union.h | 23 ---
3 files changed, 8 insertions(+), 358 deletions(-)

--- a/fs/readdir.c
+++ b/fs/readdir.c
@@ -16,12 +16,12 @@
#include <linux/security.h>
#include <linux/syscalls.h>
#include <linux/unistd.h>
-#include <linux/union.h>

#include <asm/uaccess.h>

int vfs_readdir(struct file *file, filldir_t filler, void *buf)
{
+ struct inode *inode = file->f_path.dentry->d_inode;
int res = -ENOTDIR;

if (!file->f_op || !file->f_op->readdir)
@@ -31,7 +31,13 @@ int vfs_readdir(struct file *file, filld
if (res)
goto out;

- res = do_readdir(file, buf, filler);
+ mutex_lock(&inode->i_mutex);
+ res = -ENOENT;
+ if (!IS_DEADDIR(inode)) {
+ res = file->f_op->readdir(file, buf, filler);
+ file_accessed(file);
+ }
+ mutex_unlock(&inode->i_mutex);
out:
return res;
}
--- a/fs/union.c
+++ b/fs/union.c
@@ -516,339 +516,6 @@ int last_union_is_root(struct path *path
}

/*
- * Union mounts support for readdir.
- */
-
-/* This is a copy from fs/readdir.c */
-struct getdents_callback {
- struct linux_dirent __user *current_dir;
- struct linux_dirent __user *previous;
- int count;
- int error;
-};
-
-/* The readdir union cache object */
-struct union_cache_entry {
- struct list_head list;
- struct qstr name;
-};
-
-static int union_cache_add_entry(struct list_head *list,
- const char *name, int namelen)
-{
- struct union_cache_entry *this;
- char *tmp_name;
-
- this = kmalloc(sizeof(*this), GFP_KERNEL);
- if (!this) {
- printk(KERN_CRIT
- "union_cache_add_entry(): out of kernel memory\n");
- return -ENOMEM;
- }
-
- tmp_name = kmalloc(namelen + 1, GFP_KERNEL);
- if (!tmp_name) {
- printk(KERN_CRIT
- "union_cache_add_entry(): out of kernel memory\n");
- kfree(this);
- return -ENOMEM;
- }
-
- this->name.name = tmp_name;
- this->name.len = namelen;
- this->name.hash = 0;
- memcpy(tmp_name, name, namelen);
- tmp_name[namelen] = 0;
- INIT_LIST_HEAD(&this->list);
- list_add(&this->list, list);
- return 0;
-}
-
-static void union_cache_free(struct list_head *uc_list)
-{
- struct list_head *p;
- struct list_head *ptmp;
- int count = 0;
-
- list_for_each_safe(p, ptmp, uc_list) {
- struct union_cache_entry *this;
-
- this = list_entry(p, struct union_cache_entry, list);
- list_del_init(&this->list);
- kfree(this->name.name);
- kfree(this);
- count++;
- }
- return;
-}
-
-static int union_cache_find_entry(struct list_head *uc_list,
- const char *name, int namelen)
-{
- struct union_cache_entry *p;
- int ret = 0;
-
- list_for_each_entry(p, uc_list, list) {
- if (p->name.len != namelen)
- continue;
- if (strncmp(p->name.name, name, namelen) == 0) {
- ret = 1;
- break;
- }
- }
-
- return ret;
-}
-
-/*
- * There are four filldir() wrapper necessary for the union mount readdir
- * implementation:
- *
- * - filldir_topmost(): fills the union's readdir cache and the user space
- * buffer. This is only used for the topmost directory
- * in the union stack.
- * - filldir_topmost_cacheonly(): only fills the union's readdir cache.
- * This is only used for the topmost directory in the
- * union stack.
- * - filldir_overlaid(): fills the union's readdir cache and the user space
- * buffer. This is only used for directories on the
- * stack's lower layers.
- * - filldir_overlaid_cacheonly(): only fills the union's readdir cache.
- * This is only used for directories on the stack's
- * lower layers.
- */
-
-struct union_cache_callback {
- struct getdents_callback *buf; /* original getdents_callback */
- struct list_head list; /* list of union cache entries */
- filldir_t filler; /* the filldir() we should call */
- loff_t offset; /* base offset of our dirents */
- loff_t count; /* maximum number of bytes to "read" */
-};
-
-static int filldir_topmost(void *buf, const char *name, int namlen,
- loff_t offset, u64 ino, unsigned int d_type)
-{
- struct union_cache_callback *cb = buf;
-
- union_cache_add_entry(&cb->list, name, namlen);
- return cb->filler(cb->buf, name, namlen, cb->offset + offset, ino,
- d_type);
-}
-
-static int filldir_topmost_cacheonly(void *buf, const char *name, int namlen,
- loff_t offset, u64 ino,
- unsigned int d_type)
-{
- struct union_cache_callback *cb = buf;
-
- if (offset > cb->count)
- return -EINVAL;
-
- union_cache_add_entry(&cb->list, name, namlen);
- return 0;
-}
-
-static int filldir_overlaid(void *buf, const char *name, int namlen,
- loff_t offset, u64 ino, unsigned int d_type)
-{
- struct union_cache_callback *cb = buf;
-
- switch (namlen) {
- case 2:
- if (name[1] != '.')
- break;
- case 1:
- if (name[0] != '.')
- break;
- return 0;
- }
-
- if (union_cache_find_entry(&cb->list, name, namlen))
- return 0;
-
- union_cache_add_entry(&cb->list, name, namlen);
- return cb->filler(cb->buf, name, namlen, cb->offset + offset, ino,
- d_type);
-}
-
-static int filldir_overlaid_cacheonly(void *buf, const char *name, int namlen,
- loff_t offset, u64 ino,
- unsigned int d_type)
-{
- struct union_cache_callback *cb = buf;
-
- if (offset > cb->count)
- return -EINVAL;
-
- switch (namlen) {
- case 2:
- if (name[1] != '.')
- break;
- case 1:
- if (name[0] != '.')
- break;
- return 0;
- }
-
- if (union_cache_find_entry(&cb->list, name, namlen))
- return 0;
-
- union_cache_add_entry(&cb->list, name, namlen);
- return 0;
-}
-
-/*
- * readdir_union_cache - A helper to fill the readdir cache
- */
-static int readdir_union_cache(struct file *file, void *_buf, filldir_t filler)
-{
- struct union_cache_callback *cb = _buf;
- int old_count;
- loff_t old_pos;
- int res;
-
- old_count = cb->count;
- cb->count = ((file->f_pos > i_size_read(file->f_path.dentry->d_inode)) ?
- i_size_read(file->f_path.dentry->d_inode) :
- file->f_pos) & INT_MAX;
- old_pos = file->f_pos;
- file->f_pos = 0;
- res = file->f_op->readdir(file, _buf, filler);
- file->f_pos = old_pos;
- cb->count = old_count;
- return res;
-}
-
-/*
- * readdir_union - A wrapper around ->readdir()
- *
- * This is a wrapper around the filesystems readdir(), which is walking
- * the union stack and calls ->readdir() for every directory in the stack.
- * The directory entries are read into the union mounts readdir cache to
- * support whiteout's and duplicate removal.
- */
-int readdir_union(struct file *file, void *buf, filldir_t filler)
-{
- struct inode *inode = file->f_path.dentry->d_inode;
- struct union_cache_callback cb;
- struct path path;
- loff_t offset = 0;
- int res = 0;
-
- mutex_lock(&inode->i_mutex);
- if (IS_DEADDIR(inode)) {
- mutex_unlock(&inode->i_mutex);
- return -ENOENT;
- }
-
- INIT_LIST_HEAD(&cb.list);
- cb.buf = buf;
- cb.filler = filler;
- cb.offset = 0;
- offset = i_size_read(file->f_path.dentry->d_inode);
- cb.count = file->f_pos;
-
- if (file->f_pos > 0) {
- /*
- * We have already read from this dir, lets read that stuff to
- * our union-cache only
- */
- res = readdir_union_cache(file, &cb,
- filldir_topmost_cacheonly);
- if (res) {
- mutex_unlock(&inode->i_mutex);
- goto out;
- }
- }
-
- if (file->f_pos < offset) {
- res = file->f_op->readdir(file, &cb, filldir_topmost);
- file_accessed(file);
- if (res) {
- mutex_unlock(&inode->i_mutex);
- goto out;
- }
- /* We read until EOF of this directory */
- file->f_pos = offset;
- }
-
- mutex_unlock(&inode->i_mutex);
-
- path = file->f_path;
- path_get(&path);
- while (follow_union_down(&path.mnt, &path.dentry)) {
- struct file *ftmp;
-
- /* get path reference for filep */
- path_get(&path);
- ftmp = dentry_open(path.dentry, path.mnt,
- ((file->f_flags & ~(O_ACCMODE)) |
- O_RDONLY | O_DIRECTORY | O_NOATIME));
- if (IS_ERR(ftmp)) {
- res = PTR_ERR(ftmp);
- break;
- }
-
- inode = path.dentry->d_inode;
- mutex_lock(&inode->i_mutex);
-
- /* rearrange the file position */
- cb.offset += offset;
- offset = i_size_read(inode);
- ftmp->f_pos = file->f_pos - cb.offset;
- cb.count = ftmp->f_pos;
- if (ftmp->f_pos < 0) {
- mutex_unlock(&inode->i_mutex);
- fput(ftmp);
- break;
- }
-
- res = -ENOENT;
- if (IS_DEADDIR(inode))
- goto out_fput;
-
- if (ftmp->f_pos > 0) {
- /*
- * We have already read from this dir, lets read that
- * stuff to our union-cache only
- */
- res = readdir_union_cache(ftmp, &cb,
- filldir_overlaid_cacheonly);
- if (res)
- goto out_fput;
- }
-
- if (ftmp->f_pos < offset) {
- res = ftmp->f_op->readdir(ftmp, &cb, filldir_overlaid);
- file_accessed(ftmp);
- if (res)
- file->f_pos += ftmp->f_pos;
- else
- /*
- * We read until EOF of this directory, so lets
- * advance the f_pos by the maximum offset
- * (i_size) of this directory
- */
- file->f_pos += offset;
- }
-
- file_accessed(ftmp);
-
-out_fput:
- mutex_unlock(&inode->i_mutex);
- fput(ftmp);
-
- if (res)
- break;
- }
- path_put(&path);
-out:
- union_cache_free(&cb.list);
- return res;
-}
-
-/*
* Union mount copyup support
*/

--- a/include/linux/union.h
+++ b/include/linux/union.h
@@ -54,7 +54,6 @@ extern int attach_mnt_union(struct vfsmo
struct dentry *);
extern void detach_mnt_union(struct vfsmount *);
extern int last_union_is_root(struct path *);
-extern int readdir_union(struct file *, void *, filldir_t);
extern int is_dir_unioned(struct path *);
extern int union_relookup_topmost(struct nameidata *, int);
extern struct dentry *union_create_topmost(struct nameidata *, struct qstr *,
@@ -83,27 +82,5 @@ extern int union_copyup(struct nameidata

#endif /* CONFIG_UNION_MOUNT */

-static inline int do_readdir(struct file *file, void *buf, filldir_t filler)
-{
- int res = 0;
- struct inode *inode = file->f_path.dentry->d_inode;
-
-#ifdef CONFIG_UNION_MOUNT
- if (IS_MNT_UNION(file->f_path.mnt) && is_dir_unioned(&file->f_path))
- res = readdir_union(file, buf, filler);
- else
-#endif
- {
- mutex_lock(&inode->i_mutex);
- res = -ENOENT;
- if (!IS_DEADDIR(inode)) {
- res = file->f_op->readdir(file, buf, filler);
- file_accessed(file);
- }
- mutex_unlock(&inode->i_mutex);
- }
- return res;
-}
-
#endif /* __KERNEL__ */
#endif /* __LINUX_UNION_H */
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/