* [v13 4/5] ext4: adds FS_IOC_FSSETXATTR/FS_IOC_FSGETXATTR interface support
From: Li Xi @ 2015-04-20 1:39 UTC (permalink / raw)
To: linux-fsdevel, linux-ext4, linux-api, tytso, adilger, jack, viro,
hch, dmonakhov
In-Reply-To: <1429493988-16819-1-git-send-email-lixi@ddn.com>
This patch adds FS_IOC_FSSETXATTR/FS_IOC_FSGETXATTR ioctl interface
support for ext4. The interface is kept consistent with
XFS_IOC_FSGETXATTR/XFS_IOC_FSGETXATTR.
Signed-off-by: Li Xi <lixi@ddn.com>
---
fs/ext4/ext4.h | 9 ++
fs/ext4/ioctl.c | 364 +++++++++++++++++++++++++++++++++++-----------
fs/xfs/xfs_fs.h | 47 +++----
include/uapi/linux/fs.h | 32 ++++
4 files changed, 335 insertions(+), 117 deletions(-)
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index a7acf10..2d5a097 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -384,6 +384,13 @@ struct flex_groups {
#define EXT4_FL_USER_VISIBLE 0x304BDFFF /* User visible flags */
#define EXT4_FL_USER_MODIFIABLE 0x204380FF /* User modifiable flags */
+#define EXT4_FL_XFLAG_VISIBLE (EXT4_SYNC_FL | \
+ EXT4_IMMUTABLE_FL | \
+ EXT4_APPEND_FL | \
+ EXT4_NODUMP_FL | \
+ EXT4_NOATIME_FL | \
+ EXT4_PROJINHERIT_FL)
+
/* Flags that should be inherited by new inodes from their parent. */
#define EXT4_FL_INHERITED (EXT4_SECRM_FL | EXT4_UNRM_FL | EXT4_COMPR_FL |\
EXT4_SYNC_FL | EXT4_NODUMP_FL | EXT4_NOATIME_FL |\
@@ -606,6 +613,8 @@ enum {
#define EXT4_IOC_RESIZE_FS _IOW('f', 16, __u64)
#define EXT4_IOC_SWAP_BOOT _IO('f', 17)
#define EXT4_IOC_PRECACHE_EXTENTS _IO('f', 18)
+#define EXT4_IOC_FSGETXATTR FS_IOC_FSGETXATTR
+#define EXT4_IOC_FSSETXATTR FS_IOC_FSSETXATTR
#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
/*
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
index f58a0d1..27e50a8 100644
--- a/fs/ext4/ioctl.c
+++ b/fs/ext4/ioctl.c
@@ -14,6 +14,8 @@
#include <linux/compat.h>
#include <linux/mount.h>
#include <linux/file.h>
+#include <linux/quotaops.h>
+#include <linux/quota.h>
#include <asm/uaccess.h>
#include "ext4_jbd2.h"
#include "ext4.h"
@@ -196,6 +198,225 @@ journal_err_out:
return err;
}
+static int ext4_ioctl_setflags(struct inode *inode,
+ unsigned int flags)
+{
+ struct ext4_inode_info *ei = EXT4_I(inode);
+ handle_t *handle = NULL;
+ int err = EPERM, migrate = 0;
+ struct ext4_iloc iloc;
+ unsigned int oldflags, mask, i;
+ unsigned int jflag;
+
+ /* Is it quota file? Do not allow user to mess with it */
+ if (IS_NOQUOTA(inode))
+ goto flags_out;
+
+ oldflags = ei->i_flags;
+
+ /* 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;
+ }
+
+ /*
+ * The JOURNAL_DATA flag can only be changed by
+ * the relevant capability.
+ */
+ if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) {
+ if (!capable(CAP_SYS_RESOURCE))
+ goto flags_out;
+ }
+ if ((flags ^ oldflags) & EXT4_EXTENTS_FL)
+ migrate = 1;
+
+ if (flags & EXT4_EOFBLOCKS_FL) {
+ /* we don't support adding EOFBLOCKS flag */
+ if (!(oldflags & EXT4_EOFBLOCKS_FL)) {
+ err = -EOPNOTSUPP;
+ goto flags_out;
+ }
+ } else if (oldflags & EXT4_EOFBLOCKS_FL)
+ ext4_truncate(inode);
+
+ handle = ext4_journal_start(inode, EXT4_HT_INODE, 1);
+ if (IS_ERR(handle)) {
+ err = PTR_ERR(handle);
+ goto flags_out;
+ }
+ if (IS_SYNC(inode))
+ ext4_handle_sync(handle);
+ err = ext4_reserve_inode_write(handle, inode, &iloc);
+ if (err)
+ goto flags_err;
+
+ for (i = 0, mask = 1; i < 32; i++, mask <<= 1) {
+ if (!(mask & EXT4_FL_USER_MODIFIABLE))
+ continue;
+ if (mask & flags)
+ ext4_set_inode_flag(inode, i);
+ else
+ ext4_clear_inode_flag(inode, i);
+ }
+
+ ext4_set_inode_flags(inode);
+ inode->i_ctime = ext4_current_time(inode);
+
+ err = ext4_mark_iloc_dirty(handle, inode, &iloc);
+flags_err:
+ ext4_journal_stop(handle);
+ if (err)
+ goto flags_out;
+
+ if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL))
+ err = ext4_change_inode_journal_flag(inode, jflag);
+ if (err)
+ goto flags_out;
+ if (migrate) {
+ if (flags & EXT4_EXTENTS_FL)
+ err = ext4_ext_migrate(inode);
+ else
+ err = ext4_ind_migrate(inode);
+ }
+
+flags_out:
+ return err;
+}
+
+static int ext4_ioctl_setproject(struct file *filp, __u32 projid)
+{
+ struct inode *inode = file_inode(filp);
+ struct super_block *sb = inode->i_sb;
+ struct ext4_inode_info *ei = EXT4_I(inode);
+ int err;
+ handle_t *handle;
+ kprojid_t kprojid;
+ struct ext4_iloc iloc;
+ struct ext4_inode *raw_inode;
+
+ struct dquot *transfer_to[EXT4_MAXQUOTAS] = { };
+
+ if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
+ EXT4_FEATURE_RO_COMPAT_PROJECT)) {
+ BUG_ON(__kprojid_val(EXT4_I(inode)->i_projid)
+ != EXT4_DEF_PROJID);
+ if (projid != EXT4_DEF_PROJID)
+ return -EOPNOTSUPP;
+ else
+ return 0;
+ }
+
+ kprojid = make_kprojid(&init_user_ns, (projid_t)projid);
+
+ if (projid_eq(kprojid, EXT4_I(inode)->i_projid))
+ return 0;
+
+ err = mnt_want_write_file(filp);
+ if (err)
+ return err;
+
+ err = -EPERM;
+ mutex_lock(&inode->i_mutex);
+ /* Is it quota file? Do not allow user to mess with it */
+ if (IS_NOQUOTA(inode))
+ goto project_out;
+
+ dquot_initialize(inode);
+
+ handle = ext4_journal_start(inode, EXT4_HT_QUOTA,
+ EXT4_QUOTA_INIT_BLOCKS(sb) +
+ EXT4_QUOTA_DEL_BLOCKS(sb) + 3);
+ if (IS_ERR(handle)) {
+ err = PTR_ERR(handle);
+ goto project_out;
+ }
+
+ err = ext4_reserve_inode_write(handle, inode, &iloc);
+ if (err)
+ goto project_stop;
+
+ raw_inode = ext4_raw_inode(&iloc);
+ if (EXT4_INODE_SIZE(sb) <= EXT4_GOOD_OLD_INODE_SIZE) {
+ err = -EOPNOTSUPP;
+ goto project_stop;
+ }
+
+ if (!EXT4_FITS_IN_INODE(raw_inode, ei, i_projid)) {
+ err = -EOVERFLOW;
+ goto project_stop;
+ }
+
+ transfer_to[PRJQUOTA] = dqget(sb, make_kqid_projid(kprojid));
+ if (!transfer_to[PRJQUOTA])
+ goto project_set;
+
+ err = __dquot_transfer(inode, transfer_to);
+ dqput(transfer_to[PRJQUOTA]);
+ if (err)
+ goto project_stop;
+
+project_set:
+ EXT4_I(inode)->i_projid = kprojid;
+ inode->i_ctime = ext4_current_time(inode);
+ err = ext4_mark_iloc_dirty(handle, inode, &iloc);
+project_stop:
+ ext4_journal_stop(handle);
+project_out:
+ mutex_unlock(&inode->i_mutex);
+ mnt_drop_write_file(filp);
+ return err;
+}
+
+/* Transfer internal flags to xflags */
+static inline __u32 ext4_iflags_to_xflags(unsigned long iflags)
+{
+ __u32 xflags = 0;
+
+ if (iflags & EXT4_SYNC_FL)
+ xflags |= FS_XFLAG_SYNC;
+ if (iflags & EXT4_IMMUTABLE_FL)
+ xflags |= FS_XFLAG_IMMUTABLE;
+ if (iflags & EXT4_APPEND_FL)
+ xflags |= FS_XFLAG_APPEND;
+ if (iflags & EXT4_NODUMP_FL)
+ xflags |= FS_XFLAG_NODUMP;
+ if (iflags & EXT4_NOATIME_FL)
+ xflags |= FS_XFLAG_NOATIME;
+ if (iflags & EXT4_PROJINHERIT_FL)
+ xflags |= FS_XFLAG_PROJINHERIT;
+ return xflags;
+}
+
+/* Transfer xflags flags to internal */
+static inline unsigned long ext4_xflags_to_iflags(__u32 xflags)
+{
+ unsigned long iflags = 0;
+
+ if (xflags & FS_XFLAG_SYNC)
+ iflags |= EXT4_SYNC_FL;
+ if (xflags & FS_XFLAG_IMMUTABLE)
+ iflags |= EXT4_IMMUTABLE_FL;
+ if (xflags & FS_XFLAG_APPEND)
+ iflags |= EXT4_APPEND_FL;
+ if (xflags & FS_XFLAG_NODUMP)
+ iflags |= EXT4_NODUMP_FL;
+ if (xflags & FS_XFLAG_NOATIME)
+ iflags |= EXT4_NOATIME_FL;
+ if (xflags & FS_XFLAG_PROJINHERIT)
+ iflags |= EXT4_PROJINHERIT_FL;
+
+ return iflags;
+}
+
long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct inode *inode = file_inode(filp);
@@ -211,11 +432,7 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
flags = ei->i_flags & EXT4_FL_USER_VISIBLE;
return put_user(flags, (int __user *) arg);
case EXT4_IOC_SETFLAGS: {
- handle_t *handle = NULL;
- int err, migrate = 0;
- struct ext4_iloc iloc;
- unsigned int oldflags, mask, i;
- unsigned int jflag;
+ int err;
if (!inode_owner_or_capable(inode))
return -EACCES;
@@ -229,89 +446,8 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
flags = ext4_mask_flags(inode->i_mode, flags);
- err = -EPERM;
mutex_lock(&inode->i_mutex);
- /* Is it quota file? Do not allow user to mess with it */
- if (IS_NOQUOTA(inode))
- goto flags_out;
-
- oldflags = ei->i_flags;
-
- /* 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;
- }
-
- /*
- * The JOURNAL_DATA flag can only be changed by
- * the relevant capability.
- */
- if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) {
- if (!capable(CAP_SYS_RESOURCE))
- goto flags_out;
- }
- if ((flags ^ oldflags) & EXT4_EXTENTS_FL)
- migrate = 1;
-
- if (flags & EXT4_EOFBLOCKS_FL) {
- /* we don't support adding EOFBLOCKS flag */
- if (!(oldflags & EXT4_EOFBLOCKS_FL)) {
- err = -EOPNOTSUPP;
- goto flags_out;
- }
- } else if (oldflags & EXT4_EOFBLOCKS_FL)
- ext4_truncate(inode);
-
- handle = ext4_journal_start(inode, EXT4_HT_INODE, 1);
- if (IS_ERR(handle)) {
- err = PTR_ERR(handle);
- goto flags_out;
- }
- if (IS_SYNC(inode))
- ext4_handle_sync(handle);
- err = ext4_reserve_inode_write(handle, inode, &iloc);
- if (err)
- goto flags_err;
-
- for (i = 0, mask = 1; i < 32; i++, mask <<= 1) {
- if (!(mask & EXT4_FL_USER_MODIFIABLE))
- continue;
- if (mask & flags)
- ext4_set_inode_flag(inode, i);
- else
- ext4_clear_inode_flag(inode, i);
- }
-
- ext4_set_inode_flags(inode);
- inode->i_ctime = ext4_current_time(inode);
-
- err = ext4_mark_iloc_dirty(handle, inode, &iloc);
-flags_err:
- ext4_journal_stop(handle);
- if (err)
- goto flags_out;
-
- if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL))
- err = ext4_change_inode_journal_flag(inode, jflag);
- if (err)
- goto flags_out;
- if (migrate) {
- if (flags & EXT4_EXTENTS_FL)
- err = ext4_ext_migrate(inode);
- else
- err = ext4_ind_migrate(inode);
- }
-
-flags_out:
+ err = ext4_ioctl_setflags(inode, flags);
mutex_unlock(&inode->i_mutex);
mnt_drop_write_file(filp);
return err;
@@ -615,7 +751,61 @@ resizefs_out:
}
case EXT4_IOC_PRECACHE_EXTENTS:
return ext4_ext_precache(inode);
+ case EXT4_IOC_FSGETXATTR:
+ {
+ struct fsxattr fa;
+
+ memset(&fa, 0, sizeof(struct fsxattr));
+ ext4_get_inode_flags(ei);
+ fa.fsx_xflags = ext4_iflags_to_xflags(ei->i_flags & EXT4_FL_USER_VISIBLE);
+
+ if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
+ EXT4_FEATURE_RO_COMPAT_PROJECT)) {
+ fa.fsx_projid = (__u32)from_kprojid(&init_user_ns,
+ EXT4_I(inode)->i_projid);
+ }
+
+ if (copy_to_user((struct fsxattr __user *)arg,
+ &fa, sizeof(fa)))
+ return -EFAULT;
+ return 0;
+ }
+ case EXT4_IOC_FSSETXATTR:
+ {
+ struct fsxattr fa;
+ int err;
+
+ if (copy_from_user(&fa, (struct fsxattr __user *)arg,
+ sizeof(fa)))
+ return -EFAULT;
+
+ /* Make sure caller has proper permission */
+ if (!inode_owner_or_capable(inode))
+ return -EACCES;
+
+ err = mnt_want_write_file(filp);
+ if (err)
+ return err;
+
+ flags = ext4_xflags_to_iflags(fa.fsx_xflags);
+ flags = ext4_mask_flags(inode->i_mode, flags);
+
+ mutex_lock(&inode->i_mutex);
+ flags = (ei->i_flags & ~EXT4_FL_XFLAG_VISIBLE) |
+ (flags & EXT4_FL_XFLAG_VISIBLE);
+ err = ext4_ioctl_setflags(inode, flags);
+ mutex_unlock(&inode->i_mutex);
+ mnt_drop_write_file(filp);
+ if (err)
+ return err;
+
+ err = ext4_ioctl_setproject(filp, fa.fsx_projid);
+ if (err)
+ return err;
+
+ return 0;
+ }
default:
return -ENOTTY;
}
diff --git a/fs/xfs/xfs_fs.h b/fs/xfs/xfs_fs.h
index 18dc721..64c7ae6 100644
--- a/fs/xfs/xfs_fs.h
+++ b/fs/xfs/xfs_fs.h
@@ -36,38 +36,25 @@ struct dioattr {
#endif
/*
- * Structure for XFS_IOC_FSGETXATTR[A] and XFS_IOC_FSSETXATTR.
- */
-#ifndef HAVE_FSXATTR
-struct fsxattr {
- __u32 fsx_xflags; /* xflags field value (get/set) */
- __u32 fsx_extsize; /* extsize field value (get/set)*/
- __u32 fsx_nextents; /* nextents field value (get) */
- __u32 fsx_projid; /* project identifier (get/set) */
- unsigned char fsx_pad[12];
-};
-#endif
-
-/*
* Flags for the bs_xflags/fsx_xflags field
* There should be a one-to-one correspondence between these flags and the
* XFS_DIFLAG_s.
*/
-#define XFS_XFLAG_REALTIME 0x00000001 /* data in realtime volume */
-#define XFS_XFLAG_PREALLOC 0x00000002 /* preallocated file extents */
-#define XFS_XFLAG_IMMUTABLE 0x00000008 /* file cannot be modified */
-#define XFS_XFLAG_APPEND 0x00000010 /* all writes append */
-#define XFS_XFLAG_SYNC 0x00000020 /* all writes synchronous */
-#define XFS_XFLAG_NOATIME 0x00000040 /* do not update access time */
-#define XFS_XFLAG_NODUMP 0x00000080 /* do not include in backups */
-#define XFS_XFLAG_RTINHERIT 0x00000100 /* create with rt bit set */
-#define XFS_XFLAG_PROJINHERIT 0x00000200 /* create with parents projid */
-#define XFS_XFLAG_NOSYMLINKS 0x00000400 /* disallow symlink creation */
-#define XFS_XFLAG_EXTSIZE 0x00000800 /* extent size allocator hint */
-#define XFS_XFLAG_EXTSZINHERIT 0x00001000 /* inherit inode extent size */
-#define XFS_XFLAG_NODEFRAG 0x00002000 /* do not defragment */
-#define XFS_XFLAG_FILESTREAM 0x00004000 /* use filestream allocator */
-#define XFS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */
+#define XFS_XFLAG_REALTIME FS_XFLAG_REALTIME /* data in realtime volume */
+#define XFS_XFLAG_PREALLOC FS_XFLAG_PREALLOC /* preallocated file extents */
+#define XFS_XFLAG_IMMUTABLE FS_XFLAG_IMMUTABLE /* file cannot be modified */
+#define XFS_XFLAG_APPEND FS_XFLAG_APPEND /* all writes append */
+#define XFS_XFLAG_SYNC FS_XFLAG_SYNC /* all writes synchronous */
+#define XFS_XFLAG_NOATIME FS_XFLAG_NOATIME /* do not update access time */
+#define XFS_XFLAG_NODUMP FS_XFLAG_NODUMP /* do not include in backups */
+#define XFS_XFLAG_RTINHERIT FS_XFLAG_RTINHERIT /* create with rt bit set */
+#define XFS_XFLAG_PROJINHERIT FS_XFLAG_PROJINHERIT /* create with parents projid */
+#define XFS_XFLAG_NOSYMLINKS FS_XFLAG_NOSYMLINKS /* disallow symlink creation */
+#define XFS_XFLAG_EXTSIZE FS_XFLAG_EXTSIZE /* extent size allocator hint */
+#define XFS_XFLAG_EXTSZINHERIT FS_XFLAG_EXTSZINHERIT /* inherit inode extent size */
+#define XFS_XFLAG_NODEFRAG FS_XFLAG_NODEFRAG /* do not defragment */
+#define XFS_XFLAG_FILESTREAM FS_XFLAG_FILESTREAM /* use filestream allocator */
+#define XFS_XFLAG_HASATTR FS_XFLAG_HASATTR /* no DIFLAG for this */
/*
* Structure for XFS_IOC_GETBMAP.
@@ -503,8 +490,8 @@ typedef struct xfs_swapext
#define XFS_IOC_ALLOCSP _IOW ('X', 10, struct xfs_flock64)
#define XFS_IOC_FREESP _IOW ('X', 11, struct xfs_flock64)
#define XFS_IOC_DIOINFO _IOR ('X', 30, struct dioattr)
-#define XFS_IOC_FSGETXATTR _IOR ('X', 31, struct fsxattr)
-#define XFS_IOC_FSSETXATTR _IOW ('X', 32, struct fsxattr)
+#define XFS_IOC_FSGETXATTR FS_IOC_FSGETXATTR
+#define XFS_IOC_FSSETXATTR FS_IOC_FSSETXATTR
#define XFS_IOC_ALLOCSP64 _IOW ('X', 36, struct xfs_flock64)
#define XFS_IOC_FREESP64 _IOW ('X', 37, struct xfs_flock64)
#define XFS_IOC_GETBMAP _IOWR('X', 38, struct getbmap)
diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
index fcbf647..69dda62 100644
--- a/include/uapi/linux/fs.h
+++ b/include/uapi/linux/fs.h
@@ -58,6 +58,36 @@ struct inodes_stat_t {
long dummy[5]; /* padding for sysctl ABI compatibility */
};
+/*
+ * Structure for FS_IOC_FSGETXATTR and FS_IOC_FSSETXATTR.
+ */
+struct fsxattr {
+ __u32 fsx_xflags; /* xflags field value (get/set) */
+ __u32 fsx_extsize; /* extsize field value (get/set)*/
+ __u32 fsx_nextents; /* nextents field value (get) */
+ __u32 fsx_projid; /* project identifier (get/set) */
+ unsigned char fsx_pad[12];
+};
+
+/*
+ * Flags for the fsx_xflags field
+ */
+#define FS_XFLAG_REALTIME 0x00000001 /* data in realtime volume */
+#define FS_XFLAG_PREALLOC 0x00000002 /* preallocated file extents */
+#define FS_XFLAG_IMMUTABLE 0x00000008 /* file cannot be modified */
+#define FS_XFLAG_APPEND 0x00000010 /* all writes append */
+#define FS_XFLAG_SYNC 0x00000020 /* all writes synchronous */
+#define FS_XFLAG_NOATIME 0x00000040 /* do not update access time */
+#define FS_XFLAG_NODUMP 0x00000080 /* do not include in backups */
+#define FS_XFLAG_RTINHERIT 0x00000100 /* create with rt bit set */
+#define FS_XFLAG_PROJINHERIT 0x00000200 /* create with parents projid */
+#define FS_XFLAG_NOSYMLINKS 0x00000400 /* disallow symlink creation */
+#define FS_XFLAG_EXTSIZE 0x00000800 /* extent size allocator hint */
+#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_HASATTR 0x80000000 /* no DIFLAG for this */
+
#define NR_FILE 8192 /* this can well be larger on a larger system */
@@ -163,6 +193,8 @@ struct inodes_stat_t {
#define FS_IOC_GETVERSION _IOR('v', 1, long)
#define FS_IOC_SETVERSION _IOW('v', 2, long)
#define FS_IOC_FIEMAP _IOWR('f', 11, struct fiemap)
+#define FS_IOC_FSGETXATTR _IOR('X', 31, struct fsxattr)
+#define FS_IOC_FSSETXATTR _IOW('X', 32, struct fsxattr)
#define FS_IOC32_GETFLAGS _IOR('f', 1, int)
#define FS_IOC32_SETFLAGS _IOW('f', 2, int)
#define FS_IOC32_GETVERSION _IOR('v', 1, int)
--
1.7.1
^ permalink raw reply related
* [v13 5/5] ext4: cleanup inode flag definitions
From: Li Xi @ 2015-04-20 1:39 UTC (permalink / raw)
To: linux-fsdevel, linux-ext4, linux-api, tytso, adilger, jack, viro,
hch, dmonakhov
In-Reply-To: <1429493988-16819-1-git-send-email-lixi@ddn.com>
The inode flags defined in uapi/linux/fs.h were migrated from
ext4.h. This patch changes the inode flag definitions in ext4.h
to VFS definitions to make the gaps between them clearer.
Signed-off-by: Li Xi <lixi@ddn.com>
Reviewed-by: Andreas Dilger <adilger@dilger.ca>
---
fs/ext4/ext4.h | 50 +++++++++++++++++++++++++-------------------------
1 files changed, 25 insertions(+), 25 deletions(-)
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 2d5a097..adc6a5b 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -352,34 +352,34 @@ struct flex_groups {
/*
* Inode flags
*/
-#define EXT4_SECRM_FL 0x00000001 /* Secure deletion */
-#define EXT4_UNRM_FL 0x00000002 /* Undelete */
-#define EXT4_COMPR_FL 0x00000004 /* Compress file */
-#define EXT4_SYNC_FL 0x00000008 /* Synchronous updates */
-#define EXT4_IMMUTABLE_FL 0x00000010 /* Immutable file */
-#define EXT4_APPEND_FL 0x00000020 /* writes to file may only append */
-#define EXT4_NODUMP_FL 0x00000040 /* do not dump file */
-#define EXT4_NOATIME_FL 0x00000080 /* do not update atime */
+#define EXT4_SECRM_FL FS_SECRM_FL /* Secure deletion */
+#define EXT4_UNRM_FL FS_UNRM_FL /* Undelete */
+#define EXT4_COMPR_FL FS_COMPR_FL /* Compress file */
+#define EXT4_SYNC_FL FS_SYNC_FL /* Synchronous updates */
+#define EXT4_IMMUTABLE_FL FS_IMMUTABLE_FL /* Immutable file */
+#define EXT4_APPEND_FL FS_APPEND_FL /* writes to file may only append */
+#define EXT4_NODUMP_FL FS_NODUMP_FL /* do not dump file */
+#define EXT4_NOATIME_FL FS_NOATIME_FL /* do not update atime */
/* Reserved for compression usage... */
-#define EXT4_DIRTY_FL 0x00000100
-#define EXT4_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */
-#define EXT4_NOCOMPR_FL 0x00000400 /* Don't compress */
+#define EXT4_DIRTY_FL FS_DIRTY_FL
+#define EXT4_COMPRBLK_FL FS_COMPRBLK_FL /* One or more compressed clusters */
+#define EXT4_NOCOMPR_FL FS_NOCOMP_FL /* Don't compress */
/* nb: was previously EXT2_ECOMPR_FL */
-#define EXT4_ENCRYPT_FL 0x00000800 /* encrypted file */
+#define EXT4_ENCRYPT_FL 0x00000800 /* encrypted file */
/* End compression flags --- maybe not all used */
-#define EXT4_INDEX_FL 0x00001000 /* hash-indexed directory */
-#define EXT4_IMAGIC_FL 0x00002000 /* AFS directory */
-#define EXT4_JOURNAL_DATA_FL 0x00004000 /* file data should be journaled */
-#define EXT4_NOTAIL_FL 0x00008000 /* file tail should not be merged */
-#define EXT4_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */
-#define EXT4_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/
-#define EXT4_HUGE_FILE_FL 0x00040000 /* Set to each huge file */
-#define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */
-#define EXT4_EA_INODE_FL 0x00200000 /* Inode used for large EA */
-#define EXT4_EOFBLOCKS_FL 0x00400000 /* Blocks allocated beyond EOF */
-#define EXT4_INLINE_DATA_FL 0x10000000 /* Inode has inline data. */
-#define EXT4_PROJINHERIT_FL 0x20000000 /* Create with parents projid */
-#define EXT4_RESERVED_FL 0x80000000 /* reserved for ext4 lib */
+#define EXT4_INDEX_FL FS_INDEX_FL /* hash-indexed directory */
+#define EXT4_IMAGIC_FL FS_IMAGIC_FL /* AFS directory */
+#define EXT4_JOURNAL_DATA_FL FS_JOURNAL_DATA_FL /* file data should be journaled */
+#define EXT4_NOTAIL_FL FS_NOTAIL_FL /* file tail should not be merged */
+#define EXT4_DIRSYNC_FL FS_DIRSYNC_FL /* dirsync behaviour (directories only) */
+#define EXT4_TOPDIR_FL FS_TOPDIR_FL /* Top of directory hierarchies*/
+#define EXT4_HUGE_FILE_FL 0x00040000 /* Set to each huge file */
+#define EXT4_EXTENTS_FL FS_EXTENT_FL /* Inode uses extents */
+#define EXT4_EA_INODE_FL 0x00200000 /* Inode used for large EA */
+#define EXT4_EOFBLOCKS_FL 0x00400000 /* Blocks allocated beyond EOF */
+#define EXT4_INLINE_DATA_FL 0x10000000 /* Inode has inline data. */
+#define EXT4_PROJINHERIT_FL FS_PROJINHERIT_FL /* Create with parents projid */
+#define EXT4_RESERVED_FL FS_RESERVED_FL /* reserved for ext4 lib */
#define EXT4_FL_USER_VISIBLE 0x304BDFFF /* User visible flags */
#define EXT4_FL_USER_MODIFIABLE 0x204380FF /* User modifiable flags */
--
1.7.1
^ permalink raw reply related
* Re: [PATCH/RFC 0/2] Repurpose the v4l2_plane data_offset field
From: Hans Verkuil @ 2015-04-20 9:16 UTC (permalink / raw)
To: Sakari Ailus
Cc: Laurent Pinchart, linux-media, linux-api, Sakari Ailus,
Pawel Osciak, Marek Szyprowski, Mauro Carvalho Chehab
In-Reply-To: <20150418130415.GM27451@valkosipuli.retiisi.org.uk>
Hi Sakari,
On 04/18/2015 03:04 PM, Sakari Ailus wrote:
> Hi Hans,
>
> On Fri, Apr 17, 2015 at 12:27:41PM +0200, Hans Verkuil wrote:
>> Hi Laurent,
>>
>> On 04/14/2015 09:44 PM, Laurent Pinchart wrote:
>>> Hello,
>>>
>>> The v4l2_plane data_offset field has been introduced at the same time as the
>>> the multiplane API to convey header size information between kernelspace and
>>> userspace.
>>>
>>> The API then became slightly controversial, both because different developers
>>> understood the purpose of the field differently (resulting for instance in an
>>> out-of-tree driver abusing the field for a different purpose), and because of
>>> competing proposals (see for instance "[RFC] Multi format stream support" at
>>> http://www.spinics.net/lists/linux-media/msg69130.html).
>>>
>>> Furthermore, the data_offset field isn't used by any mainline driver except
>>> vivid (for testing purpose).
>>>
>>> I need a different data offset in planes to allow data capture to or data
>>> output from a userspace-selected offset within a buffer (mainly for the
>>> DMABUF and MMAP memory types). As the data_offset field already has the
>>> right name, is unused, and ill-defined, I propose repurposing it. This is what
>>> this RFC is about.
>>>
>>> If the proposal is accepted I'll add another patch to update data_offset usage
>>> in the vivid driver.
>>
>> I am skeptical about all this for a variety of reasons:
>>
>> 1) The data_offset field is well-defined in the spec. There really is no doubt
>> about the meaning of the field.
>
> I think that's debatable. :-) The specification doesn't say much what the
> data_offset is really about. For instance, it does not specify what may be
> in the buffer before data_offset.
That's correct. Now, it is my view that, while it would be nice if a fourcc like
value would be available to tell the format of that header, in practice that format
is so tied to a specific type of hardware that you either know it (i.e. it is a custom
app for that hardware), or you ignore it altogether. There may be some exceptions for
somewhat standardized types of metadata (SMIA), but those never materialized as actual
code.
> The kerneldoc documentation next to struct v4l2_plane suggests there might
> be a header, but that's primarily for driver developers rather than users.
>
> I, for instance, understood data_offset to mean essentially how this set
> "re-purposes" it. I wonder if there are others who have originally
> understood it as such.
I know it was mis-understood, the spec was fairly vague in the past, and while more
specific you are right in that it does not actually tell the reason for the field
(i.e. skip headers).
In no way can you re-purpose the field, though.
1) It is in use.
2) If you thought it was confusing today, then that's nothing compared to the confusion
once you change the meaning from one kernel to another.
Either keep the current meaning and improve the specification, or deprecate it: warn
when it is non-zero and just mark it as 'don't use' in the spec.
>
>>
>> 2) We really don't know who else might be using it, or which applications might
>> be using it (a lot of work was done in gstreamer recently, I wonder if data_offset
>> support was implemented there).
>>
>> 3) You offer no alternative to this feature. Basically this is my main objection.
>> It is not at all unusual to have headers in front of the frame data. We (Cisco)
>> use it in one of our product series for example. And I suspect it is something that
>> happens especially in systems with an FPGA that does custom processing, and those
>> systems are exactly the ones that are generally not upstreamed and so are not
>> visible to us.
>
> If you have a header before the image, the header probably has a format as
> well. Some headers are device specific whereas some are more generic. The
> SMIA standard, for example, does specify a metadata (header or footer!)
> format.
>
> It'd be useful to be able to tell the user what kind of header there is. For
> that, the header could be located on a different plane, with a specific
> format.
>
> There's room for format information in struct v4l2_plane_pix_format but
> hardly much else. It still would cover a number of potential use cases.
>
> I might still consider making the planes independent of each other;
> conveniently there's 8 bytes of free space in struct v4l2_pix_format_mplane
> for alternative plane related information. It'd be nice to be able to do
> this without an additional buffer type since that's visible in a large
> number of other places: there's plenty of room in struct v4l2_plane for
> any video buffer related information.
Please don't confuse things: each struct v4l2_plane_pix_format relates to a
single buffer that contains the data for that plane. If one buffer contains
both metadata and actual image data, then that's all part of the same plane
since it was all transferred to the buffer with the same DMA transfer.
You cannot put the header/footer into separate planes since the only way to
achieve that would be a memcpy and the header/footer would still be part of
the actual plane data.
If the metadata arrives through its own DMA channel, then I would have no
objection to seeing that as a separate plane. But I think in general that
might be a bad idea because such metadata may come at an earlier/later time
compared to the image data, and usually apps want to receive things asap.
I still see it as a simple problem: I have a buffer, it contains a picture
of a given pixel format, but there may be a header and (currently not implemented)
a footer. Header and/or footer may have a format (also not implemented yet).
Applications can use the offsets to ignore all those headers/footers and just
go straight to the image data. Or they use it to interpret the data in the
headers/footers.
Perhaps it is a total lack of imagination, but I really cannot see what else
it is you would need. Of course, you can think of really crazy schemes, but
then you likely need to just use a new pixelformat since it is so crazy that
it doesn't fit into anything existing.
The whole point of data_offset was that it is nuts to have to come up with a
new pixelformat for otherwise standard pixelformats that just happen to have
a header in front of them. You can't duplicate all pixel formats just for that.
> Frame descriptors are not needed for this --- you're quite right in that.
> But the frame descriptors, when implemented, will very probably need plane
> specific formats in the end as not many receivers are able to separate
> different parts of the image to different buffers.
>
>>
>> IMHO the functionality it provides is very much relevant, and I would like to see
>> an alternative in place before it is repurposed.
>>
>> But frankly, I really don't see why you would want to repurpose it. Adding a new
>> field (buf_offset) would do exactly what you want it to do without causing an ABI
>> change.
>
> I said I ok with adding buf_offset field, but it might not be the best
> choice we can make: it's a temporary solution for a very specific problem,
> leaves the API with similar field names with different meanings (data_offset
> vs. buf_offset, where the other is about the header and the other about the
> data) and is not extensible. In addition, the size of the header is not
> specified; it might be smaller than what's between buf_offset and
> data_offset. Some devices produce footers as well; currently we have no way
> to specify how they are dealt with.
>
> I'd like to at least investigate if we could have something more
> future-proof for this purpose.
>
Proposals welcome!
Regards,
Hans
^ permalink raw reply
* Re: [PATCH/RFC 0/2] Repurpose the v4l2_plane data_offset field
From: Hans Verkuil @ 2015-04-20 9:34 UTC (permalink / raw)
To: Laurent Pinchart
Cc: linux-media-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA, Sakari Ailus, Pawel Osciak,
Marek Szyprowski, Mauro Carvalho Chehab, Nicolas Dufresne
In-Reply-To: <7986966.gGAFkYegjs@avalon>
On 04/17/2015 02:53 PM, Laurent Pinchart wrote:
> Hi Hans,
>
> On Friday 17 April 2015 12:27:41 Hans Verkuil wrote:
>> On 04/14/2015 09:44 PM, Laurent Pinchart wrote:
>>> Hello,
>>>
>>> The v4l2_plane data_offset field has been introduced at the same time as
>>> the the multiplane API to convey header size information between
>>> kernelspace and userspace.
>>>
>>> The API then became slightly controversial, both because different
>>> developers understood the purpose of the field differently (resulting for
>>> instance in an out-of-tree driver abusing the field for a different
>>> purpose), and because of competing proposals (see for instance "[RFC]
>>> Multi format stream support" at
>>> http://www.spinics.net/lists/linux-media/msg69130.html).
>>>
>>> Furthermore, the data_offset field isn't used by any mainline driver
>>> except vivid (for testing purpose).
>>>
>>> I need a different data offset in planes to allow data capture to or data
>>> output from a userspace-selected offset within a buffer (mainly for the
>>> DMABUF and MMAP memory types). As the data_offset field already has the
>>> right name, is unused, and ill-defined, I propose repurposing it. This is
>>> what this RFC is about.
>>>
>>> If the proposal is accepted I'll add another patch to update data_offset
>>> usage in the vivid driver.
>>
>> I am skeptical about all this for a variety of reasons:
>
> That's all good, it's an RFC :-)
>
>> 1) The data_offset field is well-defined in the spec. There really is no
>> doubt about the meaning of the field.
>
> I only partly agree. I believe the purpose of the data_offset field to be
> clear among the core V4L2 developers, but the documentation isn't precise
> enough. I've seen out-of-tree drivers using the data_offset field for other
> purposes than specifying the header size. The situation is a bit better now
> that videobuf2 handles the field properly (and avoids copying it from user to
> kernel for capture devices for instance), but there are still many users of
> older kernels.
>
> This being said, the problem wouldn't be difficult to fix, it just requires a
> documentation patch.
>
>> 2) We really don't know who else might be using it, or which applications
>> might be using it (a lot of work was done in gstreamer recently, I wonder
>> if data_offset support was implemented there).
>
> It's funny you mention that. I cloned the gstreamer repositories and tried to
> investigate. The gstreamer v4l2 elements started using data_offset a year ago
> in
>
> commit 92bdd596f2b07dbf4ccc9b8bf3d17620d44f131a
> Author: Nicolas Dufresne <nicolas.dufresne-ZGY8ohtN/8qB+jHODAdFcQ@public.gmane.org>
> Date: Fri Apr 11 17:10:11 2014 -0400
>
> v4l2: Add DMABUF and USERPTR importation
>
> (I've CC'ed Nicolas to this e-mail)
>
> I'm not too familiar with the latest gstreamer code, but after a first
> investigation it seems that gstreamer uses the data_offset field for the
> purpose introduced by this patch, not to convey the header size. One more
> argument in favour of repurposing the field ;-)
>
>> 3) You offer no alternative to this feature. Basically this is my main
>> objection. It is not at all unusual to have headers in front of the frame
>> data. We (Cisco) use it in one of our product series for example. And I
>> suspect it is something that happens especially in systems with an FPGA
>> that does custom processing, and those systems are exactly the ones that
>> are generally not upstreamed and so are not visible to us.
>>
>> IMHO the functionality it provides is very much relevant, and I would like
>> to see an alternative in place before it is repurposed.
>>
>> But frankly, I really don't see why you would want to repurpose it. Adding a
>> new field (buf_offset) would do exactly what you want it to do without
>> causing an ABI change.
>>
>> Should we ever implement a better alternative for data_offset, then that
>> field can be renamed to 'reserved2' or whatever at some point.
>>
>> Frankly, I don't think data_offset is all that bad. What is missing is info
>> about the format (so add a 'data_format' field) and possible similar info
>> about a footer (footer_size, footer_format). Yes, the name could have been
>> better (header_size), but nobody is perfect...
>
> I totally agree that the functionality is relevant, and we certainly need an
> API for that.
>
> My point, however, was twofold : I believe we need a better (as in more
> powerful) API than data_offset to specify plane content, and the current usage
> of data_offset in out-of-tree drivers, and it seems in gstreamer too, is
> different than what we had intended the field to be used for.
>
> For those two reasons, I believe it would make sense to repurpose the field
> and introduce a new API to specify information about the plane content. Let's
> kickstart the discussion :-)
>
> The following information comes to my mind as being useful to specify:
>
> - format
> - header size
> - footer size
>
> There is, however, another point I'd like to raise. I'm working on an H.264
> encoder that produces slices without headers. Userspace is thus responsible
> for filling the headers, based on information produced by the encoder.
>
> When a capture buffer at the output of the encoder contains a single slice,
> that's pretty easy to handle. Userspace can use data_offset (in its new
> purpose, or buf_offset if we decide to introduce a new field instead) to
> reserve space for a header if the header size is known in advance by the
> application, or the driver (or possibly the device) can reserve space for the
> header and report the header size.
>
> However, a capture buffer can contain multiple slices, with gaps between the
> slices for the headers. The position and size of the gaps need to be known by
> the application. I'm not sure yet if userspace can compute them, or if they're
> dynamic and need to be passed from the driver to the application on a per-
> frame basis. In the latter case I would need more than a header size and
> footer size per plane.
I wonder if the current V4L2_PIX_FMT_H264* fourcc formats support multiple slices
in one buffer. Kamil might know. But I suspect you'll have to make a new fourcc
for that. Just for reference you might want to look at VIDIOC_G_ENC_INDEX (used
by ivtv) for a somewhat similar purpose. It's an old API, and I would probably not
recommend reusing this, but it may be interesting.
Is the size of the gaps programmable in the H.264 encoder hardware?
In any case, I believe your particular use-case has absolutely nothing to do with
headers/footers in a plane (the original topic). Your headers are intrinsic to the
format, i.e. without them applications cannot handle the stream. Filling those in
is the responsibility of the whole stack (driver + any libv4l plugin) leading to a
valid data buffer.
The headers/footers in the original use-case are just due to metadata that hardware
decides to throw in for whoever is interested (or in some cases it's just garbage)
and that are not part of the actual image data.
Regards,
Hans
^ permalink raw reply
* Re: [PATCH/RFC 0/2] Repurpose the v4l2_plane data_offset field
From: Laurent Pinchart @ 2015-04-20 9:43 UTC (permalink / raw)
To: Hans Verkuil
Cc: linux-media, linux-api, Sakari Ailus, Pawel Osciak,
Marek Szyprowski, Mauro Carvalho Chehab, Nicolas Dufresne
In-Reply-To: <5534C834.6000001@xs4all.nl>
Hi Hans,
On Monday 20 April 2015 11:34:44 Hans Verkuil wrote:
> On 04/17/2015 02:53 PM, Laurent Pinchart wrote:
> > On Friday 17 April 2015 12:27:41 Hans Verkuil wrote:
> >> On 04/14/2015 09:44 PM, Laurent Pinchart wrote:
> >>> Hello,
> >>>
> >>> The v4l2_plane data_offset field has been introduced at the same time as
> >>> the the multiplane API to convey header size information between
> >>> kernelspace and userspace.
> >>>
> >>> The API then became slightly controversial, both because different
> >>> developers understood the purpose of the field differently (resulting
> >>> for instance in an out-of-tree driver abusing the field for a different
> >>> purpose), and because of competing proposals (see for instance "[RFC]
> >>> Multi format stream support" at
> >>> http://www.spinics.net/lists/linux-media/msg69130.html).
> >>>
> >>> Furthermore, the data_offset field isn't used by any mainline driver
> >>> except vivid (for testing purpose).
> >>>
> >>> I need a different data offset in planes to allow data capture to or
> >>> data output from a userspace-selected offset within a buffer (mainly for
> >>> the DMABUF and MMAP memory types). As the data_offset field already has
> >>> the right name, is unused, and ill-defined, I propose repurposing it.
> >>> This is what this RFC is about.
> >>>
> >>> If the proposal is accepted I'll add another patch to update data_offset
> >>> usage in the vivid driver.
> >>
> >> I am skeptical about all this for a variety of reasons:
> > That's all good, it's an RFC :-)
> >
> >> 1) The data_offset field is well-defined in the spec. There really is no
> >> doubt about the meaning of the field.
> >
> > I only partly agree. I believe the purpose of the data_offset field to be
> > clear among the core V4L2 developers, but the documentation isn't precise
> > enough. I've seen out-of-tree drivers using the data_offset field for
> > other purposes than specifying the header size. The situation is a bit
> > better now that videobuf2 handles the field properly (and avoids copying
> > it from user to kernel for capture devices for instance), but there are
> > still many users of older kernels.
> >
> > This being said, the problem wouldn't be difficult to fix, it just
> > requires a documentation patch.
> >
> >> 2) We really don't know who else might be using it, or which applications
> >> might be using it (a lot of work was done in gstreamer recently, I wonder
> >> if data_offset support was implemented there).
> >
> > It's funny you mention that. I cloned the gstreamer repositories and tried
> > to investigate. The gstreamer v4l2 elements started using data_offset a
> > year ago in
> >
> > commit 92bdd596f2b07dbf4ccc9b8bf3d17620d44f131a
> > Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>
> > Date: Fri Apr 11 17:10:11 2014 -0400
> >
> > v4l2: Add DMABUF and USERPTR importation
> >
> > (I've CC'ed Nicolas to this e-mail)
> >
> > I'm not too familiar with the latest gstreamer code, but after a first
> > investigation it seems that gstreamer uses the data_offset field for the
> > purpose introduced by this patch, not to convey the header size. One more
> > argument in favour of repurposing the field ;-)
> >
> >> 3) You offer no alternative to this feature. Basically this is my main
> >> objection. It is not at all unusual to have headers in front of the frame
> >> data. We (Cisco) use it in one of our product series for example. And I
> >> suspect it is something that happens especially in systems with an FPGA
> >> that does custom processing, and those systems are exactly the ones that
> >> are generally not upstreamed and so are not visible to us.
> >>
> >> IMHO the functionality it provides is very much relevant, and I would
> >> like
> >> to see an alternative in place before it is repurposed.
> >>
> >> But frankly, I really don't see why you would want to repurpose it.
> >> Adding a new field (buf_offset) would do exactly what you want it to do
> >> without causing an ABI change.
> >>
> >> Should we ever implement a better alternative for data_offset, then that
> >> field can be renamed to 'reserved2' or whatever at some point.
> >>
> >> Frankly, I don't think data_offset is all that bad. What is missing is
> >> info
> >> about the format (so add a 'data_format' field) and possible similar info
> >> about a footer (footer_size, footer_format). Yes, the name could have
> >> been
> >> better (header_size), but nobody is perfect...
> >
> > I totally agree that the functionality is relevant, and we certainly need
> > an API for that.
> >
> > My point, however, was twofold : I believe we need a better (as in more
> > powerful) API than data_offset to specify plane content, and the current
> > usage of data_offset in out-of-tree drivers, and it seems in gstreamer
> > too, is different than what we had intended the field to be used for.
> >
> > For those two reasons, I believe it would make sense to repurpose the
> > field
> > and introduce a new API to specify information about the plane content.
> > Let's kickstart the discussion :-)
> >
> > The following information comes to my mind as being useful to specify:
> >
> > - format
> > - header size
> > - footer size
> >
> > There is, however, another point I'd like to raise. I'm working on an
> > H.264
> > encoder that produces slices without headers. Userspace is thus
> > responsible
> > for filling the headers, based on information produced by the encoder.
> >
> > When a capture buffer at the output of the encoder contains a single
> > slice,
> > that's pretty easy to handle. Userspace can use data_offset (in its new
> > purpose, or buf_offset if we decide to introduce a new field instead) to
> > reserve space for a header if the header size is known in advance by the
> > application, or the driver (or possibly the device) can reserve space for
> > the header and report the header size.
> >
> > However, a capture buffer can contain multiple slices, with gaps between
> > the slices for the headers. The position and size of the gaps need to be
> > known by the application. I'm not sure yet if userspace can compute them,
> > or if they're dynamic and need to be passed from the driver to the
> > application on a per- frame basis. In the latter case I would need more
> > than a header size and footer size per plane.
>
> I wonder if the current V4L2_PIX_FMT_H264* fourcc formats support multiple
> slices in one buffer. Kamil might know. But I suspect you'll have to make a
> new fourcc for that. Just for reference you might want to look at
> VIDIOC_G_ENC_INDEX (used by ivtv) for a somewhat similar purpose. It's an
> old API, and I would probably not recommend reusing this, but it may be
> interesting.
>
> Is the size of the gaps programmable in the H.264 encoder hardware?
I don't know yet, I'm waiting for more information.
> In any case, I believe your particular use-case has absolutely nothing to do
> with headers/footers in a plane (the original topic). Your headers are
> intrinsic to the format, i.e. without them applications cannot handle the
> stream. Filling those in is the responsibility of the whole stack (driver +
> any libv4l plugin) leading to a valid data buffer.
I could agree with that. I'll wait until I get more information about the
hardware before discussing this topic further.
This patch set remains valid though, it's unrelated to my H.264 encoder.
> The headers/footers in the original use-case are just due to metadata that
> hardware decides to throw in for whoever is interested (or in some cases
> it's just garbage) and that are not part of the actual image data.
--
Regards,
Laurent Pinchart
^ permalink raw reply
* [Patch v2 0/3] firmware: dmi_scan: add SBMIOS entry point and DMI tables
From: Ivan Khoronzhuk @ 2015-04-20 10:19 UTC (permalink / raw)
To: linux-kernel, matt.fleming, jdelvare, ard.biesheuvel,
grant.likely, linux-api, linux-doc, mikew
Cc: dmidecode-devel, leif.lindholm, msalter, roy.franz,
Ivan Khoronzhuk
This series adds SMBIOS entry point table and DMI table under
/sys/firmware/dmi/tables in order to use as an alternative to utilities
reading them from /dev/mem.
Based on linux next
+ 2 patches that have not been sent by Jean Dalvere yet. They can be changed,
but, anyway, the series should be based on smth and it's desirable w/o
conflicts. The patches can be obtained with links:
http://jdelvare.nerim.net/devel/linux-3/jdelvare-dmi/firmware-dmi-03-simplify-displayed-version.patch
http://jdelvare.nerim.net/devel/linux-3/jdelvare-dmi/firmware-dmi-04-fix-product-uuid.patch
Link on V1:
https://lkml.org/lkml/2015/4/2/297
Changes since V1
- correct error path in dmi-sysfs
- don't use globally dmi_table var
- use "DMI" in attribute name
- correct error path in dmi_init
- leave dmi_kobj even in case of error
- include linux/kobject.h in header
Ivan Khoronzhuk (3):
firmware: dmi_scan: rename dmi_table to dmi_decode_table
firmware: dmi_scan: add SBMIOS entry and DMI tables
Documentation: ABI: sysfs-firmware-dmi: add -entries suffix to file
name
...sfs-firmware-dmi => sysfs-firmware-dmi-entries} | 2 +-
.../ABI/testing/sysfs-firmware-dmi-tables | 22 ++++++
drivers/firmware/dmi-sysfs.c | 17 ++--
drivers/firmware/dmi_scan.c | 92 ++++++++++++++++++++--
include/linux/dmi.h | 2 +
5 files changed, 120 insertions(+), 15 deletions(-)
rename Documentation/ABI/testing/{sysfs-firmware-dmi => sysfs-firmware-dmi-entries} (99%)
create mode 100644 Documentation/ABI/testing/sysfs-firmware-dmi-tables
--
1.9.1
^ permalink raw reply
* [Patch v2 1/3] firmware: dmi_scan: rename dmi_table to dmi_decode_table
From: Ivan Khoronzhuk @ 2015-04-20 10:19 UTC (permalink / raw)
To: linux-kernel, matt.fleming, jdelvare, ard.biesheuvel,
grant.likely, linux-api, linux-doc, mikew
Cc: dmidecode-devel, leif.lindholm, msalter, roy.franz,
Ivan Khoronzhuk
In-Reply-To: <1429525187-3376-1-git-send-email-ivan.khoronzhuk@globallogic.com>
The "dmi_table" function looks like data instance, but it does DMI
table decode. This patch renames it to "dmi_decode_table" name as
more appropriate. That allows us to use "dmi_table" name for correct
purposes.
Reviewed-by: Jean Delvare <jdelvare@suse.de>
Signed-off-by: Ivan Khoronzhuk <ivan.khoronzhuk@globallogic.com>
---
drivers/firmware/dmi_scan.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index 97b1616..a864a6b 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -80,9 +80,9 @@ static const char * __init dmi_string(const struct dmi_header *dm, u8 s)
* We have to be cautious here. We have seen BIOSes with DMI pointers
* pointing to completely the wrong place for example
*/
-static void dmi_table(u8 *buf,
- void (*decode)(const struct dmi_header *, void *),
- void *private_data)
+static void dmi_decode_table(u8 *buf,
+ void (*decode)(const struct dmi_header *, void *),
+ void *private_data)
{
u8 *data = buf;
int i = 0;
@@ -130,7 +130,7 @@ static int __init dmi_walk_early(void (*decode)(const struct dmi_header *,
if (buf == NULL)
return -1;
- dmi_table(buf, decode, NULL);
+ dmi_decode_table(buf, decode, NULL);
add_device_randomness(buf, dmi_len);
@@ -897,7 +897,7 @@ int dmi_walk(void (*decode)(const struct dmi_header *, void *),
if (buf == NULL)
return -1;
- dmi_table(buf, decode, private_data);
+ dmi_decode_table(buf, decode, private_data);
dmi_unmap(buf);
return 0;
--
1.9.1
^ permalink raw reply related
* [Patch v2 2/3] firmware: dmi_scan: add SBMIOS entry and DMI tables
From: Ivan Khoronzhuk @ 2015-04-20 10:19 UTC (permalink / raw)
To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
matt.fleming-ral2JQCrhuEAvxtiuMwx3w, jdelvare-l3A5Bk7waGM,
ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A,
grant.likely-QSEj5FYQhm4dnm+yROfE0A,
linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA, mikew-hpIqsD4AKlfQT0dZR+AlfA
Cc: dmidecode-devel-qX2TKyscuCcdnm+yROfE0A,
leif.lindholm-QSEj5FYQhm4dnm+yROfE0A,
msalter-H+wXaHxf7aLQT0dZR+AlfA, roy.franz-QSEj5FYQhm4dnm+yROfE0A,
Ivan Khoronzhuk
In-Reply-To: <1429525187-3376-1-git-send-email-ivan.khoronzhuk-hExfYMNmJl/Cnp4W7fqMDg@public.gmane.org>
Some utils, like dmidecode and smbios, need to access SMBIOS entry
table area in order to get information like SMBIOS version, size, etc.
Currently it's done via /dev/mem. But for situation when /dev/mem
usage is disabled, the utils have to use dmi sysfs instead, which
doesn't represent SMBIOS entry and adds code/delay redundancy when direct
access for table is needed.
So this patch creates dmi/tables and adds SMBIOS entry point to allow
utils in question to work correctly without /dev/mem. Also patch adds
raw dmi table to simplify dmi table processing in user space, as
proposed by Jean Delvare.
Signed-off-by: Ivan Khoronzhuk <ivan.khoronzhuk-hExfYMNmJl/Cnp4W7fqMDg@public.gmane.org>
---
.../ABI/testing/sysfs-firmware-dmi-tables | 22 ++++++
drivers/firmware/dmi-sysfs.c | 17 +++--
drivers/firmware/dmi_scan.c | 82 ++++++++++++++++++++++
include/linux/dmi.h | 2 +
4 files changed, 114 insertions(+), 9 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-firmware-dmi-tables
diff --git a/Documentation/ABI/testing/sysfs-firmware-dmi-tables b/Documentation/ABI/testing/sysfs-firmware-dmi-tables
new file mode 100644
index 0000000..ff3cac8
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-firmware-dmi-tables
@@ -0,0 +1,22 @@
+What: /sys/firmware/dmi/tables/
+Date: April 2015
+Contact: Ivan Khoronzhuk <ivan.khoronzhuk-hExfYMNmJl/Cnp4W7fqMDg@public.gmane.org>
+Description:
+ The firmware provides DMI structures as a packed list of
+ data referenced by a SMBIOS table entry point. The SMBIOS
+ entry point contains general information, like SMBIOS
+ version, DMI table size, etc. The structure, content and
+ size of SMBIOS entry point is dependent on SMBIOS version.
+ The format of SMBIOS entry point and DMI structures
+ can be read in SMBIOS specification.
+
+ The dmi/tables provides raw SMBIOS entry point and DMI tables
+ through sysfs as an alternative to utilities reading them
+ from /dev/mem. The raw SMBIOS entry point and DMI table are
+ presented as binary attributes and are accessible via:
+
+ /sys/firmware/dmi/tables/smbios_entry_point
+ /sys/firmware/dmi/tables/DMI
+
+ The complete DMI information can be obtained using these two
+ tables.
diff --git a/drivers/firmware/dmi-sysfs.c b/drivers/firmware/dmi-sysfs.c
index e0f1cb3..ef76e5e 100644
--- a/drivers/firmware/dmi-sysfs.c
+++ b/drivers/firmware/dmi-sysfs.c
@@ -566,7 +566,6 @@ static struct kobj_type dmi_sysfs_entry_ktype = {
.default_attrs = dmi_sysfs_entry_attrs,
};
-static struct kobject *dmi_kobj;
static struct kset *dmi_kset;
/* Global count of all instances seen. Only for setup */
@@ -648,17 +647,20 @@ static void cleanup_entry_list(void)
static int __init dmi_sysfs_init(void)
{
- int error = -ENOMEM;
+ int error;
int val;
- /* Set up our directory */
- dmi_kobj = kobject_create_and_add("dmi", firmware_kobj);
- if (!dmi_kobj)
+ if (!dmi_kobj) {
+ pr_err("dmi-sysfs: dmi entry is absent.\n");
+ error = -ENODATA;
goto err;
+ }
dmi_kset = kset_create_and_add("entries", NULL, dmi_kobj);
- if (!dmi_kset)
+ if (!dmi_kset) {
+ error = -ENOMEM;
goto err;
+ }
val = 0;
error = dmi_walk(dmi_sysfs_register_handle, &val);
@@ -675,7 +677,6 @@ static int __init dmi_sysfs_init(void)
err:
cleanup_entry_list();
kset_unregister(dmi_kset);
- kobject_put(dmi_kobj);
return error;
}
@@ -685,8 +686,6 @@ static void __exit dmi_sysfs_exit(void)
pr_debug("dmi-sysfs: unloading.\n");
cleanup_entry_list();
kset_unregister(dmi_kset);
- kobject_del(dmi_kobj);
- kobject_put(dmi_kobj);
}
module_init(dmi_sysfs_init);
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index a864a6b..9705be2 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -10,6 +10,9 @@
#include <asm/dmi.h>
#include <asm/unaligned.h>
+struct kobject *dmi_kobj;
+EXPORT_SYMBOL_GPL(dmi_kobj);
+
/*
* DMI stands for "Desktop Management Interface". It is part
* of and an antecedent to, SMBIOS, which stands for System
@@ -20,6 +23,9 @@ static const char dmi_empty_string[] = " ";
static u32 dmi_ver __initdata;
static u32 dmi_len;
static u16 dmi_num;
+static u8 smbios_entry_point[32];
+static int smbios_entry_point_size;
+
/*
* Catch too early calls to dmi_check_system():
*/
@@ -478,6 +484,8 @@ static int __init dmi_present(const u8 *buf)
if (memcmp(buf, "_SM_", 4) == 0 &&
buf[5] < 32 && dmi_checksum(buf, buf[5])) {
smbios_ver = get_unaligned_be16(buf + 6);
+ smbios_entry_point_size = buf[5];
+ memcpy(smbios_entry_point, buf, smbios_entry_point_size);
/* Some BIOS report weird SMBIOS version, fix that up */
switch (smbios_ver) {
@@ -512,6 +520,9 @@ static int __init dmi_present(const u8 *buf)
pr_info("SMBIOS %d.%d present.\n",
dmi_ver >> 8, dmi_ver & 0xFF);
} else {
+ smbios_entry_point_size = 15;
+ memcpy(smbios_entry_point, buf,
+ smbios_entry_point_size);
pr_info("Legacy DMI %d.%d present.\n",
dmi_ver >> 8, dmi_ver & 0xFF);
}
@@ -538,6 +549,8 @@ static int __init dmi_smbios3_present(const u8 *buf)
dmi_num = 0; /* No longer specified */
dmi_len = get_unaligned_le32(buf + 12);
dmi_base = get_unaligned_le64(buf + 16);
+ smbios_entry_point_size = buf[6];
+ memcpy(smbios_entry_point, buf, smbios_entry_point_size);
if (dmi_walk_early(dmi_decode) == 0) {
pr_info("SMBIOS %d.%d.%d present.\n",
@@ -629,6 +642,75 @@ void __init dmi_scan_machine(void)
dmi_initialized = 1;
}
+static ssize_t raw_table_read(struct file *file, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf,
+ loff_t pos, size_t count)
+{
+ memcpy(buf, attr->private + pos, count);
+ return count;
+}
+
+static BIN_ATTR(smbios_entry_point, S_IRUSR, raw_table_read, NULL, 0);
+static BIN_ATTR(DMI, S_IRUSR, raw_table_read, NULL, 0);
+
+static int __init dmi_init(void)
+{
+ int ret;
+ u8 *dmi_table = NULL;
+ struct kobject *tables_kobj = NULL;
+
+ if (!dmi_available) {
+ ret = -ENODATA;
+ goto err;
+ }
+
+ /*
+ * Set up dmi directory at /sys/firmware/dmi. This entry should stay
+ * even after farther error, as it can be used by other modules like
+ * dmi-sysfs.
+ */
+ dmi_kobj = kobject_create_and_add("dmi", firmware_kobj);
+ tables_kobj = kobject_create_and_add("tables", dmi_kobj);
+ if (!(dmi_kobj && tables_kobj)) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ bin_attr_smbios_entry_point.size = smbios_entry_point_size;
+ bin_attr_smbios_entry_point.private = smbios_entry_point;
+ ret = sysfs_create_bin_file(tables_kobj, &bin_attr_smbios_entry_point);
+ if (ret)
+ goto err;
+
+ dmi_table = dmi_remap(dmi_base, dmi_len);
+ if (!dmi_table) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ bin_attr_DMI.size = dmi_len;
+ bin_attr_DMI.private = dmi_table;
+ ret = sysfs_create_bin_file(tables_kobj, &bin_attr_DMI);
+ if (!ret)
+ return 0;
+
+err:
+ pr_err("dmi: Firmware registration failed.\n");
+
+ if (tables_kobj) {
+ sysfs_remove_bin_file(tables_kobj,
+ &bin_attr_smbios_entry_point);
+ kobject_del(tables_kobj);
+ kobject_put(tables_kobj);
+ }
+
+ if (dmi_table)
+ dmi_unmap(dmi_table);
+
+ return ret;
+}
+subsys_initcall(dmi_init);
+
/**
* dmi_set_dump_stack_arch_desc - set arch description for dump_stack()
*
diff --git a/include/linux/dmi.h b/include/linux/dmi.h
index f820f0a..2f9f988 100644
--- a/include/linux/dmi.h
+++ b/include/linux/dmi.h
@@ -2,6 +2,7 @@
#define __DMI_H__
#include <linux/list.h>
+#include <linux/kobject.h>
#include <linux/mod_devicetable.h>
/* enum dmi_field is in mod_devicetable.h */
@@ -93,6 +94,7 @@ struct dmi_dev_onboard {
int devfn;
};
+extern struct kobject *dmi_kobj;
extern int dmi_check_system(const struct dmi_system_id *list);
const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list);
extern const char * dmi_get_system_info(int field);
--
1.9.1
^ permalink raw reply related
* [Patch v2 3/3] Documentation: ABI: sysfs-firmware-dmi: add -entries suffix to file name
From: Ivan Khoronzhuk @ 2015-04-20 10:19 UTC (permalink / raw)
To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
matt.fleming-ral2JQCrhuEAvxtiuMwx3w, jdelvare-l3A5Bk7waGM,
ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A,
grant.likely-QSEj5FYQhm4dnm+yROfE0A,
linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA, mikew-hpIqsD4AKlfQT0dZR+AlfA
Cc: dmidecode-devel-qX2TKyscuCcdnm+yROfE0A,
leif.lindholm-QSEj5FYQhm4dnm+yROfE0A,
msalter-H+wXaHxf7aLQT0dZR+AlfA, roy.franz-QSEj5FYQhm4dnm+yROfE0A,
Ivan Khoronzhuk
In-Reply-To: <1429525187-3376-1-git-send-email-ivan.khoronzhuk-hExfYMNmJl/Cnp4W7fqMDg@public.gmane.org>
The dmi-sysfs module adds DMI table structures entries under
/sys/firmware/dmi/entries only, so rename documentation file to
sysfs-firmware-dmi-entries as more appropriate. Without renaming it's
confusing to differ this from sysfs-firmware-dmi-tables that adds raw
DMI table and actually adds "dmi" kobject.
Reviewed-by: Jean Delvare <jdelvare-l3A5Bk7waGM@public.gmane.org>
Signed-off-by: Ivan Khoronzhuk <ivan.khoronzhuk-hExfYMNmJl/Cnp4W7fqMDg@public.gmane.org>
---
.../ABI/testing/{sysfs-firmware-dmi => sysfs-firmware-dmi-entries} | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
rename Documentation/ABI/testing/{sysfs-firmware-dmi => sysfs-firmware-dmi-entries} (99%)
diff --git a/Documentation/ABI/testing/sysfs-firmware-dmi b/Documentation/ABI/testing/sysfs-firmware-dmi-entries
similarity index 99%
rename from Documentation/ABI/testing/sysfs-firmware-dmi
rename to Documentation/ABI/testing/sysfs-firmware-dmi-entries
index c78f9ab..210ad44 100644
--- a/Documentation/ABI/testing/sysfs-firmware-dmi
+++ b/Documentation/ABI/testing/sysfs-firmware-dmi-entries
@@ -1,4 +1,4 @@
-What: /sys/firmware/dmi/
+What: /sys/firmware/dmi/entries/
Date: February 2011
Contact: Mike Waychison <mikew-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
Description:
--
1.9.1
^ permalink raw reply related
* Re: [PATCH/RFC 0/2] Repurpose the v4l2_plane data_offset field
From: Laurent Pinchart @ 2015-04-20 15:44 UTC (permalink / raw)
To: Hans Verkuil
Cc: Sakari Ailus, linux-media-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA, Sakari Ailus, Pawel Osciak,
Marek Szyprowski, Mauro Carvalho Chehab
In-Reply-To: <5534C405.9010307-qWit8jRvyhVmR6Xm/wNWPw@public.gmane.org>
Hi Hans,
On Monday 20 April 2015 11:16:53 Hans Verkuil wrote:
> On 04/18/2015 03:04 PM, Sakari Ailus wrote:
> > On Fri, Apr 17, 2015 at 12:27:41PM +0200, Hans Verkuil wrote:
> >> On 04/14/2015 09:44 PM, Laurent Pinchart wrote:
> >>> Hello,
> >>>
> >>> The v4l2_plane data_offset field has been introduced at the same time as
> >>> the the multiplane API to convey header size information between
> >>> kernelspace and userspace.
> >>>
> >>> The API then became slightly controversial, both because different
> >>> developers understood the purpose of the field differently (resulting
> >>> for instance in an out-of-tree driver abusing the field for a different
> >>> purpose), and because of competing proposals (see for instance "[RFC]
> >>> Multi format stream support" at
> >>> http://www.spinics.net/lists/linux-media/msg69130.html).
> >>>
> >>> Furthermore, the data_offset field isn't used by any mainline driver
> >>> except vivid (for testing purpose).
> >>>
> >>> I need a different data offset in planes to allow data capture to or
> >>> data output from a userspace-selected offset within a buffer (mainly for
> >>> the DMABUF and MMAP memory types). As the data_offset field already has
> >>> the right name, is unused, and ill-defined, I propose repurposing it.
> >>> This is what this RFC is about.
> >>>
> >>> If the proposal is accepted I'll add another patch to update data_offset
> >>> usage in the vivid driver.
> >>
> >> I am skeptical about all this for a variety of reasons:
> >>
> >> 1) The data_offset field is well-defined in the spec. There really is no
> >> doubt about the meaning of the field.
> >
> > I think that's debatable. :-) The specification doesn't say much what the
> > data_offset is really about. For instance, it does not specify what may be
> > in the buffer before data_offset.
>
> That's correct. Now, it is my view that, while it would be nice if a fourcc
> like value would be available to tell the format of that header, in
> practice that format is so tied to a specific type of hardware that you
> either know it (i.e. it is a custom app for that hardware), or you ignore
> it altogether. There may be some exceptions for somewhat standardized types
> of metadata (SMIA), but those never materialized as actual code.
>
> > The kerneldoc documentation next to struct v4l2_plane suggests there might
> > be a header, but that's primarily for driver developers rather than users.
> >
> > I, for instance, understood data_offset to mean essentially how this set
> > "re-purposes" it. I wonder if there are others who have originally
> > understood it as such.
>
> I know it was mis-understood, the spec was fairly vague in the past, and
> while more specific you are right in that it does not actually tell the
> reason for the field (i.e. skip headers).
>
> In no way can you re-purpose the field, though.
>
> 1) It is in use.
It's of course hard to get an overall view of all users, but the more I look
at the problem the more it seems like both out-of-tree kernel drivers (in
particular a Marvell CSI-2 receiver driver) and userspace (in particular
gstreamer) have implemented support for the data_offset field as proposed in
this patch series. We could of course argue that this is incorrect, and that
there are out-of-tree drivers and userspace code that use data_offset for the
purpose it was initially envisioned for (I'm thinking about Cisco code
possibly, at least the one you've had the opportunity to review :-)). However,
if the majority of users use data_offset "incorrectly", maybe we should
consider that usage as being the de-facto standard and consider this series as
a documentation fix.
The question is thus, what does the majority of the users do ?
> 2) If you thought it was confusing today, then that's nothing compared to
> the confusion once you change the meaning from one kernel to another.
>
> Either keep the current meaning and improve the specification, or deprecate
> it: warn when it is non-zero and just mark it as 'don't use' in the spec.
>
> >> 2) We really don't know who else might be using it, or which applications
> >> might be using it (a lot of work was done in gstreamer recently, I
> >> wonder if data_offset support was implemented there).
> >>
> >> 3) You offer no alternative to this feature. Basically this is my main
> >> objection. It is not at all unusual to have headers in front of the
> >> frame data. We (Cisco) use it in one of our product series for example.
> >> And I suspect it is something that happens especially in systems with an
> >> FPGA that does custom processing, and those systems are exactly the ones
> >> that are generally not upstreamed and so are not visible to us.
> >
> > If you have a header before the image, the header probably has a format as
> > well. Some headers are device specific whereas some are more generic. The
> > SMIA standard, for example, does specify a metadata (header or footer!)
> > format.
> >
> > It'd be useful to be able to tell the user what kind of header there is.
> > For that, the header could be located on a different plane, with a
> > specific format.
> >
> > There's room for format information in struct v4l2_plane_pix_format but
> > hardly much else. It still would cover a number of potential use cases.
> >
> > I might still consider making the planes independent of each other;
> > conveniently there's 8 bytes of free space in struct
> > v4l2_pix_format_mplane for alternative plane related information. It'd be
> > nice to be able to do this without an additional buffer type since that's
> > visible in a large number of other places: there's plenty of room in
> > struct v4l2_plane for any video buffer related information.
>
> Please don't confuse things: each struct v4l2_plane_pix_format relates to a
> single buffer that contains the data for that plane. If one buffer contains
> both metadata and actual image data, then that's all part of the same plane
> since it was all transferred to the buffer with the same DMA transfer.
>
> You cannot put the header/footer into separate planes since the only way to
> achieve that would be a memcpy and the header/footer would still be part of
> the actual plane data.
>
> If the metadata arrives through its own DMA channel, then I would have no
> objection to seeing that as a separate plane. But I think in general that
> might be a bad idea because such metadata may come at an earlier/later time
> compared to the image data, and usually apps want to receive things asap.
>
> I still see it as a simple problem: I have a buffer, it contains a picture
> of a given pixel format, but there may be a header and (currently not
> implemented) a footer. Header and/or footer may have a format (also not
> implemented yet).
>
> Applications can use the offsets to ignore all those headers/footers and
> just go straight to the image data. Or they use it to interpret the data in
> the headers/footers.
>
> Perhaps it is a total lack of imagination, but I really cannot see what else
> it is you would need. Of course, you can think of really crazy schemes, but
> then you likely need to just use a new pixelformat since it is so crazy
> that it doesn't fit into anything existing.
>
> The whole point of data_offset was that it is nuts to have to come up with a
> new pixelformat for otherwise standard pixelformats that just happen to
> have a header in front of them. You can't duplicate all pixel formats just
> for that.
>
> > Frame descriptors are not needed for this --- you're quite right in that.
> > But the frame descriptors, when implemented, will very probably need plane
> > specific formats in the end as not many receivers are able to separate
> > different parts of the image to different buffers.
> >
> >> IMHO the functionality it provides is very much relevant, and I would
> >> like to see an alternative in place before it is repurposed.
> >>
> >> But frankly, I really don't see why you would want to repurpose it.
> >> Adding a new field (buf_offset) would do exactly what you want it to do
> >> without causing an ABI change.
> >
> > I said I ok with adding buf_offset field, but it might not be the best
> > choice we can make: it's a temporary solution for a very specific problem,
> > leaves the API with similar field names with different meanings
> > (data_offset vs. buf_offset, where the other is about the header and the
> > other about the data) and is not extensible. In addition, the size of the
> > header is not specified; it might be smaller than what's between
> > buf_offset and data_offset. Some devices produce footers as well;
> > currently we have no way to specify how they are dealt with.
> >
> > I'd like to at least investigate if we could have something more
> > future-proof for this purpose.
>
> Proposals welcome!
I certainly second that :-) Sakari, do you have something in mind ?
--
Regards,
Laurent Pinchart
^ permalink raw reply
* Re: [Patch v2 2/3] firmware: dmi_scan: add SBMIOS entry and DMI tables
From: Roy Franz @ 2015-04-20 18:32 UTC (permalink / raw)
To: Ivan Khoronzhuk
Cc: Linux Kernel Mailing List, Matt Fleming, Jean Delvare,
Ard Biesheuvel, Grant Likely, linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA, Mike Waychison,
dmidecode-devel-qX2TKyscuCcdnm+yROfE0A, Leif Lindholm,
Mark Salter
In-Reply-To: <1429525187-3376-3-git-send-email-ivan.khoronzhuk-hExfYMNmJl/Cnp4W7fqMDg@public.gmane.org>
On Mon, Apr 20, 2015 at 3:19 AM, Ivan Khoronzhuk
<ivan.khoronzhuk-hExfYMNmJl/Cnp4W7fqMDg@public.gmane.org> wrote:
> Some utils, like dmidecode and smbios, need to access SMBIOS entry
> table area in order to get information like SMBIOS version, size, etc.
> Currently it's done via /dev/mem. But for situation when /dev/mem
> usage is disabled, the utils have to use dmi sysfs instead, which
> doesn't represent SMBIOS entry and adds code/delay redundancy when direct
> access for table is needed.
>
> So this patch creates dmi/tables and adds SMBIOS entry point to allow
> utils in question to work correctly without /dev/mem. Also patch adds
> raw dmi table to simplify dmi table processing in user space, as
> proposed by Jean Delvare.
>
> Signed-off-by: Ivan Khoronzhuk <ivan.khoronzhuk-hExfYMNmJl/Cnp4W7fqMDg@public.gmane.org>
Tested-by: Roy Franz <roy.franz-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Tested with dmidecode w/patches to read tables from sysfs. The dmidecode
patches are posted on dmidecode-devel and should be commited upstream soon.
Thanks,
Roy
> ---
> .../ABI/testing/sysfs-firmware-dmi-tables | 22 ++++++
> drivers/firmware/dmi-sysfs.c | 17 +++--
> drivers/firmware/dmi_scan.c | 82 ++++++++++++++++++++++
> include/linux/dmi.h | 2 +
> 4 files changed, 114 insertions(+), 9 deletions(-)
> create mode 100644 Documentation/ABI/testing/sysfs-firmware-dmi-tables
>
> diff --git a/Documentation/ABI/testing/sysfs-firmware-dmi-tables b/Documentation/ABI/testing/sysfs-firmware-dmi-tables
> new file mode 100644
> index 0000000..ff3cac8
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-firmware-dmi-tables
> @@ -0,0 +1,22 @@
> +What: /sys/firmware/dmi/tables/
> +Date: April 2015
> +Contact: Ivan Khoronzhuk <ivan.khoronzhuk-hExfYMNmJl/Cnp4W7fqMDg@public.gmane.org>
> +Description:
> + The firmware provides DMI structures as a packed list of
> + data referenced by a SMBIOS table entry point. The SMBIOS
> + entry point contains general information, like SMBIOS
> + version, DMI table size, etc. The structure, content and
> + size of SMBIOS entry point is dependent on SMBIOS version.
> + The format of SMBIOS entry point and DMI structures
> + can be read in SMBIOS specification.
> +
> + The dmi/tables provides raw SMBIOS entry point and DMI tables
> + through sysfs as an alternative to utilities reading them
> + from /dev/mem. The raw SMBIOS entry point and DMI table are
> + presented as binary attributes and are accessible via:
> +
> + /sys/firmware/dmi/tables/smbios_entry_point
> + /sys/firmware/dmi/tables/DMI
> +
> + The complete DMI information can be obtained using these two
> + tables.
> diff --git a/drivers/firmware/dmi-sysfs.c b/drivers/firmware/dmi-sysfs.c
> index e0f1cb3..ef76e5e 100644
> --- a/drivers/firmware/dmi-sysfs.c
> +++ b/drivers/firmware/dmi-sysfs.c
> @@ -566,7 +566,6 @@ static struct kobj_type dmi_sysfs_entry_ktype = {
> .default_attrs = dmi_sysfs_entry_attrs,
> };
>
> -static struct kobject *dmi_kobj;
> static struct kset *dmi_kset;
>
> /* Global count of all instances seen. Only for setup */
> @@ -648,17 +647,20 @@ static void cleanup_entry_list(void)
>
> static int __init dmi_sysfs_init(void)
> {
> - int error = -ENOMEM;
> + int error;
> int val;
>
> - /* Set up our directory */
> - dmi_kobj = kobject_create_and_add("dmi", firmware_kobj);
> - if (!dmi_kobj)
> + if (!dmi_kobj) {
> + pr_err("dmi-sysfs: dmi entry is absent.\n");
> + error = -ENODATA;
> goto err;
> + }
>
> dmi_kset = kset_create_and_add("entries", NULL, dmi_kobj);
> - if (!dmi_kset)
> + if (!dmi_kset) {
> + error = -ENOMEM;
> goto err;
> + }
>
> val = 0;
> error = dmi_walk(dmi_sysfs_register_handle, &val);
> @@ -675,7 +677,6 @@ static int __init dmi_sysfs_init(void)
> err:
> cleanup_entry_list();
> kset_unregister(dmi_kset);
> - kobject_put(dmi_kobj);
> return error;
> }
>
> @@ -685,8 +686,6 @@ static void __exit dmi_sysfs_exit(void)
> pr_debug("dmi-sysfs: unloading.\n");
> cleanup_entry_list();
> kset_unregister(dmi_kset);
> - kobject_del(dmi_kobj);
> - kobject_put(dmi_kobj);
> }
>
> module_init(dmi_sysfs_init);
> diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
> index a864a6b..9705be2 100644
> --- a/drivers/firmware/dmi_scan.c
> +++ b/drivers/firmware/dmi_scan.c
> @@ -10,6 +10,9 @@
> #include <asm/dmi.h>
> #include <asm/unaligned.h>
>
> +struct kobject *dmi_kobj;
> +EXPORT_SYMBOL_GPL(dmi_kobj);
> +
> /*
> * DMI stands for "Desktop Management Interface". It is part
> * of and an antecedent to, SMBIOS, which stands for System
> @@ -20,6 +23,9 @@ static const char dmi_empty_string[] = " ";
> static u32 dmi_ver __initdata;
> static u32 dmi_len;
> static u16 dmi_num;
> +static u8 smbios_entry_point[32];
> +static int smbios_entry_point_size;
> +
> /*
> * Catch too early calls to dmi_check_system():
> */
> @@ -478,6 +484,8 @@ static int __init dmi_present(const u8 *buf)
> if (memcmp(buf, "_SM_", 4) == 0 &&
> buf[5] < 32 && dmi_checksum(buf, buf[5])) {
> smbios_ver = get_unaligned_be16(buf + 6);
> + smbios_entry_point_size = buf[5];
> + memcpy(smbios_entry_point, buf, smbios_entry_point_size);
>
> /* Some BIOS report weird SMBIOS version, fix that up */
> switch (smbios_ver) {
> @@ -512,6 +520,9 @@ static int __init dmi_present(const u8 *buf)
> pr_info("SMBIOS %d.%d present.\n",
> dmi_ver >> 8, dmi_ver & 0xFF);
> } else {
> + smbios_entry_point_size = 15;
> + memcpy(smbios_entry_point, buf,
> + smbios_entry_point_size);
> pr_info("Legacy DMI %d.%d present.\n",
> dmi_ver >> 8, dmi_ver & 0xFF);
> }
> @@ -538,6 +549,8 @@ static int __init dmi_smbios3_present(const u8 *buf)
> dmi_num = 0; /* No longer specified */
> dmi_len = get_unaligned_le32(buf + 12);
> dmi_base = get_unaligned_le64(buf + 16);
> + smbios_entry_point_size = buf[6];
> + memcpy(smbios_entry_point, buf, smbios_entry_point_size);
>
> if (dmi_walk_early(dmi_decode) == 0) {
> pr_info("SMBIOS %d.%d.%d present.\n",
> @@ -629,6 +642,75 @@ void __init dmi_scan_machine(void)
> dmi_initialized = 1;
> }
>
> +static ssize_t raw_table_read(struct file *file, struct kobject *kobj,
> + struct bin_attribute *attr, char *buf,
> + loff_t pos, size_t count)
> +{
> + memcpy(buf, attr->private + pos, count);
> + return count;
> +}
> +
> +static BIN_ATTR(smbios_entry_point, S_IRUSR, raw_table_read, NULL, 0);
> +static BIN_ATTR(DMI, S_IRUSR, raw_table_read, NULL, 0);
> +
> +static int __init dmi_init(void)
> +{
> + int ret;
> + u8 *dmi_table = NULL;
> + struct kobject *tables_kobj = NULL;
> +
> + if (!dmi_available) {
> + ret = -ENODATA;
> + goto err;
> + }
> +
> + /*
> + * Set up dmi directory at /sys/firmware/dmi. This entry should stay
> + * even after farther error, as it can be used by other modules like
> + * dmi-sysfs.
> + */
> + dmi_kobj = kobject_create_and_add("dmi", firmware_kobj);
> + tables_kobj = kobject_create_and_add("tables", dmi_kobj);
> + if (!(dmi_kobj && tables_kobj)) {
> + ret = -ENOMEM;
> + goto err;
> + }
> +
> + bin_attr_smbios_entry_point.size = smbios_entry_point_size;
> + bin_attr_smbios_entry_point.private = smbios_entry_point;
> + ret = sysfs_create_bin_file(tables_kobj, &bin_attr_smbios_entry_point);
> + if (ret)
> + goto err;
> +
> + dmi_table = dmi_remap(dmi_base, dmi_len);
> + if (!dmi_table) {
> + ret = -ENOMEM;
> + goto err;
> + }
> +
> + bin_attr_DMI.size = dmi_len;
> + bin_attr_DMI.private = dmi_table;
> + ret = sysfs_create_bin_file(tables_kobj, &bin_attr_DMI);
> + if (!ret)
> + return 0;
> +
> +err:
> + pr_err("dmi: Firmware registration failed.\n");
> +
> + if (tables_kobj) {
> + sysfs_remove_bin_file(tables_kobj,
> + &bin_attr_smbios_entry_point);
> + kobject_del(tables_kobj);
> + kobject_put(tables_kobj);
> + }
> +
> + if (dmi_table)
> + dmi_unmap(dmi_table);
> +
> + return ret;
> +}
> +subsys_initcall(dmi_init);
> +
> /**
> * dmi_set_dump_stack_arch_desc - set arch description for dump_stack()
> *
> diff --git a/include/linux/dmi.h b/include/linux/dmi.h
> index f820f0a..2f9f988 100644
> --- a/include/linux/dmi.h
> +++ b/include/linux/dmi.h
> @@ -2,6 +2,7 @@
> #define __DMI_H__
>
> #include <linux/list.h>
> +#include <linux/kobject.h>
> #include <linux/mod_devicetable.h>
>
> /* enum dmi_field is in mod_devicetable.h */
> @@ -93,6 +94,7 @@ struct dmi_dev_onboard {
> int devfn;
> };
>
> +extern struct kobject *dmi_kobj;
> extern int dmi_check_system(const struct dmi_system_id *list);
> const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list);
> extern const char * dmi_get_system_info(int field);
> --
> 1.9.1
>
^ permalink raw reply
* Re: [v13 2/5] ext4: adds project ID support
From: Andreas Dilger @ 2015-04-20 23:25 UTC (permalink / raw)
To: Li Xi
Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
linux-ext4-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA, tytso-3s7WtUTddSA,
jack-AlSwsSmVLrQ, viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn,
hch-wEGCiKHe2LqWVfeAwA7xHQ, dmonakhov-GEFAQzZX7r8dnm+yROfE0A
In-Reply-To: <1429493988-16819-3-git-send-email-lixi-LfVdkaOWEx8@public.gmane.org>
On Apr 19, 2015, at 7:39 PM, Li Xi <pkuelelixi-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
>
> This patch adds a new internal field of ext4 inode to save project
> identifier. Also a new flag EXT4_INODE_PROJINHERIT is added for
> inheriting project ID from parent directory.
>
> @@ -3930,12 +3939,18 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
> inode->i_mode = le16_to_cpu(raw_inode->i_mode);
> i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
> i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
> + if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_PROJECT))
> + i_projid = (projid_t)le32_to_cpu(raw_inode->i_projid);
This needs to check if EXT4_PROJID_INHERIT_FL is set, and if i_projid
fits in i_extra_isize, otherwise it could be accessing a garbage value
beyond i_extra_isize.
Cheers, Andreas
^ permalink raw reply
* Re: [v13 3/5] ext4: adds project quota support
From: Andreas Dilger @ 2015-04-20 23:27 UTC (permalink / raw)
To: Li Xi
Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
linux-ext4-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA, tytso-3s7WtUTddSA,
jack-AlSwsSmVLrQ, viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn,
hch-wEGCiKHe2LqWVfeAwA7xHQ, dmonakhov-GEFAQzZX7r8dnm+yROfE0A
In-Reply-To: <1429493988-16819-4-git-send-email-lixi-LfVdkaOWEx8@public.gmane.org>
On Apr 19, 2015, at 7:39 PM, Li Xi <pkuelelixi-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
>
> This patch adds mount options for enabling/disabling project quota
> accounting and enforcement. A new specific inode is also used for
> project quota accounting.
>
> Signed-off-by: Li Xi <lixi-LfVdkaOWEx8@public.gmane.org>
> Signed-off-by: Dmitry Monakhov <dmonakhov-GEFAQzZX7r8dnm+yROfE0A@public.gmane.org>
> Reviewed-by: Jan Kara <jack-AlSwsSmVLrQ@public.gmane.org>
> ---
> fs/ext4/ext4.h | 6 +++-
> fs/ext4/super.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++----
> 2 files changed, 55 insertions(+), 7 deletions(-)
>
> diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
> index 1446c4f..a7acf10 100644
> --- a/fs/ext4/ext4.h
> +++ b/fs/ext4/ext4.h
> @@ -1169,7 +1169,8 @@ struct ext4_super_block {
> __le32 s_overhead_clusters; /* overhead blocks/clusters in fs */
> __le32 s_backup_bgs[2]; /* groups with sparse_super2 SBs */
> __u8 s_encrypt_algos[4]; /* Encryption algorithms in use */
> - __le32 s_reserved[105]; /* Padding to the end of the block */
> + __le32 s_prj_quota_inum; /* inode for tracking project quota */
> + __le32 s_reserved[104]; /* Padding to the end of the block */
> __le32 s_checksum; /* crc32c(superblock) */
> };
>
> @@ -1184,7 +1185,7 @@ struct ext4_super_block {
> #define EXT4_MF_FS_ABORTED 0x0002 /* Fatal error detected */
>
> /* Number of quota types we support */
> -#define EXT4_MAXQUOTAS 2
> +#define EXT4_MAXQUOTAS 3
>
> /*
> * fourth extended-fs super-block data in memory
> @@ -1376,6 +1377,7 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
> ino == EXT4_BOOT_LOADER_INO ||
> ino == EXT4_JOURNAL_INO ||
> ino == EXT4_RESIZE_INO ||
> + ino == le32_to_cpu(EXT4_SB(sb)->s_es->s_prj_quota_inum) ||
This extra check isn't needed, since s_proj_quota_inum will be a regular
inode number and handled by the checks below.
Cheers, Andreas.
> (ino >= EXT4_FIRST_INO(sb) &&
> ino <= le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count));
> }
> diff --git a/fs/ext4/super.c b/fs/ext4/super.c
> index 04c6cc3..476e46f 100644
> --- a/fs/ext4/super.c
> +++ b/fs/ext4/super.c
> @@ -1036,8 +1036,8 @@ static int bdev_try_to_free_page(struct super_block *sb, struct page *page,
> }
>
> #ifdef CONFIG_QUOTA
> -#define QTYPE2NAME(t) ((t) == USRQUOTA ? "user" : "group")
> -#define QTYPE2MOPT(on, t) ((t) == USRQUOTA?((on)##USRJQUOTA):((on)##GRPJQUOTA))
> +static char *quotatypes[] = INITQFNAMES;
> +#define QTYPE2NAME(t) (quotatypes[t])
>
> static int ext4_write_dquot(struct dquot *dquot);
> static int ext4_acquire_dquot(struct dquot *dquot);
> @@ -3944,7 +3944,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
> sb->s_qcop = &ext4_qctl_sysfile_operations;
> else
> sb->s_qcop = &ext4_qctl_operations;
> - sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP;
> + sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP | QTYPE_MASK_PRJ;
> #endif
> memcpy(sb->s_uuid, es->s_uuid, sizeof(es->s_uuid));
>
> @@ -5040,6 +5040,46 @@ restore_opts:
> return err;
> }
>
> +static int ext4_statfs_project(struct super_block *sb,
> + kprojid_t projid, struct kstatfs *buf)
> +{
> + struct kqid qid;
> + struct dquot *dquot;
> + u64 limit;
> + u64 curblock;
> +
> + qid = make_kqid_projid(projid);
> + dquot = dqget(sb, qid);
> + if (!dquot)
> + return -ESRCH;
> + spin_lock(&dq_data_lock);
> +
> + limit = dquot->dq_dqb.dqb_bsoftlimit ?
> + dquot->dq_dqb.dqb_bsoftlimit :
> + dquot->dq_dqb.dqb_bhardlimit;
> + if (limit && buf->f_blocks * buf->f_bsize > limit) {
> + curblock = dquot->dq_dqb.dqb_curspace / buf->f_bsize;
> + buf->f_blocks = limit / buf->f_bsize;
> + buf->f_bfree = buf->f_bavail =
> + (buf->f_blocks > curblock) ?
> + (buf->f_blocks - curblock) : 0;
> + }
> +
> + limit = dquot->dq_dqb.dqb_isoftlimit ?
> + dquot->dq_dqb.dqb_isoftlimit :
> + dquot->dq_dqb.dqb_ihardlimit;
> + if (limit && buf->f_files > limit) {
> + buf->f_files = limit;
> + buf->f_ffree =
> + (buf->f_files > dquot->dq_dqb.dqb_curinodes) ?
> + (buf->f_files - dquot->dq_dqb.dqb_curinodes) : 0;
> + }
> +
> + spin_unlock(&dq_data_lock);
> + dqput(dquot);
> + return 0;
> +}
> +
> static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf)
> {
> struct super_block *sb = dentry->d_sb;
> @@ -5048,6 +5088,7 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf)
> ext4_fsblk_t overhead = 0, resv_blocks;
> u64 fsid;
> s64 bfree;
> + struct inode *inode = dentry->d_inode;
> resv_blocks = EXT4_C2B(sbi, atomic64_read(&sbi->s_resv_clusters));
>
> if (!test_opt(sb, MINIX_DF))
> @@ -5072,6 +5113,9 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf)
> buf->f_fsid.val[0] = fsid & 0xFFFFFFFFUL;
> buf->f_fsid.val[1] = (fsid >> 32) & 0xFFFFFFFFUL;
>
> + if (ext4_test_inode_flag(inode, EXT4_INODE_PROJINHERIT) &&
> + sb_has_quota_limits_enabled(sb, PRJQUOTA))
> + ext4_statfs_project(sb, EXT4_I(inode)->i_projid, buf);
> return 0;
> }
>
> @@ -5236,7 +5280,8 @@ static int ext4_quota_enable(struct super_block *sb, int type, int format_id,
> struct inode *qf_inode;
> unsigned long qf_inums[EXT4_MAXQUOTAS] = {
> le32_to_cpu(EXT4_SB(sb)->s_es->s_usr_quota_inum),
> - le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum)
> + le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum),
> + le32_to_cpu(EXT4_SB(sb)->s_es->s_prj_quota_inum)
> };
>
> BUG_ON(!EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA));
> @@ -5264,7 +5309,8 @@ static int ext4_enable_quotas(struct super_block *sb)
> int type, err = 0;
> unsigned long qf_inums[EXT4_MAXQUOTAS] = {
> le32_to_cpu(EXT4_SB(sb)->s_es->s_usr_quota_inum),
> - le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum)
> + le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum),
> + le32_to_cpu(EXT4_SB(sb)->s_es->s_prj_quota_inum)
> };
>
> sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE;
> --
> 1.7.1
>
Cheers, Andreas
^ permalink raw reply
* Re: [v13 4/5] ext4: adds FS_IOC_FSSETXATTR/FS_IOC_FSGETXATTR interface support
From: Andreas Dilger @ 2015-04-20 23:33 UTC (permalink / raw)
To: Li Xi
Cc: linux-fsdevel, linux-ext4, linux-api, tytso, jack, viro, hch,
dmonakhov
In-Reply-To: <1429493988-16819-5-git-send-email-lixi@ddn.com>
On Apr 19, 2015, at 7:39 PM, Li Xi <pkuelelixi@gmail.com> wrote:
>
> This patch adds FS_IOC_FSSETXATTR/FS_IOC_FSGETXATTR ioctl interface
> support for ext4. The interface is kept consistent with
> XFS_IOC_FSGETXATTR/XFS_IOC_FSGETXATTR.
>
> +static int ext4_ioctl_setproject(struct file *filp, __u32 projid)
> +{
> + struct inode *inode = file_inode(filp);
> + struct super_block *sb = inode->i_sb;
> + struct ext4_inode_info *ei = EXT4_I(inode);
> + int err;
> + handle_t *handle;
> + kprojid_t kprojid;
> + struct ext4_iloc iloc;
> + struct ext4_inode *raw_inode;
> +
> + struct dquot *transfer_to[EXT4_MAXQUOTAS] = { };
> +
> + if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
> + EXT4_FEATURE_RO_COMPAT_PROJECT)) {
> + BUG_ON(__kprojid_val(EXT4_I(inode)->i_projid)
> + != EXT4_DEF_PROJID);
> + if (projid != EXT4_DEF_PROJID)
> + return -EOPNOTSUPP;
> + else
> + return 0;
> + }
> +
> + kprojid = make_kprojid(&init_user_ns, (projid_t)projid);
> +
> + if (projid_eq(kprojid, EXT4_I(inode)->i_projid))
> + return 0;
> +
> + err = mnt_want_write_file(filp);
> + if (err)
> + return err;
> +
> + err = -EPERM;
> + mutex_lock(&inode->i_mutex);
> + /* Is it quota file? Do not allow user to mess with it */
> + if (IS_NOQUOTA(inode))
> + goto project_out;
> +
> + dquot_initialize(inode);
> +
> + handle = ext4_journal_start(inode, EXT4_HT_QUOTA,
> + EXT4_QUOTA_INIT_BLOCKS(sb) +
> + EXT4_QUOTA_DEL_BLOCKS(sb) + 3);
> + if (IS_ERR(handle)) {
> + err = PTR_ERR(handle);
> + goto project_out;
> + }
> +
> + err = ext4_reserve_inode_write(handle, inode, &iloc);
> + if (err)
> + goto project_stop;
> +
> + raw_inode = ext4_raw_inode(&iloc);
> + if (EXT4_INODE_SIZE(sb) <= EXT4_GOOD_OLD_INODE_SIZE) {
> + err = -EOPNOTSUPP;
> + goto project_stop;
> + }
This check can be done much earlier, since it isn't going to change.
It is probably best before getting i_mutex.
> + if (!EXT4_FITS_IN_INODE(raw_inode, ei, i_projid)) {
> + err = -EOVERFLOW;
> + goto project_stop;
> + }
Similarly, this can be done before starting the transaction, though
i_extra_isize may change in the future and it makes sense to check
after i_mutex is held.
Cheers, Andreas
> +
> + transfer_to[PRJQUOTA] = dqget(sb, make_kqid_projid(kprojid));
> + if (!transfer_to[PRJQUOTA])
> + goto project_set;
> +
> + err = __dquot_transfer(inode, transfer_to);
> + dqput(transfer_to[PRJQUOTA]);
> + if (err)
> + goto project_stop;
> +
> +project_set:
> + EXT4_I(inode)->i_projid = kprojid;
> + inode->i_ctime = ext4_current_time(inode);
> + err = ext4_mark_iloc_dirty(handle, inode, &iloc);
> +project_stop:
> + ext4_journal_stop(handle);
> +project_out:
> + mutex_unlock(&inode->i_mutex);
> + mnt_drop_write_file(filp);
> + return err;
> +}
> +
> +/* Transfer internal flags to xflags */
> +static inline __u32 ext4_iflags_to_xflags(unsigned long iflags)
> +{
> + __u32 xflags = 0;
> +
> + if (iflags & EXT4_SYNC_FL)
> + xflags |= FS_XFLAG_SYNC;
> + if (iflags & EXT4_IMMUTABLE_FL)
> + xflags |= FS_XFLAG_IMMUTABLE;
> + if (iflags & EXT4_APPEND_FL)
> + xflags |= FS_XFLAG_APPEND;
> + if (iflags & EXT4_NODUMP_FL)
> + xflags |= FS_XFLAG_NODUMP;
> + if (iflags & EXT4_NOATIME_FL)
> + xflags |= FS_XFLAG_NOATIME;
> + if (iflags & EXT4_PROJINHERIT_FL)
> + xflags |= FS_XFLAG_PROJINHERIT;
> + return xflags;
> +}
> +
> +/* Transfer xflags flags to internal */
> +static inline unsigned long ext4_xflags_to_iflags(__u32 xflags)
> +{
> + unsigned long iflags = 0;
> +
> + if (xflags & FS_XFLAG_SYNC)
> + iflags |= EXT4_SYNC_FL;
> + if (xflags & FS_XFLAG_IMMUTABLE)
> + iflags |= EXT4_IMMUTABLE_FL;
> + if (xflags & FS_XFLAG_APPEND)
> + iflags |= EXT4_APPEND_FL;
> + if (xflags & FS_XFLAG_NODUMP)
> + iflags |= EXT4_NODUMP_FL;
> + if (xflags & FS_XFLAG_NOATIME)
> + iflags |= EXT4_NOATIME_FL;
> + if (xflags & FS_XFLAG_PROJINHERIT)
> + iflags |= EXT4_PROJINHERIT_FL;
> +
> + return iflags;
> +}
> +
> long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
> {
> struct inode *inode = file_inode(filp);
> @@ -211,11 +432,7 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
> flags = ei->i_flags & EXT4_FL_USER_VISIBLE;
> return put_user(flags, (int __user *) arg);
> case EXT4_IOC_SETFLAGS: {
> - handle_t *handle = NULL;
> - int err, migrate = 0;
> - struct ext4_iloc iloc;
> - unsigned int oldflags, mask, i;
> - unsigned int jflag;
> + int err;
>
> if (!inode_owner_or_capable(inode))
> return -EACCES;
> @@ -229,89 +446,8 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
>
> flags = ext4_mask_flags(inode->i_mode, flags);
>
> - err = -EPERM;
> mutex_lock(&inode->i_mutex);
> - /* Is it quota file? Do not allow user to mess with it */
> - if (IS_NOQUOTA(inode))
> - goto flags_out;
> -
> - oldflags = ei->i_flags;
> -
> - /* 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;
> - }
> -
> - /*
> - * The JOURNAL_DATA flag can only be changed by
> - * the relevant capability.
> - */
> - if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) {
> - if (!capable(CAP_SYS_RESOURCE))
> - goto flags_out;
> - }
> - if ((flags ^ oldflags) & EXT4_EXTENTS_FL)
> - migrate = 1;
> -
> - if (flags & EXT4_EOFBLOCKS_FL) {
> - /* we don't support adding EOFBLOCKS flag */
> - if (!(oldflags & EXT4_EOFBLOCKS_FL)) {
> - err = -EOPNOTSUPP;
> - goto flags_out;
> - }
> - } else if (oldflags & EXT4_EOFBLOCKS_FL)
> - ext4_truncate(inode);
> -
> - handle = ext4_journal_start(inode, EXT4_HT_INODE, 1);
> - if (IS_ERR(handle)) {
> - err = PTR_ERR(handle);
> - goto flags_out;
> - }
> - if (IS_SYNC(inode))
> - ext4_handle_sync(handle);
> - err = ext4_reserve_inode_write(handle, inode, &iloc);
> - if (err)
> - goto flags_err;
> -
> - for (i = 0, mask = 1; i < 32; i++, mask <<= 1) {
> - if (!(mask & EXT4_FL_USER_MODIFIABLE))
> - continue;
> - if (mask & flags)
> - ext4_set_inode_flag(inode, i);
> - else
> - ext4_clear_inode_flag(inode, i);
> - }
> -
> - ext4_set_inode_flags(inode);
> - inode->i_ctime = ext4_current_time(inode);
> -
> - err = ext4_mark_iloc_dirty(handle, inode, &iloc);
> -flags_err:
> - ext4_journal_stop(handle);
> - if (err)
> - goto flags_out;
> -
> - if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL))
> - err = ext4_change_inode_journal_flag(inode, jflag);
> - if (err)
> - goto flags_out;
> - if (migrate) {
> - if (flags & EXT4_EXTENTS_FL)
> - err = ext4_ext_migrate(inode);
> - else
> - err = ext4_ind_migrate(inode);
> - }
> -
> -flags_out:
> + err = ext4_ioctl_setflags(inode, flags);
> mutex_unlock(&inode->i_mutex);
> mnt_drop_write_file(filp);
> return err;
> @@ -615,7 +751,61 @@ resizefs_out:
> }
> case EXT4_IOC_PRECACHE_EXTENTS:
> return ext4_ext_precache(inode);
> + case EXT4_IOC_FSGETXATTR:
> + {
> + struct fsxattr fa;
> +
> + memset(&fa, 0, sizeof(struct fsxattr));
>
> + ext4_get_inode_flags(ei);
> + fa.fsx_xflags = ext4_iflags_to_xflags(ei->i_flags & EXT4_FL_USER_VISIBLE);
> +
> + if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
> + EXT4_FEATURE_RO_COMPAT_PROJECT)) {
> + fa.fsx_projid = (__u32)from_kprojid(&init_user_ns,
> + EXT4_I(inode)->i_projid);
> + }
> +
> + if (copy_to_user((struct fsxattr __user *)arg,
> + &fa, sizeof(fa)))
> + return -EFAULT;
> + return 0;
> + }
> + case EXT4_IOC_FSSETXATTR:
> + {
> + struct fsxattr fa;
> + int err;
> +
> + if (copy_from_user(&fa, (struct fsxattr __user *)arg,
> + sizeof(fa)))
> + return -EFAULT;
> +
> + /* Make sure caller has proper permission */
> + if (!inode_owner_or_capable(inode))
> + return -EACCES;
> +
> + err = mnt_want_write_file(filp);
> + if (err)
> + return err;
> +
> + flags = ext4_xflags_to_iflags(fa.fsx_xflags);
> + flags = ext4_mask_flags(inode->i_mode, flags);
> +
> + mutex_lock(&inode->i_mutex);
> + flags = (ei->i_flags & ~EXT4_FL_XFLAG_VISIBLE) |
> + (flags & EXT4_FL_XFLAG_VISIBLE);
> + err = ext4_ioctl_setflags(inode, flags);
> + mutex_unlock(&inode->i_mutex);
> + mnt_drop_write_file(filp);
> + if (err)
> + return err;
> +
> + err = ext4_ioctl_setproject(filp, fa.fsx_projid);
> + if (err)
> + return err;
> +
> + return 0;
> + }
> default:
> return -ENOTTY;
> }
> diff --git a/fs/xfs/xfs_fs.h b/fs/xfs/xfs_fs.h
> index 18dc721..64c7ae6 100644
> --- a/fs/xfs/xfs_fs.h
> +++ b/fs/xfs/xfs_fs.h
> @@ -36,38 +36,25 @@ struct dioattr {
> #endif
>
> /*
> - * Structure for XFS_IOC_FSGETXATTR[A] and XFS_IOC_FSSETXATTR.
> - */
> -#ifndef HAVE_FSXATTR
> -struct fsxattr {
> - __u32 fsx_xflags; /* xflags field value (get/set) */
> - __u32 fsx_extsize; /* extsize field value (get/set)*/
> - __u32 fsx_nextents; /* nextents field value (get) */
> - __u32 fsx_projid; /* project identifier (get/set) */
> - unsigned char fsx_pad[12];
> -};
> -#endif
> -
> -/*
> * Flags for the bs_xflags/fsx_xflags field
> * There should be a one-to-one correspondence between these flags and the
> * XFS_DIFLAG_s.
> */
> -#define XFS_XFLAG_REALTIME 0x00000001 /* data in realtime volume */
> -#define XFS_XFLAG_PREALLOC 0x00000002 /* preallocated file extents */
> -#define XFS_XFLAG_IMMUTABLE 0x00000008 /* file cannot be modified */
> -#define XFS_XFLAG_APPEND 0x00000010 /* all writes append */
> -#define XFS_XFLAG_SYNC 0x00000020 /* all writes synchronous */
> -#define XFS_XFLAG_NOATIME 0x00000040 /* do not update access time */
> -#define XFS_XFLAG_NODUMP 0x00000080 /* do not include in backups */
> -#define XFS_XFLAG_RTINHERIT 0x00000100 /* create with rt bit set */
> -#define XFS_XFLAG_PROJINHERIT 0x00000200 /* create with parents projid */
> -#define XFS_XFLAG_NOSYMLINKS 0x00000400 /* disallow symlink creation */
> -#define XFS_XFLAG_EXTSIZE 0x00000800 /* extent size allocator hint */
> -#define XFS_XFLAG_EXTSZINHERIT 0x00001000 /* inherit inode extent size */
> -#define XFS_XFLAG_NODEFRAG 0x00002000 /* do not defragment */
> -#define XFS_XFLAG_FILESTREAM 0x00004000 /* use filestream allocator */
> -#define XFS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */
> +#define XFS_XFLAG_REALTIME FS_XFLAG_REALTIME /* data in realtime volume */
> +#define XFS_XFLAG_PREALLOC FS_XFLAG_PREALLOC /* preallocated file extents */
> +#define XFS_XFLAG_IMMUTABLE FS_XFLAG_IMMUTABLE /* file cannot be modified */
> +#define XFS_XFLAG_APPEND FS_XFLAG_APPEND /* all writes append */
> +#define XFS_XFLAG_SYNC FS_XFLAG_SYNC /* all writes synchronous */
> +#define XFS_XFLAG_NOATIME FS_XFLAG_NOATIME /* do not update access time */
> +#define XFS_XFLAG_NODUMP FS_XFLAG_NODUMP /* do not include in backups */
> +#define XFS_XFLAG_RTINHERIT FS_XFLAG_RTINHERIT /* create with rt bit set */
> +#define XFS_XFLAG_PROJINHERIT FS_XFLAG_PROJINHERIT /* create with parents projid */
> +#define XFS_XFLAG_NOSYMLINKS FS_XFLAG_NOSYMLINKS /* disallow symlink creation */
> +#define XFS_XFLAG_EXTSIZE FS_XFLAG_EXTSIZE /* extent size allocator hint */
> +#define XFS_XFLAG_EXTSZINHERIT FS_XFLAG_EXTSZINHERIT /* inherit inode extent size */
> +#define XFS_XFLAG_NODEFRAG FS_XFLAG_NODEFRAG /* do not defragment */
> +#define XFS_XFLAG_FILESTREAM FS_XFLAG_FILESTREAM /* use filestream allocator */
> +#define XFS_XFLAG_HASATTR FS_XFLAG_HASATTR /* no DIFLAG for this */
>
> /*
> * Structure for XFS_IOC_GETBMAP.
> @@ -503,8 +490,8 @@ typedef struct xfs_swapext
> #define XFS_IOC_ALLOCSP _IOW ('X', 10, struct xfs_flock64)
> #define XFS_IOC_FREESP _IOW ('X', 11, struct xfs_flock64)
> #define XFS_IOC_DIOINFO _IOR ('X', 30, struct dioattr)
> -#define XFS_IOC_FSGETXATTR _IOR ('X', 31, struct fsxattr)
> -#define XFS_IOC_FSSETXATTR _IOW ('X', 32, struct fsxattr)
> +#define XFS_IOC_FSGETXATTR FS_IOC_FSGETXATTR
> +#define XFS_IOC_FSSETXATTR FS_IOC_FSSETXATTR
> #define XFS_IOC_ALLOCSP64 _IOW ('X', 36, struct xfs_flock64)
> #define XFS_IOC_FREESP64 _IOW ('X', 37, struct xfs_flock64)
> #define XFS_IOC_GETBMAP _IOWR('X', 38, struct getbmap)
> diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
> index fcbf647..69dda62 100644
> --- a/include/uapi/linux/fs.h
> +++ b/include/uapi/linux/fs.h
> @@ -58,6 +58,36 @@ struct inodes_stat_t {
> long dummy[5]; /* padding for sysctl ABI compatibility */
> };
>
> +/*
> + * Structure for FS_IOC_FSGETXATTR and FS_IOC_FSSETXATTR.
> + */
> +struct fsxattr {
> + __u32 fsx_xflags; /* xflags field value (get/set) */
> + __u32 fsx_extsize; /* extsize field value (get/set)*/
> + __u32 fsx_nextents; /* nextents field value (get) */
> + __u32 fsx_projid; /* project identifier (get/set) */
> + unsigned char fsx_pad[12];
> +};
> +
> +/*
> + * Flags for the fsx_xflags field
> + */
> +#define FS_XFLAG_REALTIME 0x00000001 /* data in realtime volume */
> +#define FS_XFLAG_PREALLOC 0x00000002 /* preallocated file extents */
> +#define FS_XFLAG_IMMUTABLE 0x00000008 /* file cannot be modified */
> +#define FS_XFLAG_APPEND 0x00000010 /* all writes append */
> +#define FS_XFLAG_SYNC 0x00000020 /* all writes synchronous */
> +#define FS_XFLAG_NOATIME 0x00000040 /* do not update access time */
> +#define FS_XFLAG_NODUMP 0x00000080 /* do not include in backups */
> +#define FS_XFLAG_RTINHERIT 0x00000100 /* create with rt bit set */
> +#define FS_XFLAG_PROJINHERIT 0x00000200 /* create with parents projid */
> +#define FS_XFLAG_NOSYMLINKS 0x00000400 /* disallow symlink creation */
> +#define FS_XFLAG_EXTSIZE 0x00000800 /* extent size allocator hint */
> +#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_HASATTR 0x80000000 /* no DIFLAG for this */
> +
>
> #define NR_FILE 8192 /* this can well be larger on a larger system */
>
> @@ -163,6 +193,8 @@ struct inodes_stat_t {
> #define FS_IOC_GETVERSION _IOR('v', 1, long)
> #define FS_IOC_SETVERSION _IOW('v', 2, long)
> #define FS_IOC_FIEMAP _IOWR('f', 11, struct fiemap)
> +#define FS_IOC_FSGETXATTR _IOR('X', 31, struct fsxattr)
> +#define FS_IOC_FSSETXATTR _IOW('X', 32, struct fsxattr)
> #define FS_IOC32_GETFLAGS _IOR('f', 1, int)
> #define FS_IOC32_SETFLAGS _IOW('f', 2, int)
> #define FS_IOC32_GETVERSION _IOR('v', 1, int)
> --
> 1.7.1
>
Cheers, Andreas
^ permalink raw reply
* Write with Stream ID Support
From: kwan.huen @ 2015-04-21 1:47 UTC (permalink / raw)
To: Matthew Wilcox, Keith Busch, Jens Axboe,
kwan.huen-Sze3O3UU22JBDgjK7y7TUQ, Dimitri John Ledkov
Cc: linux-nvme-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA
The attached patch set enables basic write with stream ID support.
First patch reads the stream id embedded in the bio and passes to the
device along with the write command.
Second patch adds two new nvme commands to be used with ioctl
such that application can do open/close stream and host
initiated garbage collection.
^ permalink raw reply
* [PATCH 1/2] added stream id write support
From: kwan.huen @ 2015-04-21 1:47 UTC (permalink / raw)
To: Matthew Wilcox, Keith Busch, Jens Axboe,
kwan.huen-Sze3O3UU22JBDgjK7y7TUQ, Dimitri John Ledkov
Cc: linux-nvme-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1429580863-3451-1-git-send-email-kwan.huen-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
drivers/block/nvme-core.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c
index 85b8036..332341a 100644
--- a/drivers/block/nvme-core.c
+++ b/drivers/block/nvme-core.c
@@ -769,6 +769,9 @@ static int nvme_submit_iod(struct nvme_queue *nvmeq, struct nvme_iod *iod,
if (req->cmd_flags & REQ_RAHEAD)
dsmgmt |= NVME_RW_DSM_FREQ_PREFETCH;
+ if (rq_data_dir(req))
+ dsmgmt |= bio_get_streamid(req->bio) << 8;
+
cmnd = &nvmeq->sq_cmds[nvmeq->sq_tail];
memset(cmnd, 0, sizeof(*cmnd));
--
1.9.1
^ permalink raw reply related
* [PATCH 2/2] added two nvme commands for open/close streams and garbage collection
From: kwan.huen @ 2015-04-21 1:47 UTC (permalink / raw)
To: Matthew Wilcox, Keith Busch, Jens Axboe,
kwan.huen-Sze3O3UU22JBDgjK7y7TUQ, Dimitri John Ledkov
Cc: linux-nvme-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1429580863-3451-1-git-send-email-kwan.huen-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
include/uapi/linux/nvme.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/include/uapi/linux/nvme.h b/include/uapi/linux/nvme.h
index aef9a81..5025610 100644
--- a/include/uapi/linux/nvme.h
+++ b/include/uapi/linux/nvme.h
@@ -229,6 +229,8 @@ enum nvme_opcode {
nvme_cmd_resv_report = 0x0e,
nvme_cmd_resv_acquire = 0x11,
nvme_cmd_resv_release = 0x15,
+ nvme_cmd_stream_ctrl = 0x18,
+ nvme_cmd_gc_ctrl = 0x1c,
};
struct nvme_common_command {
--
1.9.1
^ permalink raw reply related
* Re: [PATCH v3 6/7] virtio: add explicit big-endian support to memory accessors
From: Greg Kurz @ 2015-04-21 7:47 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: Rusty Russell, linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, kvm-u79uwXL29TY76Z2rM5mHXA,
virtualization-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA
In-Reply-To: <20150407175522-mutt-send-email-mst-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
On Tue, 7 Apr 2015 17:56:25 +0200
"Michael S. Tsirkin" <mst-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> wrote:
> On Tue, Apr 07, 2015 at 02:15:52PM +0200, Greg Kurz wrote:
> > The current memory accessors logic is:
> > - little endian if little_endian
> > - native endian (i.e. no byteswap) if !little_endian
> >
> > If we want to fully support cross-endian vhost, we also need to be
> > able to convert to big endian.
> >
> > Instead of changing the little_endian argument to some 3-value enum, this
> > patch changes the logic to:
> > - little endian if little_endian
> > - big endian if !little_endian
> >
> > The native endian case is handled by all users with a trivial helper. This
> > patch doesn't change any functionality, nor it does add overhead.
> >
> > Signed-off-by: Greg Kurz <gkurz-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
> > ---
> > drivers/net/macvtap.c | 4 +++-
> > drivers/net/tun.c | 4 +++-
> > drivers/vhost/vhost.h | 4 +++-
> > include/linux/virtio_byteorder.h | 24 ++++++++++++++----------
> > include/linux/virtio_config.h | 4 +++-
> > include/linux/vringh.h | 4 +++-
> > 6 files changed, 29 insertions(+), 15 deletions(-)
> >
> > diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
> > index a2f2958..0a03a66 100644
> > --- a/drivers/net/macvtap.c
> > +++ b/drivers/net/macvtap.c
> > @@ -51,7 +51,9 @@ struct macvtap_queue {
> >
> > static inline bool macvtap_is_little_endian(struct macvtap_queue *q)
> > {
> > - return q->flags & MACVTAP_VNET_LE;
> > + if (q->flags & MACVTAP_VNET_LE)
> > + return true;
> > + return virtio_legacy_is_little_endian();
> > }
> >
> > static inline u16 macvtap16_to_cpu(struct macvtap_queue *q, __virtio16 val)
>
> Hmm I'm not sure how well this will work once you
> actually make it dynamic.
> Remains to be seen.
>
Oops I overlooked this mail... FWIW I could reboot/kexec from a ppc64 guest
to ppc64le and back with the following QEMU:
https://github.com/gkurz/qemu/commits/vhost/cross-endian
> > diff --git a/drivers/net/tun.c b/drivers/net/tun.c
> > index 3c3d6c0..053f9b6 100644
> > --- a/drivers/net/tun.c
> > +++ b/drivers/net/tun.c
> > @@ -208,7 +208,9 @@ struct tun_struct {
> >
> > static inline bool tun_is_little_endian(struct tun_struct *tun)
> > {
> > - return tun->flags & TUN_VNET_LE;
> > + if (tun->flags & TUN_VNET_LE)
> > + return true;
> > + return virtio_legacy_is_little_endian();
> > }
> >
> > static inline u16 tun16_to_cpu(struct tun_struct *tun, __virtio16 val)
> > diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h
> > index 6a49960..4e9a186 100644
> > --- a/drivers/vhost/vhost.h
> > +++ b/drivers/vhost/vhost.h
> > @@ -175,7 +175,9 @@ static inline bool vhost_has_feature(struct vhost_virtqueue *vq, int bit)
> >
> > static inline bool vhost_is_little_endian(struct vhost_virtqueue *vq)
> > {
> > - return vhost_has_feature(vq, VIRTIO_F_VERSION_1);
> > + if (vhost_has_feature(vq, VIRTIO_F_VERSION_1))
> > + return true;
> > + return virtio_legacy_is_little_endian();
> > }
> >
> > /* Memory accessors */
> > diff --git a/include/linux/virtio_byteorder.h b/include/linux/virtio_byteorder.h
> > index 51865d0..ce63a2c 100644
> > --- a/include/linux/virtio_byteorder.h
> > +++ b/include/linux/virtio_byteorder.h
> > @@ -3,17 +3,21 @@
> > #include <linux/types.h>
> > #include <uapi/linux/virtio_types.h>
> >
> > -/*
> > - * Low-level memory accessors for handling virtio in modern little endian and in
> > - * compatibility native endian format.
> > - */
> > +static inline bool virtio_legacy_is_little_endian(void)
> > +{
> > +#ifdef __LITTLE_ENDIAN
> > + return true;
> > +#else
> > + return false;
> > +#endif
> > +}
> >
> > static inline u16 __virtio16_to_cpu(bool little_endian, __virtio16 val)
> > {
> > if (little_endian)
> > return le16_to_cpu((__force __le16)val);
> > else
> > - return (__force u16)val;
> > + return be16_to_cpu((__force __be16)val);
> > }
> >
> > static inline __virtio16 __cpu_to_virtio16(bool little_endian, u16 val)
> > @@ -21,7 +25,7 @@ static inline __virtio16 __cpu_to_virtio16(bool little_endian, u16 val)
> > if (little_endian)
> > return (__force __virtio16)cpu_to_le16(val);
> > else
> > - return (__force __virtio16)val;
> > + return (__force __virtio16)cpu_to_be16(val);
> > }
> >
> > static inline u32 __virtio32_to_cpu(bool little_endian, __virtio32 val)
> > @@ -29,7 +33,7 @@ static inline u32 __virtio32_to_cpu(bool little_endian, __virtio32 val)
> > if (little_endian)
> > return le32_to_cpu((__force __le32)val);
> > else
> > - return (__force u32)val;
> > + return be32_to_cpu((__force __be32)val);
> > }
> >
> > static inline __virtio32 __cpu_to_virtio32(bool little_endian, u32 val)
> > @@ -37,7 +41,7 @@ static inline __virtio32 __cpu_to_virtio32(bool little_endian, u32 val)
> > if (little_endian)
> > return (__force __virtio32)cpu_to_le32(val);
> > else
> > - return (__force __virtio32)val;
> > + return (__force __virtio32)cpu_to_be32(val);
> > }
> >
> > static inline u64 __virtio64_to_cpu(bool little_endian, __virtio64 val)
> > @@ -45,7 +49,7 @@ static inline u64 __virtio64_to_cpu(bool little_endian, __virtio64 val)
> > if (little_endian)
> > return le64_to_cpu((__force __le64)val);
> > else
> > - return (__force u64)val;
> > + return be64_to_cpu((__force __be64)val);
> > }
> >
> > static inline __virtio64 __cpu_to_virtio64(bool little_endian, u64 val)
> > @@ -53,7 +57,7 @@ static inline __virtio64 __cpu_to_virtio64(bool little_endian, u64 val)
> > if (little_endian)
> > return (__force __virtio64)cpu_to_le64(val);
> > else
> > - return (__force __virtio64)val;
> > + return (__force __virtio64)cpu_to_be64(val);
> > }
> >
> > #endif /* _LINUX_VIRTIO_BYTEORDER */
> > diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h
> > index bd1a582..36a6daa 100644
> > --- a/include/linux/virtio_config.h
> > +++ b/include/linux/virtio_config.h
> > @@ -207,7 +207,9 @@ int virtqueue_set_affinity(struct virtqueue *vq, int cpu)
> >
> > static inline bool virtio_is_little_endian(struct virtio_device *vdev)
> > {
> > - return virtio_has_feature(vdev, VIRTIO_F_VERSION_1);
> > + if (virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
> > + return true;
> > + return virtio_legacy_is_little_endian();
> > }
> >
> > /* Memory accessors */
> > diff --git a/include/linux/vringh.h b/include/linux/vringh.h
> > index 3ed62ef..d786c2d 100644
> > --- a/include/linux/vringh.h
> > +++ b/include/linux/vringh.h
> > @@ -228,7 +228,9 @@ static inline void vringh_notify(struct vringh *vrh)
> >
> > static inline bool vringh_is_little_endian(const struct vringh *vrh)
> > {
> > - return vrh->little_endian;
> > + if (vrh->little_endian)
> > + return true;
> > + return virtio_legacy_is_little_endian();
> > }
> >
> > static inline u16 vringh16_to_cpu(const struct vringh *vrh, __virtio16 val)
>
^ permalink raw reply
* Re: [PATCH v4 0/8] vhost: support for cross endian guests
From: Greg Kurz @ 2015-04-21 7:50 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: Rusty Russell, linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, kvm-u79uwXL29TY76Z2rM5mHXA,
virtualization-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA
In-Reply-To: <20150417111813.2b795b2c-GiB8zCg7hOfDOqzlkpFKJg@public.gmane.org>
On Fri, 17 Apr 2015 11:18:13 +0200
Greg Kurz <gkurz-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org> wrote:
> On Fri, 10 Apr 2015 12:15:00 +0200
> Greg Kurz <gkurz-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org> wrote:
>
> > Hi,
> >
> > This patchset allows vhost to be used with legacy virtio when guest and host
> > have a different endianness.
> >
> > Patch 7 got rewritten according to Cornelia's and Michael's comments. I have
> > also introduced patch 8 that brings BE vnet headers support to tun/macvtap.
> >
> > This series is enough to have vhost_net working flawlessly. I could
> > succesfully reboot guests from ppc64 to ppc64le and vice-versa on ppc64
> > and ppc64le hosts.
> >
>
> Michael,
>
> I am ready to post v5 with the changes suggested by Cornelia... Do you have any
> extra comments on this v4 ?
>
Ping ?
> --
> Greg
>
> > ---
> >
> > Greg Kurz (8):
> > virtio: introduce virtio_is_little_endian() helper
> > tun: add tun_is_little_endian() helper
> > macvtap: introduce macvtap_is_little_endian() helper
> > vringh: introduce vringh_is_little_endian() helper
> > vhost: introduce vhost_is_little_endian() helper
> > virtio: add explicit big-endian support to memory accessors
> > vhost: feature to set the vring endianness
> > macvtap/tun: add VNET_BE flag
> >
> >
> > drivers/net/Kconfig | 12 ++++++
> > drivers/net/macvtap.c | 69 ++++++++++++++++++++++++++++++++++-
> > drivers/net/tun.c | 71 +++++++++++++++++++++++++++++++++++-
> > drivers/vhost/Kconfig | 10 +++++
> > drivers/vhost/vhost.c | 76 ++++++++++++++++++++++++++++++++++++++
> > drivers/vhost/vhost.h | 25 ++++++++++---
> > include/linux/virtio_byteorder.h | 24 +++++++-----
> > include/linux/virtio_config.h | 19 +++++++---
> > include/linux/vringh.h | 19 +++++++---
> > include/uapi/linux/if_tun.h | 2 +
> > include/uapi/linux/vhost.h | 9 +++++
> > 11 files changed, 303 insertions(+), 33 deletions(-)
> >
> > --
> > Greg
> >
> > _______________________________________________
> > Virtualization mailing list
> > Virtualization-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org
> > https://lists.linuxfoundation.org/mailman/listinfo/virtualization
> >
>
^ permalink raw reply
* Re: [v13 1/5] vfs: adds general codes to enforces project quota limits
From: Jan Kara @ 2015-04-21 11:56 UTC (permalink / raw)
To: Li Xi
Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
linux-ext4-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA, tytso-3s7WtUTddSA,
adilger-m1MBpc4rdrD3fQ9qLvQP4Q, jack-AlSwsSmVLrQ,
viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn, hch-wEGCiKHe2LqWVfeAwA7xHQ,
dmonakhov-GEFAQzZX7r8dnm+yROfE0A
In-Reply-To: <1429493988-16819-2-git-send-email-lixi-LfVdkaOWEx8@public.gmane.org>
On Mon 20-04-15 10:39:44, Li Xi wrote:
> This patch adds support for a new quota type PRJQUOTA for project quota
> enforcement. Also a new method get_projid() is added into dquot_operations
> structure.
>
> Signed-off-by: Li Xi <lixi-LfVdkaOWEx8@public.gmane.org>
> Signed-off-by: Dmitry Monakhov <dmonakhov-GEFAQzZX7r8dnm+yROfE0A@public.gmane.org>
> Reviewed-by: Jan Kara <jack-AlSwsSmVLrQ@public.gmane.org>
This patch is now upstream as commit
847aac644e92e5624f2c153bab409bf713d5ff9a. So you don't have to send it
in the next posting if you rebase on top of latest Linus' tree.
Honza
> ---
> fs/quota/dquot.c | 35 ++++++++++++++++++++++++++++++-----
> fs/quota/quota.c | 5 ++++-
> fs/quota/quotaio_v2.h | 6 ++++--
> include/linux/quota.h | 2 ++
> include/uapi/linux/quota.h | 6 ++++--
> 5 files changed, 44 insertions(+), 10 deletions(-)
>
> diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
> index 8f0acef..a02bb68 100644
> --- a/fs/quota/dquot.c
> +++ b/fs/quota/dquot.c
> @@ -1159,8 +1159,8 @@ static int need_print_warning(struct dquot_warn *warn)
> return uid_eq(current_fsuid(), warn->w_dq_id.uid);
> case GRPQUOTA:
> return in_group_p(warn->w_dq_id.gid);
> - case PRJQUOTA: /* Never taken... Just make gcc happy */
> - return 0;
> + case PRJQUOTA:
> + return 1;
> }
> return 0;
> }
> @@ -1399,6 +1399,9 @@ static void __dquot_initialize(struct inode *inode, int type)
> /* First get references to structures we might need. */
> for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
> struct kqid qid;
> + kprojid_t projid;
> + int rc;
> +
> got[cnt] = NULL;
> if (type != -1 && cnt != type)
> continue;
> @@ -1409,6 +1412,10 @@ static void __dquot_initialize(struct inode *inode, int type)
> */
> if (i_dquot(inode)[cnt])
> continue;
> +
> + if (!sb_has_quota_active(sb, cnt))
> + continue;
> +
> init_needed = 1;
>
> switch (cnt) {
> @@ -1418,6 +1425,12 @@ static void __dquot_initialize(struct inode *inode, int type)
> case GRPQUOTA:
> qid = make_kqid_gid(inode->i_gid);
> break;
> + case PRJQUOTA:
> + rc = inode->i_sb->dq_op->get_projid(inode, &projid);
> + if (rc)
> + continue;
> + qid = make_kqid_projid(projid);
> + break;
> }
> got[cnt] = dqget(sb, qid);
> }
> @@ -2161,7 +2174,8 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
> error = -EROFS;
> goto out_fmt;
> }
> - if (!sb->s_op->quota_write || !sb->s_op->quota_read) {
> + if (!sb->s_op->quota_write || !sb->s_op->quota_read ||
> + (type == PRJQUOTA && sb->dq_op->get_projid == NULL)) {
> error = -EINVAL;
> goto out_fmt;
> }
> @@ -2402,8 +2416,19 @@ static void do_get_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
>
> memset(di, 0, sizeof(*di));
> di->d_version = FS_DQUOT_VERSION;
> - di->d_flags = dquot->dq_id.type == USRQUOTA ?
> - FS_USER_QUOTA : FS_GROUP_QUOTA;
> + switch (dquot->dq_id.type) {
> + case USRQUOTA:
> + di->d_flags = FS_USER_QUOTA;
> + break;
> + case GRPQUOTA:
> + di->d_flags = FS_GROUP_QUOTA;
> + break;
> + case PRJQUOTA:
> + di->d_flags = FS_PROJ_QUOTA;
> + break;
> + default:
> + BUG();
> + }
> di->d_id = from_kqid_munged(current_user_ns(), dquot->dq_id);
>
> spin_lock(&dq_data_lock);
> diff --git a/fs/quota/quota.c b/fs/quota/quota.c
> index 2aa4151..33b30b1 100644
> --- a/fs/quota/quota.c
> +++ b/fs/quota/quota.c
> @@ -30,7 +30,10 @@ static int check_quotactl_permission(struct super_block *sb, int type, int cmd,
> case Q_XGETQSTATV:
> case Q_XQUOTASYNC:
> break;
> - /* allow to query information for dquots we "own" */
> + /*
> + * allow to query information for dquots we "own"
> + * always allow querying project quota
> + */
> case Q_GETQUOTA:
> case Q_XGETQUOTA:
> if ((type == USRQUOTA && uid_eq(current_euid(), make_kuid(current_user_ns(), id))) ||
> diff --git a/fs/quota/quotaio_v2.h b/fs/quota/quotaio_v2.h
> index f1966b4..4e95430 100644
> --- a/fs/quota/quotaio_v2.h
> +++ b/fs/quota/quotaio_v2.h
> @@ -13,12 +13,14 @@
> */
> #define V2_INITQMAGICS {\
> 0xd9c01f11, /* USRQUOTA */\
> - 0xd9c01927 /* GRPQUOTA */\
> + 0xd9c01927, /* GRPQUOTA */\
> + 0xd9c03f14, /* PRJQUOTA */\
> }
>
> #define V2_INITQVERSIONS {\
> 1, /* USRQUOTA */\
> - 1 /* GRPQUOTA */\
> + 1, /* GRPQUOTA */\
> + 1, /* PRJQUOTA */\
> }
>
> /* First generic header */
> diff --git a/include/linux/quota.h b/include/linux/quota.h
> index 50978b7..ba51f7e 100644
> --- a/include/linux/quota.h
> +++ b/include/linux/quota.h
> @@ -50,6 +50,7 @@
>
> #undef USRQUOTA
> #undef GRPQUOTA
> +#undef PRJQUOTA
> enum quota_type {
> USRQUOTA = 0, /* element used for user quotas */
> GRPQUOTA = 1, /* element used for group quotas */
> @@ -317,6 +318,7 @@ struct dquot_operations {
> /* get reserved quota for delayed alloc, value returned is managed by
> * quota code only */
> qsize_t *(*get_reserved_space) (struct inode *);
> + int (*get_projid) (struct inode *, kprojid_t *);/* Get project ID */
> };
>
> struct path;
> diff --git a/include/uapi/linux/quota.h b/include/uapi/linux/quota.h
> index 3b6cfbe..b2d9486 100644
> --- a/include/uapi/linux/quota.h
> +++ b/include/uapi/linux/quota.h
> @@ -36,11 +36,12 @@
> #include <linux/errno.h>
> #include <linux/types.h>
>
> -#define __DQUOT_VERSION__ "dquot_6.5.2"
> +#define __DQUOT_VERSION__ "dquot_6.6.0"
>
> -#define MAXQUOTAS 2
> +#define MAXQUOTAS 3
> #define USRQUOTA 0 /* element used for user quotas */
> #define GRPQUOTA 1 /* element used for group quotas */
> +#define PRJQUOTA 2 /* element used for project quotas */
>
> /*
> * Definitions for the default names of the quotas files.
> @@ -48,6 +49,7 @@
> #define INITQFNAMES { \
> "user", /* USRQUOTA */ \
> "group", /* GRPQUOTA */ \
> + "project", /* PRJQUOTA */ \
> "undefined", \
> };
>
> --
> 1.7.1
>
--
Jan Kara <jack-AlSwsSmVLrQ@public.gmane.org>
SUSE Labs, CR
^ permalink raw reply
* Re: [PATCH 0/3] UserfaultFD: Extension for non cooperative uffd usage
From: Andrea Arcangeli @ 2015-04-21 12:02 UTC (permalink / raw)
To: Pavel Emelyanov
Cc: Linux Kernel Mailing List, Linux MM, Linux API, Sanidhya Kashyap,
Dr. David Alan Gilbert, Dave Hansen
In-Reply-To: <5509D342.7000403-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org>
Hi Pavel,
On Wed, Mar 18, 2015 at 10:34:26PM +0300, Pavel Emelyanov wrote:
> Hi,
>
> On the recent LSF Andrea presented his userfault-fd patches and
> I had shown some issues that appear in usage scenarios when the
> monitor task and mm task do not cooperate to each other on VM
> changes (and fork()-s).
>
> Here's the implementation of the extended uffd API that would help
> us to address those issues.
>
> As proof of concept I've implemented only fix for fork() case, but
> I also plan to add the mremap() and exit() notifications, both are
> also required for such non-cooperative usage.
>
> More details about the extension itself is in patch #2 and the fork()
> notification description is in patch #3.
>
> Comments and suggestion are warmly welcome :)
This looks feasible.
> Andrea, what's the best way to go on with the patches -- would you
> prefer to include them in your git tree or should I instead continue
> with them on my own, re-sending them when required? Either way would
> be OK for me.
Ok so various improvements happened in userfaultfd patchset over the
last month so your incremental patchset likely requires a rebase
sorry. When you posted it I was in the middle of the updates. Now
things are working stable and I have no pending updates, so it would
be a good time for a rebase.
I can merge it if you like, it's your call if you prefer to maintain
it incrementally or if I should merge it, but I wouldn't push it to
Andrew for upstream integration in the first batch, as this
complicates things further and it's not fully complete yet (at least
the version posted only handled fork). I think it can be merged
incrementally in a second stage.
The major updates of the userfaultfd patchset over the last month were:
1) Various mixed fixes thanks to the feedback from Dave Hansen and
David Gilbert.
The most notable one is the use of mm_users instead of mm_count to
pin the mm to avoid crashes that assumed the vma still existed (in
the userfaultfd_release method and in the various ioctl). exit_mmap
doesn't even set mm->mmap to NULL, so unless I introduce a
userfaultfd_exit to call in mmput, I have to pin the mm_users to be
safe. This is mainly an issue for the non-cooperative usage you're
implementing. Can you catch the exit somehow so you can close the
fd? The memory won't be released until you do. Is this ok with you?
I suppose you had to close the fd somehow anyway.
2) userfaults are waken immediately even if they're not been "read"
yet, this can lead to POLLIN false positives (so I only allow poll
if the fd is open in nonblocking mode to be sure it won't hang). Is
it too paranoid to return POLLERR if the fd is not open in
nonblocking mode?
http://git.kernel.org/cgit/linux/kernel/git/andrea/aa.git/commit/?h=userfault&id=f222d9de0a5302dc8ac62d6fab53a84251098751
3) optimize read to return entries in O(1) and poll which was already
O(1) becomes lockless. This required to split the waitqueue in two,
one for pending faults and one for non pending faults, and the
faults are refiled across the two waitqueues when they're
read. Both waitqueues are protected by a single lock to be simpler
and faster at runtime (the fault_pending_wqh one).
http://git.kernel.org/cgit/linux/kernel/git/andrea/aa.git/commit/?h=userfault&id=9aa033ed43a1134c2223dac8c5d9e02e0100fca1
4) Allocate the ctx with kmem_cache_alloc. This is going to collide a
bit with your cleanup patch sorry.
http://git.kernel.org/cgit/linux/kernel/git/andrea/aa.git/commit/?h=userfault&id=f5a8db16d2876eed8906a4d36f1d0e06ca5490f6
5) Originally qemu had two bitflags for each page and kept 3 states
(of the 4 possible with two bits) for each page in order to deal
with the races that can happen if one thread is reading the
userfaults and another thread is calling the UFFDIO_COPY ioctl in
the background. This patch solves all races in the kernel so the
two bits per page can be dropped from qemu codebase. I started
documenting the races that can materialize by using 2 threads
(instead of running the workload single threaded with a single poll
event loop), and how userland had to solve them until I decided it
was simpler to fix the race in the kernel by running an ad-hoc
pagetable walk inside the wait_event()-kind-of-section. This
simplified qemu significantly and it doesn't make the kernel much
more complicated.
I tried this before in much older versions but I use gup_fast for
it and it didn't work well with gup_fast for various reasons.
http://git.kernel.org/cgit/linux/kernel/git/andrea/aa.git/commit/?h=userfault&id=41efeae4e93f0296436f2a9fc6b28b6b0158512a
After this patch the only reason to call UFFDIO_WAKE is to handle
the userfaults in batches in combination with the DONT_WAKE flag of
UFFDIO_COPY.
6) I removed the read recursion from mcopy_atomic. This avoids to
depend on the write-starvation behavior of rwsem to be safe. After
this change the rwsem is free to stop any further down_read if
there's a down_write waiting on the lock.
http://git.kernel.org/cgit/linux/kernel/git/andrea/aa.git/commit/?h=userfault&id=b1e3a08acc9e3f6c2614e89fc3b8e338daa58e18
About other troubles for the non cooperative usage: MADV_DONTNEED
likely needs to be trapped too or how do you know that you shall map a
zero page instead of the old data at the faulting address?
Thanks,
Andrea
^ permalink raw reply
* Re: [PATCH 2/3] uffd: Introduce the v2 API
From: Andrea Arcangeli @ 2015-04-21 12:18 UTC (permalink / raw)
To: Pavel Emelyanov
Cc: Linux Kernel Mailing List, Linux MM, Linux API, Sanidhya Kashyap
In-Reply-To: <5509D375.7000809-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org>
On Wed, Mar 18, 2015 at 10:35:17PM +0300, Pavel Emelyanov wrote:
> + if (!(ctx->features & UFFD_FEATURE_LONGMSG)) {
If we are to use different protocols, it'd be nicer to have two
different methods to assign to userfaultfd_fops.read that calls an
__always_inline function, so that the above check can be optimized
away at build time when the inline is expanded. So the branch is
converted to calling a different pointer to function which is zero
additional cost.
> + /* careful to always initialize addr if ret == 0 */
> + __u64 uninitialized_var(addr);
> + __u64 uninitialized_var(mtype);
> + if (count < sizeof(addr))
> + return ret ? ret : -EINVAL;
> + _ret = userfaultfd_ctx_read(ctx, no_wait, &mtype, &addr);
> + if (_ret < 0)
> + return ret ? ret : _ret;
> + BUG_ON(mtype != UFFD_PAGEFAULT);
> + if (put_user(addr, (__u64 __user *) buf))
> + return ret ? ret : -EFAULT;
> + _ret = sizeof(addr);
> + } else {
> + struct uffd_v2_msg msg;
> + if (count < sizeof(msg))
> + return ret ? ret : -EINVAL;
> + _ret = userfaultfd_ctx_read(ctx, no_wait, &msg.type, &msg.arg);
> + if (_ret < 0)
> + return ret ? ret : _ret;
> + if (copy_to_user(buf, &msg, sizeof(msg)))
> + return ret ? ret : -EINVAL;
> + _ret = sizeof(msg);
Reading 16bytes instead of 8bytes for each fault, probably wouldn't
move the needle much in terms of userfaultfd_read performance. Perhaps
we could consider using the uffd_v2_msg unconditionally and then have
a single protocol differentiated by the feature bits.
The only reason to have two different protocols would be to be able to
read 8 bytes per userfault, in the cooperative usage (i.e. qemu
postcopy). But if we do that we want to use the __always_inline trick
to avoid branches and additional runtime costs (otherwise we may as
well forget all microoptimizations and read 16bytes always).
> @@ -992,6 +1013,12 @@ static int userfaultfd_api(struct userfaultfd_ctx *ctx,
> /* careful not to leak info, we only read the first 8 bytes */
> uffdio_api.bits = UFFD_API_BITS;
> uffdio_api.ioctls = UFFD_API_IOCTLS;
> +
> + if (uffdio_api.api == UFFD_API_V2) {
> + ctx->features |= UFFD_FEATURE_LONGMSG;
> + uffdio_api.bits |= UFFD_API_V2_BITS;
> + }
> +
> ret = -EFAULT;
> if (copy_to_user(buf, &uffdio_api, sizeof(uffdio_api)))
> goto out;
The original meaning of the bits is:
If UFFD_BIT_WRITE was set in api.bits, it means the
!!(address&UFFD_BIT_WRITE) tells if it was a write fault (missing or
WP).
If UFFD_BIT_WP was set in api.bits, it means the
!!(address&UFFD_BIT_WP) tells if it was a WP fault (if not set it
means it was a missing fault).
Currently api.bits sets only UFFD_BIT_WRITE, and UFFD_BIT_WP will be
set later, after the WP tracking mode will be implemented.
I'm uncertain how bits translated to features and if they should be
unified or only have features.
> +struct uffd_v2_msg {
> + __u64 type;
> + __u64 arg;
> +};
> +
> +#define UFFD_PAGEFAULT 0x1
> +
> +#define UFFD_PAGEFAULT_BIT (1 << (UFFD_PAGEFAULT - 1))
> +#define __UFFD_API_V2_BITS (UFFD_PAGEFAULT_BIT)
> +
> +/*
> + * Lower PAGE_SHIFT bits are used to report those supported
> + * by the pagefault message itself. Other bits are used to
> + * report the message types v2 API supports
> + */
> +#define UFFD_API_V2_BITS (__UFFD_API_V2_BITS << 12)
> +
And why exactly is this 12 hardcoded? And which field should be masked
with the bits? In the V1 protocol it was the "arg" (userfault address)
not the "type". So this is a bit confusing and probably requires
simplification.
Thanks,
Andrea
^ permalink raw reply
* Re: [v13 2/5] ext4: adds project ID support
From: Jan Kara @ 2015-04-21 12:19 UTC (permalink / raw)
To: Andreas Dilger
Cc: Li Xi, linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
linux-ext4-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA, tytso-3s7WtUTddSA,
jack-AlSwsSmVLrQ, viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn,
hch-wEGCiKHe2LqWVfeAwA7xHQ, dmonakhov-GEFAQzZX7r8dnm+yROfE0A
In-Reply-To: <60E980ED-C4CF-4558-B0A2-5E5671388BE1-m1MBpc4rdrD3fQ9qLvQP4Q@public.gmane.org>
On Mon 20-04-15 17:25:51, Andreas Dilger wrote:
> On Apr 19, 2015, at 7:39 PM, Li Xi <pkuelelixi-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> >
> > This patch adds a new internal field of ext4 inode to save project
> > identifier. Also a new flag EXT4_INODE_PROJINHERIT is added for
> > inheriting project ID from parent directory.
> >
>
> > @@ -3930,12 +3939,18 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
> > inode->i_mode = le16_to_cpu(raw_inode->i_mode);
> > i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
> > i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
> > + if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_PROJECT))
> > + i_projid = (projid_t)le32_to_cpu(raw_inode->i_projid);
>
> This needs to check if EXT4_PROJID_INHERIT_FL is set, and if i_projid
> fits in i_extra_isize, otherwise it could be accessing a garbage value
> beyond i_extra_isize.
We don't need to check EXT4_PROJID_INHERIT_FL. That is completely
independent of whether project ID is stored or not. We should check whether
project ID fits into the inode in this place, that is correct.
Honza
--
Jan Kara <jack-AlSwsSmVLrQ@public.gmane.org>
SUSE Labs, CR
^ permalink raw reply
* Re: [v13 3/5] ext4: adds project quota support
From: Jan Kara @ 2015-04-21 12:35 UTC (permalink / raw)
To: Andreas Dilger
Cc: Li Xi, linux-fsdevel, linux-ext4, linux-api, tytso, jack, viro,
hch, dmonakhov
In-Reply-To: <000EC725-2B59-42E8-811E-0E41E6EBB306@dilger.ca>
On Mon 20-04-15 17:27:20, Andreas Dilger wrote:
> On Apr 19, 2015, at 7:39 PM, Li Xi <pkuelelixi@gmail.com> wrote:
...
> > diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
> > index 1446c4f..a7acf10 100644
> > --- a/fs/ext4/ext4.h
> > +++ b/fs/ext4/ext4.h
> > @@ -1169,7 +1169,8 @@ struct ext4_super_block {
> > __le32 s_overhead_clusters; /* overhead blocks/clusters in fs */
> > __le32 s_backup_bgs[2]; /* groups with sparse_super2 SBs */
> > __u8 s_encrypt_algos[4]; /* Encryption algorithms in use */
> > - __le32 s_reserved[105]; /* Padding to the end of the block */
> > + __le32 s_prj_quota_inum; /* inode for tracking project quota */
> > + __le32 s_reserved[104]; /* Padding to the end of the block */
> > __le32 s_checksum; /* crc32c(superblock) */
> > };
> >
> > @@ -1184,7 +1185,7 @@ struct ext4_super_block {
> > #define EXT4_MF_FS_ABORTED 0x0002 /* Fatal error detected */
> >
> > /* Number of quota types we support */
> > -#define EXT4_MAXQUOTAS 2
> > +#define EXT4_MAXQUOTAS 3
> >
> > /*
> > * fourth extended-fs super-block data in memory
> > @@ -1376,6 +1377,7 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
> > ino == EXT4_BOOT_LOADER_INO ||
> > ino == EXT4_JOURNAL_INO ||
> > ino == EXT4_RESIZE_INO ||
> > + ino == le32_to_cpu(EXT4_SB(sb)->s_es->s_prj_quota_inum) ||
>
> This extra check isn't needed, since s_proj_quota_inum will be a regular
> inode number and handled by the checks below.
So I think this needs a final decision from Ted how we handle new system
files and use it consistently among all features - project quotas, orphan
file, etc. Ted, can you share your thoughts please? Options are:
1) We allocate inodes from normal inode pool and just store their inode
numbers in superblock.
+ no need to increase number of special inodes
- slightly less robust since inode can be anywhere
- needs special treatment from fsck to know inode isn't just some lost inode
- consumes space in sb for inode numbers
2) Like 1) but also create special "system" directory and attach system
inodes there
+ fsck just needs to know about the system directory, not about every
special file
+ no wasted space in sb for every special inode
- more code in kernel to implement this
- even less robust than 1) - when system directory gets corrupt, we are in
trouble
3) Increase number of special inodes
+ consistent with what we did upto now
+ somewhat more robust since inode is in fixed place
- tune2fs needs to do quite some work to reserve more inodes
- wastes unused special inodes
Honza
--
Jan Kara <jack@suse.cz>
SUSE Labs, CR
^ permalink raw reply
* Re: [v13 4/5] ext4: adds FS_IOC_FSSETXATTR/FS_IOC_FSGETXATTR interface support
From: Jan Kara @ 2015-04-21 12:52 UTC (permalink / raw)
To: Li Xi
Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
linux-ext4-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA, tytso-3s7WtUTddSA,
adilger-m1MBpc4rdrD3fQ9qLvQP4Q, jack-AlSwsSmVLrQ,
viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn, hch-wEGCiKHe2LqWVfeAwA7xHQ,
dmonakhov-GEFAQzZX7r8dnm+yROfE0A
In-Reply-To: <1429493988-16819-5-git-send-email-lixi-LfVdkaOWEx8@public.gmane.org>
On Mon 20-04-15 10:39:47, Li Xi wrote:
> This patch adds FS_IOC_FSSETXATTR/FS_IOC_FSGETXATTR ioctl interface
> support for ext4. The interface is kept consistent with
> XFS_IOC_FSGETXATTR/XFS_IOC_FSGETXATTR.
Thanks for the patch! Besides what Andreas wrote, the patch looks good to
me.
Honza
>
> Signed-off-by: Li Xi <lixi-LfVdkaOWEx8@public.gmane.org>
> ---
> fs/ext4/ext4.h | 9 ++
> fs/ext4/ioctl.c | 364 +++++++++++++++++++++++++++++++++++-----------
> fs/xfs/xfs_fs.h | 47 +++----
> include/uapi/linux/fs.h | 32 ++++
> 4 files changed, 335 insertions(+), 117 deletions(-)
>
> diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
> index a7acf10..2d5a097 100644
> --- a/fs/ext4/ext4.h
> +++ b/fs/ext4/ext4.h
> @@ -384,6 +384,13 @@ struct flex_groups {
> #define EXT4_FL_USER_VISIBLE 0x304BDFFF /* User visible flags */
> #define EXT4_FL_USER_MODIFIABLE 0x204380FF /* User modifiable flags */
>
> +#define EXT4_FL_XFLAG_VISIBLE (EXT4_SYNC_FL | \
> + EXT4_IMMUTABLE_FL | \
> + EXT4_APPEND_FL | \
> + EXT4_NODUMP_FL | \
> + EXT4_NOATIME_FL | \
> + EXT4_PROJINHERIT_FL)
> +
> /* Flags that should be inherited by new inodes from their parent. */
> #define EXT4_FL_INHERITED (EXT4_SECRM_FL | EXT4_UNRM_FL | EXT4_COMPR_FL |\
> EXT4_SYNC_FL | EXT4_NODUMP_FL | EXT4_NOATIME_FL |\
> @@ -606,6 +613,8 @@ enum {
> #define EXT4_IOC_RESIZE_FS _IOW('f', 16, __u64)
> #define EXT4_IOC_SWAP_BOOT _IO('f', 17)
> #define EXT4_IOC_PRECACHE_EXTENTS _IO('f', 18)
> +#define EXT4_IOC_FSGETXATTR FS_IOC_FSGETXATTR
> +#define EXT4_IOC_FSSETXATTR FS_IOC_FSSETXATTR
>
> #if defined(__KERNEL__) && defined(CONFIG_COMPAT)
> /*
> diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
> index f58a0d1..27e50a8 100644
> --- a/fs/ext4/ioctl.c
> +++ b/fs/ext4/ioctl.c
> @@ -14,6 +14,8 @@
> #include <linux/compat.h>
> #include <linux/mount.h>
> #include <linux/file.h>
> +#include <linux/quotaops.h>
> +#include <linux/quota.h>
> #include <asm/uaccess.h>
> #include "ext4_jbd2.h"
> #include "ext4.h"
> @@ -196,6 +198,225 @@ journal_err_out:
> return err;
> }
>
> +static int ext4_ioctl_setflags(struct inode *inode,
> + unsigned int flags)
> +{
> + struct ext4_inode_info *ei = EXT4_I(inode);
> + handle_t *handle = NULL;
> + int err = EPERM, migrate = 0;
> + struct ext4_iloc iloc;
> + unsigned int oldflags, mask, i;
> + unsigned int jflag;
> +
> + /* Is it quota file? Do not allow user to mess with it */
> + if (IS_NOQUOTA(inode))
> + goto flags_out;
> +
> + oldflags = ei->i_flags;
> +
> + /* 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;
> + }
> +
> + /*
> + * The JOURNAL_DATA flag can only be changed by
> + * the relevant capability.
> + */
> + if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) {
> + if (!capable(CAP_SYS_RESOURCE))
> + goto flags_out;
> + }
> + if ((flags ^ oldflags) & EXT4_EXTENTS_FL)
> + migrate = 1;
> +
> + if (flags & EXT4_EOFBLOCKS_FL) {
> + /* we don't support adding EOFBLOCKS flag */
> + if (!(oldflags & EXT4_EOFBLOCKS_FL)) {
> + err = -EOPNOTSUPP;
> + goto flags_out;
> + }
> + } else if (oldflags & EXT4_EOFBLOCKS_FL)
> + ext4_truncate(inode);
> +
> + handle = ext4_journal_start(inode, EXT4_HT_INODE, 1);
> + if (IS_ERR(handle)) {
> + err = PTR_ERR(handle);
> + goto flags_out;
> + }
> + if (IS_SYNC(inode))
> + ext4_handle_sync(handle);
> + err = ext4_reserve_inode_write(handle, inode, &iloc);
> + if (err)
> + goto flags_err;
> +
> + for (i = 0, mask = 1; i < 32; i++, mask <<= 1) {
> + if (!(mask & EXT4_FL_USER_MODIFIABLE))
> + continue;
> + if (mask & flags)
> + ext4_set_inode_flag(inode, i);
> + else
> + ext4_clear_inode_flag(inode, i);
> + }
> +
> + ext4_set_inode_flags(inode);
> + inode->i_ctime = ext4_current_time(inode);
> +
> + err = ext4_mark_iloc_dirty(handle, inode, &iloc);
> +flags_err:
> + ext4_journal_stop(handle);
> + if (err)
> + goto flags_out;
> +
> + if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL))
> + err = ext4_change_inode_journal_flag(inode, jflag);
> + if (err)
> + goto flags_out;
> + if (migrate) {
> + if (flags & EXT4_EXTENTS_FL)
> + err = ext4_ext_migrate(inode);
> + else
> + err = ext4_ind_migrate(inode);
> + }
> +
> +flags_out:
> + return err;
> +}
> +
> +static int ext4_ioctl_setproject(struct file *filp, __u32 projid)
> +{
> + struct inode *inode = file_inode(filp);
> + struct super_block *sb = inode->i_sb;
> + struct ext4_inode_info *ei = EXT4_I(inode);
> + int err;
> + handle_t *handle;
> + kprojid_t kprojid;
> + struct ext4_iloc iloc;
> + struct ext4_inode *raw_inode;
> +
> + struct dquot *transfer_to[EXT4_MAXQUOTAS] = { };
> +
> + if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
> + EXT4_FEATURE_RO_COMPAT_PROJECT)) {
> + BUG_ON(__kprojid_val(EXT4_I(inode)->i_projid)
> + != EXT4_DEF_PROJID);
> + if (projid != EXT4_DEF_PROJID)
> + return -EOPNOTSUPP;
> + else
> + return 0;
> + }
> +
> + kprojid = make_kprojid(&init_user_ns, (projid_t)projid);
> +
> + if (projid_eq(kprojid, EXT4_I(inode)->i_projid))
> + return 0;
> +
> + err = mnt_want_write_file(filp);
> + if (err)
> + return err;
> +
> + err = -EPERM;
> + mutex_lock(&inode->i_mutex);
> + /* Is it quota file? Do not allow user to mess with it */
> + if (IS_NOQUOTA(inode))
> + goto project_out;
> +
> + dquot_initialize(inode);
> +
> + handle = ext4_journal_start(inode, EXT4_HT_QUOTA,
> + EXT4_QUOTA_INIT_BLOCKS(sb) +
> + EXT4_QUOTA_DEL_BLOCKS(sb) + 3);
> + if (IS_ERR(handle)) {
> + err = PTR_ERR(handle);
> + goto project_out;
> + }
> +
> + err = ext4_reserve_inode_write(handle, inode, &iloc);
> + if (err)
> + goto project_stop;
> +
> + raw_inode = ext4_raw_inode(&iloc);
> + if (EXT4_INODE_SIZE(sb) <= EXT4_GOOD_OLD_INODE_SIZE) {
> + err = -EOPNOTSUPP;
> + goto project_stop;
> + }
> +
> + if (!EXT4_FITS_IN_INODE(raw_inode, ei, i_projid)) {
> + err = -EOVERFLOW;
> + goto project_stop;
> + }
> +
> + transfer_to[PRJQUOTA] = dqget(sb, make_kqid_projid(kprojid));
> + if (!transfer_to[PRJQUOTA])
> + goto project_set;
> +
> + err = __dquot_transfer(inode, transfer_to);
> + dqput(transfer_to[PRJQUOTA]);
> + if (err)
> + goto project_stop;
> +
> +project_set:
> + EXT4_I(inode)->i_projid = kprojid;
> + inode->i_ctime = ext4_current_time(inode);
> + err = ext4_mark_iloc_dirty(handle, inode, &iloc);
> +project_stop:
> + ext4_journal_stop(handle);
> +project_out:
> + mutex_unlock(&inode->i_mutex);
> + mnt_drop_write_file(filp);
> + return err;
> +}
> +
> +/* Transfer internal flags to xflags */
> +static inline __u32 ext4_iflags_to_xflags(unsigned long iflags)
> +{
> + __u32 xflags = 0;
> +
> + if (iflags & EXT4_SYNC_FL)
> + xflags |= FS_XFLAG_SYNC;
> + if (iflags & EXT4_IMMUTABLE_FL)
> + xflags |= FS_XFLAG_IMMUTABLE;
> + if (iflags & EXT4_APPEND_FL)
> + xflags |= FS_XFLAG_APPEND;
> + if (iflags & EXT4_NODUMP_FL)
> + xflags |= FS_XFLAG_NODUMP;
> + if (iflags & EXT4_NOATIME_FL)
> + xflags |= FS_XFLAG_NOATIME;
> + if (iflags & EXT4_PROJINHERIT_FL)
> + xflags |= FS_XFLAG_PROJINHERIT;
> + return xflags;
> +}
> +
> +/* Transfer xflags flags to internal */
> +static inline unsigned long ext4_xflags_to_iflags(__u32 xflags)
> +{
> + unsigned long iflags = 0;
> +
> + if (xflags & FS_XFLAG_SYNC)
> + iflags |= EXT4_SYNC_FL;
> + if (xflags & FS_XFLAG_IMMUTABLE)
> + iflags |= EXT4_IMMUTABLE_FL;
> + if (xflags & FS_XFLAG_APPEND)
> + iflags |= EXT4_APPEND_FL;
> + if (xflags & FS_XFLAG_NODUMP)
> + iflags |= EXT4_NODUMP_FL;
> + if (xflags & FS_XFLAG_NOATIME)
> + iflags |= EXT4_NOATIME_FL;
> + if (xflags & FS_XFLAG_PROJINHERIT)
> + iflags |= EXT4_PROJINHERIT_FL;
> +
> + return iflags;
> +}
> +
> long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
> {
> struct inode *inode = file_inode(filp);
> @@ -211,11 +432,7 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
> flags = ei->i_flags & EXT4_FL_USER_VISIBLE;
> return put_user(flags, (int __user *) arg);
> case EXT4_IOC_SETFLAGS: {
> - handle_t *handle = NULL;
> - int err, migrate = 0;
> - struct ext4_iloc iloc;
> - unsigned int oldflags, mask, i;
> - unsigned int jflag;
> + int err;
>
> if (!inode_owner_or_capable(inode))
> return -EACCES;
> @@ -229,89 +446,8 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
>
> flags = ext4_mask_flags(inode->i_mode, flags);
>
> - err = -EPERM;
> mutex_lock(&inode->i_mutex);
> - /* Is it quota file? Do not allow user to mess with it */
> - if (IS_NOQUOTA(inode))
> - goto flags_out;
> -
> - oldflags = ei->i_flags;
> -
> - /* 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;
> - }
> -
> - /*
> - * The JOURNAL_DATA flag can only be changed by
> - * the relevant capability.
> - */
> - if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) {
> - if (!capable(CAP_SYS_RESOURCE))
> - goto flags_out;
> - }
> - if ((flags ^ oldflags) & EXT4_EXTENTS_FL)
> - migrate = 1;
> -
> - if (flags & EXT4_EOFBLOCKS_FL) {
> - /* we don't support adding EOFBLOCKS flag */
> - if (!(oldflags & EXT4_EOFBLOCKS_FL)) {
> - err = -EOPNOTSUPP;
> - goto flags_out;
> - }
> - } else if (oldflags & EXT4_EOFBLOCKS_FL)
> - ext4_truncate(inode);
> -
> - handle = ext4_journal_start(inode, EXT4_HT_INODE, 1);
> - if (IS_ERR(handle)) {
> - err = PTR_ERR(handle);
> - goto flags_out;
> - }
> - if (IS_SYNC(inode))
> - ext4_handle_sync(handle);
> - err = ext4_reserve_inode_write(handle, inode, &iloc);
> - if (err)
> - goto flags_err;
> -
> - for (i = 0, mask = 1; i < 32; i++, mask <<= 1) {
> - if (!(mask & EXT4_FL_USER_MODIFIABLE))
> - continue;
> - if (mask & flags)
> - ext4_set_inode_flag(inode, i);
> - else
> - ext4_clear_inode_flag(inode, i);
> - }
> -
> - ext4_set_inode_flags(inode);
> - inode->i_ctime = ext4_current_time(inode);
> -
> - err = ext4_mark_iloc_dirty(handle, inode, &iloc);
> -flags_err:
> - ext4_journal_stop(handle);
> - if (err)
> - goto flags_out;
> -
> - if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL))
> - err = ext4_change_inode_journal_flag(inode, jflag);
> - if (err)
> - goto flags_out;
> - if (migrate) {
> - if (flags & EXT4_EXTENTS_FL)
> - err = ext4_ext_migrate(inode);
> - else
> - err = ext4_ind_migrate(inode);
> - }
> -
> -flags_out:
> + err = ext4_ioctl_setflags(inode, flags);
> mutex_unlock(&inode->i_mutex);
> mnt_drop_write_file(filp);
> return err;
> @@ -615,7 +751,61 @@ resizefs_out:
> }
> case EXT4_IOC_PRECACHE_EXTENTS:
> return ext4_ext_precache(inode);
> + case EXT4_IOC_FSGETXATTR:
> + {
> + struct fsxattr fa;
> +
> + memset(&fa, 0, sizeof(struct fsxattr));
>
> + ext4_get_inode_flags(ei);
> + fa.fsx_xflags = ext4_iflags_to_xflags(ei->i_flags & EXT4_FL_USER_VISIBLE);
> +
> + if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
> + EXT4_FEATURE_RO_COMPAT_PROJECT)) {
> + fa.fsx_projid = (__u32)from_kprojid(&init_user_ns,
> + EXT4_I(inode)->i_projid);
> + }
> +
> + if (copy_to_user((struct fsxattr __user *)arg,
> + &fa, sizeof(fa)))
> + return -EFAULT;
> + return 0;
> + }
> + case EXT4_IOC_FSSETXATTR:
> + {
> + struct fsxattr fa;
> + int err;
> +
> + if (copy_from_user(&fa, (struct fsxattr __user *)arg,
> + sizeof(fa)))
> + return -EFAULT;
> +
> + /* Make sure caller has proper permission */
> + if (!inode_owner_or_capable(inode))
> + return -EACCES;
> +
> + err = mnt_want_write_file(filp);
> + if (err)
> + return err;
> +
> + flags = ext4_xflags_to_iflags(fa.fsx_xflags);
> + flags = ext4_mask_flags(inode->i_mode, flags);
> +
> + mutex_lock(&inode->i_mutex);
> + flags = (ei->i_flags & ~EXT4_FL_XFLAG_VISIBLE) |
> + (flags & EXT4_FL_XFLAG_VISIBLE);
> + err = ext4_ioctl_setflags(inode, flags);
> + mutex_unlock(&inode->i_mutex);
> + mnt_drop_write_file(filp);
> + if (err)
> + return err;
> +
> + err = ext4_ioctl_setproject(filp, fa.fsx_projid);
> + if (err)
> + return err;
> +
> + return 0;
> + }
> default:
> return -ENOTTY;
> }
> diff --git a/fs/xfs/xfs_fs.h b/fs/xfs/xfs_fs.h
> index 18dc721..64c7ae6 100644
> --- a/fs/xfs/xfs_fs.h
> +++ b/fs/xfs/xfs_fs.h
> @@ -36,38 +36,25 @@ struct dioattr {
> #endif
>
> /*
> - * Structure for XFS_IOC_FSGETXATTR[A] and XFS_IOC_FSSETXATTR.
> - */
> -#ifndef HAVE_FSXATTR
> -struct fsxattr {
> - __u32 fsx_xflags; /* xflags field value (get/set) */
> - __u32 fsx_extsize; /* extsize field value (get/set)*/
> - __u32 fsx_nextents; /* nextents field value (get) */
> - __u32 fsx_projid; /* project identifier (get/set) */
> - unsigned char fsx_pad[12];
> -};
> -#endif
> -
> -/*
> * Flags for the bs_xflags/fsx_xflags field
> * There should be a one-to-one correspondence between these flags and the
> * XFS_DIFLAG_s.
> */
> -#define XFS_XFLAG_REALTIME 0x00000001 /* data in realtime volume */
> -#define XFS_XFLAG_PREALLOC 0x00000002 /* preallocated file extents */
> -#define XFS_XFLAG_IMMUTABLE 0x00000008 /* file cannot be modified */
> -#define XFS_XFLAG_APPEND 0x00000010 /* all writes append */
> -#define XFS_XFLAG_SYNC 0x00000020 /* all writes synchronous */
> -#define XFS_XFLAG_NOATIME 0x00000040 /* do not update access time */
> -#define XFS_XFLAG_NODUMP 0x00000080 /* do not include in backups */
> -#define XFS_XFLAG_RTINHERIT 0x00000100 /* create with rt bit set */
> -#define XFS_XFLAG_PROJINHERIT 0x00000200 /* create with parents projid */
> -#define XFS_XFLAG_NOSYMLINKS 0x00000400 /* disallow symlink creation */
> -#define XFS_XFLAG_EXTSIZE 0x00000800 /* extent size allocator hint */
> -#define XFS_XFLAG_EXTSZINHERIT 0x00001000 /* inherit inode extent size */
> -#define XFS_XFLAG_NODEFRAG 0x00002000 /* do not defragment */
> -#define XFS_XFLAG_FILESTREAM 0x00004000 /* use filestream allocator */
> -#define XFS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */
> +#define XFS_XFLAG_REALTIME FS_XFLAG_REALTIME /* data in realtime volume */
> +#define XFS_XFLAG_PREALLOC FS_XFLAG_PREALLOC /* preallocated file extents */
> +#define XFS_XFLAG_IMMUTABLE FS_XFLAG_IMMUTABLE /* file cannot be modified */
> +#define XFS_XFLAG_APPEND FS_XFLAG_APPEND /* all writes append */
> +#define XFS_XFLAG_SYNC FS_XFLAG_SYNC /* all writes synchronous */
> +#define XFS_XFLAG_NOATIME FS_XFLAG_NOATIME /* do not update access time */
> +#define XFS_XFLAG_NODUMP FS_XFLAG_NODUMP /* do not include in backups */
> +#define XFS_XFLAG_RTINHERIT FS_XFLAG_RTINHERIT /* create with rt bit set */
> +#define XFS_XFLAG_PROJINHERIT FS_XFLAG_PROJINHERIT /* create with parents projid */
> +#define XFS_XFLAG_NOSYMLINKS FS_XFLAG_NOSYMLINKS /* disallow symlink creation */
> +#define XFS_XFLAG_EXTSIZE FS_XFLAG_EXTSIZE /* extent size allocator hint */
> +#define XFS_XFLAG_EXTSZINHERIT FS_XFLAG_EXTSZINHERIT /* inherit inode extent size */
> +#define XFS_XFLAG_NODEFRAG FS_XFLAG_NODEFRAG /* do not defragment */
> +#define XFS_XFLAG_FILESTREAM FS_XFLAG_FILESTREAM /* use filestream allocator */
> +#define XFS_XFLAG_HASATTR FS_XFLAG_HASATTR /* no DIFLAG for this */
>
> /*
> * Structure for XFS_IOC_GETBMAP.
> @@ -503,8 +490,8 @@ typedef struct xfs_swapext
> #define XFS_IOC_ALLOCSP _IOW ('X', 10, struct xfs_flock64)
> #define XFS_IOC_FREESP _IOW ('X', 11, struct xfs_flock64)
> #define XFS_IOC_DIOINFO _IOR ('X', 30, struct dioattr)
> -#define XFS_IOC_FSGETXATTR _IOR ('X', 31, struct fsxattr)
> -#define XFS_IOC_FSSETXATTR _IOW ('X', 32, struct fsxattr)
> +#define XFS_IOC_FSGETXATTR FS_IOC_FSGETXATTR
> +#define XFS_IOC_FSSETXATTR FS_IOC_FSSETXATTR
> #define XFS_IOC_ALLOCSP64 _IOW ('X', 36, struct xfs_flock64)
> #define XFS_IOC_FREESP64 _IOW ('X', 37, struct xfs_flock64)
> #define XFS_IOC_GETBMAP _IOWR('X', 38, struct getbmap)
> diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
> index fcbf647..69dda62 100644
> --- a/include/uapi/linux/fs.h
> +++ b/include/uapi/linux/fs.h
> @@ -58,6 +58,36 @@ struct inodes_stat_t {
> long dummy[5]; /* padding for sysctl ABI compatibility */
> };
>
> +/*
> + * Structure for FS_IOC_FSGETXATTR and FS_IOC_FSSETXATTR.
> + */
> +struct fsxattr {
> + __u32 fsx_xflags; /* xflags field value (get/set) */
> + __u32 fsx_extsize; /* extsize field value (get/set)*/
> + __u32 fsx_nextents; /* nextents field value (get) */
> + __u32 fsx_projid; /* project identifier (get/set) */
> + unsigned char fsx_pad[12];
> +};
> +
> +/*
> + * Flags for the fsx_xflags field
> + */
> +#define FS_XFLAG_REALTIME 0x00000001 /* data in realtime volume */
> +#define FS_XFLAG_PREALLOC 0x00000002 /* preallocated file extents */
> +#define FS_XFLAG_IMMUTABLE 0x00000008 /* file cannot be modified */
> +#define FS_XFLAG_APPEND 0x00000010 /* all writes append */
> +#define FS_XFLAG_SYNC 0x00000020 /* all writes synchronous */
> +#define FS_XFLAG_NOATIME 0x00000040 /* do not update access time */
> +#define FS_XFLAG_NODUMP 0x00000080 /* do not include in backups */
> +#define FS_XFLAG_RTINHERIT 0x00000100 /* create with rt bit set */
> +#define FS_XFLAG_PROJINHERIT 0x00000200 /* create with parents projid */
> +#define FS_XFLAG_NOSYMLINKS 0x00000400 /* disallow symlink creation */
> +#define FS_XFLAG_EXTSIZE 0x00000800 /* extent size allocator hint */
> +#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_HASATTR 0x80000000 /* no DIFLAG for this */
> +
>
> #define NR_FILE 8192 /* this can well be larger on a larger system */
>
> @@ -163,6 +193,8 @@ struct inodes_stat_t {
> #define FS_IOC_GETVERSION _IOR('v', 1, long)
> #define FS_IOC_SETVERSION _IOW('v', 2, long)
> #define FS_IOC_FIEMAP _IOWR('f', 11, struct fiemap)
> +#define FS_IOC_FSGETXATTR _IOR('X', 31, struct fsxattr)
> +#define FS_IOC_FSSETXATTR _IOW('X', 32, struct fsxattr)
> #define FS_IOC32_GETFLAGS _IOR('f', 1, int)
> #define FS_IOC32_SETFLAGS _IOW('f', 2, int)
> #define FS_IOC32_GETVERSION _IOR('v', 1, int)
> --
> 1.7.1
>
--
Jan Kara <jack-AlSwsSmVLrQ@public.gmane.org>
SUSE Labs, CR
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox