Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose additional file level attributes #13118

Merged
merged 1 commit into from
Mar 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -226,12 +226,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 @@ -333,6 +335,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 @@ -1459,6 +1459,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 @@ -905,21 +905,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 @@ -998,6 +1001,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);
behlendorf marked this conversation as resolved.
Show resolved Hide resolved

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 @@ -1012,6 +1103,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 @@ -149,6 +149,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