Commit b16f7e57 authored by Andreas Gruenbacher's avatar Andreas Gruenbacher

gfs2: Fix and clean up {GET,SET}FLAGS ioctl

Switch to a simple array for mapping between the FS_*_FL and GFS_DIF_*
flags.  Clarify how the mapping between FS_JOURNAL_DATA_FL and the
filesystem flags works.  The GFS2_DIF_SYSTEM flag cannot be set from
user space, so remove it from GFS2_FLAGS_USER_SET.  Fail with -EINVAL
when trying to set flags that are not supported instead of silently
ignoring those flags.

Partially fixes xfstest generic/424.
Signed-off-by: default avatarAndreas Gruenbacher <agruenba@redhat.com>
Reviewed-by: default avatarAndrew Price <anprice@redhat.com>
Signed-off-by: default avatarBob Peterson <rpeterso@redhat.com>
parent 61d6899a
...@@ -119,45 +119,22 @@ static int gfs2_readdir(struct file *file, struct dir_context *ctx) ...@@ -119,45 +119,22 @@ static int gfs2_readdir(struct file *file, struct dir_context *ctx)
} }
/** /**
* fsflags_cvt * fsflag_gfs2flag
* @table: A table of 32 u32 flags
* @val: a 32 bit value to convert
* *
* This function can be used to convert between fsflags values and * The FS_JOURNAL_DATA_FL flag maps to GFS2_DIF_INHERIT_JDATA for directories,
* GFS2's own flags values. * and to GFS2_DIF_JDATA for non-directories.
*
* Returns: the converted flags
*/ */
static u32 fsflags_cvt(const u32 *table, u32 val) static struct {
{ u32 fsflag;
u32 res = 0; u32 gfsflag;
while(val) { } fsflag_gfs2flag[] = {
if (val & 1) {FS_SYNC_FL, GFS2_DIF_SYNC},
res |= *table; {FS_IMMUTABLE_FL, GFS2_DIF_IMMUTABLE},
table++; {FS_APPEND_FL, GFS2_DIF_APPENDONLY},
val >>= 1; {FS_NOATIME_FL, GFS2_DIF_NOATIME},
} {FS_INDEX_FL, GFS2_DIF_EXHASH},
return res; {FS_TOPDIR_FL, GFS2_DIF_TOPDIR},
} {FS_JOURNAL_DATA_FL, GFS2_DIF_JDATA | GFS2_DIF_INHERIT_JDATA},
static const u32 fsflags_to_gfs2[32] = {
[3] = GFS2_DIF_SYNC,
[4] = GFS2_DIF_IMMUTABLE,
[5] = GFS2_DIF_APPENDONLY,
[7] = GFS2_DIF_NOATIME,
[12] = GFS2_DIF_EXHASH,
[14] = GFS2_DIF_INHERIT_JDATA,
[17] = GFS2_DIF_TOPDIR,
};
static const u32 gfs2_to_fsflags[32] = {
[gfs2fl_Sync] = FS_SYNC_FL,
[gfs2fl_Immutable] = FS_IMMUTABLE_FL,
[gfs2fl_AppendOnly] = FS_APPEND_FL,
[gfs2fl_NoAtime] = FS_NOATIME_FL,
[gfs2fl_ExHash] = FS_INDEX_FL,
[gfs2fl_TopLevel] = FS_TOPDIR_FL,
[gfs2fl_InheritJdata] = FS_JOURNAL_DATA_FL,
}; };
static int gfs2_get_flags(struct file *filp, u32 __user *ptr) static int gfs2_get_flags(struct file *filp, u32 __user *ptr)
...@@ -165,17 +142,23 @@ static int gfs2_get_flags(struct file *filp, u32 __user *ptr) ...@@ -165,17 +142,23 @@ static int gfs2_get_flags(struct file *filp, u32 __user *ptr)
struct inode *inode = file_inode(filp); struct inode *inode = file_inode(filp);
struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_holder gh; struct gfs2_holder gh;
int error; int i, error;
u32 fsflags; u32 gfsflags, fsflags = 0;
gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &gh); gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &gh);
error = gfs2_glock_nq(&gh); error = gfs2_glock_nq(&gh);
if (error) if (error)
goto out_uninit; goto out_uninit;
fsflags = fsflags_cvt(gfs2_to_fsflags, ip->i_diskflags); gfsflags = ip->i_diskflags;
if (!S_ISDIR(inode->i_mode) && ip->i_diskflags & GFS2_DIF_JDATA) if (S_ISDIR(inode->i_mode))
fsflags |= FS_JOURNAL_DATA_FL; 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;
if (put_user(fsflags, ptr)) if (put_user(fsflags, ptr))
error = -EFAULT; error = -EFAULT;
...@@ -210,7 +193,6 @@ void gfs2_set_inode_flags(struct inode *inode) ...@@ -210,7 +193,6 @@ void gfs2_set_inode_flags(struct inode *inode)
GFS2_DIF_APPENDONLY| \ GFS2_DIF_APPENDONLY| \
GFS2_DIF_NOATIME| \ GFS2_DIF_NOATIME| \
GFS2_DIF_SYNC| \ GFS2_DIF_SYNC| \
GFS2_DIF_SYSTEM| \
GFS2_DIF_TOPDIR| \ GFS2_DIF_TOPDIR| \
GFS2_DIF_INHERIT_JDATA) GFS2_DIF_INHERIT_JDATA)
...@@ -249,10 +231,6 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask) ...@@ -249,10 +231,6 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask)
if ((new_flags ^ flags) == 0) if ((new_flags ^ flags) == 0)
goto out; goto out;
error = -EINVAL;
if ((new_flags ^ flags) & ~GFS2_FLAGS_USER_SET)
goto out;
error = -EPERM; error = -EPERM;
if (IS_IMMUTABLE(inode) && (new_flags & GFS2_DIF_IMMUTABLE)) if (IS_IMMUTABLE(inode) && (new_flags & GFS2_DIF_IMMUTABLE))
goto out; goto out;
...@@ -303,19 +281,33 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask) ...@@ -303,19 +281,33 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask)
static int gfs2_set_flags(struct file *filp, u32 __user *ptr) static int gfs2_set_flags(struct file *filp, u32 __user *ptr)
{ {
struct inode *inode = file_inode(filp); struct inode *inode = file_inode(filp);
u32 fsflags, gfsflags; u32 fsflags, gfsflags = 0;
u32 mask;
int i;
if (get_user(fsflags, ptr)) if (get_user(fsflags, ptr))
return -EFAULT; return -EFAULT;
gfsflags = fsflags_cvt(fsflags_to_gfs2, fsflags); for (i = 0; i < ARRAY_SIZE(fsflag_gfs2flag); i++) {
if (!S_ISDIR(inode->i_mode)) { if (fsflags & fsflag_gfs2flag[i].fsflag) {
gfsflags &= ~GFS2_DIF_TOPDIR; fsflags &= ~fsflag_gfs2flag[i].fsflag;
if (gfsflags & GFS2_DIF_INHERIT_JDATA) gfsflags |= fsflag_gfs2flag[i].gfsflag;
gfsflags ^= (GFS2_DIF_JDATA | GFS2_DIF_INHERIT_JDATA); }
return do_gfs2_set_flags(filp, gfsflags, ~GFS2_DIF_SYSTEM); }
if (fsflags || gfsflags & ~GFS2_FLAGS_USER_SET)
return -EINVAL;
mask = GFS2_FLAGS_USER_SET;
if (S_ISDIR(inode->i_mode)) {
mask &= ~GFS2_DIF_JDATA;
} else {
/* The GFS2_DIF_TOPDIR flag is only valid for directories. */
if (gfsflags & GFS2_DIF_TOPDIR)
return -EINVAL;
mask &= ~(GFS2_DIF_TOPDIR | GFS2_DIF_INHERIT_JDATA);
} }
return do_gfs2_set_flags(filp, gfsflags, ~(GFS2_DIF_SYSTEM | GFS2_DIF_JDATA));
return do_gfs2_set_flags(filp, gfsflags, mask);
} }
static long gfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) static long gfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment