Actually, on this ubuntu kernel (3.13.0-24-generic), it doesn't seem
to give an error. I'll attach my test case for that. We don't yet
have a way of reproducing the corruption -- the ext_size change in the
osd simply seemed like a promising lead.
-Sam
On Sat, Jul 12, 2014 at 6:26 PM, Dave Chinner <[email protected]> wrote:
> On Sat, Jul 12, 2014 at 06:16:54PM -0700, Samuel Just wrote:
>> Hi,
>>
>> We are seeing reports of ceph-osd stores on xfs of files with some
>> garbage data (possibly misplaced from data elsewhere in the
>> filesystem). There was a bug for a while where the ceph-osd process
>> would set a value for fsx_extsize on a non-empty (possibly sparse)
>> file using XFS_IOC_FSSETXATTR. Could that plausibly result in a file
>> with garbage data?
>
> No, setting an extent size on a non-empty file will simply fail
> with EINVAL.
>
> Do you have any method of reproducing the bad data in files?
>
> Cheers,
>
> Dave.
> --
> Dave Chinner
> [email protected]
/**
* Try changing extsize on a non-empty sparse object
*/
#include <xfs/xfs.h>
#include <cstdio>
#include <unistd.h>
#include <iostream>
#include <string.h>
int main() {
char buf[256];
memset(buf, 1, sizeof(buf));
int fd = open("test", O_RDWR|O_CREAT|O_EXCL, 0666);
assert(fd >= 0);
int r = pwrite(fd, buf, 1, 24<<10);
assert(r == 1);
close(fd);
fd = open("test", O_RDWR);
assert(fd >= 0);
struct fsxattr fsx;
r = ioctl(fd, XFS_IOC_FSGETXATTR, &fsx);
if (r < 0) {
int ret = -errno;
std::cerr << "FSGETXATTR: " << ret << std::endl;
return ret;
}
// already set?
if (fsx.fsx_xflags & XFS_XFLAG_EXTSIZE) {
std::cerr << "already set" << std::endl;
return 0;
}
std::cerr << fsx.fsx_nextents << " exents, extsize is " << fsx.fsx_extsize << std::endl;
unsigned val = 4<<20;
fsx.fsx_xflags |= XFS_XFLAG_EXTSIZE;
fsx.fsx_extsize = val;
if (ioctl(fd, XFS_IOC_FSSETXATTR, &fsx) < 0) {
int ret = -errno;
std::cerr << "FSSETXATTR: " << ret << std::endl;
return ret;
}
struct fsxattr fsx2;
r = ioctl(fd, XFS_IOC_FSGETXATTR, &fsx2);
if (r < 0) {
int ret = -errno;
std::cerr << "FSGETXATTR: " << ret << std::endl;
return ret;
}
if (fsx2.fsx_xflags & XFS_XFLAG_EXTSIZE) {
std::cerr << "successfully set to " << fsx2.fsx_extsize << std::endl;
}
close(fd);
#if 0
fd = open("test", O_RDONLY);
assert(fd >= 0);
char zbuf[24<<10];
memset(zbuf, 0, sizeof(zbuf));
char obuf[24<<10];
r = read(fd, obuf, sizeof(obuf));
assert(r == sizeof(obuf));
r = memcmp(zbuf, obuf, sizeof(zbuf));
assert(r == 0);
close(fd);
#endif
}