diff --git a/kmod/src/data.c b/kmod/src/data.c index bc573bfc..ca437490 100644 --- a/kmod/src/data.c +++ b/kmod/src/data.c @@ -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; diff --git a/kmod/src/dir.c b/kmod/src/dir.c index 4dc5b3da..55909f8f 100644 --- a/kmod/src/dir.c +++ b/kmod/src/dir.c @@ -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) diff --git a/kmod/src/inode.c b/kmod/src/inode.c index bd49c494..176bc306 100644 --- a/kmod/src/inode.c +++ b/kmod/src/inode.c @@ -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) diff --git a/kmod/src/item.c b/kmod/src/item.c index 2e9de37c..ac990cf6 100644 --- a/kmod/src/item.c +++ b/kmod/src/item.c @@ -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; diff --git a/kmod/src/item.h b/kmod/src/item.h index 774f0ab7..924f2fda 100644 --- a/kmod/src/item.h +++ b/kmod/src/item.h @@ -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); diff --git a/kmod/src/xattr.c b/kmod/src/xattr.c index 19dbce6f..0fac057d 100644 --- a/kmod/src/xattr.c +++ b/kmod/src/xattr.c @@ -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;