From 4e5530351a4836679e08c8fa1dcc5782d1a0e0c4 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Sat, 27 Oct 2012 14:35:35 -0700 Subject: [PATCH] os/chain_xattr: move chained xattr helpers into separate file/module * Rename do_* -> chain_*. * Move #defines to a header. * Fix *Index users * Implement both *xattr() and f*xattr() variants for get, set, list, remove. Signed-off-by: Sage Weil --- src/Makefile.am | 2 + src/common/xattr.h | 2 + src/os/FileStore.cc | 386 ++++--------------------------------- src/os/FlatIndex.cc | 13 +- src/os/IndexManager.cc | 7 +- src/os/LFNIndex.cc | 20 +- src/os/chain_xattr.cc | 424 +++++++++++++++++++++++++++++++++++++++++ src/os/chain_xattr.h | 73 +++++++ 8 files changed, 557 insertions(+), 370 deletions(-) create mode 100644 src/os/chain_xattr.cc create mode 100644 src/os/chain_xattr.h diff --git a/src/Makefile.am b/src/Makefile.am index 926a5321f15e4..ea5c52cabf501 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1314,6 +1314,7 @@ noinst_LIBRARIES += libmds.a libos_a_SOURCES = \ os/FileJournal.cc \ os/FileStore.cc \ + os/chain_xattr.cc \ os/ObjectStore.cc \ os/JournalingObjectStore.cc \ os/LFNIndex.cc \ @@ -1768,6 +1769,7 @@ noinst_HEADERS = \ msg/msg_types.h\ objclass/objclass.h\ os/btrfs_ioctl.h\ + os/chain_xattr.h\ os/hobject.h \ os/CollectionIndex.h\ os/FileJournal.h\ diff --git a/src/common/xattr.h b/src/common/xattr.h index 1d7ab5aee7889..30b04851fa684 100644 --- a/src/common/xattr.h +++ b/src/common/xattr.h @@ -12,6 +12,8 @@ #ifndef CEPH_EXTATTR_H #define CEPH_EXTATTR_H +#include + #ifdef __cplusplus extern "C" { #endif diff --git a/src/os/FileStore.cc b/src/os/FileStore.cc index 52894af7d6d0f..86b8597c519c3 100644 --- a/src/os/FileStore.cc +++ b/src/os/FileStore.cc @@ -38,6 +38,7 @@ #include "include/fiemap.h" #include "common/xattr.h" +#include "chain_xattr.h" #if defined(DARWIN) || defined(__FreeBSD__) #include @@ -90,9 +91,6 @@ static const __SWORD_TYPE BTRFS_SUPER_MAGIC(0x9123683E); # endif #endif -#define ATTR_MAX_NAME_LEN 128 -#define ATTR_MAX_BLOCK_LEN 2048 - #define COMMIT_SNAP_ITEM "snap_%lld" #define CLUSTER_SNAP_ITEM "clustersnap_%s" @@ -130,38 +128,6 @@ ostream& operator<<(ostream& out, const FileStore::OpSequencer& s) return out << *s.parent; } -int do_getxattr(const char *fn, const char *name, void *val, size_t size); -int do_fgetxattr(int fd, const char *name, void *val, size_t size); -int do_setxattr(const char *fn, const char *name, const void *val, size_t size); -int do_fsetxattr(int fd, const char *name, const void *val, size_t size); -int do_setxattr(const char *fn, const char *name, const void *val, size_t size); -int do_listxattr(const char *fn, char *names, size_t len); -int do_removexattr(const char *fn, const char *name); - -static int sys_fgetxattr(int fd, const char *name, void *val, size_t size) -{ - int r = ::ceph_os_fgetxattr(fd, name, val, size); - return (r < 0 ? -errno : r); -} - -static int sys_setxattr(const char *fn, const char *name, const void *val, size_t size) -{ - int r = ::ceph_os_setxattr(fn, name, val, size); - return (r < 0 ? -errno : r); -} - -static int sys_removexattr(const char *fn, const char *name) -{ - int r = ::ceph_os_removexattr(fn, name); - return (r < 0 ? -errno : r); -} - -int sys_listxattr(const char *fn, char *names, size_t len) -{ - int r = ::ceph_os_listxattr(fn, names, len); - return (r < 0 ? -errno : r); -} - int FileStore::get_cdir(coll_t cid, char *s, int len) { const string &cid_str(cid.to_str()); @@ -210,7 +176,7 @@ int FileStore::lfn_getxattr(coll_t cid, const hobject_t& oid, const char *name, int r = lfn_find(cid, oid, &path); if (r < 0) return r; - r = do_getxattr(path->path(), name, val, size); + r = chain_getxattr(path->path(), name, val, size); assert(!m_filestore_fail_eio || r != -EIO); return r; } @@ -221,7 +187,7 @@ int FileStore::lfn_setxattr(coll_t cid, const hobject_t& oid, const char *name, int r = lfn_find(cid, oid, &path); if (r < 0) return r; - r = do_setxattr(path->path(), name, val, size); + r = chain_setxattr(path->path(), name, val, size); assert(!m_filestore_fail_eio || r != -EIO); return r; } @@ -232,7 +198,7 @@ int FileStore::lfn_removexattr(coll_t cid, const hobject_t& oid, const char *nam int r = lfn_find(cid, oid, &path); if (r < 0) return r; - r = do_removexattr(path->path(), name); + r = chain_removexattr(path->path(), name); assert(!m_filestore_fail_eio || r != -EIO); return r; } @@ -243,7 +209,7 @@ int FileStore::lfn_listxattr(coll_t cid, const hobject_t& oid, char *names, size int r = lfn_find(cid, oid, &path); if (r < 0) return r; - r = do_listxattr(path->path(), names, len); + r = chain_listxattr(path->path(), names, len); assert(!m_filestore_fail_eio || r != -EIO); return r; } @@ -433,280 +399,6 @@ int FileStore::lfn_unlink(coll_t cid, const hobject_t& o, return index->unlink(o); } -static void get_raw_xattr_name(const char *name, int i, char *raw_name, int raw_len) -{ - int r; - int pos = 0; - - while (*name) { - switch (*name) { - case '@': /* escape it */ - pos += 2; - assert (pos < raw_len - 1); - *raw_name = '@'; - raw_name++; - *raw_name = '@'; - break; - default: - pos++; - assert(pos < raw_len - 1); - *raw_name = *name; - break; - } - name++; - raw_name++; - } - - if (!i) { - *raw_name = '\0'; - } else { - r = snprintf(raw_name, raw_len, "@%d", i); - assert(r < raw_len - pos); - } -} - -static int translate_raw_name(const char *raw_name, char *name, int name_len, bool *is_first) -{ - int pos = 0; - - generic_dout(10) << "translate_raw_name raw_name=" << raw_name << dendl; - const char *n = name; - - *is_first = true; - while (*raw_name) { - switch (*raw_name) { - case '@': /* escape it */ - raw_name++; - if (!*raw_name) - break; - if (*raw_name != '@') { - *is_first = false; - goto done; - } - - /* fall through */ - default: - *name = *raw_name; - break; - } - pos++; - assert(pos < name_len); - name++; - raw_name++; - } -done: - *name = '\0'; - generic_dout(10) << "translate_raw_name name=" << n << dendl; - return pos; -} - -int do_fgetxattr_len(int fd, const char *name) -{ - int i = 0, total = 0; - char raw_name[ATTR_MAX_NAME_LEN * 2 + 16]; - int r; - - do { - get_raw_xattr_name(name, i, raw_name, sizeof(raw_name)); - r = sys_fgetxattr(fd, raw_name, 0, 0); - if (!i && r < 0) - return r; - if (r < 0) - break; - total += r; - i++; - } while (r == ATTR_MAX_BLOCK_LEN); - - return total; -} - -int do_getxattr(const char *fn, const char *name, void *val, size_t size) -{ - int fd = ::open(fn, O_RDONLY); - int r = 0; - if (fd < 0) { - r = -errno; - goto out; - } - r = do_fgetxattr(fd, name, val, size); - TEMP_FAILURE_RETRY(::close(fd)); - out: - return r; -} - -int do_fgetxattr(int fd, const char *name, void *val, size_t size) -{ - int i = 0, pos = 0; - char raw_name[ATTR_MAX_NAME_LEN * 2 + 16]; - int ret = 0; - int r; - size_t chunk_size; - - if (!size) - return do_fgetxattr_len(fd, name); - - do { - chunk_size = (size < ATTR_MAX_BLOCK_LEN ? size : ATTR_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 (r < 0) { - ret = r; - break; - } - - if (r > 0) - pos += r; - - i++; - } while (size && r == ATTR_MAX_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 == ATTR_MAX_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 - ret = -ERANGE; - } - } - } - return ret; -} - -int do_setxattr(const char *fn, const char *name, const void *val, size_t size) -{ - int i = 0, pos = 0; - char raw_name[ATTR_MAX_NAME_LEN * 2 + 16]; - int ret = 0; - size_t chunk_size; - - do { - chunk_size = (size < ATTR_MAX_BLOCK_LEN ? size : ATTR_MAX_BLOCK_LEN); - get_raw_xattr_name(name, i, raw_name, sizeof(raw_name)); - size -= chunk_size; - - int r = sys_setxattr(fn, raw_name, (char *)val + pos, chunk_size); - if (r < 0) { - ret = r; - break; - } - pos += chunk_size; - ret = pos; - i++; - } while (size); - - /* if we're exactly at a chunk size, remove the next one (if wasn't removed - before) */ - if (ret >= 0 && chunk_size == ATTR_MAX_BLOCK_LEN) { - get_raw_xattr_name(name, i, raw_name, sizeof(raw_name)); - int r = do_removexattr(fn, raw_name); - if (r < 0 && r != -ENODATA) - ret = r; - } - - return ret; -} - -int do_fsetxattr(int fd, const char *name, const void *val, size_t size) -{ - int i = 0, pos = 0; - char raw_name[ATTR_MAX_NAME_LEN * 2 + 16]; - int ret = 0; - size_t chunk_size; - - do { - chunk_size = (size < ATTR_MAX_BLOCK_LEN ? size : ATTR_MAX_BLOCK_LEN); - get_raw_xattr_name(name, i, raw_name, sizeof(raw_name)); - size -= chunk_size; - - int r = ::ceph_os_fsetxattr(fd, raw_name, (char *)val + pos, chunk_size); - if (r < 0) { - ret = r; - break; - } - pos += chunk_size; - ret = pos; - i++; - } while (size); - - /* if we're exactly at a chunk size, remove the next one (if wasn't removed - before) */ - if (ret >= 0 && chunk_size == ATTR_MAX_BLOCK_LEN) { - get_raw_xattr_name(name, i, raw_name, sizeof(raw_name)); - int r = ::ceph_os_fremovexattr(fd, raw_name); - if (r < 0 && r != -ENODATA) - ret = r; - } - - return ret; -} - -int do_removexattr(const char *fn, const char *name) { - int i = 0; - char raw_name[ATTR_MAX_NAME_LEN * 2 + 16]; - int r; - - do { - get_raw_xattr_name(name, i, raw_name, sizeof(raw_name)); - r = sys_removexattr(fn, raw_name); - if (!i && r < 0) { - return r; - } - i++; - } while (r >= 0); - return 0; -} - -int do_listxattr(const char *fn, char *names, size_t len) { - int r; - - if (!len) - return sys_listxattr(fn, names, len); - - r = sys_listxattr(fn, 0, 0); - if (r < 0) - return r; - - size_t total_len = r * 2; // should be enough - char *full_buf = (char *)malloc(total_len * 2); - if (!full_buf) - return -ENOMEM; - - r = sys_listxattr(fn, full_buf, total_len); - if (r < 0) - return r; - - char *p = full_buf; - char *end = full_buf + r; - char *dest = names; - char *dest_end = names + len; - - while (p < end) { - char name[ATTR_MAX_NAME_LEN * 2 + 16]; - int attr_len = strlen(p); - bool is_first; - int name_len = translate_raw_name(p, name, sizeof(name), &is_first); - if (is_first) { - if (dest + name_len > dest_end) { - r = -ERANGE; - goto done; - } - strcpy(dest, name); - dest += name_len + 1; - } - p += attr_len + 1; - } - r = dest - names; - -done: - free(full_buf); - return r; -} - FileStore::FileStore(const std::string &base, const std::string &jdev, const char *name, bool do_update) : internal_name(name), basedir(base), journalpath(jdev), @@ -1346,9 +1038,9 @@ int FileStore::_detect_fs() return ret; } - int ret = do_setxattr(fn, "user.test", &x, sizeof(x)); + int ret = chain_setxattr(fn, "user.test", &x, sizeof(x)); if (ret >= 0) - ret = do_getxattr(fn, "user.test", &y, sizeof(y)); + ret = chain_getxattr(fn, "user.test", &y, sizeof(y)); if ((ret < 0) || (x != y)) { derr << "Extended attributes don't appear to work. "; if (ret) @@ -1362,11 +1054,11 @@ int FileStore::_detect_fs() char buf[1000]; memset(buf, 0, sizeof(buf)); // shut up valgrind - do_setxattr(fn, "user.test", &buf, sizeof(buf)); - do_setxattr(fn, "user.test2", &buf, sizeof(buf)); - do_setxattr(fn, "user.test3", &buf, sizeof(buf)); - do_setxattr(fn, "user.test4", &buf, sizeof(buf)); - ret = do_setxattr(fn, "user.test5", &buf, sizeof(buf)); + chain_setxattr(fn, "user.test", &buf, sizeof(buf)); + chain_setxattr(fn, "user.test2", &buf, sizeof(buf)); + chain_setxattr(fn, "user.test3", &buf, sizeof(buf)); + chain_setxattr(fn, "user.test4", &buf, sizeof(buf)); + ret = chain_setxattr(fn, "user.test5", &buf, sizeof(buf)); if (ret == -ENOSPC) { if (!g_conf->filestore_xattr_use_omap) { derr << "limited size xattrs -- enable filestore_xattr_use_omap" << dendl; @@ -1377,11 +1069,11 @@ int FileStore::_detect_fs() derr << "limited size xattrs -- filestore_xattr_use_omap enabled" << dendl; } } - do_removexattr(fn, "user.test"); - do_removexattr(fn, "user.test2"); - do_removexattr(fn, "user.test3"); - do_removexattr(fn, "user.test4"); - do_removexattr(fn, "user.test5"); + chain_removexattr(fn, "user.test"); + chain_removexattr(fn, "user.test2"); + chain_removexattr(fn, "user.test3"); + chain_removexattr(fn, "user.test4"); + chain_removexattr(fn, "user.test5"); ::unlink(fn); TEMP_FAILURE_RETRY(::close(tmpfd)); @@ -2525,7 +2217,7 @@ void FileStore::_set_replay_guard(int fd, bufferlist v(40); ::encode(spos, v); ::encode(in_progress, v); - int r = do_fsetxattr(fd, REPLAY_GUARD_XATTR, v.c_str(), v.length()); + int r = chain_fsetxattr(fd, REPLAY_GUARD_XATTR, v.c_str(), v.length()); if (r < 0) { r = -errno; derr << "fsetxattr " << REPLAY_GUARD_XATTR << " got " << cpp_strerror(r) << dendl; @@ -2554,7 +2246,7 @@ void FileStore::_close_replay_guard(int fd, const SequencerPosition& spos) ::encode(spos, v); bool in_progress = false; ::encode(in_progress, v); - int r = do_fsetxattr(fd, REPLAY_GUARD_XATTR, v.c_str(), v.length()); + int r = chain_fsetxattr(fd, REPLAY_GUARD_XATTR, v.c_str(), v.length()); if (r < 0) { r = -errno; derr << "fsetxattr " << REPLAY_GUARD_XATTR << " got " << cpp_strerror(r) << dendl; @@ -2608,7 +2300,7 @@ int FileStore::_check_replay_guard(int fd, const SequencerPosition& spos) return 1; char buf[100]; - int r = do_fgetxattr(fd, REPLAY_GUARD_XATTR, buf, sizeof(buf)); + int r = chain_fgetxattr(fd, REPLAY_GUARD_XATTR, buf, sizeof(buf)); if (r < 0) { dout(20) << "_check_replay_guard no xattr" << dendl; assert(!m_filestore_fail_eio || r != -EIO); @@ -3952,15 +3644,15 @@ int FileStore::_getattr(coll_t cid, const hobject_t& oid, const char *name, buff int FileStore::_getattr(const char *fn, const char *name, bufferptr& bp) { char val[100]; - int l = do_getxattr(fn, name, val, sizeof(val)); + int l = chain_getxattr(fn, name, val, sizeof(val)); if (l >= 0) { bp = buffer::create(l); memcpy(bp.c_str(), val, l); } else if (l == -ERANGE) { - l = do_getxattr(fn, name, 0, 0); + l = chain_getxattr(fn, name, 0, 0); if (l > 0) { bp = buffer::create(l); - l = do_getxattr(fn, name, bp.c_str(), l); + l = chain_getxattr(fn, name, bp.c_str(), l); } } assert(!m_filestore_fail_eio || l != -EIO); @@ -4028,18 +3720,18 @@ int FileStore::_getattrs(const char *fn, map& aset, bool user_ { // get attr list char names1[100]; - int len = do_listxattr(fn, names1, sizeof(names1)-1); + int len = chain_listxattr(fn, names1, sizeof(names1)-1); char *names2 = 0; char *name = 0; if (len == -ERANGE) { - len = do_listxattr(fn, 0, 0); + len = chain_listxattr(fn, 0, 0); if (len < 0) { assert(!m_filestore_fail_eio || len != -EIO); return len; } dout(10) << " -ERANGE, len is " << len << dendl; names2 = new char[len+1]; - len = do_listxattr(fn, names2, len); + len = chain_listxattr(fn, names2, len); dout(10) << " -ERANGE, got " << len << dendl; if (len < 0) { assert(!m_filestore_fail_eio || len != -EIO); @@ -4086,8 +3778,8 @@ int FileStore::_getattrs(const char *fn, map& aset, bool user_ int FileStore::getattr(coll_t cid, const hobject_t& oid, const char *name, bufferptr &bp) { dout(15) << "getattr " << cid << "/" << oid << " '" << name << "'" << dendl; - char n[ATTR_MAX_NAME_LEN]; - get_attrname(name, n, ATTR_MAX_NAME_LEN); + char n[CHAIN_XATTR_MAX_NAME_LEN]; + get_attrname(name, n, CHAIN_XATTR_MAX_NAME_LEN); int r = _getattr(cid, oid, n, bp); if (r == -ENODATA && g_conf->filestore_xattr_use_omap) { map got; @@ -4180,8 +3872,8 @@ int FileStore::_setattrs(coll_t cid, const hobject_t& oid, map for (map::iterator p = aset.begin(); p != aset.end(); ++p) { - char n[ATTR_MAX_NAME_LEN]; - get_attrname(p->first.c_str(), n, ATTR_MAX_NAME_LEN); + char n[CHAIN_XATTR_MAX_NAME_LEN]; + get_attrname(p->first.c_str(), n, CHAIN_XATTR_MAX_NAME_LEN); if (g_conf->filestore_xattr_use_omap) { if (p->second.length() > g_conf->filestore_max_inline_xattr_size) { if (inline_set.count(p->first)) { @@ -4217,7 +3909,7 @@ int FileStore::_setattrs(coll_t cid, const hobject_t& oid, map // ??? Why do we skip setting all the other attrs if one fails? r = lfn_setxattr(cid, oid, n, val, p->second.length()); if (r < 0) { - derr << "FileStore::_setattrs: do_setxattr returned " << r << dendl; + derr << "FileStore::_setattrs: chain_setxattr returned " << r << dendl; break; } } @@ -4251,8 +3943,8 @@ int FileStore::_rmattr(coll_t cid, const hobject_t& oid, const char *name, const SequencerPosition &spos) { dout(15) << "rmattr " << cid << "/" << oid << " '" << name << "'" << dendl; - char n[ATTR_MAX_NAME_LEN]; - get_attrname(name, n, ATTR_MAX_NAME_LEN); + char n[CHAIN_XATTR_MAX_NAME_LEN]; + get_attrname(name, n, CHAIN_XATTR_MAX_NAME_LEN); int r = lfn_removexattr(cid, oid, n); if (r == -ENODATA && g_conf->filestore_xattr_use_omap) { Index index; @@ -4283,8 +3975,8 @@ int FileStore::_rmattrs(coll_t cid, const hobject_t& oid, int r = _getattrs(cid, oid, aset); if (r >= 0) { for (map::iterator p = aset.begin(); p != aset.end(); p++) { - char n[ATTR_MAX_NAME_LEN]; - get_attrname(p->first.c_str(), n, ATTR_MAX_NAME_LEN); + char n[CHAIN_XATTR_MAX_NAME_LEN]; + get_attrname(p->first.c_str(), n, CHAIN_XATTR_MAX_NAME_LEN); r = lfn_removexattr(cid, oid, n); if (r < 0) break; @@ -4326,7 +4018,7 @@ int FileStore::collection_getattr(coll_t c, const char *name, dout(15) << "collection_getattr " << fn << " '" << name << "' len " << size << dendl; char n[PATH_MAX]; get_attrname(name, n, PATH_MAX); - int r = do_getxattr(fn, n, value, size); + int r = chain_getxattr(fn, n, value, size); dout(10) << "collection_getattr " << fn << " '" << name << "' len " << size << " = " << r << dendl; assert(!m_filestore_fail_eio || r != -EIO); return r; @@ -4368,7 +4060,7 @@ int FileStore::_collection_setattr(coll_t c, const char *name, dout(10) << "collection_setattr " << fn << " '" << name << "' len " << size << dendl; char n[PATH_MAX]; get_attrname(name, n, PATH_MAX); - int r = do_setxattr(fn, n, value, size); + int r = chain_setxattr(fn, n, value, size); dout(10) << "collection_setattr " << fn << " '" << name << "' len " << size << " = " << r << dendl; return r; } @@ -4380,7 +4072,7 @@ int FileStore::_collection_rmattr(coll_t c, const char *name) dout(15) << "collection_rmattr " << fn << dendl; char n[PATH_MAX]; get_attrname(name, n, PATH_MAX); - int r = do_removexattr(fn, n); + int r = chain_removexattr(fn, n); dout(10) << "collection_rmattr " << fn << " = " << r << dendl; return r; } @@ -4397,7 +4089,7 @@ int FileStore::_collection_setattrs(coll_t cid, map& aset) ++p) { char n[PATH_MAX]; get_attrname(p->first.c_str(), n, PATH_MAX); - r = do_setxattr(fn, n, p->second.c_str(), p->second.length()); + r = chain_setxattr(fn, n, p->second.c_str(), p->second.length()); if (r < 0) break; } dout(10) << "collection_setattrs " << fn << " = " << r << dendl; diff --git a/src/os/FlatIndex.cc b/src/os/FlatIndex.cc index b3d79f541951b..e6bf79d81450d 100644 --- a/src/os/FlatIndex.cc +++ b/src/os/FlatIndex.cc @@ -23,6 +23,8 @@ #include "osd/osd_types.h" #include +#include "chain_xattr.h" + using ceph::crypto::SHA1; /* @@ -47,9 +49,6 @@ using ceph::crypto::SHA1; #define FILENAME_PREFIX_LEN (FILENAME_SHORT_LEN - FILENAME_HASH_LEN - (sizeof(FILENAME_COOKIE) - 1) - FILENAME_EXTRA) -int do_getxattr(const char *fn, const char *name, void *val, size_t size); -int do_setxattr(const char *fn, const char *name, const void *val, size_t size); - void FlatIndex::set_ref(std::tr1::shared_ptr ref) { self_ref = ref; } @@ -128,7 +127,7 @@ static void lfn_translate(const char *path, const char *name, char *new_name, in char buf[PATH_MAX]; snprintf(buf, sizeof(buf), "%s/%s", path, name); - int r = do_getxattr(buf, LFN_ATTR, new_name, len - 1); + int r = chain_getxattr(buf, LFN_ATTR, new_name, len - 1); if (r < 0) strncpy(new_name, name, len); else @@ -249,7 +248,7 @@ static int lfn_get(const char *coll_path, const hobject_t& oid, char *pathname, int r; build_filename(filename, len - path_len, lfn, i); - r = do_getxattr(pathname, LFN_ATTR, buf, sizeof(buf)); + r = chain_getxattr(pathname, LFN_ATTR, buf, sizeof(buf)); if (r < 0) r = -errno; if (r > 0) { @@ -287,7 +286,7 @@ int FlatIndex::created(const hobject_t &hoid, const char *path) { } assert(long_name[actual_len] == '\0'); assert(long_name[actual_len - 1] != '\0'); - int r = do_setxattr(path, LFN_ATTR, long_name, actual_len); + int r = chain_setxattr(path, LFN_ATTR, long_name, actual_len); if (r < 0) return r; return 0; @@ -367,7 +366,7 @@ static int get_hobject_from_oinfo(const char *dir, const char *file, bufferptr bp(PATH_MAX); snprintf(path, sizeof(path), "%s/%s", dir, file); // Hack, user.ceph._ is the attribute used to store the object info - int r = do_getxattr(path, "user.ceph._", bp.c_str(), bp.length()); + int r = chain_getxattr(path, "user.ceph._", bp.c_str(), bp.length()); if (r < 0) return r; bufferlist bl; diff --git a/src/os/IndexManager.cc b/src/os/IndexManager.cc index 82120ebf7b02f..2165036550ff9 100644 --- a/src/os/IndexManager.cc +++ b/src/os/IndexManager.cc @@ -33,19 +33,18 @@ #include "FlatIndex.h" #include "CollectionIndex.h" -int do_getxattr(const char *fn, const char *name, void *val, size_t size); -int do_setxattr(const char *fn, const char *name, const void *val, size_t size); +#include "chain_xattr.h" static int set_version(const char *path, uint32_t version) { bufferlist bl; ::encode(version, bl); - return do_setxattr(path, "user.cephos.collection_version", bl.c_str(), + return chain_setxattr(path, "user.cephos.collection_version", bl.c_str(), bl.length()); } static int get_version(const char *path, uint32_t *version) { bufferptr bp(PATH_MAX); - int r = do_getxattr(path, "user.cephos.collection_version", + int r = chain_getxattr(path, "user.cephos.collection_version", bp.c_str(), bp.length()); if (r < 0) { if (r != -ENOENT) { diff --git a/src/os/LFNIndex.cc b/src/os/LFNIndex.cc index f73865a93b818..fc4a0d223e624 100644 --- a/src/os/LFNIndex.cc +++ b/src/os/LFNIndex.cc @@ -29,8 +29,8 @@ #include "common/debug.h" #include "include/buffer.h" #include "common/ceph_crypto.h" - #include "include/compat.h" +#include "chain_xattr.h" #include "LFNIndex.h" using ceph::crypto::SHA1; @@ -48,10 +48,6 @@ const int LFNIndex::FILENAME_PREFIX_LEN = FILENAME_SHORT_LEN - FILENAME_HASH_LE FILENAME_COOKIE.size() - FILENAME_EXTRA; -int do_getxattr(const char *fn, const char *name, void *val, size_t size); -int do_setxattr(const char *fn, const char *name, const void *val, size_t size); -int do_removexattr(const char *fn, const char *name); - /* Public methods */ void LFNIndex::set_ref(std::tr1::shared_ptr ref) { @@ -272,7 +268,7 @@ static int get_hobject_from_oinfo(const char *dir, const char *file, bufferptr bp(PATH_MAX); snprintf(path, sizeof(path), "%s/%s", dir, file); // Hack, user.ceph._ is the attribute used to store the object info - int r = do_getxattr(path, "user.ceph._", bp.c_str(), bp.length()); + int r = chain_getxattr(path, "user.ceph._", bp.c_str(), bp.length()); if (r < 0) return r; bufferlist bl; @@ -405,7 +401,7 @@ int LFNIndex::add_attr_path(const vector &path, const string &attr_name, bufferlist &attr_value) { string full_path = get_full_path_subdir(path); - return do_setxattr(full_path.c_str(), mangle_attr_name(attr_name).c_str(), + return chain_setxattr(full_path.c_str(), mangle_attr_name(attr_name).c_str(), reinterpret_cast(attr_value.c_str()), attr_value.length()); } @@ -417,7 +413,7 @@ int LFNIndex::get_attr_path(const vector &path, size_t size = 1024; // Initial while (1) { bufferptr buf(size); - int r = do_getxattr(full_path.c_str(), mangle_attr_name(attr_name).c_str(), + int r = chain_getxattr(full_path.c_str(), mangle_attr_name(attr_name).c_str(), reinterpret_cast(buf.c_str()), size); if (r > 0) { @@ -440,7 +436,7 @@ int LFNIndex::remove_attr_path(const vector &path, const string &attr_name) { string full_path = get_full_path_subdir(path); string mangled_attr_name = mangle_attr_name(attr_name); - return do_removexattr(full_path.c_str(), mangled_attr_name.c_str()); + return chain_removexattr(full_path.c_str(), mangled_attr_name.c_str()); } string LFNIndex::lfn_generate_object_name_keyless(const hobject_t &hoid) { @@ -614,7 +610,7 @@ int LFNIndex::lfn_get_name(const vector &path, for ( ; ; ++i) { candidate = lfn_get_short_name(hoid, i); candidate_path = get_full_path(path, candidate); - r = do_getxattr(candidate_path.c_str(), get_lfn_attr().c_str(), buf, sizeof(buf)); + r = chain_getxattr(candidate_path.c_str(), get_lfn_attr().c_str(), buf, sizeof(buf)); if (r < 0) { if (errno != ENODATA && errno != ENOENT) return -errno; @@ -655,7 +651,7 @@ int LFNIndex::lfn_created(const vector &path, return 0; string full_path = get_full_path(path, mangled_name); string full_name = lfn_generate_object_name(hoid); - return do_setxattr(full_path.c_str(), get_lfn_attr().c_str(), + return chain_setxattr(full_path.c_str(), get_lfn_attr().c_str(), full_name.c_str(), full_name.size()); } @@ -720,7 +716,7 @@ int LFNIndex::lfn_translate(const vector &path, // Get lfn_attr string full_path = get_full_path(path, short_name); char attr[PATH_MAX]; - int r = do_getxattr(full_path.c_str(), get_lfn_attr().c_str(), attr, sizeof(attr) - 1); + int r = chain_getxattr(full_path.c_str(), get_lfn_attr().c_str(), attr, sizeof(attr) - 1); if (r < 0) return -errno; if (r < (int)sizeof(attr)) diff --git a/src/os/chain_xattr.cc b/src/os/chain_xattr.cc new file mode 100644 index 0000000000000..bab02726c0e08 --- /dev/null +++ b/src/os/chain_xattr.cc @@ -0,0 +1,424 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "chain_xattr.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "include/assert.h" + +#if defined(__linux__) +#include +#endif + +#if defined(__FreeBSD__) +#include "include/inttypes.h" +#endif + +#include "common/xattr.h" + + +static void get_raw_xattr_name(const char *name, int i, char *raw_name, int raw_len) +{ + int r; + int pos = 0; + + while (*name) { + switch (*name) { + case '@': /* escape it */ + pos += 2; + assert (pos < raw_len - 1); + *raw_name = '@'; + raw_name++; + *raw_name = '@'; + break; + default: + pos++; + assert(pos < raw_len - 1); + *raw_name = *name; + break; + } + name++; + raw_name++; + } + + if (!i) { + *raw_name = '\0'; + } else { + r = snprintf(raw_name, raw_len, "@%d", i); + assert(r < raw_len - pos); + } +} + +static int translate_raw_name(const char *raw_name, char *name, int name_len, bool *is_first) +{ + int pos = 0; + + *is_first = true; + while (*raw_name) { + switch (*raw_name) { + case '@': /* escape it */ + raw_name++; + if (!*raw_name) + break; + if (*raw_name != '@') { + *is_first = false; + goto done; + } + + /* fall through */ + default: + *name = *raw_name; + break; + } + pos++; + assert(pos < name_len); + name++; + raw_name++; + } +done: + *name = '\0'; + return pos; +} + + +// setxattr + +static int getxattr_len(const char *fn, const char *name) +{ + int i = 0, total = 0; + char raw_name[CHAIN_XATTR_MAX_NAME_LEN * 2 + 16]; + int r; + + do { + get_raw_xattr_name(name, i, raw_name, sizeof(raw_name)); + r = sys_getxattr(fn, raw_name, 0, 0); + if (!i && r < 0) + return r; + if (r < 0) + break; + total += r; + i++; + } while (r == CHAIN_XATTR_MAX_BLOCK_LEN); + + return total; +} + +int chain_getxattr(const char *fn, const char *name, void *val, size_t size) +{ + int i = 0, pos = 0; + char raw_name[CHAIN_XATTR_MAX_NAME_LEN * 2 + 16]; + int ret = 0; + int r; + size_t chunk_size; + + if (!size) + return getxattr_len(fn, name); + + 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 (r < 0) { + ret = r; + break; + } + + if (r > 0) + pos += r; + + i++; + } while (size && r == CHAIN_XATTR_MAX_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) { + 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 + ret = -ERANGE; + } + } + } + return ret; +} + +static int chain_fgetxattr_len(int fd, const char *name) +{ + int i = 0, total = 0; + char raw_name[CHAIN_XATTR_MAX_NAME_LEN * 2 + 16]; + int r; + + do { + get_raw_xattr_name(name, i, raw_name, sizeof(raw_name)); + r = sys_fgetxattr(fd, raw_name, 0, 0); + if (!i && r < 0) + return r; + if (r < 0) + break; + total += r; + i++; + } while (r == CHAIN_XATTR_MAX_BLOCK_LEN); + + return total; +} + +int chain_fgetxattr(int fd, const char *name, void *val, size_t size) +{ + int i = 0, pos = 0; + char raw_name[CHAIN_XATTR_MAX_NAME_LEN * 2 + 16]; + int ret = 0; + int r; + size_t chunk_size; + + if (!size) + return chain_fgetxattr_len(fd, name); + + 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 (r < 0) { + ret = r; + break; + } + + if (r > 0) + pos += r; + + i++; + } while (size && r == CHAIN_XATTR_MAX_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) { + 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 + ret = -ERANGE; + } + } + } + return ret; +} + + +// setxattr + +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 chunk_size; + + 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; + + int r = ::ceph_os_setxattr(fn, raw_name, (char *)val + pos, chunk_size); + if (r < 0) { + ret = r; + break; + } + pos += chunk_size; + ret = pos; + i++; + } while (size); + + /* if we're exactly at a chunk size, remove the next one (if wasn't removed + before) */ + if (ret >= 0 && chunk_size == CHAIN_XATTR_MAX_BLOCK_LEN) { + get_raw_xattr_name(name, i, raw_name, sizeof(raw_name)); + int r = ::ceph_os_removexattr(fn, raw_name); + if (r < 0 && r != -ENODATA) + ret = r; + } + + return ret; +} + +int chain_fsetxattr(int fd, 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 chunk_size; + + 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; + + int r = ::ceph_os_fsetxattr(fd, raw_name, (char *)val + pos, chunk_size); + if (r < 0) { + ret = r; + break; + } + pos += chunk_size; + ret = pos; + i++; + } while (size); + + /* if we're exactly at a chunk size, remove the next one (if wasn't removed + before) */ + if (ret >= 0 && chunk_size == CHAIN_XATTR_MAX_BLOCK_LEN) { + get_raw_xattr_name(name, i, raw_name, sizeof(raw_name)); + int r = ::ceph_os_fremovexattr(fd, raw_name); + if (r < 0 && r != -ENODATA) + ret = r; + } + + return ret; +} + + +// removexattr + +int chain_removexattr(const char *fn, const char *name) +{ + int i = 0; + char raw_name[CHAIN_XATTR_MAX_NAME_LEN * 2 + 16]; + int r; + + do { + get_raw_xattr_name(name, i, raw_name, sizeof(raw_name)); + r = ::ceph_os_removexattr(fn, raw_name); + if (!i && r < 0) { + return r; + } + i++; + } while (r >= 0); + return 0; +} + +int chain_fremovexattr(int fd, const char *name) +{ + int i = 0; + char raw_name[CHAIN_XATTR_MAX_NAME_LEN * 2 + 16]; + int r; + + do { + get_raw_xattr_name(name, i, raw_name, sizeof(raw_name)); + r = ::ceph_os_fremovexattr(fd, raw_name); + if (!i && r < 0) { + return r; + } + i++; + } while (r >= 0); + return 0; +} + + +// listxattr + +int chain_listxattr(const char *fn, char *names, size_t len) { + int r; + + if (!len) + return ::ceph_os_listxattr(fn, names, len); + + r = ::ceph_os_listxattr(fn, 0, 0); + if (r < 0) + return r; + + size_t total_len = r * 2; // should be enough + char *full_buf = (char *)malloc(total_len * 2); + if (!full_buf) + return -ENOMEM; + + r = ::ceph_os_listxattr(fn, full_buf, total_len); + if (r < 0) + return r; + + char *p = full_buf; + char *end = full_buf + r; + char *dest = names; + char *dest_end = names + len; + + while (p < end) { + char name[CHAIN_XATTR_MAX_NAME_LEN * 2 + 16]; + int attr_len = strlen(p); + bool is_first; + int name_len = translate_raw_name(p, name, sizeof(name), &is_first); + if (is_first) { + if (dest + name_len > dest_end) { + r = -ERANGE; + goto done; + } + strcpy(dest, name); + dest += name_len + 1; + } + p += attr_len + 1; + } + r = dest - names; + +done: + free(full_buf); + return r; +} + +int chain_flistxattr(int fd, char *names, size_t len) { + int r; + + if (!len) + return ::ceph_os_flistxattr(fd, names, len); + + r = ::ceph_os_flistxattr(fd, 0, 0); + if (r < 0) + return r; + + size_t total_len = r * 2; // should be enough + char *full_buf = (char *)malloc(total_len * 2); + if (!full_buf) + return -ENOMEM; + + r = ::ceph_os_flistxattr(fd, full_buf, total_len); + if (r < 0) + return r; + + char *p = full_buf; + char *end = full_buf + r; + char *dest = names; + char *dest_end = names + len; + + while (p < end) { + char name[CHAIN_XATTR_MAX_NAME_LEN * 2 + 16]; + int attr_len = strlen(p); + bool is_first; + int name_len = translate_raw_name(p, name, sizeof(name), &is_first); + if (is_first) { + if (dest + name_len > dest_end) { + r = -ERANGE; + goto done; + } + strcpy(dest, name); + dest += name_len + 1; + } + p += attr_len + 1; + } + r = dest - names; + +done: + free(full_buf); + return r; +} diff --git a/src/os/chain_xattr.h b/src/os/chain_xattr.h new file mode 100644 index 0000000000000..7e8312ff32b2a --- /dev/null +++ b/src/os/chain_xattr.h @@ -0,0 +1,73 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#ifndef __CEPH_OSD_CHAIN_XATTR_H +#define __CEPH_OSD_CHAIN_XATTR_H + +#include "common/xattr.h" + +#include + +#define CHAIN_XATTR_MAX_NAME_LEN 128 +#define CHAIN_XATTR_MAX_BLOCK_LEN 2048 + + +// wrappers to hide annoying errno handling. + +static inline int sys_fgetxattr(int fd, const char *name, void *val, size_t size) +{ + int r = ::ceph_os_fgetxattr(fd, name, val, size); + return (r < 0 ? -errno : r); +} +static inline int sys_getxattr(const char *fn, const char *name, void *val, size_t size) +{ + int r = ::ceph_os_getxattr(fn, name, val, size); + return (r < 0 ? -errno : r); +} + +static inline int sys_setxattr(const char *fn, const char *name, const void *val, size_t size) +{ + int r = ::ceph_os_setxattr(fn, name, val, size); + return (r < 0 ? -errno : r); +} +static inline int sys_fsetxattr(int fd, const char *name, const void *val, size_t size) +{ + int r = ::ceph_os_fsetxattr(fd, name, val, size); + return (r < 0 ? -errno : r); +} + +static inline int sys_listxattr(const char *fn, char *names, size_t len) +{ + int r = ::ceph_os_listxattr(fn, names, len); + return (r < 0 ? -errno : r); +} +static inline int sys_flistxattr(int fd, char *names, size_t len) +{ + int r = ::ceph_os_flistxattr(fd, names, len); + return (r < 0 ? -errno : r); +} + +static inline int sys_removexattr(const char *fn, const char *name) +{ + int r = ::ceph_os_removexattr(fn, name); + return (r < 0 ? -errno : r); +} +static inline int sys_fremovexattr(int fd, const char *name) +{ + int r = ::ceph_os_fremovexattr(fd, name); + return (r < 0 ? -errno : r); +} + + +// wrappers to chain large values across multiple xattrs + +int chain_getxattr(const char *fn, const char *name, void *val, size_t size); +int chain_fgetxattr(int fd, const char *name, void *val, size_t size); +int chain_setxattr(const char *fn, const char *name, const void *val, size_t size); +int chain_fsetxattr(int fd, const char *name, const void *val, size_t size); +int chain_listxattr(const char *fn, char *names, size_t len); +int chain_flistxattr(int fd, char *names, size_t len); +int chain_removexattr(const char *fn, const char *name); +int chain_fremovexattr(int fd, const char *name); + +#endif -- 2.39.5