mirror of
https://github.com/versity/scoutfs.git
synced 2026-01-07 12:35:28 +00:00
scoutfs: add data_wait_err for reporting errors
Add support for reporting errors to data waiters via a new SCOUTFS_IOC_DATA_WAIT_ERR ioctl. This allows waiters to return an error to readers when staging fails. Signed-off-by: Benjamin LaHaise <bcrl@kvack.org> [zab: renamed to data_wait_err, took ino arg] Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
committed by
Zach Brown
parent
d16b18562d
commit
f5863142be
@@ -1923,6 +1923,8 @@ int scoutfs_data_wait(struct inode *inode, struct scoutfs_data_wait *dw)
|
||||
spin_lock(&rt->lock);
|
||||
rb_erase(&dw->node, &rt->root);
|
||||
RB_CLEAR_NODE(&dw->node);
|
||||
if (!ret && dw->err)
|
||||
ret = dw->err;
|
||||
spin_unlock(&rt->lock);
|
||||
|
||||
return ret;
|
||||
@@ -1936,6 +1938,36 @@ void scoutfs_data_wait_changed(struct inode *inode)
|
||||
wake_up(&wq->waitq);
|
||||
}
|
||||
|
||||
long scoutfs_data_wait_err(struct inode *inode, u64 sblock, u64 eblock,
|
||||
u64 op, long err)
|
||||
{
|
||||
struct super_block *sb = inode->i_sb;
|
||||
const u64 ino = scoutfs_ino(inode);
|
||||
DECLARE_DATA_WAIT_ROOT(sb, rt);
|
||||
struct scoutfs_data_wait *dw;
|
||||
long nr = 0;
|
||||
|
||||
if (!err)
|
||||
return 0;
|
||||
|
||||
spin_lock(&rt->lock);
|
||||
|
||||
for (dw = next_data_wait(&rt->root, ino, sblock);
|
||||
dw; dw = dw_next(dw)) {
|
||||
if (dw->ino != ino || dw->iblock > eblock)
|
||||
break;
|
||||
if ((dw->op & op) && !dw->err) {
|
||||
dw->err = err;
|
||||
nr++;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock(&rt->lock);
|
||||
if (nr)
|
||||
scoutfs_data_wait_changed(inode);
|
||||
return nr;
|
||||
}
|
||||
|
||||
int scoutfs_data_waiting(struct super_block *sb, u64 ino, u64 iblock,
|
||||
struct scoutfs_ioctl_data_waiting_entry *dwe,
|
||||
unsigned int nr)
|
||||
|
||||
@@ -28,12 +28,14 @@ struct scoutfs_data_wait {
|
||||
u64 chg;
|
||||
u64 ino;
|
||||
u64 iblock;
|
||||
long err;
|
||||
u8 op;
|
||||
};
|
||||
|
||||
#define DECLARE_DATA_WAIT(nm) \
|
||||
struct scoutfs_data_wait nm = { \
|
||||
.node.__rb_parent_color = (unsigned long)(&nm.node), \
|
||||
.err = 0, \
|
||||
}
|
||||
|
||||
struct scoutfs_traced_extent {
|
||||
@@ -68,6 +70,8 @@ bool scoutfs_data_wait_found(struct scoutfs_data_wait *ow);
|
||||
int scoutfs_data_wait(struct inode *inode,
|
||||
struct scoutfs_data_wait *ow);
|
||||
void scoutfs_data_wait_changed(struct inode *inode);
|
||||
long scoutfs_data_wait_err(struct inode *inode, u64 sblock, u64 eblock, u64 op,
|
||||
long err);
|
||||
int scoutfs_data_waiting(struct super_block *sb, u64 ino, u64 iblock,
|
||||
struct scoutfs_ioctl_data_waiting_entry *dwe,
|
||||
unsigned int nr);
|
||||
|
||||
@@ -348,6 +348,65 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long scoutfs_ioc_data_wait_err(struct file *file, unsigned long arg)
|
||||
{
|
||||
struct super_block *sb = file_inode(file)->i_sb;
|
||||
struct scoutfs_ioctl_data_wait_err args;
|
||||
struct scoutfs_lock *lock = NULL;
|
||||
struct inode *inode = NULL;
|
||||
u64 sblock;
|
||||
u64 eblock;
|
||||
long ret;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
if (copy_from_user(&args, (void __user *)arg, sizeof(args)))
|
||||
return -EFAULT;
|
||||
if (args.count == 0)
|
||||
return 0;
|
||||
if ((args.op & SCOUTFS_IOC_DWO_UNKNOWN) || !IS_ERR_VALUE(args.err))
|
||||
return -EINVAL;
|
||||
if ((args.op & SCOUTFS_IOC_DWO_UNKNOWN) || !IS_ERR_VALUE(args.err))
|
||||
return -EINVAL;
|
||||
|
||||
trace_scoutfs_ioc_data_wait_err(sb, &args);
|
||||
|
||||
sblock = args.offset >> SCOUTFS_BLOCK_SHIFT;
|
||||
eblock = (args.offset + args.count - 1) >> SCOUTFS_BLOCK_SHIFT;
|
||||
|
||||
if (sblock > eblock)
|
||||
return -EINVAL;
|
||||
|
||||
inode = scoutfs_ilookup(sb, args.ino);
|
||||
if (!inode) {
|
||||
ret = -ESTALE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mutex_lock(&inode->i_mutex);
|
||||
|
||||
ret = scoutfs_lock_inode(sb, SCOUTFS_LOCK_READ,
|
||||
SCOUTFS_LKF_REFRESH_INODE, inode, &lock);
|
||||
if (ret)
|
||||
goto unlock;
|
||||
|
||||
if (!S_ISREG(inode->i_mode)) {
|
||||
ret = -EINVAL;
|
||||
} else if (scoutfs_inode_data_version(inode) != args.data_version) {
|
||||
ret = -ESTALE;
|
||||
} else {
|
||||
ret = scoutfs_data_wait_err(inode, sblock, eblock, args.op,
|
||||
args.err);
|
||||
}
|
||||
|
||||
scoutfs_unlock(sb, lock, SCOUTFS_LOCK_READ);
|
||||
unlock:
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
iput(inode);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the archived contents of the file back if the data_version
|
||||
* still matches.
|
||||
@@ -832,6 +891,8 @@ long scoutfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
return scoutfs_ioc_find_xattrs(file, arg);
|
||||
case SCOUTFS_IOC_STATFS_MORE:
|
||||
return scoutfs_ioc_statfs_more(file, arg);
|
||||
case SCOUTFS_IOC_DATA_WAIT_ERR:
|
||||
return scoutfs_ioc_data_wait_err(file, arg);
|
||||
}
|
||||
|
||||
return -ENOTTY;
|
||||
|
||||
@@ -346,5 +346,22 @@ struct scoutfs_ioctl_statfs_more {
|
||||
#define SCOUTFS_IOC_STATFS_MORE _IOR(SCOUTFS_IOCTL_MAGIC, 10, \
|
||||
struct scoutfs_ioctl_statfs_more)
|
||||
|
||||
/*
|
||||
* Cause matching waiters to return an error.
|
||||
*
|
||||
* Find current waiters that match the inode, op, and block range to wake
|
||||
* up and return an error.
|
||||
*/
|
||||
struct scoutfs_ioctl_data_wait_err {
|
||||
__u64 ino;
|
||||
__u64 data_version;
|
||||
__u64 offset;
|
||||
__u64 count;
|
||||
__u64 op;
|
||||
__s64 err;
|
||||
};
|
||||
|
||||
#define SCOUTFS_IOC_DATA_WAIT_ERR _IOR(SCOUTFS_IOCTL_MAGIC, 11, \
|
||||
struct scoutfs_ioctl_data_wait_err)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -556,6 +556,37 @@ TRACE_EVENT(scoutfs_ioc_stage,
|
||||
__entry->offset, __entry->count)
|
||||
);
|
||||
|
||||
TRACE_EVENT(scoutfs_ioc_data_wait_err,
|
||||
TP_PROTO(struct super_block *sb,
|
||||
struct scoutfs_ioctl_data_wait_err *args),
|
||||
|
||||
TP_ARGS(sb, args),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
SCSB_TRACE_FIELDS
|
||||
__field(__u64, ino)
|
||||
__field(__u64, vers)
|
||||
__field(__u64, offset)
|
||||
__field(__u64, count)
|
||||
__field(__u64, op)
|
||||
__field(__s64, err)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
SCSB_TRACE_ASSIGN(sb);
|
||||
__entry->ino = args->ino;
|
||||
__entry->vers = args->data_version;
|
||||
__entry->offset = args->offset;
|
||||
__entry->count = args->count;
|
||||
__entry->op = args->op;
|
||||
__entry->err = args->err;
|
||||
),
|
||||
|
||||
TP_printk(SCSBF" ino %llu vers %llu offset %llu count %llu op %llx err %lld",
|
||||
SCSB_TRACE_ARGS, __entry->ino, __entry->vers,
|
||||
__entry->offset, __entry->count, __entry->op, __entry->err)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(scoutfs_ino_ret_class, scoutfs_ioc_stage_ret,
|
||||
TP_PROTO(struct super_block *sb, u64 ino, int ret),
|
||||
TP_ARGS(sb, ino, ret)
|
||||
|
||||
Reference in New Issue
Block a user