When we create new files in a mounted cramfs, they only appear in the dcache, so we need to have a combined dcache_readdir plus cramfs_readdir to get all of them. Signed-off-by: Arnd Bergmann --- fs/cramfs/inode.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 97 insertions(+), 3 deletions(-) diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index 0d3ac80..e7d2b47 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -324,6 +324,46 @@ static int cramfs_statfs(struct dentry *dentry, struct kstatfs *buf) return 0; } +/* Relationship between i_mode and the DT_xxx types */ +static inline unsigned char dt_type(struct inode *inode) +{ + return (inode->i_mode >> 12) & 15; +} + +static int cramfs_readdir_cache(struct file *filp, void *dirent, filldir_t filldir) +{ + struct dentry *dentry = filp->f_path.dentry; + struct dentry *cursor = filp->private_data; + struct list_head *p, *q = &cursor->d_u.d_child; + + /* taken from dcache_readdir */ + spin_lock(&dcache_lock); + if (filp->f_pos == 2) + list_move(q, &dentry->d_subdirs); + + for (p=q->next; p != &dentry->d_subdirs; p=p->next) { + struct dentry *next; + next = list_entry(p, struct dentry, d_u.d_child); + if (d_unhashed(next) || !next->d_inode || + next->d_inode->i_private) // FIXME: renames are broken + continue; + + spin_unlock(&dcache_lock); + if (filldir(dirent, next->d_name.name, + next->d_name.len, filp->f_pos, + next->d_inode->i_ino, + dt_type(next->d_inode)) < 0) + return 0; + spin_lock(&dcache_lock); + /* next is still alive */ + list_move(q, p); + p = q; + filp->f_pos++; + } + spin_unlock(&dcache_lock); + return 0; +} + /* * Read a cramfs directory entry. */ @@ -407,8 +447,59 @@ static int cramfs_readdir_ondisk(struct dentry *dentry, void *dirent, static int cramfs_readdir(struct file *filp, void *dirent, filldir_t filldir) { - return cramfs_readdir_ondisk(filp->f_dentry, dirent, + loff_t offset = filp->f_pos; + struct dentry *dentry = filp->f_path.dentry; + int ret; + + ret = 0; + if (offset < dentry->d_inode->i_size) + ret = cramfs_readdir_ondisk(dentry, dirent, filldir, &filp->f_pos); + if (ret) + return ret; + + return cramfs_readdir_cache(filp, dirent, filldir); +} + +static loff_t cramfs_dir_lseek(struct file *file, loff_t offset, int origin) +{ + struct inode *inode = file->f_path.dentry->d_inode; + mutex_lock(&inode->i_mutex); + switch (origin) { + case 1: + offset += file->f_pos; + case 0: + if (offset >= 0) + break; + default: + mutex_unlock(&inode->i_mutex); + return -EINVAL; + } + + if (offset != file->f_pos) { + file->f_pos = offset; + if (file->f_pos >= inode->i_size) { + struct list_head *p; + struct dentry *cursor = file->private_data; + loff_t n = file->f_pos - inode->i_size; + + spin_lock(&dcache_lock); + list_del(&cursor->d_u.d_child); + p = file->f_path.dentry->d_subdirs.next; + while (n && p != &file->f_path.dentry->d_subdirs) { + struct dentry *next; + next = list_entry(p, struct dentry, d_u.d_child); + if (!d_unhashed(next) && next->d_inode && + !next->d_inode->i_private) // FIXME: renames are broken) + n--; + p = p->next; + } + list_add_tail(&cursor->d_u.d_child, p); + spin_unlock(&dcache_lock); + } + } + mutex_unlock(&inode->i_mutex); + return offset; } int cramfs_unlink(struct inode *dir, struct dentry *dentry) @@ -588,9 +679,12 @@ static const struct address_space_operations cramfs_aops = { * A directory can only readdir */ static const struct file_operations cramfs_directory_operations = { - .llseek = generic_file_llseek, - .read = generic_read_dir, + .open = dcache_dir_open, + .release = dcache_dir_close, + .llseek = cramfs_dir_lseek, + .fsync = simple_sync_file, .readdir = cramfs_readdir, + .read = generic_read_dir, }; static const struct inode_operations cramfs_dir_inode_operations = { -- 1.5.4.3 -- -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/