Re: [PATCH 01/11] vfs: syscall: Add fsinfo() to query filesystem information [ver #15]

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

 



On Mon, Jul 01, 2019 at 02:13:16PM +0100, David Howells wrote:
> Christian Brauner <christian@xxxxxxxxxx> wrote:
> 
> > > +config FSINFO
> > 
> > Hm, any reason why we would hide that syscalls under a config option?
> 
> Rasmus Villemoes asked for it to be made conditional.

Ah, ok. I guess this is another case of "what about embedded users".
Fair enough.

> 
> https://lore.kernel.org/lkml/f3646774-ee9e-d5b7-8a11-670012034d59@xxxxxxxxxxxxxxxxxx/
> 
> > Do we, not have any dumb helpers for scenarios like this?:
> > 
> > #define strlen_literal(x) (sizeof(""x"") - 1)
> > #define strlen_array(x) (sizeof(x) - 1)
> 
> git grep doesn't find them under this name.

Yeah, than we don't have that. Might be worth having such helpers at
some point.

> 
> > > +	while (!signal_pending(current)) {
> > > +		params->usage = 0;
> > > +		ret = fsinfo(path, params);
> > > +		if (IS_ERR_VALUE((long)ret))
> > > +			return ret; /* Error */
> > > +		if ((unsigned int)ret <= params->buf_size)
> > 
> > if ((size_t)ret ...? Just for the sake of clarity if for nothing else.
> > 
> > > +			return ret; /* It fitted */
> > 
> > Ok, a little confused here, tbh. params->buf_size is size_t
> 
> It's "unsigned int".

Ok, good.

> 
> > and this function returns an int. Forgot whether you mentioned this before,
> > buf_size exceed can't exceed INT_MAX?
> 
> It's mentioned in the documentation (ie. fsinfo.rst).  I'll mention it in the
> comments adjacent to the attribute definition table also.

Thanks! I missed that apparently.

> 
> > Is it really wort it to have this code generating stuff in there?
> 
> From a readability PoV, yes, tabulation is awesome, IMO;-).  Up to 5 lines per
> attribute is too much vertical space and expanding it makes the whole thing
> much less readable.  Add to that that not all attributes will be the same
> number of lines.
> 
> It would be easier if the I could get away with making the constant names
> lower case, but the thou-shalt-capitalise-constantists dislike that, so, given
> that I don't know of a way to make the C preprocessor change the case of a
> symbol, I have to include both parts.
> 
> I have four pieces of information: type, depth, constant name, struct name (if
> applicable), and I can fit them on one line this way.
> 
> You really find this:
> 
> static const struct fsinfo_attr_info fsinfo_buffer_info[FSINFO_ATTR__NR] = {
> 	[FSINFO_ATTR_STATFS] = {
> 		.type	= __FSINFO_STRUCT,
> 		.flags	= __FSINFO_SINGLE,
> 		.size	= sizeof(struct fsinfo_statfs)
> 	},
> 	[FSINFO_ATTR_FSINFO] = {
> 		.type	= __FSINFO_STRUCT,
> 		.flags	= __FSINFO_SINGLE,
> 		.size	= sizeof(struct fsinfo_fsinfo)
> 	},
> 	[FSINFO_ATTR_IDS] = {
> 		.type	= __FSINFO_STRUCT,
> 		.flags	= __FSINFO_SINGLE,
> 		.size	= sizeof(struct fsinfo_ids)
> 	},
> 	[FSINFO_ATTR_LIMITS] = {
> 		.type	= __FSINFO_STRUCT,
> 		.flags	= __FSINFO_SINGLE,
> 		.size	= sizeof(struct fsinfo_limits)
> 	},
> 	[FSINFO_ATTR_CAPABILITIES] = {
> 		.type	= __FSINFO_STRUCT,
> 		.flags	= __FSINFO_SINGLE,
> 		.size	= sizeof(struct fsinfo_capabilities)
> 	},
> 	[FSINFO_ATTR_SUPPORTS] = {
> 		.type	= __FSINFO_STRUCT,
> 		.flags	= __FSINFO_SINGLE,
> 		.size	= sizeof(struct fsinfo_supports)
> 	},
> 	[FSINFO_ATTR_TIMESTAMP_INFO] = {
> 		.type	= __FSINFO_STRUCT,
> 		.flags	= __FSINFO_SINGLE,
> 		.size	= sizeof(struct fsinfo_timestamp_info)
> 	},
> 	[FSINFO_ATTR_VOLUME_ID] = {
> 		.type	= __FSINFO_STRING,
> 		.flags	= __FSINFO_SINGLE,
> 	},
> 	[FSINFO_ATTR_VOLUME_UUID] = {
> 		.type	= __FSINFO_STRUCT,
> 		.flags	= __FSINFO_SINGLE,
> 		.size	= sizeof(struct fsinfo_volume_uuid)
> 	},
> 	[FSINFO_ATTR_VOLUME_NAME] = {
> 		.type	= __FSINFO_STRING,
> 		.flags	= __FSINFO_SINGLE,
> 	},
> 	[FSINFO_ATTR_NAME_ENCODING] = {
> 		.type	= __FSINFO_STRING,
> 		.flags	= __FSINFO_SINGLE,
> 	},
> 	[FSINFO_ATTR_NAME_CODEPAGE] = {
> 		.type	= __FSINFO_STRING,
> 		.flags	= __FSINFO_SINGLE,
> 	},
> 	[FSINFO_ATTR_PARAM_DESCRIPTION] = {
> 		.type	= __FSINFO_STRUCT,
> 		.flags	= __FSINFO_SINGLE,
> 		.size	= sizeof(struct fsinfo_param_description)
> 	},
> 	[FSINFO_ATTR_PARAM_SPECIFICATION] = {
> 		.type	= __FSINFO_STRUCT,
> 		.flags	= __FSINFO_N,
> 		.size	= sizeof(struct fsinfo_param_specification)
> 	},
> 	[FSINFO_ATTR_PARAM_ENUM] = {
> 		.type	= __FSINFO_STRUCT,
> 		.flags	= __FSINFO_N,
> 		.size	= sizeof(struct fsinfo_param_enum)
> 	},
> 	[FSINFO_ATTR_PARAMETERS] = {
> 		.type	= __FSINFO_OPAQUE,
> 		.flags	= __FSINFO_SINGLE,
> 	},
> 	[FSINFO_ATTR_LSM_PARAMETERS] = {
> 		.type	= __FSINFO_OPAQUE,
> 		.flags	= __FSINFO_SINGLE,
> 	},
> 	[FSINFO_ATTR_SERVER_NAME] = {
> 		.type	= __FSINFO_STRING,
> 		.flags	= __FSINFO_N,
> 	},
> 	[FSINFO_ATTR_SERVER_ADDRESS] = {
> 		.type	= __FSINFO_STRUCT,
> 		.flags	= __FSINFO_NM,
> 		.size	= sizeof(struct fsinfo_server_address)
> 	},
> 	[FSINFO_ATTR_AFS_CELL_NAME] = {
> 		.type	= __FSINFO_STRING,
> 		.flags	= __FSINFO_SINGLE,
> 	},
> 	[FSINFO_ATTR_MOUNT_INFO] = {
> 		.type	= __FSINFO_STRUCT,
> 		.flags	= __FSINFO_SINGLE,
> 		.size	= sizeof(struct fsinfo_mount_info)
> 	},
> 	[FSINFO_ATTR_MOUNT_DEVNAME] = {
> 		.type	= __FSINFO_STRING,
> 		.flags	= __FSINFO_SINGLE,
> 	},
> 	[FSINFO_ATTR_MOUNT_CHILDREN] = {
> 		.type	= __FSINFO_STRUCT_ARRAY,
> 		.flags	= __FSINFO_SINGLE,
> 		.size	= sizeof(struct fsinfo_mount_child)
> 	},
> 	[FSINFO_ATTR_MOUNT_SUBMOUNT] = {
> 		.type	= __FSINFO_STRING,
> 		.flags	= __FSINFO_N,
> 	},
> };
> 
> is easier to read than this?:

Yes, very much so imho. :)

> 
> static const struct fsinfo_attr_info fsinfo_buffer_info[FSINFO_ATTR__NR] = {
> 	FSINFO_STRUCT		(STATFS,		statfs),
> 	FSINFO_STRUCT		(FSINFO,		fsinfo),
> 	FSINFO_STRUCT		(IDS,			ids),
> 	FSINFO_STRUCT		(LIMITS,		limits),
> 	FSINFO_STRUCT		(CAPABILITIES,		capabilities),
> 	FSINFO_STRUCT		(SUPPORTS,		supports),
> 	FSINFO_STRUCT		(TIMESTAMP_INFO,	timestamp_info),
> 	FSINFO_STRING		(VOLUME_ID),
> 	FSINFO_STRUCT		(VOLUME_UUID,		volume_uuid),
> 	FSINFO_STRING		(VOLUME_NAME),
> 	FSINFO_STRING		(NAME_ENCODING),
> 	FSINFO_STRING		(NAME_CODEPAGE),
> 	FSINFO_STRUCT		(PARAM_DESCRIPTION,	param_description),
> 	FSINFO_STRUCT_N		(PARAM_SPECIFICATION,	param_specification),
> 	FSINFO_STRUCT_N		(PARAM_ENUM,		param_enum),
> 	FSINFO_OPAQUE		(PARAMETERS),
> 	FSINFO_OPAQUE		(LSM_PARAMETERS),
> 	FSINFO_STRING_N		(SERVER_NAME),
> 	FSINFO_STRUCT_NM	(SERVER_ADDRESS,	server_address),
> 	FSINFO_STRING		(AFS_CELL_NAME),
> 	FSINFO_STRUCT		(MOUNT_INFO,		mount_info),
> 	FSINFO_STRING		(MOUNT_DEVNAME),
> 	FSINFO_STRUCT_ARRAY	(MOUNT_CHILDREN,	mount_child),
> 	FSINFO_STRING_N		(MOUNT_SUBMOUNT),
> };
> 
> The latter also has the advantage that I can take this and drop it into the
> test program and change the helper macros to make it do other things.  With
> the fully expanded code, that isn't possible.
> 
> One thing I will grant you, though, I can simplify:
> 
> #define __FSINFO_STRUCT		0
> #define __FSINFO_STRING		1
> #define __FSINFO_OPAQUE		2
> #define __FSINFO_STRUCT_ARRAY	3
> #define __FSINFO_0		0
> #define __FSINFO_N		0x0001
> #define __FSINFO_NM		0x0002
> 
> #define _Z(T, F, S) { .type = __FSINFO_##T, .flags = __FSINFO_##F, .size = S }
> #define FSINFO_STRING(X)	 [FSINFO_ATTR_##X] = _Z(STRING, 0, 0)
> #define FSINFO_STRUCT(X,Y)	 [FSINFO_ATTR_##X] = _Z(STRUCT, 0, sizeof(struct fsinfo_##Y))
> #define FSINFO_STRING_N(X)	 [FSINFO_ATTR_##X] = _Z(STRING, N, 0)
> #define FSINFO_STRUCT_N(X,Y)	 [FSINFO_ATTR_##X] = _Z(STRUCT, N, sizeof(struct fsinfo_##Y))
> #define FSINFO_STRING_NM(X)	 [FSINFO_ATTR_##X] = _Z(STRING, NM, 0)
> #define FSINFO_STRUCT_NM(X,Y)	 [FSINFO_ATTR_##X] = _Z(STRUCT, NM, sizeof(struct fsinfo_##Y))
> #define FSINFO_OPAQUE(X)	 [FSINFO_ATTR_##X] = _Z(OPAQUE, 0, 0)
> #define FSINFO_STRUCT_ARRAY(X,Y) [FSINFO_ATTR_##X] = _Z(STRUCT_ARRAY, 0, sizeof(struct fsinfo_##Y))
> 
> a bit:
> 
> #define __FSINFO_STRUCT		0
> #define __FSINFO_STRING		1
> #define __FSINFO_OPAQUE		2
> #define __FSINFO_STRUCT_ARRAY	3
> #define __FSINFO_N		0x01
> #define __FSINFO_NM		0x02
> 
> #define _Z(T, S)    { .type = __FSINFO_##T, .flags = 0,		  .size = S }
> #define _Z_N(T, S)  { .type = __FSINFO_##T, .flags = __FSINFO_N,  .size = S }
> #define _Z_NM(T, S) { .type = __FSINFO_##T, .flags = __FSINFO_NM, .size = S }
> #define FSINFO_STRING(X)	 [FSINFO_ATTR_##X] = _Z(STRING, 0)
> #define FSINFO_STRUCT(X,Y)	 [FSINFO_ATTR_##X] = _Z(STRUCT, sizeof(struct fsinfo_##Y))
> #define FSINFO_STRING_N(X)	 [FSINFO_ATTR_##X] = _Z_N(STRING, 0)
> #define FSINFO_STRUCT_N(X,Y)	 [FSINFO_ATTR_##X] = _Z_N(STRUCT, sizeof(struct fsinfo_##Y))
> #define FSINFO_STRING_NM(X)	 [FSINFO_ATTR_##X] = _Z_NM(STRING, 0)
> #define FSINFO_STRUCT_NM(X,Y)	 [FSINFO_ATTR_##X] = _Z_NM(STRUCT, sizeof(struct fsinfo_##Y))
> #define FSINFO_OPAQUE(X)	 [FSINFO_ATTR_##X] = _Z(OPAQUE, 0)
> #define FSINFO_STRUCT_ARRAY(X,Y) [FSINFO_ATTR_##X] = _Z(STRUCT_ARRAY, sizeof(struct fsinfo_##Y))
> 
> > I urge you to think about git grep users. For them this is an absolute
> > nightmare. :)
> 
> That's a valid point, but it's a problem all over the kernel.  We use
> macroisation everywhere.  See all the declaration and define macros that nest
> layers deep.

Well maybe we can stop doing it (at least for some stuff). :)

> 
> If that's your main worry, The attribute type name could be fully expanded in
> the table, eg.:
> 
> 	FSINFO_STRUCT		(FSINFO_ATTR_CAPABILITIES,	capabilities),
> 	FSINFO_STRING_N		(FSINFO_ATTR_MOUNT_SUBMOUNT),
> 
> > > +	unsigned int result_size;
> > 
> > Wouldn't it be better if this could be a size_t?
> 
> Why?  size_t takes more space on a 64-bit system, but I'm not allowing the
> filesystem to return that much data, mainly because I don't really want to be
> allocating a >2G buffer.
> 
> In fact, for large objects there's something to be said for writing directly
> to userspace rather than going through a buffer, but for the fact that I want
> to hold, say, the RCU readlock across the entire transaction in some
> instances.
> 
> > > +	if (!user_buffer || !user_buf_size) {
> > 
> > Maybe we could be a little more strict and require both be set to their
> > respective zero values, i.e. only support reporting the size if
> > !user_buffer && user_buf_size = 0 for that to work. If only one of them
> > is set to their zero value we report EINVAL.
> 
> That's an option, certainly.

Ok, up to you. I find my suggestion a little cleaner.

> 
> > Hm, I'm not sure that "capabilities" is a good name here. This is
> > potentially misleading because of other uses of "capabilities" we
> > already have. Like, I don't want thes capabilities to pop up when I do
> > git grep capabilities. Just a short way until someone also speaks of
> > "fscaps" or "fsinfocaps" and then confusion is basically guaranteed. :)
> > 
> > Maybe "features" would be better?
> 
> Yeah - that's probably better.  The only issue is that it doesn't have a nice
> short hypocoristicon like "cap", though I could use "feat" I guess.

FEAT is probably ok. Not pretty but "cap" isn't either. 

> 
> > > +#define _ATFILE_SOURCE
> > 
> > nit: Defining fsinfoat() implicitly or what's that supposed to do? If that's
> > the case wouldn't it be nicer to just explicitly declare fsinfoat()
> 
> Um...  fsinfo() takes AT_* flags.  It's fsinfoat(), ffsinfo() and lfsinfo()
> all rolled into one, plus a couple of extra bits.  It doesn't really need an
> at-suffix on the name as there's no at-less original.

Ah, seems like a very ancient macro...



[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux