Skip to content

Commit

Permalink
xfs: introduce per-inode DAX enablement
Browse files Browse the repository at this point in the history
Rather than just being able to turn DAX on and off via a mount
option, some applications may only want to enable DAX for certain
performance critical files in a filesystem.

This patch introduces a new inode flag to enable DAX in the v3 inode
di_flags2 field. It adds support for setting and clearing flags in
the di_flags2 field via the XFS_IOC_FSSETXATTR ioctl, and sets the
S_DAX inode flag appropriately when it is seen.

When this flag is set on a directory, it acts as an "inherit flag".
That is, inodes created in the directory will automatically inherit
the on-disk inode DAX flag, enabling administrators to set up
directory heirarchies that automatically use DAX. Setting this flag
on an empty root directory will make the entire filesystem use DAX
by default.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
  • Loading branch information
Dave Chinner authored and Dave Chinner committed Jan 4, 2016
1 parent e7b8948 commit 58f88ca
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 12 deletions.
9 changes: 9 additions & 0 deletions fs/xfs/libxfs/xfs_format.h
Original file line number Diff line number Diff line change
Expand Up @@ -1023,6 +1023,15 @@ static inline void xfs_dinode_put_rdev(struct xfs_dinode *dip, xfs_dev_t rdev)
XFS_DIFLAG_PROJINHERIT | XFS_DIFLAG_NOSYMLINKS | XFS_DIFLAG_EXTSIZE | \
XFS_DIFLAG_EXTSZINHERIT | XFS_DIFLAG_NODEFRAG | XFS_DIFLAG_FILESTREAM)

/*
* Values for di_flags2 These start by being exposed to userspace in the upper
* 16 bits of the XFS_XFLAG_s range.
*/
#define XFS_DIFLAG2_DAX_BIT 0 /* use DAX for this inode */
#define XFS_DIFLAG2_DAX (1 << XFS_DIFLAG2_DAX_BIT)

#define XFS_DIFLAG2_ANY (XFS_DIFLAG2_DAX)

/*
* Inode number format:
* low inopblog bits - offset in block
Expand Down
32 changes: 23 additions & 9 deletions fs/xfs/xfs_inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -610,7 +610,9 @@ __xfs_iflock(

STATIC uint
_xfs_dic2xflags(
__uint16_t di_flags)
__uint16_t di_flags,
uint64_t di_flags2,
bool has_attr)
{
uint flags = 0;

Expand Down Expand Up @@ -645,25 +647,32 @@ _xfs_dic2xflags(
flags |= FS_XFLAG_FILESTREAM;
}

if (di_flags2 & XFS_DIFLAG2_ANY) {
if (di_flags2 & XFS_DIFLAG2_DAX)
flags |= FS_XFLAG_DAX;
}

if (has_attr)
flags |= FS_XFLAG_HASATTR;

return flags;
}

uint
xfs_ip2xflags(
xfs_inode_t *ip)
struct xfs_inode *ip)
{
xfs_icdinode_t *dic = &ip->i_d;
struct xfs_icdinode *dic = &ip->i_d;

return _xfs_dic2xflags(dic->di_flags) |
(XFS_IFORK_Q(ip) ? FS_XFLAG_HASATTR : 0);
return _xfs_dic2xflags(dic->di_flags, dic->di_flags2, XFS_IFORK_Q(ip));
}

uint
xfs_dic2xflags(
xfs_dinode_t *dip)
struct xfs_dinode *dip)
{
return _xfs_dic2xflags(be16_to_cpu(dip->di_flags)) |
(XFS_DFORK_Q(dip) ? FS_XFLAG_HASATTR : 0);
return _xfs_dic2xflags(be16_to_cpu(dip->di_flags),
be64_to_cpu(dip->di_flags2), XFS_DFORK_Q(dip));
}

/*
Expand Down Expand Up @@ -862,7 +871,8 @@ xfs_ialloc(
case S_IFREG:
case S_IFDIR:
if (pip && (pip->i_d.di_flags & XFS_DIFLAG_ANY)) {
uint di_flags = 0;
uint64_t di_flags2 = 0;
uint di_flags = 0;

if (S_ISDIR(mode)) {
if (pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT)
Expand Down Expand Up @@ -898,7 +908,11 @@ xfs_ialloc(
di_flags |= XFS_DIFLAG_NODEFRAG;
if (pip->i_d.di_flags & XFS_DIFLAG_FILESTREAM)
di_flags |= XFS_DIFLAG_FILESTREAM;
if (pip->i_d.di_flags2 & XFS_DIFLAG2_DAX)
di_flags2 |= XFS_DIFLAG2_DAX;

ip->i_d.di_flags |= di_flags;
ip->i_d.di_flags2 |= di_flags2;
}
/* FALLTHROUGH */
case S_IFLNK:
Expand Down
18 changes: 17 additions & 1 deletion fs/xfs/xfs_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -945,6 +945,7 @@ xfs_set_diflags(
unsigned int xflags)
{
unsigned int di_flags;
uint64_t di_flags2;

/* can't set PREALLOC this way, just preserve it */
di_flags = (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC);
Expand Down Expand Up @@ -977,8 +978,18 @@ xfs_set_diflags(
if (xflags & FS_XFLAG_EXTSIZE)
di_flags |= XFS_DIFLAG_EXTSIZE;
}

ip->i_d.di_flags = di_flags;

/* diflags2 only valid for v3 inodes. */
if (ip->i_d.di_version < 3)
return;

di_flags2 = 0;
if (xflags & FS_XFLAG_DAX)
di_flags2 |= XFS_DIFLAG2_DAX;

ip->i_d.di_flags2 = di_flags2;

}

STATIC void
Expand All @@ -1004,6 +1015,11 @@ xfs_diflags_to_linux(
inode->i_flags |= S_NOATIME;
else
inode->i_flags &= ~S_NOATIME;
if (xflags & FS_XFLAG_DAX)
inode->i_flags |= S_DAX;
else
inode->i_flags &= ~S_DAX;

}

static int
Expand Down
4 changes: 2 additions & 2 deletions fs/xfs/xfs_iops.c
Original file line number Diff line number Diff line change
Expand Up @@ -1201,8 +1201,8 @@ xfs_diflags_to_iflags(
inode->i_flags |= S_SYNC;
if (flags & XFS_DIFLAG_NOATIME)
inode->i_flags |= S_NOATIME;
/* XXX: Also needs an on-disk per inode flag! */
if (ip->i_mount->m_flags & XFS_MOUNT_DAX)
if (ip->i_mount->m_flags & XFS_MOUNT_DAX ||
ip->i_d.di_flags2 & XFS_DIFLAG2_DAX)
inode->i_flags |= S_DAX;
}

Expand Down
1 change: 1 addition & 0 deletions include/uapi/linux/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ struct fsxattr {
#define FS_XFLAG_EXTSZINHERIT 0x00001000 /* inherit inode extent size */
#define FS_XFLAG_NODEFRAG 0x00002000 /* do not defragment */
#define FS_XFLAG_FILESTREAM 0x00004000 /* use filestream allocator */
#define FS_XFLAG_DAX 0x00008000 /* use DAX for IO */
#define FS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */

/* the read-only stuff doesn't really belong here, but any other place is
Expand Down

0 comments on commit 58f88ca

Please sign in to comment.