lkml.org 
[lkml]   [2006]   [Dec]   [4]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 35/35] Unionfs: Extended Attributes support
    Date
    From: Josef "Jeff" Sipek <jsipek@cs.sunysb.edu>

    Extended attribute support.

    Signed-off-by: Josef "Jeff" Sipek <jsipek@cs.sunysb.edu>
    Signed-off-by: David Quigley <dquigley@fsl.cs.sunysb.edu>
    Signed-off-by: Erez Zadok <ezk@cs.sunysb.edu>
    ---
    fs/Kconfig | 9 ++++
    fs/unionfs/Makefile | 2 +
    fs/unionfs/copyup.c | 75 +++++++++++++++++++++++++++++++
    fs/unionfs/inode.c | 12 +++++
    fs/unionfs/union.h | 15 ++++++
    fs/unionfs/xattr.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++
    6 files changed, 236 insertions(+), 0 deletions(-)

    diff --git a/fs/Kconfig b/fs/Kconfig
    index 4b31ea4..b8b8e45 100644
    --- a/fs/Kconfig
    +++ b/fs/Kconfig
    @@ -1567,6 +1567,15 @@ config UNION_FS

    See <http://www.unionfs.org> for details

    +config UNION_FS_XATTR
    + bool "Unionfs extended attributes"
    + depends on UNION_FS
    + help
    + Extended attributes are name:value pairs associated with inodes by
    + the kernel or by users (see the attr(5) manual page).
    +
    + If unsure, say N.
    +
    endmenu

    menu "Network File Systems"
    diff --git a/fs/unionfs/Makefile b/fs/unionfs/Makefile
    index 25dd78f..7c98325 100644
    --- a/fs/unionfs/Makefile
    +++ b/fs/unionfs/Makefile
    @@ -3,3 +3,5 @@ obj-$(CONFIG_UNION_FS) += unionfs.o
    unionfs-y := subr.o dentry.o file.o inode.o main.o super.o \
    stale_inode.o branchman.o rdstate.o copyup.o dirhelper.o \
    rename.o unlink.o lookup.o commonfops.o dirfops.o sioq.o
    +
    +unionfs-$(CONFIG_UNION_FS_XATTR) += xattr.o
    diff --git a/fs/unionfs/copyup.c b/fs/unionfs/copyup.c
    index 0557c02..ec1c649 100644
    --- a/fs/unionfs/copyup.c
    +++ b/fs/unionfs/copyup.c
    @@ -18,6 +18,75 @@

    #include "union.h"

    +#ifdef CONFIG_UNION_FS_XATTR
    +/* copyup all extended attrs for a given dentry */
    +static int copyup_xattrs(struct dentry *old_hidden_dentry,
    + struct dentry *new_hidden_dentry)
    +{
    + int err = 0;
    + ssize_t list_size = -1;
    + char *name_list = NULL;
    + char *attr_value = NULL;
    + char *name_list_orig = NULL;
    +
    + list_size = vfs_listxattr(old_hidden_dentry, NULL, 0);
    +
    + if (list_size <= 0) {
    + err = list_size;
    + goto out;
    + }
    +
    + name_list = xattr_alloc(list_size + 1, XATTR_LIST_MAX);
    + if (!name_list || IS_ERR(name_list)) {
    + err = PTR_ERR(name_list);
    + goto out;
    + }
    + list_size = vfs_listxattr(old_hidden_dentry, name_list, list_size);
    + attr_value = xattr_alloc(XATTR_SIZE_MAX, XATTR_SIZE_MAX);
    + if (!attr_value || IS_ERR(attr_value)) {
    + err = PTR_ERR(name_list);
    + goto out;
    + }
    + name_list_orig = name_list;
    + while (*name_list) {
    + ssize_t size;
    +
    + //We need to lock here since vfs_getxattr doesn't lock for us.
    + mutex_lock(&old_hidden_dentry->d_inode->i_mutex);
    + size = vfs_getxattr(old_hidden_dentry, name_list,
    + attr_value, XATTR_SIZE_MAX);
    + mutex_unlock(&old_hidden_dentry->d_inode->i_mutex);
    + if (size < 0) {
    + err = size;
    + goto out;
    + }
    +
    + if (size > XATTR_SIZE_MAX) {
    + err = -E2BIG;
    + goto out;
    + }
    + //We don't need to lock here since vfs_setxattr does it for us.
    + err = vfs_setxattr(new_hidden_dentry, name_list, attr_value,
    + size, 0);
    +
    + if (err < 0)
    + goto out;
    + name_list += strlen(name_list) + 1;
    + }
    + out:
    + name_list = name_list_orig;
    +
    + if (name_list)
    + xattr_free(name_list, list_size + 1);
    + if (attr_value)
    + xattr_free(attr_value, XATTR_SIZE_MAX);
    + /* It is no big deal if this fails, we just roll with the punches. */
    + if (err == -ENOTSUPP || err == -EOPNOTSUPP)
    + err = 0;
    + return err;
    +}
    +#endif /* CONFIG_UNION_FS_XATTR */
    +
    /* Determine the mode based on the copyup flags, and the existing dentry. */
    static int copyup_permissions(struct super_block *sb,
    struct dentry *old_hidden_dentry,
    @@ -343,6 +412,12 @@ int copyup_named_dentry(struct inode *di
    if ((err = copyup_permissions(sb, old_hidden_dentry, new_hidden_dentry)))
    goto out_unlink;

    +#ifdef CONFIG_UNION_FS_XATTR
    + /* Selinux uses extended attributes for permissions. */
    + if ((err = copyup_xattrs(old_hidden_dentry, new_hidden_dentry)))
    + goto out_unlink;
    +#endif
    +
    /* do not allow files getting deleted to be reinterposed */
    if (!d_deleted(dentry))
    unionfs_reinterpose(dentry);
    diff --git a/fs/unionfs/inode.c b/fs/unionfs/inode.c
    index c7806e9..2e45fb0 100644
    --- a/fs/unionfs/inode.c
    +++ b/fs/unionfs/inode.c
    @@ -917,10 +917,22 @@ struct inode_operations unionfs_dir_iops
    .rename = unionfs_rename,
    .permission = unionfs_permission,
    .setattr = unionfs_setattr,
    +#ifdef CONFIG_UNION_FS_XATTR
    + .setxattr = unionfs_setxattr,
    + .getxattr = unionfs_getxattr,
    + .removexattr = unionfs_removexattr,
    + .listxattr = unionfs_listxattr,
    +#endif
    };

    struct inode_operations unionfs_main_iops = {
    .permission = unionfs_permission,
    .setattr = unionfs_setattr,
    +#ifdef CONFIG_UNION_FS_XATTR
    + .setxattr = unionfs_setxattr,
    + .getxattr = unionfs_getxattr,
    + .removexattr = unionfs_removexattr,
    + .listxattr = unionfs_listxattr,
    +#endif
    };

    diff --git a/fs/unionfs/union.h b/fs/unionfs/union.h
    index ff0b814..58e0cfb 100644
    --- a/fs/unionfs/union.h
    +++ b/fs/unionfs/union.h
    @@ -40,6 +40,7 @@
    #include <linux/string.h>
    #include <linux/vmalloc.h>
    #include <linux/writeback.h>
    +#include <linux/xattr.h>
    #include <linux/fs_stack.h>

    #include <linux/union_fs.h>
    @@ -315,6 +316,20 @@ int unionfs_ioctl_queryfile(struct file
    /* Verify that a branch is valid. */
    int check_branch(struct nameidata *nd);

    +#ifdef CONFIG_UNION_FS_XATTR
    +/* Extended attribute functions. */
    +extern void *xattr_alloc(size_t size, size_t limit);
    +extern void xattr_free(void *ptr, size_t size);
    +
    +extern ssize_t unionfs_getxattr(struct dentry *dentry, const char *name,
    + void *value, size_t size);
    +extern int unionfs_removexattr(struct dentry *dentry, const char *name);
    +extern ssize_t unionfs_listxattr(struct dentry *dentry, char *list,
    + size_t size);
    +extern int unionfs_setxattr(struct dentry *dentry, const char *name,
    + const void *value, size_t size, int flags);
    +#endif /* CONFIG_UNION_FS_XATTR */
    +
    /* The root directory is unhashed, but isn't deleted. */
    static inline int d_deleted(struct dentry *d)
    {
    diff --git a/fs/unionfs/xattr.c b/fs/unionfs/xattr.c
    new file mode 100644
    index 0000000..9f804bf
    --- /dev/null
    +++ b/fs/unionfs/xattr.c
    @@ -0,0 +1,123 @@
    +/*
    + * Copyright (c) 2003-2006 Erez Zadok
    + * Copyright (c) 2003-2006 Charles P. Wright
    + * Copyright (c) 2005-2006 Josef 'Jeff' Sipek
    + * Copyright (c) 2005-2006 Junjiro Okajima
    + * Copyright (c) 2005 Arun M. Krishnakumar
    + * Copyright (c) 2004-2006 David P. Quigley
    + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
    + * Copyright (c) 2003 Puja Gupta
    + * Copyright (c) 2003 Harikesavan Krishnan
    + * Copyright (c) 2003-2006 Stony Brook University
    + * Copyright (c) 2003-2006 The Research Foundation of State University of New York*
    + *
    + * This program is free software; you can redistribute it and/or modify
    + * it under the terms of the GNU General Public License version 2 as
    + * published by the Free Software Foundation.
    + */
    +
    +#include "union.h"
    +
    +/* This is lifted from fs/xattr.c */
    +void *xattr_alloc(size_t size, size_t limit)
    +{
    + void *ptr;
    +
    + if (size > limit)
    + return ERR_PTR(-E2BIG);
    +
    + if (!size) /* size request, no buffer is needed */
    + return NULL;
    + else if (size <= PAGE_SIZE)
    + ptr = kmalloc(size, GFP_KERNEL);
    + else
    + ptr = vmalloc(size);
    + if (!ptr)
    + return ERR_PTR(-ENOMEM);
    + return ptr;
    +}
    +
    +void xattr_free(void *ptr, size_t size)
    +{
    + if (!size) /* size request, no buffer was needed */
    + return;
    + else if (size <= PAGE_SIZE)
    + kfree(ptr);
    + else
    + vfree(ptr);
    +}
    +
    +/* BKL held by caller.
    + * dentry->d_inode->i_mutex locked
    + */
    +ssize_t unionfs_getxattr(struct dentry * dentry, const char *name, void *value,
    + size_t size)
    +{
    + struct dentry *hidden_dentry = NULL;
    + int err = -EOPNOTSUPP;
    +
    + lock_dentry(dentry);
    +
    + hidden_dentry = unionfs_lower_dentry(dentry);
    +
    + err = vfs_getxattr(hidden_dentry, (char*) name, value, size);
    +
    + unlock_dentry(dentry);
    + return err;
    +}
    +
    +/* BKL held by caller.
    + * dentry->d_inode->i_mutex locked
    + */
    +int unionfs_setxattr(struct dentry *dentry, const char *name, const void *value,
    + size_t size, int flags)
    +{
    + struct dentry *hidden_dentry = NULL;
    + int err = -EOPNOTSUPP;
    +
    + lock_dentry(dentry);
    + hidden_dentry = unionfs_lower_dentry(dentry);
    +
    + err = vfs_setxattr(hidden_dentry, (char*) name, (void*) value, size, flags);
    +
    + unlock_dentry(dentry);
    + return err;
    +}
    +
    +/* BKL held by caller.
    + * dentry->d_inode->i_mutex locked
    + */
    +int unionfs_removexattr(struct dentry *dentry, const char *name)
    +{
    + struct dentry *hidden_dentry = NULL;
    + int err = -EOPNOTSUPP;
    +
    + lock_dentry(dentry);
    + hidden_dentry = unionfs_lower_dentry(dentry);
    +
    + err = vfs_removexattr(hidden_dentry, (char*) name);
    +
    + unlock_dentry(dentry);
    + return err;
    +}
    +
    +/* BKL held by caller.
    + * dentry->d_inode->i_mutex locked
    + */
    +ssize_t unionfs_listxattr(struct dentry * dentry, char *list, size_t size)
    +{
    + struct dentry *hidden_dentry = NULL;
    + int err = -EOPNOTSUPP;
    + char *encoded_list = NULL;
    +
    + lock_dentry(dentry);
    +
    + hidden_dentry = unionfs_lower_dentry(dentry);
    +
    + encoded_list = list;
    + err = vfs_listxattr(hidden_dentry, encoded_list, size);
    +
    + unlock_dentry(dentry);
    + return err;
    +}
    +
    --
    1.4.3.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/

    \
     
     \ /
      Last update: 2006-12-04 13:37    [W:4.094 / U:0.724 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site