-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
We add support for lsattr and chattr to resolve a regression caused by 88c2839 that broke Python's xattr.list(). That changet broke Gentoo Portage's FEATURES=xattr, which depended on Python's xattr.list(). Only attributes common to both Solaris and Linux are supported. These are 'a', 'd' and 'i' in Linux's lsattr and chattr commands. 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. The resolution of issue openzfs#229 should implement some method to permit access and modification of Solaris-specific attributes. 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
There are no files selected for viewing
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) | ||
]) | ||
]) | ||
]) | ||
This comment has been minimized.
Sorry, something went wrong. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -446,6 +446,25 @@ zfs_znode_alloc(zfs_sb_t *zsb, dmu_buf_t *db, int blksz, | |
return (NULL); | ||
} | ||
|
||
void | ||
zfs_set_inode_flags(znode_t *zp, struct inode *ip) | ||
{ | ||
/* | ||
* Linux and Solaris have different sets of file attributes, so we | ||
* restrict this conversion to the intersection of the two. | ||
*/ | ||
|
||
if (zp->z_pflags & ZFS_IMMUTABLE) | ||
ip->i_flags |= S_IMMUTABLE; | ||
else | ||
ip->i_flags &= ~S_IMMUTABLE; | ||
|
||
if (zp->z_pflags & ZFS_APPENDONLY) | ||
ip->i_flags |= S_APPEND; | ||
else | ||
ip->i_flags &= ~S_APPEND; | ||
} | ||
|
||
/* | ||
* Update the embedded inode given the znode. We should work toward | ||
* eliminating this function as soon as possible by removing values | ||
|
@@ -479,6 +498,7 @@ zfs_inode_update(znode_t *zp) | |
ip->i_gid = SGID_TO_KGID(zp->z_gid); | ||
set_nlink(ip, zp->z_links); | ||
ip->i_mode = zp->z_mode; | ||
zfs_set_inode_flags(zp, ip); | ||
ip->i_blkbits = SPA_MINBLOCKSHIFT; | ||
dmu_object_size_from_db(sa_get_db(zp->z_sa_hdl), &blksize, | ||
(u_longlong_t *)&ip->i_blocks); | ||
|
@@ -849,6 +869,18 @@ zfs_xvattr_set(znode_t *zp, xvattr_t *xvap, dmu_tx_t *tx) | |
zp->z_pflags, tx); | ||
XVA_SET_RTN(xvap, XAT_SPARSE); | ||
} | ||
|
||
/* | ||
* The Solaris VFS gives filesystem drivers full control over how file | ||
* attributes are stored inside the kernel, but the Linux VFS stores | ||
* some of this inside the inode structure, so we must update it to | ||
* keep things in sync. | ||
*/ | ||
#ifdef __linux__ | ||
spin_lock(&ZTOI(zp)->i_lock); | ||
zfs_set_inode_flags(zp, ZTOI(zp)); | ||
spin_unlock(&ZTOI(zp)->i_lock); | ||
#endif | ||
This comment has been minimized.
Sorry, something went wrong.
behlendorf
|
||
} | ||
|
||
int | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -520,13 +520,99 @@ 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); | ||
} | ||
|
||
#define fchange(f0, f1, b0, b1) ((((f0) & (b0)) == (b0)) != \ | ||
(((b1) & (f1)) == (f1))) | ||
This comment has been minimized.
Sorry, something went wrong.
behlendorf
|
||
|
||
static int | ||
zpl_ioctl_setflags(struct file *filp, void __user *arg) | ||
{ | ||
struct inode *ip = filp->f_dentry->d_inode; | ||
uint64_t zfs_flags = ITOZ(ip)->z_pflags; | ||
unsigned int ioctl_flags; | ||
cred_t *cr = CRED(); | ||
xvattr_t xva; | ||
xoptattr_t *xoap; | ||
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 ((fchange(ioctl_flags, zfs_flags, FS_IMMUTABLE_FL, ZFS_IMMUTABLE) || | ||
fchange(ioctl_flags, zfs_flags, FS_APPEND_FL, ZFS_APPENDONLY)) && | ||
!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 | ||
This comment has been minimized.
Sorry, something went wrong.
behlendorf
|
||
return (-EACCES); | ||
|
||
xva_init(&xva); | ||
xoap = xva_getxoptattr(&xva); | ||
|
||
XVA_SET_REQ(&xva, XAT_IMMUTABLE); | ||
if (ioctl_flags & FS_IMMUTABLE_FL) | ||
xoap->xoa_immutable = B_TRUE; | ||
|
||
XVA_SET_REQ(&xva, XAT_APPENDONLY); | ||
if (ioctl_flags & FS_APPEND_FL) | ||
xoap->xoa_appendonly = B_TRUE; | ||
|
||
XVA_SET_REQ(&xva, XAT_NODUMP); | ||
if (ioctl_flags & FS_NODUMP_FL) | ||
xoap->xoa_nodump = B_TRUE; | ||
|
||
crhold(cr); | ||
error = -zfs_setattr(ip, (vattr_t *)&xva, 0, cr); | ||
crfree(cr); | ||
|
||
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); | ||
} | ||
|
This test is redundant with ZFS_AC_KERNEL_INODE_OWNER_OR_CAPABLE in config/kernel-xattr-handler.m4. However, I do like yours better and now that there's a non xattr consumer it makes sense to move it to it's own m4 file.