Re: [PATCH 34/41] fallthru: tmpfs fallthru support

From: Erez Zadok
Date: Mon Nov 30 2009 - 23:18:20 EST


In message <1256152779-10054-35-git-send-email-vaurora@xxxxxxxxxx>, Valerie Aurora writes:
> Add support for fallthru directory entries to tmpfs

Need to CC tmpfs maintainers here.

> XXX - Makes up inode number for dirent
>
> Signed-off-by: Valerie Aurora <vaurora@xxxxxxxxxx>
> ---
> fs/dcache.c | 3 +-
> fs/libfs.c | 21 +++++++++++++++++--
> mm/shmem.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++------
> 3 files changed, 73 insertions(+), 11 deletions(-)
>
> diff --git a/fs/dcache.c b/fs/dcache.c
> index ca8a661..8ef2d89 100644
> --- a/fs/dcache.c
> +++ b/fs/dcache.c
> @@ -2292,7 +2292,8 @@ resume:
> struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child);
> next = tmp->next;
> if (d_unhashed(dentry)||(!dentry->d_inode &&
> - !d_is_whiteout(dentry)))
> + !d_is_whiteout(dentry) &&
> + !d_is_fallthru(dentry)))
> continue;
> if (!list_empty(&dentry->d_subdirs)) {
> this_parent = dentry;
> diff --git a/fs/libfs.c b/fs/libfs.c
> index dcec3d3..01f3e73 100644
> --- a/fs/libfs.c
> +++ b/fs/libfs.c
> @@ -133,6 +133,7 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir)
> struct dentry *cursor = filp->private_data;
> struct list_head *p, *q = &cursor->d_u.d_child;
> ino_t ino;
> + int d_type;
> int i = filp->f_pos;
>
> switch (i) {
> @@ -158,14 +159,28 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir)
> 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)
> + if (d_unhashed(next) || (!next->d_inode && !d_is_fallthru(next)))
> continue;
>
> + if (d_is_fallthru(next)) {
> + /* XXX We don't know the inode
> + * number of the directory
> + * entry in the underlying
> + * file system. Should look
> + * it up, either on fallthru
> + * creation at first readdir
> + * or now at filldir time. */
> + ino = 123; /* Made up ino */

Ok, so here it's 123, as in ext2, but not jffs2, who had it set to 100...

> + d_type = DT_UNKNOWN;
> + } else {
> + ino = next->d_inode->i_ino;
> + d_type = dt_type(next->d_inode);
> + }
> +
> 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)
> + ino, d_type) < 0)
> return 0;
> spin_lock(&dcache_lock);
> /* next is still alive */
> diff --git a/mm/shmem.c b/mm/shmem.c
> index 2faa14b..4f4b4b6 100644
> --- a/mm/shmem.c
> +++ b/mm/shmem.c
> @@ -1798,8 +1798,7 @@ static int shmem_rmdir(struct inode *dir, struct dentry *dentry);
> static int shmem_unlink(struct inode *dir, struct dentry *dentry);
>
> /*
> - * This is the whiteout support for tmpfs. It uses one singleton whiteout
> - * inode per superblock thus it is very similar to shmem_link().
> + * Create a dentry to signify a whiteout.
> */
> static int shmem_whiteout(struct inode *dir, struct dentry *old_dentry,
> struct dentry *new_dentry)
> @@ -1830,8 +1829,10 @@ static int shmem_whiteout(struct inode *dir, struct dentry *old_dentry,
> spin_unlock(&sbinfo->stat_lock);
> }
>
> - if (old_dentry->d_inode) {
> - if (S_ISDIR(old_dentry->d_inode->i_mode))
> + if (old_dentry->d_inode || d_is_fallthru(old_dentry)) {
> + /* A fallthru for a dir is treated like a regular link */
> + if (old_dentry->d_inode &&
> + S_ISDIR(old_dentry->d_inode->i_mode))
> shmem_rmdir(dir, old_dentry);
> else
> shmem_unlink(dir, old_dentry);
> @@ -1848,6 +1849,48 @@ static int shmem_whiteout(struct inode *dir, struct dentry *old_dentry,
> }
>
> static void shmem_d_instantiate(struct inode *dir, struct dentry *dentry,
> + struct inode *inode);
> +
> +/*
> + * Create a dentry to signify a fallthru. A fallthru in tmpfs is the
> + * logical equivalent of an in-kernel readdir() cache. It can't be
> + * deleted until the file system is unmounted.
> + */
> +static int shmem_fallthru(struct inode *dir, struct dentry *dentry)
> +{
> + struct shmem_sb_info *sbinfo = SHMEM_SB(dir->i_sb);
> +
> + /* FIXME: this is stupid */
> + if (!(dir->i_sb->s_flags & MS_WHITEOUT))
> + return -EPERM;
> +
> + if (dentry->d_inode || d_is_fallthru(dentry) || d_is_whiteout(dentry))
> + return -EEXIST;
> +
> + /*
> + * Each new link needs a new dentry, pinning lowmem, and tmpfs
> + * dentries cannot be pruned until they are unlinked.
> + */
> + if (sbinfo->max_inodes) {
> + spin_lock(&sbinfo->stat_lock);
> + if (!sbinfo->free_inodes) {
> + spin_unlock(&sbinfo->stat_lock);
> + return -ENOSPC;
> + }
> + sbinfo->free_inodes--;
> + spin_unlock(&sbinfo->stat_lock);
> + }
> +
> + shmem_d_instantiate(dir, dentry, NULL);
> + dir->i_ctime = dir->i_mtime = CURRENT_TIME;
> +
> + spin_lock(&dentry->d_lock);
> + dentry->d_flags |= DCACHE_FALLTHRU;
> + spin_unlock(&dentry->d_lock);
> + return 0;
> +}
> +
> +static void shmem_d_instantiate(struct inode *dir, struct dentry *dentry,
> struct inode *inode)
> {
> if (d_is_whiteout(dentry)) {
> @@ -1855,14 +1898,15 @@ static void shmem_d_instantiate(struct inode *dir, struct dentry *dentry,
> shmem_free_inode(dir->i_sb);
> if (S_ISDIR(inode->i_mode))
> inode->i_mode |= S_OPAQUE;
> + } else if (d_is_fallthru(dentry)) {
> + shmem_free_inode(dir->i_sb);
> } else {
> /* New dentry */
> dir->i_size += BOGO_DIRENT_SIZE;
> dget(dentry); /* Extra count - pin the dentry in core */
> }
> - /* Will clear DCACHE_WHITEOUT flag */
> + /* Will clear DCACHE_WHITEOUT and DCACHE_FALLTHRU flags */
> d_instantiate(dentry, inode);
> -
> }
> /*
> * File creation. Allocate an inode, and we're done..
> @@ -1947,7 +1991,8 @@ static int shmem_unlink(struct inode *dir, struct dentry *dentry)
> {
> struct inode *inode = dentry->d_inode;
>
> - if (d_is_whiteout(dentry) || (inode->i_nlink > 1 && !S_ISDIR(inode->i_mode)))
> + if (d_is_whiteout(dentry) || d_is_fallthru(dentry) ||
> + (inode->i_nlink > 1 && !S_ISDIR(inode->i_mode)))
> shmem_free_inode(dir->i_sb);

I'd reorder this || condition above so the more common sub-conditions to be
true, show up first (inode->i_nlink > 1 && !S_ISDIR(inode->i_mode).
d_is_whatever should go last.

>
> if (inode) {
> @@ -2583,6 +2628,7 @@ static const struct inode_operations shmem_dir_inode_operations = {
> .mknod = shmem_mknod,
> .rename = shmem_rename,
> .whiteout = shmem_whiteout,
> + .fallthru = shmem_fallthru,
> #endif
> #ifdef CONFIG_TMPFS_POSIX_ACL
> .setattr = shmem_notify_change,
> --
> 1.6.3.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

Erez.
--
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/