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:
Zach Brown
2017-07-19 13:30:03 -07:00
parent 4f6f842efa
commit f611c769e2
6 changed files with 31 additions and 26 deletions
+6 -6
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;