Linux 4.5 compat: xattr list handler

The registered xattr .list handler was simplified in the 4.5 kernel
to only perform a permission check.  Given a dentry for the file it
must return a boolean indicating if the name is visible.  This
differs slightly from the previous APIs which also required the
function to copy the name in to the provided list and return its
size.  That is now all the responsibility of the caller.

This should be straight forward change to make to ZoL since we've
always required the caller to make the copy.  However, this was
slightly complicated by the need to support 3 older APIs.  Yes,
between 2.6.32 and 4.5 there are 4 versions of this interface!

Therefore, while the functional change in this patch is small it
includes significant cleanup to make the code understandable and
maintainable.  These changes include:

- Improved configure checks for .list, .get, and .set interfaces.
  - Interfaces checked from newest to oldest.
  - Strict checking for each possible known interface.
  - Configure fails when no known interface is available.
  - HAVE_*_XATTR_LIST renamed HAVE_XATTR_LIST_* for consistency
    with similar iops and fops configure checks.

- POSIX_ACL_XATTR_{DEFAULT|ACCESS} were removed forcing callers to
  move to their replacements, XATTR_NAME_POSIX_ACL_{DEFAULT|ACCESS}.
  Compatibility wrapper were added for old kernels.

- ZPL_XATTR_LIST_WRAPPER added which behaves the same as the existing
  ZPL_XATTR_{GET|SET} WRAPPERs.  Only the inode is guaranteed to be
  a valid pointer, passing NULL for the 'list' and 'name' variables
  is allowed and must be checked for.  All .list functions were
  updated to use the wrapper to aid readability.

- zpl_xattr_filldir() updated to use the .list function for its
  permission check which is consistent with the updated Linux 4.5
  interface.  If a .list function is registered it should return 0
  to indicate a name should be skipped, if there is no registered
  function the name will be added.

- Additional documentation from xattr(7) describing the correct
  behavior for each namespace was added before the relevant handlers.

Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Tim Chase <tim@chase2k.com>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Issue #4228
This commit is contained in:
Brian Behlendorf 2016-01-14 18:01:24 -05:00
parent beeed4596b
commit 4967a3eb9d
3 changed files with 543 additions and 307 deletions

View File

@ -3,8 +3,8 @@ dnl # 2.6.35 API change,
dnl # The 'struct xattr_handler' was constified in the generic dnl # The 'struct xattr_handler' was constified in the generic
dnl # super_block structure. dnl # super_block structure.
dnl # dnl #
AC_DEFUN([ZFS_AC_KERNEL_CONST_XATTR_HANDLER], AC_DEFUN([ZFS_AC_KERNEL_CONST_XATTR_HANDLER], [
[AC_MSG_CHECKING([whether super_block uses const struct xattr_hander]) AC_MSG_CHECKING([whether super_block uses const struct xattr_handler])
ZFS_LINUX_TRY_COMPILE([ ZFS_LINUX_TRY_COMPILE([
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/xattr.h> #include <linux/xattr.h>
@ -26,29 +26,29 @@ AC_DEFUN([ZFS_AC_KERNEL_CONST_XATTR_HANDLER],
],[ ],[
AC_MSG_RESULT([yes]) AC_MSG_RESULT([yes])
AC_DEFINE(HAVE_CONST_XATTR_HANDLER, 1, AC_DEFINE(HAVE_CONST_XATTR_HANDLER, 1,
[super_block uses const struct xattr_hander]) [super_block uses const struct xattr_handler])
],[ ],[
AC_MSG_RESULT([no]) AC_MSG_RESULT([no])
]) ])
]) ])
dnl # dnl #
dnl # 2.6.33 API change, dnl # Supported xattr handler get() interfaces checked newest to oldest.
dnl # The xattr_hander->get() callback was changed to take a dentry
dnl # instead of an inode, and a handler_flags argument was added.
dnl #
dnl # 4.4 API change,
dnl # The xattr_hander->get() callback was changed to take a xattr_handler,
dnl # and handler_flags argument was removed and should be accessed by
dnl # handler->flags.
dnl # dnl #
AC_DEFUN([ZFS_AC_KERNEL_XATTR_HANDLER_GET], [ AC_DEFUN([ZFS_AC_KERNEL_XATTR_HANDLER_GET], [
AC_MSG_CHECKING([whether xattr_handler->get() wants dentry]) dnl #
dnl # 4.4 API change,
dnl # The xattr_handler->get() callback was changed to take a
dnl # attr_handler, and handler_flags argument was removed and
dnl # should be accessed by handler->flags.
dnl #
AC_MSG_CHECKING([whether xattr_handler->get() wants xattr_handler])
ZFS_LINUX_TRY_COMPILE([ ZFS_LINUX_TRY_COMPILE([
#include <linux/xattr.h> #include <linux/xattr.h>
int get(struct dentry *dentry, const char *name, int get(const struct xattr_handler *handler,
void *buffer, size_t size, int handler_flags) { return 0; } struct dentry *dentry, const char *name,
void *buffer, size_t size) { return 0; }
static const struct xattr_handler static const struct xattr_handler
xops __attribute__ ((unused)) = { xops __attribute__ ((unused)) = {
.get = get, .get = get,
@ -56,16 +56,23 @@ AC_DEFUN([ZFS_AC_KERNEL_XATTR_HANDLER_GET], [
],[ ],[
],[ ],[
AC_MSG_RESULT(yes) AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_DENTRY_XATTR_GET, 1, AC_DEFINE(HAVE_XATTR_GET_HANDLER, 1,
[xattr_handler->get() wants dentry]) [xattr_handler->get() wants xattr_handler])
],[ ],[
dnl #
dnl # 2.6.33 API change,
dnl # The xattr_handler->get() callback was changed to take
dnl # a dentry instead of an inode, and a handler_flags
dnl # argument was added.
dnl #
AC_MSG_RESULT(no) AC_MSG_RESULT(no)
AC_MSG_CHECKING([whether xattr_handler->get() wants xattr_handler]) AC_MSG_CHECKING([whether xattr_handler->get() wants dentry])
ZFS_LINUX_TRY_COMPILE([ ZFS_LINUX_TRY_COMPILE([
#include <linux/xattr.h> #include <linux/xattr.h>
int get(const struct xattr_handler *handler, struct dentry *dentry, int get(struct dentry *dentry, const char *name,
const char *name, void *buffer, size_t size) { return 0; } void *buffer, size_t size, int handler_flags)
{ return 0; }
static const struct xattr_handler static const struct xattr_handler
xops __attribute__ ((unused)) = { xops __attribute__ ((unused)) = {
.get = get, .get = get,
@ -73,32 +80,54 @@ AC_DEFUN([ZFS_AC_KERNEL_XATTR_HANDLER_GET], [
],[ ],[
],[ ],[
AC_MSG_RESULT(yes) AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_HANDLER_XATTR_GET, 1, AC_DEFINE(HAVE_XATTR_GET_DENTRY, 1,
[xattr_handler->get() wants xattr_handler]) [xattr_handler->get() wants dentry])
],[ ],[
dnl #
dnl # 2.6.32 API
dnl #
AC_MSG_RESULT(no) AC_MSG_RESULT(no)
AC_MSG_CHECKING(
[whether xattr_handler->get() wants inode])
ZFS_LINUX_TRY_COMPILE([
#include <linux/xattr.h>
int get(struct inode *ip, const char *name,
void *buffer, size_t size) { return 0; }
static const struct xattr_handler
xops __attribute__ ((unused)) = {
.get = get,
};
],[
],[
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_XATTR_GET_INODE, 1,
[xattr_handler->get() wants inode])
],[
AC_MSG_ERROR([no; please file a bug report])
])
]) ])
]) ])
]) ])
dnl # dnl #
dnl # 2.6.33 API change, dnl # Supported xattr handler set() interfaces checked newest to oldest.
dnl # The xattr_hander->set() callback was changed to take a dentry
dnl # instead of an inode, and a handler_flags argument was added.
dnl #
dnl # 4.4 API change,
dnl # The xattr_hander->set() callback was changed to take a xattr_handler,
dnl # and handler_flags argument was removed and should be accessed by
dnl # handler->flags.
dnl # dnl #
AC_DEFUN([ZFS_AC_KERNEL_XATTR_HANDLER_SET], [ AC_DEFUN([ZFS_AC_KERNEL_XATTR_HANDLER_SET], [
AC_MSG_CHECKING([whether xattr_handler->set() wants dentry]) dnl #
dnl # 4.4 API change,
dnl # The xattr_handler->set() callback was changed to take a
dnl # xattr_handler, and handler_flags argument was removed and
dnl # should be accessed by handler->flags.
dnl #
AC_MSG_CHECKING([whether xattr_handler->set() wants xattr_handler])
ZFS_LINUX_TRY_COMPILE([ ZFS_LINUX_TRY_COMPILE([
#include <linux/xattr.h> #include <linux/xattr.h>
int set(struct dentry *dentry, const char *name, int set(const struct xattr_handler *handler,
const void *buffer, size_t size, int flags, struct dentry *dentry, const char *name,
int handler_flags) { return 0; } const void *buffer, size_t size, int flags)
{ return 0; }
static const struct xattr_handler static const struct xattr_handler
xops __attribute__ ((unused)) = { xops __attribute__ ((unused)) = {
.set = set, .set = set,
@ -106,16 +135,23 @@ AC_DEFUN([ZFS_AC_KERNEL_XATTR_HANDLER_SET], [
],[ ],[
],[ ],[
AC_MSG_RESULT(yes) AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_DENTRY_XATTR_SET, 1, AC_DEFINE(HAVE_XATTR_SET_HANDLER, 1,
[xattr_handler->set() wants dentry]) [xattr_handler->set() wants xattr_handler])
],[ ],[
dnl #
dnl # 2.6.33 API change,
dnl # The xattr_handler->set() callback was changed to take a
dnl # dentry instead of an inode, and a handler_flags
dnl # argument was added.
dnl #
AC_MSG_RESULT(no) AC_MSG_RESULT(no)
AC_MSG_CHECKING([whether xattr_handler->set() wants xattr_handler]) AC_MSG_CHECKING([whether xattr_handler->set() wants dentry])
ZFS_LINUX_TRY_COMPILE([ ZFS_LINUX_TRY_COMPILE([
#include <linux/xattr.h> #include <linux/xattr.h>
int set(const struct xattr_handler *handler, struct dentry *dentry, int set(struct dentry *dentry, const char *name,
const char *name, const void *buffer, size_t size, int flags) { return 0; } const void *buffer, size_t size, int flags,
int handler_flags) { return 0; }
static const struct xattr_handler static const struct xattr_handler
xops __attribute__ ((unused)) = { xops __attribute__ ((unused)) = {
.set = set, .set = set,
@ -123,32 +159,49 @@ AC_DEFUN([ZFS_AC_KERNEL_XATTR_HANDLER_SET], [
],[ ],[
],[ ],[
AC_MSG_RESULT(yes) AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_HANDLER_XATTR_SET, 1, AC_DEFINE(HAVE_XATTR_SET_DENTRY, 1,
[xattr_handler->set() wants xattr_handler]) [xattr_handler->set() wants dentry])
],[ ],[
dnl #
dnl # 2.6.32 API
dnl #
AC_MSG_RESULT(no) AC_MSG_RESULT(no)
AC_MSG_CHECKING(
[whether xattr_handler->set() wants inode])
ZFS_LINUX_TRY_COMPILE([
#include <linux/xattr.h>
int set(struct inode *ip, const char *name,
const void *buffer, size_t size, int flags)
{ return 0; }
static const struct xattr_handler
xops __attribute__ ((unused)) = {
.set = set,
};
],[
],[
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_XATTR_SET_INODE, 1,
[xattr_handler->set() wants inode])
],[
AC_MSG_ERROR([no; please file a bug report])
])
]) ])
]) ])
]) ])
dnl # dnl #
dnl # 2.6.33 API change, dnl # Supported xattr handler list() interfaces checked newest to oldest.
dnl # The xattr_hander->list() callback was changed to take a dentry
dnl # instead of an inode, and a handler_flags argument was added.
dnl #
dnl # 4.4 API change,
dnl # The xattr_hander->list() callback was changed to take a xattr_handler,
dnl # and handler_flags argument was removed and should be accessed by
dnl # handler->flags.
dnl # dnl #
AC_DEFUN([ZFS_AC_KERNEL_XATTR_HANDLER_LIST], [ AC_DEFUN([ZFS_AC_KERNEL_XATTR_HANDLER_LIST], [
AC_MSG_CHECKING([whether xattr_handler->list() wants dentry]) dnl # 4.5 API change,
dnl # The xattr_handler->list() callback was changed to take only a
dnl # dentry and it only needs to return if it's accessable.
AC_MSG_CHECKING([whether xattr_handler->list() wants simple])
ZFS_LINUX_TRY_COMPILE([ ZFS_LINUX_TRY_COMPILE([
#include <linux/xattr.h> #include <linux/xattr.h>
size_t list(struct dentry *dentry, char *list, size_t list_size, bool list(struct dentry *dentry) { return 0; }
const char *name, size_t name_len, int handler_flags)
{ return 0; }
static const struct xattr_handler static const struct xattr_handler
xops __attribute__ ((unused)) = { xops __attribute__ ((unused)) = {
.list = list, .list = list,
@ -156,16 +209,24 @@ AC_DEFUN([ZFS_AC_KERNEL_XATTR_HANDLER_LIST], [
],[ ],[
],[ ],[
AC_MSG_RESULT(yes) AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_DENTRY_XATTR_LIST, 1, AC_DEFINE(HAVE_XATTR_LIST_SIMPLE, 1,
[xattr_handler->list() wants dentry]) [xattr_handler->list() wants simple])
],[ ],[
dnl #
dnl # 4.4 API change,
dnl # The xattr_handler->list() callback was changed to take a
dnl # xattr_handler, and handler_flags argument was removed
dnl # and should be accessed by handler->flags.
dnl #
AC_MSG_RESULT(no) AC_MSG_RESULT(no)
AC_MSG_CHECKING([whether xattr_handler->list() wants xattr_handler]) AC_MSG_CHECKING(
[whether xattr_handler->list() wants xattr_handler])
ZFS_LINUX_TRY_COMPILE([ ZFS_LINUX_TRY_COMPILE([
#include <linux/xattr.h> #include <linux/xattr.h>
size_t list(const struct xattr_handler *handler, struct dentry *dentry, size_t list(const struct xattr_handler *handler,
char *list, size_t list_size, const char *name, size_t name_len) { return 0; } struct dentry *dentry, char *list, size_t list_size,
const char *name, size_t name_len) { return 0; }
static const struct xattr_handler static const struct xattr_handler
xops __attribute__ ((unused)) = { xops __attribute__ ((unused)) = {
.list = list, .list = list,
@ -173,10 +234,61 @@ AC_DEFUN([ZFS_AC_KERNEL_XATTR_HANDLER_LIST], [
],[ ],[
],[ ],[
AC_MSG_RESULT(yes) AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_HANDLER_XATTR_LIST, 1, AC_DEFINE(HAVE_XATTR_LIST_HANDLER, 1,
[xattr_handler->list() wants xattr_handler]) [xattr_handler->list() wants xattr_handler])
],[ ],[
dnl #
dnl # 2.6.33 API change,
dnl # The xattr_handler->list() callback was changed
dnl # to take a dentry instead of an inode, and a
dnl # handler_flags argument was added.
dnl #
AC_MSG_RESULT(no) AC_MSG_RESULT(no)
AC_MSG_CHECKING(
[whether xattr_handler->list() wants dentry])
ZFS_LINUX_TRY_COMPILE([
#include <linux/xattr.h>
size_t list(struct dentry *dentry,
char *list, size_t list_size,
const char *name, size_t name_len,
int handler_flags) { return 0; }
static const struct xattr_handler
xops __attribute__ ((unused)) = {
.list = list,
};
],[
],[
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_XATTR_LIST_DENTRY, 1,
[xattr_handler->list() wants dentry])
],[
dnl #
dnl # 2.6.32 API
dnl #
AC_MSG_RESULT(no)
AC_MSG_CHECKING(
[whether xattr_handler->list() wants inode])
ZFS_LINUX_TRY_COMPILE([
#include <linux/xattr.h>
size_t list(struct inode *ip, char *lst,
size_t list_size, const char *name,
size_t name_len) { return 0; }
static const struct xattr_handler
xops __attribute__ ((unused)) = {
.list = list,
};
],[
],[
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_XATTR_LIST_INODE, 1,
[xattr_handler->list() wants inode])
],[
AC_MSG_ERROR(
[no; please file a bug report])
])
])
]) ])
]) ])
]) ])

View File

@ -41,12 +41,86 @@ typedef const struct xattr_handler xattr_handler_t;
typedef struct xattr_handler xattr_handler_t; typedef struct xattr_handler xattr_handler_t;
#endif #endif
/*
* 3.7 API change,
* Preferred XATTR_NAME_* definitions introduced, these are mapped to
* the previous definitions for older kernels.
*/
#ifndef XATTR_NAME_POSIX_ACL_DEFAULT
#define XATTR_NAME_POSIX_ACL_DEFAULT POSIX_ACL_XATTR_DEFAULT
#endif
#ifndef XATTR_NAME_POSIX_ACL_ACCESS
#define XATTR_NAME_POSIX_ACL_ACCESS POSIX_ACL_XATTR_ACCESS
#endif
/*
* 4.5 API change,
*/
#if defined(HAVE_XATTR_LIST_SIMPLE)
#define ZPL_XATTR_LIST_WRAPPER(fn) \
static bool \
fn(struct dentry *dentry) \
{ \
return (!!__ ## fn(dentry->d_inode, NULL, 0, NULL, 0)); \
}
/*
* 4.4 API change,
*/
#elif defined(HAVE_XATTR_LIST_DENTRY)
#define ZPL_XATTR_LIST_WRAPPER(fn) \
static size_t \
fn(struct dentry *dentry, char *list, size_t list_size, \
const char *name, size_t name_len, int type) \
{ \
return (__ ## fn(dentry->d_inode, \
list, list_size, name, name_len)); \
}
/* /*
* 2.6.33 API change, * 2.6.33 API change,
* The xattr_hander->get() callback was changed to take a dentry */
#elif defined(HAVE_XATTR_LIST_HANDLER)
#define ZPL_XATTR_LIST_WRAPPER(fn) \
static size_t \
fn(const struct xattr_handler *handler, struct dentry *dentry, \
char *list, size_t list_size, const char *name, size_t name_len) \
{ \
return (__ ## fn(dentry->d_inode, \
list, list_size, name, name_len)); \
}
/*
* 2.6.32 API
*/
#elif defined(HAVE_XATTR_LIST_INODE)
#define ZPL_XATTR_LIST_WRAPPER(fn) \
static size_t \
fn(struct inode *ip, char *list, size_t list_size, \
const char *name, size_t name_len) \
{ \
return (__ ## fn(ip, list, list_size, name, name_len)); \
}
#endif
/*
* 4.4 API change,
* The xattr_handler->get() callback was changed to take a xattr_handler,
* and handler_flags argument was removed and should be accessed by
* handler->flags.
*/
#if defined(HAVE_XATTR_GET_HANDLER)
#define ZPL_XATTR_GET_WRAPPER(fn) \
static int \
fn(const struct xattr_handler *handler, struct dentry *dentry, \
const char *name, void *buffer, size_t size) \
{ \
return (__ ## fn(dentry->d_inode, name, buffer, size)); \
}
/*
* 2.6.33 API change,
* The xattr_handler->get() callback was changed to take a dentry
* instead of an inode, and a handler_flags argument was added. * instead of an inode, and a handler_flags argument was added.
*/ */
#ifdef HAVE_DENTRY_XATTR_GET #elif defined(HAVE_XATTR_GET_DENTRY)
#define ZPL_XATTR_GET_WRAPPER(fn) \ #define ZPL_XATTR_GET_WRAPPER(fn) \
static int \ static int \
fn(struct dentry *dentry, const char *name, void *buffer, size_t size, \ fn(struct dentry *dentry, const char *name, void *buffer, size_t size, \
@ -55,34 +129,37 @@ fn(struct dentry *dentry, const char *name, void *buffer, size_t size, \
return (__ ## fn(dentry->d_inode, name, buffer, size)); \ return (__ ## fn(dentry->d_inode, name, buffer, size)); \
} }
/* /*
* 4.4 API change, * 2.6.32 API
* The xattr_hander->get() callback was changed to take a xattr_handler,
* and handler_flags argument was removed and should be accessed by
* handler->flags.
*/ */
#elif defined(HAVE_HANDLER_XATTR_GET) #elif defined(HAVE_XATTR_GET_INODE)
#define ZPL_XATTR_GET_WRAPPER(fn) \
static int \
fn(const struct xattr_handler *handler, struct dentry *dentry, \
const char *name, void *buffer, size_t size) \
{ \
return (__ ## fn(dentry->d_inode, name, buffer, size)); \
}
#else
#define ZPL_XATTR_GET_WRAPPER(fn) \ #define ZPL_XATTR_GET_WRAPPER(fn) \
static int \ static int \
fn(struct inode *ip, const char *name, void *buffer, size_t size) \ fn(struct inode *ip, const char *name, void *buffer, size_t size) \
{ \ { \
return (__ ## fn(ip, name, buffer, size)); \ return (__ ## fn(ip, name, buffer, size)); \
} }
#endif /* HAVE_DENTRY_XATTR_GET */ #endif
/*
* 4.4 API change,
* The xattr_handler->set() callback was changed to take a xattr_handler,
* and handler_flags argument was removed and should be accessed by
* handler->flags.
*/
#if defined(HAVE_XATTR_SET_HANDLER)
#define ZPL_XATTR_SET_WRAPPER(fn) \
static int \
fn(const struct xattr_handler *handler, struct dentry *dentry, \
const char *name, const void *buffer, size_t size, int flags) \
{ \
return (__ ## fn(dentry->d_inode, name, buffer, size, flags)); \
}
/* /*
* 2.6.33 API change, * 2.6.33 API change,
* The xattr_hander->set() callback was changed to take a dentry * The xattr_handler->set() callback was changed to take a dentry
* instead of an inode, and a handler_flags argument was added. * instead of an inode, and a handler_flags argument was added.
*/ */
#ifdef HAVE_DENTRY_XATTR_SET #elif defined(HAVE_XATTR_SET_DENTRY)
#define ZPL_XATTR_SET_WRAPPER(fn) \ #define ZPL_XATTR_SET_WRAPPER(fn) \
static int \ static int \
fn(struct dentry *dentry, const char *name, const void *buffer, \ fn(struct dentry *dentry, const char *name, const void *buffer, \
@ -91,20 +168,9 @@ fn(struct dentry *dentry, const char *name, const void *buffer, \
return (__ ## fn(dentry->d_inode, name, buffer, size, flags)); \ return (__ ## fn(dentry->d_inode, name, buffer, size, flags)); \
} }
/* /*
* 4.4 API change, * 2.6.32 API
* The xattr_hander->set() callback was changed to take a xattr_handler,
* and handler_flags argument was removed and should be accessed by
* handler->flags.
*/ */
#elif defined(HAVE_HANDLER_XATTR_SET) #elif defined(HAVE_XATTR_SET_INODE)
#define ZPL_XATTR_SET_WRAPPER(fn) \
static int \
fn(const struct xattr_handler *handler, struct dentry *dentry, \
const char *name, const void *buffer, size_t size, int flags) \
{ \
return (__ ## fn(dentry->d_inode, name, buffer, size, flags)); \
}
#else
#define ZPL_XATTR_SET_WRAPPER(fn) \ #define ZPL_XATTR_SET_WRAPPER(fn) \
static int \ static int \
fn(struct inode *ip, const char *name, const void *buffer, \ fn(struct inode *ip, const char *name, const void *buffer, \
@ -112,7 +178,7 @@ fn(struct inode *ip, const char *name, const void *buffer, \
{ \ { \
return (__ ## fn(ip, name, buffer, size, flags)); \ return (__ ## fn(ip, name, buffer, size, flags)); \
} }
#endif /* HAVE_DENTRY_XATTR_SET */ #endif
#ifdef HAVE_6ARGS_SECURITY_INODE_INIT_SECURITY #ifdef HAVE_6ARGS_SECURITY_INODE_INIT_SECURITY
#define zpl_security_inode_init_security(ip, dip, qstr, nm, val, len) \ #define zpl_security_inode_init_security(ip, dip, qstr, nm, val, len) \

View File

@ -88,19 +88,50 @@ typedef struct xattr_filldir {
size_t size; size_t size;
size_t offset; size_t offset;
char *buf; char *buf;
struct inode *inode; struct dentry *dentry;
} xattr_filldir_t; } xattr_filldir_t;
static const struct xattr_handler *zpl_xattr_handler(const char *);
static int
zpl_xattr_permission(xattr_filldir_t *xf, const char *name, int name_len)
{
static const struct xattr_handler *handler;
struct dentry *d = xf->dentry;
handler = zpl_xattr_handler(name);
if (!handler)
return (0);
if (handler->list) {
#if defined(HAVE_XATTR_LIST_SIMPLE)
if (!handler->list(d))
return (0);
#elif defined(HAVE_XATTR_LIST_DENTRY)
if (!handler->list(d, NULL, 0, name, name_len, 0))
return (0);
#elif defined(HAVE_XATTR_LIST_HANDLER)
if (!handler->list(handler, d, NULL, 0, name, name_len))
return (0);
#elif defined(HAVE_XATTR_LIST_INODE)
if (!handler->list(d->d_inode, NULL, 0, name, name_len))
return (0);
#endif
}
return (1);
}
/*
* Determine is a given xattr name should be visible and if so copy it
* in to the provided buffer (xf->buf).
*/
static int static int
zpl_xattr_filldir(xattr_filldir_t *xf, const char *name, int name_len) zpl_xattr_filldir(xattr_filldir_t *xf, const char *name, int name_len)
{ {
if (strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) == 0) /* Check permissions using the per-namespace list xattr handler. */
if (!(ITOZSB(xf->inode)->z_flags & ZSB_XATTR)) if (!zpl_xattr_permission(xf, name, name_len))
return (0); return (0);
if (strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) == 0)
if (!capable(CAP_SYS_ADMIN))
return (0);
/* When xf->buf is NULL only calculate the required size. */ /* When xf->buf is NULL only calculate the required size. */
if (xf->buf) { if (xf->buf) {
@ -154,7 +185,7 @@ zpl_xattr_readdir(struct inode *dxip, xattr_filldir_t *xf)
static ssize_t static ssize_t
zpl_xattr_list_dir(xattr_filldir_t *xf, cred_t *cr) zpl_xattr_list_dir(xattr_filldir_t *xf, cred_t *cr)
{ {
struct inode *ip = xf->inode; struct inode *ip = xf->dentry->d_inode;
struct inode *dxip = NULL; struct inode *dxip = NULL;
int error; int error;
@ -176,7 +207,7 @@ zpl_xattr_list_dir(xattr_filldir_t *xf, cred_t *cr)
static ssize_t static ssize_t
zpl_xattr_list_sa(xattr_filldir_t *xf) zpl_xattr_list_sa(xattr_filldir_t *xf)
{ {
znode_t *zp = ITOZ(xf->inode); znode_t *zp = ITOZ(xf->dentry->d_inode);
nvpair_t *nvp = NULL; nvpair_t *nvp = NULL;
int error = 0; int error = 0;
@ -207,7 +238,7 @@ zpl_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size)
{ {
znode_t *zp = ITOZ(dentry->d_inode); znode_t *zp = ITOZ(dentry->d_inode);
zfs_sb_t *zsb = ZTOZSB(zp); zfs_sb_t *zsb = ZTOZSB(zp);
xattr_filldir_t xf = { buffer_size, 0, buffer, dentry->d_inode }; xattr_filldir_t xf = { buffer_size, 0, buffer, dentry };
cred_t *cr = CRED(); cred_t *cr = CRED();
fstrans_cookie_t cookie; fstrans_cookie_t cookie;
int error = 0; int error = 0;
@ -614,6 +645,43 @@ out:
return (error); return (error);
} }
/*
* Extended user attributes
*
* "Extended user attributes may be assigned to files and directories for
* storing arbitrary additional information such as the mime type,
* character set or encoding of a file. The access permissions for user
* attributes are defined by the file permission bits: read permission
* is required to retrieve the attribute value, and writer permission is
* required to change it.
*
* The file permission bits of regular files and directories are
* interpreted differently from the file permission bits of special
* files and symbolic links. For regular files and directories the file
* permission bits define access to the file's contents, while for
* device special files they define access to the device described by
* the special file. The file permissions of symbolic links are not
* used in access checks. These differences would allow users to
* consume filesystem resources in a way not controllable by disk quotas
* for group or world writable special files and directories.
*
* For this reason, extended user attributes are allowed only for
* regular files and directories, and access to extended user attributes
* is restricted to the owner and to users with appropriate capabilities
* for directories with the sticky bit set (see the chmod(1) manual page
* for an explanation of the sticky bit)." - xattr(7)
*
* ZFS allows extended user attributes to be disabled administratively
* by setting the 'xattr=off' property on the dataset.
*/
static int
__zpl_xattr_user_list(struct inode *ip, char *list, size_t list_size,
const char *name, size_t name_len)
{
return (ITOZSB(ip)->z_flags & ZSB_XATTR);
}
ZPL_XATTR_LIST_WRAPPER(zpl_xattr_user_list);
static int static int
__zpl_xattr_user_get(struct inode *ip, const char *name, __zpl_xattr_user_get(struct inode *ip, const char *name,
void *value, size_t size) void *value, size_t size)
@ -656,12 +724,31 @@ __zpl_xattr_user_set(struct inode *ip, const char *name,
} }
ZPL_XATTR_SET_WRAPPER(zpl_xattr_user_set); ZPL_XATTR_SET_WRAPPER(zpl_xattr_user_set);
xattr_handler_t zpl_xattr_user_handler = { xattr_handler_t zpl_xattr_user_handler =
{
.prefix = XATTR_USER_PREFIX, .prefix = XATTR_USER_PREFIX,
.list = zpl_xattr_user_list,
.get = zpl_xattr_user_get, .get = zpl_xattr_user_get,
.set = zpl_xattr_user_set, .set = zpl_xattr_user_set,
}; };
/*
* Trusted extended attributes
*
* "Trusted extended attributes are visible and accessible only to
* processes that have the CAP_SYS_ADMIN capability. Attributes in this
* class are used to implement mechanisms in user space (i.e., outside
* the kernel) which keep information in extended attributes to which
* ordinary processes should not have access." - xattr(7)
*/
static int
__zpl_xattr_trusted_list(struct inode *ip, char *list, size_t list_size,
const char *name, size_t name_len)
{
return (capable(CAP_SYS_ADMIN));
}
ZPL_XATTR_LIST_WRAPPER(zpl_xattr_trusted_list);
static int static int
__zpl_xattr_trusted_get(struct inode *ip, const char *name, __zpl_xattr_trusted_get(struct inode *ip, const char *name,
void *value, size_t size) void *value, size_t size)
@ -704,12 +791,34 @@ __zpl_xattr_trusted_set(struct inode *ip, const char *name,
} }
ZPL_XATTR_SET_WRAPPER(zpl_xattr_trusted_set); ZPL_XATTR_SET_WRAPPER(zpl_xattr_trusted_set);
xattr_handler_t zpl_xattr_trusted_handler = { xattr_handler_t zpl_xattr_trusted_handler =
{
.prefix = XATTR_TRUSTED_PREFIX, .prefix = XATTR_TRUSTED_PREFIX,
.list = zpl_xattr_trusted_list,
.get = zpl_xattr_trusted_get, .get = zpl_xattr_trusted_get,
.set = zpl_xattr_trusted_set, .set = zpl_xattr_trusted_set,
}; };
/*
* Extended security attributes
*
* "The security attribute namespace is used by kernel security modules,
* such as Security Enhanced Linux, and also to implement file
* capabilities (see capabilities(7)). Read and write access
* permissions to security attributes depend on the policy implemented
* for each security attribute by the security module. When no security
* module is loaded, all processes have read access to extended security
* attributes, and write access is limited to processes that have the
* CAP_SYS_ADMIN capability." - xattr(7)
*/
static int
__zpl_xattr_security_list(struct inode *ip, char *list, size_t list_size,
const char *name, size_t name_len)
{
return (1);
}
ZPL_XATTR_LIST_WRAPPER(zpl_xattr_security_list);
static int static int
__zpl_xattr_security_get(struct inode *ip, const char *name, __zpl_xattr_security_get(struct inode *ip, const char *name,
void *value, size_t size) void *value, size_t size)
@ -801,14 +910,25 @@ zpl_xattr_security_init(struct inode *ip, struct inode *dip,
} }
#endif /* HAVE_CALLBACK_SECURITY_INODE_INIT_SECURITY */ #endif /* HAVE_CALLBACK_SECURITY_INODE_INIT_SECURITY */
/*
* Security xattr namespace handlers.
*/
xattr_handler_t zpl_xattr_security_handler = { xattr_handler_t zpl_xattr_security_handler = {
.prefix = XATTR_SECURITY_PREFIX, .prefix = XATTR_SECURITY_PREFIX,
.list = zpl_xattr_security_list,
.get = zpl_xattr_security_get, .get = zpl_xattr_security_get,
.set = zpl_xattr_security_set, .set = zpl_xattr_security_set,
}; };
/*
* Extended system attributes
*
* "Extended system attributes are used by the kernel to store system
* objects such as Access Control Lists. Read and write access permissions
* to system attributes depend on the policy implemented for each system
* attribute implemented by filesystems in the kernel." - xattr(7)
*/
#ifdef CONFIG_FS_POSIX_ACL #ifdef CONFIG_FS_POSIX_ACL
int int
zpl_set_acl(struct inode *ip, int type, struct posix_acl *acl) zpl_set_acl(struct inode *ip, int type, struct posix_acl *acl)
{ {
@ -822,7 +942,7 @@ zpl_set_acl(struct inode *ip, int type, struct posix_acl *acl)
switch (type) { switch (type) {
case ACL_TYPE_ACCESS: case ACL_TYPE_ACCESS:
name = POSIX_ACL_XATTR_ACCESS; name = XATTR_NAME_POSIX_ACL_ACCESS;
if (acl) { if (acl) {
zpl_equivmode_t mode = ip->i_mode; zpl_equivmode_t mode = ip->i_mode;
error = posix_acl_equiv_mode(acl, &mode); error = posix_acl_equiv_mode(acl, &mode);
@ -849,7 +969,7 @@ zpl_set_acl(struct inode *ip, int type, struct posix_acl *acl)
break; break;
case ACL_TYPE_DEFAULT: case ACL_TYPE_DEFAULT:
name = POSIX_ACL_XATTR_DEFAULT; name = XATTR_NAME_POSIX_ACL_ACCESS;
if (!S_ISDIR(ip->i_mode)) if (!S_ISDIR(ip->i_mode))
return (acl ? -EACCES : 0); return (acl ? -EACCES : 0);
break; break;
@ -899,10 +1019,10 @@ zpl_get_acl(struct inode *ip, int type)
switch (type) { switch (type) {
case ACL_TYPE_ACCESS: case ACL_TYPE_ACCESS:
name = POSIX_ACL_XATTR_ACCESS; name = XATTR_NAME_POSIX_ACL_ACCESS;
break; break;
case ACL_TYPE_DEFAULT: case ACL_TYPE_DEFAULT:
name = POSIX_ACL_XATTR_DEFAULT; name = XATTR_NAME_POSIX_ACL_DEFAULT;
break; break;
default: default:
return (ERR_PTR(-EINVAL)); return (ERR_PTR(-EINVAL));
@ -1051,101 +1171,46 @@ zpl_chmod_acl(struct inode *ip)
return (error); return (error);
} }
static size_t static int
zpl_xattr_acl_list(struct inode *ip, char *list, size_t list_size, __zpl_xattr_acl_list_access(struct inode *ip, char *list, size_t list_size,
const char *name, size_t name_len, int type) const char *name, size_t name_len)
{ {
char *xattr_name; char *xattr_name = XATTR_NAME_POSIX_ACL_ACCESS;
size_t xattr_size; size_t xattr_size = sizeof (XATTR_NAME_POSIX_ACL_ACCESS);
if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIXACL) if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIXACL)
return (0); return (0);
switch (type) {
case ACL_TYPE_ACCESS:
xattr_name = POSIX_ACL_XATTR_ACCESS;
xattr_size = sizeof (xattr_name);
break;
case ACL_TYPE_DEFAULT:
xattr_name = POSIX_ACL_XATTR_DEFAULT;
xattr_size = sizeof (xattr_name);
break;
default:
return (0);
}
if (list && xattr_size <= list_size) if (list && xattr_size <= list_size)
memcpy(list, xattr_name, xattr_size); memcpy(list, xattr_name, xattr_size);
return (xattr_size); return (xattr_size);
} }
ZPL_XATTR_LIST_WRAPPER(zpl_xattr_acl_list_access);
#ifdef HAVE_DENTRY_XATTR_LIST
static size_t
zpl_xattr_acl_list_access(struct dentry *dentry, char *list,
size_t list_size, const char *name, size_t name_len, int type)
{
ASSERT3S(type, ==, ACL_TYPE_ACCESS);
return zpl_xattr_acl_list(dentry->d_inode,
list, list_size, name, name_len, type);
}
static size_t
zpl_xattr_acl_list_default(struct dentry *dentry, char *list,
size_t list_size, const char *name, size_t name_len, int type)
{
ASSERT3S(type, ==, ACL_TYPE_DEFAULT);
return zpl_xattr_acl_list(dentry->d_inode,
list, list_size, name, name_len, type);
}
#elif defined(HAVE_HANDLER_XATTR_LIST)
static size_t
zpl_xattr_acl_list_access(const struct xattr_handler *handler,
struct dentry *dentry, char *list, size_t list_size, const char *name,
size_t name_len)
{
int type = handler->flags;
ASSERT3S(type, ==, ACL_TYPE_ACCESS);
return zpl_xattr_acl_list(dentry->d_inode,
list, list_size, name, name_len, type);
}
static size_t
zpl_xattr_acl_list_default(const struct xattr_handler *handler,
struct dentry *dentry, char *list, size_t list_size, const char *name,
size_t name_len)
{
int type = handler->flags;
ASSERT3S(type, ==, ACL_TYPE_DEFAULT);
return zpl_xattr_acl_list(dentry->d_inode,
list, list_size, name, name_len, type);
}
#else
static size_t
zpl_xattr_acl_list_access(struct inode *ip, char *list, size_t list_size,
const char *name, size_t name_len)
{
return zpl_xattr_acl_list(ip,
list, list_size, name, name_len, ACL_TYPE_ACCESS);
}
static size_t
zpl_xattr_acl_list_default(struct inode *ip, char *list, size_t list_size,
const char *name, size_t name_len)
{
return zpl_xattr_acl_list(ip,
list, list_size, name, name_len, ACL_TYPE_DEFAULT);
}
#endif /* HAVE_DENTRY_XATTR_LIST */
static int static int
zpl_xattr_acl_get(struct inode *ip, const char *name, __zpl_xattr_acl_list_default(struct inode *ip, char *list, size_t list_size,
void *buffer, size_t size, int type) const char *name, size_t name_len)
{
char *xattr_name = XATTR_NAME_POSIX_ACL_DEFAULT;
size_t xattr_size = sizeof (XATTR_NAME_POSIX_ACL_DEFAULT);
if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIXACL)
return (0);
if (list && xattr_size <= list_size)
memcpy(list, xattr_name, xattr_size);
return (xattr_size);
}
ZPL_XATTR_LIST_WRAPPER(zpl_xattr_acl_list_default);
static int
__zpl_xattr_acl_get_access(struct inode *ip, const char *name,
void *buffer, size_t size)
{ {
struct posix_acl *acl; struct posix_acl *acl;
int type = ACL_TYPE_ACCESS;
int error; int error;
if (strcmp(name, "") != 0) if (strcmp(name, "") != 0)
@ -1165,65 +1230,41 @@ zpl_xattr_acl_get(struct inode *ip, const char *name,
return (error); return (error);
} }
ZPL_XATTR_GET_WRAPPER(zpl_xattr_acl_get_access);
#ifdef HAVE_DENTRY_XATTR_GET
static int
zpl_xattr_acl_get_access(struct dentry *dentry, const char *name,
void *buffer, size_t size, int type)
{
ASSERT3S(type, ==, ACL_TYPE_ACCESS);
return (zpl_xattr_acl_get(dentry->d_inode, name, buffer, size, type));
}
static int static int
zpl_xattr_acl_get_default(struct dentry *dentry, const char *name, __zpl_xattr_acl_get_default(struct inode *ip, const char *name,
void *buffer, size_t size, int type)
{
ASSERT3S(type, ==, ACL_TYPE_DEFAULT);
return (zpl_xattr_acl_get(dentry->d_inode, name, buffer, size, type));
}
#elif defined(HAVE_HANDLER_XATTR_GET)
static int
zpl_xattr_acl_get_access(const struct xattr_handler *handler,
struct dentry *dentry, const char *name, void *buffer, size_t size)
{
int type = handler->flags;
ASSERT3S(type, ==, ACL_TYPE_ACCESS);
return (zpl_xattr_acl_get(dentry->d_inode, name, buffer, size, type));
}
static int
zpl_xattr_acl_get_default(const struct xattr_handler *handler,
struct dentry *dentry, const char *name, void *buffer, size_t size)
{
int type = handler->flags;
ASSERT3S(type, ==, ACL_TYPE_DEFAULT);
return (zpl_xattr_acl_get(dentry->d_inode, name, buffer, size, type));
}
#else
static int
zpl_xattr_acl_get_access(struct inode *ip, const char *name,
void *buffer, size_t size) void *buffer, size_t size)
{
return (zpl_xattr_acl_get(ip, name, buffer, size, ACL_TYPE_ACCESS));
}
static int
zpl_xattr_acl_get_default(struct inode *ip, const char *name,
void *buffer, size_t size)
{
return (zpl_xattr_acl_get(ip, name, buffer, size, ACL_TYPE_DEFAULT));
}
#endif /* HAVE_DENTRY_XATTR_GET */
static int
zpl_xattr_acl_set(struct inode *ip, const char *name,
const void *value, size_t size, int flags, int type)
{ {
struct posix_acl *acl; struct posix_acl *acl;
int type = ACL_TYPE_DEFAULT;
int error;
if (strcmp(name, "") != 0)
return (-EINVAL);
if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIXACL)
return (-EOPNOTSUPP);
acl = zpl_get_acl(ip, type);
if (IS_ERR(acl))
return (PTR_ERR(acl));
if (acl == NULL)
return (-ENODATA);
error = zpl_acl_to_xattr(acl, buffer, size);
zpl_posix_acl_release(acl);
return (error);
}
ZPL_XATTR_GET_WRAPPER(zpl_xattr_acl_get_default);
static int
__zpl_xattr_acl_set_access(struct inode *ip, const char *name,
const void *value, size_t size, int flags)
{
struct posix_acl *acl;
int type = ACL_TYPE_ACCESS;
int error = 0; int error = 0;
if (strcmp(name, "") != 0) if (strcmp(name, "") != 0)
@ -1255,88 +1296,77 @@ zpl_xattr_acl_set(struct inode *ip, const char *name,
return (error); return (error);
} }
ZPL_XATTR_SET_WRAPPER(zpl_xattr_acl_set_access);
#ifdef HAVE_DENTRY_XATTR_SET
static int
zpl_xattr_acl_set_access(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags, int type)
{
ASSERT3S(type, ==, ACL_TYPE_ACCESS);
return (zpl_xattr_acl_set(dentry->d_inode,
name, value, size, flags, type));
}
static int static int
zpl_xattr_acl_set_default(struct dentry *dentry, const char *name, __zpl_xattr_acl_set_default(struct inode *ip, const char *name,
const void *value, size_t size, int flags, int type)
{
ASSERT3S(type, ==, ACL_TYPE_DEFAULT);
return zpl_xattr_acl_set(dentry->d_inode,
name, value, size, flags, type);
}
#elif defined(HAVE_HANDLER_XATTR_SET)
static int
zpl_xattr_acl_set_access(const struct xattr_handler *handler,
struct dentry *dentry, const char *name, const void *value, size_t size,
int flags)
{
int type = handler->flags;
ASSERT3S(type, ==, ACL_TYPE_ACCESS);
return (zpl_xattr_acl_set(dentry->d_inode,
name, value, size, flags, type));
}
static int
zpl_xattr_acl_set_default(const struct xattr_handler *handler,
struct dentry *dentry, const char *name, const void *value, size_t size,
int flags)
{
int type = handler->flags;
ASSERT3S(type, ==, ACL_TYPE_DEFAULT);
return zpl_xattr_acl_set(dentry->d_inode,
name, value, size, flags, type);
}
#else
static int
zpl_xattr_acl_set_access(struct inode *ip, const char *name,
const void *value, size_t size, int flags) const void *value, size_t size, int flags)
{ {
return zpl_xattr_acl_set(ip, struct posix_acl *acl;
name, value, size, flags, ACL_TYPE_ACCESS); int type = ACL_TYPE_DEFAULT;
} int error = 0;
static int if (strcmp(name, "") != 0)
zpl_xattr_acl_set_default(struct inode *ip, const char *name, return (-EINVAL);
const void *value, size_t size, int flags)
{
return zpl_xattr_acl_set(ip,
name, value, size, flags, ACL_TYPE_DEFAULT);
}
#endif /* HAVE_DENTRY_XATTR_SET */
struct xattr_handler zpl_xattr_acl_access_handler = if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIXACL)
return (-EOPNOTSUPP);
if (!zpl_inode_owner_or_capable(ip))
return (-EPERM);
if (value) {
acl = zpl_acl_from_xattr(value, size);
if (IS_ERR(acl))
return (PTR_ERR(acl));
else if (acl) {
error = posix_acl_valid(acl);
if (error) {
zpl_posix_acl_release(acl);
return (error);
}
}
} else {
acl = NULL;
}
error = zpl_set_acl(ip, type, acl);
zpl_posix_acl_release(acl);
return (error);
}
ZPL_XATTR_SET_WRAPPER(zpl_xattr_acl_set_default);
/*
* ACL access xattr namespace handlers.
*/
xattr_handler_t zpl_xattr_acl_access_handler =
{ {
.prefix = POSIX_ACL_XATTR_ACCESS, .prefix = XATTR_NAME_POSIX_ACL_ACCESS,
.list = zpl_xattr_acl_list_access, .list = zpl_xattr_acl_list_access,
.get = zpl_xattr_acl_get_access, .get = zpl_xattr_acl_get_access,
.set = zpl_xattr_acl_set_access, .set = zpl_xattr_acl_set_access,
#if defined(HAVE_DENTRY_XATTR_LIST) || defined(HAVE_HANDLER_XATTR_LIST) #if defined(HAVE_XATTR_LIST_SIMPLE) || \
defined(HAVE_XATTR_LIST_DENTRY) || \
defined(HAVE_XATTR_LIST_HANDLER)
.flags = ACL_TYPE_ACCESS, .flags = ACL_TYPE_ACCESS,
#endif /* HAVE_DENTRY_XATTR_LIST */ #endif
}; };
struct xattr_handler zpl_xattr_acl_default_handler = /*
* ACL default xattr namespace handlers.
*/
xattr_handler_t zpl_xattr_acl_default_handler =
{ {
.prefix = POSIX_ACL_XATTR_DEFAULT, .prefix = XATTR_NAME_POSIX_ACL_DEFAULT,
.list = zpl_xattr_acl_list_default, .list = zpl_xattr_acl_list_default,
.get = zpl_xattr_acl_get_default, .get = zpl_xattr_acl_get_default,
.set = zpl_xattr_acl_set_default, .set = zpl_xattr_acl_set_default,
#if defined(HAVE_DENTRY_XATTR_LIST) || defined(HAVE_HANDLER_XATTR_LIST) #if defined(HAVE_XATTR_LIST_SIMPLE) || \
defined(HAVE_XATTR_LIST_DENTRY) || \
defined(HAVE_XATTR_LIST_HANDLER)
.flags = ACL_TYPE_DEFAULT, .flags = ACL_TYPE_DEFAULT,
#endif /* HAVE_DENTRY_XATTR_LIST */ #endif
}; };
#endif /* CONFIG_FS_POSIX_ACL */ #endif /* CONFIG_FS_POSIX_ACL */
@ -1351,3 +1381,31 @@ xattr_handler_t *zpl_xattr_handlers[] = {
#endif /* CONFIG_FS_POSIX_ACL */ #endif /* CONFIG_FS_POSIX_ACL */
NULL NULL
}; };
static const struct xattr_handler *
zpl_xattr_handler(const char *name)
{
if (strncmp(name, XATTR_USER_PREFIX,
XATTR_USER_PREFIX_LEN) == 0)
return (&zpl_xattr_user_handler);
if (strncmp(name, XATTR_TRUSTED_PREFIX,
XATTR_TRUSTED_PREFIX_LEN) == 0)
return (&zpl_xattr_trusted_handler);
if (strncmp(name, XATTR_SECURITY_PREFIX,
XATTR_SECURITY_PREFIX_LEN) == 0)
return (&zpl_xattr_security_handler);
#ifdef CONFIG_FS_POSIX_ACL
if (strncmp(name, XATTR_NAME_POSIX_ACL_ACCESS,
sizeof (XATTR_NAME_POSIX_ACL_ACCESS)) == 0)
return (&zpl_xattr_acl_access_handler);
if (strncmp(name, XATTR_NAME_POSIX_ACL_DEFAULT,
sizeof (XATTR_NAME_POSIX_ACL_DEFAULT)) == 0)
return (&zpl_xattr_acl_default_handler);
#endif /* CONFIG_FS_POSIX_ACL */
return (NULL);
}