From patchwork Sun Oct 11 22:58:35 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?q?Andreas_Gr=C3=BCnbacher?= X-Patchwork-Id: 7371021 Return-Path: X-Original-To: patchwork-cifs-client@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 85512BEEA4 for ; Sun, 11 Oct 2015 23:24:52 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 38257208FA for ; Sun, 11 Oct 2015 23:24:51 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id C725220941 for ; Sun, 11 Oct 2015 23:24:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932363AbbJKXCA (ORCPT ); Sun, 11 Oct 2015 19:02:00 -0400 Received: from mx1.redhat.com ([209.132.183.28]:35454 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932328AbbJKXB6 (ORCPT ); Sun, 11 Oct 2015 19:01:58 -0400 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) by mx1.redhat.com (Postfix) with ESMTPS id BB32A2FE81A; Sun, 11 Oct 2015 23:01:57 +0000 (UTC) Received: from nuc.home.com (vpn1-7-138.ams2.redhat.com [10.36.7.138]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t9BMx36m016614; Sun, 11 Oct 2015 19:01:51 -0400 From: Andreas Gruenbacher To: Alexander Viro , "Theodore Ts'o" , Andreas Dilger , "J. Bruce Fields" , Jeff Layton , Trond Myklebust , Anna Schumaker , Dave Chinner , linux-ext4@vger.kernel.org, xfs@oss.sgi.com, linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-nfs@vger.kernel.org, linux-cifs@vger.kernel.org, linux-api@vger.kernel.org Cc: Andreas Gruenbacher Subject: [PATCH v10 24/46] xfs: Add richacl support Date: Mon, 12 Oct 2015 00:58:35 +0200 Message-Id: <1444604337-17651-25-git-send-email-andreas.gruenbacher@gmail.com> In-Reply-To: <1444604337-17651-1-git-send-email-andreas.gruenbacher@gmail.com> References: <1444604337-17651-1-git-send-email-andreas.gruenbacher@gmail.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.26 Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, FREEMAIL_FROM,RCVD_IN_DNSWL_HI,T_RP_MATCHES_RCVD,UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Andreas Gruenbacher The richacl feature flag (mkfs.xfs -m richacl=1) determines whether an xfs filesystem supports posix acls or richacls. Richacls are stored in "system.richacl" xattrs. If richacls are not compiled into the kernel, mounting richacl filesystems will fail. Signed-off-by: Andreas Gruenbacher --- fs/ext4/richacl.h | 1 - fs/xfs/Kconfig | 11 ++++++ fs/xfs/Makefile | 1 + fs/xfs/libxfs/xfs_format.h | 16 +++++++- fs/xfs/xfs_iops.c | 42 +++++++++++++++----- fs/xfs/xfs_richacl.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/xfs_richacl.h | 34 ++++++++++++++++ fs/xfs/xfs_super.c | 14 ++++++- fs/xfs/xfs_super.h | 9 ++++- fs/xfs/xfs_xattr.c | 4 ++ 10 files changed, 215 insertions(+), 14 deletions(-) create mode 100644 fs/xfs/xfs_richacl.c create mode 100644 fs/xfs/xfs_richacl.h diff --git a/fs/ext4/richacl.h b/fs/ext4/richacl.h index fc7826f..f26fbdd 100644 --- a/fs/ext4/richacl.h +++ b/fs/ext4/richacl.h @@ -24,7 +24,6 @@ extern struct richacl *ext4_get_richacl(struct inode *); extern int ext4_set_richacl(struct inode *, struct richacl *); - extern int ext4_init_richacl(handle_t *, struct inode *, struct inode *); #else /* CONFIG_EXT4_FS_RICHACL */ diff --git a/fs/xfs/Kconfig b/fs/xfs/Kconfig index 5d47b4d..05dd312 100644 --- a/fs/xfs/Kconfig +++ b/fs/xfs/Kconfig @@ -52,6 +52,17 @@ config XFS_POSIX_ACL If you don't know what Access Control Lists are, say N. +config XFS_RICHACL + bool "XFS Rich Access Control Lists (EXPERIMENTAL)" + depends on XFS_FS + select FS_RICHACL + help + Richacls are an implementation of NFSv4 ACLs, extended by file masks + to cleanly integrate into the POSIX file permission model. To learn + more about them, see http://www.bestbits.at/richacl/. + + If you don't know what Richacls are, say N. + config XFS_RT bool "XFS Realtime subvolume support" depends on XFS_FS diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile index a096841..7df9ae3 100644 --- a/fs/xfs/Makefile +++ b/fs/xfs/Makefile @@ -118,6 +118,7 @@ xfs-$(CONFIG_XFS_QUOTA) += xfs_dquot.o \ xfs-$(CONFIG_XFS_RT) += xfs_rtalloc.o xfs-$(CONFIG_XFS_POSIX_ACL) += xfs_acl.o +xfs-$(CONFIG_XFS_RICHACL) += xfs_richacl.o xfs-$(CONFIG_PROC_FS) += xfs_stats.o xfs-$(CONFIG_SYSCTL) += xfs_sysctl.o xfs-$(CONFIG_COMPAT) += xfs_ioctl32.o diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h index 9590a06..8c6da45 100644 --- a/fs/xfs/libxfs/xfs_format.h +++ b/fs/xfs/libxfs/xfs_format.h @@ -461,10 +461,18 @@ xfs_sb_has_ro_compat_feature( #define XFS_SB_FEAT_INCOMPAT_FTYPE (1 << 0) /* filetype in dirent */ #define XFS_SB_FEAT_INCOMPAT_SPINODES (1 << 1) /* sparse inode chunks */ #define XFS_SB_FEAT_INCOMPAT_META_UUID (1 << 2) /* metadata UUID */ + +#ifdef CONFIG_XFS_RICHACL +#define XFS_SB_FEAT_INCOMPAT_RICHACL (1 << 3) /* richacls */ +#else +#define XFS_SB_FEAT_INCOMPAT_RICHACL 0 +#endif + #define XFS_SB_FEAT_INCOMPAT_ALL \ (XFS_SB_FEAT_INCOMPAT_FTYPE| \ XFS_SB_FEAT_INCOMPAT_SPINODES| \ - XFS_SB_FEAT_INCOMPAT_META_UUID) + XFS_SB_FEAT_INCOMPAT_META_UUID| \ + XFS_SB_FEAT_INCOMPAT_RICHACL) #define XFS_SB_FEAT_INCOMPAT_UNKNOWN ~XFS_SB_FEAT_INCOMPAT_ALL static inline bool @@ -530,6 +538,12 @@ static inline bool xfs_sb_version_hasmetauuid(struct xfs_sb *sbp) (sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_META_UUID); } +static inline bool xfs_sb_version_hasrichacl(struct xfs_sb *sbp) +{ + return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) && + (sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_RICHACL); +} + /* * end of superblock version macros */ diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index 8294132..e37bdf87 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -27,6 +27,7 @@ #include "xfs_bmap.h" #include "xfs_bmap_util.h" #include "xfs_acl.h" +#include "xfs_richacl.h" #include "xfs_quota.h" #include "xfs_error.h" #include "xfs_attr.h" @@ -42,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -133,7 +135,8 @@ xfs_generic_create( { struct inode *inode; struct xfs_inode *ip = NULL; - struct posix_acl *default_acl, *acl; + struct posix_acl *default_acl = NULL, *acl = NULL; + struct richacl *richacl = NULL; struct xfs_name name; int error; @@ -149,9 +152,15 @@ xfs_generic_create( rdev = 0; } - error = posix_acl_create(dir, &mode, &default_acl, &acl); - if (error) - return error; + if (XFS_IS_RICHACL(dir)) { + richacl = richacl_create(&mode, dir); + if (IS_ERR(richacl)) + return PTR_ERR(richacl); + } else { + error = posix_acl_create(dir, &mode, &default_acl, &acl); + if (error) + return error; + } if (!tmpfile) { xfs_dentry_to_name(&name, dentry, mode); @@ -180,6 +189,13 @@ xfs_generic_create( goto out_cleanup_inode; } #endif +#ifdef CONFIG_XFS_RICHACL + if (richacl) { + error = xfs_set_richacl(inode, richacl); + if (error) + goto out_cleanup_inode; + } +#endif if (tmpfile) d_tmpfile(dentry, inode); @@ -189,10 +205,9 @@ xfs_generic_create( xfs_finish_inode_setup(ip); out_free_acl: - if (default_acl) - posix_acl_release(default_acl); - if (acl) - posix_acl_release(acl); + posix_acl_release(default_acl); + posix_acl_release(acl); + richacl_put(richacl); return error; out_cleanup_inode: @@ -722,7 +737,10 @@ xfs_setattr_nonsize( * Posix ACL code seems to care about this issue either. */ if ((mask & ATTR_MODE) && !(flags & XFS_ATTR_NOACL)) { - error = posix_acl_chmod(inode, inode->i_mode); + if (XFS_IS_RICHACL(inode)) + error = richacl_chmod(inode, inode->i_mode); + else + error = posix_acl_chmod(inode, inode->i_mode); if (error) return error; } @@ -1104,6 +1122,8 @@ xfs_vn_tmpfile( static const struct inode_operations xfs_inode_operations = { .get_acl = xfs_get_acl, .set_acl = xfs_set_acl, + .get_richacl = xfs_get_richacl, + .set_richacl = xfs_set_richacl, .getattr = xfs_vn_getattr, .setattr = xfs_vn_setattr, .setxattr = generic_setxattr, @@ -1132,6 +1152,8 @@ static const struct inode_operations xfs_dir_inode_operations = { .rename2 = xfs_vn_rename, .get_acl = xfs_get_acl, .set_acl = xfs_set_acl, + .get_richacl = xfs_get_richacl, + .set_richacl = xfs_set_richacl, .getattr = xfs_vn_getattr, .setattr = xfs_vn_setattr, .setxattr = generic_setxattr, @@ -1160,6 +1182,8 @@ static const struct inode_operations xfs_dir_ci_inode_operations = { .rename2 = xfs_vn_rename, .get_acl = xfs_get_acl, .set_acl = xfs_set_acl, + .get_richacl = xfs_get_richacl, + .set_richacl = xfs_set_richacl, .getattr = xfs_vn_getattr, .setattr = xfs_vn_setattr, .setxattr = generic_setxattr, diff --git a/fs/xfs/xfs_richacl.c b/fs/xfs/xfs_richacl.c new file mode 100644 index 0000000..af74e92 --- /dev/null +++ b/fs/xfs/xfs_richacl.c @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * Author: Andreas Gruenbacher + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#include "xfs.h" +#include "xfs_format.h" +#include "xfs_log_format.h" +#include "xfs_inode.h" +#include "xfs_attr.h" + +#include + +struct richacl * +xfs_get_richacl(struct inode *inode) +{ + struct xfs_inode *ip = XFS_I(inode); + struct richacl *acl; + int size = XATTR_SIZE_MAX; + void *value; + int error; + + value = kmem_zalloc_large(size, KM_SLEEP); + if (!value) + return ERR_PTR(-ENOMEM); + + error = xfs_attr_get(ip, XATTR_NAME_RICHACL, value, &size, ATTR_ROOT); + if (error) { + /* + * If the attribute doesn't exist make sure we have a negative + * cache entry, for any other error assume it is transient and + * leave the cache entry as ACL_NOT_CACHED. + */ + acl = (error == -ENOATTR) ? NULL : ERR_PTR(error); + } else + acl = richacl_from_xattr(&init_user_ns, value, size); + + if (!IS_ERR(acl)) + set_cached_richacl(inode, acl); + kfree(value); + + return acl; +} + +int +xfs_set_richacl(struct inode *inode, struct richacl *acl) +{ + struct xfs_inode *ip = XFS_I(inode); + umode_t mode = inode->i_mode; + int error; + + if (acl) { + /* Don't allow acls with unmapped identifiers. */ + if (richacl_has_unmapped_identifiers(acl)) + return -EINVAL; + + if (richacl_equiv_mode(acl, &mode) == 0) { + xfs_set_mode(inode, mode); + acl = NULL; + } + } + if (acl) { + void *value; + int size = richacl_xattr_size(acl); + + value = kmem_zalloc_large(size, KM_SLEEP); + if (!value) + return -ENOMEM; + richacl_to_xattr(&init_user_ns, acl, value, size); + error = xfs_attr_set(ip, XATTR_NAME_RICHACL, value, size, + ATTR_ROOT); + kfree(value); + + if (!error) { + mode &= ~S_IRWXUGO; + mode |= richacl_masks_to_mode(acl); + xfs_set_mode(inode, mode); + } + } else { + error = xfs_attr_remove(ip, XATTR_NAME_RICHACL, ATTR_ROOT); + if (error == -ENOATTR) + error = 0; + } + if (!error) + set_cached_richacl(inode, acl); + + return 0; +} diff --git a/fs/xfs/xfs_richacl.h b/fs/xfs/xfs_richacl.h new file mode 100644 index 0000000..78ad314 --- /dev/null +++ b/fs/xfs/xfs_richacl.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * Author: Andreas Gruenbacher + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#ifndef __FS_XFS_RICHACL_H +#define __FS_XFS_RICHACL_H + +#include + +#ifdef CONFIG_XFS_RICHACL + +#define XFS_IS_RICHACL(inode) IS_RICHACL(inode) + +extern struct richacl *xfs_get_richacl(struct inode *); +extern int xfs_set_richacl(struct inode *, struct richacl *); + +#else /* CONFIG_XFS_RICHACL */ + +#define XFS_IS_RICHACL(inode) (0) +#define xfs_get_richacl NULL +#define xfs_set_richacl NULL + +#endif /* CONFIG_XFS_RICHACL */ +#endif /* __FS_XFS_RICHACL_H */ diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index 904f637..74eeb0e 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -1500,7 +1500,19 @@ xfs_fs_fill_super( sb->s_maxbytes = xfs_max_file_offset(sb->s_blocksize_bits); sb->s_max_links = XFS_MAXLINK; sb->s_time_gran = 1; - set_posix_acl_flag(sb); + + if (xfs_sb_version_hasrichacl(&mp->m_sb)) { +#ifdef CONFIG_XFS_RICHACL + sb->s_flags |= MS_RICHACL; +#else + error = -EOPNOTSUPP; + goto out_free_sb; +#endif + } else { +#ifdef CONFIG_XFS_POSIX_ACL + sb->s_flags |= MS_POSIXACL; +#endif + } /* version 5 superblocks support inode version counters. */ if (XFS_SB_VERSION_NUM(&mp->m_sb) == XFS_SB_VERSION_5) diff --git a/fs/xfs/xfs_super.h b/fs/xfs/xfs_super.h index 499058f..072fd57 100644 --- a/fs/xfs/xfs_super.h +++ b/fs/xfs/xfs_super.h @@ -30,10 +30,14 @@ extern void xfs_qm_exit(void); #ifdef CONFIG_XFS_POSIX_ACL # define XFS_ACL_STRING "ACLs, " -# define set_posix_acl_flag(sb) ((sb)->s_flags |= MS_POSIXACL) #else # define XFS_ACL_STRING -# define set_posix_acl_flag(sb) do { } while (0) +#endif + +#ifdef CONFIG_XFS_RICHACL +# define XFS_RICHACL_STRING "Richacls, " +#else +# define XFS_RICHACL_STRING #endif #define XFS_SECURITY_STRING "security attributes, " @@ -52,6 +56,7 @@ extern void xfs_qm_exit(void); #define XFS_VERSION_STRING "SGI XFS" #define XFS_BUILD_OPTIONS XFS_ACL_STRING \ + XFS_RICHACL_STRING \ XFS_SECURITY_STRING \ XFS_REALTIME_STRING \ XFS_DBG_STRING /* DBG must be last */ diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c index c0368151..238b39f 100644 --- a/fs/xfs/xfs_xattr.c +++ b/fs/xfs/xfs_xattr.c @@ -28,6 +28,7 @@ #include "xfs_acl.h" #include +#include #include @@ -103,6 +104,9 @@ const struct xattr_handler *xfs_xattr_handlers[] = { &posix_acl_access_xattr_handler, &posix_acl_default_xattr_handler, #endif +#ifdef CONFIG_XFS_RICHACL + &richacl_xattr_handler, +#endif NULL };