Skip to content

Commit f93506d

Browse files
authored
Linux 6.17 compat: Fix broken projectquota on 6.17
We need to specifically use the FX_XFLAG_* macros in zpl_ioctl_*attr() codepaths, and the FS_*_FL macros in the zpl_ioctl_*flags() codepaths. The earlier code just assumes the FS_*_FL macros for both codepaths. The 6.17 kernel add a bitmask check in copy_fsxattr_from_user() that exposed this error via failing 'projectquota' ZTS tests. Reviewed-by: Alexander Motin <alexander.motin@TrueNAS.com> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Tony Hutter <hutter2@llnl.gov> Closes #17884 Closes #17869
1 parent 8c225ff commit f93506d

File tree

6 files changed

+146
-33
lines changed

6 files changed

+146
-33
lines changed

cmd/zfs/zfs_project.c

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -145,11 +145,11 @@ zfs_project_handle_one(const char *name, zfs_project_control_t *zpc)
145145
switch (zpc->zpc_op) {
146146
case ZFS_PROJECT_OP_LIST:
147147
(void) printf("%5u %c %s\n", fsx.fsx_projid,
148-
(fsx.fsx_xflags & ZFS_PROJINHERIT_FL) ? 'P' : '-', name);
148+
(fsx.fsx_xflags & FS_XFLAG_PROJINHERIT) ? 'P' : '-', name);
149149
goto out;
150150
case ZFS_PROJECT_OP_CHECK:
151151
if (fsx.fsx_projid == zpc->zpc_expected_projid &&
152-
fsx.fsx_xflags & ZFS_PROJINHERIT_FL)
152+
fsx.fsx_xflags & FS_XFLAG_PROJINHERIT)
153153
goto out;
154154

155155
if (!zpc->zpc_newline) {
@@ -164,41 +164,61 @@ zfs_project_handle_one(const char *name, zfs_project_control_t *zpc)
164164
"(%u/%u)\n", name, fsx.fsx_projid,
165165
(uint32_t)zpc->zpc_expected_projid);
166166

167-
if (!(fsx.fsx_xflags & ZFS_PROJINHERIT_FL))
167+
if (!(fsx.fsx_xflags & FS_XFLAG_PROJINHERIT))
168168
(void) printf("%s - project inherit flag is not set\n",
169169
name);
170170

171171
goto out;
172172
case ZFS_PROJECT_OP_CLEAR:
173-
if (!(fsx.fsx_xflags & ZFS_PROJINHERIT_FL) &&
173+
if (!(fsx.fsx_xflags & FS_XFLAG_PROJINHERIT) &&
174174
(zpc->zpc_keep_projid ||
175175
fsx.fsx_projid == ZFS_DEFAULT_PROJID))
176176
goto out;
177177

178-
fsx.fsx_xflags &= ~ZFS_PROJINHERIT_FL;
178+
fsx.fsx_xflags &= ~FS_XFLAG_PROJINHERIT;
179179
if (!zpc->zpc_keep_projid)
180180
fsx.fsx_projid = ZFS_DEFAULT_PROJID;
181181
break;
182182
case ZFS_PROJECT_OP_SET:
183183
if (fsx.fsx_projid == zpc->zpc_expected_projid &&
184-
(!zpc->zpc_set_flag || fsx.fsx_xflags & ZFS_PROJINHERIT_FL))
184+
(!zpc->zpc_set_flag ||
185+
fsx.fsx_xflags & FS_XFLAG_PROJINHERIT))
185186
goto out;
186187

187188
fsx.fsx_projid = zpc->zpc_expected_projid;
188189
if (zpc->zpc_set_flag)
189-
fsx.fsx_xflags |= ZFS_PROJINHERIT_FL;
190+
fsx.fsx_xflags |= FS_XFLAG_PROJINHERIT;
190191
break;
191192
default:
192193
ASSERT(0);
193194
break;
194195
}
195196

196197
ret = ioctl(fd, ZFS_IOC_FSSETXATTR, &fsx);
197-
if (ret)
198+
if (ret) {
198199
(void) fprintf(stderr,
199200
gettext("failed to set xattr for %s: %s\n"),
200201
name, strerror(errno));
201202

203+
if (errno == ENOTSUP) {
204+
char *kver = zfs_version_kernel();
205+
/*
206+
* Special case: a module/userspace version mismatch can
207+
* return ENOTSUP due to us fixing the XFLAGs bits in
208+
* #17884. In that case give a hint to the user that
209+
* they should take action to make the versions match.
210+
*/
211+
if (strcmp(kver, ZFS_META_ALIAS) != 0) {
212+
fprintf(stderr,
213+
gettext("Warning: The zfs module version "
214+
"(%s) and userspace\nversion (%s) do not "
215+
"match up. This may be the\ncause of the "
216+
"\"Operation not supported\" error.\n"),
217+
kver, ZFS_META_ALIAS);
218+
}
219+
}
220+
}
221+
202222
out:
203223
close(fd);
204224
return (ret);

include/sys/zfs_project.h

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,18 +35,16 @@
3535

3636
#include <sys/vfs.h>
3737

38-
#ifdef FS_PROJINHERIT_FL
39-
#define ZFS_PROJINHERIT_FL FS_PROJINHERIT_FL
40-
#else
41-
#define ZFS_PROJINHERIT_FL 0x20000000
42-
#endif
43-
4438
#ifdef FS_IOC_FSGETXATTR
4539
typedef struct fsxattr zfsxattr_t;
4640

4741
#define ZFS_IOC_FSGETXATTR FS_IOC_FSGETXATTR
4842
#define ZFS_IOC_FSSETXATTR FS_IOC_FSSETXATTR
4943
#else
44+
/* Non-Linux OS */
45+
#define FS_PROJINHERIT_FL 0x20000000
46+
#define FS_XFLAG_PROJINHERIT FS_PROJINHERIT_FL
47+
5048
struct zfsxattr {
5149
uint32_t fsx_xflags; /* xflags field value (get/set) */
5250
uint32_t fsx_extsize; /* extsize field value (get/set) */

lib/libspl/include/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ libspl_sys_HEADERS += \
7878
%D%/os/linux/sys/param.h \
7979
%D%/os/linux/sys/stat.h \
8080
%D%/os/linux/sys/sysmacros.h \
81+
%D%/os/linux/sys/vfs.h \
8182
%D%/os/linux/sys/zfs_context_os.h
8283

8384
libspl_ia32_HEADERS = \
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// SPDX-License-Identifier: CDDL-1.0
2+
/*
3+
* CDDL HEADER START
4+
*
5+
* The contents of this file are subject to the terms of the
6+
* Common Development and Distribution License, Version 1.0 only
7+
* (the "License"). You may not use this file except in compliance
8+
* with the License.
9+
*
10+
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11+
* or https://opensource.org/licenses/CDDL-1.0.
12+
* See the License for the specific language governing permissions
13+
* and limitations under the License.
14+
*
15+
* When distributing Covered Code, include this CDDL HEADER in each
16+
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17+
* If applicable, add the following below this CDDL HEADER, with the
18+
* fields enclosed by brackets "[]" replaced with your own identifying
19+
* information: Portions Copyright [yyyy] [name of copyright owner]
20+
*
21+
* CDDL HEADER END
22+
*/
23+
/* Copyright 2025 by Lawrence Livermore National Security, LLC. */
24+
25+
/* This is the Linux userspace version of include/os/linux/spl/sys/vfs.h */
26+
27+
#ifndef _LIBSPL_SYS_VFS_H
28+
#define _LIBSPL_SYS_VFS_H
29+
30+
#include <linux/fs.h>
31+
#include <sys/statfs.h>
32+
33+
#endif

module/os/freebsd/zfs/zfs_vnops_os.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ zfs_ioctl_getxattr(vnode_t *vp, zfsxattr_t *fsx)
278278

279279
memset(fsx, 0, sizeof (*fsx));
280280
fsx->fsx_xflags = (zp->z_pflags & ZFS_PROJINHERIT) ?
281-
ZFS_PROJINHERIT_FL : 0;
281+
FS_PROJINHERIT_FL : 0;
282282
fsx->fsx_projid = zp->z_projid;
283283

284284
return (0);
@@ -290,7 +290,7 @@ zfs_ioctl_setflags(vnode_t *vp, uint32_t ioctl_flags, xvattr_t *xva)
290290
uint64_t zfs_flags = VTOZ(vp)->z_pflags;
291291
xoptattr_t *xoap;
292292

293-
if (ioctl_flags & ~(ZFS_PROJINHERIT_FL))
293+
if (ioctl_flags & ~(FS_PROJINHERIT_FL))
294294
return (SET_ERROR(EOPNOTSUPP));
295295

296296
xva_init(xva);
@@ -304,7 +304,7 @@ zfs_ioctl_setflags(vnode_t *vp, uint32_t ioctl_flags, xvattr_t *xva)
304304
} \
305305
} while (0)
306306

307-
FLAG_CHANGE(ZFS_PROJINHERIT_FL, ZFS_PROJINHERIT, XAT_PROJINHERIT,
307+
FLAG_CHANGE(FS_PROJINHERIT_FL, ZFS_PROJINHERIT, XAT_PROJINHERIT,
308308
xoap->xoa_projinherit);
309309

310310
#undef FLAG_CHANGE

module/os/linux/zfs/zpl_file.c

Lines changed: 77 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -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

817829
static 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

Comments
 (0)