diff --git a/src/os/chain_xattr.cc b/src/os/chain_xattr.cc index c0e64ea32fc7b..c08acdb11b869 100644 --- a/src/os/chain_xattr.cc +++ b/src/os/chain_xattr.cc @@ -138,6 +138,10 @@ int chain_getxattr(const char *fn, const char *name, void *val, size_t size) size -= chunk_size; r = sys_getxattr(fn, raw_name, (char *)val + pos, chunk_size); + if (i && r == -ENODATA) { + ret = pos; + break; + } if (r < 0) { ret = r; break; @@ -201,6 +205,10 @@ int chain_fgetxattr(int fd, const char *name, void *val, size_t size) size -= chunk_size; r = sys_fgetxattr(fd, raw_name, (char *)val + pos, chunk_size); + if (i && r == -ENODATA) { + ret = pos; + break; + } if (r < 0) { ret = r; break; diff --git a/src/test/objectstore/chain_xattr.cc b/src/test/objectstore/chain_xattr.cc index 7e2e69371292f..c2e33f7107e40 100644 --- a/src/test/objectstore/chain_xattr.cc +++ b/src/test/objectstore/chain_xattr.cc @@ -148,6 +148,44 @@ TEST(chain_xattr, get_and_set) { ::unlink(file); } +TEST(chain_xattr, chunk_aligned) { + const char* file = FILENAME; + ::unlink(file); + int fd = ::open(file, O_CREAT|O_WRONLY|O_TRUNC, 0700); + const string user("user."); + + // set N* chunk size + const string name = "user.foo"; + const string name2 = "user.bar"; + + for (int len = CHAIN_XATTR_MAX_BLOCK_LEN - 10; + len < CHAIN_XATTR_MAX_BLOCK_LEN + 10; + ++len) { + cout << len << std::endl; + const string x(len, 'x'); + char buf[len*2]; + ASSERT_EQ(len, chain_setxattr(file, name.c_str(), x.c_str(), len)); + char attrbuf[4096]; + int l = ceph_os_listxattr(file, attrbuf, sizeof(attrbuf)); + for (char *p = attrbuf; p - attrbuf < l; p += strlen(p) + 1) { + cout << " attr " << p << std::endl; + } + ASSERT_EQ(len, chain_getxattr(file, name.c_str(), buf, len*2)); + ASSERT_EQ(0, chain_removexattr(file, name.c_str())); + + ASSERT_EQ(len, chain_fsetxattr(fd, name2.c_str(), x.c_str(), len)); + l = ceph_os_flistxattr(fd, attrbuf, sizeof(attrbuf)); + for (char *p = attrbuf; p - attrbuf < l; p += strlen(p) + 1) { + cout << " attr " << p << std::endl; + } + ASSERT_EQ(len, chain_fgetxattr(fd, name2.c_str(), buf, len*2)); + ASSERT_EQ(0, chain_fremovexattr(fd, name2.c_str())); + } + + ::close(fd); + ::unlink(file); +} + TEST(chain_xattr, listxattr) { const char* file = FILENAME; ::unlink(file);