bcachefs: Errcodes can now subtype standard error codes

The next patch is going to be adding private error codes for all the
places we return -ENOSPC.

Additionally, this patch updates return paths at all module boundaries
to call bch2_err_class(), to return the standard error code.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
Kent Overstreet 2022-09-18 15:43:50 -04:00
parent 57ce827442
commit 5c1ef830f6
7 changed files with 164 additions and 99 deletions

View File

@ -15,7 +15,7 @@ static const char * const bch2_errcode_strs[] = {
#define BCH_ERR_0 0
static unsigned bch2_errcode_parents[] = {
#define x(class, err) [BCH_ERR_##err - BCH_ERR_START] = BCH_ERR_##class,
#define x(class, err) [BCH_ERR_##err - BCH_ERR_START] = class,
BCH_ERRCODES()
#undef x
};
@ -49,3 +49,14 @@ bool __bch2_err_matches(int err, int class)
return err == class;
}
int __bch2_err_class(int err)
{
err = -err;
BUG_ON((unsigned) err >= BCH_ERR_MAX);
while (err >= BCH_ERR_START && bch2_errcode_parents[err - BCH_ERR_START])
err = bch2_errcode_parents[err - BCH_ERR_START];
return -err;
}

View File

@ -3,51 +3,51 @@
#define _BCACHEFS_ERRCODE_H
#define BCH_ERRCODES() \
x(0, open_buckets_empty) \
x(0, freelist_empty) \
x(freelist_empty, no_buckets_found) \
x(0, insufficient_devices) \
x(0, transaction_restart) \
x(transaction_restart, transaction_restart_fault_inject) \
x(transaction_restart, transaction_restart_relock) \
x(transaction_restart, transaction_restart_relock_path) \
x(transaction_restart, transaction_restart_relock_path_intent) \
x(transaction_restart, transaction_restart_relock_after_fill) \
x(transaction_restart, transaction_restart_too_many_iters) \
x(transaction_restart, transaction_restart_lock_node_reused) \
x(transaction_restart, transaction_restart_fill_relock) \
x(transaction_restart, transaction_restart_fill_mem_alloc_fail)\
x(transaction_restart, transaction_restart_mem_realloced) \
x(transaction_restart, transaction_restart_in_traverse_all) \
x(transaction_restart, transaction_restart_would_deadlock) \
x(transaction_restart, transaction_restart_would_deadlock_write)\
x(transaction_restart, transaction_restart_upgrade) \
x(transaction_restart, transaction_restart_key_cache_upgrade) \
x(transaction_restart, transaction_restart_key_cache_fill) \
x(transaction_restart, transaction_restart_key_cache_raced) \
x(transaction_restart, transaction_restart_key_cache_realloced)\
x(transaction_restart, transaction_restart_journal_preres_get) \
x(transaction_restart, transaction_restart_nested) \
x(0, no_btree_node) \
x(no_btree_node, no_btree_node_relock) \
x(no_btree_node, no_btree_node_upgrade) \
x(no_btree_node, no_btree_node_drop) \
x(no_btree_node, no_btree_node_lock_root) \
x(no_btree_node, no_btree_node_up) \
x(no_btree_node, no_btree_node_down) \
x(no_btree_node, no_btree_node_init) \
x(no_btree_node, no_btree_node_cached) \
x(0, lock_fail_node_reused) \
x(0, lock_fail_root_changed) \
x(0, journal_reclaim_would_deadlock) \
x(0, fsck) \
x(fsck, fsck_fix) \
x(fsck, fsck_ignore) \
x(fsck, fsck_errors_not_fixed) \
x(fsck, fsck_repair_unimplemented) \
x(fsck, fsck_repair_impossible) \
x(0, need_snapshot_cleanup) \
x(0, need_topology_repair)
x(0, open_buckets_empty) \
x(0, freelist_empty) \
x(BCH_ERR_freelist_empty, no_buckets_found) \
x(0, insufficient_devices) \
x(0, transaction_restart) \
x(BCH_ERR_transaction_restart, transaction_restart_fault_inject) \
x(BCH_ERR_transaction_restart, transaction_restart_relock) \
x(BCH_ERR_transaction_restart, transaction_restart_relock_path) \
x(BCH_ERR_transaction_restart, transaction_restart_relock_path_intent) \
x(BCH_ERR_transaction_restart, transaction_restart_relock_after_fill) \
x(BCH_ERR_transaction_restart, transaction_restart_too_many_iters) \
x(BCH_ERR_transaction_restart, transaction_restart_lock_node_reused) \
x(BCH_ERR_transaction_restart, transaction_restart_fill_relock) \
x(BCH_ERR_transaction_restart, transaction_restart_fill_mem_alloc_fail)\
x(BCH_ERR_transaction_restart, transaction_restart_mem_realloced) \
x(BCH_ERR_transaction_restart, transaction_restart_in_traverse_all) \
x(BCH_ERR_transaction_restart, transaction_restart_would_deadlock) \
x(BCH_ERR_transaction_restart, transaction_restart_would_deadlock_write)\
x(BCH_ERR_transaction_restart, transaction_restart_upgrade) \
x(BCH_ERR_transaction_restart, transaction_restart_key_cache_upgrade) \
x(BCH_ERR_transaction_restart, transaction_restart_key_cache_fill) \
x(BCH_ERR_transaction_restart, transaction_restart_key_cache_raced) \
x(BCH_ERR_transaction_restart, transaction_restart_key_cache_realloced)\
x(BCH_ERR_transaction_restart, transaction_restart_journal_preres_get) \
x(BCH_ERR_transaction_restart, transaction_restart_nested) \
x(0, no_btree_node) \
x(BCH_ERR_no_btree_node, no_btree_node_relock) \
x(BCH_ERR_no_btree_node, no_btree_node_upgrade) \
x(BCH_ERR_no_btree_node, no_btree_node_drop) \
x(BCH_ERR_no_btree_node, no_btree_node_lock_root) \
x(BCH_ERR_no_btree_node, no_btree_node_up) \
x(BCH_ERR_no_btree_node, no_btree_node_down) \
x(BCH_ERR_no_btree_node, no_btree_node_init) \
x(BCH_ERR_no_btree_node, no_btree_node_cached) \
x(0, lock_fail_node_reused) \
x(0, lock_fail_root_changed) \
x(0, journal_reclaim_would_deadlock) \
x(0, fsck) \
x(BCH_ERR_fsck, fsck_fix) \
x(BCH_ERR_fsck, fsck_ignore) \
x(BCH_ERR_fsck, fsck_errors_not_fixed) \
x(BCH_ERR_fsck, fsck_repair_unimplemented) \
x(BCH_ERR_fsck, fsck_repair_impossible) \
x(0, need_snapshot_cleanup) \
x(0, need_topology_repair)
enum bch_errcode {
BCH_ERR_START = 2048,
@ -71,4 +71,11 @@ static inline bool _bch2_err_matches(int err, int class)
_bch2_err_matches(_err, _class); \
})
int __bch2_err_class(int);
static inline long bch2_err_class(long err)
{
return err < 0 ? __bch2_err_class(err) : err;
}
#endif /* _BCACHFES_ERRCODE_H */

View File

@ -1186,7 +1186,7 @@ int bch2_read_folio(struct file *file, struct folio *folio)
ret = bch2_read_single_page(page, page->mapping);
folio_unlock(folio);
return ret;
return bch2_err_class(ret);
}
/* writepages: */
@ -1465,7 +1465,7 @@ int bch2_writepages(struct address_space *mapping, struct writeback_control *wbc
if (w.io)
bch2_writepage_do_io(&w);
blk_finish_plug(&plug);
return ret;
return bch2_err_class(ret);
}
/* buffered writes: */
@ -1550,7 +1550,7 @@ err_unlock:
bch2_pagecache_add_put(&inode->ei_pagecache_lock);
kfree(res);
*fsdata = NULL;
return ret;
return bch2_err_class(ret);
}
int bch2_write_end(struct file *file, struct address_space *mapping,
@ -1975,7 +1975,7 @@ ssize_t bch2_read_iter(struct kiocb *iocb, struct iov_iter *iter)
iocb->ki_pos,
iocb->ki_pos + count - 1);
if (ret < 0)
return ret;
goto out;
}
file_accessed(file);
@ -1991,8 +1991,8 @@ ssize_t bch2_read_iter(struct kiocb *iocb, struct iov_iter *iter)
ret = generic_file_read_iter(iocb, iter);
bch2_pagecache_add_put(&inode->ei_pagecache_lock);
}
return ret;
out:
return bch2_err_class(ret);
}
/* O_DIRECT writes */
@ -2224,6 +2224,9 @@ err:
/* inode->i_dio_count is our ref on inode and thus bch_fs */
inode_dio_end(&inode->v);
if (ret < 0)
ret = bch2_err_class(ret);
if (!sync) {
req->ki_complete(req, ret);
ret = -EIOCBQUEUED;
@ -2332,8 +2335,10 @@ ssize_t bch2_write_iter(struct kiocb *iocb, struct iov_iter *from)
struct bch_inode_info *inode = file_bch_inode(file);
ssize_t ret;
if (iocb->ki_flags & IOCB_DIRECT)
return bch2_direct_write(iocb, from);
if (iocb->ki_flags & IOCB_DIRECT) {
ret = bch2_direct_write(iocb, from);
goto out;
}
inode_lock(&inode->v);
@ -2357,8 +2362,8 @@ unlock:
if (ret > 0)
ret = generic_write_sync(iocb, ret);
return ret;
out:
return bch2_err_class(ret);
}
/* fsync: */
@ -2392,7 +2397,7 @@ int bch2_fsync(struct file *file, loff_t start, loff_t end, int datasync)
ret2 = sync_inode_metadata(&inode->v, 1);
ret3 = bch2_flush_inode(c, inode_inum(inode));
return ret ?: ret2 ?: ret3;
return bch2_err_class(ret ?: ret2 ?: ret3);
}
/* truncate: */
@ -2698,7 +2703,7 @@ int bch2_truncate(struct mnt_idmap *idmap,
ret = bch2_setattr_nonsize(idmap, inode, iattr);
err:
bch2_pagecache_block_put(&inode->ei_pagecache_lock);
return ret;
return bch2_err_class(ret);
}
/* fallocate: */
@ -3128,7 +3133,7 @@ long bch2_fallocate_dispatch(struct file *file, int mode,
inode_unlock(&inode->v);
percpu_ref_put(&c->writes);
return ret;
return bch2_err_class(ret);
}
loff_t bch2_remap_file_range(struct file *file_src, loff_t pos_src,
@ -3206,7 +3211,7 @@ loff_t bch2_remap_file_range(struct file *file_src, loff_t pos_src,
err:
bch2_unlock_inodes(INODE_LOCK|INODE_PAGECACHE_BLOCK, src, dst);
return ret;
return bch2_err_class(ret);
}
/* fseek: */
@ -3431,18 +3436,26 @@ err:
loff_t bch2_llseek(struct file *file, loff_t offset, int whence)
{
loff_t ret;
switch (whence) {
case SEEK_SET:
case SEEK_CUR:
case SEEK_END:
return generic_file_llseek(file, offset, whence);
ret = generic_file_llseek(file, offset, whence);
break;
case SEEK_DATA:
return bch2_seek_data(file, offset);
ret = bch2_seek_data(file, offset);
break;
case SEEK_HOLE:
return bch2_seek_hole(file, offset);
ret = bch2_seek_hole(file, offset);
break;
default:
ret = -EINVAL;
break;
}
return -EINVAL;
return bch2_err_class(ret);
}
void bch2_fs_fsio_exit(struct bch_fs *c)

View File

@ -455,51 +455,67 @@ long bch2_fs_file_ioctl(struct file *file, unsigned cmd, unsigned long arg)
{
struct bch_inode_info *inode = file_bch_inode(file);
struct bch_fs *c = inode->v.i_sb->s_fs_info;
long ret;
switch (cmd) {
case FS_IOC_GETFLAGS:
return bch2_ioc_getflags(inode, (int __user *) arg);
ret = bch2_ioc_getflags(inode, (int __user *) arg);
break;
case FS_IOC_SETFLAGS:
return bch2_ioc_setflags(c, file, inode, (int __user *) arg);
ret = bch2_ioc_setflags(c, file, inode, (int __user *) arg);
break;
case FS_IOC_FSGETXATTR:
return bch2_ioc_fsgetxattr(inode, (void __user *) arg);
ret = bch2_ioc_fsgetxattr(inode, (void __user *) arg);
break;
case FS_IOC_FSSETXATTR:
return bch2_ioc_fssetxattr(c, file, inode,
(void __user *) arg);
ret = bch2_ioc_fssetxattr(c, file, inode,
(void __user *) arg);
break;
case BCHFS_IOC_REINHERIT_ATTRS:
return bch2_ioc_reinherit_attrs(c, file, inode,
(void __user *) arg);
ret = bch2_ioc_reinherit_attrs(c, file, inode,
(void __user *) arg);
break;
case FS_IOC_GETVERSION:
return -ENOTTY;
ret = -ENOTTY;
break;
case FS_IOC_SETVERSION:
return -ENOTTY;
ret = -ENOTTY;
break;
case FS_IOC_GOINGDOWN:
return bch2_ioc_goingdown(c, (u32 __user *) arg);
ret = bch2_ioc_goingdown(c, (u32 __user *) arg);
break;
case BCH_IOCTL_SUBVOLUME_CREATE: {
struct bch_ioctl_subvolume i;
if (copy_from_user(&i, (void __user *) arg, sizeof(i)))
return -EFAULT;
return bch2_ioctl_subvolume_create(c, file, i);
ret = copy_from_user(&i, (void __user *) arg, sizeof(i))
? -EFAULT
: bch2_ioctl_subvolume_create(c, file, i);
break;
}
case BCH_IOCTL_SUBVOLUME_DESTROY: {
struct bch_ioctl_subvolume i;
if (copy_from_user(&i, (void __user *) arg, sizeof(i)))
return -EFAULT;
return bch2_ioctl_subvolume_destroy(c, file, i);
ret = copy_from_user(&i, (void __user *) arg, sizeof(i))
? -EFAULT
: bch2_ioctl_subvolume_destroy(c, file, i);
break;
}
default:
return bch2_fs_ioctl(c, cmd, (void __user *) arg);
ret = bch2_fs_ioctl(c, cmd, (void __user *) arg);
break;
}
return bch2_err_class(ret);
}
#ifdef CONFIG_COMPAT

View File

@ -419,7 +419,7 @@ static int bch2_mknod(struct mnt_idmap *idmap,
(subvol_inum) { 0 }, 0);
if (IS_ERR(inode))
return PTR_ERR(inode);
return bch2_err_class(PTR_ERR(inode));
d_instantiate(dentry, &inode->v);
return 0;
@ -529,7 +529,7 @@ static int bch2_symlink(struct mnt_idmap *idmap,
inode = __bch2_create(idmap, dir, dentry, S_IFLNK|S_IRWXUGO, 0,
(subvol_inum) { 0 }, BCH_CREATE_TMPFILE);
if (unlikely(IS_ERR(inode)))
return PTR_ERR(inode);
return bch2_err_class(PTR_ERR(inode));
inode_lock(&inode->v);
ret = page_symlink(&inode->v, symname, strlen(symname) + 1);
@ -769,7 +769,7 @@ err_trans:
err:
mutex_unlock(&inode->ei_update_lock);
return ret;
return bch2_err_class(ret);
}
static int bch2_getattr(struct mnt_idmap *idmap,
@ -839,7 +839,7 @@ static int bch2_tmpfile(struct mnt_idmap *idmap,
(subvol_inum) { 0 }, BCH_CREATE_TMPFILE);
if (IS_ERR(inode))
return PTR_ERR(inode);
return bch2_err_class(PTR_ERR(inode));
d_mark_tmpfile(file, &inode->v);
d_instantiate(file->f_path.dentry, &inode->v);
@ -1454,7 +1454,7 @@ static int bch2_vfs_write_inode(struct inode *vinode,
ATTR_ATIME|ATTR_MTIME|ATTR_CTIME);
mutex_unlock(&inode->ei_update_lock);
return ret;
return bch2_err_class(ret);
}
static void bch2_evict_inode(struct inode *vinode)
@ -1558,6 +1558,7 @@ static int bch2_statfs(struct dentry *dentry, struct kstatfs *buf)
static int bch2_sync_fs(struct super_block *sb, int wait)
{
struct bch_fs *c = sb->s_fs_info;
int ret;
if (c->opts.journal_flush_disabled)
return 0;
@ -1567,7 +1568,8 @@ static int bch2_sync_fs(struct super_block *sb, int wait)
return 0;
}
return bch2_journal_flush(&c->journal);
ret = bch2_journal_flush(&c->journal);
return bch2_err_class(ret);
}
static struct bch_fs *bch2_path_to_fs(const char *path)
@ -1623,7 +1625,7 @@ static int bch2_remount(struct super_block *sb, int *flags, char *data)
ret = bch2_parse_mount_opts(c, &opts, data);
if (ret)
return ret;
goto err;
if (opts.read_only != c->opts.read_only) {
down_write(&c->state_lock);
@ -1637,7 +1639,8 @@ static int bch2_remount(struct super_block *sb, int *flags, char *data)
if (ret) {
bch_err(c, "error going rw: %i", ret);
up_write(&c->state_lock);
return -EINVAL;
ret = -EINVAL;
goto err;
}
sb->s_flags &= ~SB_RDONLY;
@ -1650,8 +1653,8 @@ static int bch2_remount(struct super_block *sb, int *flags, char *data)
if (opts.errors >= 0)
c->opts.errors = opts.errors;
return ret;
err:
return bch2_err_class(ret);
}
static int bch2_show_devname(struct seq_file *seq, struct dentry *root)

View File

@ -40,14 +40,14 @@
#include "util.h"
#define SYSFS_OPS(type) \
const struct sysfs_ops type ## _sysfs_ops = { \
const struct sysfs_ops type ## _sysfs_ops = { \
.show = type ## _show, \
.store = type ## _store \
}
#define SHOW(fn) \
static ssize_t fn ## _to_text(struct printbuf *, \
struct kobject *, struct attribute *);\
struct kobject *, struct attribute *); \
\
static ssize_t fn ## _show(struct kobject *kobj, struct attribute *attr,\
char *buf) \
@ -66,15 +66,24 @@ static ssize_t fn ## _show(struct kobject *kobj, struct attribute *attr,\
memcpy(buf, out.buf, ret); \
} \
printbuf_exit(&out); \
return ret; \
return bch2_err_class(ret); \
} \
\
static ssize_t fn ## _to_text(struct printbuf *out, struct kobject *kobj,\
struct attribute *attr)
#define STORE(fn) \
static ssize_t fn ## _store_inner(struct kobject *, struct attribute *,\
const char *, size_t); \
\
static ssize_t fn ## _store(struct kobject *kobj, struct attribute *attr,\
const char *buf, size_t size) \
{ \
return bch2_err_class(fn##_store_inner(kobj, attr, buf, size)); \
} \
\
static ssize_t fn ## _store_inner(struct kobject *kobj, struct attribute *attr,\
const char *buf, size_t size)
#define __sysfs_attribute(_name, _mode) \
static struct attribute sysfs_##_name = \

View File

@ -350,17 +350,19 @@ err:
bch2_trans_exit(&trans);
if (ret)
return ret;
goto out;
ret = bch2_xattr_list_bcachefs(c, &inode->ei_inode, &buf, false);
if (ret)
return ret;
goto out;
ret = bch2_xattr_list_bcachefs(c, &inode->ei_inode, &buf, true);
if (ret)
return ret;
goto out;
return buf.used;
out:
return bch2_err_class(ret);
}
static int bch2_xattr_get_handler(const struct xattr_handler *handler,
@ -369,8 +371,10 @@ static int bch2_xattr_get_handler(const struct xattr_handler *handler,
{
struct bch_inode_info *inode = to_bch_ei(vinode);
struct bch_fs *c = inode->v.i_sb->s_fs_info;
int ret;
return bch2_xattr_get(c, inode, name, buffer, size, handler->flags);
ret = bch2_xattr_get(c, inode, name, buffer, size, handler->flags);
return bch2_err_class(ret);
}
static int bch2_xattr_set_handler(const struct xattr_handler *handler,
@ -382,11 +386,13 @@ static int bch2_xattr_set_handler(const struct xattr_handler *handler,
struct bch_inode_info *inode = to_bch_ei(vinode);
struct bch_fs *c = inode->v.i_sb->s_fs_info;
struct bch_hash_info hash = bch2_hash_info_init(c, &inode->ei_inode);
int ret;
return bch2_trans_do(c, NULL, NULL, 0,
ret = bch2_trans_do(c, NULL, NULL, 0,
bch2_xattr_set(&trans, inode_inum(inode), &hash,
name, value, size,
handler->flags, flags));
return bch2_err_class(ret);
}
static const struct xattr_handler bch_xattr_user_handler = {