break;
total += r;
i++;
- } while (r == CHAIN_XATTR_MAX_BLOCK_LEN);
+ } while (r == CHAIN_XATTR_MAX_BLOCK_LEN ||
+ r == CHAIN_XATTR_SHORT_BLOCK_LEN);
return total;
}
do {
chunk_size = (size < CHAIN_XATTR_MAX_BLOCK_LEN ? size : CHAIN_XATTR_MAX_BLOCK_LEN);
get_raw_xattr_name(name, i, raw_name, sizeof(raw_name));
- size -= chunk_size;
r = sys_getxattr(fn, raw_name, (char *)val + pos, chunk_size);
if (i && r == -ENODATA) {
break;
}
- if (r > 0)
+ if (r > 0) {
pos += r;
+ size -= r;
+ }
i++;
- } while (size && r == CHAIN_XATTR_MAX_BLOCK_LEN);
+ } while (size && (r == CHAIN_XATTR_MAX_BLOCK_LEN ||
+ r == CHAIN_XATTR_SHORT_BLOCK_LEN));
if (r >= 0) {
ret = pos;
/* is there another chunk? that can happen if the last read size span over
exactly one block */
- if (chunk_size == CHAIN_XATTR_MAX_BLOCK_LEN) {
+ if (chunk_size == CHAIN_XATTR_MAX_BLOCK_LEN ||
+ chunk_size == CHAIN_XATTR_SHORT_BLOCK_LEN) {
get_raw_xattr_name(name, i, raw_name, sizeof(raw_name));
r = sys_getxattr(fn, raw_name, 0, 0);
if (r > 0) { // there's another chunk.. the original buffer was too small
break;
total += r;
i++;
- } while (r == CHAIN_XATTR_MAX_BLOCK_LEN);
+ } while (r == CHAIN_XATTR_MAX_BLOCK_LEN ||
+ r == CHAIN_XATTR_SHORT_BLOCK_LEN);
return total;
}
do {
chunk_size = (size < CHAIN_XATTR_MAX_BLOCK_LEN ? size : CHAIN_XATTR_MAX_BLOCK_LEN);
get_raw_xattr_name(name, i, raw_name, sizeof(raw_name));
- size -= chunk_size;
r = sys_fgetxattr(fd, raw_name, (char *)val + pos, chunk_size);
if (i && r == -ENODATA) {
break;
}
- if (r > 0)
+ if (r > 0) {
pos += r;
+ size -= r;
+ }
i++;
- } while (size && r == CHAIN_XATTR_MAX_BLOCK_LEN);
+ } while (size && (r == CHAIN_XATTR_MAX_BLOCK_LEN ||
+ r == CHAIN_XATTR_SHORT_BLOCK_LEN));
if (r >= 0) {
ret = pos;
/* is there another chunk? that can happen if the last read size span over
exactly one block */
- if (chunk_size == CHAIN_XATTR_MAX_BLOCK_LEN) {
+ if (chunk_size == CHAIN_XATTR_MAX_BLOCK_LEN ||
+ chunk_size == CHAIN_XATTR_SHORT_BLOCK_LEN) {
get_raw_xattr_name(name, i, raw_name, sizeof(raw_name));
r = sys_fgetxattr(fd, raw_name, 0, 0);
if (r > 0) { // there's another chunk.. the original buffer was too small
// setxattr
+static int get_xattr_block_size(size_t size)
+{
+ if (size <= CHAIN_XATTR_SHORT_LEN_THRESHOLD)
+ // this may fit in the inode; stripe over short attrs so that XFS
+ // won't kick it out.
+ return CHAIN_XATTR_SHORT_BLOCK_LEN;
+ return CHAIN_XATTR_MAX_BLOCK_LEN;
+}
+
int chain_setxattr(const char *fn, const char *name, const void *val, size_t size)
{
int i = 0, pos = 0;
char raw_name[CHAIN_XATTR_MAX_NAME_LEN * 2 + 16];
int ret = 0;
+ size_t max_chunk_size = get_xattr_block_size(size);
do {
- size_t chunk_size = (size < CHAIN_XATTR_MAX_BLOCK_LEN ? size : CHAIN_XATTR_MAX_BLOCK_LEN);
+ size_t chunk_size = (size < max_chunk_size ? size : max_chunk_size);
get_raw_xattr_name(name, i, raw_name, sizeof(raw_name));
size -= chunk_size;
int i = 0, pos = 0;
char raw_name[CHAIN_XATTR_MAX_NAME_LEN * 2 + 16];
int ret = 0;
+ size_t max_chunk_size = get_xattr_block_size(size);
do {
- size_t chunk_size = (size < CHAIN_XATTR_MAX_BLOCK_LEN ? size : CHAIN_XATTR_MAX_BLOCK_LEN);
+ size_t chunk_size = (size < max_chunk_size ? size : max_chunk_size);
get_raw_xattr_name(name, i, raw_name, sizeof(raw_name));
size -= chunk_size;
ASSERT_EQ(0, chain_fremovexattr(fd, name2.c_str()));
}
+ for (int len = CHAIN_XATTR_SHORT_BLOCK_LEN - 10;
+ len < CHAIN_XATTR_SHORT_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));
+ }
+
+ {
+ // test tail path in chain_getxattr
+ const char *aname = "user.baz";
+ char buf[CHAIN_XATTR_SHORT_BLOCK_LEN*3];
+ memset(buf, 'x', sizeof(buf));
+ ASSERT_EQ(sizeof(buf), chain_setxattr(file, aname, buf, sizeof(buf)));
+ ASSERT_EQ(-ERANGE, chain_getxattr(file, aname, buf,
+ CHAIN_XATTR_SHORT_BLOCK_LEN*2));
+ }
+ {
+ // test tail path in chain_fgetxattr
+ const char *aname = "user.biz";
+ char buf[CHAIN_XATTR_SHORT_BLOCK_LEN*3];
+ memset(buf, 'x', sizeof(buf));
+ ASSERT_EQ(sizeof(buf), chain_fsetxattr(fd, aname, buf, sizeof(buf)));
+ ASSERT_EQ(-ERANGE, chain_fgetxattr(fd, aname, buf,
+ CHAIN_XATTR_SHORT_BLOCK_LEN*2));
+ }
+
::close(fd);
::unlink(file);
}