[DTrace-devel] [PATCH] Add support for getmajor() and getminor() subroutines

Eugene Loh eugene.loh at oracle.com
Tue Feb 15 20:10:06 UTC 2022


Actually, I probably did this wrong, but before I fix could someone 
comment on this inconsistency?

In kernel header include/linux/kdev_t.h, we have:
         #include <uapi/linux/kdev_t.h>

         #define MINORBITS       20
         #define MINORMASK       ((1U << MINORBITS) - 1)

         #define MAJOR(dev)      ((unsigned int) ((dev) >> MINORBITS))
         #define MINOR(dev)      ((unsigned int) ((dev) & MINORMASK))

Then, in include/uapi/linux/kdev_t.h, we have:
         #define MAJOR(dev)      ((dev)>>8)
         #define MINOR(dev)      ((dev) & 0xff)

Should I simply ignore the uapi version?  (Also, it has 
sizeof(kdev_t)==8, while the kernel has 4.)

On 2/15/22 3:00 PM, eugene.loh at oracle.com wrote:
> From: Eugene Loh <eugene.loh at oracle.com>
>
> The expected behavior is unclear.  E.g., with D script
>      y = 0x1234567890abcdef;
>      printf("%x\n", getmajor(y));
>      printf("%x\n", getminor(y));
> Solaris gives
>      12345678
>      90abcdef
> while legacy DTrace (on Linux) gives
>      90a
>      bcdef
> Further, there were no tests.
>
> Implement the behavior that is in /usr/include/linux/kdev_t.h:
>      #define MAJOR(dev)      ((dev)>>8)
>      #define MINOR(dev)      ((dev) & 0xff)
> and add tests.
>
> Signed-off-by: Eugene Loh <eugene.loh at oracle.com>
> ---
>   libdtrace/dt_cg.c                   | 27 +++++++++++-
>   test/unittest/funcs/tst.getmajor.sh | 65 +++++++++++++++++++++++++++++
>   test/unittest/funcs/tst.getminor.sh | 59 ++++++++++++++++++++++++++
>   3 files changed, 149 insertions(+), 2 deletions(-)
>   create mode 100755 test/unittest/funcs/tst.getmajor.sh
>   create mode 100755 test/unittest/funcs/tst.getminor.sh
>
> diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
> index b6b39617..bd05bd32 100644
> --- a/libdtrace/dt_cg.c
> +++ b/libdtrace/dt_cg.c
> @@ -3374,6 +3374,29 @@ dt_cg_subr_dirname(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
>   	dt_cg_subr_path_helper(dnp, dlp, drp, "dt_dirname");
>   }
>   
> +/*
> + * For getmajor and getminor, see /usr/include/linux/kdev_t.h.
> + */
> +static void
> +dt_cg_subr_getmajor(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
> +{
> +	dt_node_t	*arg = dnp->dn_args;
> +
> +	dt_cg_node(arg, dlp, drp);
> +	dnp->dn_reg = arg->dn_reg;
> +	emit(dlp, BPF_ALU64_IMM(BPF_RSH, dnp->dn_reg, 8));
> +}
> +
> +static void
> +dt_cg_subr_getminor(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
> +{
> +	dt_node_t	*arg = dnp->dn_args;
> +
> +	dt_cg_node(arg, dlp, drp);
> +	dnp->dn_reg = arg->dn_reg;
> +	emit(dlp, BPF_ALU64_IMM(BPF_AND, dnp->dn_reg, 0xff));
> +}
> +
>   /*
>    * Get and return a new speculation ID.  These are unallocated entries in the
>    * specs map, obtained by calling dt_speculation().  Return zero if none is
> @@ -4120,8 +4143,8 @@ static dt_cg_subr_f *_dt_cg_subr[DIF_SUBR_MAX + 1] = {
>   	[DIF_SUBR_COPYINTO]		= NULL,
>   	[DIF_SUBR_MSGDSIZE]		= NULL,
>   	[DIF_SUBR_MSGSIZE]		= NULL,
> -	[DIF_SUBR_GETMAJOR]		= NULL,
> -	[DIF_SUBR_GETMINOR]		= NULL,
> +	[DIF_SUBR_GETMAJOR]		= &dt_cg_subr_getmajor,
> +	[DIF_SUBR_GETMINOR]		= &dt_cg_subr_getminor,
>   	[DIF_SUBR_DDI_PATHNAME]		= NULL,
>   	[DIF_SUBR_STRJOIN]		= dt_cg_subr_strjoin,
>   	[DIF_SUBR_LLTOSTR]		= &dt_cg_subr_lltostr,
> diff --git a/test/unittest/funcs/tst.getmajor.sh b/test/unittest/funcs/tst.getmajor.sh
> new file mode 100755
> index 00000000..65fb5036
> --- /dev/null
> +++ b/test/unittest/funcs/tst.getmajor.sh
> @@ -0,0 +1,65 @@
> +#!/bin/bash
> +#
> +# Oracle Linux DTrace.
> +# Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
> +# Licensed under the Universal Permissive License v 1.0 as shown at
> +# http://oss.oracle.com/licenses/upl.
> +#
> +
> +dtrace=$1
> +
> +DIRNAME="$tmpdir/getmajor.$$.$RANDOM"
> +mkdir -p $DIRNAME
> +cd $DIRNAME
> +
> +cat << EOF > test.c
> +#include <stdio.h>
> +#include <sys/types.h>		/* for dev_t, or use <sys/stat.h> */
> +#include <linux/kdev_t.h>	/* for MAJOR */
> +
> +int main(int c, char **v) {
> +	long long y = 0x1234567890abcdefll;
> +	dev_t x = y;
> +
> +	/*
> +	 * sizeof(dev_t) is:
> +	 *   8 bytes in  user  header /usr/include/sys/types.h
> +	 *   4 bytes in kernel header include/linux/types.h
> +	 * DTrace uses the kernel dev_t.  So truncate the result.
> +	 */
> +	printf("%x\n\n", (unsigned int) MAJOR(x));
> +	return 0;
> +}
> +EOF
> +
> +gcc test.c
> +if [ $? -ne 0 ]; then
> +	echo ERROR: test.c did not compile
> +	exit 1
> +fi
> +
> +./a.out > test.out
> +
> +$dtrace -qn '
> +BEGIN
> +{
> +	printf("%x\n", getmajor(0x1234567890abcdef));
> +	exit(0)
> +}' > dtrace.out
> +if [ $? -ne 0 ]; then
> +	echo ERROR: dtrace error
> +	exit 1
> +fi
> +
> +diff test.out dtrace.out
> +if [ $? -ne 0 ]; then
> +	echo ERROR: unexpected output
> +	echo expect:
> +	cat test.out
> +	echo actual:
> +	cat dtrace.out
> +	exit 1
> +fi
> +
> +echo success
> +exit 0
> diff --git a/test/unittest/funcs/tst.getminor.sh b/test/unittest/funcs/tst.getminor.sh
> new file mode 100755
> index 00000000..34b77e23
> --- /dev/null
> +++ b/test/unittest/funcs/tst.getminor.sh
> @@ -0,0 +1,59 @@
> +#!/bin/bash
> +#
> +# Oracle Linux DTrace.
> +# Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
> +# Licensed under the Universal Permissive License v 1.0 as shown at
> +# http://oss.oracle.com/licenses/upl.
> +#
> +
> +dtrace=$1
> +
> +DIRNAME="$tmpdir/getminor.$$.$RANDOM"
> +mkdir -p $DIRNAME
> +cd $DIRNAME
> +
> +cat << EOF > test.c
> +#include <stdio.h>
> +#include <sys/types.h>		/* for dev_t, or use <sys/stat.h> */
> +#include <linux/kdev_t.h>	/* for MINOR */
> +
> +int main(int c, char **v) {
> +	long long y = 0x1234567890abcdefll;
> +	dev_t x = y;
> +
> +	printf("%x\n\n", (unsigned int) MINOR(x));
> +	return 0;
> +}
> +EOF
> +
> +gcc test.c
> +if [ $? -ne 0 ]; then
> +	echo ERROR: test.c did not compile
> +	exit 1
> +fi
> +
> +./a.out > test.out
> +
> +$dtrace -qn '
> +BEGIN
> +{
> +	printf("%x\n", getminor(0x1234567890abcdef));
> +	exit(0)
> +}' > dtrace.out
> +if [ $? -ne 0 ]; then
> +	echo ERROR: dtrace error
> +	exit 1
> +fi
> +
> +diff test.out dtrace.out
> +if [ $? -ne 0 ]; then
> +	echo ERROR: unexpected output
> +	echo expect:
> +	cat test.out
> +	echo actual:
> +	cat dtrace.out
> +	exit 1
> +fi
> +
> +echo success
> +exit 0



More information about the DTrace-devel mailing list