mirror of
https://github.com/versity/scoutfs.git
synced 2026-08-15 19:56:36 +00:00
@@ -25,6 +25,7 @@ scoutfs-y += \
|
||||
forest.o \
|
||||
inode.o \
|
||||
ioctl.o \
|
||||
iomap.o \
|
||||
item.o \
|
||||
kernelcompat.o \
|
||||
lock.o \
|
||||
|
||||
@@ -222,3 +222,13 @@ endif
|
||||
ifneq (,$(shell grep 'define timer_container_of' include/linux/timer.h))
|
||||
ccflags-y += -DKC_TIMER_CONTAINER_OF
|
||||
endif
|
||||
|
||||
#
|
||||
# v6.4-rc1-4f80818b4a58c
|
||||
#
|
||||
# iomap needs iterator nofault support in the read/write paths. We can still
|
||||
# use iomap for fiemap and llseek though.
|
||||
#
|
||||
ifneq (,$(shell grep 'copy_page_to_iter_nofault' include/linux/uio.h))
|
||||
ccflags-y += -DKC_USE_IOMAP_FOR_IO
|
||||
endif
|
||||
|
||||
+240
-249
@@ -21,9 +21,11 @@
|
||||
#include <linux/log2.h>
|
||||
#include <linux/falloc.h>
|
||||
#include <linux/fiemap.h>
|
||||
#include <linux/iomap.h>
|
||||
#include <linux/writeback.h>
|
||||
#include <linux/overflow.h>
|
||||
#include <linux/iversion.h>
|
||||
#include <linux/fadvise.h>
|
||||
|
||||
#include "format.h"
|
||||
#include "super.h"
|
||||
@@ -42,6 +44,7 @@
|
||||
#include "msg.h"
|
||||
#include "ext.h"
|
||||
#include "util.h"
|
||||
#include "iomap.h"
|
||||
|
||||
/*
|
||||
* We want to amortize work done after dirtying the shared transaction
|
||||
@@ -63,12 +66,6 @@ struct data_info {
|
||||
#define DECLARE_DATA_INFO(sb, name) \
|
||||
struct data_info *name = SCOUTFS_SB(sb)->data_info
|
||||
|
||||
struct data_ext_args {
|
||||
u64 ino;
|
||||
struct inode *inode;
|
||||
struct scoutfs_lock *lock;
|
||||
};
|
||||
|
||||
static void item_from_extent(struct scoutfs_key *key,
|
||||
struct scoutfs_data_extent_val *dv, u64 ino,
|
||||
u64 start, u64 len, u64 map, u8 flags)
|
||||
@@ -181,7 +178,7 @@ static int data_ext_remove(struct super_block *sb, void *arg, u64 start,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct scoutfs_ext_ops data_ext_ops = {
|
||||
struct scoutfs_ext_ops data_ext_ops = {
|
||||
.next = data_ext_next,
|
||||
.insert = data_ext_insert,
|
||||
.remove = data_ext_remove,
|
||||
@@ -323,10 +320,8 @@ int scoutfs_data_truncate_items(struct super_block *sb, struct inode *inode,
|
||||
if (WARN_ON_ONCE(last < iblock))
|
||||
return -EINVAL;
|
||||
|
||||
if (inode) {
|
||||
if (inode)
|
||||
si = SCOUTFS_I(inode);
|
||||
down_write(&si->extent_sem);
|
||||
}
|
||||
|
||||
while (iblock <= last) {
|
||||
if (inode)
|
||||
@@ -336,10 +331,12 @@ int scoutfs_data_truncate_items(struct super_block *sb, struct inode *inode,
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
if (inode)
|
||||
if (inode) {
|
||||
down_write(&si->extent_sem);
|
||||
ret = scoutfs_dirty_inode_item(inode, lock);
|
||||
else
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
ret = truncate_extents(sb, inode, ino, iblock, last,
|
||||
@@ -348,8 +345,10 @@ int scoutfs_data_truncate_items(struct super_block *sb, struct inode *inode,
|
||||
if (inode)
|
||||
scoutfs_update_inode_item(inode, lock, &ind_locks);
|
||||
scoutfs_release_trans(sb);
|
||||
if (inode)
|
||||
if (inode) {
|
||||
up_write(&si->extent_sem);
|
||||
scoutfs_inode_index_unlock(sb, &ind_locks);
|
||||
}
|
||||
|
||||
if (ret <= 0)
|
||||
break;
|
||||
@@ -358,9 +357,6 @@ int scoutfs_data_truncate_items(struct super_block *sb, struct inode *inode,
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (si)
|
||||
up_write(&si->extent_sem);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -386,9 +382,9 @@ static inline u64 ext_last(struct scoutfs_extent *ext)
|
||||
* reasonable when a file population is known to be large and dense but
|
||||
* known to be written with non-streaming write patterns.
|
||||
*/
|
||||
static int alloc_block(struct super_block *sb, struct inode *inode,
|
||||
struct scoutfs_extent *ext, u64 iblock,
|
||||
struct scoutfs_lock *lock)
|
||||
int scoutfs_data_alloc_block(struct super_block *sb, struct inode *inode,
|
||||
struct scoutfs_extent *ext, u64 iblock,
|
||||
struct scoutfs_lock *lock)
|
||||
{
|
||||
DECLARE_DATA_INFO(sb, datinf);
|
||||
struct scoutfs_mount_options opts;
|
||||
@@ -611,6 +607,7 @@ static int scoutfs_get_block(struct inode *inode, sector_t iblock,
|
||||
un.len = 1;
|
||||
un.map = ext.map + (iblock - ext.start);
|
||||
un.flags = ext.flags & ~(SEF_OFFLINE|SEF_UNWRITTEN);
|
||||
|
||||
ret = scoutfs_ext_set(sb, &data_ext_ops, &args,
|
||||
un.start, un.len, un.map, un.flags);
|
||||
if (ret == 0) {
|
||||
@@ -622,7 +619,7 @@ static int scoutfs_get_block(struct inode *inode, sector_t iblock,
|
||||
|
||||
/* allocate and map blocks containing our logical block */
|
||||
if (create && !ext.map) {
|
||||
ret = alloc_block(sb, inode, &ext, iblock, lock);
|
||||
ret = scoutfs_data_alloc_block(sb, inode, &ext, iblock, lock);
|
||||
if (ret == 0)
|
||||
set_buffer_new(bh);
|
||||
} else {
|
||||
@@ -653,11 +650,18 @@ static int scoutfs_get_block_read(struct inode *inode, sector_t iblock,
|
||||
struct buffer_head *bh, int create)
|
||||
{
|
||||
struct scoutfs_inode_info *si = SCOUTFS_I(inode);
|
||||
bool caller_has_sem;
|
||||
int ret;
|
||||
|
||||
down_read(&si->extent_sem);
|
||||
caller_has_sem = scoutfs_per_task_get(&si->pt_extent_sem) != NULL;
|
||||
|
||||
if (!caller_has_sem)
|
||||
down_read(&si->extent_sem);
|
||||
|
||||
ret = scoutfs_get_block(inode, iblock, bh, create);
|
||||
up_read(&si->extent_sem);
|
||||
|
||||
if (!caller_has_sem)
|
||||
up_read(&si->extent_sem);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -706,44 +710,55 @@ static int scoutfs_readpage(struct file *file, struct page *page)
|
||||
struct scoutfs_lock *inode_lock = NULL;
|
||||
SCOUTFS_DECLARE_PER_TASK_ENTRY(pt_ent);
|
||||
DECLARE_DATA_WAIT(dw);
|
||||
bool locked;
|
||||
int flags;
|
||||
int ret;
|
||||
|
||||
flags = SCOUTFS_LKF_REFRESH_INODE | SCOUTFS_LKF_NONBLOCK;
|
||||
ret = scoutfs_lock_inode(sb, SCOUTFS_LOCK_READ, flags, inode,
|
||||
&inode_lock);
|
||||
if (ret < 0) {
|
||||
unlock_page(page);
|
||||
if (ret == -EAGAIN) {
|
||||
flags &= ~SCOUTFS_LKF_NONBLOCK;
|
||||
ret = scoutfs_lock_inode(sb, SCOUTFS_LOCK_READ, flags,
|
||||
inode, &inode_lock);
|
||||
if (ret == 0) {
|
||||
scoutfs_unlock(sb, inode_lock,
|
||||
SCOUTFS_LOCK_READ);
|
||||
ret = AOP_TRUNCATED_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) {
|
||||
inode_lock = scoutfs_per_task_get(&si->pt_data_lock);
|
||||
if (!inode_lock) {
|
||||
flags = SCOUTFS_LKF_REFRESH_INODE | SCOUTFS_LKF_NONBLOCK;
|
||||
ret = scoutfs_lock_inode(sb, SCOUTFS_LOCK_READ, flags, inode,
|
||||
&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)
|
||||
if (ret == -EAGAIN) {
|
||||
flags &= ~SCOUTFS_LKF_NONBLOCK;
|
||||
ret = scoutfs_lock_inode(sb, SCOUTFS_LOCK_READ, flags,
|
||||
inode, &inode_lock);
|
||||
if (ret == 0) {
|
||||
scoutfs_unlock(sb, inode_lock,
|
||||
SCOUTFS_LOCK_READ);
|
||||
ret = AOP_TRUNCATED_PAGE;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
locked = true;
|
||||
|
||||
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);
|
||||
locked = false;
|
||||
}
|
||||
if (ret > 0) {
|
||||
ret = scoutfs_data_wait(inode, &dw);
|
||||
if (ret == 0)
|
||||
ret = AOP_TRUNCATED_PAGE;
|
||||
}
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
} else {
|
||||
WARN_ON_ONCE(true);
|
||||
}
|
||||
} else {
|
||||
locked = false;
|
||||
}
|
||||
|
||||
#ifdef KC_MPAGE_READ_FOLIO
|
||||
@@ -752,8 +767,10 @@ 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);
|
||||
if (locked) {
|
||||
scoutfs_unlock(sb, inode_lock, SCOUTFS_LOCK_READ);
|
||||
scoutfs_per_task_del(&si->pt_data_lock, &pt_ent);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -761,14 +778,22 @@ static int scoutfs_readpage(struct file *file, struct page *page)
|
||||
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;
|
||||
bool found_lock;
|
||||
int ret;
|
||||
|
||||
ret = scoutfs_lock_inode(sb, SCOUTFS_LOCK_READ,
|
||||
SCOUTFS_LKF_REFRESH_INODE, inode, &inode_lock);
|
||||
if (ret)
|
||||
return;
|
||||
inode_lock = scoutfs_per_task_get(&si->pt_data_lock);
|
||||
if (!inode_lock) {
|
||||
ret = scoutfs_lock_inode(sb, SCOUTFS_LOCK_READ,
|
||||
SCOUTFS_LKF_REFRESH_INODE, inode, &inode_lock);
|
||||
if (ret)
|
||||
return;
|
||||
found_lock = false;
|
||||
} else {
|
||||
found_lock = true;
|
||||
}
|
||||
|
||||
ret = scoutfs_data_wait_check(inode, readahead_pos(rac),
|
||||
readahead_length(rac), SEF_OFFLINE,
|
||||
@@ -777,7 +802,8 @@ static void scoutfs_readahead(struct readahead_control *rac)
|
||||
if (ret == 0)
|
||||
mpage_readahead(rac, scoutfs_get_block_read);
|
||||
|
||||
scoutfs_unlock(sb, inode_lock, SCOUTFS_LOCK_READ);
|
||||
if (!found_lock)
|
||||
scoutfs_unlock(sb, inode_lock, SCOUTFS_LOCK_READ);
|
||||
}
|
||||
|
||||
static int scoutfs_writepage(struct page *page, struct writeback_control *wbc)
|
||||
@@ -866,8 +892,8 @@ out:
|
||||
}
|
||||
|
||||
/* kinda like __filemap_fdatawrite_range! :P */
|
||||
static int writepages_sync_none(struct address_space *mapping, loff_t start,
|
||||
loff_t end)
|
||||
int scoutfs_writepages_sync_none(struct address_space *mapping,
|
||||
loff_t start, loff_t end)
|
||||
{
|
||||
struct writeback_control wbc = {
|
||||
.sync_mode = WB_SYNC_NONE,
|
||||
@@ -879,12 +905,26 @@ static int writepages_sync_none(struct address_space *mapping, loff_t start,
|
||||
return mapping->a_ops->writepages(mapping, &wbc);
|
||||
}
|
||||
|
||||
void scoutfs_do_write_end(struct inode *inode, struct scoutfs_lock *data_lock,
|
||||
struct list_head *ind_locks)
|
||||
{
|
||||
struct scoutfs_inode_info *si = SCOUTFS_I(inode);
|
||||
|
||||
if (!si->staging) {
|
||||
scoutfs_inode_set_data_seq(inode);
|
||||
scoutfs_inode_inc_data_version(inode);
|
||||
}
|
||||
|
||||
inode_inc_iversion(inode);
|
||||
scoutfs_update_inode_item(inode, data_lock, ind_locks);
|
||||
scoutfs_inode_queue_writeback(inode);
|
||||
}
|
||||
|
||||
static int scoutfs_write_end(struct file *file, struct address_space *mapping,
|
||||
loff_t pos, unsigned len, unsigned copied,
|
||||
struct page *page, void *fsdata)
|
||||
{
|
||||
struct inode *inode = mapping->host;
|
||||
struct scoutfs_inode_info *si = SCOUTFS_I(inode);
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct write_begin_data *wbd = fsdata;
|
||||
int ret;
|
||||
@@ -893,16 +933,9 @@ static int scoutfs_write_end(struct file *file, struct address_space *mapping,
|
||||
len, copied);
|
||||
|
||||
ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata);
|
||||
if (ret > 0) {
|
||||
if (!si->staging) {
|
||||
scoutfs_inode_set_data_seq(inode);
|
||||
scoutfs_inode_inc_data_version(inode);
|
||||
}
|
||||
if (ret > 0)
|
||||
scoutfs_do_write_end(inode, wbd->lock, &wbd->ind_locks);
|
||||
|
||||
inode_inc_iversion(inode);
|
||||
scoutfs_update_inode_item(inode, wbd->lock, &wbd->ind_locks);
|
||||
scoutfs_inode_queue_writeback(inode);
|
||||
}
|
||||
scoutfs_release_trans(sb);
|
||||
scoutfs_inode_index_unlock(sb, &wbd->ind_locks);
|
||||
kfree(wbd);
|
||||
@@ -914,18 +947,16 @@ static int scoutfs_write_end(struct file *file, struct address_space *mapping,
|
||||
* to very long commit latencies with lots of dirty file data.
|
||||
*
|
||||
* This hack tries to minimize these writeback latencies while
|
||||
* keeping concurrent large file strreaming writes from
|
||||
* keeping concurrent large file streaming writes from
|
||||
* suffering too terribly. Every N bytes we kick off background
|
||||
* writbeack on the previous N bytes. By the time transaction
|
||||
* writeback on the previous N bytes. By the time transaction
|
||||
* commit comes along it will find that dirty file blocks have
|
||||
* already been written.
|
||||
*/
|
||||
#define BACKGROUND_WRITEBACK_BYTES (16 * 1024 * 1024)
|
||||
#define BACKGROUND_WRITEBACK_MASK (BACKGROUND_WRITEBACK_BYTES - 1)
|
||||
if (ret > 0 && ((pos + ret) & BACKGROUND_WRITEBACK_MASK) == 0)
|
||||
writepages_sync_none(mapping,
|
||||
pos + ret - BACKGROUND_WRITEBACK_BYTES,
|
||||
pos + ret - 1);
|
||||
scoutfs_writepages_sync_none(mapping,
|
||||
pos + ret - BACKGROUND_WRITEBACK_BYTES,
|
||||
pos + ret - 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1079,27 +1110,27 @@ long scoutfs_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
|
||||
|
||||
inode_dio_wait(inode);
|
||||
|
||||
down_write(&si->extent_sem);
|
||||
|
||||
if (!(mode & FALLOC_FL_KEEP_SIZE) &&
|
||||
(offset + len > i_size_read(inode))) {
|
||||
ret = inode_newsize_ok(inode, offset + len);
|
||||
if (ret)
|
||||
goto out_extent;
|
||||
goto out_mutex;
|
||||
}
|
||||
|
||||
iblock = offset >> SCOUTFS_BLOCK_SM_SHIFT;
|
||||
last = (offset + len - 1) >> SCOUTFS_BLOCK_SM_SHIFT;
|
||||
|
||||
while(iblock <= last) {
|
||||
while (iblock <= last) {
|
||||
|
||||
ret = scoutfs_quota_check_data(sb, inode);
|
||||
if (ret)
|
||||
goto out_extent;
|
||||
goto out_mutex;
|
||||
|
||||
ret = scoutfs_inode_index_lock_hold(inode, &ind_locks, false, true);
|
||||
if (ret)
|
||||
goto out_extent;
|
||||
goto out_mutex;
|
||||
|
||||
down_write(&si->extent_sem);
|
||||
|
||||
ret = fallocate_extents(sb, inode, iblock, last, lock);
|
||||
|
||||
@@ -1116,6 +1147,7 @@ long scoutfs_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
|
||||
if (ret >= 0)
|
||||
scoutfs_update_inode_item(inode, lock, &ind_locks);
|
||||
scoutfs_release_trans(sb);
|
||||
up_write(&si->extent_sem);
|
||||
scoutfs_inode_index_unlock(sb, &ind_locks);
|
||||
|
||||
/* txn couldn't meet the request. Let's try with a new txn */
|
||||
@@ -1125,14 +1157,12 @@ long scoutfs_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
|
||||
}
|
||||
|
||||
if (ret <= 0)
|
||||
goto out_extent;
|
||||
goto out_mutex;
|
||||
|
||||
iblock += ret;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
out_extent:
|
||||
up_write(&si->extent_sem);
|
||||
out_mutex:
|
||||
scoutfs_unlock(sb, lock, SCOUTFS_LOCK_WRITE);
|
||||
inode_unlock(inode);
|
||||
@@ -1142,6 +1172,39 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef KC_USE_IOMAP_FOR_IO
|
||||
static int scoutfs_fadvise(struct file *file, loff_t start, loff_t end, int advice)
|
||||
{
|
||||
struct inode *inode = file_inode(file);
|
||||
struct scoutfs_inode_info *si = SCOUTFS_I(inode);
|
||||
SCOUTFS_DECLARE_PER_TASK_ENTRY(pt_extent_ent);
|
||||
bool locked = false;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* We need to get the extent_sem now, or we'll be out of order with the
|
||||
* mapping.invalidate_lock.
|
||||
*/
|
||||
if (advice == POSIX_FADV_WILLNEED) {
|
||||
down_read(&si->extent_sem);
|
||||
locked = true;
|
||||
|
||||
if (!scoutfs_per_task_add_excl(&si->pt_extent_sem, &pt_extent_ent,
|
||||
&pt_extent_ent))
|
||||
WARN_ON_ONCE(true);
|
||||
}
|
||||
|
||||
ret = generic_fadvise(file, start, end, advice);
|
||||
|
||||
if (locked) {
|
||||
scoutfs_per_task_del(&si->pt_extent_sem, &pt_extent_ent);
|
||||
up_read(&si->extent_sem);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* A special case of initializing a single large offline extent. This
|
||||
* chooses not to deal with any existing extents. It can only be used
|
||||
@@ -1439,7 +1502,6 @@ int scoutfs_data_move_blocks(struct inode *from, u64 from_off,
|
||||
from_start += len;
|
||||
}
|
||||
|
||||
|
||||
up_write(&from_si->extent_sem);
|
||||
up_write(&to_si->extent_sem);
|
||||
|
||||
@@ -1572,163 +1634,47 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* This copies to userspace :/
|
||||
*/
|
||||
static int fill_extent(struct fiemap_extent_info *fieinfo,
|
||||
struct scoutfs_extent *ext, u32 fiemap_flags)
|
||||
{
|
||||
u32 flags;
|
||||
|
||||
if (ext->len == 0)
|
||||
return 0;
|
||||
|
||||
flags = fiemap_flags;
|
||||
if (ext->flags & SEF_OFFLINE)
|
||||
flags |= FIEMAP_EXTENT_UNKNOWN;
|
||||
else if (ext->flags & SEF_UNWRITTEN)
|
||||
flags |= FIEMAP_EXTENT_UNWRITTEN;
|
||||
|
||||
return fiemap_fill_next_extent(fieinfo,
|
||||
ext->start << SCOUTFS_BLOCK_SM_SHIFT,
|
||||
ext->map << SCOUTFS_BLOCK_SM_SHIFT,
|
||||
ext->len << SCOUTFS_BLOCK_SM_SHIFT,
|
||||
flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return all the file's extents whose blocks overlap with the caller's
|
||||
* byte region. We set _LAST on the last extent and _UNKNOWN on offline
|
||||
* extents.
|
||||
*/
|
||||
int scoutfs_data_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||
u64 start, u64 len)
|
||||
{
|
||||
struct scoutfs_inode_info *si = SCOUTFS_I(inode);
|
||||
struct super_block *sb = inode->i_sb;
|
||||
const u64 ino = scoutfs_ino(inode);
|
||||
struct scoutfs_lock *lock = NULL;
|
||||
struct scoutfs_extent *info = NULL;
|
||||
struct page *page = NULL;
|
||||
struct scoutfs_extent ext;
|
||||
struct scoutfs_extent cur;
|
||||
struct data_ext_args args;
|
||||
u32 last_flags;
|
||||
u64 iblock;
|
||||
u64 last;
|
||||
int entries = 0;
|
||||
SCOUTFS_DECLARE_PER_TASK_ENTRY(pt_ent);
|
||||
int ret;
|
||||
int complete = 0;
|
||||
|
||||
if (len == 0) {
|
||||
ret = 0;
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = fiemap_prep(inode, fieinfo, start, &len, FIEMAP_FLAG_SYNC);
|
||||
/*
|
||||
* We don't support xattrs stored in extents. The magic incantation
|
||||
* to communicate this to the caller is to reset fi_flags to
|
||||
* FIEMAP_FLAG_XATTR and return -EBADR.
|
||||
*/
|
||||
if (fieinfo->fi_flags & FIEMAP_FLAG_XATTR) {
|
||||
fieinfo->fi_flags = FIEMAP_FLAG_XATTR;
|
||||
ret = -EBADR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
inode_lock(inode);
|
||||
|
||||
ret = scoutfs_lock_inode(sb, SCOUTFS_LOCK_READ, 0, inode, &lock);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
page = alloc_page(GFP_KERNEL);
|
||||
if (!page) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
scoutfs_per_task_add_excl(&si->pt_data_lock, &pt_ent, lock);
|
||||
|
||||
/* use a dummy extent to track */
|
||||
memset(&cur, 0, sizeof(cur));
|
||||
last_flags = 0;
|
||||
ret = iomap_fiemap(inode, fieinfo, start, len, &scoutfs_iomap_report_ops);
|
||||
|
||||
iblock = start >> SCOUTFS_BLOCK_SM_SHIFT;
|
||||
last = (start + len - 1) >> SCOUTFS_BLOCK_SM_SHIFT;
|
||||
scoutfs_per_task_del(&si->pt_data_lock, &pt_ent);
|
||||
scoutfs_unlock(sb, lock, SCOUTFS_LOCK_READ);
|
||||
|
||||
args.ino = ino;
|
||||
args.inode = inode;
|
||||
|
||||
/* outer loop */
|
||||
while (iblock <= last) {
|
||||
/* lock */
|
||||
inode_lock(inode);
|
||||
down_read(&si->extent_sem);
|
||||
|
||||
ret = scoutfs_lock_inode(sb, SCOUTFS_LOCK_READ, 0, inode, &lock);
|
||||
if (ret) {
|
||||
up_read(&si->extent_sem);
|
||||
inode_unlock(inode);
|
||||
break;
|
||||
}
|
||||
|
||||
args.lock = lock;
|
||||
|
||||
/* collect entries */
|
||||
info = page_address(page);
|
||||
memset(info, 0, PAGE_SIZE);
|
||||
while (entries < (PAGE_SIZE / sizeof(struct fiemap_extent)) - 1) {
|
||||
ret = scoutfs_ext_next(sb, &data_ext_ops, &args,
|
||||
iblock, 1, &ext);
|
||||
if (ret < 0) {
|
||||
if (ret == -ENOENT)
|
||||
ret = 0;
|
||||
complete = 1;
|
||||
last_flags = FIEMAP_EXTENT_LAST;
|
||||
break;
|
||||
}
|
||||
|
||||
trace_scoutfs_data_fiemap_extent(sb, ino, &ext);
|
||||
|
||||
if (ext.start > last) {
|
||||
/* not setting _LAST, it's for end of file */
|
||||
ret = 0;
|
||||
complete = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (scoutfs_ext_can_merge(&cur, &ext)) {
|
||||
/* merged extents could be greater than input len */
|
||||
cur.len += ext.len;
|
||||
} else {
|
||||
/* fill it */
|
||||
memcpy(info, &cur, sizeof(cur));
|
||||
|
||||
entries++;
|
||||
info++;
|
||||
|
||||
cur = ext;
|
||||
}
|
||||
|
||||
iblock = ext.start + ext.len;
|
||||
}
|
||||
|
||||
/* unlock */
|
||||
scoutfs_unlock(sb, lock, SCOUTFS_LOCK_READ);
|
||||
up_read(&si->extent_sem);
|
||||
inode_unlock(inode);
|
||||
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
/* emit entries */
|
||||
info = page_address(page);
|
||||
for (; entries > 0; entries--) {
|
||||
ret = fill_extent(fieinfo, info, 0);
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
info++;
|
||||
}
|
||||
|
||||
if (complete)
|
||||
break;
|
||||
}
|
||||
|
||||
/* still one left, it's in cur */
|
||||
if (cur.len)
|
||||
ret = fill_extent(fieinfo, &cur, last_flags);
|
||||
inode_unlock(inode);
|
||||
|
||||
out:
|
||||
if (ret == 1)
|
||||
ret = 0;
|
||||
if (page)
|
||||
__free_page(page);
|
||||
trace_scoutfs_data_fiemap(sb, start, len, ret);
|
||||
|
||||
return ret;
|
||||
@@ -1827,6 +1773,7 @@ int scoutfs_data_wait_check(struct inode *inode, loff_t pos, loff_t len,
|
||||
DECLARE_DATA_WAIT_ROOT(sb, rt);
|
||||
DECLARE_DATA_WAITQ(inode, wq);
|
||||
struct scoutfs_extent ext = {0,};
|
||||
bool caller_has_sem;
|
||||
u64 iblock;
|
||||
u64 last_block;
|
||||
u64 on;
|
||||
@@ -1845,7 +1792,7 @@ int scoutfs_data_wait_check(struct inode *inode, loff_t pos, loff_t len,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((sef & SEF_OFFLINE)) {
|
||||
if (sef & SEF_OFFLINE) {
|
||||
scoutfs_inode_get_onoff(inode, &on, &off);
|
||||
if (off == 0) {
|
||||
ret = 0;
|
||||
@@ -1853,12 +1800,14 @@ int scoutfs_data_wait_check(struct inode *inode, loff_t pos, loff_t len,
|
||||
}
|
||||
}
|
||||
|
||||
down_read(&si->extent_sem);
|
||||
caller_has_sem = scoutfs_per_task_get(&si->pt_extent_sem) != NULL;
|
||||
if (!caller_has_sem)
|
||||
down_read(&si->extent_sem);
|
||||
|
||||
iblock = pos >> SCOUTFS_BLOCK_SM_SHIFT;
|
||||
last_block = (pos + len - 1) >> SCOUTFS_BLOCK_SM_SHIFT;
|
||||
|
||||
while(iblock <= last_block) {
|
||||
while (iblock <= last_block) {
|
||||
ret = scoutfs_ext_next(sb, &data_ext_ops, &args,
|
||||
iblock, 1, &ext);
|
||||
if (ret < 0) {
|
||||
@@ -1891,7 +1840,8 @@ int scoutfs_data_wait_check(struct inode *inode, loff_t pos, loff_t len,
|
||||
iblock = ext.start + ext.len;
|
||||
}
|
||||
|
||||
up_read(&si->extent_sem);
|
||||
if (!caller_has_sem)
|
||||
up_read(&si->extent_sem);
|
||||
|
||||
out:
|
||||
trace_scoutfs_data_wait_check(sb, ino, pos, len, sef, op, &ext, ret);
|
||||
@@ -2168,40 +2118,77 @@ static vm_fault_t scoutfs_data_filemap_fault(struct vm_fault *vmf)
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct scoutfs_lock *inode_lock = NULL;
|
||||
SCOUTFS_DECLARE_PER_TASK_ENTRY(pt_ent);
|
||||
SCOUTFS_DECLARE_PER_TASK_ENTRY(pt_sem);
|
||||
DECLARE_DATA_WAIT(dw);
|
||||
#ifdef KC_USE_IOMAP_FOR_IO
|
||||
bool caller_has_sem;
|
||||
#endif
|
||||
loff_t pos;
|
||||
int err;
|
||||
vm_fault_t ret = VM_FAULT_SIGBUS;
|
||||
bool found_lock;
|
||||
|
||||
pos = vmf->pgoff;
|
||||
pos <<= PAGE_SHIFT;
|
||||
|
||||
retry:
|
||||
err = scoutfs_lock_inode(sb, SCOUTFS_LOCK_READ,
|
||||
SCOUTFS_LKF_REFRESH_INODE, inode, &inode_lock);
|
||||
if (err < 0)
|
||||
return vmf_error(err);
|
||||
inode_lock = scoutfs_per_task_get(&si->pt_data_lock);
|
||||
if (!inode_lock) {
|
||||
found_lock = false;
|
||||
|
||||
if (scoutfs_per_task_add_excl(&si->pt_data_lock, &pt_ent, inode_lock)) {
|
||||
/* protect checked extents from stage/release */
|
||||
atomic_inc(&inode->i_dio_count);
|
||||
err = scoutfs_lock_inode(sb, SCOUTFS_LOCK_READ,
|
||||
SCOUTFS_LKF_REFRESH_INODE, inode, &inode_lock);
|
||||
if (err < 0)
|
||||
return vmf_error(err);
|
||||
|
||||
err = scoutfs_data_wait_check(inode, pos, PAGE_SIZE,
|
||||
SEF_OFFLINE, SCOUTFS_IOC_DWO_READ,
|
||||
&dw, inode_lock);
|
||||
if (err != 0) {
|
||||
if (err < 0)
|
||||
ret = vmf_error(err);
|
||||
goto out;
|
||||
if (scoutfs_per_task_add_excl(&si->pt_data_lock, &pt_ent, inode_lock)) {
|
||||
/* protect checked extents from stage/release */
|
||||
inode_dio_begin(inode);
|
||||
|
||||
err = scoutfs_data_wait_check(inode, pos, PAGE_SIZE,
|
||||
SEF_OFFLINE, SCOUTFS_IOC_DWO_READ,
|
||||
&dw, inode_lock);
|
||||
if (err != 0) {
|
||||
if (err < 0)
|
||||
ret = vmf_error(err);
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
WARN_ON_ONCE(true);
|
||||
}
|
||||
} else {
|
||||
found_lock = true;
|
||||
}
|
||||
|
||||
#ifdef KC_USE_IOMAP_FOR_IO
|
||||
caller_has_sem = scoutfs_per_task_get(&si->pt_extent_sem) != NULL;
|
||||
if (!caller_has_sem) {
|
||||
down_read(&si->extent_sem);
|
||||
if (!scoutfs_per_task_add_excl(&si->pt_extent_sem, &pt_sem,
|
||||
&caller_has_sem))
|
||||
WARN_ON_ONCE(true);
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = filemap_fault(vmf);
|
||||
|
||||
#ifdef KC_USE_IOMAP_FOR_IO
|
||||
if (!caller_has_sem) {
|
||||
up_read(&si->extent_sem);
|
||||
scoutfs_per_task_del(&si->pt_extent_sem, &pt_sem);
|
||||
}
|
||||
#endif
|
||||
|
||||
out:
|
||||
if (scoutfs_per_task_del(&si->pt_data_lock, &pt_ent))
|
||||
inode_dio_end(inode);
|
||||
scoutfs_unlock(sb, inode_lock, SCOUTFS_LOCK_READ);
|
||||
if (!found_lock) {
|
||||
if (scoutfs_per_task_del(&si->pt_data_lock, &pt_ent))
|
||||
inode_dio_end(inode);
|
||||
else
|
||||
WARN_ON_ONCE(true);
|
||||
|
||||
scoutfs_unlock(sb, inode_lock, SCOUTFS_LOCK_READ);
|
||||
}
|
||||
|
||||
if (scoutfs_data_wait_found(&dw)) {
|
||||
err = scoutfs_data_wait(inode, &dw);
|
||||
if (err == 0)
|
||||
@@ -2229,6 +2216,7 @@ static int scoutfs_file_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
|
||||
const struct address_space_operations scoutfs_file_aops = {
|
||||
#ifdef KC_MPAGE_READ_FOLIO
|
||||
.direct_IO = noop_direct_IO,
|
||||
.dirty_folio = block_dirty_folio,
|
||||
.invalidate_folio = block_invalidate_folio,
|
||||
.read_folio = scoutfs_read_folio,
|
||||
@@ -2252,6 +2240,9 @@ const struct file_operations scoutfs_file_fops = {
|
||||
.fsync = scoutfs_file_fsync,
|
||||
.llseek = scoutfs_file_llseek,
|
||||
.fallocate = scoutfs_fallocate,
|
||||
#ifdef KC_USE_IOMAP_FOR_IO
|
||||
.fadvise = scoutfs_fadvise,
|
||||
#endif
|
||||
};
|
||||
|
||||
void scoutfs_data_init_btrees(struct super_block *sb,
|
||||
|
||||
@@ -38,10 +38,30 @@ struct scoutfs_data_wait {
|
||||
.err = 0, \
|
||||
}
|
||||
|
||||
struct data_ext_args {
|
||||
u64 ino;
|
||||
struct inode *inode;
|
||||
struct scoutfs_lock *lock;
|
||||
};
|
||||
|
||||
extern const struct address_space_operations scoutfs_file_aops;
|
||||
extern const struct file_operations scoutfs_file_fops;
|
||||
extern struct scoutfs_ext_ops data_ext_ops;
|
||||
|
||||
struct scoutfs_alloc;
|
||||
struct scoutfs_block_writer;
|
||||
struct scoutfs_extent;
|
||||
|
||||
#define BACKGROUND_WRITEBACK_BYTES (16 * 1024 * 1024)
|
||||
#define BACKGROUND_WRITEBACK_MASK (BACKGROUND_WRITEBACK_BYTES - 1)
|
||||
int scoutfs_writepages_sync_none(struct address_space *mapping, loff_t start, loff_t end);
|
||||
|
||||
void scoutfs_do_write_end(struct inode *inode, struct scoutfs_lock *data_lock,
|
||||
struct list_head *ind_locks);
|
||||
|
||||
int scoutfs_data_alloc_block(struct super_block *sb, struct inode *inode,
|
||||
struct scoutfs_extent *ext, u64 iblock,
|
||||
struct scoutfs_lock *lock);
|
||||
|
||||
int scoutfs_get_block_write(struct inode *inode, sector_t iblock, struct buffer_head *bh,
|
||||
int create);
|
||||
|
||||
+604
-38
@@ -18,6 +18,7 @@
|
||||
#include <linux/mpage.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/aio.h>
|
||||
#include <linux/iomap.h>
|
||||
|
||||
#include "format.h"
|
||||
#include "super.h"
|
||||
@@ -29,6 +30,544 @@
|
||||
#include "per_task.h"
|
||||
#include "omap.h"
|
||||
#include "quota.h"
|
||||
#include "iomap.h"
|
||||
#include "trans.h"
|
||||
#include "msg.h"
|
||||
|
||||
#ifdef KC_USE_IOMAP_FOR_IO
|
||||
|
||||
static bool scoutfs_should_use_dio(struct kiocb *iocb, struct iov_iter *iter)
|
||||
{
|
||||
/* Current offset must be aligned */
|
||||
if (iocb->ki_pos & SCOUTFS_BLOCK_SM_MASK)
|
||||
return false;
|
||||
|
||||
if (iov_iter_alignment(iter) & SCOUTFS_BLOCK_SM_MASK)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* copied from fs/gfs2/file.c */
|
||||
static inline bool should_fault_in_pages(struct iov_iter *i,
|
||||
struct kiocb *iocb,
|
||||
size_t *prev_count,
|
||||
size_t *window_size)
|
||||
{
|
||||
size_t count = iov_iter_count(i);
|
||||
size_t size, offs;
|
||||
|
||||
if (!count)
|
||||
return false;
|
||||
if (!user_backed_iter(i))
|
||||
return false;
|
||||
|
||||
size = PAGE_SIZE;
|
||||
offs = offset_in_page(iocb->ki_pos);
|
||||
if (*prev_count != count || !*window_size) {
|
||||
size_t nr_dirtied;
|
||||
|
||||
nr_dirtied = max(current->nr_dirtied_pause -
|
||||
current->nr_dirtied, 8);
|
||||
size = min_t(size_t, SZ_1M, nr_dirtied << PAGE_SHIFT);
|
||||
}
|
||||
|
||||
*prev_count = count;
|
||||
*window_size = size - offs;
|
||||
return true;
|
||||
}
|
||||
|
||||
static ssize_t scoutfs_file_buffered_read(struct kiocb *iocb, struct iov_iter *to)
|
||||
{
|
||||
struct inode *inode = file_inode(iocb->ki_filp);
|
||||
struct scoutfs_inode_info *si = SCOUTFS_I(inode);
|
||||
SCOUTFS_DECLARE_PER_TASK_ENTRY(pt_extent_ent);
|
||||
size_t prev_count = 0;
|
||||
size_t window_size = 0;
|
||||
size_t read = 0;
|
||||
bool locked = false;
|
||||
ssize_t ret;
|
||||
|
||||
pagefault_disable();
|
||||
iocb->ki_flags |= IOCB_NOIO;
|
||||
ret = generic_file_read_iter(iocb, to);
|
||||
iocb->ki_flags &= ~IOCB_NOIO;
|
||||
pagefault_enable();
|
||||
|
||||
if (ret >= 0) {
|
||||
if (iov_iter_count(to) == 0)
|
||||
return ret;
|
||||
read = ret;
|
||||
} else if (ret != -EFAULT) {
|
||||
if (ret != -EAGAIN)
|
||||
return ret;
|
||||
}
|
||||
|
||||
retry:
|
||||
down_read(&si->extent_sem);
|
||||
|
||||
if (!scoutfs_per_task_add_excl(&si->pt_extent_sem, &pt_extent_ent,
|
||||
&pt_extent_ent))
|
||||
WARN_ON_ONCE(true);
|
||||
locked = true;
|
||||
|
||||
pagefault_disable();
|
||||
ret = generic_file_read_iter(iocb, to);
|
||||
pagefault_enable();
|
||||
if (ret <= 0 && ret != -EFAULT)
|
||||
goto out;
|
||||
if (ret > 0)
|
||||
read += ret;
|
||||
|
||||
if (should_fault_in_pages(to, iocb, &prev_count, &window_size)) {
|
||||
scoutfs_per_task_del(&si->pt_extent_sem, &pt_extent_ent);
|
||||
up_read(&si->extent_sem);
|
||||
locked = false;
|
||||
window_size -= fault_in_iov_iter_writeable(to, window_size);
|
||||
if (window_size != 0)
|
||||
goto retry;
|
||||
}
|
||||
|
||||
out:
|
||||
if (locked) {
|
||||
scoutfs_per_task_del(&si->pt_extent_sem, &pt_extent_ent);
|
||||
up_read(&si->extent_sem);
|
||||
}
|
||||
|
||||
return read ? read : ret;
|
||||
}
|
||||
|
||||
static ssize_t scoutfs_file_direct_read(struct kiocb *iocb, struct iov_iter *to,
|
||||
bool nowait)
|
||||
{
|
||||
struct file *file = iocb->ki_filp;
|
||||
size_t prev_count = 0;
|
||||
size_t window_size = 0;
|
||||
size_t read = 0;
|
||||
ssize_t ret;
|
||||
|
||||
if (!scoutfs_should_use_dio(iocb, to)) {
|
||||
iocb->ki_flags &= ~IOCB_DIRECT;
|
||||
return scoutfs_file_buffered_read(iocb, to);
|
||||
}
|
||||
|
||||
retry:
|
||||
pagefault_disable();
|
||||
to->nofault = true;
|
||||
ret = iomap_dio_rw(iocb, to, &scoutfs_iomap_ops, NULL, IOMAP_DIO_PARTIAL, read);
|
||||
to->nofault = false;
|
||||
pagefault_enable();
|
||||
|
||||
if (ret <= 0 && ret != -EFAULT)
|
||||
goto out;
|
||||
if (ret > 0)
|
||||
read = ret;
|
||||
|
||||
if (should_fault_in_pages(to, iocb, &prev_count, &window_size)) {
|
||||
window_size -= fault_in_iov_iter_writeable(to, window_size);
|
||||
if (window_size != 0)
|
||||
goto retry;
|
||||
}
|
||||
|
||||
out:
|
||||
file_accessed(file);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
ssize_t scoutfs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
|
||||
{
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct inode *inode = file_inode(file);
|
||||
struct scoutfs_inode_info *si = SCOUTFS_I(inode);
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct scoutfs_lock *scoutfs_inode_lock;
|
||||
SCOUTFS_DECLARE_PER_TASK_ENTRY(pt_data_ent);
|
||||
DECLARE_DATA_WAIT(dw);
|
||||
int lock_flags = SCOUTFS_LKF_REFRESH_INODE;
|
||||
bool is_dio = (iocb->ki_flags & IOCB_DIRECT);
|
||||
bool nowait = (iocb->ki_flags & IOCB_NOWAIT);
|
||||
bool inode_locked;
|
||||
ssize_t ret;
|
||||
|
||||
/* IOCB_NOWAIT is only for direct I/O */
|
||||
if (!is_dio && nowait)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
retry:
|
||||
scoutfs_inode_lock = NULL;
|
||||
inode_locked = false;
|
||||
|
||||
if (is_dio) {
|
||||
if (nowait) {
|
||||
if (!inode_trylock_shared(inode)) {
|
||||
ret = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
lock_flags |= SCOUTFS_LKF_NONBLOCK;
|
||||
} else {
|
||||
inode_lock_shared(inode);
|
||||
}
|
||||
inode_dio_begin(inode);
|
||||
inode_locked = true;
|
||||
} else {
|
||||
/* protect checked extents from release */
|
||||
inode_lock(inode);
|
||||
inode_dio_begin(inode);
|
||||
inode_unlock(inode);
|
||||
}
|
||||
|
||||
ret = scoutfs_lock_inode(sb, SCOUTFS_LOCK_READ,
|
||||
lock_flags, inode, &scoutfs_inode_lock);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (scoutfs_per_task_add_excl(&si->pt_data_lock, &pt_data_ent,
|
||||
scoutfs_inode_lock)) {
|
||||
ret = scoutfs_data_wait_check(inode, iocb->ki_pos, iov_iter_count(to),
|
||||
SEF_OFFLINE, SCOUTFS_IOC_DWO_READ, &dw,
|
||||
scoutfs_inode_lock);
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
} else {
|
||||
WARN_ON_ONCE(true);
|
||||
}
|
||||
|
||||
if (is_dio)
|
||||
ret = scoutfs_file_direct_read(iocb, to, nowait);
|
||||
else
|
||||
ret = scoutfs_file_buffered_read(iocb, to);
|
||||
|
||||
out:
|
||||
inode_dio_end(inode);
|
||||
|
||||
if (scoutfs_inode_lock) {
|
||||
scoutfs_per_task_del(&si->pt_data_lock, &pt_data_ent);
|
||||
scoutfs_unlock(sb, scoutfs_inode_lock, SCOUTFS_LOCK_READ);
|
||||
}
|
||||
|
||||
if (inode_locked)
|
||||
inode_unlock_shared(inode);
|
||||
|
||||
if (scoutfs_data_wait_found(&dw)) {
|
||||
ret = scoutfs_data_wait(inode, &dw);
|
||||
if (ret == 0)
|
||||
goto retry;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int lock_for_iomap_write(struct inode *inode, struct list_head *ind_locks,
|
||||
struct scoutfs_lock *scoutfs_inode_lock,
|
||||
bool nowait)
|
||||
{
|
||||
struct super_block *sb = inode->i_sb;
|
||||
u64 seq;
|
||||
int ret;
|
||||
|
||||
do {
|
||||
ret = scoutfs_inode_index_start(sb, &seq) ?:
|
||||
scoutfs_inode_index_prepare(sb, ind_locks, inode, true) ?:
|
||||
scoutfs_inode_index_try_lock_hold(sb, ind_locks, seq, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* A return value > 0 means the seq number changed */
|
||||
if (ret > 0) {
|
||||
if (nowait)
|
||||
return -EAGAIN;
|
||||
continue;
|
||||
}
|
||||
ret = scoutfs_dirty_inode_item(inode, scoutfs_inode_lock);
|
||||
|
||||
break;
|
||||
} while (true);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void unlock_for_iomap_write(struct inode *inode,
|
||||
struct scoutfs_lock *scoutfs_inode_lock,
|
||||
struct list_head *ind_locks,
|
||||
size_t written)
|
||||
{
|
||||
struct super_block *sb = inode->i_sb;
|
||||
|
||||
if (written > 0)
|
||||
scoutfs_do_write_end(inode, scoutfs_inode_lock, ind_locks);
|
||||
|
||||
scoutfs_release_trans(sb);
|
||||
scoutfs_inode_index_unlock(sb, ind_locks);
|
||||
}
|
||||
|
||||
static ssize_t scoutfs_file_direct_write(struct kiocb *iocb, struct iov_iter *from,
|
||||
struct scoutfs_lock *scoutfs_inode_lock)
|
||||
{
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct inode *inode = file_inode(file);
|
||||
bool nowait = (iocb->ki_flags & IOCB_NOWAIT);
|
||||
LIST_HEAD(ind_locks);
|
||||
size_t prev_count = 0;
|
||||
size_t window_size = 0;
|
||||
size_t written = 0;
|
||||
ssize_t ret = 0;
|
||||
bool locked = false;
|
||||
|
||||
if (!scoutfs_should_use_dio(iocb, from)) {
|
||||
iocb->ki_flags &= ~IOCB_DIRECT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
retry:
|
||||
ret = lock_for_iomap_write(inode, &ind_locks, scoutfs_inode_lock, nowait);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
locked = true;
|
||||
|
||||
/*
|
||||
* Due to lock ordering issues, we need to disable page faults while we're
|
||||
* doing the iomap iterations. Pass IOMAP_DIO_PARTIAL so that the iomap
|
||||
* code knows it's OK to return a partial result. We will try to fault in
|
||||
* any needed pages later on.
|
||||
*/
|
||||
from->nofault = true;
|
||||
ret = iomap_dio_rw(iocb, from, &scoutfs_iomap_ops, NULL,
|
||||
IOMAP_DIO_PARTIAL | IOMAP_DIO_FORCE_WAIT,
|
||||
written);
|
||||
from->nofault = false;
|
||||
|
||||
if (ret <= 0) {
|
||||
if (ret == -ENOTBLK)
|
||||
ret = 0;
|
||||
if (ret != -EFAULT)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* No increment (+=) because iomap returns a cumulative value. */
|
||||
if (ret > 0)
|
||||
written = ret;
|
||||
|
||||
/*
|
||||
* We might have skipped some pages that needed to be faulted in. If so, drop
|
||||
* our locks to avoid deadlock and try to fault them in. Then we can relock
|
||||
* and try the remaining DIO writes.
|
||||
*/
|
||||
if (should_fault_in_pages(from, iocb, &prev_count, &window_size)) {
|
||||
unlock_for_iomap_write(inode, scoutfs_inode_lock, &ind_locks, written);
|
||||
locked = false;
|
||||
window_size -= fault_in_iov_iter_readable(from, window_size);
|
||||
if (window_size != 0)
|
||||
goto retry;
|
||||
}
|
||||
|
||||
out:
|
||||
if (locked) {
|
||||
unlock_for_iomap_write(inode, scoutfs_inode_lock, &ind_locks, written);
|
||||
}
|
||||
|
||||
return ret < 0 ? ret : written;
|
||||
}
|
||||
|
||||
static ssize_t scoutfs_file_buffered_write(struct kiocb *iocb, struct iov_iter *from,
|
||||
struct scoutfs_lock *scoutfs_inode_lock)
|
||||
{
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct inode *inode = file_inode(file);
|
||||
LIST_HEAD(ind_locks);
|
||||
size_t prev_count = 0;
|
||||
size_t window_size = 0;
|
||||
size_t orig_count = iov_iter_count(from);
|
||||
size_t written = 0;
|
||||
bool locked;
|
||||
ssize_t ret;
|
||||
|
||||
retry:
|
||||
locked = false;
|
||||
|
||||
/*
|
||||
* Because of lock ordering issues with the page fault code, we need to
|
||||
* try to manually fault in any pages before acquiring locks. Then we
|
||||
* disable page faults while doing the iomap iterations.
|
||||
*/
|
||||
if (should_fault_in_pages(from, iocb, &prev_count, &window_size)) {
|
||||
window_size -= fault_in_iov_iter_readable(from, window_size);
|
||||
if (window_size == 0) {
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
from->count = min(from->count, window_size);
|
||||
}
|
||||
|
||||
ret = lock_for_iomap_write(inode, &ind_locks, scoutfs_inode_lock, false);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
locked = true;
|
||||
|
||||
pagefault_disable();
|
||||
ret = iomap_file_buffered_write(iocb, from, &scoutfs_iomap_ops);
|
||||
pagefault_enable();
|
||||
|
||||
/* Accumulate the count of what's been written so far */
|
||||
if (ret > 0)
|
||||
written += ret;
|
||||
|
||||
if (ret <= 0 && ret != -EFAULT)
|
||||
goto out;
|
||||
|
||||
from->count = orig_count - written;
|
||||
if (should_fault_in_pages(from, iocb, &prev_count, &window_size)) {
|
||||
/*
|
||||
* There are still some pages to be faulted in. Drop our locks and
|
||||
* try another pass.
|
||||
*/
|
||||
unlock_for_iomap_write(inode, scoutfs_inode_lock, &ind_locks, written);
|
||||
locked = false;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
out:
|
||||
if (locked) {
|
||||
unlock_for_iomap_write(inode, scoutfs_inode_lock, &ind_locks, written);
|
||||
}
|
||||
|
||||
from->count = orig_count - written;
|
||||
|
||||
return written ? written : ret;
|
||||
}
|
||||
|
||||
ssize_t scoutfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
||||
{
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct inode *inode = file_inode(file);
|
||||
struct scoutfs_inode_info *si = SCOUTFS_I(inode);
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct scoutfs_lock *scoutfs_inode_lock = NULL;
|
||||
SCOUTFS_DECLARE_PER_TASK_ENTRY(pt_data_ent);
|
||||
DECLARE_DATA_WAIT(dw);
|
||||
int lock_flags = SCOUTFS_LKF_REFRESH_INODE;
|
||||
bool added_pt_data;
|
||||
bool is_dio = (iocb->ki_flags & IOCB_DIRECT);
|
||||
bool nowait = (iocb->ki_flags & IOCB_NOWAIT);
|
||||
bool is_sync = (iocb->ki_flags & IOCB_DSYNC);
|
||||
ssize_t buffered;
|
||||
ssize_t ret;
|
||||
ssize_t ret2;
|
||||
|
||||
/* We don't support O_DSYNC */
|
||||
iocb->ki_flags &= ~IOCB_DSYNC;
|
||||
|
||||
/* IOCB_NOWAIT is only for direct I/O */
|
||||
if (!is_dio && nowait)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (nowait)
|
||||
lock_flags |= SCOUTFS_LKF_NONBLOCK;
|
||||
|
||||
retry:
|
||||
|
||||
added_pt_data = false;
|
||||
|
||||
if (nowait) {
|
||||
if (!inode_trylock(inode)) {
|
||||
return -EAGAIN;
|
||||
}
|
||||
} else {
|
||||
inode_lock(inode);
|
||||
}
|
||||
|
||||
ret = scoutfs_lock_inode(sb, SCOUTFS_LOCK_WRITE, lock_flags,
|
||||
inode, &scoutfs_inode_lock);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = generic_write_checks(iocb, from);
|
||||
if (ret <= 0)
|
||||
goto out;
|
||||
|
||||
ret = scoutfs_inode_check_retention(inode);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = scoutfs_complete_truncate(inode, scoutfs_inode_lock);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = scoutfs_quota_check_data(sb, inode);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (scoutfs_per_task_add_excl(&si->pt_data_lock, &pt_data_ent,
|
||||
scoutfs_inode_lock)) {
|
||||
/* data_version is per inode, whole file must be online */
|
||||
added_pt_data = true;
|
||||
|
||||
ret = scoutfs_data_wait_check(inode, 0, i_size_read(inode), SEF_OFFLINE,
|
||||
SCOUTFS_IOC_DWO_WRITE, &dw,
|
||||
scoutfs_inode_lock);
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* XXX: remove SUID bit */
|
||||
|
||||
if (is_dio) {
|
||||
ret = scoutfs_file_direct_write(iocb, from, scoutfs_inode_lock);
|
||||
if (ret < 0 || !iov_iter_count(from))
|
||||
goto out;
|
||||
|
||||
buffered = scoutfs_file_buffered_write(iocb, from, scoutfs_inode_lock);
|
||||
if (buffered <= 0) {
|
||||
if (ret == 0)
|
||||
ret = buffered;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure all data is persisted. We want the next direct IO read to be
|
||||
* able to read what was just written. If this fails, just return the
|
||||
* byte count written by direct I/O, since we don't know if the
|
||||
* buffered pages made it to disk.
|
||||
*/
|
||||
ret2 = generic_write_sync(iocb, buffered);
|
||||
invalidate_mapping_pages(file->f_mapping,
|
||||
(iocb->ki_pos - buffered) >> PAGE_SHIFT,
|
||||
(iocb->ki_pos - 1) >> PAGE_SHIFT);
|
||||
if (ret == 0 || ret2 >= 0)
|
||||
ret += ret2;
|
||||
} else {
|
||||
ret = scoutfs_file_buffered_write(iocb, from, scoutfs_inode_lock);
|
||||
if (ret > 0)
|
||||
ret = generic_write_sync(iocb, ret);
|
||||
}
|
||||
|
||||
out:
|
||||
if (added_pt_data) {
|
||||
scoutfs_per_task_del(&si->pt_data_lock, &pt_data_ent);
|
||||
added_pt_data = false;
|
||||
}
|
||||
|
||||
scoutfs_unlock(sb, scoutfs_inode_lock, SCOUTFS_LOCK_WRITE);
|
||||
inode_unlock(inode);
|
||||
|
||||
if (scoutfs_data_wait_found(&dw)) {
|
||||
ret = scoutfs_data_wait(inode, &dw);
|
||||
if (ret == 0)
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (is_sync)
|
||||
iocb->ki_flags |= IOCB_DSYNC;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
ssize_t scoutfs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
|
||||
{
|
||||
@@ -139,6 +678,71 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
loff_t scoutfs_file_llseek(struct file *file, loff_t offset, int whence)
|
||||
{
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
struct scoutfs_inode_info *si = SCOUTFS_I(inode);
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct scoutfs_lock *lock = NULL;
|
||||
SCOUTFS_DECLARE_PER_TASK_ENTRY(pt_ent);
|
||||
bool ilocked = false;
|
||||
int ret = 0;
|
||||
|
||||
switch (whence) {
|
||||
case SEEK_END:
|
||||
case SEEK_DATA:
|
||||
case SEEK_HOLE:
|
||||
/*
|
||||
* These require a lock and inode refresh as they reference i_size.
|
||||
*/
|
||||
inode_lock(inode);
|
||||
ilocked = true;
|
||||
|
||||
ret = scoutfs_lock_inode(sb, SCOUTFS_LOCK_READ,
|
||||
SCOUTFS_LKF_REFRESH_INODE, inode,
|
||||
&lock);
|
||||
if (ret == 0) {
|
||||
if (!scoutfs_per_task_add_excl(&si->pt_data_lock, &pt_ent, lock))
|
||||
WARN_ON_ONCE(true);
|
||||
}
|
||||
case SEEK_SET:
|
||||
case SEEK_CUR:
|
||||
/* No lock required */
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
if (whence == SEEK_DATA) {
|
||||
offset = iomap_seek_data(inode, offset,
|
||||
&scoutfs_iomap_report_ops);
|
||||
} else if (whence == SEEK_HOLE) {
|
||||
offset = iomap_seek_hole(inode, offset,
|
||||
&scoutfs_iomap_report_ops);
|
||||
} else {
|
||||
offset = generic_file_llseek(file, offset, whence);
|
||||
}
|
||||
}
|
||||
|
||||
if (ilocked)
|
||||
inode_unlock(inode);
|
||||
|
||||
if (lock) {
|
||||
scoutfs_per_task_del(&si->pt_data_lock, &pt_ent);
|
||||
scoutfs_unlock(sb, lock, SCOUTFS_LOCK_READ);
|
||||
}
|
||||
|
||||
/* The iomap functions don't update the file pointer */
|
||||
if (ret == 0 && offset >= 0)
|
||||
offset = vfs_setpos(file, offset, sb->s_maxbytes);
|
||||
|
||||
return ret ? ret : offset;
|
||||
}
|
||||
|
||||
int scoutfs_permission(KC_VFS_NS_DEF
|
||||
struct inode *inode, int mask)
|
||||
{
|
||||
@@ -161,41 +765,3 @@ int scoutfs_permission(KC_VFS_NS_DEF
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
loff_t scoutfs_file_llseek(struct file *file, loff_t offset, int whence)
|
||||
{
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct scoutfs_lock *lock = NULL;
|
||||
int ret = 0;
|
||||
|
||||
switch (whence) {
|
||||
case SEEK_END:
|
||||
case SEEK_DATA:
|
||||
case SEEK_HOLE:
|
||||
/*
|
||||
* These require a lock and inode refresh as they
|
||||
* reference i_size.
|
||||
*
|
||||
* XXX: SEEK_DATA/SEEK_HOLE can search our extent
|
||||
* items instead of relying on generic_file_llseek()
|
||||
* trickery.
|
||||
*/
|
||||
ret = scoutfs_lock_inode(sb, SCOUTFS_LOCK_READ,
|
||||
SCOUTFS_LKF_REFRESH_INODE, inode,
|
||||
&lock);
|
||||
case SEEK_SET:
|
||||
case SEEK_CUR:
|
||||
/* No lock required, fall through to the generic helper */
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
offset = generic_file_llseek(file, offset, whence);
|
||||
|
||||
scoutfs_unlock(sb, lock, SCOUTFS_LOCK_READ);
|
||||
|
||||
return ret ? ret : offset;
|
||||
}
|
||||
|
||||
+4
-1
@@ -95,6 +95,7 @@ static void scoutfs_inode_ctor(void *obj)
|
||||
seqlock_init(&si->seqlock);
|
||||
si->staging = false;
|
||||
scoutfs_per_task_init(&si->pt_data_lock);
|
||||
scoutfs_per_task_init(&si->pt_extent_sem);
|
||||
atomic64_set(&si->data_waitq.changed, 0);
|
||||
init_waitqueue_head(&si->data_waitq.waitq);
|
||||
init_rwsem(&si->xattr_rwsem);
|
||||
@@ -398,7 +399,9 @@ static int set_inode_size(struct inode *inode, struct scoutfs_lock *lock,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
scoutfs_per_task_add(&si->pt_data_lock, &pt_ent, lock);
|
||||
if (!scoutfs_per_task_add_excl(&si->pt_data_lock, &pt_ent, lock))
|
||||
WARN_ON_ONCE(true);
|
||||
|
||||
ret = block_truncate_page(inode->i_mapping, new_size, scoutfs_get_block_write);
|
||||
scoutfs_per_task_del(&si->pt_data_lock, &pt_ent);
|
||||
if (ret < 0)
|
||||
|
||||
@@ -51,6 +51,7 @@ struct scoutfs_inode_info {
|
||||
seqlock_t seqlock;
|
||||
bool staging; /* holder of i_mutex is staging */
|
||||
struct scoutfs_per_task pt_data_lock;
|
||||
struct scoutfs_per_task pt_extent_sem;
|
||||
struct scoutfs_data_waitq data_waitq;
|
||||
struct rw_semaphore xattr_rwsem;
|
||||
struct list_head writeback_entry;
|
||||
|
||||
+3
-1
@@ -49,6 +49,7 @@
|
||||
#include "quota.h"
|
||||
#include "scoutfs_trace.h"
|
||||
#include "util.h"
|
||||
#include "msg.h"
|
||||
|
||||
/*
|
||||
* We make inode index items coherent by locking fixed size regions of
|
||||
@@ -529,7 +530,8 @@ static long scoutfs_ioc_stage(struct file *file, unsigned long arg)
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
scoutfs_per_task_add(&si->pt_data_lock, &pt_ent, lock);
|
||||
if (!scoutfs_per_task_add_excl(&si->pt_data_lock, &pt_ent, lock))
|
||||
WARN_ON_ONCE(true);
|
||||
|
||||
isize = i_size_read(inode);
|
||||
|
||||
|
||||
@@ -0,0 +1,316 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Versity Software, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
* License v2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/iomap.h>
|
||||
|
||||
#include "format.h"
|
||||
#include "super.h"
|
||||
#include "inode.h"
|
||||
#include "key.h"
|
||||
#include "counters.h"
|
||||
#include "scoutfs_trace.h"
|
||||
#include "item.h"
|
||||
#include "btree.h"
|
||||
#include "lock.h"
|
||||
#include "ext.h"
|
||||
#include "iomap.h"
|
||||
#include "msg.h"
|
||||
#include "trans.h"
|
||||
|
||||
#define KNOWN_FLAGS (IOMAP_REPORT|IOMAP_DIRECT|IOMAP_WRITE|IOMAP_NOWAIT)
|
||||
|
||||
static void scoutfs_set_iomap(struct inode *inode, struct iomap *iomap,
|
||||
struct scoutfs_extent *ext, loff_t offset,
|
||||
u64 iblock, loff_t length)
|
||||
{
|
||||
struct super_block *sb = inode->i_sb;
|
||||
|
||||
iomap->flags |= IOMAP_F_BUFFER_HEAD;
|
||||
iomap->bdev = sb->s_bdev;
|
||||
|
||||
if (offset + length > i_size_read(inode))
|
||||
iomap->flags |= IOMAP_F_DIRTY;
|
||||
|
||||
if (ext->len == 0 || ext->start > iblock) {
|
||||
iomap->type = IOMAP_HOLE;
|
||||
iomap->addr = IOMAP_NULL_ADDR;
|
||||
iomap->offset = offset;
|
||||
|
||||
if (ext->len > 0) {
|
||||
/* There's a hole at the starting offset */
|
||||
iomap->length = min_t(loff_t,
|
||||
(ext->start - iblock) << SCOUTFS_BLOCK_SM_SHIFT,
|
||||
length);
|
||||
} else {
|
||||
/* There's an implicit hole at EOF */
|
||||
iomap->length = length;
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ext->flags & SEF_OFFLINE) {
|
||||
iomap->type = IOMAP_DELALLOC;
|
||||
iomap->addr = IOMAP_NULL_ADDR;
|
||||
} else if (ext->flags & SEF_UNWRITTEN) {
|
||||
iomap->type = IOMAP_UNWRITTEN;
|
||||
iomap->addr = (u64) ext->map << SCOUTFS_BLOCK_SM_SHIFT;
|
||||
iomap->flags |= IOMAP_F_NEW;
|
||||
} else if (ext->map) {
|
||||
iomap->type = IOMAP_MAPPED;
|
||||
iomap->addr = (u64) ext->map << SCOUTFS_BLOCK_SM_SHIFT;
|
||||
} else {
|
||||
WARN_ON(true); /* holes should've been handled above */
|
||||
}
|
||||
|
||||
iomap->offset = (u64) ext->start << SCOUTFS_BLOCK_SM_SHIFT;
|
||||
iomap->length = (u64) ext->len << SCOUTFS_BLOCK_SM_SHIFT;
|
||||
|
||||
out:
|
||||
trace_scoutfs_set_iomap(sb, scoutfs_ino(inode), iblock, length, iomap->type,
|
||||
iomap->flags, iomap->offset, iomap->length, ext->map);
|
||||
}
|
||||
|
||||
static int scoutfs_iomap_begin_report(struct inode *inode, loff_t offset, loff_t length,
|
||||
unsigned int flags, struct iomap *iomap,
|
||||
struct iomap *srcmap)
|
||||
{
|
||||
struct scoutfs_inode_info *si = SCOUTFS_I(inode);
|
||||
struct super_block *sb = inode->i_sb;
|
||||
const u64 ino = scoutfs_ino(inode);
|
||||
struct scoutfs_lock *lock = NULL;
|
||||
struct scoutfs_extent ext;
|
||||
struct data_ext_args args;
|
||||
u64 iblock;
|
||||
int ret;
|
||||
|
||||
WARN_ON_ONCE(flags & ~KNOWN_FLAGS);
|
||||
WARN_ON(!inode_is_locked(inode));
|
||||
|
||||
iblock = offset >> SCOUTFS_BLOCK_SM_SHIFT;
|
||||
|
||||
/* make sure caller holds a cluster lock */
|
||||
lock = scoutfs_per_task_get(&si->pt_data_lock);
|
||||
WARN_ON(!lock);
|
||||
|
||||
args.ino = ino;
|
||||
args.inode = inode;
|
||||
args.lock = lock;
|
||||
|
||||
memset(&ext, 0, sizeof(ext));
|
||||
|
||||
down_read(&si->extent_sem);
|
||||
|
||||
ret = scoutfs_ext_next(sb, &data_ext_ops, &args, iblock, 1, &ext);
|
||||
|
||||
if (ret == -ENOENT)
|
||||
ret = 0;
|
||||
|
||||
if (ret == 0)
|
||||
scoutfs_set_iomap(inode, iomap, &ext, offset, iblock, length);
|
||||
|
||||
up_read(&si->extent_sem);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct iomap_ops scoutfs_iomap_report_ops = {
|
||||
.iomap_begin = scoutfs_iomap_begin_report,
|
||||
};
|
||||
|
||||
#ifdef KC_USE_IOMAP_FOR_IO
|
||||
|
||||
static int scoutfs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
|
||||
unsigned int flags, struct iomap *iomap,
|
||||
struct iomap *srcmap)
|
||||
{
|
||||
struct scoutfs_inode_info *si = SCOUTFS_I(inode);
|
||||
struct super_block *sb = inode->i_sb;
|
||||
const u64 ino = scoutfs_ino(inode);
|
||||
struct scoutfs_lock *data_lock = NULL;
|
||||
struct scoutfs_extent ext;
|
||||
struct data_ext_args args;
|
||||
u64 iblock;
|
||||
bool write_locked = false;
|
||||
int ret = 0;
|
||||
|
||||
WARN_ON_ONCE(flags & ~KNOWN_FLAGS);
|
||||
|
||||
iblock = offset >> SCOUTFS_BLOCK_SM_SHIFT;
|
||||
|
||||
/* make sure caller holds a cluster lock */
|
||||
data_lock = scoutfs_per_task_get(&si->pt_data_lock);
|
||||
WARN_ON(!data_lock);
|
||||
|
||||
args.ino = ino;
|
||||
args.inode = inode;
|
||||
args.lock = data_lock;
|
||||
|
||||
memset(&ext, 0, sizeof(ext));
|
||||
|
||||
if (flags & IOMAP_WRITE) {
|
||||
down_write(&si->extent_sem);
|
||||
write_locked = true;
|
||||
|
||||
ret = scoutfs_ext_next(sb, &data_ext_ops, &args, iblock, 1, &ext);
|
||||
|
||||
if (ret == -ENOENT)
|
||||
ret = 0;
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if (ext.start > iblock)
|
||||
memset(&ext, 0, sizeof(ext));
|
||||
|
||||
/* non-staging callers should have waited on offline blocks */
|
||||
if (WARN_ON_ONCE(ext.map && (ext.flags & SEF_OFFLINE) && !si->staging)){
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!si->staging) {
|
||||
ret = scoutfs_inode_check_retention(inode);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
/* No need to allocate space */
|
||||
if (ext.map) {
|
||||
trace_scoutfs_data_get_block_found(sb, ino, &ext);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = scoutfs_data_alloc_block(sb, inode, &ext, iblock, data_lock);
|
||||
if (ret == 0)
|
||||
iomap->flags |= IOMAP_F_NEW;
|
||||
} else {
|
||||
down_read(&si->extent_sem);
|
||||
|
||||
ret = scoutfs_ext_next(sb, &data_ext_ops, &args, iblock, 1, &ext);
|
||||
|
||||
up_read(&si->extent_sem);
|
||||
|
||||
if (ret == -ENOENT)
|
||||
ret = 0;
|
||||
|
||||
if (ext.len)
|
||||
trace_scoutfs_data_get_block_found(sb, ino, &ext);
|
||||
}
|
||||
|
||||
out:
|
||||
if (ret == 0)
|
||||
scoutfs_set_iomap(inode, iomap, &ext, offset, iblock, length);
|
||||
|
||||
if (write_locked)
|
||||
up_write(&si->extent_sem);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int scoutfs_iomap_end(struct inode *inode, loff_t offset, loff_t length,
|
||||
ssize_t written, unsigned flags, struct iomap *iomap)
|
||||
{
|
||||
struct scoutfs_inode_info *si = SCOUTFS_I(inode);
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct scoutfs_lock *data_lock = NULL;
|
||||
struct scoutfs_extent un;
|
||||
struct scoutfs_extent ext;
|
||||
struct data_ext_args args;
|
||||
u64 blks_remaining;
|
||||
u64 start_blk;
|
||||
u64 end_blk;
|
||||
int ret = 0;
|
||||
|
||||
if (!(flags & IOMAP_WRITE))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If we hit an error during a direct I/O write, tell the iomap layer to fall
|
||||
* back to buffered I/O by returning the magic value -ENOTBLK.
|
||||
*/
|
||||
if ((flags & IOMAP_DIRECT) && written == 0)
|
||||
return -ENOTBLK;
|
||||
|
||||
data_lock = scoutfs_per_task_get(&si->pt_data_lock);
|
||||
WARN_ON(!data_lock);
|
||||
|
||||
down_write(&si->extent_sem);
|
||||
|
||||
/* convert unwritten to written, could be staging */
|
||||
if (iomap->type == IOMAP_UNWRITTEN) {
|
||||
args.ino = scoutfs_ino(inode);
|
||||
args.inode = inode;
|
||||
args.lock = data_lock;
|
||||
|
||||
/* This is the file block where this write began */
|
||||
start_blk = offset >> SCOUTFS_BLOCK_SM_SHIFT;
|
||||
|
||||
/* This is the file block where this write ended */
|
||||
end_blk = (offset + written - 1) >> SCOUTFS_BLOCK_SM_SHIFT;
|
||||
|
||||
/* We wrote this many blocks */
|
||||
blks_remaining = (end_blk - start_blk) + 1;
|
||||
|
||||
while (blks_remaining > 0) {
|
||||
ret = scoutfs_ext_next(sb, &data_ext_ops, &args, start_blk,
|
||||
1, &ext);
|
||||
|
||||
/*
|
||||
* The extent with the original starting block(s) has to exist.
|
||||
* It's possible that it has been split by page_mkwrite
|
||||
* converting one or more of the blocks from unwritten to
|
||||
* written while we weren't holding the extent_sem in the gap
|
||||
* between iomap_begin and iomap_end. The starting block
|
||||
* still has to be contained within the extent we found.
|
||||
*
|
||||
* But we hold the vfs inode write lock, so we don't have to
|
||||
* worry about truncate removing the extent(s) that cover our
|
||||
* iomap.
|
||||
*/
|
||||
BUG_ON(ret);
|
||||
BUG_ON(start_blk < ext.start);
|
||||
|
||||
un.start = start_blk;
|
||||
un.len = min_t(u64, blks_remaining,
|
||||
(ext.len - (un.start - ext.start)));
|
||||
un.map = (iomap->addr >> SCOUTFS_BLOCK_SM_SHIFT) +
|
||||
(un.start - (iomap->offset >> SCOUTFS_BLOCK_SM_SHIFT));
|
||||
|
||||
WARN_ON(un.map != (ext.map + (un.start - ext.start)));
|
||||
|
||||
un.flags = ext.flags & ~SEF_UNWRITTEN;
|
||||
|
||||
ret = scoutfs_ext_set(sb, &data_ext_ops, &args, un.start, un.len,
|
||||
un.map, un.flags);
|
||||
WARN_ON(ret); /* uh-oh, we already wrote those blocks */
|
||||
|
||||
start_blk += un.len;
|
||||
blks_remaining -= un.len;
|
||||
}
|
||||
}
|
||||
|
||||
if (offset + written > i_size_read(inode))
|
||||
i_size_write(inode, offset + written);
|
||||
|
||||
up_write(&si->extent_sem);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct iomap_ops scoutfs_iomap_ops = {
|
||||
.iomap_begin = scoutfs_iomap_begin,
|
||||
.iomap_end = scoutfs_iomap_end,
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef _SCOUTFS_IOMAP_H
|
||||
#define _SCOUTFS_IOMAP_H
|
||||
|
||||
extern const struct iomap_ops scoutfs_iomap_report_ops;
|
||||
extern const struct iomap_ops scoutfs_iomap_ops;
|
||||
extern const struct iomap_page_ops scoutfs_iomap_page_ops;
|
||||
|
||||
#endif
|
||||
@@ -3269,6 +3269,40 @@ TRACE_EVENT(scoutfs_trigger_fired,
|
||||
TP_printk(SCSBF" %s", SCSB_TRACE_ARGS, __entry->name)
|
||||
);
|
||||
|
||||
TRACE_EVENT(scoutfs_set_iomap,
|
||||
TP_PROTO(struct super_block *sb, u64 ino, u64 iblock, loff_t length,
|
||||
unsigned int type, unsigned int iflags, loff_t ioffset, loff_t ilength,
|
||||
u64 map),
|
||||
|
||||
TP_ARGS(sb, ino, iblock, length, type, iflags, ioffset, ilength, map),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
SCSB_TRACE_FIELDS
|
||||
__field(u64, ino)
|
||||
__field(u64, iblock)
|
||||
__field(loff_t, length)
|
||||
__field(unsigned int, type)
|
||||
__field(loff_t, ioffset)
|
||||
__field(loff_t, ilength)
|
||||
__field(u64, map)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
SCSB_TRACE_ASSIGN(sb);
|
||||
__entry->ino = ino;
|
||||
__entry->iblock = iblock;
|
||||
__entry->length = length;
|
||||
__entry->type = type;
|
||||
__entry->ioffset = ioffset;
|
||||
__entry->ilength = ilength;
|
||||
__entry->map = map;
|
||||
),
|
||||
|
||||
TP_printk(SCSBF" ino %llu iblock %llu len %llu type %d ioff %llu ilen %llu map %llu", SCSB_TRACE_ARGS,
|
||||
__entry->ino, __entry->iblock, __entry->length, __entry->type,
|
||||
__entry->ioffset, __entry->ilength, __entry->map)
|
||||
);
|
||||
|
||||
#endif /* _TRACE_SCOUTFS_H */
|
||||
|
||||
/* This part must be outside protection */
|
||||
|
||||
@@ -330,7 +330,6 @@ int scoutfs_trans_sync(struct super_block *sb, int wait)
|
||||
struct write_attempt attempt = { .ret = 0 };
|
||||
int ret;
|
||||
|
||||
|
||||
if (!wait) {
|
||||
queue_trans_work(sb);
|
||||
return 0;
|
||||
|
||||
@@ -65,7 +65,6 @@ generic/088
|
||||
generic/090
|
||||
generic/091
|
||||
generic/092
|
||||
generic/094
|
||||
generic/096
|
||||
generic/097
|
||||
generic/098
|
||||
@@ -168,7 +167,6 @@ generic/220
|
||||
generic/221
|
||||
generic/222
|
||||
generic/223
|
||||
generic/225
|
||||
generic/227
|
||||
generic/228
|
||||
generic/229
|
||||
@@ -430,7 +428,6 @@ generic/584
|
||||
generic/586
|
||||
generic/587
|
||||
generic/588
|
||||
generic/591
|
||||
generic/592
|
||||
generic/593
|
||||
generic/594
|
||||
@@ -537,13 +534,9 @@ generic/078
|
||||
generic/079
|
||||
generic/081
|
||||
generic/082
|
||||
generic/091
|
||||
generic/094
|
||||
generic/096
|
||||
generic/110
|
||||
generic/111
|
||||
generic/113
|
||||
generic/114
|
||||
generic/115
|
||||
generic/116
|
||||
generic/118
|
||||
@@ -552,9 +545,7 @@ generic/121
|
||||
generic/122
|
||||
generic/123
|
||||
generic/128
|
||||
generic/130
|
||||
generic/134
|
||||
generic/135
|
||||
generic/136
|
||||
generic/138
|
||||
generic/139
|
||||
@@ -602,7 +593,6 @@ generic/194
|
||||
generic/195
|
||||
generic/196
|
||||
generic/197
|
||||
generic/198
|
||||
generic/199
|
||||
generic/200
|
||||
generic/201
|
||||
@@ -610,11 +600,6 @@ generic/202
|
||||
generic/203
|
||||
generic/205
|
||||
generic/206
|
||||
generic/207
|
||||
generic/210
|
||||
generic/211
|
||||
generic/212
|
||||
generic/214
|
||||
generic/216
|
||||
generic/217
|
||||
generic/218
|
||||
@@ -622,13 +607,11 @@ generic/219
|
||||
generic/220
|
||||
generic/222
|
||||
generic/223
|
||||
generic/225
|
||||
generic/227
|
||||
generic/229
|
||||
generic/230
|
||||
generic/235
|
||||
generic/238
|
||||
generic/240
|
||||
generic/244
|
||||
generic/250
|
||||
generic/252
|
||||
@@ -640,7 +623,6 @@ generic/259
|
||||
generic/260
|
||||
generic/261
|
||||
generic/262
|
||||
generic/263
|
||||
generic/264
|
||||
generic/265
|
||||
generic/266
|
||||
@@ -709,7 +691,6 @@ generic/383
|
||||
generic/384
|
||||
generic/385
|
||||
generic/386
|
||||
generic/391
|
||||
generic/392
|
||||
generic/395
|
||||
generic/396
|
||||
@@ -718,17 +699,14 @@ generic/398
|
||||
generic/400
|
||||
generic/402
|
||||
generic/404
|
||||
generic/406
|
||||
generic/407
|
||||
generic/408
|
||||
generic/412
|
||||
generic/413
|
||||
generic/414
|
||||
generic/417
|
||||
generic/419
|
||||
generic/420
|
||||
generic/421
|
||||
generic/422
|
||||
generic/424
|
||||
generic/425
|
||||
generic/427
|
||||
@@ -736,15 +714,12 @@ generic/439
|
||||
generic/440
|
||||
generic/446
|
||||
generic/449
|
||||
generic/450
|
||||
generic/451
|
||||
generic/453
|
||||
generic/454
|
||||
generic/456
|
||||
generic/458
|
||||
generic/462
|
||||
generic/463
|
||||
generic/465
|
||||
generic/466
|
||||
generic/468
|
||||
generic/469
|
||||
@@ -776,7 +751,6 @@ generic/528
|
||||
generic/530
|
||||
generic/536
|
||||
generic/537
|
||||
generic/538
|
||||
generic/539
|
||||
generic/540
|
||||
generic/541
|
||||
@@ -788,7 +762,6 @@ generic/546
|
||||
generic/548
|
||||
generic/549
|
||||
generic/550
|
||||
generic/552
|
||||
generic/553
|
||||
generic/555
|
||||
generic/556
|
||||
@@ -806,10 +779,8 @@ generic/581
|
||||
generic/582
|
||||
generic/583
|
||||
generic/584
|
||||
generic/586
|
||||
generic/587
|
||||
generic/588
|
||||
generic/591
|
||||
generic/592
|
||||
generic/593
|
||||
generic/594
|
||||
@@ -826,7 +797,6 @@ generic/605
|
||||
generic/606
|
||||
generic/607
|
||||
generic/608
|
||||
generic/609
|
||||
generic/610
|
||||
generic/612
|
||||
generic/613
|
||||
@@ -842,7 +812,6 @@ generic/635
|
||||
generic/644
|
||||
generic/645
|
||||
generic/646
|
||||
generic/647
|
||||
generic/651
|
||||
generic/652
|
||||
generic/653
|
||||
@@ -864,7 +833,6 @@ generic/669
|
||||
generic/673
|
||||
generic/674
|
||||
generic/675
|
||||
generic/677
|
||||
generic/678
|
||||
generic/679
|
||||
generic/680
|
||||
@@ -879,4 +847,4 @@ generic/688
|
||||
generic/689
|
||||
shared/002
|
||||
shared/032
|
||||
Passed all 512 tests
|
||||
Passed all 509 tests
|
||||
|
||||
@@ -0,0 +1,876 @@
|
||||
Ran:
|
||||
generic/001
|
||||
generic/002
|
||||
generic/004
|
||||
generic/005
|
||||
generic/006
|
||||
generic/007
|
||||
generic/008
|
||||
generic/009
|
||||
generic/011
|
||||
generic/012
|
||||
generic/013
|
||||
generic/014
|
||||
generic/015
|
||||
generic/016
|
||||
generic/018
|
||||
generic/020
|
||||
generic/021
|
||||
generic/022
|
||||
generic/023
|
||||
generic/024
|
||||
generic/025
|
||||
generic/026
|
||||
generic/028
|
||||
generic/029
|
||||
generic/030
|
||||
generic/031
|
||||
generic/032
|
||||
generic/033
|
||||
generic/034
|
||||
generic/035
|
||||
generic/037
|
||||
generic/039
|
||||
generic/040
|
||||
generic/041
|
||||
generic/050
|
||||
generic/052
|
||||
generic/053
|
||||
generic/056
|
||||
generic/057
|
||||
generic/058
|
||||
generic/059
|
||||
generic/060
|
||||
generic/061
|
||||
generic/062
|
||||
generic/063
|
||||
generic/064
|
||||
generic/065
|
||||
generic/066
|
||||
generic/067
|
||||
generic/069
|
||||
generic/070
|
||||
generic/071
|
||||
generic/073
|
||||
generic/076
|
||||
generic/078
|
||||
generic/079
|
||||
generic/080
|
||||
generic/081
|
||||
generic/082
|
||||
generic/084
|
||||
generic/086
|
||||
generic/087
|
||||
generic/088
|
||||
generic/090
|
||||
generic/091
|
||||
generic/092
|
||||
generic/096
|
||||
generic/097
|
||||
generic/098
|
||||
generic/099
|
||||
generic/101
|
||||
generic/104
|
||||
generic/105
|
||||
generic/106
|
||||
generic/107
|
||||
generic/110
|
||||
generic/111
|
||||
generic/113
|
||||
generic/114
|
||||
generic/115
|
||||
generic/116
|
||||
generic/117
|
||||
generic/118
|
||||
generic/119
|
||||
generic/120
|
||||
generic/121
|
||||
generic/122
|
||||
generic/123
|
||||
generic/124
|
||||
generic/126
|
||||
generic/128
|
||||
generic/129
|
||||
generic/130
|
||||
generic/131
|
||||
generic/134
|
||||
generic/135
|
||||
generic/136
|
||||
generic/138
|
||||
generic/139
|
||||
generic/140
|
||||
generic/141
|
||||
generic/142
|
||||
generic/143
|
||||
generic/144
|
||||
generic/145
|
||||
generic/146
|
||||
generic/147
|
||||
generic/148
|
||||
generic/149
|
||||
generic/150
|
||||
generic/151
|
||||
generic/152
|
||||
generic/153
|
||||
generic/154
|
||||
generic/155
|
||||
generic/156
|
||||
generic/157
|
||||
generic/158
|
||||
generic/159
|
||||
generic/160
|
||||
generic/161
|
||||
generic/162
|
||||
generic/163
|
||||
generic/169
|
||||
generic/171
|
||||
generic/172
|
||||
generic/173
|
||||
generic/174
|
||||
generic/177
|
||||
generic/178
|
||||
generic/179
|
||||
generic/180
|
||||
generic/181
|
||||
generic/182
|
||||
generic/183
|
||||
generic/184
|
||||
generic/185
|
||||
generic/188
|
||||
generic/189
|
||||
generic/190
|
||||
generic/191
|
||||
generic/193
|
||||
generic/194
|
||||
generic/195
|
||||
generic/196
|
||||
generic/197
|
||||
generic/198
|
||||
generic/199
|
||||
generic/200
|
||||
generic/201
|
||||
generic/202
|
||||
generic/203
|
||||
generic/205
|
||||
generic/206
|
||||
generic/207
|
||||
generic/210
|
||||
generic/211
|
||||
generic/212
|
||||
generic/214
|
||||
generic/215
|
||||
generic/216
|
||||
generic/217
|
||||
generic/218
|
||||
generic/219
|
||||
generic/220
|
||||
generic/221
|
||||
generic/222
|
||||
generic/223
|
||||
generic/227
|
||||
generic/228
|
||||
generic/229
|
||||
generic/230
|
||||
generic/235
|
||||
generic/236
|
||||
generic/237
|
||||
generic/238
|
||||
generic/240
|
||||
generic/244
|
||||
generic/245
|
||||
generic/246
|
||||
generic/247
|
||||
generic/248
|
||||
generic/249
|
||||
generic/250
|
||||
generic/252
|
||||
generic/253
|
||||
generic/254
|
||||
generic/255
|
||||
generic/256
|
||||
generic/257
|
||||
generic/258
|
||||
generic/259
|
||||
generic/260
|
||||
generic/261
|
||||
generic/262
|
||||
generic/263
|
||||
generic/264
|
||||
generic/265
|
||||
generic/266
|
||||
generic/267
|
||||
generic/268
|
||||
generic/271
|
||||
generic/272
|
||||
generic/276
|
||||
generic/277
|
||||
generic/278
|
||||
generic/279
|
||||
generic/281
|
||||
generic/282
|
||||
generic/283
|
||||
generic/284
|
||||
generic/286
|
||||
generic/287
|
||||
generic/288
|
||||
generic/289
|
||||
generic/290
|
||||
generic/291
|
||||
generic/292
|
||||
generic/293
|
||||
generic/294
|
||||
generic/295
|
||||
generic/296
|
||||
generic/301
|
||||
generic/302
|
||||
generic/303
|
||||
generic/304
|
||||
generic/305
|
||||
generic/306
|
||||
generic/307
|
||||
generic/308
|
||||
generic/309
|
||||
generic/312
|
||||
generic/313
|
||||
generic/314
|
||||
generic/315
|
||||
generic/316
|
||||
generic/317
|
||||
generic/319
|
||||
generic/322
|
||||
generic/324
|
||||
generic/325
|
||||
generic/326
|
||||
generic/327
|
||||
generic/328
|
||||
generic/329
|
||||
generic/330
|
||||
generic/331
|
||||
generic/332
|
||||
generic/335
|
||||
generic/336
|
||||
generic/337
|
||||
generic/341
|
||||
generic/342
|
||||
generic/343
|
||||
generic/346
|
||||
generic/348
|
||||
generic/353
|
||||
generic/355
|
||||
generic/358
|
||||
generic/359
|
||||
generic/360
|
||||
generic/361
|
||||
generic/362
|
||||
generic/363
|
||||
generic/364
|
||||
generic/365
|
||||
generic/366
|
||||
generic/367
|
||||
generic/368
|
||||
generic/369
|
||||
generic/370
|
||||
generic/371
|
||||
generic/372
|
||||
generic/373
|
||||
generic/374
|
||||
generic/375
|
||||
generic/376
|
||||
generic/377
|
||||
generic/378
|
||||
generic/379
|
||||
generic/380
|
||||
generic/381
|
||||
generic/382
|
||||
generic/383
|
||||
generic/384
|
||||
generic/385
|
||||
generic/386
|
||||
generic/389
|
||||
generic/391
|
||||
generic/392
|
||||
generic/393
|
||||
generic/394
|
||||
generic/395
|
||||
generic/396
|
||||
generic/397
|
||||
generic/398
|
||||
generic/400
|
||||
generic/401
|
||||
generic/402
|
||||
generic/403
|
||||
generic/404
|
||||
generic/406
|
||||
generic/407
|
||||
generic/408
|
||||
generic/412
|
||||
generic/413
|
||||
generic/414
|
||||
generic/417
|
||||
generic/419
|
||||
generic/420
|
||||
generic/421
|
||||
generic/422
|
||||
generic/424
|
||||
generic/425
|
||||
generic/426
|
||||
generic/427
|
||||
generic/428
|
||||
generic/436
|
||||
generic/437
|
||||
generic/439
|
||||
generic/440
|
||||
generic/443
|
||||
generic/445
|
||||
generic/446
|
||||
generic/448
|
||||
generic/449
|
||||
generic/450
|
||||
generic/451
|
||||
generic/452
|
||||
generic/453
|
||||
generic/454
|
||||
generic/456
|
||||
generic/458
|
||||
generic/460
|
||||
generic/462
|
||||
generic/463
|
||||
generic/465
|
||||
generic/466
|
||||
generic/468
|
||||
generic/469
|
||||
generic/470
|
||||
generic/471
|
||||
generic/474
|
||||
generic/477
|
||||
generic/478
|
||||
generic/479
|
||||
generic/480
|
||||
generic/481
|
||||
generic/483
|
||||
generic/485
|
||||
generic/486
|
||||
generic/487
|
||||
generic/488
|
||||
generic/489
|
||||
generic/490
|
||||
generic/491
|
||||
generic/492
|
||||
generic/498
|
||||
generic/499
|
||||
generic/501
|
||||
generic/502
|
||||
generic/503
|
||||
generic/504
|
||||
generic/505
|
||||
generic/506
|
||||
generic/507
|
||||
generic/508
|
||||
generic/509
|
||||
generic/510
|
||||
generic/511
|
||||
generic/512
|
||||
generic/513
|
||||
generic/514
|
||||
generic/515
|
||||
generic/516
|
||||
generic/517
|
||||
generic/518
|
||||
generic/519
|
||||
generic/520
|
||||
generic/523
|
||||
generic/524
|
||||
generic/525
|
||||
generic/526
|
||||
generic/527
|
||||
generic/528
|
||||
generic/529
|
||||
generic/530
|
||||
generic/531
|
||||
generic/533
|
||||
generic/534
|
||||
generic/535
|
||||
generic/536
|
||||
generic/537
|
||||
generic/538
|
||||
generic/539
|
||||
generic/540
|
||||
generic/541
|
||||
generic/542
|
||||
generic/543
|
||||
generic/544
|
||||
generic/545
|
||||
generic/546
|
||||
generic/547
|
||||
generic/548
|
||||
generic/549
|
||||
generic/550
|
||||
generic/552
|
||||
generic/553
|
||||
generic/555
|
||||
generic/556
|
||||
generic/557
|
||||
generic/566
|
||||
generic/567
|
||||
generic/571
|
||||
generic/572
|
||||
generic/573
|
||||
generic/574
|
||||
generic/575
|
||||
generic/576
|
||||
generic/577
|
||||
generic/578
|
||||
generic/580
|
||||
generic/581
|
||||
generic/582
|
||||
generic/583
|
||||
generic/584
|
||||
generic/586
|
||||
generic/587
|
||||
generic/588
|
||||
generic/592
|
||||
generic/593
|
||||
generic/594
|
||||
generic/595
|
||||
generic/596
|
||||
generic/597
|
||||
generic/598
|
||||
generic/599
|
||||
generic/600
|
||||
generic/601
|
||||
generic/602
|
||||
generic/603
|
||||
generic/604
|
||||
generic/605
|
||||
generic/606
|
||||
generic/607
|
||||
generic/608
|
||||
generic/609
|
||||
generic/610
|
||||
generic/611
|
||||
generic/612
|
||||
generic/613
|
||||
generic/614
|
||||
generic/618
|
||||
generic/621
|
||||
generic/623
|
||||
generic/624
|
||||
generic/625
|
||||
generic/626
|
||||
generic/628
|
||||
generic/629
|
||||
generic/630
|
||||
generic/632
|
||||
generic/634
|
||||
generic/635
|
||||
generic/637
|
||||
generic/638
|
||||
generic/639
|
||||
generic/640
|
||||
generic/644
|
||||
generic/645
|
||||
generic/646
|
||||
generic/647
|
||||
generic/651
|
||||
generic/652
|
||||
generic/653
|
||||
generic/654
|
||||
generic/655
|
||||
generic/657
|
||||
generic/658
|
||||
generic/659
|
||||
generic/660
|
||||
generic/661
|
||||
generic/662
|
||||
generic/663
|
||||
generic/664
|
||||
generic/665
|
||||
generic/666
|
||||
generic/667
|
||||
generic/668
|
||||
generic/669
|
||||
generic/673
|
||||
generic/674
|
||||
generic/675
|
||||
generic/676
|
||||
generic/677
|
||||
generic/678
|
||||
generic/679
|
||||
generic/680
|
||||
generic/681
|
||||
generic/682
|
||||
generic/683
|
||||
generic/684
|
||||
generic/685
|
||||
generic/686
|
||||
generic/687
|
||||
generic/688
|
||||
generic/689
|
||||
shared/002
|
||||
shared/032
|
||||
Not
|
||||
run:
|
||||
generic/008
|
||||
generic/009
|
||||
generic/012
|
||||
generic/015
|
||||
generic/016
|
||||
generic/018
|
||||
generic/021
|
||||
generic/022
|
||||
generic/025
|
||||
generic/026
|
||||
generic/031
|
||||
generic/033
|
||||
generic/050
|
||||
generic/052
|
||||
generic/058
|
||||
generic/059
|
||||
generic/060
|
||||
generic/061
|
||||
generic/063
|
||||
generic/064
|
||||
generic/078
|
||||
generic/079
|
||||
generic/081
|
||||
generic/082
|
||||
generic/091
|
||||
generic/096
|
||||
generic/110
|
||||
generic/111
|
||||
generic/113
|
||||
generic/114
|
||||
generic/115
|
||||
generic/116
|
||||
generic/118
|
||||
generic/119
|
||||
generic/121
|
||||
generic/122
|
||||
generic/123
|
||||
generic/128
|
||||
generic/130
|
||||
generic/134
|
||||
generic/135
|
||||
generic/136
|
||||
generic/138
|
||||
generic/139
|
||||
generic/140
|
||||
generic/142
|
||||
generic/143
|
||||
generic/144
|
||||
generic/145
|
||||
generic/146
|
||||
generic/147
|
||||
generic/148
|
||||
generic/149
|
||||
generic/150
|
||||
generic/151
|
||||
generic/152
|
||||
generic/153
|
||||
generic/154
|
||||
generic/155
|
||||
generic/156
|
||||
generic/157
|
||||
generic/158
|
||||
generic/159
|
||||
generic/160
|
||||
generic/161
|
||||
generic/162
|
||||
generic/163
|
||||
generic/171
|
||||
generic/172
|
||||
generic/173
|
||||
generic/174
|
||||
generic/177
|
||||
generic/178
|
||||
generic/179
|
||||
generic/180
|
||||
generic/181
|
||||
generic/182
|
||||
generic/183
|
||||
generic/185
|
||||
generic/188
|
||||
generic/189
|
||||
generic/190
|
||||
generic/191
|
||||
generic/193
|
||||
generic/194
|
||||
generic/195
|
||||
generic/196
|
||||
generic/197
|
||||
generic/198
|
||||
generic/199
|
||||
generic/200
|
||||
generic/201
|
||||
generic/202
|
||||
generic/203
|
||||
generic/205
|
||||
generic/206
|
||||
generic/207
|
||||
generic/210
|
||||
generic/211
|
||||
generic/212
|
||||
generic/214
|
||||
generic/216
|
||||
generic/217
|
||||
generic/218
|
||||
generic/219
|
||||
generic/220
|
||||
generic/222
|
||||
generic/223
|
||||
generic/227
|
||||
generic/229
|
||||
generic/230
|
||||
generic/235
|
||||
generic/238
|
||||
generic/240
|
||||
generic/244
|
||||
generic/250
|
||||
generic/252
|
||||
generic/253
|
||||
generic/254
|
||||
generic/255
|
||||
generic/256
|
||||
generic/259
|
||||
generic/260
|
||||
generic/261
|
||||
generic/262
|
||||
generic/263
|
||||
generic/264
|
||||
generic/265
|
||||
generic/266
|
||||
generic/267
|
||||
generic/268
|
||||
generic/271
|
||||
generic/272
|
||||
generic/276
|
||||
generic/277
|
||||
generic/278
|
||||
generic/279
|
||||
generic/281
|
||||
generic/282
|
||||
generic/283
|
||||
generic/284
|
||||
generic/287
|
||||
generic/288
|
||||
generic/289
|
||||
generic/290
|
||||
generic/291
|
||||
generic/292
|
||||
generic/293
|
||||
generic/295
|
||||
generic/296
|
||||
generic/301
|
||||
generic/302
|
||||
generic/303
|
||||
generic/304
|
||||
generic/305
|
||||
generic/312
|
||||
generic/314
|
||||
generic/316
|
||||
generic/317
|
||||
generic/324
|
||||
generic/326
|
||||
generic/327
|
||||
generic/328
|
||||
generic/329
|
||||
generic/330
|
||||
generic/331
|
||||
generic/332
|
||||
generic/353
|
||||
generic/355
|
||||
generic/358
|
||||
generic/359
|
||||
generic/361
|
||||
generic/362
|
||||
generic/363
|
||||
generic/364
|
||||
generic/365
|
||||
generic/366
|
||||
generic/367
|
||||
generic/368
|
||||
generic/369
|
||||
generic/370
|
||||
generic/371
|
||||
generic/372
|
||||
generic/373
|
||||
generic/374
|
||||
generic/378
|
||||
generic/379
|
||||
generic/380
|
||||
generic/381
|
||||
generic/382
|
||||
generic/383
|
||||
generic/384
|
||||
generic/385
|
||||
generic/386
|
||||
generic/391
|
||||
generic/392
|
||||
generic/395
|
||||
generic/396
|
||||
generic/397
|
||||
generic/398
|
||||
generic/400
|
||||
generic/402
|
||||
generic/404
|
||||
generic/406
|
||||
generic/407
|
||||
generic/408
|
||||
generic/412
|
||||
generic/413
|
||||
generic/414
|
||||
generic/417
|
||||
generic/419
|
||||
generic/420
|
||||
generic/421
|
||||
generic/422
|
||||
generic/424
|
||||
generic/425
|
||||
generic/427
|
||||
generic/439
|
||||
generic/440
|
||||
generic/446
|
||||
generic/449
|
||||
generic/450
|
||||
generic/451
|
||||
generic/453
|
||||
generic/454
|
||||
generic/456
|
||||
generic/458
|
||||
generic/462
|
||||
generic/463
|
||||
generic/465
|
||||
generic/466
|
||||
generic/468
|
||||
generic/469
|
||||
generic/470
|
||||
generic/471
|
||||
generic/474
|
||||
generic/485
|
||||
generic/487
|
||||
generic/488
|
||||
generic/491
|
||||
generic/492
|
||||
generic/499
|
||||
generic/501
|
||||
generic/503
|
||||
generic/505
|
||||
generic/506
|
||||
generic/507
|
||||
generic/508
|
||||
generic/511
|
||||
generic/513
|
||||
generic/514
|
||||
generic/515
|
||||
generic/516
|
||||
generic/517
|
||||
generic/518
|
||||
generic/519
|
||||
generic/520
|
||||
generic/528
|
||||
generic/530
|
||||
generic/536
|
||||
generic/537
|
||||
generic/538
|
||||
generic/539
|
||||
generic/540
|
||||
generic/541
|
||||
generic/542
|
||||
generic/543
|
||||
generic/544
|
||||
generic/545
|
||||
generic/546
|
||||
generic/548
|
||||
generic/549
|
||||
generic/550
|
||||
generic/552
|
||||
generic/553
|
||||
generic/555
|
||||
generic/556
|
||||
generic/566
|
||||
generic/567
|
||||
generic/572
|
||||
generic/573
|
||||
generic/574
|
||||
generic/575
|
||||
generic/576
|
||||
generic/577
|
||||
generic/578
|
||||
generic/580
|
||||
generic/581
|
||||
generic/582
|
||||
generic/583
|
||||
generic/584
|
||||
generic/586
|
||||
generic/587
|
||||
generic/588
|
||||
generic/592
|
||||
generic/593
|
||||
generic/594
|
||||
generic/595
|
||||
generic/596
|
||||
generic/597
|
||||
generic/598
|
||||
generic/599
|
||||
generic/600
|
||||
generic/601
|
||||
generic/602
|
||||
generic/603
|
||||
generic/605
|
||||
generic/606
|
||||
generic/607
|
||||
generic/608
|
||||
generic/609
|
||||
generic/610
|
||||
generic/612
|
||||
generic/613
|
||||
generic/621
|
||||
generic/623
|
||||
generic/624
|
||||
generic/625
|
||||
generic/626
|
||||
generic/628
|
||||
generic/629
|
||||
generic/630
|
||||
generic/635
|
||||
generic/644
|
||||
generic/645
|
||||
generic/646
|
||||
generic/647
|
||||
generic/651
|
||||
generic/652
|
||||
generic/653
|
||||
generic/654
|
||||
generic/655
|
||||
generic/657
|
||||
generic/658
|
||||
generic/659
|
||||
generic/660
|
||||
generic/661
|
||||
generic/662
|
||||
generic/663
|
||||
generic/664
|
||||
generic/665
|
||||
generic/666
|
||||
generic/667
|
||||
generic/668
|
||||
generic/669
|
||||
generic/673
|
||||
generic/674
|
||||
generic/675
|
||||
generic/677
|
||||
generic/678
|
||||
generic/679
|
||||
generic/680
|
||||
generic/681
|
||||
generic/682
|
||||
generic/683
|
||||
generic/684
|
||||
generic/685
|
||||
generic/686
|
||||
generic/687
|
||||
generic/688
|
||||
generic/689
|
||||
shared/002
|
||||
shared/032
|
||||
Passed all 509 tests
|
||||
@@ -1,9 +1,11 @@
|
||||
generic/003 # missing atime update in buffered read
|
||||
generic/075 # file content mismatch failures (fds, etc)
|
||||
generic/094 # preallocation generates an unwritten block where a hole is expected
|
||||
generic/103 # enospc causes trans commit failures
|
||||
generic/108 # mount fails on failing device?
|
||||
generic/112 # file content mismatch failures (fds, etc)
|
||||
generic/213 # enospc causes trans commit failures
|
||||
generic/225 # preallocation generates an unwritten block where a hole is expected
|
||||
generic/318 # can't support user namespaces until v5.11
|
||||
generic/321 # requires selinux enabled for '+' in ls?
|
||||
generic/338 # BUG_ON update inode error handling
|
||||
@@ -37,6 +39,7 @@ generic/565 # xfs_io copy_range missing in el7
|
||||
generic/568 # falloc not resulting in block count increase
|
||||
generic/569 # swap
|
||||
generic/570 # swap
|
||||
generic/591 # do we care if splice() and O_DIRECT works on pipes?
|
||||
generic/620 # dm-hugedisk
|
||||
generic/633 # id-mapped mounts missing in el7
|
||||
generic/636 # swap
|
||||
|
||||
@@ -231,6 +231,11 @@ t_filter_dmesg()
|
||||
# lockdep or kasan warnings can cause this
|
||||
re="$re|Disabling lock debugging due to kernel taint"
|
||||
|
||||
# mixing mmap and direct I/O can generate a warning
|
||||
re="$re|Page cache invalidation failure on direct I/O. Possible data corruption due to collision with buffered I/O!"
|
||||
re="$re|File: /mnt/test.* PID:.* Comm: dd"
|
||||
re="$re|dio_warn_stale_pagecache*"
|
||||
|
||||
egrep -v "($re)" | \
|
||||
ignore_harmless_unwind_kasan_stack_oob | \
|
||||
ignore_harmless_xfs_lockdep_warning
|
||||
|
||||
@@ -10,14 +10,12 @@ thread 4 complete
|
||||
extents: 1
|
||||
1
|
||||
00000200: ea ea ea ea ea ea ea ea ea ea ea ea ea ea ea ea ................
|
||||
0
|
||||
0: offset: 0 length: 2 flags: ..L
|
||||
extents: 1
|
||||
== mmap write to an offline extent
|
||||
0: offset: 0 length: 2 flags: O.L
|
||||
extents: 1
|
||||
1
|
||||
0
|
||||
0: offset: 0 length: 2 flags: ..L
|
||||
extents: 1
|
||||
00000000 ea ea ea ea ea ea ea ea ea ea ea ea ea ea ea ea |................|
|
||||
|
||||
+84
-78
@@ -90,7 +90,7 @@ done
|
||||
|
||||
# set some T_ defaults
|
||||
T_TRACE_DUMP="0"
|
||||
T_TRACE_PRINTK="0"
|
||||
T_TRACE_PRINTK=""
|
||||
T_PORT_START="19700"
|
||||
T_LOOP_ITER="1"
|
||||
|
||||
@@ -137,6 +137,9 @@ while true; do
|
||||
test -n "$2" || die "-l must have a nr iterations argument"
|
||||
test "$2" -eq "$2" 2>/dev/null || die "-l <nr> argument must be an integer"
|
||||
T_LOOP_ITER="$2"
|
||||
|
||||
# when looping, break after first failure
|
||||
T_ABORT="1"
|
||||
shift
|
||||
;;
|
||||
-M)
|
||||
@@ -399,31 +402,44 @@ if [ -n "$T_INSMOD" ]; then
|
||||
cmd insmod "$T_MODULE"
|
||||
fi
|
||||
|
||||
if [ -n "$T_TRACE_MULT" ]; then
|
||||
# orig_trace_size=$(cat /sys/kernel/debug/tracing/buffer_size_kb)
|
||||
orig_trace_size=1408
|
||||
mult_trace_size=$((orig_trace_size * T_TRACE_MULT))
|
||||
msg "increasing trace buffer size from $orig_trace_size KiB to $mult_trace_size KiB"
|
||||
echo $mult_trace_size > /sys/kernel/debug/tracing/buffer_size_kb
|
||||
fi
|
||||
start_tracing() {
|
||||
if [ -n "$T_TRACE_MULT" ]; then
|
||||
orig_trace_size=1408
|
||||
mult_trace_size=$((orig_trace_size * T_TRACE_MULT))
|
||||
msg "increasing trace buffer size from $orig_trace_size KiB to $mult_trace_size KiB"
|
||||
echo $mult_trace_size > /sys/kernel/debug/tracing/buffer_size_kb
|
||||
fi
|
||||
|
||||
nr_globs=${#T_TRACE_GLOB[@]}
|
||||
if [ $nr_globs -gt 0 ]; then
|
||||
echo 0 > /sys/kernel/debug/tracing/events/scoutfs/enable
|
||||
nr_globs=${#T_TRACE_GLOB[@]}
|
||||
if [ $nr_globs -gt 0 ]; then
|
||||
echo 0 > /sys/kernel/debug/tracing/events/scoutfs/enable
|
||||
|
||||
for g in "${T_TRACE_GLOB[@]}"; do
|
||||
for e in /sys/kernel/debug/tracing/events/scoutfs/$g/enable; do
|
||||
if test -w "$e"; then
|
||||
echo 1 > "$e"
|
||||
else
|
||||
die "-t glob '$g' matched no scoutfs events"
|
||||
fi
|
||||
for g in "${T_TRACE_GLOB[@]}"; do
|
||||
for e in /sys/kernel/debug/tracing/events/scoutfs/$g/enable; do
|
||||
if test -w "$e"; then
|
||||
echo 1 > "$e"
|
||||
else
|
||||
die "-t glob '$g' matched no scoutfs events"
|
||||
fi
|
||||
done
|
||||
done
|
||||
done
|
||||
|
||||
nr_events=$(cat /sys/kernel/debug/tracing/set_event | wc -l)
|
||||
msg "enabled $nr_events trace events from $nr_globs -t globs"
|
||||
fi
|
||||
nr_events=$(cat /sys/kernel/debug/tracing/set_event | wc -l)
|
||||
msg "enabled $nr_events trace events from $nr_globs -t globs"
|
||||
fi
|
||||
}
|
||||
|
||||
stop_tracing() {
|
||||
if [ -n "$T_TRACE_GLOB" -o -n "$T_TRACE_PRINTK" ]; then
|
||||
msg "saving traces and disabling tracing"
|
||||
echo 0 > /sys/kernel/debug/tracing/events/scoutfs/enable
|
||||
echo 0 > /sys/kernel/debug/tracing/options/trace_printk
|
||||
cat /sys/kernel/debug/tracing/trace | gzip > "$T_RESULTS/traces.gz"
|
||||
if [ -n "$orig_trace_size" ]; then
|
||||
echo $orig_trace_size > /sys/kernel/debug/tracing/buffer_size_kb
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
if [ -n "$T_TRACE_PRINTK" ]; then
|
||||
echo "$T_TRACE_PRINTK" > /sys/kernel/debug/tracing/options/trace_printk
|
||||
@@ -603,24 +619,26 @@ passed=0
|
||||
skipped=0
|
||||
failed=0
|
||||
skipped_permitted=0
|
||||
for t in $tests; do
|
||||
# tests has basenames from sequence, get path and name
|
||||
t="tests/$t"
|
||||
test_name=$(basename "$t" | sed -e 's/.sh$//')
|
||||
for iter in $(seq 1 $T_LOOP_ITER); do
|
||||
|
||||
# get stats from previous pass
|
||||
last="$T_RESULTS/last-passed-test-stats"
|
||||
stats=$(grep -s "^$test_name " "$last" | cut -d " " -f 2-)
|
||||
test -n "$stats" && stats="last: $stats"
|
||||
printf " %-30s $stats" "$test_name"
|
||||
start_tracing
|
||||
|
||||
# mark in dmesg as to what test we are running
|
||||
echo "run scoutfs test $test_name" > /dev/kmsg
|
||||
for t in $tests; do
|
||||
# tests has basenames from sequence, get path and name
|
||||
t="tests/$t"
|
||||
test_name=$(basename "$t" | sed -e 's/.sh$//')
|
||||
|
||||
# let the test get at its extra files
|
||||
T_EXTRA="$T_TESTS/extra/$test_name"
|
||||
# get stats from previous pass
|
||||
last="$T_RESULTS/last-passed-test-stats"
|
||||
stats=$(grep -s "^$test_name " "$last" | cut -d " " -f 2-)
|
||||
test -n "$stats" && stats="last: $stats"
|
||||
printf " %-30s $stats" "$test_name"
|
||||
|
||||
for iter in $(seq 1 $T_LOOP_ITER); do
|
||||
# mark in dmesg as to what test we are running
|
||||
echo "run scoutfs test $test_name" > /dev/kmsg
|
||||
|
||||
# let the test get at its extra files
|
||||
T_EXTRA="$T_TESTS/extra/$test_name"
|
||||
|
||||
# create a temporary dir and file path for the test
|
||||
T_TMPDIR="$T_RESULTS/tmp/$test_name"
|
||||
@@ -710,55 +728,43 @@ for t in $tests; do
|
||||
sts=$T_FAIL_STATUS
|
||||
fi
|
||||
|
||||
# stop looping if we didn't pass
|
||||
if [ "$sts" != "$T_PASS_STATUS" ]; then
|
||||
break;
|
||||
# show and record the result of the test
|
||||
if [ "$sts" == "$T_PASS_STATUS" ]; then
|
||||
echo " passed: $stats"
|
||||
((passed++))
|
||||
# save stats for passed test
|
||||
grep -s -v "^$test_name " "$last" > "$last.tmp"
|
||||
echo "$test_name $stats" >> "$last.tmp"
|
||||
mv -f "$last.tmp" "$last"
|
||||
elif [ "$sts" == "$T_SKIP_PERMITTED_STATUS" ]; then
|
||||
echo " [ skipped (permitted): $message ]"
|
||||
echo "$test_name skipped (permitted) $message " >> "$T_RESULTS/skip.log"
|
||||
((skipped_permitted++))
|
||||
elif [ "$sts" == "$T_SKIP_STATUS" ]; then
|
||||
echo " [ skipped: $message ]"
|
||||
echo "$test_name $message" >> "$T_RESULTS/skip.log"
|
||||
((skipped++))
|
||||
elif [ "$sts" == "$T_FAIL_STATUS" ]; then
|
||||
echo " [ failed: $message ]"
|
||||
echo "$test_name $message" >> "$T_RESULTS/fail.log"
|
||||
((failed++))
|
||||
|
||||
if [ -n "$T_ABORT" ]; then
|
||||
stop_tracing
|
||||
die "aborting after first failure"
|
||||
fi
|
||||
fi
|
||||
|
||||
# record results for TAP format output
|
||||
t_tap_progress $test_name $sts
|
||||
((testcount++))
|
||||
done
|
||||
|
||||
# show and record the result of the test
|
||||
if [ "$sts" == "$T_PASS_STATUS" ]; then
|
||||
echo " passed: $stats"
|
||||
((passed++))
|
||||
# save stats for passed test
|
||||
grep -s -v "^$test_name " "$last" > "$last.tmp"
|
||||
echo "$test_name $stats" >> "$last.tmp"
|
||||
mv -f "$last.tmp" "$last"
|
||||
elif [ "$sts" == "$T_SKIP_PERMITTED_STATUS" ]; then
|
||||
echo " [ skipped (permitted): $message ]"
|
||||
echo "$test_name skipped (permitted) $message " >> "$T_RESULTS/skip.log"
|
||||
((skipped_permitted++))
|
||||
elif [ "$sts" == "$T_SKIP_STATUS" ]; then
|
||||
echo " [ skipped: $message ]"
|
||||
echo "$test_name $message" >> "$T_RESULTS/skip.log"
|
||||
((skipped++))
|
||||
elif [ "$sts" == "$T_FAIL_STATUS" ]; then
|
||||
echo " [ failed: $message ]"
|
||||
echo "$test_name $message" >> "$T_RESULTS/fail.log"
|
||||
((failed++))
|
||||
|
||||
test -n "$T_ABORT" && die "aborting after first failure"
|
||||
fi
|
||||
|
||||
# record results for TAP format output
|
||||
t_tap_progress $test_name $sts
|
||||
((testcount++))
|
||||
|
||||
stop_tracing
|
||||
done
|
||||
|
||||
msg "all tests run: $passed passed, $skipped skipped, $skipped_permitted skipped (permitted), $failed failed"
|
||||
|
||||
|
||||
if [ -n "$T_TRACE_GLOB" -o -n "$T_TRACE_PRINTK" ]; then
|
||||
msg "saving traces and disabling tracing"
|
||||
echo 0 > /sys/kernel/debug/tracing/events/scoutfs/enable
|
||||
echo 0 > /sys/kernel/debug/tracing/options/trace_printk
|
||||
cat /sys/kernel/debug/tracing/trace > "$T_RESULTS/traces"
|
||||
if [ -n "$orig_trace_size" ]; then
|
||||
echo $orig_trace_size > /sys/kernel/debug/tracing/buffer_size_kb
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$skipped" == 0 -a "$failed" == 0 ]; then
|
||||
msg "all tests passed"
|
||||
unmount_all
|
||||
|
||||
@@ -80,7 +80,7 @@ static void *run_test_func(void *ptr)
|
||||
for (read = 0; read < size;) {
|
||||
ret = pread(fd, buf, size - read, read);
|
||||
if (ret < 0) {
|
||||
perror("pwrite");
|
||||
perror("pread");
|
||||
exit(-1);
|
||||
}
|
||||
read += ret;
|
||||
|
||||
+2
-6
@@ -27,9 +27,7 @@ sleep 1
|
||||
jobs | wc -l
|
||||
scoutfs stage "${F}-stage" "$F" -V "$vers" -o 0 -l 8192
|
||||
# xfs_io thread <here> will output 16 bytes of read data
|
||||
sleep 1
|
||||
# should be 0 - no more waiting jobs, xfs_io should have exited
|
||||
jobs | wc -l
|
||||
wait
|
||||
scoutfs get-fiemap -L "$F"
|
||||
|
||||
echo "== mmap write to an offline extent"
|
||||
@@ -43,9 +41,7 @@ sleep 1
|
||||
jobs | wc -l
|
||||
scoutfs stage "${F}-stage" "$F" -V "$vers" -o 0 -l 8192
|
||||
# no output here from write
|
||||
sleep 1
|
||||
# should be 0 - no more waiting jobs, xfs_io should have exited
|
||||
jobs | wc -l
|
||||
wait
|
||||
scoutfs get-fiemap -L "$F"
|
||||
# read back contents to assure write changed the file
|
||||
dd status=none if="$F" bs=1 count=48 skip=512 | hexdump -C
|
||||
|
||||
@@ -116,7 +116,14 @@ awk '
|
||||
grep -E "^(Ran|Not run|Failures):" "$T_TMPDIR/results" | fmt -w 1 > "$T_TMPDIR/results.fmt"
|
||||
grep -E "^(Passed|Failed).*tests$" "$T_TMPDIR/results" >> "$T_TMPDIR/results.fmt"
|
||||
|
||||
diff -u "$T_EXTRA/expected-results" "$T_TMPDIR/results.fmt" > "$T_TMPDIR/results.diff"
|
||||
if grep -q copy_page_to_iter_nofault /lib/modules/$(uname -r)/build/include/linux/uio.h
|
||||
then
|
||||
diff -u "$T_EXTRA/expected-results" "$T_TMPDIR/results.fmt" > "$T_TMPDIR/results.diff"
|
||||
else
|
||||
# no direct I/O
|
||||
diff -u "$T_EXTRA/expected-results.nodio" "$T_TMPDIR/results.fmt" > "$T_TMPDIR/results.diff"
|
||||
fi
|
||||
|
||||
if [ -s "$T_TMPDIR/results.diff" ]; then
|
||||
echo "tests that were skipped/run differed from expected:"
|
||||
cat "$T_TMPDIR/results.diff"
|
||||
|
||||
Reference in New Issue
Block a user