Re: [RFC] shmem: Add eventfd notification on utlilization level

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

 



Any updates?

Thank you,
Kyungmin Park

On Wed, Feb 11, 2015 at 11:50 PM, Krzysztof Kozlowski
<k.kozlowski@xxxxxxxxxxx> wrote:
> Allow notifying user space when used space of tmpfs exceeds specified
> level.
>
> The utilization level is passed as mount option 'warn_used'. The kernel
> will notify user-space through eventfd after exceeding this number of
> used blocks.
>
> The eventfd descriptor has to be passed through sysfs file:
> /sys/fs/tmpfs/tmpfs-[0-9]+/warn_used_blocks_efd
>
> Signed-off-by: Krzysztof Kozlowski <k.kozlowski@xxxxxxxxxxx>
> ---
>  include/linux/shmem_fs.h |   4 ++
>  mm/shmem.c               | 138 ++++++++++++++++++++++++++++++++++++++++++++++-
>  2 files changed, 140 insertions(+), 2 deletions(-)
>
> diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
> index 50777b5b1e4c..c2ec9909da95 100644
> --- a/include/linux/shmem_fs.h
> +++ b/include/linux/shmem_fs.h
> @@ -35,6 +35,10 @@ struct shmem_sb_info {
>         kgid_t gid;                 /* Mount gid for root directory */
>         umode_t mode;               /* Mount mode for root directory */
>         struct mempolicy *mpol;     /* default memory policy for mappings */
> +       unsigned long warn_used;    /* Warn on reaching used blocks */
> +       struct kobject s_kobj;      /* kobj for sysfs attributes */
> +       struct completion s_kobj_unregister; /* synchronization for put_super */
> +       struct eventfd_ctx *warn_used_efd; /* user-space passed eventfd */
>  };
>
>  static inline struct shmem_inode_info *SHMEM_I(struct inode *inode)
> diff --git a/mm/shmem.c b/mm/shmem.c
> index f69d296bd0a3..b559adcef3b3 100644
> --- a/mm/shmem.c
> +++ b/mm/shmem.c
> @@ -34,6 +34,7 @@
>  #include <linux/aio.h>
>
>  static struct vfsmount *shm_mnt;
> +static struct kset *shmem_kset;
>
>  #ifdef CONFIG_SHMEM
>  /*
> @@ -69,6 +70,7 @@ static struct vfsmount *shm_mnt;
>  #include <linux/syscalls.h>
>  #include <linux/fcntl.h>
>  #include <uapi/linux/memfd.h>
> +#include <linux/eventfd.h>
>
>  #include <asm/uaccess.h>
>  #include <asm/pgtable.h>
> @@ -199,6 +201,106 @@ static struct backing_dev_info shmem_backing_dev_info  __read_mostly = {
>  static LIST_HEAD(shmem_swaplist);
>  static DEFINE_MUTEX(shmem_swaplist_mutex);
>
> +
> +struct shmem_attr {
> +       struct attribute attr;
> +       ssize_t (*show)(struct shmem_attr *, struct shmem_sb_info *, char *);
> +       ssize_t (*store)(struct shmem_attr *, struct shmem_sb_info *,
> +                        const char *, size_t);
> +};
> +
> +static int shmem_setup_warn_used_blocks_eventfd(struct shmem_sb_info *sbinfo,
> +                                       unsigned int efd)
> +{
> +       int ret = 0;
> +
> +       if (sbinfo->warn_used_efd) {
> +               eventfd_ctx_put(sbinfo->warn_used_efd);
> +               sbinfo->warn_used_efd = NULL;
> +       }
> +
> +       sbinfo->warn_used_efd = eventfd_ctx_fdget(efd);
> +       if (IS_ERR(sbinfo->warn_used_efd)) {
> +               ret = PTR_ERR(sbinfo->warn_used_efd);
> +               sbinfo->warn_used_efd = NULL;
> +       }
> +
> +       return ret;
> +}
> +
> +static int parse_strtouint(const char *buf,
> +               unsigned long long max, unsigned int *value)
> +{
> +       int ret;
> +
> +       ret = kstrtouint(skip_spaces(buf), 0, value);
> +       if (!ret && *value > max)
> +               ret = -EINVAL;
> +       return ret;
> +}
> +
> +static ssize_t warn_used_blocks_efd_store(struct shmem_attr *a,
> +                                       struct shmem_sb_info *sbinfo,
> +                                       const char *buf, size_t count)
> +{
> +       unsigned int val;
> +       int ret;
> +
> +       if (parse_strtouint(buf, -1ULL, &val))
> +               return -EINVAL;
> +
> +       ret = shmem_setup_warn_used_blocks_eventfd(sbinfo, val);
> +
> +       return ret ? ret : count;
> +}
> +
> +static struct shmem_attr
> +shmem_attr_warn_used_blocks_efd = __ATTR_WO(warn_used_blocks_efd);
> +
> +static struct attribute *shmem_attrs[] = {
> +       &shmem_attr_warn_used_blocks_efd.attr,
> +       NULL,
> +};
> +
> +static ssize_t shmem_attr_show(struct kobject *kobj,
> +                             struct attribute *attr, char *buf)
> +{
> +       struct shmem_sb_info *sbinfo = container_of(kobj, struct shmem_sb_info,
> +                                               s_kobj);
> +       struct shmem_attr *a = container_of(attr, struct shmem_attr, attr);
> +
> +       return a->show ? a->show(a, sbinfo, buf) : 0;
> +}
> +
> +static ssize_t shmem_attr_store(struct kobject *kobj,
> +                              struct attribute *attr,
> +                              const char *buf, size_t len)
> +{
> +       struct shmem_sb_info *sbinfo = container_of(kobj, struct shmem_sb_info,
> +                                               s_kobj);
> +       struct shmem_attr *a = container_of(attr, struct shmem_attr, attr);
> +
> +       return a->store ? a->store(a, sbinfo, buf, len) : 0;
> +}
> +
> +static void shmem_sb_release(struct kobject *kobj)
> +{
> +       struct shmem_sb_info *sbinfo = container_of(kobj, struct shmem_sb_info,
> +                                               s_kobj);
> +       complete(&sbinfo->s_kobj_unregister);
> +}
> +
> +static const struct sysfs_ops shmem_attr_ops = {
> +       .show   = shmem_attr_show,
> +       .store  = shmem_attr_store,
> +};
> +
> +static struct kobj_type shmem_ktype = {
> +       .default_attrs  = shmem_attrs,
> +       .sysfs_ops      = &shmem_attr_ops,
> +       .release        = shmem_sb_release,
> +};
> +
>  static int shmem_reserve_inode(struct super_block *sb)
>  {
>         struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
> @@ -1170,6 +1272,13 @@ repeat:
>                         }
>                         percpu_counter_inc(&sbinfo->used_blocks);
>                 }
> +               if (sbinfo->warn_used) {
> +                       if (percpu_counter_compare(&sbinfo->used_blocks,
> +                                               sbinfo->warn_used) >= 0) {
> +                               if (sbinfo->warn_used_efd)
> +                                       eventfd_signal(sbinfo->warn_used_efd, 1);
> +                       }
> +               }
>
>                 page = shmem_alloc_page(gfp, info, index);
>                 if (!page) {
> @@ -2824,6 +2933,10 @@ static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo,
>                         mpol = NULL;
>                         if (mpol_parse_str(value, &mpol))
>                                 goto bad_val;
> +               } else if (!strcmp(this_char,"warn_used")) {
> +                       sbinfo->warn_used = memparse(value, &rest);
> +                       if (*rest)
> +                               goto bad_val;
>                 } else {
>                         printk(KERN_ERR "tmpfs: Bad mount option %s\n",
>                                this_char);
> @@ -2984,6 +3097,13 @@ static void shmem_put_super(struct super_block *sb)
>         struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
>
>         percpu_counter_destroy(&sbinfo->used_blocks);
> +       if (sbinfo->warn_used_efd) {
> +               eventfd_ctx_put(sbinfo->warn_used_efd);
> +               sbinfo->warn_used_efd = NULL;
> +       }
> +       kobject_del(&sbinfo->s_kobj);
> +       kobject_put(&sbinfo->s_kobj);
> +       wait_for_completion(&sbinfo->s_kobj_unregister);
>         mpol_put(sbinfo->mpol);
>         kfree(sbinfo);
>         sb->s_fs_info = NULL;
> @@ -2994,6 +3114,7 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent)
>         struct inode *inode;
>         struct shmem_sb_info *sbinfo;
>         int err = -ENOMEM;
> +       static unsigned int no;
>
>         /* Round up to L1_CACHE_BYTES to resist false sharing */
>         sbinfo = kzalloc(max((int)sizeof(struct shmem_sb_info),
> @@ -3045,17 +3166,25 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent)
>  #ifdef CONFIG_TMPFS_POSIX_ACL
>         sb->s_flags |= MS_POSIXACL;
>  #endif
> +       sbinfo->s_kobj.kset = shmem_kset;
> +       init_completion(&sbinfo->s_kobj_unregister);
> +       err = kobject_init_and_add(&sbinfo->s_kobj, &shmem_ktype, NULL,
> +                                  "%s-%u", sb->s_id, no++);
> +       if (err)
> +               goto failed;
>
>         inode = shmem_get_inode(sb, NULL, S_IFDIR | sbinfo->mode, 0, VM_NORESERVE);
>         if (!inode)
> -               goto failed;
> +               goto failed_kobj;
>         inode->i_uid = sbinfo->uid;
>         inode->i_gid = sbinfo->gid;
>         sb->s_root = d_make_root(inode);
>         if (!sb->s_root)
> -               goto failed;
> +               goto failed_kobj;
>         return 0;
>
> +failed_kobj:
> +       kobject_del(&sbinfo->s_kobj);
>  failed:
>         shmem_put_super(sb);
>         return err;
> @@ -3225,6 +3354,10 @@ int __init shmem_init(void)
>         if (shmem_inode_cachep)
>                 return 0;
>
> +       shmem_kset = kset_create_and_add("tmpfs", NULL, fs_kobj);
> +       if (!shmem_kset)
> +               return -ENOMEM;
> +
>         error = bdi_init(&shmem_backing_dev_info);
>         if (error)
>                 goto out4;
> @@ -3255,6 +3388,7 @@ out3:
>         bdi_destroy(&shmem_backing_dev_info);
>  out4:
>         shm_mnt = ERR_PTR(error);
> +       kset_unregister(shmem_kset);
>         return error;
>  }
>
> --
> 1.9.1
>
> --
> To unsubscribe, send a message with 'unsubscribe linux-mm' in
> the body to majordomo@xxxxxxxxx.  For more info on Linux MM,
> see: http://www.linux-mm.org/ .
> Don't email: <a href=mailto:"dont@xxxxxxxxx";> email@xxxxxxxxx </a>

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@xxxxxxxxx.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@xxxxxxxxx";> email@xxxxxxxxx </a>




[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]