bcachefs: Implement fileattr_(get|set)
inode_operations.fileattr_(get|set) didn't exist when the various flag ioctls where implemented - but they do now, which means we can delete a bunch of ioctl code in favor of standard VFS level wrappers. Closes: https://lore.kernel.org/linux-bcachefs/7ltgrgqgfummyrlvw7hnfhnu42rfiamoq3lpcvrjnlyytldmzp@yazbhusnztqn/ Cc: Petr Vorel <pvorel@suse.cz> Cc: Andrea Cervesato <andrea.cervesato@suse.de> Cc: Dave Chinner <david@fromorbit.com> Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
@@ -21,206 +21,6 @@
|
||||
#define FSOP_GOING_FLAGS_LOGFLUSH 0x1 /* flush log but not data */
|
||||
#define FSOP_GOING_FLAGS_NOLOGFLUSH 0x2 /* don't flush log nor data */
|
||||
|
||||
struct flags_set {
|
||||
unsigned mask;
|
||||
unsigned flags;
|
||||
|
||||
unsigned projid;
|
||||
|
||||
bool set_projinherit;
|
||||
bool projinherit;
|
||||
};
|
||||
|
||||
static int bch2_inode_flags_set(struct btree_trans *trans,
|
||||
struct bch_inode_info *inode,
|
||||
struct bch_inode_unpacked *bi,
|
||||
void *p)
|
||||
{
|
||||
struct bch_fs *c = inode->v.i_sb->s_fs_info;
|
||||
/*
|
||||
* We're relying on btree locking here for exclusion with other ioctl
|
||||
* calls - use the flags in the btree (@bi), not inode->i_flags:
|
||||
*/
|
||||
struct flags_set *s = p;
|
||||
unsigned newflags = s->flags;
|
||||
unsigned oldflags = bi->bi_flags & s->mask;
|
||||
|
||||
if (((newflags ^ oldflags) & (BCH_INODE_append|BCH_INODE_immutable)) &&
|
||||
!capable(CAP_LINUX_IMMUTABLE))
|
||||
return -EPERM;
|
||||
|
||||
if (!S_ISREG(bi->bi_mode) &&
|
||||
!S_ISDIR(bi->bi_mode) &&
|
||||
(newflags & (BCH_INODE_nodump|BCH_INODE_noatime)) != newflags)
|
||||
return -EINVAL;
|
||||
|
||||
if ((newflags ^ oldflags) & BCH_INODE_casefolded) {
|
||||
#ifdef CONFIG_UNICODE
|
||||
int ret = 0;
|
||||
/* Not supported on individual files. */
|
||||
if (!S_ISDIR(bi->bi_mode))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/*
|
||||
* Make sure the dir is empty, as otherwise we'd need to
|
||||
* rehash everything and update the dirent keys.
|
||||
*/
|
||||
ret = bch2_empty_dir_trans(trans, inode_inum(inode));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = bch2_request_incompat_feature(c, bcachefs_metadata_version_casefolding);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
bch2_check_set_feature(c, BCH_FEATURE_casefolding);
|
||||
#else
|
||||
printk(KERN_ERR "Cannot use casefolding on a kernel without CONFIG_UNICODE\n");
|
||||
return -EOPNOTSUPP;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (s->set_projinherit) {
|
||||
bi->bi_fields_set &= ~(1 << Inode_opt_project);
|
||||
bi->bi_fields_set |= ((int) s->projinherit << Inode_opt_project);
|
||||
}
|
||||
|
||||
bi->bi_flags &= ~s->mask;
|
||||
bi->bi_flags |= newflags;
|
||||
|
||||
bi->bi_ctime = timespec_to_bch2_time(c, current_time(&inode->v));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bch2_ioc_getflags(struct bch_inode_info *inode, int __user *arg)
|
||||
{
|
||||
unsigned flags = map_flags(bch_flags_to_uflags, inode->ei_inode.bi_flags);
|
||||
|
||||
return put_user(flags, arg);
|
||||
}
|
||||
|
||||
static int bch2_ioc_setflags(struct bch_fs *c,
|
||||
struct file *file,
|
||||
struct bch_inode_info *inode,
|
||||
void __user *arg)
|
||||
{
|
||||
struct flags_set s = { .mask = map_defined(bch_flags_to_uflags) };
|
||||
unsigned uflags;
|
||||
int ret;
|
||||
|
||||
if (get_user(uflags, (int __user *) arg))
|
||||
return -EFAULT;
|
||||
|
||||
s.flags = map_flags_rev(bch_flags_to_uflags, uflags);
|
||||
if (uflags)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ret = mnt_want_write_file(file);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
inode_lock(&inode->v);
|
||||
if (!inode_owner_or_capable(file_mnt_idmap(file), &inode->v)) {
|
||||
ret = -EACCES;
|
||||
goto setflags_out;
|
||||
}
|
||||
|
||||
mutex_lock(&inode->ei_update_lock);
|
||||
ret = bch2_subvol_is_ro(c, inode->ei_inum.subvol) ?:
|
||||
bch2_write_inode(c, inode, bch2_inode_flags_set, &s,
|
||||
ATTR_CTIME);
|
||||
mutex_unlock(&inode->ei_update_lock);
|
||||
|
||||
setflags_out:
|
||||
inode_unlock(&inode->v);
|
||||
mnt_drop_write_file(file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bch2_ioc_fsgetxattr(struct bch_inode_info *inode,
|
||||
struct fsxattr __user *arg)
|
||||
{
|
||||
struct fsxattr fa = { 0 };
|
||||
|
||||
fa.fsx_xflags = map_flags(bch_flags_to_xflags, inode->ei_inode.bi_flags);
|
||||
|
||||
if (inode->ei_inode.bi_fields_set & (1 << Inode_opt_project))
|
||||
fa.fsx_xflags |= FS_XFLAG_PROJINHERIT;
|
||||
|
||||
fa.fsx_projid = inode->ei_qid.q[QTYP_PRJ];
|
||||
|
||||
if (copy_to_user(arg, &fa, sizeof(fa)))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fssetxattr_inode_update_fn(struct btree_trans *trans,
|
||||
struct bch_inode_info *inode,
|
||||
struct bch_inode_unpacked *bi,
|
||||
void *p)
|
||||
{
|
||||
struct flags_set *s = p;
|
||||
|
||||
if (s->projid != bi->bi_project) {
|
||||
bi->bi_fields_set |= 1U << Inode_opt_project;
|
||||
bi->bi_project = s->projid;
|
||||
}
|
||||
|
||||
return bch2_inode_flags_set(trans, inode, bi, p);
|
||||
}
|
||||
|
||||
static int bch2_ioc_fssetxattr(struct bch_fs *c,
|
||||
struct file *file,
|
||||
struct bch_inode_info *inode,
|
||||
struct fsxattr __user *arg)
|
||||
{
|
||||
struct flags_set s = { .mask = map_defined(bch_flags_to_xflags) };
|
||||
struct fsxattr fa;
|
||||
int ret;
|
||||
|
||||
if (copy_from_user(&fa, arg, sizeof(fa)))
|
||||
return -EFAULT;
|
||||
|
||||
s.set_projinherit = true;
|
||||
s.projinherit = (fa.fsx_xflags & FS_XFLAG_PROJINHERIT) != 0;
|
||||
fa.fsx_xflags &= ~FS_XFLAG_PROJINHERIT;
|
||||
|
||||
s.flags = map_flags_rev(bch_flags_to_xflags, fa.fsx_xflags);
|
||||
if (fa.fsx_xflags)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (fa.fsx_projid >= U32_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* inode fields accessible via the xattr interface are stored with a +1
|
||||
* bias, so that 0 means unset:
|
||||
*/
|
||||
s.projid = fa.fsx_projid + 1;
|
||||
|
||||
ret = mnt_want_write_file(file);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
inode_lock(&inode->v);
|
||||
if (!inode_owner_or_capable(file_mnt_idmap(file), &inode->v)) {
|
||||
ret = -EACCES;
|
||||
goto err;
|
||||
}
|
||||
|
||||
mutex_lock(&inode->ei_update_lock);
|
||||
ret = bch2_subvol_is_ro(c, inode->ei_inum.subvol) ?:
|
||||
bch2_set_projid(c, inode, fa.fsx_projid) ?:
|
||||
bch2_write_inode(c, inode, fssetxattr_inode_update_fn, &s,
|
||||
ATTR_CTIME);
|
||||
mutex_unlock(&inode->ei_update_lock);
|
||||
err:
|
||||
inode_unlock(&inode->v);
|
||||
mnt_drop_write_file(file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bch2_reinherit_attrs_fn(struct btree_trans *trans,
|
||||
struct bch_inode_info *inode,
|
||||
struct bch_inode_unpacked *bi,
|
||||
@@ -558,23 +358,6 @@ long bch2_fs_file_ioctl(struct file *file, unsigned cmd, unsigned long arg)
|
||||
long ret;
|
||||
|
||||
switch (cmd) {
|
||||
case FS_IOC_GETFLAGS:
|
||||
ret = bch2_ioc_getflags(inode, (int __user *) arg);
|
||||
break;
|
||||
|
||||
case FS_IOC_SETFLAGS:
|
||||
ret = bch2_ioc_setflags(c, file, inode, (int __user *) arg);
|
||||
break;
|
||||
|
||||
case FS_IOC_FSGETXATTR:
|
||||
ret = bch2_ioc_fsgetxattr(inode, (void __user *) arg);
|
||||
break;
|
||||
|
||||
case FS_IOC_FSSETXATTR:
|
||||
ret = bch2_ioc_fssetxattr(c, file, inode,
|
||||
(void __user *) arg);
|
||||
break;
|
||||
|
||||
case BCHFS_IOC_REINHERIT_ATTRS:
|
||||
ret = bch2_ioc_reinherit_attrs(c, file, inode,
|
||||
(void __user *) arg);
|
||||
|
||||
@@ -2,81 +2,6 @@
|
||||
#ifndef _BCACHEFS_FS_IOCTL_H
|
||||
#define _BCACHEFS_FS_IOCTL_H
|
||||
|
||||
/* Inode flags: */
|
||||
|
||||
/* bcachefs inode flags -> vfs inode flags: */
|
||||
static const __maybe_unused unsigned bch_flags_to_vfs[] = {
|
||||
[__BCH_INODE_sync] = S_SYNC,
|
||||
[__BCH_INODE_immutable] = S_IMMUTABLE,
|
||||
[__BCH_INODE_append] = S_APPEND,
|
||||
[__BCH_INODE_noatime] = S_NOATIME,
|
||||
[__BCH_INODE_casefolded] = S_CASEFOLD,
|
||||
};
|
||||
|
||||
/* bcachefs inode flags -> FS_IOC_GETFLAGS: */
|
||||
static const __maybe_unused unsigned bch_flags_to_uflags[] = {
|
||||
[__BCH_INODE_sync] = FS_SYNC_FL,
|
||||
[__BCH_INODE_immutable] = FS_IMMUTABLE_FL,
|
||||
[__BCH_INODE_append] = FS_APPEND_FL,
|
||||
[__BCH_INODE_nodump] = FS_NODUMP_FL,
|
||||
[__BCH_INODE_noatime] = FS_NOATIME_FL,
|
||||
[__BCH_INODE_casefolded] = FS_CASEFOLD_FL,
|
||||
};
|
||||
|
||||
/* bcachefs inode flags -> FS_IOC_FSGETXATTR: */
|
||||
static const __maybe_unused unsigned bch_flags_to_xflags[] = {
|
||||
[__BCH_INODE_sync] = FS_XFLAG_SYNC,
|
||||
[__BCH_INODE_immutable] = FS_XFLAG_IMMUTABLE,
|
||||
[__BCH_INODE_append] = FS_XFLAG_APPEND,
|
||||
[__BCH_INODE_nodump] = FS_XFLAG_NODUMP,
|
||||
[__BCH_INODE_noatime] = FS_XFLAG_NOATIME,
|
||||
//[__BCH_INODE_PROJINHERIT] = FS_XFLAG_PROJINHERIT;
|
||||
};
|
||||
|
||||
#define set_flags(_map, _in, _out) \
|
||||
do { \
|
||||
unsigned _i; \
|
||||
\
|
||||
for (_i = 0; _i < ARRAY_SIZE(_map); _i++) \
|
||||
if ((_in) & (1 << _i)) \
|
||||
(_out) |= _map[_i]; \
|
||||
else \
|
||||
(_out) &= ~_map[_i]; \
|
||||
} while (0)
|
||||
|
||||
#define map_flags(_map, _in) \
|
||||
({ \
|
||||
unsigned _out = 0; \
|
||||
\
|
||||
set_flags(_map, _in, _out); \
|
||||
_out; \
|
||||
})
|
||||
|
||||
#define map_flags_rev(_map, _in) \
|
||||
({ \
|
||||
unsigned _i, _out = 0; \
|
||||
\
|
||||
for (_i = 0; _i < ARRAY_SIZE(_map); _i++) \
|
||||
if ((_in) & _map[_i]) { \
|
||||
(_out) |= 1 << _i; \
|
||||
(_in) &= ~_map[_i]; \
|
||||
} \
|
||||
(_out); \
|
||||
})
|
||||
|
||||
#define map_defined(_map) \
|
||||
({ \
|
||||
unsigned _in = ~0; \
|
||||
\
|
||||
map_flags_rev(_map, _in); \
|
||||
})
|
||||
|
||||
/* Set VFS inode flags from bcachefs inode: */
|
||||
static inline void bch2_inode_flags_to_vfs(struct bch_inode_info *inode)
|
||||
{
|
||||
set_flags(bch_flags_to_vfs, inode->ei_inode.bi_flags, inode->v.i_flags);
|
||||
}
|
||||
|
||||
long bch2_fs_file_ioctl(struct file *, unsigned, unsigned long);
|
||||
long bch2_compat_fs_ioctl(struct file *, unsigned, unsigned long);
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <linux/backing-dev.h>
|
||||
#include <linux/exportfs.h>
|
||||
#include <linux/fiemap.h>
|
||||
#include <linux/fileattr.h>
|
||||
#include <linux/fs_context.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pagemap.h>
|
||||
@@ -51,6 +52,19 @@ static void bch2_vfs_inode_init(struct btree_trans *, subvol_inum,
|
||||
struct bch_inode_unpacked *,
|
||||
struct bch_subvolume *);
|
||||
|
||||
/* Set VFS inode flags from bcachefs inode: */
|
||||
static inline void bch2_inode_flags_to_vfs(struct bch_inode_info *inode)
|
||||
{
|
||||
static const __maybe_unused unsigned bch_flags_to_vfs[] = {
|
||||
[__BCH_INODE_sync] = S_SYNC,
|
||||
[__BCH_INODE_immutable] = S_IMMUTABLE,
|
||||
[__BCH_INODE_append] = S_APPEND,
|
||||
[__BCH_INODE_noatime] = S_NOATIME,
|
||||
[__BCH_INODE_casefolded] = S_CASEFOLD,
|
||||
};
|
||||
set_flags(bch_flags_to_vfs, inode->ei_inode.bi_flags, inode->v.i_flags);
|
||||
}
|
||||
|
||||
void bch2_inode_update_after_write(struct btree_trans *trans,
|
||||
struct bch_inode_info *inode,
|
||||
struct bch_inode_unpacked *bi,
|
||||
@@ -1449,6 +1463,157 @@ static int bch2_open(struct inode *vinode, struct file *file)
|
||||
return generic_file_open(vinode, file);
|
||||
}
|
||||
|
||||
/* bcachefs inode flags -> FS_IOC_GETFLAGS: */
|
||||
static const __maybe_unused unsigned bch_flags_to_uflags[] = {
|
||||
[__BCH_INODE_sync] = FS_SYNC_FL,
|
||||
[__BCH_INODE_immutable] = FS_IMMUTABLE_FL,
|
||||
[__BCH_INODE_append] = FS_APPEND_FL,
|
||||
[__BCH_INODE_nodump] = FS_NODUMP_FL,
|
||||
[__BCH_INODE_noatime] = FS_NOATIME_FL,
|
||||
[__BCH_INODE_casefolded] = FS_CASEFOLD_FL,
|
||||
};
|
||||
|
||||
/* bcachefs inode flags -> FS_IOC_FSGETXATTR: */
|
||||
static const __maybe_unused unsigned bch_flags_to_xflags[] = {
|
||||
[__BCH_INODE_sync] = FS_XFLAG_SYNC,
|
||||
[__BCH_INODE_immutable] = FS_XFLAG_IMMUTABLE,
|
||||
[__BCH_INODE_append] = FS_XFLAG_APPEND,
|
||||
[__BCH_INODE_nodump] = FS_XFLAG_NODUMP,
|
||||
[__BCH_INODE_noatime] = FS_XFLAG_NOATIME,
|
||||
};
|
||||
|
||||
static int bch2_fileattr_get(struct dentry *dentry,
|
||||
struct fileattr *fa)
|
||||
{
|
||||
struct bch_inode_info *inode = to_bch_ei(d_inode(dentry));
|
||||
|
||||
fileattr_fill_xflags(fa, map_flags(bch_flags_to_xflags, inode->ei_inode.bi_flags));
|
||||
|
||||
if (inode->ei_inode.bi_fields_set & (1 << Inode_opt_project))
|
||||
fa->fsx_xflags |= FS_XFLAG_PROJINHERIT;
|
||||
|
||||
if (inode->ei_inode.bi_flags & BCH_INODE_casefolded)
|
||||
fa->flags |= FS_CASEFOLD_FL;
|
||||
|
||||
fa->fsx_projid = inode->ei_qid.q[QTYP_PRJ];
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct flags_set {
|
||||
unsigned mask;
|
||||
unsigned flags;
|
||||
unsigned projid;
|
||||
bool set_project;
|
||||
};
|
||||
|
||||
static int fssetxattr_inode_update_fn(struct btree_trans *trans,
|
||||
struct bch_inode_info *inode,
|
||||
struct bch_inode_unpacked *bi,
|
||||
void *p)
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
struct flags_set *s = p;
|
||||
|
||||
/*
|
||||
* We're relying on btree locking here for exclusion with other ioctl
|
||||
* calls - use the flags in the btree (@bi), not inode->i_flags:
|
||||
*/
|
||||
unsigned newflags = s->flags;
|
||||
unsigned oldflags = bi->bi_flags & s->mask;
|
||||
|
||||
if (!S_ISREG(bi->bi_mode) &&
|
||||
!S_ISDIR(bi->bi_mode) &&
|
||||
(newflags & (BCH_INODE_nodump|BCH_INODE_noatime)) != newflags)
|
||||
return -EINVAL;
|
||||
|
||||
if ((newflags ^ oldflags) & BCH_INODE_casefolded) {
|
||||
#ifdef CONFIG_UNICODE
|
||||
int ret = 0;
|
||||
/* Not supported on individual files. */
|
||||
if (!S_ISDIR(bi->bi_mode))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/*
|
||||
* Make sure the dir is empty, as otherwise we'd need to
|
||||
* rehash everything and update the dirent keys.
|
||||
*/
|
||||
ret = bch2_empty_dir_trans(trans, inode_inum(inode));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = bch2_request_incompat_feature(c, bcachefs_metadata_version_casefolding);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
bch2_check_set_feature(c, BCH_FEATURE_casefolding);
|
||||
#else
|
||||
printk(KERN_ERR "Cannot use casefolding on a kernel without CONFIG_UNICODE\n");
|
||||
return -EOPNOTSUPP;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (s->set_project) {
|
||||
bi->bi_project = s->projid;
|
||||
bi->bi_fields_set |= BIT(Inode_opt_project);
|
||||
}
|
||||
|
||||
bi->bi_flags &= ~s->mask;
|
||||
bi->bi_flags |= newflags;
|
||||
|
||||
bi->bi_ctime = timespec_to_bch2_time(c, current_time(&inode->v));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bch2_fileattr_set(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry,
|
||||
struct fileattr *fa)
|
||||
{
|
||||
struct bch_inode_info *inode = to_bch_ei(d_inode(dentry));
|
||||
struct bch_fs *c = inode->v.i_sb->s_fs_info;
|
||||
struct flags_set s = {};
|
||||
int ret;
|
||||
|
||||
if (fa->fsx_valid) {
|
||||
fa->fsx_xflags &= ~FS_XFLAG_PROJINHERIT;
|
||||
|
||||
s.mask = map_defined(bch_flags_to_xflags);
|
||||
s.flags |= map_flags_rev(bch_flags_to_xflags, fa->fsx_xflags);
|
||||
if (fa->fsx_xflags)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (fa->fsx_projid >= U32_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* inode fields accessible via the xattr interface are stored with a +1
|
||||
* bias, so that 0 means unset:
|
||||
*/
|
||||
if ((inode->ei_inode.bi_project ||
|
||||
fa->fsx_projid) &&
|
||||
inode->ei_inode.bi_project != fa->fsx_projid + 1) {
|
||||
s.projid = fa->fsx_projid + 1;
|
||||
s.set_project = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (fa->flags_valid) {
|
||||
s.mask = map_defined(bch_flags_to_uflags);
|
||||
s.flags |= map_flags_rev(bch_flags_to_uflags, fa->flags);
|
||||
if (fa->flags)
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
mutex_lock(&inode->ei_update_lock);
|
||||
ret = bch2_subvol_is_ro(c, inode->ei_inum.subvol) ?:
|
||||
(s.set_project
|
||||
? bch2_set_projid(c, inode, fa->fsx_projid)
|
||||
: 0) ?:
|
||||
bch2_write_inode(c, inode, fssetxattr_inode_update_fn, &s,
|
||||
ATTR_CTIME);
|
||||
mutex_unlock(&inode->ei_update_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations bch_file_operations = {
|
||||
.open = bch2_open,
|
||||
.llseek = bch2_llseek,
|
||||
@@ -1476,6 +1641,8 @@ static const struct inode_operations bch_file_inode_operations = {
|
||||
.get_inode_acl = bch2_get_acl,
|
||||
.set_acl = bch2_set_acl,
|
||||
#endif
|
||||
.fileattr_get = bch2_fileattr_get,
|
||||
.fileattr_set = bch2_fileattr_set,
|
||||
};
|
||||
|
||||
static const struct inode_operations bch_dir_inode_operations = {
|
||||
@@ -1496,6 +1663,8 @@ static const struct inode_operations bch_dir_inode_operations = {
|
||||
.get_inode_acl = bch2_get_acl,
|
||||
.set_acl = bch2_set_acl,
|
||||
#endif
|
||||
.fileattr_get = bch2_fileattr_get,
|
||||
.fileattr_set = bch2_fileattr_set,
|
||||
};
|
||||
|
||||
static const struct file_operations bch_dir_file_operations = {
|
||||
@@ -1518,6 +1687,8 @@ static const struct inode_operations bch_symlink_inode_operations = {
|
||||
.get_inode_acl = bch2_get_acl,
|
||||
.set_acl = bch2_set_acl,
|
||||
#endif
|
||||
.fileattr_get = bch2_fileattr_get,
|
||||
.fileattr_set = bch2_fileattr_set,
|
||||
};
|
||||
|
||||
static const struct inode_operations bch_special_inode_operations = {
|
||||
@@ -1528,6 +1699,8 @@ static const struct inode_operations bch_special_inode_operations = {
|
||||
.get_inode_acl = bch2_get_acl,
|
||||
.set_acl = bch2_set_acl,
|
||||
#endif
|
||||
.fileattr_get = bch2_fileattr_get,
|
||||
.fileattr_set = bch2_fileattr_set,
|
||||
};
|
||||
|
||||
static const struct address_space_operations bch_address_space_operations = {
|
||||
|
||||
@@ -739,4 +739,42 @@ static inline void memcpy_swab(void *_dst, void *_src, size_t len)
|
||||
*--dst = *src++;
|
||||
}
|
||||
|
||||
#define set_flags(_map, _in, _out) \
|
||||
do { \
|
||||
unsigned _i; \
|
||||
\
|
||||
for (_i = 0; _i < ARRAY_SIZE(_map); _i++) \
|
||||
if ((_in) & (1 << _i)) \
|
||||
(_out) |= _map[_i]; \
|
||||
else \
|
||||
(_out) &= ~_map[_i]; \
|
||||
} while (0)
|
||||
|
||||
#define map_flags(_map, _in) \
|
||||
({ \
|
||||
unsigned _out = 0; \
|
||||
\
|
||||
set_flags(_map, _in, _out); \
|
||||
_out; \
|
||||
})
|
||||
|
||||
#define map_flags_rev(_map, _in) \
|
||||
({ \
|
||||
unsigned _i, _out = 0; \
|
||||
\
|
||||
for (_i = 0; _i < ARRAY_SIZE(_map); _i++) \
|
||||
if ((_in) & _map[_i]) { \
|
||||
(_out) |= 1 << _i; \
|
||||
(_in) &= ~_map[_i]; \
|
||||
} \
|
||||
(_out); \
|
||||
})
|
||||
|
||||
#define map_defined(_map) \
|
||||
({ \
|
||||
unsigned _in = ~0; \
|
||||
\
|
||||
map_flags_rev(_map, _in); \
|
||||
})
|
||||
|
||||
#endif /* _BCACHEFS_UTIL_H */
|
||||
|
||||
Reference in New Issue
Block a user