Skip to content

Commit

Permalink
Implement File Attribute Support
Browse files Browse the repository at this point in the history
We add support for lsattr and chattr. Only attributes common to both
Solaris and Linux are supported. These are 'a', 'd' and 'i'. File
attributes exclusive to Solaris are present in the ZFS code, but cannot
be accessed or modified through this method. That was the case prior to
this patch.

This commit removes the ZFS_IOC_GETFLAGS and ZFS_IOC_SETFLAGS macros in
recognition that this is not equivalent to the Solaris operation. The
resolution of issue openzfs#229 should implement something
equivalent that will permit access and modification of Solaris-specific
attributes.

This resolves a regression caused by
88c2839 that broke python's
xattr.list(). This broke Gentoo Portage's FEATURES=xattr, which depended
on this.

https://bugs.gentoo.org/show_bug.cgi?id=483516
Issue openzfs#1691

Original-patch-by: Brian Behlendorf <[email protected]>
Signed-off-by: Richard Yao <[email protected]>
  • Loading branch information
ryao committed Dec 29, 2013
1 parent e9f5cb8 commit 6964051
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 6 deletions.
30 changes: 30 additions & 0 deletions config/kernel-is_owner_or_cap.m4
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
dnl #
dnl # 2.6.39 API change
dnl # is_owner_or_cap() was renamed to inode_owner_or_capable().
dnl #
AC_DEFUN([ZFS_AC_KERNEL_INODE_OWNER_OR_CAPABLE], [
AC_MSG_CHECKING([whether inode_owner_or_capable() exists])
ZFS_LINUX_TRY_COMPILE([
#include <linux/fs.h>
],[
struct inode *ip = NULL;
inode_owner_or_capable(ip);
],[
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_INODE_OWNER_OR_CAPABLE, 1, [inode_owner_or_capable() exists])
],[
AC_MSG_RESULT(no)
AC_MSG_CHECKING([whether is_owner_or_cap() exists])
ZFS_LINUX_TRY_COMPILE([
#include <linux/fs.h>
],[
struct inode *ip = NULL;
is_owner_or_cap(ip);
],[
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_IS_OWNER_OR_CAP, 1, [is_owner_or_cap() exists])
],[
AC_MSG_ERROR(no; file a bug report with ZFSOnLinux)
])
])
])
1 change: 1 addition & 0 deletions config/kernel.m4
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ AC_DEFUN([ZFS_AC_CONFIG_KERNEL], [
ZFS_AC_KERNEL_5ARG_SGET
ZFS_AC_KERNEL_LSEEK_EXECUTE
ZFS_AC_KERNEL_VFS_ITERATE
ZFS_AC_KERNEL_INODE_OWNER_OR_CAPABLE
AS_IF([test "$LINUX_OBJ" != "$LINUX"], [
KERNELMAKE_PARAMS="$KERNELMAKE_PARAMS O=$LINUX_OBJ"
Expand Down
3 changes: 0 additions & 3 deletions include/linux/vfs_compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,6 @@ typedef int zpl_umode_t;
#define zpl_sget(type, cmp, set, fl, mtd) sget(type, cmp, set, mtd)
#endif /* HAVE_5ARG_SGET */

#define ZFS_IOC_GETFLAGS FS_IOC_GETFLAGS
#define ZFS_IOC_SETFLAGS FS_IOC_SETFLAGS

#if defined(SEEK_HOLE) && defined(SEEK_DATA) && !defined(HAVE_LSEEK_EXECUTE)
static inline loff_t
lseek_execute(
Expand Down
96 changes: 93 additions & 3 deletions module/zfs/zpl_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -520,13 +520,103 @@ zpl_fallocate(struct file *filp, int mode, loff_t offset, loff_t len)
}
#endif /* HAVE_FILE_FALLOCATE */

/*
* Map zfs file z_pflags (xvattr_t) to linux file attributes. Only file
* attributes common to both Linux and Solaris are mapped.
*/
static int
zpl_ioctl_getflags(struct file *filp, void __user *arg)
{
struct inode *ip = filp->f_dentry->d_inode;
unsigned int ioctl_flags = 0;
uint64_t zfs_flags = ITOZ(ip)->z_pflags;
int error;

if (zfs_flags & ZFS_IMMUTABLE)
ioctl_flags |= FS_IMMUTABLE_FL;

if (zfs_flags & ZFS_APPENDONLY)
ioctl_flags |= FS_APPEND_FL;

if (zfs_flags & ZFS_NODUMP)
ioctl_flags |= FS_NODUMP_FL;

ioctl_flags &= FS_FL_USER_VISIBLE;

error = copy_to_user(arg, &ioctl_flags, sizeof(ioctl_flags));

return (error);
}

static int
zpl_ioctl_setflags(struct file *filp, void __user *arg)
{
struct inode *ip = filp->f_dentry->d_inode;
znode_t *zp = ITOZ(ip);
unsigned int ioctl_flags;
uint64_t zfs_flags, old_zfs_flags;
cred_t *cr = CRED();
xvattr_t xva;
int error;

if (copy_from_user(&ioctl_flags, arg, sizeof(ioctl_flags)))
return (-EFAULT);

if ((ioctl_flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | FS_NODUMP_FL)))
return (-EOPNOTSUPP);

if ((ioctl_flags & ~(FS_FL_USER_MODIFIABLE)))
return (-EACCES);

if ((ioctl_flags & (FS_IMMUTABLE_FL | FS_APPEND_FL)
&& !capable(CAP_LINUX_IMMUTABLE)))
return (-EACCES);

#ifdef HAVE_INODE_OWNER_OR_CAPABLE
if (!inode_owner_or_capable(ip))
#else
if (!is_owner_or_cap(ip))
#endif
return (-EACCES);

xva_init(&xva);
zfs_flags = old_zfs_flags = ITOZ(ip)->z_pflags;

if (ioctl_flags & FS_IMMUTABLE_FL)
zfs_flags |= ZFS_IMMUTABLE;
else
zfs_flags &= ~ZFS_IMMUTABLE;

if (ioctl_flags & FS_APPEND_FL)
zfs_flags |= ZFS_APPENDONLY;
else
zfs_flags &= ~ZFS_APPENDONLY;

if (ioctl_flags & FS_NODUMP_FL)
zfs_flags |= ZFS_NODUMP;
else
zfs_flags &= ~ZFS_NODUMP;

zp->z_pflags = zfs_flags;

crhold(cr);
error = -zfs_setattr(ip, (vattr_t *)&xva, 0, cr);
crfree(cr);

if (error)
zp->z_pflags = old_zfs_flags;

return (error);
}

static long
zpl_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
switch (cmd) {
case ZFS_IOC_GETFLAGS:
case ZFS_IOC_SETFLAGS:
return (-EOPNOTSUPP);
case FS_IOC_GETFLAGS:
return zpl_ioctl_getflags(filp, (void *)arg);
case FS_IOC_SETFLAGS:
return zpl_ioctl_setflags(filp, (void *)arg);
default:
return (-ENOTTY);
}
Expand Down

0 comments on commit 6964051

Please sign in to comment.