mirror of
https://github.com/versity/scoutfs.git
synced 2026-09-05 23:56:58 +00:00
scoutfs: map inode index item locks in one place
We have to map many index item keys down to a lock that then has a start and end key range. We also use this mapping over in index item locking to avoid trying to acquire locks multiple times. We were duplicating the mapping calculation in these two places. This refactors these functions to use one range calculation function. It's going to be used in future patches to fix the mapping of the size index items. This should result in no functional changes. Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
+13
-2
@@ -712,6 +712,17 @@ static int cmp_index_lock(void *priv, struct list_head *A, struct list_head *B)
|
||||
scoutfs_cmp_u64s(a->ino, b->ino);
|
||||
}
|
||||
|
||||
static void clamp_inode_index(u8 type, u64 *major, u32 *minor, u64 *ino)
|
||||
{
|
||||
struct scoutfs_inode_index_key start;
|
||||
|
||||
scoutfs_lock_get_index_item_range(type, *major, *ino, &start, NULL);
|
||||
|
||||
*major = be64_to_cpu(start.major);
|
||||
*minor = be32_to_cpu(start.minor);
|
||||
*ino = be64_to_cpu(start.ino);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the lock that covers the given index item. Returns NULL if
|
||||
* there isn't a lock that covers the item. We know that the list is
|
||||
@@ -726,7 +737,7 @@ static struct scoutfs_lock *find_index_lock(struct list_head *lock_list,
|
||||
struct index_lock needle;
|
||||
int cmp;
|
||||
|
||||
scoutfs_lock_clamp_inode_index(type, &major, &minor, &ino);
|
||||
clamp_inode_index(type, &major, &minor, &ino);
|
||||
needle.type = type;
|
||||
needle.major = major;
|
||||
needle.minor = minor;
|
||||
@@ -897,7 +908,7 @@ static int add_index_lock(struct list_head *list, u64 ino, u8 type, u64 major,
|
||||
{
|
||||
struct index_lock *ind_lock;
|
||||
|
||||
scoutfs_lock_clamp_inode_index(type, &major, &minor, &ino);
|
||||
clamp_inode_index(type, &major, &minor, &ino);
|
||||
|
||||
list_for_each_entry(ind_lock, list, head) {
|
||||
if (ind_lock->type == type && ind_lock->major == major &&
|
||||
|
||||
+61
-66
@@ -28,6 +28,7 @@
|
||||
#include "inode.h"
|
||||
#include "trans.h"
|
||||
#include "counters.h"
|
||||
#include "endian_swap.h"
|
||||
|
||||
#define LN_FMT "%u.%u.%u.%llu.%llu"
|
||||
#define LN_ARG(name) \
|
||||
@@ -630,63 +631,31 @@ int scoutfs_lock_global(struct super_block *sb, int mode, int flags, int type,
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the caller's major, minor, and ino to the start of lock that
|
||||
* covers the incoming index item. This can be used to discover when
|
||||
* multiple items map to the same lock.
|
||||
* Set the caller's index items to the range of index item keys that are
|
||||
* covered by the lock which covers the given type and major.
|
||||
*
|
||||
* We're trying to strike a balance between minimizing lock
|
||||
* communication by locking a large number of items and minimizing
|
||||
* contention and hold times by locking a small number of items.
|
||||
*
|
||||
* The seq indexes have natural batching and limits on the number of
|
||||
* keys per major value.
|
||||
*
|
||||
* The file size index are very different. For them we use a mix of a
|
||||
* sort of linear-log distribution (top 4 bits of size), and then also a
|
||||
* lot of inodes per size.
|
||||
*
|
||||
* This can also be used to find items that are covered by the same lock
|
||||
* because their starting keys are the same.
|
||||
*/
|
||||
void scoutfs_lock_clamp_inode_index(u8 type, u64 *major, u32 *minor, u64 *ino)
|
||||
void scoutfs_lock_get_index_item_range(u8 type, u64 major, u64 ino,
|
||||
struct scoutfs_inode_index_key *start,
|
||||
struct scoutfs_inode_index_key *end)
|
||||
{
|
||||
u64 major_mask;
|
||||
u64 ino_mask;
|
||||
int bit;
|
||||
|
||||
switch(type) {
|
||||
case SCOUTFS_INODE_INDEX_SIZE_TYPE:
|
||||
major_mask = 0;
|
||||
if (*major) {
|
||||
bit = fls64(*major);
|
||||
if (bit > 4)
|
||||
major_mask = (1 << (bit - 4)) - 1;
|
||||
}
|
||||
ino_mask = (1 << 12) - 1;
|
||||
break;
|
||||
|
||||
case SCOUTFS_INODE_INDEX_META_SEQ_TYPE:
|
||||
case SCOUTFS_INODE_INDEX_DATA_SEQ_TYPE:
|
||||
major_mask = SCOUTFS_LOCK_SEQ_GROUP_MASK;
|
||||
ino_mask = ~0ULL;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
*major &= ~major_mask;
|
||||
*minor = 0;
|
||||
*ino &= ~ino_mask;
|
||||
}
|
||||
|
||||
/*
|
||||
* map inode index items to locks. The idea is to not have to
|
||||
* constantly get locks over a reasonable distribution of items, but
|
||||
* also not have an insane amount of items covered by locks. time and
|
||||
* seq indexes have natural batching and limits on the number of keys
|
||||
* per major value. Size keys are very different. For them we use a
|
||||
* mix of a sort of linear-log distribution (top 4 bits of size), and
|
||||
* then also a lot of inodes per size.
|
||||
*/
|
||||
int scoutfs_lock_inode_index(struct super_block *sb, int mode,
|
||||
u8 type, u64 major, u64 ino,
|
||||
struct scoutfs_lock **ret_lock)
|
||||
{
|
||||
struct scoutfs_lock_name lock_name;
|
||||
struct scoutfs_inode_index_key start_ikey;
|
||||
struct scoutfs_inode_index_key end_ikey;
|
||||
struct scoutfs_key_buf start;
|
||||
struct scoutfs_key_buf end;
|
||||
u64 major_mask;
|
||||
u64 ino_mask;
|
||||
int bit;
|
||||
|
||||
switch(type) {
|
||||
case SCOUTFS_INODE_INDEX_SIZE_TYPE:
|
||||
major_mask = 0;
|
||||
@@ -707,24 +676,50 @@ int scoutfs_lock_inode_index(struct super_block *sb, int mode,
|
||||
BUG();
|
||||
}
|
||||
|
||||
if (start) {
|
||||
start->zone = SCOUTFS_INODE_INDEX_ZONE;
|
||||
start->type = type;
|
||||
start->major = cpu_to_be64(major & ~major_mask);
|
||||
start->minor = 0;
|
||||
start->ino = cpu_to_be64(ino & ~ino_mask);
|
||||
}
|
||||
|
||||
if (end) {
|
||||
end->zone = SCOUTFS_INODE_INDEX_ZONE;
|
||||
end->type = type;
|
||||
end->major = cpu_to_be64(major | major_mask);
|
||||
end->minor = 0;
|
||||
end->ino = cpu_to_be64(ino | ino_mask);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Lock the given index item. We use the index masks to name a reasonable
|
||||
* batch of logical items to lock and calculate the start and end
|
||||
* key values that are covered by the lock.
|
||||
*
|
||||
*/
|
||||
int scoutfs_lock_inode_index(struct super_block *sb, int mode,
|
||||
u8 type, u64 major, u64 ino,
|
||||
struct scoutfs_lock **ret_lock)
|
||||
{
|
||||
struct scoutfs_lock_name lock_name;
|
||||
struct scoutfs_inode_index_key start_ikey;
|
||||
struct scoutfs_inode_index_key end_ikey;
|
||||
struct scoutfs_key_buf start;
|
||||
struct scoutfs_key_buf end;
|
||||
|
||||
scoutfs_lock_get_index_item_range(type, major, ino,
|
||||
&start_ikey, &end_ikey);
|
||||
|
||||
lock_name.scope = SCOUTFS_LOCK_SCOPE_FS_ITEMS;
|
||||
lock_name.zone = SCOUTFS_INODE_INDEX_ZONE;
|
||||
lock_name.type = type;
|
||||
lock_name.first = cpu_to_le64(major & ~major_mask);
|
||||
lock_name.second = cpu_to_le64(ino & ~ino_mask);
|
||||
lock_name.zone = start_ikey.zone;
|
||||
lock_name.type = start_ikey.type;
|
||||
lock_name.first = be64_to_le64(start_ikey.major);
|
||||
lock_name.second = be64_to_le64(start_ikey.ino);
|
||||
|
||||
start_ikey.zone = SCOUTFS_INODE_INDEX_ZONE;
|
||||
start_ikey.type = type;
|
||||
start_ikey.major = cpu_to_be64(major & ~major_mask);
|
||||
start_ikey.minor = cpu_to_be32(0);
|
||||
start_ikey.ino = cpu_to_be64(ino & ~ino_mask);
|
||||
scoutfs_key_init(&start, &start_ikey, sizeof(start_ikey));
|
||||
|
||||
end_ikey.zone = SCOUTFS_INODE_INDEX_ZONE;
|
||||
end_ikey.type = type;
|
||||
end_ikey.major = cpu_to_be64(major | major_mask);
|
||||
end_ikey.minor = cpu_to_be32(0);
|
||||
end_ikey.ino = cpu_to_be64(ino | ino_mask);
|
||||
scoutfs_key_init(&end, &end_ikey, sizeof(end_ikey));
|
||||
|
||||
return lock_name_keys(sb, mode, 0, &lock_name,
|
||||
|
||||
+3
-1
@@ -36,7 +36,9 @@ int scoutfs_lock_inode(struct super_block *sb, int mode, int flags,
|
||||
struct inode *inode, struct scoutfs_lock **ret_lock);
|
||||
int scoutfs_lock_ino(struct super_block *sb, int mode, int flags, u64 ino,
|
||||
struct scoutfs_lock **ret_lock);
|
||||
void scoutfs_lock_clamp_inode_index(u8 type, u64 *major, u32 *minor, u64 *ino);
|
||||
void scoutfs_lock_get_index_item_range(u8 type, u64 major, u64 ino,
|
||||
struct scoutfs_inode_index_key *start,
|
||||
struct scoutfs_inode_index_key *end);
|
||||
int scoutfs_lock_inode_index(struct super_block *sb, int mode,
|
||||
u8 type, u64 major, u64 ino,
|
||||
struct scoutfs_lock **ret_lock);
|
||||
|
||||
Reference in New Issue
Block a user