Commit 29309a4e authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'gfs2-4.15.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2

Pull gfs2 updates from Bob Peterson:
 "We've got a total of 17 GFS2 patches for this merge window. The
  patches are basically in three categories: (1) patches related to
  broken xfstest cases, (2) patches related to improving iomap and start
  using it in GFS2, and (3) general typos and clarifications.

  Please note that one of the iomap patches extends beyond GFS2 and
  affects other file systems, but it was publically reviewed by a
  variety of file system people in the community.

  From Andreas Gruenbacher:

   - rename variable 'bsize' to 'factor' to clarify the logic related to
     gfs2_block_map.

   - correctly set ctime in the setflags ioctl, which fixes broken
     xfstests test 277.

   - fix broken xfstest 258, due to an atime initialization problem.

   - fix broken xfstest 307, in which GFS2 was not setting ctime when
     setting acls.

   - switch general iomap code from blkno to disk offset for a variety
     of file systems.

   - add a new IOMAP_F_DATA_INLINE flag for iomap to indicate blocks
     that have data mixed with metadata.

   - implement SEEK_HOLE and SEEK_DATA via iomap in GFS2.

   - fix failing xfstest case 066, which was due to not properly syncing
     dirty inodes when changing extended attributes.

   - fix a minor typo in a comment.

   - partially fix xfstest 424, which involved GET_FLAGS and SET_FLAGS
     ioctl. This is also a cleanup and simplification of the translation
     of flags from fs flags to gfs2 flags.

   - add support for STATX_ATTR_ in statx, which fixed broken xfstest
     424.

   - fix for failing xfstest 093 which fixes a recursive glock problem
     with gfs2_xattr_get and _set

  From me:

   - make inode height info part of the 'metapath' data structure to
     facilitate using iomap in GFS2.

   - start using iomap inside GFS2 and switch GFS2's block_map functions
     to use iomap under the covers.

   - switch GFS2's fiemap implementation from using block_map to using
     iomap under the covers.

   - fix journaled data pages not being properly synced to media when
     writing inodes. This was caught with xfstests.

   - fix another failing xfstest case in which switching a file from
     ordered_write to journaled data via set_flags caused a deadlock"

* tag 'gfs2-4.15.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2:
  gfs2: Allow gfs2_xattr_set to be called with the glock held
  gfs2: Add support for statx inode flags
  gfs2: Fix and clean up {GET,SET}FLAGS ioctl
  gfs2: Fix a harmless typo
  gfs2: Fix xattr fsync
  GFS2: Take inode off order_write list when setting jdata flag
  GFS2: flush the log and all pages for jdata as we do for WB_SYNC_ALL
  gfs2: Implement SEEK_HOLE / SEEK_DATA via iomap
  GFS2: Switch fiemap implementation to use iomap
  GFS2: Implement iomap for block_map
  GFS2: Make height info part of metapath
  gfs2: Always update inode ctime in set_acl
  gfs2: Support negative atimes
  gfs2: Update ctime in setflags ioctl
  gfs2: Clarify gfs2_block_map
parents ac446dcc d0920a9c
...@@ -4,6 +4,7 @@ config GFS2_FS ...@@ -4,6 +4,7 @@ config GFS2_FS
select FS_POSIX_ACL select FS_POSIX_ACL
select CRC32 select CRC32
select QUOTACTL select QUOTACTL
select FS_IOMAP
help help
A cluster filesystem. A cluster filesystem.
......
...@@ -141,6 +141,7 @@ int gfs2_set_acl(struct inode *inode, struct posix_acl *acl, int type) ...@@ -141,6 +141,7 @@ int gfs2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
ret = __gfs2_set_acl(inode, acl, type); ret = __gfs2_set_acl(inode, acl, type);
if (!ret && mode != inode->i_mode) { if (!ret && mode != inode->i_mode) {
inode->i_ctime = current_time(inode);
inode->i_mode = mode; inode->i_mode = mode;
mark_inode_dirty(inode); mark_inode_dirty(inode);
} }
......
This diff is collapsed.
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
#ifndef __BMAP_DOT_H__ #ifndef __BMAP_DOT_H__
#define __BMAP_DOT_H__ #define __BMAP_DOT_H__
#include <linux/iomap.h>
#include "inode.h" #include "inode.h"
struct inode; struct inode;
...@@ -47,6 +49,8 @@ static inline void gfs2_write_calc_reserv(const struct gfs2_inode *ip, ...@@ -47,6 +49,8 @@ static inline void gfs2_write_calc_reserv(const struct gfs2_inode *ip,
extern int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page); extern int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page);
extern int gfs2_block_map(struct inode *inode, sector_t lblock, extern int gfs2_block_map(struct inode *inode, sector_t lblock,
struct buffer_head *bh, int create); struct buffer_head *bh, int create);
extern int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length,
unsigned flags, struct iomap *iomap);
extern int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, extern int gfs2_extent_map(struct inode *inode, u64 lblock, int *new,
u64 *dblock, unsigned *extlen); u64 *dblock, unsigned *extlen);
extern int gfs2_setattr_size(struct inode *inode, u64 size); extern int gfs2_setattr_size(struct inode *inode, u64 size);
......
...@@ -60,9 +60,7 @@ static loff_t gfs2_llseek(struct file *file, loff_t offset, int whence) ...@@ -60,9 +60,7 @@ static loff_t gfs2_llseek(struct file *file, loff_t offset, int whence)
loff_t error; loff_t error;
switch (whence) { switch (whence) {
case SEEK_END: /* These reference inode->i_size */ case SEEK_END:
case SEEK_DATA:
case SEEK_HOLE:
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY,
&i_gh); &i_gh);
if (!error) { if (!error) {
...@@ -70,8 +68,21 @@ static loff_t gfs2_llseek(struct file *file, loff_t offset, int whence) ...@@ -70,8 +68,21 @@ static loff_t gfs2_llseek(struct file *file, loff_t offset, int whence)
gfs2_glock_dq_uninit(&i_gh); gfs2_glock_dq_uninit(&i_gh);
} }
break; break;
case SEEK_DATA:
error = gfs2_seek_data(file, offset);
break;
case SEEK_HOLE:
error = gfs2_seek_hole(file, offset);
break;
case SEEK_CUR: case SEEK_CUR:
case SEEK_SET: case SEEK_SET:
/*
* These don't reference inode->i_size and don't depend on the
* block mapping, so we don't need the glock.
*/
error = generic_file_llseek(file, offset, whence); error = generic_file_llseek(file, offset, whence);
break; break;
default: default:
...@@ -108,45 +119,22 @@ static int gfs2_readdir(struct file *file, struct dir_context *ctx) ...@@ -108,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
* GFS2's own flags values.
* *
* Returns: the converted flags * The FS_JOURNAL_DATA_FL flag maps to GFS2_DIF_INHERIT_JDATA for directories,
* and to GFS2_DIF_JDATA for non-directories.
*/ */
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)
...@@ -154,17 +142,23 @@ static int gfs2_get_flags(struct file *filp, u32 __user *ptr) ...@@ -154,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;
...@@ -199,7 +193,6 @@ void gfs2_set_inode_flags(struct inode *inode) ...@@ -199,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)
...@@ -238,10 +231,6 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask) ...@@ -238,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;
...@@ -256,7 +245,7 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask) ...@@ -256,7 +245,7 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask)
goto out; goto out;
} }
if ((flags ^ new_flags) & GFS2_DIF_JDATA) { if ((flags ^ new_flags) & GFS2_DIF_JDATA) {
if (flags & GFS2_DIF_JDATA) if (new_flags & GFS2_DIF_JDATA)
gfs2_log_flush(sdp, ip->i_gl, NORMAL_FLUSH); gfs2_log_flush(sdp, ip->i_gl, NORMAL_FLUSH);
error = filemap_fdatawrite(inode->i_mapping); error = filemap_fdatawrite(inode->i_mapping);
if (error) if (error)
...@@ -264,6 +253,8 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask) ...@@ -264,6 +253,8 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask)
error = filemap_fdatawait(inode->i_mapping); error = filemap_fdatawait(inode->i_mapping);
if (error) if (error)
goto out; goto out;
if (new_flags & GFS2_DIF_JDATA)
gfs2_ordered_del_inode(ip);
} }
error = gfs2_trans_begin(sdp, RES_DINODE, 0); error = gfs2_trans_begin(sdp, RES_DINODE, 0);
if (error) if (error)
...@@ -271,6 +262,7 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask) ...@@ -271,6 +262,7 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask)
error = gfs2_meta_inode_buffer(ip, &bh); error = gfs2_meta_inode_buffer(ip, &bh);
if (error) if (error)
goto out_trans_end; goto out_trans_end;
inode->i_ctime = current_time(inode);
gfs2_trans_add_meta(ip->i_gl, bh); gfs2_trans_add_meta(ip->i_gl, bh);
ip->i_diskflags = new_flags; ip->i_diskflags = new_flags;
gfs2_dinode_out(ip, bh->b_data); gfs2_dinode_out(ip, bh->b_data);
...@@ -289,19 +281,33 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask) ...@@ -289,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);
} }
return do_gfs2_set_flags(filp, gfsflags, ~(GFS2_DIF_SYSTEM | GFS2_DIF_JDATA)); }
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, 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)
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
#include <linux/posix_acl.h> #include <linux/posix_acl.h>
#include <linux/gfs2_ondisk.h> #include <linux/gfs2_ondisk.h>
#include <linux/crc32.h> #include <linux/crc32.h>
#include <linux/fiemap.h> #include <linux/iomap.h>
#include <linux/security.h> #include <linux/security.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
...@@ -189,7 +189,8 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type, ...@@ -189,7 +189,8 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
gfs2_set_iop(inode); gfs2_set_iop(inode);
inode->i_atime.tv_sec = 0; /* Lowest possible timestamp; will be overwritten in gfs2_dinode_in. */
inode->i_atime.tv_sec = 1LL << (8 * sizeof(inode->i_atime.tv_sec) - 1);
inode->i_atime.tv_nsec = 0; inode->i_atime.tv_nsec = 0;
unlock_new_inode(inode); unlock_new_inode(inode);
...@@ -1986,6 +1987,7 @@ static int gfs2_getattr(const struct path *path, struct kstat *stat, ...@@ -1986,6 +1987,7 @@ static int gfs2_getattr(const struct path *path, struct kstat *stat,
struct inode *inode = d_inode(path->dentry); struct inode *inode = d_inode(path->dentry);
struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_holder gh; struct gfs2_holder gh;
u32 gfsflags;
int error; int error;
gfs2_holder_mark_uninitialized(&gh); gfs2_holder_mark_uninitialized(&gh);
...@@ -1995,13 +1997,30 @@ static int gfs2_getattr(const struct path *path, struct kstat *stat, ...@@ -1995,13 +1997,30 @@ static int gfs2_getattr(const struct path *path, struct kstat *stat,
return error; return error;
} }
gfsflags = ip->i_diskflags;
if (gfsflags & GFS2_DIF_APPENDONLY)
stat->attributes |= STATX_ATTR_APPEND;
if (gfsflags & GFS2_DIF_IMMUTABLE)
stat->attributes |= STATX_ATTR_IMMUTABLE;
stat->attributes_mask |= (STATX_ATTR_APPEND |
STATX_ATTR_COMPRESSED |
STATX_ATTR_ENCRYPTED |
STATX_ATTR_IMMUTABLE |
STATX_ATTR_NODUMP);
generic_fillattr(inode, stat); generic_fillattr(inode, stat);
if (gfs2_holder_initialized(&gh)) if (gfs2_holder_initialized(&gh))
gfs2_glock_dq_uninit(&gh); gfs2_glock_dq_uninit(&gh);
return 0; return 0;
} }
const struct iomap_ops gfs2_iomap_ops = {
.iomap_begin = gfs2_iomap_begin,
};
static int gfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, static int gfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
u64 start, u64 len) u64 start, u64 len)
{ {
...@@ -2009,39 +2028,57 @@ static int gfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, ...@@ -2009,39 +2028,57 @@ static int gfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
struct gfs2_holder gh; struct gfs2_holder gh;
int ret; int ret;
ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC); inode_lock_shared(inode);
if (ret)
return ret;
inode_lock(inode);
ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &gh); ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &gh);
if (ret) if (ret)
goto out; goto out;
if (gfs2_is_stuffed(ip)) { ret = iomap_fiemap(inode, fieinfo, start, len, &gfs2_iomap_ops);
u64 phys = ip->i_no_addr << inode->i_blkbits;
u64 size = i_size_read(inode);
u32 flags = FIEMAP_EXTENT_LAST|FIEMAP_EXTENT_NOT_ALIGNED|
FIEMAP_EXTENT_DATA_INLINE;
phys += sizeof(struct gfs2_dinode);
phys += start;
if (start + len > size)
len = size - start;
if (start < size)
ret = fiemap_fill_next_extent(fieinfo, start, phys,
len, flags);
if (ret == 1)
ret = 0;
} else {
ret = __generic_block_fiemap(inode, fieinfo, start, len,
gfs2_block_map);
}
gfs2_glock_dq_uninit(&gh); gfs2_glock_dq_uninit(&gh);
out: out:
inode_unlock(inode); inode_unlock_shared(inode);
return ret;
}
loff_t gfs2_seek_data(struct file *file, loff_t offset)
{
struct inode *inode = file->f_mapping->host;
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_holder gh;
loff_t ret;
inode_lock_shared(inode);
ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &gh);
if (!ret)
ret = iomap_seek_data(inode, offset, &gfs2_iomap_ops);
gfs2_glock_dq_uninit(&gh);
inode_unlock_shared(inode);
if (ret < 0)
return ret;
return vfs_setpos(file, ret, inode->i_sb->s_maxbytes);
}
loff_t gfs2_seek_hole(struct file *file, loff_t offset)
{
struct inode *inode = file->f_mapping->host;
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_holder gh;
loff_t ret;
inode_lock_shared(inode);
ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &gh);
if (!ret)
ret = iomap_seek_hole(inode, offset, &gfs2_iomap_ops);
gfs2_glock_dq_uninit(&gh);
inode_unlock_shared(inode);
if (ret < 0)
return ret; return ret;
return vfs_setpos(file, ret, inode->i_sb->s_maxbytes);
} }
const struct inode_operations gfs2_file_iops = { const struct inode_operations gfs2_file_iops = {
......
...@@ -109,6 +109,8 @@ extern int gfs2_setattr_simple(struct inode *inode, struct iattr *attr); ...@@ -109,6 +109,8 @@ extern int gfs2_setattr_simple(struct inode *inode, struct iattr *attr);
extern struct inode *gfs2_lookup_simple(struct inode *dip, const char *name); extern struct inode *gfs2_lookup_simple(struct inode *dip, const char *name);
extern void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf); extern void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf);
extern int gfs2_open_common(struct inode *inode, struct file *file); extern int gfs2_open_common(struct inode *inode, struct file *file);
extern loff_t gfs2_seek_data(struct file *file, loff_t offset);
extern loff_t gfs2_seek_hole(struct file *file, loff_t offset);
extern const struct inode_operations gfs2_file_iops; extern const struct inode_operations gfs2_file_iops;
extern const struct inode_operations gfs2_dir_iops; extern const struct inode_operations gfs2_dir_iops;
......
...@@ -754,14 +754,15 @@ static int gfs2_write_inode(struct inode *inode, struct writeback_control *wbc) ...@@ -754,14 +754,15 @@ static int gfs2_write_inode(struct inode *inode, struct writeback_control *wbc)
struct address_space *metamapping = gfs2_glock2aspace(ip->i_gl); struct address_space *metamapping = gfs2_glock2aspace(ip->i_gl);
struct backing_dev_info *bdi = inode_to_bdi(metamapping->host); struct backing_dev_info *bdi = inode_to_bdi(metamapping->host);
int ret = 0; int ret = 0;
bool flush_all = (wbc->sync_mode == WB_SYNC_ALL || gfs2_is_jdata(ip));
if (wbc->sync_mode == WB_SYNC_ALL) if (flush_all)
gfs2_log_flush(GFS2_SB(inode), ip->i_gl, NORMAL_FLUSH); gfs2_log_flush(GFS2_SB(inode), ip->i_gl, NORMAL_FLUSH);
if (bdi->wb.dirty_exceeded) if (bdi->wb.dirty_exceeded)
gfs2_ail1_flush(sdp, wbc); gfs2_ail1_flush(sdp, wbc);
else else
filemap_fdatawrite(metamapping); filemap_fdatawrite(metamapping);
if (wbc->sync_mode == WB_SYNC_ALL) if (flush_all)
ret = filemap_fdatawait(metamapping); ret = filemap_fdatawait(metamapping);
if (ret) if (ret)
mark_inode_dirty_sync(inode); mark_inode_dirty_sync(inode);
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/gfs2_ondisk.h> #include <linux/gfs2_ondisk.h>
#include <linux/writeback.h> #include <linux/writeback.h>
#include <linux/ktime.h> #include <linux/ktime.h>
#include <linux/iomap.h>
#include "incore.h" #include "incore.h"
#include "glock.h" #include "glock.h"
#include "rgrp.h" #include "rgrp.h"
...@@ -470,6 +471,70 @@ TRACE_EVENT(gfs2_bmap, ...@@ -470,6 +471,70 @@ TRACE_EVENT(gfs2_bmap,
__entry->errno) __entry->errno)
); );
TRACE_EVENT(gfs2_iomap_start,
TP_PROTO(const struct gfs2_inode *ip, loff_t pos, ssize_t length,
u16 flags),
TP_ARGS(ip, pos, length, flags),
TP_STRUCT__entry(
__field( dev_t, dev )
__field( u64, inum )
__field( loff_t, pos )
__field( ssize_t, length )
__field( u16, flags )
),
TP_fast_assign(
__entry->dev = ip->i_gl->gl_name.ln_sbd->sd_vfs->s_dev;
__entry->inum = ip->i_no_addr;
__entry->pos = pos;
__entry->length = length;
__entry->flags = flags;
),
TP_printk("%u,%u bmap %llu iomap start %llu/%lu flags:%08x",
MAJOR(__entry->dev), MINOR(__entry->dev),
(unsigned long long)__entry->inum,
(unsigned long long)__entry->pos,
(unsigned long)__entry->length, (u16)__entry->flags)
);
TRACE_EVENT(gfs2_iomap_end,
TP_PROTO(const struct gfs2_inode *ip, struct iomap *iomap, int ret),
TP_ARGS(ip, iomap, ret),
TP_STRUCT__entry(
__field( dev_t, dev )
__field( u64, inum )
__field( loff_t, offset )
__field( ssize_t, length )
__field( u16, flags )
__field( u16, type )
__field( int, ret )
),
TP_fast_assign(
__entry->dev = ip->i_gl->gl_name.ln_sbd->sd_vfs->s_dev;
__entry->inum = ip->i_no_addr;
__entry->offset = iomap->offset;
__entry->length = iomap->length;
__entry->flags = iomap->flags;
__entry->type = iomap->type;
__entry->ret = ret;
),
TP_printk("%u,%u bmap %llu iomap end %llu/%lu ty:%d flags:%08x rc:%d",
MAJOR(__entry->dev), MINOR(__entry->dev),
(unsigned long long)__entry->inum,
(unsigned long long)__entry->offset,
(unsigned long)__entry->length, (u16)__entry->type,
(u16)__entry->flags, __entry->ret)
);
/* Keep track of blocks as they are allocated/freed */ /* Keep track of blocks as they are allocated/freed */
TRACE_EVENT(gfs2_block_alloc, TRACE_EVENT(gfs2_block_alloc,
......
...@@ -145,7 +145,7 @@ static struct gfs2_bufdata *gfs2_alloc_bufdata(struct gfs2_glock *gl, ...@@ -145,7 +145,7 @@ static struct gfs2_bufdata *gfs2_alloc_bufdata(struct gfs2_glock *gl,
* *
* This is used in two distinct cases: * This is used in two distinct cases:
* i) In ordered write mode * i) In ordered write mode
* We put the data buffer on a list so that we can ensure that its * We put the data buffer on a list so that we can ensure that it's
* synced to disk at the right time * synced to disk at the right time
* ii) In journaled data mode * ii) In journaled data mode
* We need to journal the data block in the same way as metadata in * We need to journal the data block in the same way as metadata in
......
...@@ -231,7 +231,6 @@ static int ea_dealloc_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh, ...@@ -231,7 +231,6 @@ static int ea_dealloc_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh,
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_rgrpd *rgd; struct gfs2_rgrpd *rgd;
struct gfs2_holder rg_gh; struct gfs2_holder rg_gh;
struct buffer_head *dibh;
__be64 *dataptrs; __be64 *dataptrs;
u64 bn = 0; u64 bn = 0;
u64 bstart = 0; u64 bstart = 0;
...@@ -308,13 +307,8 @@ static int ea_dealloc_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh, ...@@ -308,13 +307,8 @@ static int ea_dealloc_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh,
ea->ea_num_ptrs = 0; ea->ea_num_ptrs = 0;
} }
error = gfs2_meta_inode_buffer(ip, &dibh);
if (!error) {
ip->i_inode.i_ctime = current_time(&ip->i_inode); ip->i_inode.i_ctime = current_time(&ip->i_inode);
gfs2_trans_add_meta(ip->i_gl, dibh); __mark_inode_dirty(&ip->i_inode, I_DIRTY_SYNC | I_DIRTY_DATASYNC);
gfs2_dinode_out(ip, dibh->b_data);
brelse(dibh);
}
gfs2_trans_end(sdp); gfs2_trans_end(sdp);
...@@ -616,7 +610,6 @@ static int gfs2_xattr_get(const struct xattr_handler *handler, ...@@ -616,7 +610,6 @@ static int gfs2_xattr_get(const struct xattr_handler *handler,
{ {
struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_holder gh; struct gfs2_holder gh;
bool need_unlock = false;
int ret; int ret;
/* During lookup, SELinux calls this function with the glock locked. */ /* During lookup, SELinux calls this function with the glock locked. */
...@@ -625,10 +618,11 @@ static int gfs2_xattr_get(const struct xattr_handler *handler, ...@@ -625,10 +618,11 @@ static int gfs2_xattr_get(const struct xattr_handler *handler,
ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh); ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh);
if (ret) if (ret)
return ret; return ret;
need_unlock = true; } else {
gfs2_holder_mark_uninitialized(&gh);
} }
ret = __gfs2_xattr_get(inode, name, buffer, size, handler->flags); ret = __gfs2_xattr_get(inode, name, buffer, size, handler->flags);
if (need_unlock) if (gfs2_holder_initialized(&gh))
gfs2_glock_dq_uninit(&gh); gfs2_glock_dq_uninit(&gh);
return ret; return ret;
} }
...@@ -749,7 +743,6 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er, ...@@ -749,7 +743,6 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er,
ea_skeleton_call_t skeleton_call, void *private) ea_skeleton_call_t skeleton_call, void *private)
{ {
struct gfs2_alloc_parms ap = { .target = blks }; struct gfs2_alloc_parms ap = { .target = blks };
struct buffer_head *dibh;
int error; int error;
error = gfs2_rindex_update(GFS2_SB(&ip->i_inode)); error = gfs2_rindex_update(GFS2_SB(&ip->i_inode));
...@@ -774,13 +767,8 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er, ...@@ -774,13 +767,8 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er,
if (error) if (error)
goto out_end_trans; goto out_end_trans;
error = gfs2_meta_inode_buffer(ip, &dibh);
if (!error) {
ip->i_inode.i_ctime = current_time(&ip->i_inode); ip->i_inode.i_ctime = current_time(&ip->i_inode);
gfs2_trans_add_meta(ip->i_gl, dibh); __mark_inode_dirty(&ip->i_inode, I_DIRTY_SYNC | I_DIRTY_DATASYNC);
gfs2_dinode_out(ip, dibh->b_data);
brelse(dibh);
}
out_end_trans: out_end_trans:
gfs2_trans_end(GFS2_SB(&ip->i_inode)); gfs2_trans_end(GFS2_SB(&ip->i_inode));
...@@ -891,7 +879,6 @@ static int ea_set_simple_noalloc(struct gfs2_inode *ip, struct buffer_head *bh, ...@@ -891,7 +879,6 @@ static int ea_set_simple_noalloc(struct gfs2_inode *ip, struct buffer_head *bh,
struct gfs2_ea_header *ea, struct ea_set *es) struct gfs2_ea_header *ea, struct ea_set *es)
{ {
struct gfs2_ea_request *er = es->es_er; struct gfs2_ea_request *er = es->es_er;
struct buffer_head *dibh;
int error; int error;
error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE + 2 * RES_EATTR, 0); error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE + 2 * RES_EATTR, 0);
...@@ -908,14 +895,9 @@ static int ea_set_simple_noalloc(struct gfs2_inode *ip, struct buffer_head *bh, ...@@ -908,14 +895,9 @@ static int ea_set_simple_noalloc(struct gfs2_inode *ip, struct buffer_head *bh,
if (es->es_el) if (es->es_el)
ea_set_remove_stuffed(ip, es->es_el); ea_set_remove_stuffed(ip, es->es_el);
error = gfs2_meta_inode_buffer(ip, &dibh);
if (error)
goto out;
ip->i_inode.i_ctime = current_time(&ip->i_inode); ip->i_inode.i_ctime = current_time(&ip->i_inode);
gfs2_trans_add_meta(ip->i_gl, dibh); __mark_inode_dirty(&ip->i_inode, I_DIRTY_SYNC | I_DIRTY_DATASYNC);
gfs2_dinode_out(ip, dibh->b_data);
brelse(dibh);
out:
gfs2_trans_end(GFS2_SB(&ip->i_inode)); gfs2_trans_end(GFS2_SB(&ip->i_inode));
return error; return error;
} }
...@@ -1111,7 +1093,6 @@ static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el) ...@@ -1111,7 +1093,6 @@ static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el)
{ {
struct gfs2_ea_header *ea = el->el_ea; struct gfs2_ea_header *ea = el->el_ea;
struct gfs2_ea_header *prev = el->el_prev; struct gfs2_ea_header *prev = el->el_prev;
struct buffer_head *dibh;
int error; int error;
error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE + RES_EATTR, 0); error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE + RES_EATTR, 0);
...@@ -1132,13 +1113,8 @@ static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el) ...@@ -1132,13 +1113,8 @@ static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el)
ea->ea_type = GFS2_EATYPE_UNUSED; ea->ea_type = GFS2_EATYPE_UNUSED;
} }
error = gfs2_meta_inode_buffer(ip, &dibh);
if (!error) {
ip->i_inode.i_ctime = current_time(&ip->i_inode); ip->i_inode.i_ctime = current_time(&ip->i_inode);
gfs2_trans_add_meta(ip->i_gl, dibh); __mark_inode_dirty(&ip->i_inode, I_DIRTY_SYNC | I_DIRTY_DATASYNC);
gfs2_dinode_out(ip, dibh->b_data);
brelse(dibh);
}
gfs2_trans_end(GFS2_SB(&ip->i_inode)); gfs2_trans_end(GFS2_SB(&ip->i_inode));
...@@ -1268,10 +1244,19 @@ static int gfs2_xattr_set(const struct xattr_handler *handler, ...@@ -1268,10 +1244,19 @@ static int gfs2_xattr_set(const struct xattr_handler *handler,
if (ret) if (ret)
return ret; return ret;
/* May be called from gfs_setattr with the glock locked. */
if (!gfs2_glock_is_locked_by_me(ip->i_gl)) {
ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
if (ret) if (ret)
return ret; return ret;
} else {
if (WARN_ON_ONCE(ip->i_gl->gl_state != LM_ST_EXCLUSIVE))
return -EIO;
gfs2_holder_mark_uninitialized(&gh);
}
ret = __gfs2_xattr_set(inode, name, value, size, flags, handler->flags); ret = __gfs2_xattr_set(inode, name, value, size, flags, handler->flags);
if (gfs2_holder_initialized(&gh))
gfs2_glock_dq_uninit(&gh); gfs2_glock_dq_uninit(&gh);
return ret; return ret;
} }
......
...@@ -23,6 +23,7 @@ struct vm_fault; ...@@ -23,6 +23,7 @@ struct vm_fault;
* Flags for all iomap mappings: * Flags for all iomap mappings:
*/ */
#define IOMAP_F_NEW 0x01 /* blocks have been newly allocated */ #define IOMAP_F_NEW 0x01 /* blocks have been newly allocated */
#define IOMAP_F_BOUNDARY 0x02 /* mapping ends at metadata boundary */
/* /*
* Flags that only need to be reported for IOMAP_REPORT requests: * Flags that only need to be reported for IOMAP_REPORT requests:
......
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