vfs: create a generic checking and prep function for FS_IOC_SETFLAGS
Create a generic function to check incoming FS_IOC_SETFLAGS flag values and later prepare the inode for updates so that we can standardize the implementations that follow ext4's flag values. Note that the efivarfs implementation no longer fails a no-op SETFLAGS without CAP_LINUX_IMMUTABLE since that's the behavior in ext*. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Reviewed-by: Jan Kara <jack@suse.cz> Reviewed-by: Christoph Hellwig <hch@lst.de> Acked-by: David Sterba <dsterba@suse.com> Reviewed-by: Bob Peterson <rpeterso@redhat.com>
This commit is contained in:
parent
d1fdb6d8f6
commit
5aca284210
@ -187,7 +187,7 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
|
||||
struct btrfs_inode *binode = BTRFS_I(inode);
|
||||
struct btrfs_root *root = binode->root;
|
||||
struct btrfs_trans_handle *trans;
|
||||
unsigned int fsflags;
|
||||
unsigned int fsflags, old_fsflags;
|
||||
int ret;
|
||||
const char *comp = NULL;
|
||||
u32 binode_flags = binode->flags;
|
||||
@ -212,13 +212,10 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
|
||||
inode_lock(inode);
|
||||
|
||||
fsflags = btrfs_mask_fsflags_for_type(inode, fsflags);
|
||||
if ((fsflags ^ btrfs_inode_flags_to_fsflags(binode->flags)) &
|
||||
(FS_APPEND_FL | FS_IMMUTABLE_FL)) {
|
||||
if (!capable(CAP_LINUX_IMMUTABLE)) {
|
||||
ret = -EPERM;
|
||||
goto out_unlock;
|
||||
}
|
||||
}
|
||||
old_fsflags = btrfs_inode_flags_to_fsflags(binode->flags);
|
||||
ret = vfs_ioc_setflags_prepare(inode, old_fsflags, fsflags);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
|
||||
if (fsflags & FS_SYNC_FL)
|
||||
binode_flags |= BTRFS_INODE_SYNC;
|
||||
|
@ -110,16 +110,22 @@ out_free:
|
||||
return size;
|
||||
}
|
||||
|
||||
static int
|
||||
efivarfs_ioc_getxflags(struct file *file, void __user *arg)
|
||||
static inline unsigned int efivarfs_getflags(struct inode *inode)
|
||||
{
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
unsigned int i_flags;
|
||||
unsigned int flags = 0;
|
||||
|
||||
i_flags = inode->i_flags;
|
||||
if (i_flags & S_IMMUTABLE)
|
||||
flags |= FS_IMMUTABLE_FL;
|
||||
return flags;
|
||||
}
|
||||
|
||||
static int
|
||||
efivarfs_ioc_getxflags(struct file *file, void __user *arg)
|
||||
{
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
unsigned int flags = efivarfs_getflags(inode);
|
||||
|
||||
if (copy_to_user(arg, &flags, sizeof(flags)))
|
||||
return -EFAULT;
|
||||
@ -132,6 +138,7 @@ efivarfs_ioc_setxflags(struct file *file, void __user *arg)
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
unsigned int flags;
|
||||
unsigned int i_flags = 0;
|
||||
unsigned int oldflags = efivarfs_getflags(inode);
|
||||
int error;
|
||||
|
||||
if (!inode_owner_or_capable(inode))
|
||||
@ -143,9 +150,6 @@ efivarfs_ioc_setxflags(struct file *file, void __user *arg)
|
||||
if (flags & ~FS_IMMUTABLE_FL)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!capable(CAP_LINUX_IMMUTABLE))
|
||||
return -EPERM;
|
||||
|
||||
if (flags & FS_IMMUTABLE_FL)
|
||||
i_flags |= S_IMMUTABLE;
|
||||
|
||||
@ -155,12 +159,16 @@ efivarfs_ioc_setxflags(struct file *file, void __user *arg)
|
||||
return error;
|
||||
|
||||
inode_lock(inode);
|
||||
|
||||
error = vfs_ioc_setflags_prepare(inode, oldflags, flags);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
inode_set_flags(inode, i_flags, S_IMMUTABLE);
|
||||
out:
|
||||
inode_unlock(inode);
|
||||
|
||||
mnt_drop_write_file(file);
|
||||
|
||||
return 0;
|
||||
return error;
|
||||
}
|
||||
|
||||
static long
|
||||
|
@ -60,18 +60,10 @@ long ext2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
}
|
||||
oldflags = ei->i_flags;
|
||||
|
||||
/*
|
||||
* The IMMUTABLE and APPEND_ONLY flags can only be changed by
|
||||
* the relevant capability.
|
||||
*
|
||||
* This test looks nicer. Thanks to Pauline Middelink
|
||||
*/
|
||||
if ((flags ^ oldflags) & (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL)) {
|
||||
if (!capable(CAP_LINUX_IMMUTABLE)) {
|
||||
inode_unlock(inode);
|
||||
ret = -EPERM;
|
||||
goto setflags_out;
|
||||
}
|
||||
ret = vfs_ioc_setflags_prepare(inode, oldflags, flags);
|
||||
if (ret) {
|
||||
inode_unlock(inode);
|
||||
goto setflags_out;
|
||||
}
|
||||
|
||||
flags = flags & EXT2_FL_USER_MODIFIABLE;
|
||||
|
@ -289,16 +289,9 @@ static int ext4_ioctl_setflags(struct inode *inode,
|
||||
/* The JOURNAL_DATA flag is modifiable only by root */
|
||||
jflag = flags & EXT4_JOURNAL_DATA_FL;
|
||||
|
||||
/*
|
||||
* The IMMUTABLE and APPEND_ONLY flags can only be changed by
|
||||
* the relevant capability.
|
||||
*
|
||||
* This test looks nicer. Thanks to Pauline Middelink
|
||||
*/
|
||||
if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) {
|
||||
if (!capable(CAP_LINUX_IMMUTABLE))
|
||||
goto flags_out;
|
||||
}
|
||||
err = vfs_ioc_setflags_prepare(inode, oldflags, flags);
|
||||
if (err)
|
||||
goto flags_out;
|
||||
|
||||
/*
|
||||
* The JOURNAL_DATA flag can only be changed by
|
||||
|
@ -136,27 +136,36 @@ static struct {
|
||||
{FS_JOURNAL_DATA_FL, GFS2_DIF_JDATA | GFS2_DIF_INHERIT_JDATA},
|
||||
};
|
||||
|
||||
static inline u32 gfs2_gfsflags_to_fsflags(struct inode *inode, u32 gfsflags)
|
||||
{
|
||||
int i;
|
||||
u32 fsflags = 0;
|
||||
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
gfsflags &= ~GFS2_DIF_JDATA;
|
||||
else
|
||||
gfsflags &= ~GFS2_DIF_INHERIT_JDATA;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(fsflag_gfs2flag); i++)
|
||||
if (gfsflags & fsflag_gfs2flag[i].gfsflag)
|
||||
fsflags |= fsflag_gfs2flag[i].fsflag;
|
||||
return fsflags;
|
||||
}
|
||||
|
||||
static int gfs2_get_flags(struct file *filp, u32 __user *ptr)
|
||||
{
|
||||
struct inode *inode = file_inode(filp);
|
||||
struct gfs2_inode *ip = GFS2_I(inode);
|
||||
struct gfs2_holder gh;
|
||||
int i, error;
|
||||
u32 gfsflags, fsflags = 0;
|
||||
int error;
|
||||
u32 fsflags;
|
||||
|
||||
gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &gh);
|
||||
error = gfs2_glock_nq(&gh);
|
||||
if (error)
|
||||
goto out_uninit;
|
||||
|
||||
gfsflags = ip->i_diskflags;
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
gfsflags &= ~GFS2_DIF_JDATA;
|
||||
else
|
||||
gfsflags &= ~GFS2_DIF_INHERIT_JDATA;
|
||||
for (i = 0; i < ARRAY_SIZE(fsflag_gfs2flag); i++)
|
||||
if (gfsflags & fsflag_gfs2flag[i].gfsflag)
|
||||
fsflags |= fsflag_gfs2flag[i].fsflag;
|
||||
fsflags = gfs2_gfsflags_to_fsflags(inode, ip->i_diskflags);
|
||||
|
||||
if (put_user(fsflags, ptr))
|
||||
error = -EFAULT;
|
||||
@ -200,9 +209,11 @@ void gfs2_set_inode_flags(struct inode *inode)
|
||||
* @filp: file pointer
|
||||
* @reqflags: The flags to set
|
||||
* @mask: Indicates which flags are valid
|
||||
* @fsflags: The FS_* inode flags passed in
|
||||
*
|
||||
*/
|
||||
static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask)
|
||||
static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask,
|
||||
const u32 fsflags)
|
||||
{
|
||||
struct inode *inode = file_inode(filp);
|
||||
struct gfs2_inode *ip = GFS2_I(inode);
|
||||
@ -210,7 +221,7 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask)
|
||||
struct buffer_head *bh;
|
||||
struct gfs2_holder gh;
|
||||
int error;
|
||||
u32 new_flags, flags;
|
||||
u32 new_flags, flags, oldflags;
|
||||
|
||||
error = mnt_want_write_file(filp);
|
||||
if (error)
|
||||
@ -220,6 +231,11 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask)
|
||||
if (error)
|
||||
goto out_drop_write;
|
||||
|
||||
oldflags = gfs2_gfsflags_to_fsflags(inode, ip->i_diskflags);
|
||||
error = vfs_ioc_setflags_prepare(inode, oldflags, fsflags);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
error = -EACCES;
|
||||
if (!inode_owner_or_capable(inode))
|
||||
goto out;
|
||||
@ -308,7 +324,7 @@ static int gfs2_set_flags(struct file *filp, u32 __user *ptr)
|
||||
mask &= ~(GFS2_DIF_TOPDIR | GFS2_DIF_INHERIT_JDATA);
|
||||
}
|
||||
|
||||
return do_gfs2_set_flags(filp, gfsflags, mask);
|
||||
return do_gfs2_set_flags(filp, gfsflags, mask, fsflags);
|
||||
}
|
||||
|
||||
static int gfs2_getlabel(struct file *filp, char __user *label)
|
||||
|
@ -57,9 +57,8 @@ static int hfsplus_ioctl_bless(struct file *file, int __user *user_flags)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hfsplus_ioctl_getflags(struct file *file, int __user *user_flags)
|
||||
static inline unsigned int hfsplus_getflags(struct inode *inode)
|
||||
{
|
||||
struct inode *inode = file_inode(file);
|
||||
struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
|
||||
unsigned int flags = 0;
|
||||
|
||||
@ -69,6 +68,13 @@ static int hfsplus_ioctl_getflags(struct file *file, int __user *user_flags)
|
||||
flags |= FS_APPEND_FL;
|
||||
if (hip->userflags & HFSPLUS_FLG_NODUMP)
|
||||
flags |= FS_NODUMP_FL;
|
||||
return flags;
|
||||
}
|
||||
|
||||
static int hfsplus_ioctl_getflags(struct file *file, int __user *user_flags)
|
||||
{
|
||||
struct inode *inode = file_inode(file);
|
||||
unsigned int flags = hfsplus_getflags(inode);
|
||||
|
||||
return put_user(flags, user_flags);
|
||||
}
|
||||
@ -78,6 +84,7 @@ static int hfsplus_ioctl_setflags(struct file *file, int __user *user_flags)
|
||||
struct inode *inode = file_inode(file);
|
||||
struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
|
||||
unsigned int flags, new_fl = 0;
|
||||
unsigned int oldflags = hfsplus_getflags(inode);
|
||||
int err = 0;
|
||||
|
||||
err = mnt_want_write_file(file);
|
||||
@ -96,13 +103,9 @@ static int hfsplus_ioctl_setflags(struct file *file, int __user *user_flags)
|
||||
|
||||
inode_lock(inode);
|
||||
|
||||
if ((flags & (FS_IMMUTABLE_FL|FS_APPEND_FL)) ||
|
||||
inode->i_flags & (S_IMMUTABLE|S_APPEND)) {
|
||||
if (!capable(CAP_LINUX_IMMUTABLE)) {
|
||||
err = -EPERM;
|
||||
goto out_unlock_inode;
|
||||
}
|
||||
}
|
||||
err = vfs_ioc_setflags_prepare(inode, oldflags, flags);
|
||||
if (err)
|
||||
goto out_unlock_inode;
|
||||
|
||||
/* don't silently ignore unsupported ext2 flags */
|
||||
if (flags & ~(FS_IMMUTABLE_FL|FS_APPEND_FL|FS_NODUMP_FL)) {
|
||||
|
24
fs/inode.c
24
fs/inode.c
@ -2170,3 +2170,27 @@ struct timespec64 current_time(struct inode *inode)
|
||||
return timespec64_trunc(now, inode->i_sb->s_time_gran);
|
||||
}
|
||||
EXPORT_SYMBOL(current_time);
|
||||
|
||||
/*
|
||||
* Generic function to check FS_IOC_SETFLAGS values and reject any invalid
|
||||
* configurations.
|
||||
*
|
||||
* Note: the caller should be holding i_mutex, or else be sure that they have
|
||||
* exclusive access to the inode structure.
|
||||
*/
|
||||
int vfs_ioc_setflags_prepare(struct inode *inode, unsigned int oldflags,
|
||||
unsigned int flags)
|
||||
{
|
||||
/*
|
||||
* The IMMUTABLE and APPEND_ONLY flags can only be changed by
|
||||
* the relevant capability.
|
||||
*
|
||||
* This test looks nicer. Thanks to Pauline Middelink
|
||||
*/
|
||||
if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL) &&
|
||||
!capable(CAP_LINUX_IMMUTABLE))
|
||||
return -EPERM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(vfs_ioc_setflags_prepare);
|
||||
|
@ -98,24 +98,16 @@ long jfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
/* Lock against other parallel changes of flags */
|
||||
inode_lock(inode);
|
||||
|
||||
oldflags = jfs_inode->mode2;
|
||||
|
||||
/*
|
||||
* The IMMUTABLE and APPEND_ONLY flags can only be changed by
|
||||
* the relevant capability.
|
||||
*/
|
||||
if ((oldflags & JFS_IMMUTABLE_FL) ||
|
||||
((flags ^ oldflags) &
|
||||
(JFS_APPEND_FL | JFS_IMMUTABLE_FL))) {
|
||||
if (!capable(CAP_LINUX_IMMUTABLE)) {
|
||||
inode_unlock(inode);
|
||||
err = -EPERM;
|
||||
goto setflags_out;
|
||||
}
|
||||
oldflags = jfs_map_ext2(jfs_inode->mode2 & JFS_FL_USER_VISIBLE,
|
||||
0);
|
||||
err = vfs_ioc_setflags_prepare(inode, oldflags, flags);
|
||||
if (err) {
|
||||
inode_unlock(inode);
|
||||
goto setflags_out;
|
||||
}
|
||||
|
||||
flags = flags & JFS_FL_USER_MODIFIABLE;
|
||||
flags |= oldflags & ~JFS_FL_USER_MODIFIABLE;
|
||||
flags |= jfs_inode->mode2 & ~JFS_FL_USER_MODIFIABLE;
|
||||
jfs_inode->mode2 = flags;
|
||||
|
||||
jfs_set_inode_flags(inode);
|
||||
|
@ -148,13 +148,8 @@ static int nilfs_ioctl_setflags(struct inode *inode, struct file *filp,
|
||||
|
||||
oldflags = NILFS_I(inode)->i_flags;
|
||||
|
||||
/*
|
||||
* The IMMUTABLE and APPEND_ONLY flags can only be changed by the
|
||||
* relevant capability.
|
||||
*/
|
||||
ret = -EPERM;
|
||||
if (((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) &&
|
||||
!capable(CAP_LINUX_IMMUTABLE))
|
||||
ret = vfs_ioc_setflags_prepare(inode, oldflags, flags);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = nilfs_transaction_begin(inode->i_sb, &ti, 0);
|
||||
|
@ -106,16 +106,9 @@ static int ocfs2_set_inode_attr(struct inode *inode, unsigned flags,
|
||||
flags = flags & mask;
|
||||
flags |= oldflags & ~mask;
|
||||
|
||||
/*
|
||||
* The IMMUTABLE and APPEND_ONLY flags can only be changed by
|
||||
* the relevant capability.
|
||||
*/
|
||||
status = -EPERM;
|
||||
if ((oldflags & OCFS2_IMMUTABLE_FL) || ((flags ^ oldflags) &
|
||||
(OCFS2_APPEND_FL | OCFS2_IMMUTABLE_FL))) {
|
||||
if (!capable(CAP_LINUX_IMMUTABLE))
|
||||
goto bail_unlock;
|
||||
}
|
||||
status = vfs_ioc_setflags_prepare(inode, oldflags, flags);
|
||||
if (status)
|
||||
goto bail_unlock;
|
||||
|
||||
handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
|
||||
if (IS_ERR(handle)) {
|
||||
|
@ -357,11 +357,28 @@ static ssize_t orangefs_file_write_iter(struct kiocb *iocb,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int orangefs_getflags(struct inode *inode, unsigned long *uval)
|
||||
{
|
||||
__u64 val = 0;
|
||||
int ret;
|
||||
|
||||
ret = orangefs_inode_getxattr(inode,
|
||||
"user.pvfs2.meta_hint",
|
||||
&val, sizeof(val));
|
||||
if (ret < 0 && ret != -ENODATA)
|
||||
return ret;
|
||||
else if (ret == -ENODATA)
|
||||
val = 0;
|
||||
*uval = val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform a miscellaneous operation on a file.
|
||||
*/
|
||||
static long orangefs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct inode *inode = file_inode(file);
|
||||
int ret = -ENOTTY;
|
||||
__u64 val = 0;
|
||||
unsigned long uval;
|
||||
@ -375,20 +392,16 @@ static long orangefs_ioctl(struct file *file, unsigned int cmd, unsigned long ar
|
||||
* and append flags
|
||||
*/
|
||||
if (cmd == FS_IOC_GETFLAGS) {
|
||||
val = 0;
|
||||
ret = orangefs_inode_getxattr(file_inode(file),
|
||||
"user.pvfs2.meta_hint",
|
||||
&val, sizeof(val));
|
||||
if (ret < 0 && ret != -ENODATA)
|
||||
ret = orangefs_getflags(inode, &uval);
|
||||
if (ret)
|
||||
return ret;
|
||||
else if (ret == -ENODATA)
|
||||
val = 0;
|
||||
uval = val;
|
||||
gossip_debug(GOSSIP_FILE_DEBUG,
|
||||
"orangefs_ioctl: FS_IOC_GETFLAGS: %llu\n",
|
||||
(unsigned long long)uval);
|
||||
return put_user(uval, (int __user *)arg);
|
||||
} else if (cmd == FS_IOC_SETFLAGS) {
|
||||
unsigned long old_uval;
|
||||
|
||||
ret = 0;
|
||||
if (get_user(uval, (int __user *)arg))
|
||||
return -EFAULT;
|
||||
@ -404,11 +417,17 @@ static long orangefs_ioctl(struct file *file, unsigned int cmd, unsigned long ar
|
||||
gossip_err("orangefs_ioctl: the FS_IOC_SETFLAGS only supports setting one of FS_IMMUTABLE_FL|FS_APPEND_FL|FS_NOATIME_FL\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = orangefs_getflags(inode, &old_uval);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = vfs_ioc_setflags_prepare(inode, old_uval, uval);
|
||||
if (ret)
|
||||
return ret;
|
||||
val = uval;
|
||||
gossip_debug(GOSSIP_FILE_DEBUG,
|
||||
"orangefs_ioctl: FS_IOC_SETFLAGS: %llu\n",
|
||||
(unsigned long long)val);
|
||||
ret = orangefs_inode_setxattr(file_inode(file),
|
||||
ret = orangefs_inode_setxattr(inode,
|
||||
"user.pvfs2.meta_hint",
|
||||
&val, sizeof(val), 0);
|
||||
}
|
||||
|
@ -74,13 +74,11 @@ long reiserfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
err = -EPERM;
|
||||
goto setflags_out;
|
||||
}
|
||||
if (((flags ^ REISERFS_I(inode)->
|
||||
i_attrs) & (REISERFS_IMMUTABLE_FL |
|
||||
REISERFS_APPEND_FL))
|
||||
&& !capable(CAP_LINUX_IMMUTABLE)) {
|
||||
err = -EPERM;
|
||||
err = vfs_ioc_setflags_prepare(inode,
|
||||
REISERFS_I(inode)->i_attrs,
|
||||
flags);
|
||||
if (err)
|
||||
goto setflags_out;
|
||||
}
|
||||
if ((flags & REISERFS_NOTAIL_FL) &&
|
||||
S_ISREG(inode->i_mode)) {
|
||||
int result;
|
||||
|
@ -107,18 +107,11 @@ static int setflags(struct inode *inode, int flags)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/*
|
||||
* The IMMUTABLE and APPEND_ONLY flags can only be changed by
|
||||
* the relevant capability.
|
||||
*/
|
||||
mutex_lock(&ui->ui_mutex);
|
||||
oldflags = ubifs2ioctl(ui->flags);
|
||||
if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) {
|
||||
if (!capable(CAP_LINUX_IMMUTABLE)) {
|
||||
err = -EPERM;
|
||||
goto out_unlock;
|
||||
}
|
||||
}
|
||||
err = vfs_ioc_setflags_prepare(inode, oldflags, flags);
|
||||
if (err)
|
||||
goto out_unlock;
|
||||
|
||||
ui->flags = ioctl2ubifs(flags);
|
||||
ubifs_set_inode_flags(inode);
|
||||
|
@ -3546,4 +3546,7 @@ static inline struct sock *io_uring_get_socket(struct file *file)
|
||||
}
|
||||
#endif
|
||||
|
||||
int vfs_ioc_setflags_prepare(struct inode *inode, unsigned int oldflags,
|
||||
unsigned int flags);
|
||||
|
||||
#endif /* _LINUX_FS_H */
|
||||
|
Loading…
Reference in New Issue
Block a user