lkml.org 
[lkml]   [2016]   [Aug]   [16]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v25 12/22] vfs: Cache richacl in struct inode
    Date
    Cache richacls in struct inode so that this doesn't have to be done
    individually in each filesystem. This is similar to POSIX ACLs.

    Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
    ---
    fs/inode.c | 13 +++++---
    fs/richacl.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++
    include/linux/fs.h | 5 ++-
    include/linux/richacl.h | 11 +++++++
    4 files changed, 105 insertions(+), 5 deletions(-)

    diff --git a/fs/inode.c b/fs/inode.c
    index cc081dd..618bf5d4 100644
    --- a/fs/inode.c
    +++ b/fs/inode.c
    @@ -181,8 +181,11 @@ int inode_init_always(struct super_block *sb, struct inode *inode)
    inode->i_private = NULL;
    inode->i_mapping = mapping;
    INIT_HLIST_HEAD(&inode->i_dentry); /* buggered by rcu freeing */
    -#ifdef CONFIG_FS_POSIX_ACL
    - inode->i_acl = inode->i_default_acl = ACL_NOT_CACHED;
    +#if defined(CONFIG_FS_POSIX_ACL) || defined(CONFIG_FS_RICHACL)
    + inode->i_acl = ACL_NOT_CACHED;
    +# if defined(CONFIG_FS_POSIX_ACL)
    + inode->i_default_acl = ACL_NOT_CACHED;
    +# endif
    #endif

    #ifdef CONFIG_FSNOTIFY
    @@ -238,17 +241,19 @@ void __destroy_inode(struct inode *inode)
    atomic_long_dec(&inode->i_sb->s_remove_count);
    }

    -#ifdef CONFIG_FS_POSIX_ACL
    +#if defined(CONFIG_FS_POSIX_ACL) || defined(CONFIG_FS_RICHACL)
    if (inode->i_acl && !is_uncached_acl(inode->i_acl))
    base_acl_put(inode->i_acl);
    +# if defined(CONFIG_FS_POSIX_ACL)
    if (inode->i_default_acl && !is_uncached_acl(inode->i_default_acl))
    base_acl_put(inode->i_default_acl);
    +# endif
    #endif
    this_cpu_dec(nr_inodes);
    }
    EXPORT_SYMBOL(__destroy_inode);

    -#ifdef CONFIG_FS_POSIX_ACL
    +#if defined(CONFIG_FS_POSIX_ACL) || defined(CONFIG_FS_RICHACL)
    struct base_acl *__get_cached_acl(struct base_acl **p)
    {
    struct base_acl *base_acl;
    diff --git a/fs/richacl.c b/fs/richacl.c
    index 57a4048..731c468 100644
    --- a/fs/richacl.c
    +++ b/fs/richacl.c
    @@ -20,6 +20,87 @@
    #include <linux/slab.h>
    #include <linux/richacl.h>

    +void set_cached_richacl(struct inode *inode, struct richacl *acl)
    +{
    + struct base_acl *old;
    +
    + old = xchg(&inode->i_acl, &richacl_get(acl)->a_base);
    + if (!is_uncached_acl(old))
    + base_acl_put(old);
    +}
    +EXPORT_SYMBOL_GPL(set_cached_richacl);
    +
    +void forget_cached_richacl(struct inode *inode)
    +{
    + __forget_cached_acl(&inode->i_acl);
    +}
    +EXPORT_SYMBOL_GPL(forget_cached_richacl);
    +
    +struct richacl *get_richacl(struct inode *inode)
    +{
    + struct base_acl *sentinel, *base_acl;
    + struct richacl *acl;
    +
    + if (!IS_RICHACL(inode))
    + return NULL;
    +
    + /*
    + * The sentinel is used to detect when another operation like
    + * set_cached_richacl() or forget_cached_richacl() races with
    + * get_richacl().
    + * It is guaranteed that is_uncached_acl(sentinel) is true.
    + */
    +
    + base_acl = __get_cached_acl(&inode->i_acl);
    + if (!is_uncached_acl(base_acl))
    + return richacl(base_acl);
    +
    + sentinel = uncached_acl_sentinel(current);
    +
    + /*
    + * If the ACL isn't being read yet, set our sentinel. Otherwise, the
    + * current value of the ACL will not be ACL_NOT_CACHED and so our own
    + * sentinel will not be set; another task will update the cache. We
    + * could wait for that other task to complete its job, but it's easier
    + * to just call ->get_acl to fetch the ACL ourself. (This is going to
    + * be an unlikely race.)
    + */
    + if (cmpxchg(&inode->i_acl, ACL_NOT_CACHED, sentinel) != ACL_NOT_CACHED)
    + /* fall through */ ;
    +
    + /*
    + * Normally, the ACL returned by ->get_richacl will be cached.
    + * A filesystem can prevent that by calling
    + * forget_cached_richacl(inode) in ->get_richacl.
    + *
    + * If the filesystem doesn't have a ->get_richacl function at all,
    + * we'll just create the negative cache entry.
    + */
    + if (!inode->i_op->get_richacl) {
    + set_cached_richacl(inode, NULL);
    + return NULL;
    + }
    +
    + acl = inode->i_op->get_richacl(inode);
    + if (IS_ERR(acl)) {
    + /*
    + * Remove our sentinel so that we don't block future attempts
    + * to cache the ACL.
    + */
    + cmpxchg(&inode->i_acl, sentinel, ACL_NOT_CACHED);
    + return acl;
    + }
    +
    + /*
    + * Cache the result, but only if our sentinel is still in place.
    + */
    + richacl_get(acl);
    + if (unlikely(cmpxchg(&inode->i_acl, sentinel, &acl->a_base) != sentinel))
    + richacl_put(acl);
    + return acl;
    +}
    +EXPORT_SYMBOL_GPL(get_richacl);
    +
    /**
    * richacl_alloc - allocate a richacl
    * @count: number of entries
    diff --git a/include/linux/fs.h b/include/linux/fs.h
    index fbb57f9..89df251 100644
    --- a/include/linux/fs.h
    +++ b/include/linux/fs.h
    @@ -584,6 +584,7 @@ struct base_acl {
    struct rcu_head ba_rcu;
    };
    struct posix_acl;
    +struct richacl;
    #define ACL_NOT_CACHED ((void *)(-1))

    static inline struct base_acl *
    @@ -614,9 +615,11 @@ struct inode {
    kgid_t i_gid;
    unsigned int i_flags;

    -#if defined(CONFIG_FS_POSIX_ACL)
    +#if defined(CONFIG_FS_POSIX_ACL) || defined(CONFIG_FS_RICHACL)
    struct base_acl *i_acl;
    +# if defined(CONFIG_FS_POSIX_ACL)
    struct base_acl *i_default_acl;
    +# endif
    #endif

    const struct inode_operations *i_op;
    diff --git a/include/linux/richacl.h b/include/linux/richacl.h
    index d535206..207fe06 100644
    --- a/include/linux/richacl.h
    +++ b/include/linux/richacl.h
    @@ -70,6 +70,17 @@ richacl_put(struct richacl *acl)
    base_acl_put(&acl->a_base);
    }

    +static inline struct richacl *
    +richacl(struct base_acl *base_acl)
    +{
    + BUILD_BUG_ON(offsetof(struct richacl, a_base) != 0);
    + return container_of(base_acl, struct richacl, a_base);
    +}
    +
    +extern void set_cached_richacl(struct inode *, struct richacl *);
    +extern void forget_cached_richacl(struct inode *);
    +extern struct richacl *get_richacl(struct inode *);
    +
    /**
    * richace_is_owner - check if @ace is an OWNER@ entry
    */
    --
    2.7.4
    \
     
     \ /
      Last update: 2016-09-17 09:57    [W:4.419 / U:0.180 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site