mirror of
https://github.com/versity/scoutfs.git
synced 2026-09-27 18:34:35 +00:00
Use contiguous key struct instead of kvecs
Using kvecs for keys seemed like a good idea because there were a few uses that had keys in fragmented memory: dirent keys made up of an on-stack struct and the file name in the dentry, and keys straddling the pages that make up a cached segment. But it hasn't worked out very well. The code to perform ops on keys by iterating over vectors is pretty fiddly. And the raw kvecs only describe the actively referenced key, they know nothing about the total size of the buffer that the key resides in. Some ops can't check that they're not clobbering things, they're relying on callers not to mess up. And critically, the kvec iteration's become a bottleneck. It turns out that comparing keys is a very hot path in the item cache. All the code to initialize and iterate over two key vectors adds up when each high level fs operation is a few tree descents and each tree descent is a bunch of compares. So let's back off and have a specific struct for tracking keys that are stored in contiguous memory regions. Users ensure that keys are contiguous. The code ends up being a lot clearer, code now can see how big the full key buffer is, and the rbtree node comparison fast path is now just a memcmp. Almost all of the changes in the patch are mechanical semantic changes involving types, function names, args, and occasionaly slightly different return conventions. A slightly more involved change is that now dirent key users have to manage an allocated contiguous key with a copy of the path from the dentry. Item reading is now a little more clever about calculating the greatest range it can cache by initially walking all the segments instead of trying to do it as it runs out of items in each segment. The largest meaningful change is that now keys can't straddle page boundaries in memory which means they can't cross block boundaries in the segment. We align key offsets to the next block as we write keys to segments that would have straddled a block. We then also have to account for that padding when building segments. We add a helper that calculates if a given number of items will fit in a segment which is used by item dirtying, segment writing, and compaction. I left the tracepoint formatting for another patch. Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
+16
-17
@@ -127,26 +127,28 @@ static void load_inode(struct inode *inode, struct scoutfs_inode *cinode)
|
||||
ci->data_version = le64_to_cpu(cinode->data_version);
|
||||
}
|
||||
|
||||
static void set_inode_key(struct scoutfs_inode_key *ikey, u64 ino)
|
||||
static void init_inode_key(struct scoutfs_key_buf *key,
|
||||
struct scoutfs_inode_key *ikey, u64 ino)
|
||||
{
|
||||
ikey->type = SCOUTFS_INODE_KEY;
|
||||
ikey->ino = cpu_to_be64(ino);
|
||||
|
||||
scoutfs_key_init(key, ikey, sizeof(struct scoutfs_inode_key));
|
||||
}
|
||||
|
||||
static int scoutfs_read_locked_inode(struct inode *inode)
|
||||
{
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct scoutfs_inode_key ikey;
|
||||
struct scoutfs_key_buf key;
|
||||
struct scoutfs_inode sinode;
|
||||
SCOUTFS_DECLARE_KVEC(key);
|
||||
SCOUTFS_DECLARE_KVEC(val);
|
||||
int ret;
|
||||
|
||||
set_inode_key(&ikey, scoutfs_ino(inode));
|
||||
scoutfs_kvec_init(key, &ikey, sizeof(ikey));
|
||||
init_inode_key(&key, &ikey, scoutfs_ino(inode));
|
||||
scoutfs_kvec_init(val, &sinode, sizeof(sinode));
|
||||
|
||||
ret = scoutfs_item_lookup_exact(sb, key, val, sizeof(sinode));
|
||||
ret = scoutfs_item_lookup_exact(sb, &key, val, sizeof(sinode));
|
||||
if (ret == 0)
|
||||
load_inode(inode, &sinode);
|
||||
|
||||
@@ -269,16 +271,15 @@ int scoutfs_dirty_inode_item(struct inode *inode)
|
||||
{
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct scoutfs_inode_key ikey;
|
||||
struct scoutfs_key_buf key;
|
||||
struct scoutfs_inode sinode;
|
||||
SCOUTFS_DECLARE_KVEC(key);
|
||||
int ret;
|
||||
|
||||
store_inode(&sinode, inode);
|
||||
|
||||
set_inode_key(&ikey, scoutfs_ino(inode));
|
||||
scoutfs_kvec_init(key, &ikey, sizeof(ikey));
|
||||
init_inode_key(&key, &ikey, scoutfs_ino(inode));
|
||||
|
||||
ret = scoutfs_item_dirty(sb, key);
|
||||
ret = scoutfs_item_dirty(sb, &key);
|
||||
if (!ret)
|
||||
trace_scoutfs_dirty_inode(inode);
|
||||
return ret;
|
||||
@@ -297,18 +298,17 @@ void scoutfs_update_inode_item(struct inode *inode)
|
||||
{
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct scoutfs_inode_key ikey;
|
||||
struct scoutfs_key_buf key;
|
||||
struct scoutfs_inode sinode;
|
||||
SCOUTFS_DECLARE_KVEC(key);
|
||||
SCOUTFS_DECLARE_KVEC(val);
|
||||
int err;
|
||||
|
||||
store_inode(&sinode, inode);
|
||||
|
||||
set_inode_key(&ikey, scoutfs_ino(inode));
|
||||
scoutfs_kvec_init(key, &ikey, sizeof(ikey));
|
||||
init_inode_key(&key, &ikey, scoutfs_ino(inode));
|
||||
scoutfs_kvec_init(val, &sinode, sizeof(sinode));
|
||||
|
||||
err = scoutfs_item_update(sb, key, val);
|
||||
err = scoutfs_item_update(sb, &key, val);
|
||||
BUG_ON(err);
|
||||
|
||||
trace_scoutfs_update_inode(inode);
|
||||
@@ -388,8 +388,8 @@ struct inode *scoutfs_new_inode(struct super_block *sb, struct inode *dir,
|
||||
{
|
||||
struct scoutfs_inode_info *ci;
|
||||
struct scoutfs_inode_key ikey;
|
||||
struct scoutfs_key_buf key;
|
||||
struct scoutfs_inode sinode;
|
||||
SCOUTFS_DECLARE_KVEC(key);
|
||||
SCOUTFS_DECLARE_KVEC(val);
|
||||
struct inode *inode;
|
||||
u64 ino;
|
||||
@@ -419,11 +419,10 @@ struct inode *scoutfs_new_inode(struct super_block *sb, struct inode *dir,
|
||||
set_inode_ops(inode);
|
||||
|
||||
store_inode(&sinode, inode);
|
||||
set_inode_key(&ikey, scoutfs_ino(inode));
|
||||
scoutfs_kvec_init(key, &ikey, sizeof(ikey));
|
||||
init_inode_key(&key, &ikey, scoutfs_ino(inode));
|
||||
scoutfs_kvec_init(val, &sinode, sizeof(sinode));
|
||||
|
||||
ret = scoutfs_item_create(sb, key, val);
|
||||
ret = scoutfs_item_create(sb, &key, val);
|
||||
if (ret) {
|
||||
iput(inode);
|
||||
return ERR_PTR(ret);
|
||||
|
||||
Reference in New Issue
Block a user