[RFC 6/7] cramfs: read directory entries from dcache

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]
  Powered by Linux