mirror of
https://github.com/versity/scoutfs.git
synced 2026-08-28 03:46:12 +00:00
scoutfs: add 'end' to item_next to limit reads
Add an end key to the item_next calls to limit how many items will be read into the cache. Callers typically get this from the lock they hold that covers the iteration. We differentiate between iteration and caching so that a series of small iterations (listxattr on inodes, namespace walk in small dirs) can be satisfied by a single read of adjacent items from segments. Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
+6
-6
@@ -309,7 +309,7 @@ static int try_merge(struct super_block *sb, struct native_extent *cur,
|
||||
ext.flags = 0;
|
||||
init_extent_key(&key, key_bytes, &ext, arg, type);
|
||||
|
||||
ret = scoutfs_item_next_same(sb, &key, &last, NULL);
|
||||
ret = scoutfs_item_next_same(sb, &key, &last, NULL, NULL);
|
||||
if (ret < 0) {
|
||||
if (ret == -ENOENT)
|
||||
ret = 0;
|
||||
@@ -455,7 +455,7 @@ static int remove_extent(struct super_block *sb,
|
||||
|
||||
/* find outer existing extent that contains removal extent */
|
||||
init_extent_key(&key, key_bytes, rem, arg, type);
|
||||
ret = scoutfs_item_next_same(sb, &key, &last, NULL);
|
||||
ret = scoutfs_item_next_same(sb, &key, &last, NULL, NULL);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
@@ -552,7 +552,7 @@ int scoutfs_data_truncate_items(struct super_block *sb, u64 ino, u64 iblock,
|
||||
init_extent_key(&key, key_bytes, &rng, ino,
|
||||
SCOUTFS_FILE_EXTENT_TYPE);
|
||||
|
||||
ret = scoutfs_item_next_same(sb, &key, &last, NULL);
|
||||
ret = scoutfs_item_next_same(sb, &key, &last, NULL, NULL);
|
||||
if (ret < 0) {
|
||||
if (ret == -ENOENT)
|
||||
ret = 0;
|
||||
@@ -797,7 +797,7 @@ retry:
|
||||
init_extent_key(&key, key_bytes, &ext, sbi->node_id, type);
|
||||
init_extent_key(&last, last_bytes, &last_ext, sbi->node_id, type);
|
||||
|
||||
ret = scoutfs_item_next_same(sb, &key, &last, NULL);
|
||||
ret = scoutfs_item_next_same(sb, &key, &last, NULL, NULL);
|
||||
if (ret < 0) {
|
||||
if (ret == -ENOENT) {
|
||||
/* if the cursor's empty fall back to next large */
|
||||
@@ -966,7 +966,7 @@ static int scoutfs_get_block(struct inode *inode, sector_t iblock,
|
||||
* item consistency.
|
||||
*/
|
||||
down_read(&datinf->alloc_rwsem);
|
||||
ret = scoutfs_item_next_same(sb, &key, &last, NULL);
|
||||
ret = scoutfs_item_next_same(sb, &key, &last, NULL, NULL);
|
||||
up_read(&datinf->alloc_rwsem);
|
||||
if (ret < 0) {
|
||||
if (ret == -ENOENT)
|
||||
@@ -1146,7 +1146,7 @@ int scoutfs_data_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||
ext.flags = 0;
|
||||
init_extent_key(&key, key_bytes, &ext, ino, type);
|
||||
|
||||
ret = scoutfs_item_next_same(sb, &key, &last, NULL);
|
||||
ret = scoutfs_item_next_same(sb, &key, &last, NULL, NULL);
|
||||
if (ret < 0) {
|
||||
if (ret != -ENOENT)
|
||||
break;
|
||||
|
||||
+2
-2
@@ -344,7 +344,7 @@ static int scoutfs_readdir(struct file *file, void *dirent, filldir_t filldir)
|
||||
|
||||
scoutfs_kvec_init(val, dent, item_len);
|
||||
ret = scoutfs_item_next_same_min(sb, &key, &last_key, val,
|
||||
offsetof(struct scoutfs_dirent, name[1]));
|
||||
offsetof(struct scoutfs_dirent, name[1]), NULL);
|
||||
if (ret < 0) {
|
||||
if (ret == -ENOENT)
|
||||
ret = 0;
|
||||
@@ -878,7 +878,7 @@ static int add_next_linkref(struct super_block *sb, u64 ino,
|
||||
init_link_backref_key(&last, &last_lbkey, ino, U64_MAX, NULL, 0);
|
||||
|
||||
/* next backref key is now in ent */
|
||||
ret = scoutfs_item_next(sb, &key, &last, NULL);
|
||||
ret = scoutfs_item_next(sb, &key, &last, NULL, NULL);
|
||||
trace_printk("ino %llu dir_ino %llu ret %d key_len %u\n",
|
||||
ino, dir_ino, ret, key.key_len);
|
||||
if (ret < 0)
|
||||
|
||||
+1
-1
@@ -933,7 +933,7 @@ int scoutfs_scan_orphans(struct super_block *sb)
|
||||
init_orphan_key(&last, &last_okey, sbi->node_id, ~0ULL);
|
||||
|
||||
while (1) {
|
||||
ret = scoutfs_item_next_same(sb, &key, &last, NULL);
|
||||
ret = scoutfs_item_next_same(sb, &key, &last, NULL, NULL);
|
||||
if (ret == -ENOENT) /* No more orphan items */
|
||||
break;
|
||||
if (ret < 0)
|
||||
|
||||
+14
-12
@@ -844,6 +844,10 @@ static struct cached_item *item_for_next(struct rb_root *root,
|
||||
* Return the next item starting with the given key, returning the last
|
||||
* key at the most.
|
||||
*
|
||||
* While iteration stops the last key we can cache up to the end key so
|
||||
* that a sequence of small iterations covered by one lock are satisfied
|
||||
* with a large read of items from segments into the cache.
|
||||
*
|
||||
* -ENOENT is returned if there are no items between the given and last
|
||||
* keys.
|
||||
*
|
||||
@@ -855,12 +859,12 @@ static struct cached_item *item_for_next(struct rb_root *root,
|
||||
* by the caller's value buffer length.
|
||||
*/
|
||||
int scoutfs_item_next(struct super_block *sb, struct scoutfs_key_buf *key,
|
||||
struct scoutfs_key_buf *last, struct kvec *val)
|
||||
struct scoutfs_key_buf *last, struct kvec *val,
|
||||
struct scoutfs_key_buf *end)
|
||||
{
|
||||
struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb);
|
||||
struct item_cache *cac = sbi->item_cache;
|
||||
struct scoutfs_key_buf *read_start = NULL;
|
||||
struct scoutfs_key_buf *read_end = NULL;
|
||||
struct scoutfs_key_buf *range_end = NULL;
|
||||
struct cached_item *item;
|
||||
unsigned long flags;
|
||||
@@ -874,9 +878,8 @@ int scoutfs_item_next(struct super_block *sb, struct scoutfs_key_buf *key,
|
||||
}
|
||||
|
||||
read_start = scoutfs_key_alloc(sb, SCOUTFS_MAX_KEY_SIZE);
|
||||
read_end = scoutfs_key_alloc(sb, SCOUTFS_MAX_KEY_SIZE);
|
||||
range_end = scoutfs_key_alloc(sb, SCOUTFS_MAX_KEY_SIZE);
|
||||
if (!read_start || !read_end || !range_end) {
|
||||
if (!read_start || !range_end) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
@@ -902,12 +905,10 @@ int scoutfs_item_next(struct super_block *sb, struct scoutfs_key_buf *key,
|
||||
if (!cached) {
|
||||
/* missing cache starts at key */
|
||||
scoutfs_key_copy(read_start, key);
|
||||
scoutfs_key_copy(read_end, range_end);
|
||||
|
||||
} else if (scoutfs_key_compare(range_end, last) < 0) {
|
||||
/* missing cache starts at range_end */
|
||||
scoutfs_key_copy(read_start, range_end);
|
||||
scoutfs_key_copy(read_end, last);
|
||||
|
||||
} else {
|
||||
/* no items and we have cache between key and last */
|
||||
@@ -917,7 +918,7 @@ int scoutfs_item_next(struct super_block *sb, struct scoutfs_key_buf *key,
|
||||
|
||||
spin_unlock_irqrestore(&cac->lock, flags);
|
||||
|
||||
ret = scoutfs_manifest_read_items(sb, read_start, read_end);
|
||||
ret = scoutfs_manifest_read_items(sb, read_start, end);
|
||||
|
||||
spin_lock_irqsave(&cac->lock, flags);
|
||||
if (ret)
|
||||
@@ -927,7 +928,6 @@ int scoutfs_item_next(struct super_block *sb, struct scoutfs_key_buf *key,
|
||||
spin_unlock_irqrestore(&cac->lock, flags);
|
||||
out:
|
||||
scoutfs_key_free(sb, read_start);
|
||||
scoutfs_key_free(sb, read_end);
|
||||
scoutfs_key_free(sb, range_end);
|
||||
|
||||
trace_printk("ret %d\n", ret);
|
||||
@@ -943,7 +943,8 @@ out:
|
||||
int scoutfs_item_next_same_min(struct super_block *sb,
|
||||
struct scoutfs_key_buf *key,
|
||||
struct scoutfs_key_buf *last,
|
||||
struct kvec *val, int len)
|
||||
struct kvec *val, int len,
|
||||
struct scoutfs_key_buf *end)
|
||||
{
|
||||
int key_len = key->key_len;
|
||||
int ret;
|
||||
@@ -953,7 +954,7 @@ int scoutfs_item_next_same_min(struct super_block *sb,
|
||||
if (WARN_ON_ONCE(!val || scoutfs_kvec_length(val) < len))
|
||||
return -EINVAL;
|
||||
|
||||
ret = scoutfs_item_next(sb, key, last, val);
|
||||
ret = scoutfs_item_next(sb, key, last, val, end);
|
||||
if (ret >= 0 && (key->key_len != key_len || ret < len))
|
||||
ret = -EIO;
|
||||
|
||||
@@ -967,14 +968,15 @@ int scoutfs_item_next_same_min(struct super_block *sb,
|
||||
* search key. It treats size mismatches as a sign of corruption.
|
||||
*/
|
||||
int scoutfs_item_next_same(struct super_block *sb, struct scoutfs_key_buf *key,
|
||||
struct scoutfs_key_buf *last, struct kvec *val)
|
||||
struct scoutfs_key_buf *last, struct kvec *val,
|
||||
struct scoutfs_key_buf *end)
|
||||
{
|
||||
int key_len = key->key_len;
|
||||
int ret;
|
||||
|
||||
trace_printk("key len %u\n", key_len);
|
||||
|
||||
ret = scoutfs_item_next(sb, key, last, val);
|
||||
ret = scoutfs_item_next(sb, key, last, val, end);
|
||||
if (ret >= 0 && (key->key_len != key_len))
|
||||
ret = -EIO;
|
||||
|
||||
|
||||
+6
-3
@@ -18,13 +18,16 @@ int scoutfs_item_lookup_exact(struct super_block *sb,
|
||||
struct scoutfs_key_buf *key, struct kvec *val,
|
||||
int size, struct scoutfs_key_buf *end);
|
||||
int scoutfs_item_next(struct super_block *sb, struct scoutfs_key_buf *key,
|
||||
struct scoutfs_key_buf *last, struct kvec *val);
|
||||
struct scoutfs_key_buf *last, struct kvec *val,
|
||||
struct scoutfs_key_buf *end);
|
||||
int scoutfs_item_next_same_min(struct super_block *sb,
|
||||
struct scoutfs_key_buf *key,
|
||||
struct scoutfs_key_buf *last,
|
||||
struct kvec *val, int len);
|
||||
struct kvec *val, int len,
|
||||
struct scoutfs_key_buf *end);
|
||||
int scoutfs_item_next_same(struct super_block *sb, struct scoutfs_key_buf *key,
|
||||
struct scoutfs_key_buf *last, struct kvec *val);
|
||||
struct scoutfs_key_buf *last, struct kvec *val,
|
||||
struct scoutfs_key_buf *end);
|
||||
int scoutfs_item_create(struct super_block *sb, struct scoutfs_key_buf *key,
|
||||
struct kvec *val);
|
||||
int scoutfs_item_dirty(struct super_block *sb, struct scoutfs_key_buf *key);
|
||||
|
||||
+2
-2
@@ -394,7 +394,7 @@ ssize_t scoutfs_listxattr(struct dentry *dentry, char *buffer, size_t size)
|
||||
|
||||
total = 0;
|
||||
for (;;) {
|
||||
ret = scoutfs_item_next(sb, key, last, NULL);
|
||||
ret = scoutfs_item_next(sb, key, last, NULL, lck->end);
|
||||
if (ret < 0) {
|
||||
if (ret == -ENOENT)
|
||||
ret = total;
|
||||
@@ -476,7 +476,7 @@ int scoutfs_xattr_drop(struct super_block *sb, u64 ino)
|
||||
/* the inode is dead so we don't need the xattr sem */
|
||||
|
||||
for (;;) {
|
||||
ret = scoutfs_item_next(sb, key, last, NULL);
|
||||
ret = scoutfs_item_next(sb, key, last, NULL, lck->end);
|
||||
if (ret < 0) {
|
||||
if (ret == -ENOENT)
|
||||
ret = 0;
|
||||
|
||||
Reference in New Issue
Block a user