Skip to content

Commit

Permalink
Merge pull request openzfs#48 from truenas/NAS-114369
Browse files Browse the repository at this point in the history
Expose additional file level attributes
  • Loading branch information
Ryan Moeller authored Mar 9, 2022
2 parents 912ee0c + 5448a8b commit 5c561a2
Show file tree
Hide file tree
Showing 24 changed files with 806 additions and 64 deletions.
3 changes: 3 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -232,12 +232,14 @@ AC_CONFIG_FILES([
tests/zfs-tests/cmd/randfree_file/Makefile
tests/zfs-tests/cmd/randwritecomp/Makefile
tests/zfs-tests/cmd/readmmap/Makefile
tests/zfs-tests/cmd/read_dos_attributes/Makefile
tests/zfs-tests/cmd/rename_dir/Makefile
tests/zfs-tests/cmd/rm_lnkcnt_zero_file/Makefile
tests/zfs-tests/cmd/send_doall/Makefile
tests/zfs-tests/cmd/stride_dd/Makefile
tests/zfs-tests/cmd/threadsappend/Makefile
tests/zfs-tests/cmd/user_ns_exec/Makefile
tests/zfs-tests/cmd/write_dos_attributes/Makefile
tests/zfs-tests/cmd/xattrtest/Makefile
tests/zfs-tests/include/Makefile
tests/zfs-tests/tests/Makefile
Expand Down Expand Up @@ -338,6 +340,7 @@ AC_CONFIG_FILES([
tests/zfs-tests/tests/functional/deadman/Makefile
tests/zfs-tests/tests/functional/delegate/Makefile
tests/zfs-tests/tests/functional/devices/Makefile
tests/zfs-tests/tests/functional/dos_attributes/Makefile
tests/zfs-tests/tests/functional/events/Makefile
tests/zfs-tests/tests/functional/exec/Makefile
tests/zfs-tests/tests/functional/fallocate/Makefile
Expand Down
35 changes: 35 additions & 0 deletions include/sys/fs/zfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -1376,6 +1376,41 @@ typedef enum zfs_ioc {
*/
#define BLKZNAME _IOR(0x12, 125, char[ZFS_MAX_DATASET_NAME_LEN])

#ifdef __linux__

/*
* IOCTLs to update and retrieve additional file level attributes on
* Linux.
*/
#define ZFS_IOC_GETDOSFLAGS _IOR(0x83, 1, uint64_t)
#define ZFS_IOC_SETDOSFLAGS _IOW(0x83, 2, uint64_t)

/*
* Additional file level attributes, that are stored
* in the upper half of z_pflags
*/
#define ZFS_READONLY 0x0000000100000000ull
#define ZFS_HIDDEN 0x0000000200000000ull
#define ZFS_SYSTEM 0x0000000400000000ull
#define ZFS_ARCHIVE 0x0000000800000000ull
#define ZFS_IMMUTABLE 0x0000001000000000ull
#define ZFS_NOUNLINK 0x0000002000000000ull
#define ZFS_APPENDONLY 0x0000004000000000ull
#define ZFS_NODUMP 0x0000008000000000ull
#define ZFS_OPAQUE 0x0000010000000000ull
#define ZFS_AV_QUARANTINED 0x0000020000000000ull
#define ZFS_AV_MODIFIED 0x0000040000000000ull
#define ZFS_REPARSE 0x0000080000000000ull
#define ZFS_OFFLINE 0x0000100000000000ull
#define ZFS_SPARSE 0x0000200000000000ull

#define ZFS_DOS_FL_USER_VISIBLE (ZFS_IMMUTABLE | ZFS_APPENDONLY | \
ZFS_NOUNLINK | ZFS_ARCHIVE | ZFS_NODUMP | ZFS_SYSTEM | \
ZFS_HIDDEN | ZFS_READONLY | ZFS_REPARSE | ZFS_OFFLINE | \
ZFS_SPARSE)

#endif

/*
* ZFS-specific error codes used for returning descriptive errors
* to the userland through zfs ioctls.
Expand Down
2 changes: 1 addition & 1 deletion include/sys/zfs_znode.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ extern "C" {

/*
* Additional file level attributes, that are stored
* in the upper half of zp_flags
* in the upper half of z_pflags
*/
#define ZFS_READONLY 0x0000000100000000ull
#define ZFS_HIDDEN 0x0000000200000000ull
Expand Down
125 changes: 110 additions & 15 deletions module/os/linux/zfs/zpl_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -900,21 +900,24 @@ __zpl_ioctl_setflags(struct inode *ip, uint32_t ioctl_flags, xvattr_t *xva)
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;

XVA_SET_REQ(xva, XAT_PROJINHERIT);
if (ioctl_flags & ZFS_PROJINHERIT_FL)
xoap->xoa_projinherit = B_TRUE;
#define FLAG_CHANGE(iflag, zflag, xflag, xfield) do { \
if (((ioctl_flags & (iflag)) && !(zfs_flags & (zflag))) || \
((zfs_flags & (zflag)) && !(ioctl_flags & (iflag)))) { \
XVA_SET_REQ(xva, (xflag)); \
(xfield) = ((ioctl_flags & (iflag)) != 0); \
} \
} while (0)

FLAG_CHANGE(FS_IMMUTABLE_FL, ZFS_IMMUTABLE, XAT_IMMUTABLE,
xoap->xoa_immutable);
FLAG_CHANGE(FS_APPEND_FL, ZFS_APPENDONLY, XAT_APPENDONLY,
xoap->xoa_appendonly);
FLAG_CHANGE(FS_NODUMP_FL, ZFS_NODUMP, XAT_NODUMP,
xoap->xoa_nodump);
FLAG_CHANGE(ZFS_PROJINHERIT_FL, ZFS_PROJINHERIT, XAT_PROJINHERIT,
xoap->xoa_projinherit);

#undef FLAG_CHANGE

return (0);
}
Expand Down Expand Up @@ -993,6 +996,94 @@ zpl_ioctl_setxattr(struct file *filp, void __user *arg)
return (err);
}

/*
* Expose Additional File Level Attributes of ZFS.
*/
static int
zpl_ioctl_getdosflags(struct file *filp, void __user *arg)
{
struct inode *ip = file_inode(filp);
uint64_t dosflags = ITOZ(ip)->z_pflags;
dosflags &= ZFS_DOS_FL_USER_VISIBLE;
int err = copy_to_user(arg, &dosflags, sizeof (dosflags));

return (err);
}

static int
__zpl_ioctl_setdosflags(struct inode *ip, uint64_t ioctl_flags, xvattr_t *xva)
{
uint64_t zfs_flags = ITOZ(ip)->z_pflags;
xoptattr_t *xoap;

if (ioctl_flags & (~ZFS_DOS_FL_USER_VISIBLE))
return (-EOPNOTSUPP);

if ((fchange(ioctl_flags, zfs_flags, ZFS_IMMUTABLE, ZFS_IMMUTABLE) ||
fchange(ioctl_flags, zfs_flags, ZFS_APPENDONLY, ZFS_APPENDONLY)) &&
!capable(CAP_LINUX_IMMUTABLE))
return (-EPERM);

if (!zpl_inode_owner_or_capable(kcred->user_ns, ip))
return (-EACCES);

xva_init(xva);
xoap = xva_getxoptattr(xva);

#define FLAG_CHANGE(iflag, xflag, xfield) do { \
if (((ioctl_flags & (iflag)) && !(zfs_flags & (iflag))) || \
((zfs_flags & (iflag)) && !(ioctl_flags & (iflag)))) { \
XVA_SET_REQ(xva, (xflag)); \
(xfield) = ((ioctl_flags & (iflag)) != 0); \
} \
} while (0)

FLAG_CHANGE(ZFS_IMMUTABLE, XAT_IMMUTABLE, xoap->xoa_immutable);
FLAG_CHANGE(ZFS_APPENDONLY, XAT_APPENDONLY, xoap->xoa_appendonly);
FLAG_CHANGE(ZFS_NODUMP, XAT_NODUMP, xoap->xoa_nodump);
FLAG_CHANGE(ZFS_READONLY, XAT_READONLY, xoap->xoa_readonly);
FLAG_CHANGE(ZFS_HIDDEN, XAT_HIDDEN, xoap->xoa_hidden);
FLAG_CHANGE(ZFS_SYSTEM, XAT_SYSTEM, xoap->xoa_system);
FLAG_CHANGE(ZFS_ARCHIVE, XAT_ARCHIVE, xoap->xoa_archive);
FLAG_CHANGE(ZFS_NOUNLINK, XAT_NOUNLINK, xoap->xoa_nounlink);
FLAG_CHANGE(ZFS_REPARSE, XAT_REPARSE, xoap->xoa_reparse);
FLAG_CHANGE(ZFS_OFFLINE, XAT_OFFLINE, xoap->xoa_offline);
FLAG_CHANGE(ZFS_SPARSE, XAT_SPARSE, xoap->xoa_sparse);

#undef FLAG_CHANGE

return (0);
}

/*
* Set Additional File Level Attributes of ZFS.
*/
static int
zpl_ioctl_setdosflags(struct file *filp, void __user *arg)
{
struct inode *ip = file_inode(filp);
uint64_t dosflags;
cred_t *cr = CRED();
xvattr_t xva;
int err;
fstrans_cookie_t cookie;

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

err = __zpl_ioctl_setdosflags(ip, dosflags, &xva);
if (err)
return (err);

crhold(cr);
cookie = spl_fstrans_mark();
err = -zfs_setattr(ITOZ(ip), (vattr_t *)&xva, 0, cr);
spl_fstrans_unmark(cookie);
crfree(cr);

return (err);
}

static long
zpl_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
Expand All @@ -1007,6 +1098,10 @@ zpl_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
return (zpl_ioctl_getxattr(filp, (void *)arg));
case ZFS_IOC_FSSETXATTR:
return (zpl_ioctl_setxattr(filp, (void *)arg));
case ZFS_IOC_GETDOSFLAGS:
return (zpl_ioctl_getdosflags(filp, (void *)arg));
case ZFS_IOC_SETDOSFLAGS:
return (zpl_ioctl_setdosflags(filp, (void *)arg));
default:
return (-ENOTTY);
}
Expand Down
2 changes: 1 addition & 1 deletion tests/runfiles/common.run
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ outputdir = /var/tmp/test_results
tags = ['functional']

[tests/functional/acl/off]
tests = ['posixmode']
tests = ['dosmode', 'posixmode']
tags = ['functional', 'acl']

[tests/functional/alloc_class]
Expand Down
4 changes: 0 additions & 4 deletions tests/runfiles/freebsd.run
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@ failsafe = callbacks/zfs_failsafe
outputdir = /var/tmp/test_results
tags = ['functional']

[tests/functional/acl/off:FreeBSD]
tests = ['dosmode']
tags = ['functional', 'acl']

[tests/functional/cli_root/zfs_jail:FreeBSD]
tests = ['zfs_jail_001_pos']
tags = ['functional', 'cli_root', 'zfs_jail']
4 changes: 4 additions & 0 deletions tests/runfiles/linux.run
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,10 @@ tests = ['projectid_001_pos', 'projectid_002_pos', 'projectid_003_pos',
'projecttree_001_pos', 'projecttree_002_pos', 'projecttree_003_neg']
tags = ['functional', 'projectquota']

[tests/functional/dos_attributes:Linux]
tests = ['read_dos_attrs_001', 'write_dos_attrs_001']
tags = ['functional', 'dos_attributes']

[tests/functional/rsend:Linux]
tests = ['send_realloc_dnode_size', 'send_encrypted_files']
tags = ['functional', 'rsend']
Expand Down
2 changes: 2 additions & 0 deletions tests/zfs-tests/cmd/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ if BUILD_LINUX
SUBDIRS += \
getversion \
randfree_file \
read_dos_attributes \
user_ns_exec \
write_dos_attributes \
xattrtest
endif
1 change: 1 addition & 0 deletions tests/zfs-tests/cmd/read_dos_attributes/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/read_dos_attributes
6 changes: 6 additions & 0 deletions tests/zfs-tests/cmd/read_dos_attributes/Makefile.am
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
include $(top_srcdir)/config/Rules.am

pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin

pkgexec_PROGRAMS = read_dos_attributes
read_dos_attributes_SOURCES = read_dos_attributes.c
Loading

0 comments on commit 5c561a2

Please sign in to comment.