@@ -811,28 +811,44 @@ zpl_fadvise(struct file *filp, loff_t offset, loff_t len, int advice)
811811 return (error );
812812}
813813
814- #define ZFS_FL_USER_VISIBLE (FS_FL_USER_VISIBLE | ZFS_PROJINHERIT_FL)
815- #define ZFS_FL_USER_MODIFIABLE (FS_FL_USER_MODIFIABLE | ZFS_PROJINHERIT_FL)
814+ #define ZFS_FL_USER_VISIBLE (FS_FL_USER_VISIBLE | FS_PROJINHERIT_FL)
815+ #define ZFS_FL_USER_MODIFIABLE (FS_FL_USER_MODIFIABLE | FS_PROJINHERIT_FL)
816+
817+
818+ static struct {
819+ uint64_t zfs_flag ;
820+ uint32_t fs_flag ;
821+ uint32_t xflag ;
822+ } flags_lookup [] = {
823+ {ZFS_IMMUTABLE , FS_IMMUTABLE_FL , FS_XFLAG_IMMUTABLE },
824+ {ZFS_APPENDONLY , FS_APPEND_FL , FS_XFLAG_APPEND },
825+ {ZFS_NODUMP , FS_NODUMP_FL , FS_XFLAG_NODUMP },
826+ {ZFS_PROJINHERIT , FS_PROJINHERIT_FL , FS_XFLAG_PROJINHERIT }
827+ };
816828
817829static uint32_t
818830__zpl_ioctl_getflags (struct inode * ip )
819831{
820832 uint64_t zfs_flags = ITOZ (ip )-> z_pflags ;
821833 uint32_t ioctl_flags = 0 ;
834+ for (int i = 0 ; i < ARRAY_SIZE (flags_lookup ); i ++ )
835+ if (zfs_flags & flags_lookup [i ].zfs_flag )
836+ ioctl_flags |= flags_lookup [i ].fs_flag ;
822837
823- if (zfs_flags & ZFS_IMMUTABLE )
824- ioctl_flags |= FS_IMMUTABLE_FL ;
825-
826- if (zfs_flags & ZFS_APPENDONLY )
827- ioctl_flags |= FS_APPEND_FL ;
838+ return (ioctl_flags );
839+ }
828840
829- if (zfs_flags & ZFS_NODUMP )
830- ioctl_flags |= FS_NODUMP_FL ;
841+ static uint32_t
842+ __zpl_ioctl_getxflags (struct inode * ip )
843+ {
844+ uint64_t zfs_flags = ITOZ (ip )-> z_pflags ;
845+ uint32_t ioctl_flags = 0 ;
831846
832- if (zfs_flags & ZFS_PROJINHERIT )
833- ioctl_flags |= ZFS_PROJINHERIT_FL ;
847+ for (int i = 0 ; i < ARRAY_SIZE (flags_lookup ); i ++ )
848+ if (zfs_flags & flags_lookup [i ].zfs_flag )
849+ ioctl_flags |= flags_lookup [i ].xflag ;
834850
835- return (ioctl_flags & ZFS_FL_USER_VISIBLE );
851+ return (ioctl_flags );
836852}
837853
838854/*
@@ -846,6 +862,7 @@ zpl_ioctl_getflags(struct file *filp, void __user *arg)
846862 int err ;
847863
848864 flags = __zpl_ioctl_getflags (file_inode (filp ));
865+ flags = flags & ZFS_FL_USER_VISIBLE ;
849866 err = copy_to_user (arg , & flags , sizeof (flags ));
850867
851868 return (err );
@@ -869,7 +886,7 @@ __zpl_ioctl_setflags(struct inode *ip, uint32_t ioctl_flags, xvattr_t *xva)
869886 xoptattr_t * xoap ;
870887
871888 if (ioctl_flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | FS_NODUMP_FL |
872- ZFS_PROJINHERIT_FL ))
889+ FS_PROJINHERIT_FL ))
873890 return (- EOPNOTSUPP );
874891
875892 if (ioctl_flags & ~ZFS_FL_USER_MODIFIABLE )
@@ -900,7 +917,51 @@ __zpl_ioctl_setflags(struct inode *ip, uint32_t ioctl_flags, xvattr_t *xva)
900917 xoap -> xoa_appendonly );
901918 FLAG_CHANGE (FS_NODUMP_FL , ZFS_NODUMP , XAT_NODUMP ,
902919 xoap -> xoa_nodump );
903- FLAG_CHANGE (ZFS_PROJINHERIT_FL , ZFS_PROJINHERIT , XAT_PROJINHERIT ,
920+ FLAG_CHANGE (FS_PROJINHERIT_FL , ZFS_PROJINHERIT , XAT_PROJINHERIT ,
921+ xoap -> xoa_projinherit );
922+
923+ #undef FLAG_CHANGE
924+
925+ return (0 );
926+ }
927+
928+ static int
929+ __zpl_ioctl_setxflags (struct inode * ip , uint32_t ioctl_flags , xvattr_t * xva )
930+ {
931+ uint64_t zfs_flags = ITOZ (ip )-> z_pflags ;
932+ xoptattr_t * xoap ;
933+
934+ if (ioctl_flags & ~(FS_XFLAG_IMMUTABLE | FS_XFLAG_APPEND |
935+ FS_XFLAG_NODUMP | FS_XFLAG_PROJINHERIT ))
936+ return (- EOPNOTSUPP );
937+
938+ if ((fchange (ioctl_flags , zfs_flags , FS_XFLAG_IMMUTABLE ,
939+ ZFS_IMMUTABLE ) ||
940+ fchange (ioctl_flags , zfs_flags , FS_XFLAG_APPEND , ZFS_APPENDONLY )) &&
941+ !capable (CAP_LINUX_IMMUTABLE ))
942+ return (- EPERM );
943+
944+ if (!zpl_inode_owner_or_capable (zfs_init_idmap , ip ))
945+ return (- EACCES );
946+
947+ xva_init (xva );
948+ xoap = xva_getxoptattr (xva );
949+
950+ #define FLAG_CHANGE (iflag , zflag , xflag , xfield ) do { \
951+ if (((ioctl_flags & (iflag)) && !(zfs_flags & (zflag))) || \
952+ ((zfs_flags & (zflag)) && !(ioctl_flags & (iflag)))) { \
953+ XVA_SET_REQ(xva, (xflag)); \
954+ (xfield) = ((ioctl_flags & (iflag)) != 0); \
955+ } \
956+ } while (0)
957+
958+ FLAG_CHANGE (FS_XFLAG_IMMUTABLE , ZFS_IMMUTABLE , XAT_IMMUTABLE ,
959+ xoap -> xoa_immutable );
960+ FLAG_CHANGE (FS_XFLAG_APPEND , ZFS_APPENDONLY , XAT_APPENDONLY ,
961+ xoap -> xoa_appendonly );
962+ FLAG_CHANGE (FS_XFLAG_NODUMP , ZFS_NODUMP , XAT_NODUMP ,
963+ xoap -> xoa_nodump );
964+ FLAG_CHANGE (FS_XFLAG_PROJINHERIT , ZFS_PROJINHERIT , XAT_PROJINHERIT ,
904965 xoap -> xoa_projinherit );
905966
906967#undef FLAG_CHANGE
@@ -941,7 +1002,7 @@ zpl_ioctl_getxattr(struct file *filp, void __user *arg)
9411002 struct inode * ip = file_inode (filp );
9421003 int err ;
9431004
944- fsx .fsx_xflags = __zpl_ioctl_getflags (ip );
1005+ fsx .fsx_xflags = __zpl_ioctl_getxflags (ip );
9451006 fsx .fsx_projid = ITOZ (ip )-> z_projid ;
9461007 err = copy_to_user (arg , & fsx , sizeof (fsx ));
9471008
@@ -965,7 +1026,7 @@ zpl_ioctl_setxattr(struct file *filp, void __user *arg)
9651026 if (!zpl_is_valid_projid (fsx .fsx_projid ))
9661027 return (- EINVAL );
9671028
968- err = __zpl_ioctl_setflags (ip , fsx .fsx_xflags , & xva );
1029+ err = __zpl_ioctl_setxflags (ip , fsx .fsx_xflags , & xva );
9691030 if (err )
9701031 return (err );
9711032
0 commit comments