diff mbox

btrfs: bugfix: handle FS_IOC32_{GETFLAGS,SETFLAGS,GETVERSION} in btrfs_ioctl

Message ID 201505131715.27483.luke@dashjr.org (mailing list archive)
State Superseded
Headers show

Commit Message

Luke-Jr May 13, 2015, 5:15 p.m. UTC
32-bit ioctl uses these rather than the regular FS_IOC_* versions. They can be 
handled in btrfs using the same code. Without this, 32-bit {ch,ls}attr fail.

Signed-off-by: Luke Dashjr <luke-jr+git@utopios.org>
---
 fs/btrfs/ioctl.c | 3 +++
 1 file changed, 3 insertions(+)

Comments

Greg KH May 13, 2015, 5:38 p.m. UTC | #1
On Wed, May 13, 2015 at 05:15:26PM +0000, Luke Dashjr wrote:
> 32-bit ioctl uses these rather than the regular FS_IOC_* versions. They can be 
> handled in btrfs using the same code. Without this, 32-bit {ch,ls}attr fail.
> 
> Signed-off-by: Luke Dashjr <luke-jr+git@utopios.org>
> ---
>  fs/btrfs/ioctl.c | 3 +++
>  1 file changed, 3 insertions(+)

<formletter>

This is not the correct way to submit patches for inclusion in the
stable kernel tree.  Please read Documentation/stable_kernel_rules.txt
for how to do this properly.

</formletter>
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Sterba May 14, 2015, 2:06 p.m. UTC | #2
On Wed, May 13, 2015 at 05:15:26PM +0000, Luke Dashjr wrote:
> 32-bit ioctl uses these rather than the regular FS_IOC_* versions. They can be 
> handled in btrfs using the same code. Without this, 32-bit {ch,ls}attr fail.

Yes, but this has to be implemented in another way. See eg.
https://git.kernel.org/linus/e9750824114ff
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Luke-Jr May 14, 2015, 4:27 p.m. UTC | #3
On Thursday, May 14, 2015 2:06:17 PM David Sterba wrote:
> On Wed, May 13, 2015 at 05:15:26PM +0000, Luke Dashjr wrote:
> > 32-bit ioctl uses these rather than the regular FS_IOC_* versions. They
> > can be handled in btrfs using the same code. Without this, 32-bit
> > {ch,ls}attr fail.
> 
> Yes, but this has to be implemented in another way. See eg.
> https://git.kernel.org/linus/e9750824114ff

I don't see what is different with that implementation. All f2fs_compat_ioctl 
does is change cmd to the plain-IOC equivalent and call f2fs_ioctl with the 
same arg (compat_ptr merely causes a cast to void* and back, which AFAIK is a 
noop on 64-bit?). Am I missing something? I could try to just imitate it, but 
I'd rather know what is significant/going on to ensure I don't waste your time 
with code I don't even properly understand myself.

Perhaps by coincidence, the patch does at least in practice work (although at 
least `btrfs send` appears to be broken still, and I'm at a loss for how to 
approach fixing that).

Luke
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Sterba May 15, 2015, 11:19 a.m. UTC | #4
On Thu, May 14, 2015 at 04:27:54PM +0000, Luke Dashjr wrote:
> On Thursday, May 14, 2015 2:06:17 PM David Sterba wrote:
> > On Wed, May 13, 2015 at 05:15:26PM +0000, Luke Dashjr wrote:
> > > 32-bit ioctl uses these rather than the regular FS_IOC_* versions. They
> > > can be handled in btrfs using the same code. Without this, 32-bit
> > > {ch,ls}attr fail.
> > 
> > Yes, but this has to be implemented in another way. See eg.
> > https://git.kernel.org/linus/e9750824114ff
> 
> I don't see what is different with that implementation. All f2fs_compat_ioctl 
> does is change cmd to the plain-IOC equivalent and call f2fs_ioctl with the 
> same arg (compat_ptr merely causes a cast to void* and back, which AFAIK is a 
> noop on 64-bit?). Am I missing something?

No, that's the idea. Add new calback for compat_ioctl, put it under
#ifdef CONFIG_COMPAT and do the same number switch.

> I could try to just imitate it, but 
> I'd rather know what is significant/going on to ensure I don't waste your time 
> with code I don't even properly understand myself.
> 
> Perhaps by coincidence, the patch does at least in practice work (although at 
> least `btrfs send` appears to be broken still, and I'm at a loss for how to 
> approach fixing that).

The 'receive' 32bit/64bit was broken due to size difference in the ioctl
structure that led to different ioctl. This is transparently fixed, see
BTRFS_IOC_SET_RECEIVED_SUBVOL_32 at the top of ioctl.c.

In what way is SEND broken? There are only u64/s64 members in
btrfs_ioctl_send_args, I don't see how this could break on 32/64
userspace/kernel.
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Luke-Jr May 15, 2015, 4:35 p.m. UTC | #5
On Friday, May 15, 2015 11:19:22 AM David Sterba wrote:
> On Thu, May 14, 2015 at 04:27:54PM +0000, Luke Dashjr wrote:
> > On Thursday, May 14, 2015 2:06:17 PM David Sterba wrote:
> > > On Wed, May 13, 2015 at 05:15:26PM +0000, Luke Dashjr wrote:
> > > > 32-bit ioctl uses these rather than the regular FS_IOC_* versions.
> > > > They can be handled in btrfs using the same code. Without this,
> > > > 32-bit {ch,ls}attr fail.
> > > 
> > > Yes, but this has to be implemented in another way. See eg.
> > > https://git.kernel.org/linus/e9750824114ff
> > 
> > I don't see what is different with that implementation. All
> > f2fs_compat_ioctl does is change cmd to the plain-IOC equivalent and
> > call f2fs_ioctl with the same arg (compat_ptr merely causes a cast to
> > void* and back, which AFAIK is a noop on 64-bit?). Am I missing
> > something?
> 
> No, that's the idea. Add new calback for compat_ioctl, put it under
> #ifdef CONFIG_COMPAT and do the same number switch.

The idea is to wrap it in a way that doesn't actually change any of the logic?
I'm not sure I understand still :(

> > I could try to just imitate it, but
> > I'd rather know what is significant/going on to ensure I don't waste your
> > time with code I don't even properly understand myself.
> > 
> > Perhaps by coincidence, the patch does at least in practice work
> > (although at least `btrfs send` appears to be broken still, and I'm at a
> > loss for how to approach fixing that).
> 
> The 'receive' 32bit/64bit was broken due to size difference in the ioctl
> structure that led to different ioctl. This is transparently fixed, see
> BTRFS_IOC_SET_RECEIVED_SUBVOL_32 at the top of ioctl.c.
> 
> In what way is SEND broken? There are only u64/s64 members in
> btrfs_ioctl_send_args, I don't see how this could break on 32/64
> userspace/kernel.

# btrfs send -p home/initial/ home/20150514_1431573370/
At subvol home/20150514_1431573370/
ERROR: send ioctl failed with -25: Inappropriate ioctl for device

But I am stuck on 3.14.41 due to Linux being unstable in newer versions[1], so 
maybe this is unrelated to 32-bit and already fixed in 4.0?

Luke

1. https://bugzilla.kernel.org/show_bug.cgi?id=87891
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Luke-Jr Oct. 29, 2015, 8:22 a.m. UTC | #6
On Friday, May 15, 2015 11:19:22 AM David Sterba wrote:
> On Thu, May 14, 2015 at 04:27:54PM +0000, Luke Dashjr wrote:
> > On Thursday, May 14, 2015 2:06:17 PM David Sterba wrote:
> > > On Wed, May 13, 2015 at 05:15:26PM +0000, Luke Dashjr wrote:
> > > > 32-bit ioctl uses these rather than the regular FS_IOC_* versions.
> > > > They can be handled in btrfs using the same code. Without this,
> > > > 32-bit {ch,ls}attr fail.
> > > 
> > > Yes, but this has to be implemented in another way. See eg.
> > > https://git.kernel.org/linus/e9750824114ff
> > 
> > I don't see what is different with that implementation. All
> > f2fs_compat_ioctl does is change cmd to the plain-IOC equivalent and
> > call f2fs_ioctl with the same arg (compat_ptr merely causes a cast to
> > void* and back, which AFAIK is a noop on 64-bit?). Am I missing
> > something?
> 
> No, that's the idea. Add new calback for compat_ioctl, put it under
> #ifdef CONFIG_COMPAT and do the same number switch.

Ok, someone else explained this to me. Please let me know if PATCHv2 (sent 
separately) does not address the needed changes.

> > I could try to just imitate it, but
> > I'd rather know what is significant/going on to ensure I don't waste your
> > time with code I don't even properly understand myself.
> > 
> > Perhaps by coincidence, the patch does at least in practice work
> > (although at least `btrfs send` appears to be broken still, and I'm at a
> > loss for how to approach fixing that).
> 
> The 'receive' 32bit/64bit was broken due to size difference in the ioctl
> structure that led to different ioctl. This is transparently fixed, see
> BTRFS_IOC_SET_RECEIVED_SUBVOL_32 at the top of ioctl.c.
> 
> In what way is SEND broken? There are only u64/s64 members in
> btrfs_ioctl_send_args, I don't see how this could break on 32/64
> userspace/kernel.

I've investigated this now, and it seems to be the pointer-type clone_sources 
member of struct btrfs_ioctl_send_args. I can't think of a perfect way to fix 
this, but it might not be *too* ugly to:
- replace the current clone_sources with a u64 that must always be (u64)-1;
  this causes older kernels to error cleanly if called with a new ioctl data
- use the top 1 or 2 bits of flags to indicate sizeof(void*) as it appears to
  userspace OR just use up reserved[0] for pointer size:
      io_send.ptr_size = sizeof(void*);
- replace one of the reserved fields with the new clone_sources

The way it was done for receive seems like it might not work for non-x86 
compat interfaces (eg, MIPS n32) - but I could be wrong.

Thoughts?

Luke
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Sterba Oct. 29, 2015, 2:39 p.m. UTC | #7
On Thu, Oct 29, 2015 at 08:22:34AM +0000, Luke Dashjr wrote:
> > > I don't see what is different with that implementation. All
> > > f2fs_compat_ioctl does is change cmd to the plain-IOC equivalent and
> > > call f2fs_ioctl with the same arg (compat_ptr merely causes a cast to
> > > void* and back, which AFAIK is a noop on 64-bit?). Am I missing
> > > something?
> > 
> > No, that's the idea. Add new calback for compat_ioctl, put it under
> > #ifdef CONFIG_COMPAT and do the same number switch.
> 
> Ok, someone else explained this to me. Please let me know if PATCHv2 (sent 
> separately) does not address the needed changes.

Patch is ok, thanks.

> > > I could try to just imitate it, but
> > > I'd rather know what is significant/going on to ensure I don't waste your
> > > time with code I don't even properly understand myself.
> > > 
> > > Perhaps by coincidence, the patch does at least in practice work
> > > (although at least `btrfs send` appears to be broken still, and I'm at a
> > > loss for how to approach fixing that).
> > 
> > The 'receive' 32bit/64bit was broken due to size difference in the ioctl
> > structure that led to different ioctl. This is transparently fixed, see
> > BTRFS_IOC_SET_RECEIVED_SUBVOL_32 at the top of ioctl.c.
> > 
> > In what way is SEND broken? There are only u64/s64 members in
> > btrfs_ioctl_send_args, I don't see how this could break on 32/64
> > userspace/kernel.
> 
> I've investigated this now, and it seems to be the pointer-type clone_sources 
> member of struct btrfs_ioctl_send_args. I can't think of a perfect way to fix 
> this, but it might not be *too* ugly to:
> - replace the current clone_sources with a u64 that must always be (u64)-1;
>   this causes older kernels to error cleanly if called with a new ioctl data
> - use the top 1 or 2 bits of flags to indicate sizeof(void*) as it appears to
>   userspace OR just use up reserved[0] for pointer size:
>       io_send.ptr_size = sizeof(void*);
> - replace one of the reserved fields with the new clone_sources

All the change seem too intrusive or not so easy to use.

I suggest to add an anonymous union and add a u64 member that would
force the type width:

struct btrfs_ioctl_send_args {
        __s64 send_fd;                  /* in */
        __u64 clone_sources_count;      /* in */
	union {
		__u64 __user *clone_sources;    /* in */
		u64 __pointer_alignment;
	};
        __u64 parent_root;              /* in */
        __u64 flags;                    /* in */
        __u64 reserved[4];              /* in */
};

> The way it was done for receive seems like it might not work for non-x86 
> compat interfaces (eg, MIPS n32) - but I could be wrong.

Possible, but I don't see right now how it would not work on eg. mips32.
unless sizeof(long) is 8 bytes there and CONFIG_64BIT is not defined.
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Luke-Jr Oct. 29, 2015, 7:01 p.m. UTC | #8
On Thursday, October 29, 2015 2:39:32 PM David Sterba wrote:
> On Thu, Oct 29, 2015 at 08:22:34AM +0000, Luke Dashjr wrote:
> > > In what way is SEND broken? There are only u64/s64 members in
> > > btrfs_ioctl_send_args, I don't see how this could break on 32/64
> > > userspace/kernel.
> > 
> > I've investigated this now, and it seems to be the pointer-type
> > clone_sources member of struct btrfs_ioctl_send_args. I can't think of a
> > perfect way to fix this, but it might not be *too* ugly to:
> > - replace the current clone_sources with a u64 that must always be
> > (u64)-1;
> > 
> >   this causes older kernels to error cleanly if called with a new ioctl
> >   data
> > 
> > - use the top 1 or 2 bits of flags to indicate sizeof(void*) as it
> > appears to
> > 
> >   userspace OR just use up reserved[0] for pointer size:
> >       io_send.ptr_size = sizeof(void*);
> > 
> > - replace one of the reserved fields with the new clone_sources
> 
> All the change seem too intrusive or not so easy to use.
> 
> I suggest to add an anonymous union and add a u64 member that would
> force the type width:
> 
> struct btrfs_ioctl_send_args {
>         __s64 send_fd;                  /* in */
>         __u64 clone_sources_count;      /* in */
> 	union {
> 		__u64 __user *clone_sources;    /* in */
> 		u64 __pointer_alignment;
> 	};
>         __u64 parent_root;              /* in */
>         __u64 flags;                    /* in */
>         __u64 reserved[4];              /* in */
> };

What guarantees the union to position clone_sources in the LSB of 
__pointer_alignment (rather than the MSB side)?

> > The way it was done for receive seems like it might not work for non-x86
> > compat interfaces (eg, MIPS n32) - but I could be wrong.
> 
> Possible, but I don't see right now how it would not work on eg. mips32.
> unless sizeof(long) is 8 bytes there and CONFIG_64BIT is not defined.

n32 is a MIPS64 ABI, like the new x32 ABI for x86_64 machines, so I would 
expect sizeof(long) to be 8 bytes, and am uncertain of if this implies any 
particular alignment. (But I don't have any MIPS systems, so this isn't 
something I'm too concerned with myself.)

Luke
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Thomas Rohwer Oct. 29, 2015, 7:36 p.m. UTC | #9
> I suggest to add an anonymous union and add a u64 member that would
> force the type width:
>
> struct btrfs_ioctl_send_args {
>          __s64 send_fd;                  /* in */
>          __u64 clone_sources_count;      /* in */
> 	union {
> 		__u64 __user *clone_sources;    /* in */
> 		u64 __pointer_alignment;
> 	};
>          __u64 parent_root;              /* in */
>          __u64 flags;                    /* in */
>          __u64 reserved[4];              /* in */
> };

I am no expert, but would this change alone modify the user space ABI of a 32-bit Linux kernel?
I.e. people in the (presumably currently working) btrfs-send situation (32-bit) user space/32-bit kernel
would have to upgrade user space tools and kernel at the same time. Otherwise, they will encounter a non-working setup.
I think, my suggested patch does not change any working ABI, and no change to the user
space tools are necessary.


Sincerely,

Thomas Rohwer

--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Luke-Jr Oct. 29, 2015, 8:04 p.m. UTC | #10
On Thursday, October 29, 2015 7:36:35 PM Thomas Rohwer wrote:
> > I suggest to add an anonymous union and add a u64 member that would
> > force the type width:
> > 
> > struct btrfs_ioctl_send_args {
> > 
> >          __s64 send_fd;                  /* in */
> >          __u64 clone_sources_count;      /* in */
> > 	
> > 	union {
> > 	
> > 		__u64 __user *clone_sources;    /* in */
> > 		u64 __pointer_alignment;
> > 	
> > 	};
> > 	
> >          __u64 parent_root;              /* in */
> >          __u64 flags;                    /* in */
> >          __u64 reserved[4];              /* in */
> > 
> > };
> 
> I am no expert, but would this change alone modify the user space ABI of a
> 32-bit Linux kernel? I.e. people in the (presumably currently working)
> btrfs-send situation (32-bit) user space/32-bit kernel would have to
> upgrade user space tools and kernel at the same time. Otherwise, they will
> encounter a non-working setup.

Yes, it would, but this appears to already be the case for btrfs-progs in 
general.

> I think, my suggested patch does not change any working ABI, and no change
> to the user space tools are necessary.

Don't the user space tools need to call a different ioctl?

Luke
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 1c22c65..31af093 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -5225,10 +5225,13 @@  long btrfs_ioctl(struct file *file, unsigned int
 
 	switch (cmd) {
 	case FS_IOC_GETFLAGS:
+	case FS_IOC32_GETFLAGS:
 		return btrfs_ioctl_getflags(file, argp);
 	case FS_IOC_SETFLAGS:
+	case FS_IOC32_SETFLAGS:
 		return btrfs_ioctl_setflags(file, argp);
 	case FS_IOC_GETVERSION:
+	case FS_IOC32_GETVERSION:
 		return btrfs_ioctl_getversion(file, argp);
 	case FITRIM:
 		return btrfs_ioctl_fitrim(file, argp);