On Wed, 3 Jul 2024 at 12:33, Christian Brauner <brauner@xxxxxxxxxx> wrote: > > Fwiw, that's why I prefer structs versioned by size which we added clean > handling for via copy_struct_from_user() That works very well for the kernel interface for new things, but it actually doesn't solve the issue for user space library versioning. If you are something like 'glibc', you don't have the option of saying "pass in struct and size". You are kind of stuck with the API rules, and the rules are that you expose a 'struct stat' that has a fixed size. So I don't disagree that copy_struct_from_user() is a good model, but what would happen is just that then glibc says "I will need to make a decision", and would pick a size that is bigger than the current size it uses, so that glibc later could do those extensions without breaking the ABI. And yes, it would pass that larger size to the kernel,. because it would want the kernel to zero out the unused tail of the struct. So the 'struct and extensible size' thing really only works when everybody agrees on using it, and users pass the size end-to-end. Side note: this is our original i386 'stat64': unsigned long st_blocks; /* Number 512-byte blocks allocated. */ unsigned long __pad4; /* future possible st_blocks high bits */ unsigned long st_atime; unsigned long __pad5; unsigned long st_mtime; unsigned long __pad6; unsigned long st_ctime; unsigned long __pad7; /* will be high 32 bits of ctime someday */ which is kind of sad. The code was literally designed to extend the time range, had a comment to that effect and all, and then we screwed it up. On little-endian, we could literally have done it as unsigned long long st_ctime:44, st_ctime_usec:20; without losin gbinary compatibility. But it's sadly not what we did. Instead we gave the full 32-bit padding to the nsec field. And yes, I had to go back a long time to find this screw-up. It happened back in 2002. Oh well. Not the first time we've royally screwed up, and it most definitely won't be the last time either. Linus