mirror of
https://github.com/versity/scoutfs.git
synced 2026-05-03 11:25:43 +00:00
Compare commits
45 Commits
v1.29
...
auke/rhel1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
13fe77fc64 | ||
|
|
cd868b5bda | ||
|
|
98b2fe2510 | ||
|
|
e69d4426d8 | ||
|
|
f8d40497bd | ||
|
|
5eaea548f8 | ||
|
|
da6dff7336 | ||
|
|
788e12d6c8 | ||
|
|
8bc8312441 | ||
|
|
ac006094ff | ||
|
|
800bced7d6 | ||
|
|
cc9b3ae3a9 | ||
|
|
414b63004c | ||
|
|
85997d0b80 | ||
|
|
a41f3050ae | ||
|
|
82b2684e9b | ||
|
|
313945cbcf | ||
|
|
2b221c1ba7 | ||
|
|
93442500a1 | ||
|
|
3616783836 | ||
|
|
4184d7557c | ||
|
|
a5780b7d00 | ||
|
|
ea9e4e9013 | ||
|
|
af31b9f1e8 | ||
|
|
ad65116d8f | ||
|
|
e20765a9c7 | ||
|
|
066da5c2a2 | ||
|
|
7eacc7139c | ||
|
|
9e3b01b3b4 | ||
|
|
876c233f06 | ||
|
|
6aa5876c71 | ||
|
|
7a9f9ec698 | ||
|
|
fc0fc1427f | ||
|
|
ec68845201 | ||
|
|
5e2009f939 | ||
|
|
8bdc20af21 | ||
|
|
857a39579e | ||
|
|
38d36c9f5c | ||
|
|
b724567b2a | ||
|
|
add1da10dc | ||
|
|
b9c49629a2 | ||
|
|
9737009437 | ||
|
|
3d54ae03e6 | ||
|
|
e27ec0add6 | ||
|
|
5457741672 |
@@ -1,6 +1,23 @@
|
||||
Versity ScoutFS Release Notes
|
||||
=============================
|
||||
|
||||
---
|
||||
v1.30
|
||||
\
|
||||
*Apr 21, 2026*
|
||||
|
||||
Fix a problem reading the accumulated totals of contributing .totl.
|
||||
xattrs when log merging is in progress. The problem would have readers
|
||||
of the totals calculate the sums incorrectly.
|
||||
|
||||
Fix a problem updating quota rules. There was a race where updates
|
||||
could be corrupted if they happened while a transaction was being
|
||||
written.
|
||||
|
||||
Fix a problem deleting files with .indx. xattrs. The internal indexing
|
||||
metadata wouldn't be properly deleted so the files would still claim to
|
||||
be present and visible in the index, though the file no longer existed.
|
||||
|
||||
---
|
||||
v1.29
|
||||
\
|
||||
|
||||
@@ -60,11 +60,11 @@ scoutfs-y += \
|
||||
#
|
||||
.PHONY: $(src)/check_exported_types
|
||||
$(src)/check_exported_types:
|
||||
@if egrep '\<[us](8|16|32|64\>)' $(src)/format.h $(src)/ioctl.h; then \
|
||||
@if grep -E '\<[us](8|16|32|64\>)' $(src)/format.h $(src)/ioctl.h; then \
|
||||
echo "no raw types in exported headers, preface with __"; \
|
||||
exit 1; \
|
||||
fi
|
||||
@if egrep '\<__packed\>' $(src)/format.h $(src)/ioctl.h; then \
|
||||
@if grep -E '\<__packed\>' $(src)/format.h $(src)/ioctl.h; then \
|
||||
echo "no __packed allowed in exported headers"; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
@@ -496,3 +496,131 @@ endif
|
||||
ifneq (,$(shell grep 'struct posix_acl.*get_inode_acl' include/linux/fs.h))
|
||||
ccflags-y += -DKC_GET_INODE_ACL
|
||||
endif
|
||||
|
||||
#
|
||||
# v6.1-rc5-2-ge9a688bcb193
|
||||
#
|
||||
# get_random_u32_below() implementation
|
||||
ifneq (,$(shell grep 'u32 get_random_u32_below' include/linux/random.h))
|
||||
ccflags-y += -DKC_HAVE_GET_RANDOM_U32_BELOW
|
||||
endif
|
||||
|
||||
# v6.5-rc1-7-g9b6304c1d537
|
||||
#
|
||||
# ctime accessor methods
|
||||
ifneq (,$(shell grep 'timespec64 inode_set_ctime_current' include/linux/fs.h))
|
||||
ccflags-y += -DKC_FS_INODE_C_TIME_ACCESSOR
|
||||
endif
|
||||
|
||||
#
|
||||
# v6.6-rc5-1-g077c212f0344
|
||||
#
|
||||
# Must use access methods from fs.h to get to inode ctime/mtime/atime
|
||||
ifneq (,$(shell grep 'inline time64_t inode_get_atime_sec' include/linux/fs.h))
|
||||
ccflags-y += -DKC_FS_INODE_AM_TIME_ACCESSOR
|
||||
endif
|
||||
|
||||
#
|
||||
# v6.12-rc1-3-g5f60d5f6bbc1
|
||||
#
|
||||
# asm/unaligned.h replaced with linux/unaligned.h
|
||||
ifneq (,$(shell grep -s 'define __LINUX_UNALIGNED_H' include/linux/unaligned.h))
|
||||
ccflags-y += -DKC_HAVE__LINUX_UNALIGNED_H
|
||||
endif
|
||||
|
||||
#
|
||||
# v6.9-rc4-29-g203c1ce0bb06
|
||||
#
|
||||
# RIP bd_inode. (note, struct moved between headers!)
|
||||
ifneq (,$(shell grep -s 'struct inode.*bd_inode' include/linux/blk_types.h include/linux/fs.h))
|
||||
ccflags-y += -DKC_HAVE_BD_INODE
|
||||
endif
|
||||
|
||||
#
|
||||
# v6.8-9146-gc759e609030c
|
||||
#
|
||||
# Removes __assign_str_len() and removes the 2nd param of __assign_str().
|
||||
ifneq (,$(shell grep -s 'define __assign_str.dst, src' \
|
||||
include/trace/trace_events.h \
|
||||
include/trace/ftrace.h \
|
||||
include/trace/stages/stage6_event_callback.h))
|
||||
ccflags-y += -DKC_HAVE_ASSIGN_STR_PARMS
|
||||
endif
|
||||
|
||||
#
|
||||
# v6.5-113-g615e95831ec3
|
||||
#
|
||||
ifneq (,$(shell grep 'generic_fillattr..*,.u32,' include/linux/fs.h))
|
||||
ccflags-y += -DKC_GENERIC_FILLATTR_REQUEST_MASK
|
||||
endif
|
||||
|
||||
#
|
||||
# v6.6-rc4-53-gc42d50aefd17
|
||||
#
|
||||
# el10 yet again modifies the shrinker API significantly, breaking our current
|
||||
# implementation.
|
||||
ifneq (,$(shell grep 'struct shrinker .shrinker_alloc' include/linux/shrinker.h))
|
||||
ccflags-y += -DKC_SHRINKER_ALLOC
|
||||
endif
|
||||
|
||||
#
|
||||
# v6.9-rc4-8-gead083aeeed9
|
||||
#
|
||||
# set_blocksize() now has a struct file arg.
|
||||
ifneq (,$(shell grep -s 'int set_blocksize.struct file' include/linux/blkdev.h))
|
||||
ccflags-y += -DKC_BLKDEV_SET_BLOCKSIZE_FILE
|
||||
endif
|
||||
|
||||
#
|
||||
# v5.1-rc3-29-gaa30f47cf666
|
||||
#
|
||||
# struct kobj_type now has member `default_groups`
|
||||
ifneq (,$(shell grep 'const struct attribute_group ..default_groups;' include/linux/kobject.h))
|
||||
ccflags-y += -DKC_KOBJECT_DEFAULT_GROUPS
|
||||
endif
|
||||
|
||||
#
|
||||
# v5.19-rc3-395-g67235182a41c
|
||||
#
|
||||
# Adds buffer_migrate_folio(), similar to other fss. Quote willy: "If the filesystem
|
||||
# implements migrate_folio and writepages, there is no need for a writepage implementation."
|
||||
ifneq (,$(shell grep 'int buffer_migrate_folio.struct address_space' include/linux/buffer_head.h))
|
||||
ccflags-y += -DKC_HAVE_BUFFER_MIGRATE_FOLIO
|
||||
endif
|
||||
|
||||
#
|
||||
# v6.7-rc4-307-g17bf23a981be
|
||||
#
|
||||
# block_write_full_page() is replaced with block_write_full_folio(),
|
||||
# but that isn't exported as it used to be (and the only users now
|
||||
# are builtin). However, the kernel will fall back to using the
|
||||
# .writepages method instead, so we can drop this method.
|
||||
ifneq (,$(shell grep 'int block_write_full_page.struct page' include/linux/buffer_head.h))
|
||||
ccflags-y += -DKC_HAVE_BLOCK_WRITE_FULL_PAGE
|
||||
endif
|
||||
|
||||
#
|
||||
# v6.4-rc2-29-gc6585011bc1d
|
||||
#
|
||||
# generic_file_splice_read is removed. It can be replaced with filemap_splice_read
|
||||
# or copy_splice_read.
|
||||
ifneq (,$(shell grep 'ssize_t generic_file_splice_read.struct file' include/linux/fs.h))
|
||||
ccflags-y += -DKC_HAVE_GENERIC_FILE_SPLICE_READ
|
||||
endif
|
||||
|
||||
#
|
||||
# v4.6-rc3-29-g6192269444eb
|
||||
#
|
||||
# Adds .iterate_shared readdir() iterator vfs method.
|
||||
ifneq (,$(shell grep 'iterate_shared...struct file.., struct dir_context' include/linux/fs.h))
|
||||
ccflags-y += -DKC_HAVE_ITERATE_SHARED
|
||||
endif
|
||||
|
||||
#
|
||||
# v6.11-rc1-54-g9f04609f74ec
|
||||
#
|
||||
# Last of a series of changes that make block_write_begin/end take a folio instead of
|
||||
# a struct pagep.
|
||||
ifneq (,$(shell grep 'int __block_write_begin.struct.folio' include/linux/buffer_head.h))
|
||||
ccflags-y += -DKC_BLOCK_WRITE_BEGIN_FOLIO
|
||||
endif
|
||||
|
||||
@@ -197,7 +197,7 @@ int scoutfs_set_acl_locked(struct inode *inode, struct posix_acl *acl, int type,
|
||||
if (!value) {
|
||||
/* can be setting an acl that only affects mode, didn't need xattr */
|
||||
inode_inc_iversion(inode);
|
||||
inode->i_ctime = current_time(inode);
|
||||
inode_set_ctime_current(inode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -308,14 +308,14 @@ static bool invalid_extent(u64 start, u64 end, u64 first, u64 last)
|
||||
static bool invalid_meta_blkno(struct super_block *sb, u64 blkno)
|
||||
{
|
||||
struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb);
|
||||
u64 last_meta = (i_size_read(sbi->meta_bdev->bd_inode) >> SCOUTFS_BLOCK_LG_SHIFT) - 1;
|
||||
u64 last_meta = (i_size_read(KC_BDEV_INODE(sbi->meta_bdev)) >> SCOUTFS_BLOCK_LG_SHIFT) - 1;
|
||||
|
||||
return invalid_extent(blkno, blkno, SCOUTFS_META_DEV_START_BLKNO, last_meta);
|
||||
}
|
||||
|
||||
static bool invalid_data_extent(struct super_block *sb, u64 start, u64 len)
|
||||
{
|
||||
u64 last_data = (i_size_read(sb->s_bdev->bd_inode) >> SCOUTFS_BLOCK_SM_SHIFT) - 1;
|
||||
u64 last_data = (i_size_read(KC_BDEV_INODE(sb->s_bdev)) >> SCOUTFS_BLOCK_SM_SHIFT) - 1;
|
||||
|
||||
return invalid_extent(start, start + len - 1, SCOUTFS_DATA_DEV_START_BLKNO, last_data);
|
||||
}
|
||||
|
||||
@@ -103,8 +103,8 @@ int scoutfs_get_attr_x(struct inode *inode, struct scoutfs_ioctl_inode_attr_x *i
|
||||
size = fill_attr(size, iax, SCOUTFS_IOC_IAX_OFFLINE_BLOCKS,
|
||||
offline_blocks, offline);
|
||||
}
|
||||
size = fill_attr(size, iax, SCOUTFS_IOC_IAX_CTIME, ctime_sec, inode->i_ctime.tv_sec);
|
||||
size = fill_attr(size, iax, SCOUTFS_IOC_IAX_CTIME, ctime_nsec, inode->i_ctime.tv_nsec);
|
||||
size = fill_attr(size, iax, SCOUTFS_IOC_IAX_CTIME, ctime_sec, inode_get_ctime_sec(inode));
|
||||
size = fill_attr(size, iax, SCOUTFS_IOC_IAX_CTIME, ctime_nsec, inode_get_ctime_nsec(inode));
|
||||
size = fill_attr(size, iax, SCOUTFS_IOC_IAX_CRTIME, crtime_sec, si->crtime.tv_sec);
|
||||
size = fill_attr(size, iax, SCOUTFS_IOC_IAX_CRTIME, crtime_nsec, si->crtime.tv_nsec);
|
||||
size = fill_attr(size, iax, SCOUTFS_IOC_IAX_SIZE, size, i_size_read(inode));
|
||||
@@ -223,10 +223,8 @@ int scoutfs_set_attr_x(struct inode *inode, struct scoutfs_ioctl_inode_attr_x *i
|
||||
scoutfs_inode_set_data_version(inode, iax->data_version);
|
||||
if (iax->x_mask & SCOUTFS_IOC_IAX_SIZE)
|
||||
i_size_write(inode, iax->size);
|
||||
if (iax->x_mask & SCOUTFS_IOC_IAX_CTIME) {
|
||||
inode->i_ctime.tv_sec = iax->ctime_sec;
|
||||
inode->i_ctime.tv_nsec = iax->ctime_nsec;
|
||||
}
|
||||
if (iax->x_mask & SCOUTFS_IOC_IAX_CTIME)
|
||||
inode_set_ctime(inode, iax->ctime_sec, iax->ctime_nsec);
|
||||
if (iax->x_mask & SCOUTFS_IOC_IAX_CRTIME) {
|
||||
si->crtime.tv_sec = iax->crtime_sec;
|
||||
si->crtime.tv_nsec = iax->crtime_nsec;
|
||||
|
||||
@@ -884,7 +884,7 @@ int scoutfs_block_dirty_ref(struct super_block *sb, struct scoutfs_alloc *alloc,
|
||||
hdr->magic = cpu_to_le32(magic);
|
||||
hdr->fsid = cpu_to_le64(sbi->fsid);
|
||||
hdr->blkno = cpu_to_le64(bl->blkno);
|
||||
prandom_bytes(&hdr->seq, sizeof(hdr->seq));
|
||||
get_random_bytes(&hdr->seq, sizeof(hdr->seq));
|
||||
|
||||
trace_scoutfs_block_dirty_ref(sb, le64_to_cpu(ref->blkno), le64_to_cpu(ref->seq),
|
||||
le64_to_cpu(hdr->blkno), le64_to_cpu(hdr->seq));
|
||||
@@ -1229,7 +1229,12 @@ static int sm_block_io(struct super_block *sb, struct block_device *bdev, blk_op
|
||||
kc_bio_set_sector(bio, blkno << (SCOUTFS_BLOCK_SM_SHIFT - 9));
|
||||
bio->bi_end_io = sm_block_bio_end_io;
|
||||
bio->bi_private = &sbc;
|
||||
bio_add_page(bio, page, SCOUTFS_BLOCK_SM_SIZE, 0);
|
||||
ret = bio_add_page(bio, page, SCOUTFS_BLOCK_SM_SIZE, 0);
|
||||
if (ret != SCOUTFS_BLOCK_SM_SIZE) {
|
||||
bio_put(bio);
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
init_completion(&sbc.comp);
|
||||
sbc.err = 0;
|
||||
@@ -1285,9 +1290,12 @@ int scoutfs_block_setup(struct super_block *sb)
|
||||
|
||||
binf->sb = sb;
|
||||
init_waitqueue_head(&binf->waitq);
|
||||
KC_INIT_SHRINKER_FUNCS(&binf->shrinker, block_count_objects,
|
||||
block_scan_objects);
|
||||
KC_REGISTER_SHRINKER(&binf->shrinker, "scoutfs-block:" SCSBF, SCSB_ARGS(sb));
|
||||
KC_SETUP_SHRINKER(binf->shrinker, binf, 0, block_count_objects,
|
||||
block_scan_objects, "scoutfs-block:" SCSBF, SCSB_ARGS(sb));
|
||||
if (KC_SHRINKER_IS_NULL(binf->shrinker)) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
INIT_WORK(&binf->free_work, block_free_work);
|
||||
init_llist_head(&binf->free_llist);
|
||||
|
||||
@@ -1309,7 +1317,7 @@ void scoutfs_block_destroy(struct super_block *sb)
|
||||
struct block_info *binf = SCOUTFS_SB(sb)->block_info;
|
||||
|
||||
if (binf) {
|
||||
KC_UNREGISTER_SHRINKER(&binf->shrinker);
|
||||
KC_UNREGISTER_SHRINKER(binf->shrinker);
|
||||
block_shrink_all(sb);
|
||||
flush_work(&binf->free_work);
|
||||
rhashtable_destroy(&binf->ht);
|
||||
|
||||
@@ -2042,7 +2042,7 @@ struct merged_item {
|
||||
u64 seq;
|
||||
u8 flags;
|
||||
unsigned int val_len;
|
||||
u8 val[0];
|
||||
u8 val[];
|
||||
};
|
||||
|
||||
static inline struct merged_item *mitem_container(struct rb_node *node)
|
||||
@@ -2183,6 +2183,8 @@ static int merge_read_item(struct super_block *sb, struct scoutfs_key *key, u64
|
||||
if (ret > 0) {
|
||||
if (ret == SCOUTFS_DELTA_COMBINED) {
|
||||
scoutfs_inc_counter(sb, btree_merge_delta_combined);
|
||||
if (seq > found->seq)
|
||||
found->seq = seq;
|
||||
} else if (ret == SCOUTFS_DELTA_COMBINED_NULL) {
|
||||
scoutfs_inc_counter(sb, btree_merge_delta_null);
|
||||
free_mitem(rng, found);
|
||||
@@ -2208,7 +2210,7 @@ static int merge_read_item(struct super_block *sb, struct scoutfs_key *key, u64
|
||||
mitem->flags = flags;
|
||||
mitem->val_len = val_len;
|
||||
if (val_len)
|
||||
memcpy(mitem->val, val, val_len);
|
||||
memcpy(&mitem->val[0], val, val_len);
|
||||
|
||||
if (found) {
|
||||
replace_mitem(rng, found, mitem);
|
||||
@@ -2486,6 +2488,14 @@ int scoutfs_btree_merge(struct super_block *sb,
|
||||
mitem = next_mitem(mitem);
|
||||
free_mitem(&rng, tmp);
|
||||
}
|
||||
|
||||
if (mitem && walk_val_len == 0 &&
|
||||
!(walk_flags & (BTW_INSERT | BTW_DELETE)) &&
|
||||
scoutfs_trigger(sb, LOG_MERGE_FORCE_PARTIAL)) {
|
||||
ret = -ERANGE;
|
||||
*next_ret = mitem->key;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
@@ -30,7 +30,7 @@ struct scoutfs_btree_item_list {
|
||||
u64 seq;
|
||||
u8 flags;
|
||||
int val_len;
|
||||
u8 val[0];
|
||||
u8 val[];
|
||||
};
|
||||
|
||||
int scoutfs_btree_lookup(struct super_block *sb,
|
||||
|
||||
@@ -34,6 +34,17 @@ static struct attribute scoutfs_counter_attrs[] = {
|
||||
#define NR_ATTRS ARRAY_SIZE(scoutfs_counter_attrs)
|
||||
static struct attribute *scoutfs_counter_attr_ptrs[NR_ATTRS + 1];
|
||||
|
||||
#ifdef KC_KOBJECT_DEFAULT_GROUPS
|
||||
static struct attribute_group scoutfs_counter_attr_group = {
|
||||
.attrs = scoutfs_counter_attr_ptrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *scoutfs_counter_attr_groups[] = {
|
||||
&scoutfs_counter_attr_group,
|
||||
NULL,
|
||||
};
|
||||
#endif
|
||||
|
||||
static ssize_t scoutfs_counter_attr_show(struct kobject *kobj,
|
||||
struct attribute *attr, char *buf)
|
||||
{
|
||||
@@ -45,7 +56,6 @@ static ssize_t scoutfs_counter_attr_show(struct kobject *kobj,
|
||||
counters = container_of(kobj, struct scoutfs_counters, kobj);
|
||||
index = attr - scoutfs_counter_attrs;
|
||||
pcpu = &counters->FIRST_COUNTER + index;
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%lld\n", percpu_counter_sum(pcpu));
|
||||
}
|
||||
|
||||
@@ -63,7 +73,7 @@ static const struct sysfs_ops scoutfs_counter_attr_ops = {
|
||||
};
|
||||
|
||||
static struct kobj_type scoutfs_counters_ktype = {
|
||||
.default_attrs = scoutfs_counter_attr_ptrs,
|
||||
.KC_KOBJ_DEFAULT_OP = KC_KOBJ_DEFAULT_PICK(scoutfs_counter_attr_groups, scoutfs_counter_attr_ptrs),
|
||||
.sysfs_ops = &scoutfs_counter_attr_ops,
|
||||
.release = scoutfs_counters_kobj_release,
|
||||
};
|
||||
|
||||
113
kmod/src/data.c
113
kmod/src/data.c
@@ -718,24 +718,24 @@ static int scoutfs_readpage(struct file *file, struct page *page)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (scoutfs_per_task_add_excl(&si->pt_data_lock, &pt_ent, inode_lock)) {
|
||||
ret = scoutfs_data_wait_check(inode, page_offset(page),
|
||||
PAGE_SIZE, SEF_OFFLINE,
|
||||
SCOUTFS_IOC_DWO_READ, &dw,
|
||||
inode_lock);
|
||||
if (ret != 0) {
|
||||
unlock_page(page);
|
||||
scoutfs_per_task_del(&si->pt_data_lock, &pt_ent);
|
||||
scoutfs_unlock(sb, inode_lock, SCOUTFS_LOCK_READ);
|
||||
}
|
||||
if (ret > 0) {
|
||||
ret = scoutfs_data_wait(inode, &dw);
|
||||
if (ret == 0)
|
||||
ret = AOP_TRUNCATED_PAGE;
|
||||
}
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
scoutfs_per_task_add_excl(&si->pt_data_lock, &pt_ent, inode_lock);
|
||||
|
||||
ret = scoutfs_data_wait_check(inode, page_offset(page),
|
||||
PAGE_SIZE, SEF_OFFLINE,
|
||||
SCOUTFS_IOC_DWO_READ, &dw,
|
||||
inode_lock);
|
||||
if (ret != 0) {
|
||||
unlock_page(page);
|
||||
scoutfs_per_task_del(&si->pt_data_lock, &pt_ent);
|
||||
scoutfs_unlock(sb, inode_lock, SCOUTFS_LOCK_READ);
|
||||
}
|
||||
if (ret > 0) {
|
||||
ret = scoutfs_data_wait(inode, &dw);
|
||||
if (ret == 0)
|
||||
ret = AOP_TRUNCATED_PAGE;
|
||||
}
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
#ifdef KC_MPAGE_READ_FOLIO
|
||||
ret = mpage_read_folio(folio, scoutfs_get_block_read);
|
||||
@@ -743,8 +743,8 @@ static int scoutfs_readpage(struct file *file, struct page *page)
|
||||
ret = mpage_readpage(page, scoutfs_get_block_read);
|
||||
#endif
|
||||
|
||||
scoutfs_unlock(sb, inode_lock, SCOUTFS_LOCK_READ);
|
||||
scoutfs_per_task_del(&si->pt_data_lock, &pt_ent);
|
||||
scoutfs_unlock(sb, inode_lock, SCOUTFS_LOCK_READ);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -762,8 +762,10 @@ static int scoutfs_readpages(struct file *file, struct address_space *mapping,
|
||||
struct list_head *pages, unsigned nr_pages)
|
||||
{
|
||||
struct inode *inode = file->f_inode;
|
||||
struct scoutfs_inode_info *si = SCOUTFS_I(inode);
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct scoutfs_lock *inode_lock = NULL;
|
||||
SCOUTFS_DECLARE_PER_TASK_ENTRY(pt_ent);
|
||||
struct page *page;
|
||||
struct page *tmp;
|
||||
int ret;
|
||||
@@ -773,6 +775,8 @@ static int scoutfs_readpages(struct file *file, struct address_space *mapping,
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
scoutfs_per_task_add_excl(&si->pt_data_lock, &pt_ent, inode_lock);
|
||||
|
||||
list_for_each_entry_safe(page, tmp, pages, lru) {
|
||||
ret = scoutfs_data_wait_check(inode, page_offset(page),
|
||||
PAGE_SIZE, SEF_OFFLINE,
|
||||
@@ -792,6 +796,7 @@ static int scoutfs_readpages(struct file *file, struct address_space *mapping,
|
||||
|
||||
ret = mpage_readpages(mapping, pages, nr_pages, scoutfs_get_block_read);
|
||||
out:
|
||||
scoutfs_per_task_del(&si->pt_data_lock, &pt_ent);
|
||||
scoutfs_unlock(sb, inode_lock, SCOUTFS_LOCK_READ);
|
||||
BUG_ON(!list_empty(pages));
|
||||
return ret;
|
||||
@@ -800,8 +805,10 @@ out:
|
||||
static void scoutfs_readahead(struct readahead_control *rac)
|
||||
{
|
||||
struct inode *inode = rac->file->f_inode;
|
||||
struct scoutfs_inode_info *si = SCOUTFS_I(inode);
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct scoutfs_lock *inode_lock = NULL;
|
||||
SCOUTFS_DECLARE_PER_TASK_ENTRY(pt_ent);
|
||||
int ret;
|
||||
|
||||
ret = scoutfs_lock_inode(sb, SCOUTFS_LOCK_READ,
|
||||
@@ -809,6 +816,8 @@ static void scoutfs_readahead(struct readahead_control *rac)
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
scoutfs_per_task_add_excl(&si->pt_data_lock, &pt_ent, inode_lock);
|
||||
|
||||
ret = scoutfs_data_wait_check(inode, readahead_pos(rac),
|
||||
readahead_length(rac), SEF_OFFLINE,
|
||||
SCOUTFS_IOC_DWO_READ, NULL,
|
||||
@@ -816,14 +825,17 @@ static void scoutfs_readahead(struct readahead_control *rac)
|
||||
if (ret == 0)
|
||||
mpage_readahead(rac, scoutfs_get_block_read);
|
||||
|
||||
scoutfs_per_task_del(&si->pt_data_lock, &pt_ent);
|
||||
scoutfs_unlock(sb, inode_lock, SCOUTFS_LOCK_READ);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef KC_HAVE_BLOCK_WRITE_FULL_PAGE
|
||||
static int scoutfs_writepage(struct page *page, struct writeback_control *wbc)
|
||||
{
|
||||
return block_write_full_page(page, scoutfs_get_block_write, wbc);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int scoutfs_writepages(struct address_space *mapping,
|
||||
struct writeback_control *wbc)
|
||||
@@ -843,7 +855,7 @@ static int scoutfs_write_begin(struct file *file,
|
||||
#ifdef KC_BLOCK_WRITE_BEGIN_AOP_FLAGS
|
||||
unsigned flags,
|
||||
#endif
|
||||
struct page **pagep, void **fsdata)
|
||||
KC_PAGE_OR_FOLIO(struct page **pagep, struct folio **folio), void **fsdata)
|
||||
{
|
||||
struct inode *inode = mapping->host;
|
||||
struct scoutfs_inode_info *si = SCOUTFS_I(inode);
|
||||
@@ -888,7 +900,7 @@ retry:
|
||||
#ifdef KC_BLOCK_WRITE_BEGIN_AOP_FLAGS
|
||||
flags,
|
||||
#endif
|
||||
pagep, scoutfs_get_block_write);
|
||||
KC_PAGE_OR_FOLIO(pagep, folio), scoutfs_get_block_write);
|
||||
if (ret < 0) {
|
||||
scoutfs_release_trans(sb);
|
||||
scoutfs_inode_index_unlock(sb, &wbd->ind_locks);
|
||||
@@ -921,7 +933,8 @@ static int writepages_sync_none(struct address_space *mapping, loff_t start,
|
||||
|
||||
static int scoutfs_write_end(struct file *file, struct address_space *mapping,
|
||||
loff_t pos, unsigned len, unsigned copied,
|
||||
struct page *page, void *fsdata)
|
||||
KC_PAGE_OR_FOLIO(struct page *pagep, struct folio *folio),
|
||||
void *fsdata)
|
||||
{
|
||||
struct inode *inode = mapping->host;
|
||||
struct scoutfs_inode_info *si = SCOUTFS_I(inode);
|
||||
@@ -929,10 +942,11 @@ static int scoutfs_write_end(struct file *file, struct address_space *mapping,
|
||||
struct write_begin_data *wbd = fsdata;
|
||||
int ret;
|
||||
|
||||
trace_scoutfs_write_end(sb, scoutfs_ino(inode), page->index, (u64)pos,
|
||||
len, copied);
|
||||
trace_scoutfs_write_end(sb, scoutfs_ino(inode),
|
||||
KC_PAGE_OR_FOLIO(pagep->index, folio_index(folio)),
|
||||
(u64)pos, len, copied);
|
||||
|
||||
ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata);
|
||||
ret = generic_write_end(file, mapping, pos, len, copied, KC_PAGE_OR_FOLIO(pagep, folio), fsdata);
|
||||
if (ret > 0) {
|
||||
if (!si->staging) {
|
||||
scoutfs_inode_set_data_seq(inode);
|
||||
@@ -1485,12 +1499,14 @@ int scoutfs_data_move_blocks(struct inode *from, u64 from_off,
|
||||
|
||||
cur_time = current_time(from);
|
||||
if (!is_stage) {
|
||||
to->i_ctime = to->i_mtime = cur_time;
|
||||
inode_set_ctime_to_ts(to, cur_time);
|
||||
inode_set_mtime_to_ts(to, cur_time);
|
||||
inode_inc_iversion(to);
|
||||
scoutfs_inode_inc_data_version(to);
|
||||
scoutfs_inode_set_data_seq(to);
|
||||
}
|
||||
from->i_ctime = from->i_mtime = cur_time;
|
||||
inode_set_ctime_to_ts(from, cur_time);
|
||||
inode_set_mtime_to_ts(from, cur_time);
|
||||
inode_inc_iversion(from);
|
||||
scoutfs_inode_inc_data_version(from);
|
||||
scoutfs_inode_set_data_seq(from);
|
||||
@@ -2064,7 +2080,11 @@ static int scoutfs_data_page_mkwrite(struct vm_area_struct *vma,
|
||||
struct vm_fault *vmf)
|
||||
{
|
||||
#endif
|
||||
#ifdef KC_MPAGE_READ_FOLIO
|
||||
struct folio *folio = page_folio(vmf->page);
|
||||
#else
|
||||
struct page *page = vmf->page;
|
||||
#endif
|
||||
struct file *file = vma->vm_file;
|
||||
struct inode *inode = file_inode(file);
|
||||
struct scoutfs_inode_info *si = SCOUTFS_I(inode);
|
||||
@@ -2132,27 +2152,50 @@ static int scoutfs_data_page_mkwrite(struct vm_area_struct *vma,
|
||||
|
||||
down_write(&si->extent_sem);
|
||||
|
||||
#ifdef KC_MPAGE_READ_FOLIO
|
||||
if (!folio_trylock(folio)) {
|
||||
#else
|
||||
if (!trylock_page(page)) {
|
||||
#endif
|
||||
ret = VM_FAULT_NOPAGE;
|
||||
goto out_sem;
|
||||
}
|
||||
ret = VM_FAULT_LOCKED;
|
||||
|
||||
#ifdef KC_MPAGE_READ_FOLIO
|
||||
if ((folio->mapping != inode->i_mapping) ||
|
||||
(!folio_test_uptodate(folio)) ||
|
||||
(folio_pos(folio) > size)) {
|
||||
folio_unlock(folio);
|
||||
#else
|
||||
if ((page->mapping != inode->i_mapping) ||
|
||||
(!PageUptodate(page)) ||
|
||||
(page_offset(page) > size)) {
|
||||
(page_offset(page) > size)) {
|
||||
unlock_page(page);
|
||||
#endif
|
||||
ret = VM_FAULT_NOPAGE;
|
||||
goto out_sem;
|
||||
}
|
||||
|
||||
#ifdef KC_MPAGE_READ_FOLIO
|
||||
if (folio_index(folio) == (size - 1) >> PAGE_SHIFT)
|
||||
#else
|
||||
if (page->index == (size - 1) >> PAGE_SHIFT)
|
||||
#endif
|
||||
len = ((size - 1) & ~PAGE_MASK) + 1;
|
||||
|
||||
#ifdef KC_MPAGE_READ_FOLIO
|
||||
err = __block_write_begin(KC_PAGE_OR_FOLIO(folio_page(folio, 0), folio), pos, PAGE_SIZE, scoutfs_get_block);
|
||||
#else
|
||||
err = __block_write_begin(page, pos, PAGE_SIZE, scoutfs_get_block);
|
||||
#endif
|
||||
if (err) {
|
||||
ret = vmf_error(err);
|
||||
#ifdef KC_MPAGE_READ_FOLIO
|
||||
folio_unlock(folio);
|
||||
#else
|
||||
unlock_page(page);
|
||||
#endif
|
||||
goto out_sem;
|
||||
}
|
||||
/* end scoutfs_write_begin */
|
||||
@@ -2162,8 +2205,13 @@ static int scoutfs_data_page_mkwrite(struct vm_area_struct *vma,
|
||||
* progress, we are guaranteed that writeback during freezing will
|
||||
* see the dirty page and writeprotect it again.
|
||||
*/
|
||||
#ifdef KC_MPAGE_READ_FOLIO
|
||||
folio_mark_dirty(folio);
|
||||
folio_wait_stable(folio);
|
||||
#else
|
||||
set_page_dirty(page);
|
||||
wait_for_stable_page(page);
|
||||
#endif
|
||||
|
||||
/* scoutfs_write_end */
|
||||
scoutfs_inode_set_data_seq(inode);
|
||||
@@ -2290,6 +2338,9 @@ const struct address_space_operations scoutfs_file_aops = {
|
||||
.dirty_folio = block_dirty_folio,
|
||||
.invalidate_folio = block_invalidate_folio,
|
||||
.read_folio = scoutfs_read_folio,
|
||||
#ifdef KC_HAVE_BUFFER_MIGRATE_FOLIO
|
||||
.migrate_folio = buffer_migrate_folio,
|
||||
#endif
|
||||
#else
|
||||
.readpage = scoutfs_readpage,
|
||||
#endif
|
||||
@@ -2298,7 +2349,9 @@ const struct address_space_operations scoutfs_file_aops = {
|
||||
#else
|
||||
.readahead = scoutfs_readahead,
|
||||
#endif
|
||||
#ifdef KC_HAVE_BLOCK_WRITE_FULL_PAGE
|
||||
.writepage = scoutfs_writepage,
|
||||
#endif
|
||||
.writepages = scoutfs_writepages,
|
||||
.write_begin = scoutfs_write_begin,
|
||||
.write_end = scoutfs_write_end,
|
||||
@@ -2313,8 +2366,12 @@ const struct file_operations scoutfs_file_fops = {
|
||||
#else
|
||||
.read_iter = scoutfs_file_read_iter,
|
||||
.write_iter = scoutfs_file_write_iter,
|
||||
.splice_read = generic_file_splice_read,
|
||||
.splice_write = iter_file_splice_write,
|
||||
#endif
|
||||
#ifdef KC_HAVE_GENERIC_FILE_SPLICE_READ
|
||||
.splice_read = generic_file_splice_read,
|
||||
#else
|
||||
.splice_read = copy_splice_read,
|
||||
#endif
|
||||
.mmap = scoutfs_file_mmap,
|
||||
.unlocked_ioctl = scoutfs_ioctl,
|
||||
|
||||
@@ -761,6 +761,7 @@ static int scoutfs_mknod(KC_VFS_NS_DEF
|
||||
struct scoutfs_lock *dir_lock = NULL;
|
||||
struct scoutfs_lock *inode_lock = NULL;
|
||||
struct scoutfs_inode_info *si;
|
||||
struct kc_timespec cur_time;
|
||||
LIST_HEAD(ind_locks);
|
||||
u64 hash;
|
||||
u64 pos;
|
||||
@@ -792,9 +793,13 @@ static int scoutfs_mknod(KC_VFS_NS_DEF
|
||||
set_dentry_fsdata(dentry, dir_lock);
|
||||
|
||||
i_size_write(dir, i_size_read(dir) + dentry->d_name.len);
|
||||
dir->i_mtime = dir->i_ctime = current_time(inode);
|
||||
inode->i_mtime = inode->i_atime = inode->i_ctime = dir->i_mtime;
|
||||
si->crtime = inode->i_mtime;
|
||||
cur_time = current_time(inode);
|
||||
inode_set_mtime_to_ts(dir, cur_time);
|
||||
inode_set_ctime_to_ts(dir, cur_time);
|
||||
inode_set_mtime_to_ts(inode, cur_time);
|
||||
inode_set_atime_to_ts(inode, cur_time);
|
||||
inode_set_ctime_to_ts(inode, cur_time);
|
||||
si->crtime = inode_get_mtime(inode);
|
||||
inode_inc_iversion(dir);
|
||||
inode_inc_iversion(inode);
|
||||
scoutfs_forest_inc_inode_count(sb);
|
||||
@@ -847,6 +852,7 @@ static int scoutfs_link(struct dentry *old_dentry,
|
||||
struct scoutfs_lock *dir_lock;
|
||||
struct scoutfs_lock *inode_lock = NULL;
|
||||
struct scoutfs_lock *orph_lock = NULL;
|
||||
struct kc_timespec cur_time;
|
||||
LIST_HEAD(ind_locks);
|
||||
bool del_orphan = false;
|
||||
u64 dir_size;
|
||||
@@ -921,8 +927,10 @@ retry:
|
||||
set_dentry_fsdata(dentry, dir_lock);
|
||||
|
||||
i_size_write(dir, dir_size);
|
||||
dir->i_mtime = dir->i_ctime = current_time(inode);
|
||||
inode->i_ctime = dir->i_mtime;
|
||||
cur_time = current_time(inode);
|
||||
inode_set_mtime_to_ts(dir, cur_time);
|
||||
inode_set_ctime_to_ts(dir, cur_time);
|
||||
inode_set_ctime_to_ts(inode, inode_get_mtime(dir));
|
||||
inc_nlink(inode);
|
||||
inode_inc_iversion(dir);
|
||||
inode_inc_iversion(inode);
|
||||
@@ -1032,13 +1040,13 @@ retry:
|
||||
|
||||
set_dentry_fsdata(dentry, dir_lock);
|
||||
|
||||
dir->i_ctime = ts;
|
||||
dir->i_mtime = ts;
|
||||
inode_set_ctime_to_ts(dir, ts);
|
||||
inode_set_mtime_to_ts(dir, ts);
|
||||
i_size_write(dir, i_size_read(dir) - dentry->d_name.len);
|
||||
inode_inc_iversion(dir);
|
||||
inode_inc_iversion(inode);
|
||||
|
||||
inode->i_ctime = ts;
|
||||
inode_set_ctime_to_ts(inode, ts);
|
||||
drop_nlink(inode);
|
||||
if (S_ISDIR(inode->i_mode)) {
|
||||
drop_nlink(dir);
|
||||
@@ -1241,6 +1249,7 @@ static int scoutfs_symlink(KC_VFS_NS_DEF
|
||||
struct scoutfs_lock *dir_lock = NULL;
|
||||
struct scoutfs_lock *inode_lock = NULL;
|
||||
struct scoutfs_inode_info *si;
|
||||
struct kc_timespec cur_time;
|
||||
LIST_HEAD(ind_locks);
|
||||
u64 hash;
|
||||
u64 pos;
|
||||
@@ -1280,11 +1289,13 @@ static int scoutfs_symlink(KC_VFS_NS_DEF
|
||||
set_dentry_fsdata(dentry, dir_lock);
|
||||
|
||||
i_size_write(dir, i_size_read(dir) + dentry->d_name.len);
|
||||
dir->i_mtime = dir->i_ctime = current_time(inode);
|
||||
cur_time = current_time(inode);
|
||||
inode_set_mtime_to_ts(dir, cur_time);
|
||||
inode_set_ctime_to_ts(dir, cur_time);
|
||||
inode_inc_iversion(dir);
|
||||
|
||||
inode->i_ctime = dir->i_mtime;
|
||||
si->crtime = inode->i_ctime;
|
||||
inode_set_ctime_to_ts(inode, inode_get_mtime(dir));
|
||||
si->crtime = inode_get_ctime(inode);
|
||||
i_size_write(inode, name_len);
|
||||
inode_inc_iversion(inode);
|
||||
scoutfs_forest_inc_inode_count(sb);
|
||||
@@ -1806,15 +1817,15 @@ retry:
|
||||
}
|
||||
|
||||
now = current_time(old_inode);
|
||||
old_dir->i_ctime = now;
|
||||
old_dir->i_mtime = now;
|
||||
inode_set_ctime_to_ts(old_dir, now);
|
||||
inode_set_mtime_to_ts(old_dir, now);
|
||||
if (new_dir != old_dir) {
|
||||
new_dir->i_ctime = now;
|
||||
new_dir->i_mtime = now;
|
||||
inode_set_ctime_to_ts(new_dir, now);
|
||||
inode_set_mtime_to_ts(new_dir, now);
|
||||
}
|
||||
old_inode->i_ctime = now;
|
||||
inode_set_ctime_to_ts(old_inode, now);
|
||||
if (new_inode)
|
||||
new_inode->i_ctime = now;
|
||||
inode_set_ctime_to_ts(new_inode, now);
|
||||
|
||||
inode_inc_iversion(old_dir);
|
||||
inode_inc_iversion(old_inode);
|
||||
@@ -1941,6 +1952,7 @@ static int scoutfs_tmpfile(KC_VFS_NS_DEF
|
||||
struct scoutfs_lock *inode_lock = NULL;
|
||||
struct scoutfs_lock *orph_lock = NULL;
|
||||
struct scoutfs_inode_info *si;
|
||||
struct kc_timespec cur_time;
|
||||
LIST_HEAD(ind_locks);
|
||||
int ret;
|
||||
|
||||
@@ -1957,8 +1969,11 @@ static int scoutfs_tmpfile(KC_VFS_NS_DEF
|
||||
if (ret < 0)
|
||||
goto out; /* XXX returning error but items created */
|
||||
|
||||
inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
|
||||
si->crtime = inode->i_mtime;
|
||||
cur_time = current_time(inode);
|
||||
inode_set_mtime_to_ts(inode, cur_time);
|
||||
inode_set_ctime_to_ts(inode, cur_time);
|
||||
inode_set_atime_to_ts(inode, cur_time);
|
||||
si->crtime = inode_get_mtime(inode);
|
||||
insert_inode_hash(inode);
|
||||
ihold(inode); /* need to update inode modifications in d_tmpfile */
|
||||
#ifdef KC_D_TMPFILE_DENTRY
|
||||
@@ -2026,7 +2041,11 @@ const struct inode_operations scoutfs_symlink_iops = {
|
||||
};
|
||||
|
||||
const struct file_operations scoutfs_dir_fops = {
|
||||
#ifdef KC_HAVE_ITERATE_SHARED
|
||||
.iterate_shared = scoutfs_readdir,
|
||||
#else
|
||||
.iterate = scoutfs_readdir,
|
||||
#endif
|
||||
#ifdef KC_FMODE_KABI_ITERATE
|
||||
.open = scoutfs_dir_open,
|
||||
#endif
|
||||
|
||||
@@ -217,6 +217,9 @@ static struct attribute *fence_attrs[] = {
|
||||
SCOUTFS_ATTR_PTR(rid),
|
||||
NULL,
|
||||
};
|
||||
#ifdef KC_KOBJECT_DEFAULT_GROUPS
|
||||
ATTRIBUTE_GROUPS(fence);
|
||||
#endif
|
||||
|
||||
#define FENCE_TIMEOUT_MS (MSEC_PER_SEC * 30)
|
||||
|
||||
@@ -255,7 +258,8 @@ int scoutfs_fence_start(struct super_block *sb, u64 rid, __be32 ipv4_addr, int r
|
||||
fence->rid = rid;
|
||||
|
||||
ret = scoutfs_sysfs_create_attrs_parent(sb, &fi->kset->kobj,
|
||||
&fence->ssa, fence_attrs,
|
||||
&fence->ssa,
|
||||
KC_KOBJ_DEFAULT(fence),
|
||||
"%016llx", rid);
|
||||
if (ret < 0) {
|
||||
kfree(fence);
|
||||
|
||||
@@ -239,9 +239,9 @@ static int forest_read_items(struct super_block *sb, struct scoutfs_key *key, u6
|
||||
* to reset their state and retry with a newer version of the btrees.
|
||||
*/
|
||||
int scoutfs_forest_read_items_roots(struct super_block *sb, struct scoutfs_net_roots *roots,
|
||||
struct scoutfs_key *key, struct scoutfs_key *bloom_key,
|
||||
struct scoutfs_key *start, struct scoutfs_key *end,
|
||||
scoutfs_forest_item_cb cb, void *arg)
|
||||
u64 merge_input_seq, struct scoutfs_key *key,
|
||||
struct scoutfs_key *bloom_key, struct scoutfs_key *start,
|
||||
struct scoutfs_key *end, scoutfs_forest_item_cb cb, void *arg)
|
||||
{
|
||||
struct forest_read_items_data rid = {
|
||||
.cb = cb,
|
||||
@@ -317,15 +317,17 @@ int scoutfs_forest_read_items_roots(struct super_block *sb, struct scoutfs_net_r
|
||||
|
||||
scoutfs_inc_counter(sb, forest_bloom_pass);
|
||||
|
||||
if ((le64_to_cpu(lt.flags) & SCOUTFS_LOG_TREES_FINALIZED))
|
||||
rid.fic |= FIC_FINALIZED;
|
||||
if ((le64_to_cpu(lt.flags) & SCOUTFS_LOG_TREES_FINALIZED) &&
|
||||
(merge_input_seq == 0 ||
|
||||
le64_to_cpu(lt.finalize_seq) < merge_input_seq))
|
||||
rid.fic |= FIC_MERGE_INPUT;
|
||||
|
||||
ret = scoutfs_btree_read_items(sb, <.item_root, key, start,
|
||||
end, forest_read_items, &rid);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
rid.fic &= ~FIC_FINALIZED;
|
||||
rid.fic &= ~FIC_MERGE_INPUT;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
@@ -345,7 +347,7 @@ int scoutfs_forest_read_items(struct super_block *sb,
|
||||
|
||||
ret = scoutfs_client_get_roots(sb, &roots);
|
||||
if (ret == 0)
|
||||
ret = scoutfs_forest_read_items_roots(sb, &roots, key, bloom_key, start, end,
|
||||
ret = scoutfs_forest_read_items_roots(sb, &roots, 0, key, bloom_key, start, end,
|
||||
cb, arg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ struct scoutfs_lock;
|
||||
/* caller gives an item to the callback */
|
||||
enum {
|
||||
FIC_FS_ROOT = (1 << 0),
|
||||
FIC_FINALIZED = (1 << 1),
|
||||
FIC_MERGE_INPUT = (1 << 1),
|
||||
};
|
||||
typedef int (*scoutfs_forest_item_cb)(struct super_block *sb, struct scoutfs_key *key, u64 seq,
|
||||
u8 flags, void *val, int val_len, int fic, void *arg);
|
||||
@@ -25,9 +25,9 @@ int scoutfs_forest_read_items(struct super_block *sb,
|
||||
struct scoutfs_key *end,
|
||||
scoutfs_forest_item_cb cb, void *arg);
|
||||
int scoutfs_forest_read_items_roots(struct super_block *sb, struct scoutfs_net_roots *roots,
|
||||
struct scoutfs_key *key, struct scoutfs_key *bloom_key,
|
||||
struct scoutfs_key *start, struct scoutfs_key *end,
|
||||
scoutfs_forest_item_cb cb, void *arg);
|
||||
u64 merge_input_seq, struct scoutfs_key *key,
|
||||
struct scoutfs_key *bloom_key, struct scoutfs_key *start,
|
||||
struct scoutfs_key *end, scoutfs_forest_item_cb cb, void *arg);
|
||||
int scoutfs_forest_set_bloom_bits(struct super_block *sb,
|
||||
struct scoutfs_lock *lock);
|
||||
void scoutfs_forest_set_max_seq(struct super_block *sb, u64 max_seq);
|
||||
|
||||
@@ -275,12 +275,9 @@ static void load_inode(struct inode *inode, struct scoutfs_inode *cinode, int in
|
||||
i_gid_write(inode, le32_to_cpu(cinode->gid));
|
||||
inode->i_mode = le32_to_cpu(cinode->mode);
|
||||
inode->i_rdev = le32_to_cpu(cinode->rdev);
|
||||
inode->i_atime.tv_sec = le64_to_cpu(cinode->atime.sec);
|
||||
inode->i_atime.tv_nsec = le32_to_cpu(cinode->atime.nsec);
|
||||
inode->i_mtime.tv_sec = le64_to_cpu(cinode->mtime.sec);
|
||||
inode->i_mtime.tv_nsec = le32_to_cpu(cinode->mtime.nsec);
|
||||
inode->i_ctime.tv_sec = le64_to_cpu(cinode->ctime.sec);
|
||||
inode->i_ctime.tv_nsec = le32_to_cpu(cinode->ctime.nsec);
|
||||
inode_set_atime(inode, le64_to_cpu(cinode->atime.sec), le32_to_cpu(cinode->atime.nsec));
|
||||
inode_set_mtime(inode, le64_to_cpu(cinode->mtime.sec), le32_to_cpu(cinode->mtime.nsec));
|
||||
inode_set_ctime(inode, le64_to_cpu(cinode->ctime.sec), le32_to_cpu(cinode->ctime.nsec));
|
||||
|
||||
si->meta_seq = le64_to_cpu(cinode->meta_seq);
|
||||
si->data_seq = le64_to_cpu(cinode->data_seq);
|
||||
@@ -401,6 +398,7 @@ int scoutfs_getattr(KC_VFS_NS_DEF
|
||||
SCOUTFS_LKF_REFRESH_INODE, inode, &lock);
|
||||
if (ret == 0) {
|
||||
generic_fillattr(KC_VFS_INIT_NS
|
||||
KC_FILLATTR_REQUEST_MASK
|
||||
inode, stat);
|
||||
scoutfs_unlock(sb, lock, SCOUTFS_LOCK_READ);
|
||||
}
|
||||
@@ -412,6 +410,7 @@ static int set_inode_size(struct inode *inode, struct scoutfs_lock *lock,
|
||||
{
|
||||
struct scoutfs_inode_info *si = SCOUTFS_I(inode);
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct kc_timespec cur_time;
|
||||
SCOUTFS_DECLARE_PER_TASK_ENTRY(pt_ent);
|
||||
LIST_HEAD(ind_locks);
|
||||
int ret;
|
||||
@@ -434,7 +433,9 @@ static int set_inode_size(struct inode *inode, struct scoutfs_lock *lock,
|
||||
scoutfs_inode_inc_data_version(inode);
|
||||
|
||||
truncate_setsize(inode, new_size);
|
||||
inode->i_ctime = inode->i_mtime = current_time(inode);
|
||||
cur_time = current_time(inode);
|
||||
inode_set_ctime_to_ts(inode, cur_time);
|
||||
inode_set_mtime_to_ts(inode, cur_time);
|
||||
if (truncate)
|
||||
si->flags |= SCOUTFS_INO_FLAG_TRUNCATE;
|
||||
scoutfs_inode_set_data_seq(inode);
|
||||
@@ -901,14 +902,14 @@ static void store_inode(struct scoutfs_inode *cinode, struct inode *inode, int i
|
||||
cinode->gid = cpu_to_le32(i_gid_read(inode));
|
||||
cinode->mode = cpu_to_le32(inode->i_mode);
|
||||
cinode->rdev = cpu_to_le32(inode->i_rdev);
|
||||
cinode->atime.sec = cpu_to_le64(inode->i_atime.tv_sec);
|
||||
cinode->atime.nsec = cpu_to_le32(inode->i_atime.tv_nsec);
|
||||
cinode->atime.sec = cpu_to_le64(inode_get_atime_sec(inode));
|
||||
cinode->atime.nsec = cpu_to_le32(inode_get_atime_nsec(inode));
|
||||
memset(cinode->atime.__pad, 0, sizeof(cinode->atime.__pad));
|
||||
cinode->ctime.sec = cpu_to_le64(inode->i_ctime.tv_sec);
|
||||
cinode->ctime.nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
|
||||
cinode->ctime.sec = cpu_to_le64(inode_get_ctime_sec(inode));
|
||||
cinode->ctime.nsec = cpu_to_le32(inode_get_ctime_nsec(inode));
|
||||
memset(cinode->ctime.__pad, 0, sizeof(cinode->ctime.__pad));
|
||||
cinode->mtime.sec = cpu_to_le64(inode->i_mtime.tv_sec);
|
||||
cinode->mtime.nsec = cpu_to_le32(inode->i_mtime.tv_nsec);
|
||||
cinode->mtime.sec = cpu_to_le64(inode_get_mtime_sec(inode));
|
||||
cinode->mtime.nsec = cpu_to_le32(inode_get_mtime_nsec(inode));
|
||||
memset(cinode->mtime.__pad, 0, sizeof(cinode->mtime.__pad));
|
||||
|
||||
cinode->meta_seq = cpu_to_le64(scoutfs_inode_meta_seq(inode));
|
||||
@@ -1566,6 +1567,7 @@ int scoutfs_new_inode(struct super_block *sb, struct inode *dir, umode_t mode, d
|
||||
struct scoutfs_inode sinode;
|
||||
struct scoutfs_key key;
|
||||
struct inode *inode;
|
||||
struct kc_timespec cur_time;
|
||||
int inode_bytes;
|
||||
int ret;
|
||||
|
||||
@@ -1595,7 +1597,10 @@ int scoutfs_new_inode(struct super_block *sb, struct inode *dir, umode_t mode, d
|
||||
inode_init_owner(KC_VFS_INIT_NS
|
||||
inode, dir, mode);
|
||||
inode_set_bytes(inode, 0);
|
||||
inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
|
||||
cur_time = current_time(inode);
|
||||
inode_set_mtime_to_ts(inode, cur_time);
|
||||
inode_set_atime_to_ts(inode, cur_time);
|
||||
inode_set_ctime_to_ts(inode, cur_time);
|
||||
inode->i_rdev = rdev;
|
||||
set_inode_ops(inode);
|
||||
|
||||
@@ -2068,7 +2073,7 @@ void scoutfs_inode_schedule_orphan_dwork(struct super_block *sb)
|
||||
|
||||
low = (opts.orphan_scan_delay_ms * 80) / 100;
|
||||
high = (opts.orphan_scan_delay_ms * 120) / 100;
|
||||
delay = msecs_to_jiffies(low + prandom_u32_max(high - low)) ?: 1;
|
||||
delay = msecs_to_jiffies(low + get_random_u32_below(high - low)) ?: 1;
|
||||
|
||||
mod_delayed_work(system_wq, &inf->orphan_scan_dwork, delay);
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ struct cached_item {
|
||||
unsigned int val_len;
|
||||
struct scoutfs_key key;
|
||||
u64 seq;
|
||||
char val[0];
|
||||
char val[];
|
||||
};
|
||||
|
||||
#define CACHED_ITEM_ALIGN 8
|
||||
@@ -424,7 +424,7 @@ static struct cached_item *alloc_item(struct cached_page *pg,
|
||||
item->seq = seq;
|
||||
|
||||
if (val_len)
|
||||
memcpy(item->val, val, val_len);
|
||||
memcpy(&item->val[0], val, val_len);
|
||||
|
||||
update_pg_max_seq(pg, item);
|
||||
|
||||
@@ -1999,7 +1999,7 @@ int scoutfs_item_update(struct super_block *sb, struct scoutfs_key *key,
|
||||
|
||||
if (val_len <= found->val_len) {
|
||||
if (val_len)
|
||||
memcpy(found->val, val, val_len);
|
||||
memcpy(&found->val[0], val, val_len);
|
||||
if (val_len < found->val_len)
|
||||
pg->erased_bytes += item_val_bytes(found->val_len) -
|
||||
item_val_bytes(val_len);
|
||||
@@ -2316,7 +2316,7 @@ int scoutfs_item_write_dirty(struct super_block *sb)
|
||||
lst->seq = item->seq;
|
||||
lst->flags = item->deletion ? SCOUTFS_ITEM_FLAG_DELETION : 0;
|
||||
lst->val_len = item->val_len;
|
||||
memcpy(lst->val, item->val, item->val_len);
|
||||
memcpy(&lst->val[0], item->val, item->val_len);
|
||||
}
|
||||
|
||||
spin_lock(&cinf->dirty_lock);
|
||||
@@ -2626,10 +2626,10 @@ int scoutfs_item_setup(struct super_block *sb)
|
||||
|
||||
for_each_possible_cpu(cpu)
|
||||
init_pcpu_pages(cinf, cpu);
|
||||
|
||||
KC_INIT_SHRINKER_FUNCS(&cinf->shrinker, item_cache_count_objects,
|
||||
item_cache_scan_objects);
|
||||
KC_REGISTER_SHRINKER(&cinf->shrinker, "scoutfs-item:" SCSBF, SCSB_ARGS(sb));
|
||||
KC_SETUP_SHRINKER(cinf->shrinker, cinf, 0, item_cache_count_objects,
|
||||
item_cache_scan_objects, "scoutfs-item:" SCSBF, SCSB_ARGS(sb));
|
||||
if (KC_SHRINKER_IS_NULL(cinf->shrinker))
|
||||
return -ENOMEM;
|
||||
#ifdef KC_CPU_NOTIFIER
|
||||
cinf->notifier.notifier_call = item_cpu_callback;
|
||||
register_hotcpu_notifier(&cinf->notifier);
|
||||
@@ -2654,7 +2654,7 @@ void scoutfs_item_destroy(struct super_block *sb)
|
||||
#ifdef KC_CPU_NOTIFIER
|
||||
unregister_hotcpu_notifier(&cinf->notifier);
|
||||
#endif
|
||||
KC_UNREGISTER_SHRINKER(&cinf->shrinker);
|
||||
KC_UNREGISTER_SHRINKER(cinf->shrinker);
|
||||
|
||||
for_each_possible_cpu(cpu)
|
||||
drop_pcpu_pages(sb, cinf, cpu);
|
||||
|
||||
@@ -147,3 +147,13 @@ unsigned long kc_list_lru_shrink_walk(struct list_lru *lru, struct shrink_contro
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef KC_FS_INODE_C_TIME_ACCESSOR
|
||||
struct timespec64 inode_set_ctime_current(struct inode *inode)
|
||||
{
|
||||
struct timespec64 now = current_time(inode);
|
||||
|
||||
inode_set_ctime(inode, now.tv_sec, now.tv_nsec);
|
||||
return now;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -142,25 +142,54 @@ struct timespec64 kc_current_time(struct inode *inode);
|
||||
#define kc_timespec timespec64
|
||||
#endif
|
||||
|
||||
#ifndef KC_SHRINKER_SHRINK
|
||||
#ifdef KC_SHRINKER_ALLOC
|
||||
// el10+
|
||||
|
||||
#define KC_DEFINE_SHRINKER(name) struct shrinker name
|
||||
#define KC_INIT_SHRINKER_FUNCS(name, countfn, scanfn) do { \
|
||||
__typeof__(name) _shrink = (name); \
|
||||
_shrink->count_objects = (countfn); \
|
||||
_shrink->scan_objects = (scanfn); \
|
||||
_shrink->seeks = DEFAULT_SEEKS; \
|
||||
#define KC_DEFINE_SHRINKER(name) struct shrinker *(name)
|
||||
#define KC_SHRINKER_CONTAINER_OF(ptr, type) ptr->private_data
|
||||
#define KC_SETUP_SHRINKER(ptr, priv, flags, countfn, scanfn, fmt, args) \
|
||||
do { \
|
||||
ptr = shrinker_alloc(flags, fmt, args); \
|
||||
if (ptr) { \
|
||||
ptr->private_data = (priv); \
|
||||
ptr->seeks = DEFAULT_SEEKS; \
|
||||
ptr->count_objects = countfn; \
|
||||
ptr->scan_objects = scanfn; \
|
||||
shrinker_register(ptr); \
|
||||
} \
|
||||
} while (0)
|
||||
#define KC_UNREGISTER_SHRINKER(ptr) shrinker_free(ptr)
|
||||
#define KC_SHRINKER_FN(ptr) (ptr)
|
||||
#define KC_SHRINKER_IS_NULL(ptr) (!(ptr))
|
||||
|
||||
#else /* KC_SHRINKER_ALLOC */
|
||||
#ifndef KC_SHRINKER_SHRINK
|
||||
// el9, el8
|
||||
|
||||
#define KC_DEFINE_SHRINKER(name) struct shrinker (name)
|
||||
#define KC_SHRINKER_CONTAINER_OF(ptr, type) container_of(ptr, type, shrinker)
|
||||
#ifdef KC_SHRINKER_NAME
|
||||
#define KC_REGISTER_SHRINKER register_shrinker
|
||||
#define KC_SETUP_SHRINKER(ptr, priv, flags, countfn, scanfn, fmt, args) \
|
||||
do { \
|
||||
(ptr).count_objects = (countfn); \
|
||||
(ptr).scan_objects = (scanfn); \
|
||||
(ptr).seeks = DEFAULT_SEEKS; \
|
||||
register_shrinker(&(ptr), fmt, args); \
|
||||
} while (0)
|
||||
#else
|
||||
#define KC_REGISTER_SHRINKER(ptr, fmt, ...) (register_shrinker(ptr))
|
||||
#define KC_SETUP_SHRINKER(ptr, priv, flags, countfn, scanfn, fmt, args) \
|
||||
do { \
|
||||
(ptr).count_objects = (countfn); \
|
||||
(ptr).scan_objects = (scanfn); \
|
||||
(ptr).seeks = DEFAULT_SEEKS; \
|
||||
register_shrinker(&(ptr)); \
|
||||
} while (0)
|
||||
#endif /* KC_SHRINKER_NAME */
|
||||
#define KC_UNREGISTER_SHRINKER(ptr) (unregister_shrinker(ptr))
|
||||
#define KC_SHRINKER_FN(ptr) (ptr)
|
||||
#else
|
||||
#define KC_UNREGISTER_SHRINKER(ptr) (unregister_shrinker(&(ptr)))
|
||||
#define KC_SHRINKER_FN(ptr) (&ptr)
|
||||
|
||||
#else /* KC_SHRINKER_SHRINK */
|
||||
// el7
|
||||
|
||||
#include <linux/shrinker.h>
|
||||
#ifndef SHRINK_STOP
|
||||
@@ -176,19 +205,21 @@ struct kc_shrinker_wrapper {
|
||||
};
|
||||
|
||||
#define KC_DEFINE_SHRINKER(name) struct kc_shrinker_wrapper name;
|
||||
#define KC_INIT_SHRINKER_FUNCS(name, countfn, scanfn) do { \
|
||||
struct kc_shrinker_wrapper *_wrap = (name); \
|
||||
_wrap->count_objects = (countfn); \
|
||||
_wrap->scan_objects = (scanfn); \
|
||||
_wrap->shrink.shrink = kc_shrink_wrapper_fn; \
|
||||
_wrap->shrink.seeks = DEFAULT_SEEKS; \
|
||||
} while (0)
|
||||
#define KC_SHRINKER_CONTAINER_OF(ptr, type) container_of(container_of(ptr, struct kc_shrinker_wrapper, shrink), type, shrinker)
|
||||
#define KC_REGISTER_SHRINKER(ptr, fmt, ...) (register_shrinker(ptr.shrink))
|
||||
#define KC_UNREGISTER_SHRINKER(ptr) (unregister_shrinker(ptr.shrink))
|
||||
#define KC_SHRINKER_FN(ptr) (ptr.shrink)
|
||||
#define KC_SETUP_SHRINKER(ptr, priv, flags, countfn, scanfn, fmt, args) \
|
||||
do { \
|
||||
(ptr).count_objects = (countfn); \
|
||||
(ptr).scan_objects = (scanfn); \
|
||||
(ptr).shrink.shrink = kc_shrink_wrapper_fn; \
|
||||
(ptr).shrink.seeks = DEFAULT_SEEKS; \
|
||||
register_shrinker(&(ptr).shrink); \
|
||||
} while (0)
|
||||
#define KC_UNREGISTER_SHRINKER(ptr) (unregister_shrinker(&(ptr).shrink))
|
||||
#define KC_SHRINKER_FN(ptr) (&(ptr).shrink)
|
||||
|
||||
#endif /* KC_SHRINKER_SHRINK */
|
||||
#define KC_SHRINKER_IS_NULL(ptr) (0)
|
||||
#endif /* KC_SHRINKER_ALLOC */
|
||||
|
||||
#ifdef KC_KERNEL_GETSOCKNAME_ADDRLEN
|
||||
#include <linux/net.h>
|
||||
@@ -279,6 +310,12 @@ typedef unsigned int blk_opf_t;
|
||||
#endif
|
||||
#endif /* KC_VFS_METHOD_MNT_IDMAP_ARG */
|
||||
|
||||
#ifdef KC_GENERIC_FILLATTR_REQUEST_MASK
|
||||
#define KC_FILLATTR_REQUEST_MASK request_mask,
|
||||
#else
|
||||
#define KC_FILLATTR_REQUEST_MASK
|
||||
#endif
|
||||
|
||||
#ifdef KC_BIO_ALLOC_DEV_OPF_ARGS
|
||||
#define kc_bio_alloc bio_alloc
|
||||
#else
|
||||
@@ -452,6 +489,7 @@ unsigned long kc_list_lru_shrink_walk(struct list_lru *lru, struct shrink_contro
|
||||
kc_list_lru_walk_cb_t isolate, void *cb_arg);
|
||||
#else
|
||||
#define kc_list_lru_shrink_walk list_lru_shrink_walk
|
||||
#define kc_list_lru_walk list_lru_walk
|
||||
#endif
|
||||
|
||||
#if defined(KC_LIST_LRU_WALK_CB_ITEM_LOCK)
|
||||
@@ -489,4 +527,133 @@ static inline void stack_trace_print(unsigned long *entries, unsigned int nr_ent
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef KC_HAVE_GET_RANDOM_U32_BELOW
|
||||
#define get_random_u32_below prandom_u32_max
|
||||
#endif
|
||||
|
||||
#ifndef KC_FS_INODE_C_TIME_ACCESSOR
|
||||
struct timespec64 inode_set_ctime_current(struct inode *inode);
|
||||
static inline struct timespec64 inode_set_ctime_to_ts(struct inode *inode,
|
||||
struct timespec64 ts)
|
||||
{
|
||||
inode->i_ctime.tv_sec = ts.tv_sec;
|
||||
inode->i_ctime.tv_nsec = ts.tv_nsec;
|
||||
return ts;
|
||||
}
|
||||
|
||||
static inline struct timespec64 inode_set_ctime(struct inode *inode,
|
||||
time64_t sec, long nsec)
|
||||
{
|
||||
struct timespec64 ts = { .tv_sec = sec,
|
||||
.tv_nsec = nsec };
|
||||
|
||||
return inode_set_ctime_to_ts(inode, ts);
|
||||
}
|
||||
|
||||
static inline struct timespec64 inode_get_ctime(const struct inode *inode)
|
||||
{
|
||||
struct timespec64 ts = { .tv_sec = inode->i_ctime.tv_sec,
|
||||
.tv_nsec = inode->i_ctime.tv_nsec };
|
||||
return ts;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef KC_FS_INODE_AM_TIME_ACCESSOR
|
||||
static inline struct timespec64 inode_get_mtime(const struct inode *inode)
|
||||
{
|
||||
struct timespec64 ts = { .tv_sec = inode->i_mtime.tv_sec,
|
||||
.tv_nsec = inode->i_mtime.tv_nsec };
|
||||
return ts;
|
||||
}
|
||||
|
||||
static inline struct timespec64 inode_set_mtime_to_ts(struct inode *inode,
|
||||
struct timespec64 ts)
|
||||
{
|
||||
inode->i_mtime.tv_sec = ts.tv_sec;
|
||||
inode->i_mtime.tv_nsec = ts.tv_nsec;
|
||||
return ts;
|
||||
}
|
||||
|
||||
static inline struct timespec64 inode_set_mtime(struct inode *inode,
|
||||
time64_t sec, long nsec)
|
||||
{
|
||||
struct timespec64 ts = { .tv_sec = sec,
|
||||
.tv_nsec = nsec };
|
||||
|
||||
return inode_set_mtime_to_ts(inode, ts);
|
||||
}
|
||||
|
||||
static inline struct timespec64 inode_set_atime_to_ts(struct inode *inode,
|
||||
struct timespec64 ts)
|
||||
{
|
||||
inode->i_atime.tv_sec = ts.tv_sec;
|
||||
inode->i_atime.tv_nsec = ts.tv_nsec;
|
||||
return ts;
|
||||
}
|
||||
|
||||
static inline struct timespec64 inode_set_atime(struct inode *inode,
|
||||
time64_t sec, long nsec)
|
||||
{
|
||||
struct timespec64 ts = { .tv_sec = sec,
|
||||
.tv_nsec = nsec };
|
||||
|
||||
return inode_set_atime_to_ts(inode, ts);
|
||||
}
|
||||
|
||||
static inline time64_t inode_get_ctime_sec(const struct inode *inode)
|
||||
{
|
||||
return inode->i_ctime.tv_sec;
|
||||
}
|
||||
static inline long inode_get_ctime_nsec(const struct inode *inode)
|
||||
{
|
||||
return inode->i_ctime.tv_nsec;
|
||||
}
|
||||
static inline time64_t inode_get_mtime_sec(const struct inode *inode)
|
||||
{
|
||||
return inode->i_mtime.tv_sec;
|
||||
}
|
||||
static inline long inode_get_mtime_nsec(const struct inode *inode)
|
||||
{
|
||||
return inode->i_mtime.tv_nsec;
|
||||
}
|
||||
static inline time64_t inode_get_atime_sec(const struct inode *inode)
|
||||
{
|
||||
return inode->i_atime.tv_sec;
|
||||
}
|
||||
static inline long inode_get_atime_nsec(const struct inode *inode)
|
||||
{
|
||||
return inode->i_atime.tv_nsec;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef KC_HAVE_BD_INODE
|
||||
#define KC_BDEV_INODE(b) (b)->bd_inode
|
||||
#define KC_BDEV_MAPPING(b) (b)->bd_inode->i_mapping
|
||||
#else
|
||||
#define KC_BDEV_INODE(b) (b)->bd_mapping->host
|
||||
#define KC_BDEV_MAPPING(b) (b)->bd_mapping
|
||||
#endif
|
||||
|
||||
#ifdef KC_HAVE_ASSIGN_STR_PARMS
|
||||
#define kc__assign_str(a, b) __assign_str(a, b)
|
||||
#else
|
||||
#define kc__assign_str(a, b) __assign_str(a)
|
||||
#endif
|
||||
|
||||
#ifdef KC_KOBJECT_DEFAULT_GROUPS
|
||||
#define KC_KOBJ_DEFAULT_OP default_groups
|
||||
#define KC_KOBJ_DEFAULT(name) (name##_groups)
|
||||
#define KC_KOBJ_DEFAULT_PICK(group, attrs) (group)
|
||||
#else
|
||||
#define KC_KOBJ_DEFAULT_OP default_attrs
|
||||
#define KC_KOBJ_DEFAULT(name) (name##_attrs)
|
||||
#define KC_KOBJ_DEFAULT_PICK(group, attrs) (attrs)
|
||||
#endif
|
||||
|
||||
#ifdef KC_BLOCK_WRITE_BEGIN_FOLIO
|
||||
#define KC_PAGE_OR_FOLIO(p, f) f
|
||||
#else
|
||||
#define KC_PAGE_OR_FOLIO(p, f) p
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -752,13 +752,18 @@ static struct attribute *options_attrs[] = {
|
||||
SCOUTFS_ATTR_PTR(quorum_slot_nr),
|
||||
NULL,
|
||||
};
|
||||
#ifdef KC_KOBJECT_DEFAULT_GROUPS
|
||||
ATTRIBUTE_GROUPS(options);
|
||||
#endif
|
||||
|
||||
int scoutfs_options_setup(struct super_block *sb)
|
||||
{
|
||||
DECLARE_OPTIONS_INFO(sb, optinf);
|
||||
int ret;
|
||||
|
||||
ret = scoutfs_sysfs_create_attrs(sb, &optinf->sysfs_attrs, options_attrs, "mount_options");
|
||||
ret = scoutfs_sysfs_create_attrs(sb, &optinf->sysfs_attrs,
|
||||
KC_KOBJ_DEFAULT_PICK(options_groups, options_attrs),
|
||||
"mount_options");
|
||||
if (ret < 0)
|
||||
scoutfs_options_destroy(sb);
|
||||
return ret;
|
||||
|
||||
@@ -162,7 +162,7 @@ static void quorum_slot_sin(struct scoutfs_quorum_config *qconf, int i, struct s
|
||||
static ktime_t election_timeout(void)
|
||||
{
|
||||
return ktime_add_ms(ktime_get(), SCOUTFS_QUORUM_ELECT_MIN_MS +
|
||||
prandom_u32_max(SCOUTFS_QUORUM_ELECT_VAR_MS));
|
||||
get_random_u32_below(SCOUTFS_QUORUM_ELECT_VAR_MS));
|
||||
}
|
||||
|
||||
static ktime_t heartbeat_interval(void)
|
||||
@@ -1192,6 +1192,9 @@ static struct attribute *quorum_attrs[] = {
|
||||
SCOUTFS_ATTR_PTR(is_leader),
|
||||
NULL,
|
||||
};
|
||||
#ifdef KC_KOBJECT_DEFAULT_GROUPS
|
||||
ATTRIBUTE_GROUPS(quorum);
|
||||
#endif
|
||||
|
||||
static inline bool valid_ipv4_unicast(__be32 addr)
|
||||
{
|
||||
@@ -1352,7 +1355,7 @@ int scoutfs_quorum_setup(struct super_block *sb)
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = scoutfs_sysfs_create_attrs(sb, &qinf->ssa, quorum_attrs,
|
||||
ret = scoutfs_sysfs_create_attrs(sb, &qinf->ssa, KC_KOBJ_DEFAULT(quorum),
|
||||
"quorum");
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "totl.h"
|
||||
#include "util.h"
|
||||
#include "quota.h"
|
||||
#include "trans.h"
|
||||
#include "counters.h"
|
||||
#include "scoutfs_trace.h"
|
||||
|
||||
@@ -204,7 +205,7 @@ static struct squota_check *lookup_random_check(struct rhashtable *rht)
|
||||
|
||||
tbl = rht_dereference_rcu(rht->tbl, rht);
|
||||
do {
|
||||
for (s = 0, i = prandom_u32_max(tbl->size);
|
||||
for (s = 0, i = get_random_u32_below(tbl->size);
|
||||
s < tbl->size;
|
||||
s++, i = (i + 1) % tbl->size) {
|
||||
rht_for_each_entry_rcu(chk, pos, tbl, i, head) {
|
||||
@@ -269,7 +270,7 @@ static void shrink_all_cached_checks(struct squota_info *qtinf)
|
||||
{
|
||||
struct shrink_control sc = { .nr_to_scan = LONG_MAX, };
|
||||
|
||||
scan_cached_checks(KC_SHRINKER_FN(&qtinf->shrinker), &sc);
|
||||
scan_cached_checks(KC_SHRINKER_FN(qtinf->shrinker), &sc);
|
||||
}
|
||||
|
||||
static u8 ns_is_attr(u8 ns)
|
||||
@@ -1086,6 +1087,10 @@ int scoutfs_quota_mod_rule(struct super_block *sb, bool is_add,
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = scoutfs_hold_trans(sb, true);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
down_write(&qtinf->rwsem);
|
||||
|
||||
if (is_add) {
|
||||
@@ -1095,28 +1100,30 @@ int scoutfs_quota_mod_rule(struct super_block *sb, bool is_add,
|
||||
else if (ret == 0)
|
||||
ret = -EEXIST;
|
||||
if (ret < 0)
|
||||
goto unlock;
|
||||
goto release;
|
||||
|
||||
rule_to_rule_val(&rv, &rule);
|
||||
ret = scoutfs_item_create(sb, &key, &rv, sizeof(rv), lock);
|
||||
if (ret < 0)
|
||||
goto unlock;
|
||||
goto release;
|
||||
|
||||
} else {
|
||||
ret = find_rule(sb, &rule, &key, lock) ?:
|
||||
scoutfs_item_delete(sb, &key, lock);
|
||||
if (ret < 0)
|
||||
goto unlock;
|
||||
goto release;
|
||||
}
|
||||
|
||||
scoutfs_quota_invalidate(sb);
|
||||
ret = 0;
|
||||
|
||||
unlock:
|
||||
release:
|
||||
up_write(&qtinf->rwsem);
|
||||
scoutfs_unlock(sb, lock, SCOUTFS_LOCK_WRITE);
|
||||
scoutfs_release_trans(sb);
|
||||
|
||||
out:
|
||||
scoutfs_unlock(sb, lock, SCOUTFS_LOCK_WRITE);
|
||||
|
||||
if (is_add)
|
||||
trace_scoutfs_quota_add_rule(sb, &rule, ret);
|
||||
else
|
||||
@@ -1225,8 +1232,12 @@ int scoutfs_quota_setup(struct super_block *sb)
|
||||
spin_lock_init(&qtinf->lock);
|
||||
init_waitqueue_head(&qtinf->waitq);
|
||||
|
||||
KC_INIT_SHRINKER_FUNCS(&qtinf->shrinker, count_cached_checks, scan_cached_checks);
|
||||
KC_REGISTER_SHRINKER(&qtinf->shrinker, "scoutfs-quota:" SCSBF, SCSB_ARGS(sb));
|
||||
KC_SETUP_SHRINKER(qtinf->shrinker, qtinf, 0, count_cached_checks,
|
||||
scan_cached_checks, "scoutfs-quota:" SCSBF, SCSB_ARGS(sb));
|
||||
if (KC_SHRINKER_IS_NULL(qtinf->shrinker)) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
sbi->squota_info = qtinf;
|
||||
|
||||
@@ -1250,7 +1261,7 @@ void scoutfs_quota_destroy(struct super_block *sb)
|
||||
|
||||
if (qtinf) {
|
||||
debugfs_remove(qtinf->drop_dentry);
|
||||
KC_UNREGISTER_SHRINKER(&qtinf->shrinker);
|
||||
KC_UNREGISTER_SHRINKER(qtinf->shrinker);
|
||||
|
||||
spin_lock(&qtinf->lock);
|
||||
rs = rcu_dereference_protected(qtinf->ruleset, lockdep_is_held(&qtinf->lock));
|
||||
|
||||
@@ -102,7 +102,7 @@ TRACE_EVENT(scoutfs_setattr,
|
||||
SCSB_TRACE_ASSIGN(dentry->d_inode->i_sb);
|
||||
__entry->ino = scoutfs_ino(dentry->d_inode);
|
||||
__entry->d_len = dentry->d_name.len;
|
||||
__assign_str(d_name, dentry->d_name.name);
|
||||
kc__assign_str(d_name, dentry->d_name.name);
|
||||
__entry->ia_valid = attr->ia_valid;
|
||||
__entry->size_change = !!(attr->ia_valid & ATTR_SIZE);
|
||||
__entry->ia_size = attr->ia_size;
|
||||
@@ -1638,9 +1638,9 @@ TRACE_EVENT(scoutfs_rename,
|
||||
TP_fast_assign(
|
||||
SCSB_TRACE_ASSIGN(sb);
|
||||
__entry->old_dir_ino = scoutfs_ino(old_dir);
|
||||
__assign_str(old_name, old_dentry->d_name.name)
|
||||
kc__assign_str(old_name, old_dentry->d_name.name);
|
||||
__entry->new_dir_ino = scoutfs_ino(new_dir);
|
||||
__assign_str(new_name, new_dentry->d_name.name)
|
||||
kc__assign_str(new_name, new_dentry->d_name.name);
|
||||
__entry->new_inode_ino = new_dentry->d_inode ?
|
||||
scoutfs_ino(new_dentry->d_inode) : 0;
|
||||
),
|
||||
@@ -1670,7 +1670,7 @@ TRACE_EVENT(scoutfs_d_revalidate,
|
||||
TP_fast_assign(
|
||||
SCSB_TRACE_ASSIGN(sb);
|
||||
__entry->dentry = dentry;
|
||||
__assign_str(name, dentry->d_name.name)
|
||||
kc__assign_str(name, dentry->d_name.name);
|
||||
__entry->ino = dentry->d_inode ? scoutfs_ino(dentry->d_inode) : 0;
|
||||
__entry->dir_ino = dir_ino;
|
||||
__entry->flags = flags;
|
||||
@@ -1705,7 +1705,7 @@ TRACE_EVENT(scoutfs_validate_dentry,
|
||||
SCSB_TRACE_ASSIGN(sb);
|
||||
__entry->dentry = dentry;
|
||||
__entry->dir_ino = dir_ino;
|
||||
__assign_str(name, dentry->d_name.name)
|
||||
kc__assign_str(name, dentry->d_name.name);
|
||||
__entry->dentry_ino = dentry_ino;
|
||||
__entry->dent_ino = dent_ino;
|
||||
__entry->fsdata_gen = (unsigned long long)dentry->d_fsdata;
|
||||
@@ -1827,7 +1827,7 @@ TRACE_EVENT(scoutfs_get_name,
|
||||
SCSB_TRACE_ASSIGN(sb);
|
||||
__entry->parent_ino = scoutfs_ino(parent);
|
||||
__entry->child_ino = scoutfs_ino(child);
|
||||
__assign_str(name, name);
|
||||
kc__assign_str(name, name);
|
||||
),
|
||||
|
||||
TP_printk(SCSBF" parent %llu child %llu name: %s",
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include <net/sock.h>
|
||||
#include <net/tcp.h>
|
||||
#include <linux/log2.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "format.h"
|
||||
#include "counters.h"
|
||||
@@ -3467,7 +3466,7 @@ out:
|
||||
|
||||
static u64 device_blocks(struct block_device *bdev, int shift)
|
||||
{
|
||||
return i_size_read(bdev->bd_inode) >> shift;
|
||||
return i_size_read(KC_BDEV_INODE(bdev)) >> shift;
|
||||
}
|
||||
|
||||
static int server_resize_devices(struct super_block *sb, struct scoutfs_net_connection *conn,
|
||||
|
||||
@@ -18,7 +18,11 @@
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/sort.h>
|
||||
#ifdef KC_HAVE__LINUX_UNALIGNED_H
|
||||
#include <linux/unaligned.h>
|
||||
#else
|
||||
#include <asm/unaligned.h>
|
||||
#endif
|
||||
|
||||
#include "super.h"
|
||||
#include "format.h"
|
||||
@@ -2346,6 +2350,9 @@ static struct attribute *srch_attrs[] = {
|
||||
SCOUTFS_ATTR_PTR(compact_delay_ms),
|
||||
NULL,
|
||||
};
|
||||
#ifdef KC_KOBJECT_DEFAULT_GROUPS
|
||||
ATTRIBUTE_GROUPS(srch);
|
||||
#endif
|
||||
|
||||
void scoutfs_srch_destroy(struct super_block *sb)
|
||||
{
|
||||
@@ -2387,7 +2394,8 @@ int scoutfs_srch_setup(struct super_block *sb)
|
||||
|
||||
sbi->srch_info = srinf;
|
||||
|
||||
ret = scoutfs_sysfs_create_attrs(sb, &srinf->ssa, srch_attrs, "srch");
|
||||
ret = scoutfs_sysfs_create_attrs(sb, &srinf->ssa, KC_KOBJ_DEFAULT(srch),
|
||||
"srch");
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
|
||||
@@ -283,7 +283,7 @@ int scoutfs_write_super(struct super_block *sb,
|
||||
static bool small_bdev(struct super_block *sb, char *which, u64 blocks,
|
||||
struct block_device *bdev, int shift)
|
||||
{
|
||||
u64 size = (u64)i_size_read(bdev->bd_inode);
|
||||
u64 size = (u64)i_size_read(KC_BDEV_INODE(bdev));
|
||||
u64 count = size >> shift;
|
||||
|
||||
if (blocks > count) {
|
||||
@@ -508,7 +508,7 @@ static int scoutfs_fill_super(struct super_block *sb, void *data, int silent)
|
||||
sb->s_time_gran = 1;
|
||||
|
||||
/* btree blocks use long lived bh->b_data refs */
|
||||
mapping_set_gfp_mask(sb->s_bdev->bd_inode->i_mapping, GFP_NOFS);
|
||||
mapping_set_gfp_mask(KC_BDEV_MAPPING(sb->s_bdev), GFP_NOFS);
|
||||
|
||||
sbi = kzalloc(sizeof(struct scoutfs_sb_info), GFP_KERNEL);
|
||||
sb->s_fs_info = sbi;
|
||||
@@ -552,6 +552,7 @@ static int scoutfs_fill_super(struct super_block *sb, void *data, int silent)
|
||||
}
|
||||
sbi->meta_bdev_file = meta_bdev_file;
|
||||
sbi->meta_bdev = file_bdev(meta_bdev_file);
|
||||
|
||||
#else
|
||||
#ifdef KC_BLKDEV_PUT_HOLDER_ARG
|
||||
meta_bdev = blkdev_get_by_path(opts.metadev_path, SCOUTFS_META_BDEV_MODE, sb, NULL);
|
||||
@@ -567,7 +568,11 @@ static int scoutfs_fill_super(struct super_block *sb, void *data, int silent)
|
||||
sbi->meta_bdev = meta_bdev;
|
||||
#endif
|
||||
|
||||
#ifdef KC_BLKDEV_SET_BLOCKSIZE_FILE
|
||||
ret = set_blocksize(sbi->meta_bdev_file, SCOUTFS_BLOCK_SM_SIZE);
|
||||
#else
|
||||
ret = set_blocksize(sbi->meta_bdev, SCOUTFS_BLOCK_SM_SIZE);
|
||||
#endif
|
||||
if (ret != 0) {
|
||||
scoutfs_err(sb, "failed to set metadev blocksize, returned %d",
|
||||
ret);
|
||||
|
||||
@@ -103,12 +103,11 @@ static ssize_t attr_funcs_show(struct kobject *kobj, struct attribute *attr,
|
||||
}; \
|
||||
\
|
||||
static struct kobj_type _name##_ktype = { \
|
||||
.default_attrs = _name##_attrs, \
|
||||
.KC_KOBJ_DEFAULT_OP = KC_KOBJ_DEFAULT(_name), \
|
||||
.sysfs_ops = &_name##_sysfs_ops, \
|
||||
.release = _name##_release, \
|
||||
};
|
||||
|
||||
|
||||
static struct attribute *sb_id_attrs[] = {
|
||||
&data_device_maj_min_attr_funcs.attr,
|
||||
&format_version_attr_funcs.attr,
|
||||
@@ -116,6 +115,9 @@ static struct attribute *sb_id_attrs[] = {
|
||||
&rid_attr_funcs.attr,
|
||||
NULL,
|
||||
};
|
||||
#ifdef KC_KOBJECT_DEFAULT_GROUPS
|
||||
ATTRIBUTE_GROUPS(sb_id);
|
||||
#endif
|
||||
KTYPE(sb_id);
|
||||
|
||||
struct kobject *scoutfs_sysfs_sb_dir(struct super_block *sb)
|
||||
@@ -155,7 +157,12 @@ void scoutfs_sysfs_init_attrs(struct super_block *sb,
|
||||
int scoutfs_sysfs_create_attrs_parent(struct super_block *sb,
|
||||
struct kobject *parent,
|
||||
struct scoutfs_sysfs_attrs *ssa,
|
||||
struct attribute **attrs, char *fmt, ...)
|
||||
#ifdef KC_KOBJECT_DEFAULT_GROUPS
|
||||
const struct attribute_group **groups,
|
||||
#else
|
||||
struct attribute **attrs,
|
||||
#endif
|
||||
char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
size_t name_len;
|
||||
@@ -168,7 +175,11 @@ int scoutfs_sysfs_create_attrs_parent(struct super_block *sb,
|
||||
|
||||
ssa->sb = sb;
|
||||
init_completion(&ssa->comp);
|
||||
#ifdef KC_KOBJECT_DEFAULT_GROUPS
|
||||
ssa->ktype.default_groups = groups;
|
||||
#else
|
||||
ssa->ktype.default_attrs = attrs;
|
||||
#endif
|
||||
ssa->ktype.sysfs_ops = &kobj_sysfs_ops;
|
||||
ssa->ktype.release = scoutfs_sysfs_release;
|
||||
|
||||
|
||||
@@ -39,10 +39,15 @@ void scoutfs_sysfs_init_attrs(struct super_block *sb,
|
||||
int scoutfs_sysfs_create_attrs_parent(struct super_block *sb,
|
||||
struct kobject *parent,
|
||||
struct scoutfs_sysfs_attrs *ssa,
|
||||
struct attribute **attrs, char *fmt, ...);
|
||||
#define scoutfs_sysfs_create_attrs(sb, ssa, attrs, fmt, args...) \
|
||||
#ifdef KC_KOBJECT_DEFAULT_GROUPS
|
||||
const struct attribute_group **groups,
|
||||
#else
|
||||
struct attribute **attrs,
|
||||
#endif
|
||||
char *fmt, ...);
|
||||
#define scoutfs_sysfs_create_attrs(sb, ssa, group_or_attrs, fmt, args...) \
|
||||
scoutfs_sysfs_create_attrs_parent(sb, scoutfs_sysfs_sb_dir(sb), \
|
||||
ssa, attrs, fmt, ##args)
|
||||
ssa, group_or_attrs, fmt, ##args)
|
||||
|
||||
void scoutfs_sysfs_destroy_attrs(struct super_block *sb,
|
||||
struct scoutfs_sysfs_attrs *ssa);
|
||||
|
||||
@@ -30,6 +30,11 @@ void scoutfs_totl_merge_init(struct scoutfs_totl_merging *merg)
|
||||
memset(merg, 0, sizeof(struct scoutfs_totl_merging));
|
||||
}
|
||||
|
||||
/*
|
||||
* bin the incoming merge inputs so that we can resolve delta items
|
||||
* properly. Finalized logs that are merge inputs are kept separately
|
||||
* from those that are not.
|
||||
*/
|
||||
void scoutfs_totl_merge_contribute(struct scoutfs_totl_merging *merg,
|
||||
u64 seq, u8 flags, void *val, int val_len, int fic)
|
||||
{
|
||||
@@ -39,10 +44,10 @@ void scoutfs_totl_merge_contribute(struct scoutfs_totl_merging *merg,
|
||||
merg->fs_seq = seq;
|
||||
merg->fs_total = le64_to_cpu(tval->total);
|
||||
merg->fs_count = le64_to_cpu(tval->count);
|
||||
} else if (fic & FIC_FINALIZED) {
|
||||
merg->fin_seq = seq;
|
||||
merg->fin_total += le64_to_cpu(tval->total);
|
||||
merg->fin_count += le64_to_cpu(tval->count);
|
||||
} else if (fic & FIC_MERGE_INPUT) {
|
||||
merg->inp_seq = seq;
|
||||
merg->inp_total += le64_to_cpu(tval->total);
|
||||
merg->inp_count += le64_to_cpu(tval->count);
|
||||
} else {
|
||||
merg->log_seq = seq;
|
||||
merg->log_total += le64_to_cpu(tval->total);
|
||||
@@ -53,15 +58,18 @@ void scoutfs_totl_merge_contribute(struct scoutfs_totl_merging *merg,
|
||||
/*
|
||||
* .totl. item merging has to be careful because the log btree merging
|
||||
* code can write partial results to the fs_root. This means that a
|
||||
* reader can see both cases where new finalized logs should be applied
|
||||
* to the old fs items and where old finalized logs have already been
|
||||
* applied to the partially merged fs items. Currently active logged
|
||||
* items are always applied on top of all cases.
|
||||
* reader can see both cases where merge input deltas should be applied
|
||||
* to the old fs items and where they have already been applied to the
|
||||
* partially merged fs items.
|
||||
*
|
||||
* Only finalized log trees that are inputs to the current merge cycle
|
||||
* are tracked in the inp_ bucket. Finalized trees that aren't merge
|
||||
* inputs and active log trees are always applied unconditionally since
|
||||
* they cannot be in fs_root.
|
||||
*
|
||||
* These cases are differentiated with a combination of sequence numbers
|
||||
* in items, the count of contributing xattrs, and a flag
|
||||
* differentiating finalized and active logged items. This lets us
|
||||
* recognize all cases, including when finalized logs were merged and
|
||||
* in items and the count of contributing xattrs. This lets us
|
||||
* recognize all cases, including when merge inputs were merged and
|
||||
* deleted the fs item.
|
||||
*/
|
||||
void scoutfs_totl_merge_resolve(struct scoutfs_totl_merging *merg, __u64 *total, __u64 *count)
|
||||
@@ -75,14 +83,14 @@ void scoutfs_totl_merge_resolve(struct scoutfs_totl_merging *merg, __u64 *total,
|
||||
*count = merg->fs_count;
|
||||
}
|
||||
|
||||
/* apply finalized logs if they're newer or creating */
|
||||
if (((merg->fs_seq != 0) && (merg->fin_seq > merg->fs_seq)) ||
|
||||
((merg->fs_seq == 0) && (merg->fin_count > 0))) {
|
||||
*total += merg->fin_total;
|
||||
*count += merg->fin_count;
|
||||
/* apply merge input deltas if they're newer or creating */
|
||||
if (((merg->fs_seq != 0) && (merg->inp_seq > merg->fs_seq)) ||
|
||||
((merg->fs_seq == 0) && (merg->inp_count > 0))) {
|
||||
*total += merg->inp_total;
|
||||
*count += merg->inp_count;
|
||||
}
|
||||
|
||||
/* always apply active logs which must be newer than fs and finalized */
|
||||
/* always apply non-input finalized and active logs */
|
||||
if (merg->log_seq > 0) {
|
||||
*total += merg->log_total;
|
||||
*count += merg->log_count;
|
||||
|
||||
@@ -7,9 +7,9 @@ struct scoutfs_totl_merging {
|
||||
u64 fs_seq;
|
||||
u64 fs_total;
|
||||
u64 fs_count;
|
||||
u64 fin_seq;
|
||||
u64 fin_total;
|
||||
s64 fin_count;
|
||||
u64 inp_seq;
|
||||
u64 inp_total;
|
||||
s64 inp_count;
|
||||
u64 log_seq;
|
||||
u64 log_total;
|
||||
s64 log_count;
|
||||
|
||||
@@ -46,6 +46,7 @@ static char *names[] = {
|
||||
[SCOUTFS_TRIGGER_SRCH_MERGE_STOP_SAFE] = "srch_merge_stop_safe",
|
||||
[SCOUTFS_TRIGGER_STATFS_LOCK_PURGE] = "statfs_lock_purge",
|
||||
[SCOUTFS_TRIGGER_RECLAIM_SKIP_FINALIZE] = "reclaim_skip_finalize",
|
||||
[SCOUTFS_TRIGGER_LOG_MERGE_FORCE_PARTIAL] = "log_merge_force_partial",
|
||||
};
|
||||
|
||||
bool scoutfs_trigger_test_and_clear(struct super_block *sb, unsigned int t)
|
||||
|
||||
@@ -9,6 +9,7 @@ enum scoutfs_trigger {
|
||||
SCOUTFS_TRIGGER_SRCH_MERGE_STOP_SAFE,
|
||||
SCOUTFS_TRIGGER_STATFS_LOCK_PURGE,
|
||||
SCOUTFS_TRIGGER_RECLAIM_SKIP_FINALIZE,
|
||||
SCOUTFS_TRIGGER_LOG_MERGE_FORCE_PARTIAL,
|
||||
SCOUTFS_TRIGGER_NR,
|
||||
};
|
||||
|
||||
|
||||
@@ -52,6 +52,15 @@ static struct volopt_nr_name {
|
||||
/* initialized by setup, pointer array is null terminated */
|
||||
static struct kobj_attribute volopt_attrs[ARRAY_SIZE(volopt_table)];
|
||||
static struct attribute *volopt_attr_ptrs[ARRAY_SIZE(volopt_table) + 1];
|
||||
#ifdef KC_KOBJECT_DEFAULT_GROUPS
|
||||
static const struct attribute_group volopt_group = {
|
||||
.attrs = volopt_attr_ptrs,
|
||||
};
|
||||
static const struct attribute_group *volopt_groups[] = {
|
||||
&volopt_group,
|
||||
NULL,
|
||||
};
|
||||
#endif
|
||||
|
||||
static void get_opt_data(struct kobj_attribute *attr, struct scoutfs_volume_options *volopt,
|
||||
u64 *bit, __le64 **opt)
|
||||
@@ -164,7 +173,9 @@ int scoutfs_volopt_setup(struct super_block *sb)
|
||||
BUILD_BUG_ON(ARRAY_SIZE(volopt_table) != ARRAY_SIZE(volopt_attr_ptrs) - 1);
|
||||
volopt_attr_ptrs[i] = NULL;
|
||||
|
||||
ret = scoutfs_sysfs_create_attrs(sb, &vinf->ssa, volopt_attr_ptrs, "volume_options");
|
||||
ret = scoutfs_sysfs_create_attrs(sb, &vinf->ssa,
|
||||
KC_KOBJ_DEFAULT_PICK(volopt_groups, volopt_attr_ptrs),
|
||||
"volume_options");
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
|
||||
106
kmod/src/wkic.c
106
kmod/src/wkic.c
@@ -95,6 +95,7 @@ struct wkic_info {
|
||||
/* block reading slow path */
|
||||
struct mutex roots_mutex;
|
||||
struct scoutfs_net_roots roots;
|
||||
u64 merge_input_seq;
|
||||
u64 roots_read_seq;
|
||||
ktime_t roots_expire;
|
||||
|
||||
@@ -171,7 +172,7 @@ struct wkic_item {
|
||||
u64 seq;
|
||||
unsigned int val_len;
|
||||
u8 flags;
|
||||
u8 val[0] __aligned(ARCH_KMALLOC_MINALIGN); /* totls have native structs */
|
||||
u8 val[] __aligned(ARCH_KMALLOC_MINALIGN); /* totls have native structs */
|
||||
};
|
||||
|
||||
static struct wkic_item *witem_container(struct rb_node *node)
|
||||
@@ -763,7 +764,7 @@ static void fill_page_items(struct super_block *sb, struct wkic_page *wpage, str
|
||||
pg_item->val_len = witem->val_len;
|
||||
pg_item->flags = witem->flags;
|
||||
if (witem->val_len)
|
||||
memcpy(pg_item->val, witem->val, witem->val_len);
|
||||
memcpy(&pg_item->val[0], witem->val, witem->val_len);
|
||||
|
||||
/* always inserting greatest item into page */
|
||||
rb_link_node(&pg_item->node, parent, node);
|
||||
@@ -805,29 +806,79 @@ static void free_page_list(struct super_block *sb, struct list_head *list)
|
||||
* read_seq number so that we can compare the age of the items in cached
|
||||
* pages. Only one request to refresh the roots is in progress at a
|
||||
* time. This is the slow path that's only used when the cache isn't
|
||||
* populated and the roots aren't cached. The root request is fast
|
||||
* enough, especially compared to the resulting item reading IO, that we
|
||||
* don't mind hiding it behind a trivial mutex.
|
||||
* populated and the roots aren't cached.
|
||||
*
|
||||
* We read roots directly from the on-disk superblock rather than
|
||||
* requesting them from the server so that we can also read the
|
||||
* log_merge btree from the same superblock. The merge status item
|
||||
* seq tells us which finalized log trees are inputs to the current
|
||||
* merge, which is needed to correctly resolve totl delta items.
|
||||
*/
|
||||
static int get_roots(struct super_block *sb, struct wkic_info *winf,
|
||||
struct scoutfs_net_roots *roots_ret, u64 *read_seq, bool force_new)
|
||||
static int refresh_roots(struct super_block *sb, struct wkic_info *winf)
|
||||
{
|
||||
struct scoutfs_super_block *super;
|
||||
struct scoutfs_log_merge_status *stat;
|
||||
SCOUTFS_BTREE_ITEM_REF(iref);
|
||||
struct scoutfs_key key;
|
||||
int ret;
|
||||
|
||||
super = kmalloc(sizeof(*super), GFP_NOFS);
|
||||
if (!super)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = scoutfs_read_super(sb, super);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
winf->roots = (struct scoutfs_net_roots){
|
||||
.fs_root = super->fs_root,
|
||||
.logs_root = super->logs_root,
|
||||
.srch_root = super->srch_root,
|
||||
};
|
||||
|
||||
winf->merge_input_seq = 0;
|
||||
if (super->log_merge.ref.blkno) {
|
||||
scoutfs_key_set_zeros(&key);
|
||||
key.sk_zone = SCOUTFS_LOG_MERGE_STATUS_ZONE;
|
||||
ret = scoutfs_btree_lookup(sb, &super->log_merge, &key, &iref);
|
||||
if (ret == 0) {
|
||||
if (iref.val_len == sizeof(*stat)) {
|
||||
stat = iref.val;
|
||||
winf->merge_input_seq = le64_to_cpu(stat->seq);
|
||||
} else {
|
||||
ret = -EUCLEAN;
|
||||
}
|
||||
scoutfs_btree_put_iref(&iref);
|
||||
} else if (ret == -ENOENT) {
|
||||
ret = 0;
|
||||
}
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
winf->roots_read_seq++;
|
||||
winf->roots_expire = ktime_add_ms(ktime_get_raw(), WKIC_CACHE_LIFETIME_MS);
|
||||
out:
|
||||
kfree(super);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int get_roots(struct super_block *sb, struct wkic_info *winf,
|
||||
struct scoutfs_net_roots *roots_ret, u64 *merge_input_seq,
|
||||
u64 *read_seq, bool force_new)
|
||||
{
|
||||
struct scoutfs_net_roots roots;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&winf->roots_mutex);
|
||||
|
||||
if (force_new || ktime_before(winf->roots_expire, ktime_get_raw())) {
|
||||
ret = scoutfs_client_get_roots(sb, &roots);
|
||||
ret = refresh_roots(sb, winf);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
winf->roots = roots;
|
||||
winf->roots_read_seq++;
|
||||
winf->roots_expire = ktime_add_ms(ktime_get_raw(), WKIC_CACHE_LIFETIME_MS);
|
||||
}
|
||||
|
||||
*roots_ret = winf->roots;
|
||||
*merge_input_seq = winf->merge_input_seq;
|
||||
*read_seq = winf->roots_read_seq;
|
||||
ret = 0;
|
||||
out:
|
||||
@@ -870,24 +921,30 @@ static int insert_read_pages(struct super_block *sb, struct wkic_info *winf,
|
||||
struct scoutfs_key end;
|
||||
struct wkic_page *wpage;
|
||||
LIST_HEAD(pages);
|
||||
u64 read_seq;
|
||||
u64 merge_input_seq;
|
||||
u64 read_seq = 0;
|
||||
int ret;
|
||||
|
||||
ret = 0;
|
||||
retry_stale:
|
||||
ret = get_roots(sb, winf, &roots, &read_seq, ret == -ESTALE);
|
||||
ret = get_roots(sb, winf, &roots, &merge_input_seq, &read_seq, ret == -ESTALE);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
goto check_stale;
|
||||
|
||||
start = *range_start;
|
||||
end = *range_end;
|
||||
ret = scoutfs_forest_read_items_roots(sb, &roots, key, range_start, &start, &end,
|
||||
read_items_cb, &root);
|
||||
ret = scoutfs_forest_read_items_roots(sb, &roots, merge_input_seq, key, range_start,
|
||||
&start, &end, read_items_cb, &root);
|
||||
trace_scoutfs_wkic_read_items(sb, key, &start, &end);
|
||||
check_stale:
|
||||
ret = scoutfs_block_check_stale(sb, ret, &saved, &roots.fs_root.ref, &roots.logs_root.ref);
|
||||
if (ret < 0) {
|
||||
if (ret == -ESTALE)
|
||||
if (ret == -ESTALE) {
|
||||
/* not safe to retry due to delta items, must restart clean */
|
||||
free_item_tree(&root);
|
||||
root = RB_ROOT;
|
||||
goto retry_stale;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1112,8 +1169,13 @@ int scoutfs_wkic_setup(struct super_block *sb)
|
||||
}
|
||||
|
||||
winf->sb = sb;
|
||||
KC_INIT_SHRINKER_FUNCS(&winf->shrinker, wkic_shrink_count, wkic_shrink_scan);
|
||||
KC_REGISTER_SHRINKER(&winf->shrinker, "scoutfs-weak_item:" SCSBF, SCSB_ARGS(sb));
|
||||
KC_SETUP_SHRINKER(winf->shrinker, winf, 0, wkic_shrink_count,
|
||||
wkic_shrink_scan, "scoutfs-weak_item:" SCSBF, SCSB_ARGS(sb));
|
||||
if (KC_SHRINKER_IS_NULL(winf->shrinker)) {
|
||||
debugfs_remove(winf->drop_dentry);
|
||||
kfree(winf);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
sbi->wkic_info = winf;
|
||||
return 0;
|
||||
@@ -1141,7 +1203,7 @@ void scoutfs_wkic_destroy(struct super_block *sb)
|
||||
|
||||
if (winf) {
|
||||
debugfs_remove(winf->drop_dentry);
|
||||
KC_UNREGISTER_SHRINKER(&winf->shrinker);
|
||||
KC_UNREGISTER_SHRINKER(winf->shrinker);
|
||||
|
||||
/* trees are in sync so tearing down one frees all pages */
|
||||
rbtree_postorder_for_each_entry_safe(wpage, tmp, &winf->wpage_roots[0], nodes[0]) {
|
||||
|
||||
@@ -907,7 +907,7 @@ int scoutfs_xattr_set_locked(struct inode *inode, const char *name, size_t name_
|
||||
|
||||
/* XXX do these want i_mutex or anything? */
|
||||
inode_inc_iversion(inode);
|
||||
inode->i_ctime = current_time(inode);
|
||||
inode_set_ctime_to_ts(inode, current_time(inode));
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
@@ -1265,6 +1265,7 @@ int scoutfs_xattr_drop(struct super_block *sb, u64 ino,
|
||||
ret = parse_indx_key(&tag_key, xat->name, xat->name_len, ino);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
scoutfs_xattr_set_indx_key_xid(&tag_key, le64_to_cpu(key.skx_id));
|
||||
}
|
||||
|
||||
if ((tgs.totl || tgs.indx) && locked_zone != tag_key.sk_zone) {
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
t_filter_fs()
|
||||
{
|
||||
sed -e 's@mnt/test\.[0-9]*@mnt/test@g' \
|
||||
-e 's@Device: [a-fA-F0-9]*h/[0-9]*d@Device: 0h/0d@g'
|
||||
-e 's@Device: [a-fA-F0-9]*h/[0-9]*d@Device: 0h/0d@g' \
|
||||
-e 's@Device: [0-9]*,[0-9]*@Device: 0h/0d@g'
|
||||
}
|
||||
|
||||
#
|
||||
@@ -20,9 +21,6 @@ t_filter_fs()
|
||||
# [ 2687.691366] BUG: KASAN: stack-out-of-bounds in get_reg+0x1bc/0x230
|
||||
# ...
|
||||
# [ 2687.706220] ==================================================================
|
||||
# [ 2687.707284] Disabling lock debugging due to kernel taint
|
||||
#
|
||||
# That final lock debugging message may not be included.
|
||||
#
|
||||
ignore_harmless_unwind_kasan_stack_oob()
|
||||
{
|
||||
@@ -46,10 +44,6 @@ awk '
|
||||
saved=""
|
||||
}
|
||||
( in_soob == 2 && $0 ~ /==================================================================/ ) {
|
||||
in_soob = 3
|
||||
soob_nr = NR
|
||||
}
|
||||
( in_soob == 3 && NR > soob_nr && $0 !~ /Disabling lock debugging/ ) {
|
||||
in_soob = 0
|
||||
}
|
||||
( !in_soob ) { print $0 }
|
||||
@@ -61,6 +55,58 @@ awk '
|
||||
'
|
||||
}
|
||||
|
||||
#
|
||||
# in el97+, XFS can generate a spurious lockdep circular dependency
|
||||
# warning about reclaim. Fixed upstream in e.g. v5.7-rc4-129-g6dcde60efd94
|
||||
#
|
||||
ignore_harmless_xfs_lockdep_warning()
|
||||
{
|
||||
awk '
|
||||
BEGIN {
|
||||
in_block = 0
|
||||
block_nr = 0
|
||||
buf = ""
|
||||
}
|
||||
( !in_block && $0 ~ /======================================================/ ) {
|
||||
in_block = 1
|
||||
block_nr = NR
|
||||
buf = $0 "\n"
|
||||
next
|
||||
}
|
||||
( in_block == 1 && NR == (block_nr + 1) ) {
|
||||
if (match($0, /WARNING: possible circular locking dependency detected/) != 0) {
|
||||
in_block = 2
|
||||
buf = buf $0 "\n"
|
||||
} else {
|
||||
in_block = 0
|
||||
printf "%s", buf
|
||||
print $0
|
||||
buf = ""
|
||||
}
|
||||
next
|
||||
}
|
||||
( in_block == 2 ) {
|
||||
buf = buf $0 "\n"
|
||||
if ($0 ~ /<\/TASK>/) {
|
||||
if (buf ~ /xfs_(nondir_|dir_)?ilock_class/ && buf ~ /fs_reclaim/) {
|
||||
# known xfs lockdep false positive, discard
|
||||
} else {
|
||||
printf "%s", buf
|
||||
}
|
||||
in_block = 0
|
||||
buf = ""
|
||||
}
|
||||
next
|
||||
}
|
||||
{ print $0 }
|
||||
END {
|
||||
if (buf) {
|
||||
printf "%s", buf
|
||||
}
|
||||
}
|
||||
'
|
||||
}
|
||||
|
||||
#
|
||||
# Filter out expected messages. Putting messages here implies that
|
||||
# tests aren't relying on messages to discover failures.. they're
|
||||
@@ -176,6 +222,10 @@ t_filter_dmesg()
|
||||
# creating block devices may trigger this
|
||||
re="$re|block device autoloading is deprecated and will be removed."
|
||||
|
||||
egrep -v "($re)" | \
|
||||
ignore_harmless_unwind_kasan_stack_oob
|
||||
# lockdep or kasan warnings can cause this
|
||||
re="$re|Disabling lock debugging due to kernel taint"
|
||||
|
||||
grep -v -E "($re)" | \
|
||||
ignore_harmless_unwind_kasan_stack_oob | \
|
||||
ignore_harmless_xfs_lockdep_warning
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ four
|
||||
--- dir within dir
|
||||
--- overwrite file
|
||||
--- can't overwrite non-empty dir
|
||||
mv: cannot move '/mnt/test/test/basic-posix-consistency/dir/c/clobber' to '/mnt/test/test/basic-posix-consistency/dir/a/dir': Directory not empty
|
||||
mv: cannot overwrite '/mnt/test/test/basic-posix-consistency/dir/a/dir': Directory not empty
|
||||
--- can overwrite empty dir
|
||||
--- can rename into root
|
||||
== path resoluion
|
||||
|
||||
54
tests/golden/basic-xattr-indx
Normal file
54
tests/golden/basic-xattr-indx
Normal file
@@ -0,0 +1,54 @@
|
||||
== testing invalid read-xattr-index arguments
|
||||
bad index position entry argument 'bad', it must be in the form "a.b.ino" where each value can be prefixed by '0' for octal or '0x' for hex
|
||||
scoutfs: read-xattr-index failed: Invalid argument (22)
|
||||
bad index position entry argument '1.2', it must be in the form "a.b.ino" where each value can be prefixed by '0' for octal or '0x' for hex
|
||||
scoutfs: read-xattr-index failed: Invalid argument (22)
|
||||
initial major index position '256' must be between 0 and 255, inclusive.
|
||||
scoutfs: read-xattr-index failed: Invalid argument (22)
|
||||
first index position 1.2.3 must be less than last index position 0.0.0
|
||||
scoutfs: read-xattr-index failed: Invalid argument (22)
|
||||
first index position 1.2.0 must be less than last index position 1.1.2
|
||||
scoutfs: read-xattr-index failed: Invalid argument (22)
|
||||
first index position 2.2.2 must be less than last index position 2.2.1
|
||||
scoutfs: read-xattr-index failed: Invalid argument (22)
|
||||
== testing invalid names
|
||||
setfattr: /mnt/test/test/basic-xattr-indx/invalid: Invalid argument
|
||||
setfattr: /mnt/test/test/basic-xattr-indx/invalid: Invalid argument
|
||||
setfattr: /mnt/test/test/basic-xattr-indx/invalid: Invalid argument
|
||||
setfattr: /mnt/test/test/basic-xattr-indx/invalid: Invalid argument
|
||||
setfattr: /mnt/test/test/basic-xattr-indx/invalid: Invalid argument
|
||||
setfattr: /mnt/test/test/basic-xattr-indx/invalid: Invalid argument
|
||||
setfattr: /mnt/test/test/basic-xattr-indx/invalid: Invalid argument
|
||||
setfattr: /mnt/test/test/basic-xattr-indx/invalid: Invalid argument
|
||||
setfattr: /mnt/test/test/basic-xattr-indx/invalid: Invalid argument
|
||||
setfattr: /mnt/test/test/basic-xattr-indx/invalid: Invalid argument
|
||||
setfattr: /mnt/test/test/basic-xattr-indx/invalid: Invalid argument
|
||||
setfattr: /mnt/test/test/basic-xattr-indx/invalid: Numerical result out of range
|
||||
== testing boundary values
|
||||
0.0 found
|
||||
255.max found
|
||||
== indx xattr must have no value
|
||||
setfattr: /mnt/test/test/basic-xattr-indx/noval: Invalid argument
|
||||
setfattr: /mnt/test/test/basic-xattr-indx/noval: Invalid argument
|
||||
== set indx xattr and verify index entry
|
||||
found
|
||||
== setting same indx xattr again is a no-op
|
||||
found
|
||||
== removing non-existent indx xattr succeeds
|
||||
setfattr: /mnt/test/test/basic-xattr-indx/file: No such attribute
|
||||
still found
|
||||
== explicit xattr removal cleans up index entry
|
||||
== file deletion cleans up index entry
|
||||
found before delete
|
||||
== multiple indx xattrs on one file cleaned up by deletion
|
||||
entries before delete: 2
|
||||
entries after delete: 0
|
||||
== partial removal leaves other entries
|
||||
300 found
|
||||
== multiple files at same index position
|
||||
files at same position: 2
|
||||
surviving file found
|
||||
== cross-mount visibility
|
||||
found on mount 1
|
||||
== duplicate position deduplication
|
||||
entries for same position: 1
|
||||
3
tests/golden/totl-merge-read
Normal file
3
tests/golden/totl-merge-read
Normal file
@@ -0,0 +1,3 @@
|
||||
== setup
|
||||
expected 4681
|
||||
== cleanup
|
||||
@@ -301,7 +301,7 @@ fi
|
||||
# include everything by default
|
||||
test -z "$T_INCLUDE" && T_INCLUDE="-e '.*'"
|
||||
# (quickly) exclude nothing by default
|
||||
test -z "$T_EXCLUDE" && T_EXCLUDE="-e '\Zx'"
|
||||
test -z "$T_EXCLUDE" && T_EXCLUDE="-e '^$'"
|
||||
|
||||
# eval to strip re ticks but not expand
|
||||
tests=$(grep -v "^#" $T_SEQUENCE |
|
||||
@@ -694,8 +694,8 @@ for t in $tests; do
|
||||
if [ "$sts" == "$T_PASS_STATUS" ]; then
|
||||
dmesg | t_filter_dmesg > "$T_TMPDIR/dmesg.after"
|
||||
diff --old-line-format="" --unchanged-line-format="" \
|
||||
"$T_TMPDIR/dmesg.before" "$T_TMPDIR/dmesg.after" > \
|
||||
"$T_TMPDIR/dmesg.new"
|
||||
"$T_TMPDIR/dmesg.before" "$T_TMPDIR/dmesg.after" | \
|
||||
grep -v '^$' > "$T_TMPDIR/dmesg.new"
|
||||
|
||||
if [ -s "$T_TMPDIR/dmesg.new" ]; then
|
||||
message="unexpected messages in dmesg"
|
||||
|
||||
@@ -26,7 +26,9 @@ srch-basic-functionality.sh
|
||||
simple-xattr-unit.sh
|
||||
retention-basic.sh
|
||||
totl-xattr-tag.sh
|
||||
basic-xattr-indx.sh
|
||||
quota.sh
|
||||
totl-merge-read.sh
|
||||
lock-refleak.sh
|
||||
lock-shrink-consistency.sh
|
||||
lock-shrink-read-race.sh
|
||||
|
||||
@@ -138,7 +138,9 @@ echo "--- can't overwrite non-empty dir"
|
||||
mkdir "$T_D0/dir/a/dir"
|
||||
touch "$T_D0/dir/a/dir/nope"
|
||||
mkdir "$T_D1/dir/c/clobber"
|
||||
mv -T "$T_D1/dir/c/clobber" "$T_D1/dir/a/dir" 2>&1 | t_filter_fs
|
||||
mv -T "$T_D1/dir/c/clobber" "$T_D1/dir/a/dir" 2>&1 | \
|
||||
sed "s@mv: cannot move '.*' to '\(.*\)': Directory not empty@mv: cannot overwrite '\1': Directory not empty@g" | \
|
||||
t_filter_fs
|
||||
find "$T_D0/dir" -ls 2>&1 | t_filter_fs > "$T_TMP.0"
|
||||
find "$T_D1/dir" -ls 2>&1 | t_filter_fs > "$T_TMP.1"
|
||||
diff -u "$T_TMP.0" "$T_TMP.1"
|
||||
|
||||
143
tests/tests/basic-xattr-indx.sh
Normal file
143
tests/tests/basic-xattr-indx.sh
Normal file
@@ -0,0 +1,143 @@
|
||||
#
|
||||
# Test basic .indx. xattr tag functionality and index entry lifecycle
|
||||
#
|
||||
|
||||
t_require_commands touch rm setfattr scoutfs stat
|
||||
t_require_mounts 2
|
||||
|
||||
# query index from a specific mount, default mount 0
|
||||
read_xattr_index()
|
||||
{
|
||||
local nr="${1:-0}"
|
||||
local mnt="$(eval echo \$T_M$nr)"
|
||||
shift
|
||||
|
||||
sync
|
||||
echo 1 > $(t_debugfs_path $nr)/drop_weak_item_cache
|
||||
scoutfs read-xattr-index -p "$mnt" "$@"
|
||||
}
|
||||
|
||||
MAJOR=5
|
||||
MINOR=100
|
||||
|
||||
echo "== testing invalid read-xattr-index arguments"
|
||||
scoutfs read-xattr-index -p "$T_M0" bad 2>&1
|
||||
scoutfs read-xattr-index -p "$T_M0" 1.2 2>&1
|
||||
scoutfs read-xattr-index -p "$T_M0" 1.2.3 256.0.0 2>&1
|
||||
scoutfs read-xattr-index -p "$T_M0" 1.2.3 0.0.0 2>&1
|
||||
scoutfs read-xattr-index -p "$T_M0" 1.2.0 1.1.2 2>&1
|
||||
scoutfs read-xattr-index -p "$T_M0" 2.2.2 2.2.1 2>&1
|
||||
|
||||
echo "== testing invalid names"
|
||||
touch "$T_D0/invalid"
|
||||
setfattr -n scoutfs.hide.indx.test.$MAJOR "$T_D0/invalid" 2>&1 | t_filter_fs
|
||||
setfattr -n scoutfs.hide.indx.test "$T_D0/invalid" 2>&1 | t_filter_fs
|
||||
setfattr -n scoutfs.hide.indx.test.. "$T_D0/invalid" 2>&1 | t_filter_fs
|
||||
setfattr -n scoutfs.hide.indx.test..$MINOR "$T_D0/invalid" 2>&1 | t_filter_fs
|
||||
setfattr -n scoutfs.hide.indx.test.$MAJOR. "$T_D0/invalid" 2>&1 | t_filter_fs
|
||||
setfattr -n scoutfs.hide.indx.test.256.$MINOR "$T_D0/invalid" 2>&1 | t_filter_fs
|
||||
setfattr -n scoutfs.hide.indx.test.abc.$MINOR "$T_D0/invalid" 2>&1 | t_filter_fs
|
||||
setfattr -n scoutfs.hide.indx.test.$MAJOR.abc "$T_D0/invalid" 2>&1 | t_filter_fs
|
||||
setfattr -n scoutfs.hide.indx.test.-1.$MINOR "$T_D0/invalid" 2>&1 | t_filter_fs
|
||||
setfattr -n scoutfs.hide.indx.test.$MAJOR.-1 "$T_D0/invalid" 2>&1 | t_filter_fs
|
||||
setfattr -n scoutfs.hide.indx.test.18446744073709551616.$MINOR "$T_D0/invalid" 2>&1 | t_filter_fs
|
||||
setfattr -n scoutfs.hide.indx.$(printf 'x%.0s' $(seq 1 240)).$MAJOR.$MINOR "$T_D0/invalid" 2>&1 | t_filter_fs
|
||||
rm -f "$T_D0/invalid"
|
||||
|
||||
echo "== testing boundary values"
|
||||
touch "$T_D0/boundary"
|
||||
INO=$(stat -c "%i" "$T_D0/boundary")
|
||||
setfattr -n scoutfs.hide.indx.test.0.0 "$T_D0/boundary"
|
||||
read_xattr_index 0 0.0.0 0.0.-1 | awk '($3 == "'$INO'") {print "0.0 found"}'
|
||||
setfattr -x scoutfs.hide.indx.test.0.0 "$T_D0/boundary"
|
||||
setfattr -n scoutfs.hide.indx.test.255.18446744073709551615 "$T_D0/boundary"
|
||||
read_xattr_index 0 255.0.0 255.-1.-1 | awk '($3 == "'$INO'") {print "255.max found"}'
|
||||
setfattr -x scoutfs.hide.indx.test.255.18446744073709551615 "$T_D0/boundary"
|
||||
rm -f "$T_D0/boundary"
|
||||
|
||||
echo "== indx xattr must have no value"
|
||||
touch "$T_D0/noval"
|
||||
setfattr -n scoutfs.hide.indx.test.$MAJOR.$MINOR -v "" "$T_D0/noval" 2>&1 | t_filter_fs
|
||||
setfattr -n scoutfs.hide.indx.test.$MAJOR.$MINOR -v 0 "$T_D0/noval" 2>&1 | t_filter_fs
|
||||
setfattr -n scoutfs.hide.indx.test.$MAJOR.$MINOR -v 1 "$T_D0/noval" 2>&1 | t_filter_fs
|
||||
rm -f "$T_D0/noval"
|
||||
|
||||
echo "== set indx xattr and verify index entry"
|
||||
touch "$T_D0/file"
|
||||
INO=$(stat -c "%i" "$T_D0/file")
|
||||
setfattr -n scoutfs.hide.indx.test.$MAJOR.$MINOR "$T_D0/file"
|
||||
read_xattr_index 0 $MAJOR.0.0 $MAJOR.-1.-1 | awk '($3 == "'$INO'") {print "found"}'
|
||||
|
||||
echo "== setting same indx xattr again is a no-op"
|
||||
setfattr -n scoutfs.hide.indx.test.$MAJOR.$MINOR "$T_D0/file"
|
||||
read_xattr_index 0 $MAJOR.0.0 $MAJOR.-1.-1 | awk '($3 == "'$INO'") {print "found"}'
|
||||
|
||||
echo "== removing non-existent indx xattr succeeds"
|
||||
setfattr -x scoutfs.hide.indx.nonexistent.$MAJOR.999 "$T_D0/file" 2>&1 | t_filter_fs
|
||||
read_xattr_index 0 $MAJOR.0.0 $MAJOR.-1.-1 | awk '($3 == "'$INO'") {print "still found"}'
|
||||
|
||||
echo "== explicit xattr removal cleans up index entry"
|
||||
setfattr -x scoutfs.hide.indx.test.$MAJOR.$MINOR "$T_D0/file"
|
||||
read_xattr_index 0 $MAJOR.0.0 $MAJOR.-1.-1 | awk '($3 == "'$INO'") {print "found orphan"}'
|
||||
rm -f "$T_D0/file"
|
||||
|
||||
echo "== file deletion cleans up index entry"
|
||||
touch "$T_D0/file2"
|
||||
INO=$(stat -c "%i" "$T_D0/file2")
|
||||
setfattr -n scoutfs.hide.indx.test.$MAJOR.$MINOR "$T_D0/file2"
|
||||
read_xattr_index 0 $MAJOR.0.0 $MAJOR.-1.-1 | awk '($3 == "'$INO'") {print "found before delete"}'
|
||||
rm -f "$T_D0/file2"
|
||||
read_xattr_index 0 $MAJOR.0.0 $MAJOR.-1.-1 | awk '($3 == "'$INO'") {print "found orphan after delete"}'
|
||||
|
||||
echo "== multiple indx xattrs on one file cleaned up by deletion"
|
||||
touch "$T_D0/file3"
|
||||
INO=$(stat -c "%i" "$T_D0/file3")
|
||||
setfattr -n scoutfs.hide.indx.a.$MAJOR.200 "$T_D0/file3"
|
||||
setfattr -n scoutfs.hide.indx.b.$MAJOR.300 "$T_D0/file3"
|
||||
BEFORE=$(read_xattr_index 0 $MAJOR.0.0 $MAJOR.-1.-1 | awk '($3 == "'$INO'")' | wc -l)
|
||||
echo "entries before delete: $BEFORE"
|
||||
rm -f "$T_D0/file3"
|
||||
AFTER=$(read_xattr_index 0 $MAJOR.0.0 $MAJOR.-1.-1 | awk '($3 == "'$INO'")' | wc -l)
|
||||
echo "entries after delete: $AFTER"
|
||||
|
||||
echo "== partial removal leaves other entries"
|
||||
touch "$T_D0/partial"
|
||||
INO=$(stat -c "%i" "$T_D0/partial")
|
||||
setfattr -n scoutfs.hide.indx.a.$MAJOR.200 "$T_D0/partial"
|
||||
setfattr -n scoutfs.hide.indx.b.$MAJOR.300 "$T_D0/partial"
|
||||
setfattr -x scoutfs.hide.indx.a.$MAJOR.200 "$T_D0/partial"
|
||||
read_xattr_index 0 $MAJOR.200.0 $MAJOR.200.-1 | awk '($3 == "'$INO'") {print "200 found"}'
|
||||
read_xattr_index 0 $MAJOR.300.0 $MAJOR.300.-1 | awk '($3 == "'$INO'") {print "300 found"}'
|
||||
rm -f "$T_D0/partial"
|
||||
|
||||
echo "== multiple files at same index position"
|
||||
touch "$T_D0/multi_a" "$T_D0/multi_b"
|
||||
INO_A=$(stat -c "%i" "$T_D0/multi_a")
|
||||
INO_B=$(stat -c "%i" "$T_D0/multi_b")
|
||||
setfattr -n scoutfs.hide.indx.test.$MAJOR.$MINOR "$T_D0/multi_a"
|
||||
setfattr -n scoutfs.hide.indx.test.$MAJOR.$MINOR "$T_D0/multi_b"
|
||||
COUNT=$(read_xattr_index 0 $MAJOR.$MINOR.0 $MAJOR.$MINOR.-1 | wc -l)
|
||||
echo "files at same position: $COUNT"
|
||||
rm -f "$T_D0/multi_a"
|
||||
read_xattr_index 0 $MAJOR.$MINOR.0 $MAJOR.$MINOR.-1 | awk '($3 == "'$INO_A'") {print "deleted file still found"}'
|
||||
read_xattr_index 0 $MAJOR.$MINOR.0 $MAJOR.$MINOR.-1 | awk '($3 == "'$INO_B'") {print "surviving file found"}'
|
||||
rm -f "$T_D0/multi_b"
|
||||
|
||||
echo "== cross-mount visibility"
|
||||
touch "$T_D0/file4"
|
||||
INO=$(stat -c "%i" "$T_D0/file4")
|
||||
setfattr -n scoutfs.hide.indx.test.$MAJOR.$MINOR "$T_D0/file4"
|
||||
read_xattr_index 1 $MAJOR.0.0 $MAJOR.-1.-1 | awk '($3 == "'$INO'") {print "found on mount 1"}'
|
||||
rm -f "$T_D0/file4"
|
||||
read_xattr_index 1 $MAJOR.0.0 $MAJOR.-1.-1 | awk '($3 == "'$INO'") {print "found orphan on mount 1"}'
|
||||
|
||||
echo "== duplicate position deduplication"
|
||||
touch "$T_D0/file5"
|
||||
INO=$(stat -c "%i" "$T_D0/file5")
|
||||
setfattr -n scoutfs.hide.indx.aa.$MAJOR.$MINOR "$T_D0/file5"
|
||||
setfattr -n scoutfs.hide.indx.bb.$MAJOR.$MINOR "$T_D0/file5"
|
||||
COUNT=$(read_xattr_index 0 $MAJOR.0.0 $MAJOR.-1.-1 | awk '($3 == "'$INO'")' | wc -l)
|
||||
echo "entries for same position: $COUNT"
|
||||
rm -f "$T_D0/file5"
|
||||
|
||||
t_pass
|
||||
@@ -11,8 +11,8 @@
|
||||
# format version.
|
||||
#
|
||||
|
||||
# not supported on el8 or higher
|
||||
if [ $(source /etc/os-release ; echo ${VERSION_ID:0:1}) -gt 7 ]; then
|
||||
# not supported on el8, or higher versions.
|
||||
if [ $(source /etc/os-release ; echo ${VERSION_ID} | cut -d. -f1) -gt 7 ]; then
|
||||
t_skip_permitted "Unsupported OS version"
|
||||
fi
|
||||
|
||||
|
||||
50
tests/tests/totl-merge-read.sh
Normal file
50
tests/tests/totl-merge-read.sh
Normal file
@@ -0,0 +1,50 @@
|
||||
#
|
||||
# Test that merge_read_item() correctly updates the sequence number when
|
||||
# combining delta items from multiple finalized log trees. Each mount
|
||||
# sets a totl value in its own 3-bit lane (powers of 8) so that any
|
||||
# double-counting overflows the lane and is caught by: or(v, exp) != exp.
|
||||
#
|
||||
|
||||
t_require_commands setfattr scoutfs
|
||||
t_require_mounts 5
|
||||
|
||||
echo "== setup"
|
||||
for nr in $(t_fs_nrs); do
|
||||
d=$(eval echo \$T_D$nr)
|
||||
for i in $(seq 1 2500); do : > "$d/f$nr$i"; done
|
||||
done
|
||||
sync
|
||||
t_force_log_merge
|
||||
|
||||
vals=(1 8 64 512 4096)
|
||||
expected=4681
|
||||
n=0
|
||||
for nr in $(t_fs_nrs); do
|
||||
d=$(eval echo \$T_D$nr)
|
||||
v=${vals[$((n++))]}
|
||||
for i in $(seq 1 2500); do
|
||||
setfattr -n "scoutfs.totl.t.$i.0.0" -v $v "$d/f$nr$i"
|
||||
done
|
||||
done
|
||||
|
||||
t_trigger_arm_silent log_merge_force_partial $(t_server_nr)
|
||||
|
||||
bad="$T_TMPDIR/bad"
|
||||
for nr in $(t_fs_nrs); do
|
||||
( while true; do
|
||||
echo 1 > "$(t_debugfs_path $nr)/drop_weak_item_cache"
|
||||
scoutfs read-xattr-totals -p "$(eval echo \$T_M$nr)" | \
|
||||
awk -F'[ =,]+' -v e=$expected 'or($2+0,e) != e'
|
||||
done ) >> "$bad" &
|
||||
done
|
||||
|
||||
echo "expected $expected"
|
||||
t_force_log_merge
|
||||
t_silent_kill $(jobs -p)
|
||||
test -s "$bad" && echo "double-counted:" && cat "$bad"
|
||||
|
||||
echo "== cleanup"
|
||||
for nr in $(t_fs_nrs); do
|
||||
find "$(eval echo \$T_D$nr)" -name "f$nr*" -delete
|
||||
done
|
||||
t_pass
|
||||
@@ -71,7 +71,7 @@ else
|
||||
m64=""
|
||||
fi
|
||||
|
||||
sparse $m64 $include $search/include "$@" 2>&1 | egrep -v "($RE)" | tee .sparse.output
|
||||
sparse $m64 $include $search/include "$@" 2>&1 | grep -v -E "($RE)" | tee .sparse.output
|
||||
|
||||
rm -f $defines
|
||||
|
||||
|
||||
Reference in New Issue
Block a user