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-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html