Re: [PATCH 03/19] fsinfo: Provide a bitmap of supported features [ver #16]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Feb 18, 2020 at 05:05:20PM +0000, David Howells wrote:
> Provide a bitmap of features that a filesystem may provide for the path
> being queried.  Features include such things as:
> 
>  (1) The general class of filesystem, such as kernel-interface,
>      block-based, flash-based, network-based.
> 
>  (2) Supported inode features, such as which timestamps are supported,
>      whether simple numeric user, group or project IDs are supported and
>      whether user identification is actually more complex behind the
>      scenes.
> 
>  (3) Supported volume features, such as it having a UUID, a name or a
>      filesystem ID.
> 
>  (4) Supported filesystem features, such as what types of file are
>      supported, whether sparse files, extended attributes and quotas are
>      supported.
> 
>  (5) Supported interface features, such as whether locking and leases are
>      supported, what open flags are honoured and how i_version is managed.
> 
> For some filesystems, this may be an immutable set and can just be memcpy'd
> into the reply buffer.
> ---
> 
>  fs/fsinfo.c                 |   41 +++++++++++++++++++
>  include/linux/fsinfo.h      |   32 +++++++++++++++
>  include/uapi/linux/fsinfo.h |   78 ++++++++++++++++++++++++++++++++++++
>  samples/vfs/test-fsinfo.c   |   93 ++++++++++++++++++++++++++++++++++++++++++-
>  4 files changed, 242 insertions(+), 2 deletions(-)
> 
> diff --git a/fs/fsinfo.c b/fs/fsinfo.c
> index 3bc35b91f20b..55710d6da327 100644
> --- a/fs/fsinfo.c
> +++ b/fs/fsinfo.c
> @@ -36,6 +36,17 @@ int fsinfo_string(const char *s, struct fsinfo_context *ctx)
>  }
>  EXPORT_SYMBOL(fsinfo_string);
>  
> +/*
> + * Get information about fsinfo() itself.
> + */
> +static int fsinfo_generic_fsinfo(struct path *path, struct fsinfo_context *ctx)
> +{
> +	struct fsinfo_fsinfo *info = ctx->buffer;
> +
> +	info->max_features = FSINFO_FEAT__NR;
> +	return sizeof(*info);
> +}
> +
>  /*
>   * Get basic filesystem stats from statfs.
>   */
> @@ -121,6 +132,33 @@ static int fsinfo_generic_supports(struct path *path, struct fsinfo_context *ctx
>  	return sizeof(*c);
>  }
>  
> +static int fsinfo_generic_features(struct path *path, struct fsinfo_context *ctx)
> +{
> +	struct fsinfo_features *ft = ctx->buffer;
> +	struct super_block *sb = path->dentry->d_sb;
> +
> +	if (sb->s_mtd)
> +		fsinfo_set_feature(ft, FSINFO_FEAT_IS_FLASH_FS);
> +	else if (sb->s_bdev)
> +		fsinfo_set_feature(ft, FSINFO_FEAT_IS_BLOCK_FS);
> +
> +	if (sb->s_quota_types & QTYPE_MASK_USR)
> +		fsinfo_set_feature(ft, FSINFO_FEAT_USER_QUOTAS);
> +	if (sb->s_quota_types & QTYPE_MASK_GRP)
> +		fsinfo_set_feature(ft, FSINFO_FEAT_GROUP_QUOTAS);
> +	if (sb->s_quota_types & QTYPE_MASK_PRJ)
> +		fsinfo_set_feature(ft, FSINFO_FEAT_PROJECT_QUOTAS);
> +	if (sb->s_d_op && sb->s_d_op->d_automount)
> +		fsinfo_set_feature(ft, FSINFO_FEAT_AUTOMOUNTS);
> +	if (sb->s_id[0])
> +		fsinfo_set_feature(ft, FSINFO_FEAT_VOLUME_ID);
> +
> +	fsinfo_set_feature(ft, FSINFO_FEAT_HAS_ATIME);
> +	fsinfo_set_feature(ft, FSINFO_FEAT_HAS_CTIME);
> +	fsinfo_set_feature(ft, FSINFO_FEAT_HAS_MTIME);
> +	return sizeof(*ft);
> +}
> +
>  static const struct fsinfo_timestamp_info fsinfo_default_timestamp_info = {
>  	.atime = {
>  		.minimum	= S64_MIN,
> @@ -252,6 +290,9 @@ static const struct fsinfo_attribute fsinfo_common_attributes[] = {
>  	FSINFO_VSTRUCT	(FSINFO_ATTR_TIMESTAMP_INFO,	fsinfo_generic_timestamp_info),
>  	FSINFO_STRING 	(FSINFO_ATTR_VOLUME_ID,		fsinfo_generic_volume_id),
>  	FSINFO_VSTRUCT	(FSINFO_ATTR_VOLUME_UUID,	fsinfo_generic_volume_uuid),
> +	FSINFO_VSTRUCT	(FSINFO_ATTR_FEATURES,		fsinfo_generic_features),
> +
> +	FSINFO_VSTRUCT	(FSINFO_ATTR_FSINFO,		fsinfo_generic_fsinfo),
>  	FSINFO_VSTRUCT_N(FSINFO_ATTR_FSINFO_ATTRIBUTE_INFO, fsinfo_attribute_info),
>  	FSINFO_LIST	(FSINFO_ATTR_FSINFO_ATTRIBUTES,	fsinfo_attributes),
>  	{}
> diff --git a/include/linux/fsinfo.h b/include/linux/fsinfo.h
> index dcd55dbb02fa..564765c70659 100644
> --- a/include/linux/fsinfo.h
> +++ b/include/linux/fsinfo.h
> @@ -65,6 +65,38 @@ struct fsinfo_attribute {
>  
>  extern int fsinfo_string(const char *, struct fsinfo_context *);
>  
> +static inline void fsinfo_set_feature(struct fsinfo_features *f,
> +				      enum fsinfo_feature feature)
> +{
> +	f->features[feature / 8] |= 1 << (feature % 8);
> +}
> +
> +static inline void fsinfo_clear_feature(struct fsinfo_features *f,
> +					enum fsinfo_feature feature)
> +{
> +	f->features[feature / 8] &= ~(1 << (feature % 8));
> +}
> +
> +/**
> + * fsinfo_set_unix_features - Set standard UNIX features.
> + * @f: The features mask to alter
> + */
> +static inline void fsinfo_set_unix_features(struct fsinfo_features *f)
> +{
> +	fsinfo_set_feature(f, FSINFO_FEAT_UIDS);
> +	fsinfo_set_feature(f, FSINFO_FEAT_GIDS);
> +	fsinfo_set_feature(f, FSINFO_FEAT_DIRECTORIES);
> +	fsinfo_set_feature(f, FSINFO_FEAT_SYMLINKS);
> +	fsinfo_set_feature(f, FSINFO_FEAT_HARD_LINKS);
> +	fsinfo_set_feature(f, FSINFO_FEAT_DEVICE_FILES);
> +	fsinfo_set_feature(f, FSINFO_FEAT_UNIX_SPECIALS);
> +	fsinfo_set_feature(f, FSINFO_FEAT_SPARSE);
> +	fsinfo_set_feature(f, FSINFO_FEAT_HAS_ATIME);
> +	fsinfo_set_feature(f, FSINFO_FEAT_HAS_CTIME);
> +	fsinfo_set_feature(f, FSINFO_FEAT_HAS_MTIME);
> +	fsinfo_set_feature(f, FSINFO_FEAT_HAS_INODE_NUMBERS);
> +}
> +
>  #endif /* CONFIG_FSINFO */
>  
>  #endif /* _LINUX_FSINFO_H */
> diff --git a/include/uapi/linux/fsinfo.h b/include/uapi/linux/fsinfo.h
> index 365d54fe9290..f40b5c0b5516 100644
> --- a/include/uapi/linux/fsinfo.h
> +++ b/include/uapi/linux/fsinfo.h
> @@ -22,9 +22,11 @@
>  #define FSINFO_ATTR_VOLUME_ID		0x05	/* Volume ID (string) */
>  #define FSINFO_ATTR_VOLUME_UUID		0x06	/* Volume UUID (LE uuid) */
>  #define FSINFO_ATTR_VOLUME_NAME		0x07	/* Volume name (string) */
> +#define FSINFO_ATTR_FEATURES		0x08	/* Filesystem features (bits) */
>  
>  #define FSINFO_ATTR_FSINFO_ATTRIBUTE_INFO 0x100	/* Information about attr N (for path) */
>  #define FSINFO_ATTR_FSINFO_ATTRIBUTES	0x101	/* List of supported attrs (for path) */
> +#define FSINFO_ATTR_FSINFO		0x102	/* Information about fsinfo() as a whole */
>  
>  /*
>   * Optional fsinfo() parameter structure.
> @@ -45,6 +47,17 @@ struct fsinfo_params {
>  	__u64	__reserved[3];
>  };
>  
> +/*
> + * Information struct for fsinfo(FSINFO_ATTR_FSINFO).
> + *
> + * This gives information about fsinfo() itself.
> + */
> +struct fsinfo_fsinfo {
> +	__u32	max_features;	/* Number of supported features (fsinfo_features__nr) */
> +};
> +
> +#define FSINFO_ATTR_FSINFO__STRUCT struct fsinfo_fsinfo
> +
>  enum fsinfo_value_type {
>  	FSINFO_TYPE_VSTRUCT	= 0,	/* Version-lengthed struct (up to 4096 bytes) */
>  	FSINFO_TYPE_STRING	= 1,	/* NUL-term var-length string (up to 4095 chars) */
> @@ -154,6 +167,71 @@ struct fsinfo_supports {
>  
>  #define FSINFO_ATTR_SUPPORTS__STRUCT struct fsinfo_supports
>  
> +/*
> + * Information struct for fsinfo(FSINFO_ATTR_FEATURES).
> + *
> + * Bitmask indicating filesystem features where renderable as single bits.
> + */
> +enum fsinfo_feature {
> +	FSINFO_FEAT_IS_KERNEL_FS	= 0,	/* fs is kernel-special filesystem */
> +	FSINFO_FEAT_IS_BLOCK_FS		= 1,	/* fs is block-based filesystem */
> +	FSINFO_FEAT_IS_FLASH_FS		= 2,	/* fs is flash filesystem */
> +	FSINFO_FEAT_IS_NETWORK_FS	= 3,	/* fs is network filesystem */
> +	FSINFO_FEAT_IS_AUTOMOUNTER_FS	= 4,	/* fs is automounter special filesystem */
> +	FSINFO_FEAT_IS_MEMORY_FS	= 5,	/* fs is memory-based filesystem */
> +	FSINFO_FEAT_AUTOMOUNTS		= 6,	/* fs supports automounts */
> +	FSINFO_FEAT_ADV_LOCKS		= 7,	/* fs supports advisory file locking */
> +	FSINFO_FEAT_MAND_LOCKS		= 8,	/* fs supports mandatory file locking */
> +	FSINFO_FEAT_LEASES		= 9,	/* fs supports file leases */
> +	FSINFO_FEAT_UIDS		= 10,	/* fs supports numeric uids */
> +	FSINFO_FEAT_GIDS		= 11,	/* fs supports numeric gids */
> +	FSINFO_FEAT_PROJIDS		= 12,	/* fs supports numeric project ids */
> +	FSINFO_FEAT_STRING_USER_IDS	= 13,	/* fs supports string user identifiers */
> +	FSINFO_FEAT_GUID_USER_IDS	= 14,	/* fs supports GUID user identifiers */
> +	FSINFO_FEAT_WINDOWS_ATTRS	= 15,	/* fs has windows attributes */
> +	FSINFO_FEAT_USER_QUOTAS		= 16,	/* fs has per-user quotas */
> +	FSINFO_FEAT_GROUP_QUOTAS	= 17,	/* fs has per-group quotas */
> +	FSINFO_FEAT_PROJECT_QUOTAS	= 18,	/* fs has per-project quotas */
> +	FSINFO_FEAT_XATTRS		= 19,	/* fs has xattrs */
> +	FSINFO_FEAT_JOURNAL		= 20,	/* fs has a journal */
> +	FSINFO_FEAT_DATA_IS_JOURNALLED	= 21,	/* fs is using data journalling */
> +	FSINFO_FEAT_O_SYNC		= 22,	/* fs supports O_SYNC */
> +	FSINFO_FEAT_O_DIRECT		= 23,	/* fs supports O_DIRECT */
> +	FSINFO_FEAT_VOLUME_ID		= 24,	/* fs has a volume ID */
> +	FSINFO_FEAT_VOLUME_UUID		= 25,	/* fs has a volume UUID */
> +	FSINFO_FEAT_VOLUME_NAME		= 26,	/* fs has a volume name */
> +	FSINFO_FEAT_VOLUME_FSID		= 27,	/* fs has a volume FSID */
> +	FSINFO_FEAT_IVER_ALL_CHANGE	= 28,	/* i_version represents data + meta changes */
> +	FSINFO_FEAT_IVER_DATA_CHANGE	= 29,	/* i_version represents data changes only */
> +	FSINFO_FEAT_IVER_MONO_INCR	= 30,	/* i_version incremented monotonically */
> +	FSINFO_FEAT_DIRECTORIES		= 31,	/* fs supports (sub)directories */
> +	FSINFO_FEAT_SYMLINKS		= 32,	/* fs supports symlinks */
> +	FSINFO_FEAT_HARD_LINKS		= 33,	/* fs supports hard links */
> +	FSINFO_FEAT_HARD_LINKS_1DIR	= 34,	/* fs supports hard links in same dir only */
> +	FSINFO_FEAT_DEVICE_FILES	= 35,	/* fs supports bdev, cdev */
> +	FSINFO_FEAT_UNIX_SPECIALS	= 36,	/* fs supports pipe, fifo, socket */
> +	FSINFO_FEAT_RESOURCE_FORKS	= 37,	/* fs supports resource forks/streams */
> +	FSINFO_FEAT_NAME_CASE_INDEP	= 38,	/* Filename case independence is mandatory */
> +	FSINFO_FEAT_NAME_NON_UTF8	= 39,	/* fs has non-utf8 names */
> +	FSINFO_FEAT_NAME_HAS_CODEPAGE	= 40,	/* fs has a filename codepage */
> +	FSINFO_FEAT_SPARSE		= 41,	/* fs supports sparse files */
> +	FSINFO_FEAT_NOT_PERSISTENT	= 42,	/* fs is not persistent */
> +	FSINFO_FEAT_NO_UNIX_MODE	= 43,	/* fs does not support unix mode bits */
> +	FSINFO_FEAT_HAS_ATIME		= 44,	/* fs supports access time */
> +	FSINFO_FEAT_HAS_BTIME		= 45,	/* fs supports birth/creation time */
> +	FSINFO_FEAT_HAS_CTIME		= 46,	/* fs supports change time */
> +	FSINFO_FEAT_HAS_MTIME		= 47,	/* fs supports modification time */
> +	FSINFO_FEAT_HAS_ACL		= 48,	/* fs supports ACLs of some sort */
> +	FSINFO_FEAT_HAS_INODE_NUMBERS	= 49,	/* fs has inode numbers */
> +	FSINFO_FEAT__NR
> +};
> +
> +struct fsinfo_features {
> +	__u8	features[(FSINFO_FEAT__NR + 7) / 8];

Hm...the structure size is pretty small (56 bytes) and will expand as we
add new _FEAT flags.  Is this ok because the fsinfo code will truncate
its response to userspace to whatever buffer size userspace tells it?

--D

> +};
> +
> +#define FSINFO_ATTR_FEATURES__STRUCT struct fsinfo_features
> +
>  struct fsinfo_timestamp_one {
>  	__s64	minimum;	/* Minimum timestamp value in seconds */
>  	__u64	maximum;	/* Maximum timestamp value in seconds */
> diff --git a/samples/vfs/test-fsinfo.c b/samples/vfs/test-fsinfo.c
> index 9a4d49db2996..6fbf0ce099b2 100644
> --- a/samples/vfs/test-fsinfo.c
> +++ b/samples/vfs/test-fsinfo.c
> @@ -107,6 +107,13 @@ static void dump_attribute_info(void *reply, unsigned int size)
>  	       attr->name ? attr->name : "");
>  }
>  
> +static void dump_fsinfo_info(void *reply, unsigned int size)
> +{
> +	struct fsinfo_fsinfo *f = reply;
> +
> +	printf("Number of feature bits: %u\n", f->max_features);
> +}
> +
>  static void dump_fsinfo_generic_statfs(void *reply, unsigned int size)
>  {
>  	struct fsinfo_statfs *f = reply;
> @@ -172,6 +179,74 @@ static void dump_fsinfo_generic_supports(void *reply, unsigned int size)
>  	printf("\twin_fattrs   : %x\n", f->win_file_attrs);
>  }
>  
> +#define FSINFO_FEATURE_NAME(C) [FSINFO_FEAT_##C] = #C
> +static const char *fsinfo_feature_names[FSINFO_FEAT__NR] = {
> +	FSINFO_FEATURE_NAME(IS_KERNEL_FS),
> +	FSINFO_FEATURE_NAME(IS_BLOCK_FS),
> +	FSINFO_FEATURE_NAME(IS_FLASH_FS),
> +	FSINFO_FEATURE_NAME(IS_NETWORK_FS),
> +	FSINFO_FEATURE_NAME(IS_AUTOMOUNTER_FS),
> +	FSINFO_FEATURE_NAME(IS_MEMORY_FS),
> +	FSINFO_FEATURE_NAME(AUTOMOUNTS),
> +	FSINFO_FEATURE_NAME(ADV_LOCKS),
> +	FSINFO_FEATURE_NAME(MAND_LOCKS),
> +	FSINFO_FEATURE_NAME(LEASES),
> +	FSINFO_FEATURE_NAME(UIDS),
> +	FSINFO_FEATURE_NAME(GIDS),
> +	FSINFO_FEATURE_NAME(PROJIDS),
> +	FSINFO_FEATURE_NAME(STRING_USER_IDS),
> +	FSINFO_FEATURE_NAME(GUID_USER_IDS),
> +	FSINFO_FEATURE_NAME(WINDOWS_ATTRS),
> +	FSINFO_FEATURE_NAME(USER_QUOTAS),
> +	FSINFO_FEATURE_NAME(GROUP_QUOTAS),
> +	FSINFO_FEATURE_NAME(PROJECT_QUOTAS),
> +	FSINFO_FEATURE_NAME(XATTRS),
> +	FSINFO_FEATURE_NAME(JOURNAL),
> +	FSINFO_FEATURE_NAME(DATA_IS_JOURNALLED),
> +	FSINFO_FEATURE_NAME(O_SYNC),
> +	FSINFO_FEATURE_NAME(O_DIRECT),
> +	FSINFO_FEATURE_NAME(VOLUME_ID),
> +	FSINFO_FEATURE_NAME(VOLUME_UUID),
> +	FSINFO_FEATURE_NAME(VOLUME_NAME),
> +	FSINFO_FEATURE_NAME(VOLUME_FSID),
> +	FSINFO_FEATURE_NAME(IVER_ALL_CHANGE),
> +	FSINFO_FEATURE_NAME(IVER_DATA_CHANGE),
> +	FSINFO_FEATURE_NAME(IVER_MONO_INCR),
> +	FSINFO_FEATURE_NAME(DIRECTORIES),
> +	FSINFO_FEATURE_NAME(SYMLINKS),
> +	FSINFO_FEATURE_NAME(HARD_LINKS),
> +	FSINFO_FEATURE_NAME(HARD_LINKS_1DIR),
> +	FSINFO_FEATURE_NAME(DEVICE_FILES),
> +	FSINFO_FEATURE_NAME(UNIX_SPECIALS),
> +	FSINFO_FEATURE_NAME(RESOURCE_FORKS),
> +	FSINFO_FEATURE_NAME(NAME_CASE_INDEP),
> +	FSINFO_FEATURE_NAME(NAME_NON_UTF8),
> +	FSINFO_FEATURE_NAME(NAME_HAS_CODEPAGE),
> +	FSINFO_FEATURE_NAME(SPARSE),
> +	FSINFO_FEATURE_NAME(NOT_PERSISTENT),
> +	FSINFO_FEATURE_NAME(NO_UNIX_MODE),
> +	FSINFO_FEATURE_NAME(HAS_ATIME),
> +	FSINFO_FEATURE_NAME(HAS_BTIME),
> +	FSINFO_FEATURE_NAME(HAS_CTIME),
> +	FSINFO_FEATURE_NAME(HAS_MTIME),
> +	FSINFO_FEATURE_NAME(HAS_ACL),
> +	FSINFO_FEATURE_NAME(HAS_INODE_NUMBERS),
> +};
> +
> +static void dump_fsinfo_generic_features(void *reply, unsigned int size)
> +{
> +	struct fsinfo_features *f = reply;
> +	int i;
> +
> +	printf("\n\t");
> +	for (i = 0; i < sizeof(f->features); i++)
> +		printf("%02x", f->features[i]);
> +	printf("\n");
> +	for (i = 0; i < FSINFO_FEAT__NR; i++)
> +		if (f->features[i / 8] & (1 << (i % 8)))
> +			printf("\t- %s\n", fsinfo_feature_names[i]);
> +}
> +
>  static void print_time(struct fsinfo_timestamp_one *t, char stamp)
>  {
>  	printf("\t%ctime       : gran=%gs range=%llx-%llx\n",
> @@ -235,7 +310,6 @@ static void dump_string(void *reply, unsigned int size)
>  
>  #define dump_fsinfo_generic_volume_id		dump_string
>  #define dump_fsinfo_generic_volume_name		dump_string
> -#define dump_fsinfo_generic_name_encoding	dump_string
>  
>  /*
>   *
> @@ -266,6 +340,7 @@ static const struct fsinfo_attribute fsinfo_attributes[] = {
>  	FSINFO_VSTRUCT	(FSINFO_ATTR_IDS,		fsinfo_generic_ids),
>  	FSINFO_VSTRUCT	(FSINFO_ATTR_LIMITS,		fsinfo_generic_limits),
>  	FSINFO_VSTRUCT	(FSINFO_ATTR_SUPPORTS,		fsinfo_generic_supports),
> +	FSINFO_VSTRUCT	(FSINFO_ATTR_FEATURES,		fsinfo_generic_features),
>  	FSINFO_VSTRUCT	(FSINFO_ATTR_TIMESTAMP_INFO,	fsinfo_generic_timestamp_info),
>  	FSINFO_STRING	(FSINFO_ATTR_VOLUME_ID,		fsinfo_generic_volume_id),
>  	FSINFO_VSTRUCT	(FSINFO_ATTR_VOLUME_UUID,	fsinfo_generic_volume_uuid),
> @@ -475,6 +550,7 @@ static int cmp_u32(const void *a, const void *b)
>  int main(int argc, char **argv)
>  {
>  	struct fsinfo_attribute_info attr_info;
> +	struct fsinfo_fsinfo fsinfo_info;
>  	struct fsinfo_params params = {
>  		.at_flags	= AT_SYMLINK_NOFOLLOW,
>  		.flags		= FSINFO_FLAGS_QUERY_PATH,
> @@ -531,6 +607,18 @@ int main(int argc, char **argv)
>  	qsort(attrs, nr, sizeof(attrs[0]), cmp_u32);
>  
>  	if (meta) {
> +		params.request = FSINFO_ATTR_FSINFO;
> +		params.Nth = 0;
> +		params.Mth = 0;
> +		ret = fsinfo(AT_FDCWD, argv[0], &params, &fsinfo_info, sizeof(fsinfo_info));
> +		if (ret == -1) {
> +			fprintf(stderr, "Unable to get fsinfo information: %m\n");
> +			exit(1);
> +		}
> +
> +		dump_fsinfo_info(&fsinfo_info, ret);
> +		printf("\n");
> +
>  		printf("ATTR ID  TYPE         FLAGS    SIZE  ESIZE NAME\n");
>  		printf("======== ============ ======== ===== ===== =========\n");
>  		for (i = 0; i < nr; i++) {
> @@ -558,7 +646,8 @@ int main(int argc, char **argv)
>  			exit(1);
>  		}
>  
> -		if (attrs[i] == FSINFO_ATTR_FSINFO_ATTRIBUTE_INFO ||
> +		if (attrs[i] == FSINFO_ATTR_FSINFO ||
> +		    attrs[i] == FSINFO_ATTR_FSINFO_ATTRIBUTE_INFO ||
>  		    attrs[i] == FSINFO_ATTR_FSINFO_ATTRIBUTES)
>  			continue;
>  
> 
> 



[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux