Can't get Major and Minor number for device correctly.

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


I've a kernel module which needs to get hold of the gen_disk structure. To make it a bit interactive I've a user space program which uses stat sys call to get the respective device's dev_t number (I use s_rdev of the struct stat) and pass it on to my module via an ioctl call. This part works good.

When my module tries to use the get_gendisk function it returns NULL. I printed out the MAJOR(dev_t) and MINOR(dev_t) and was surprised to get the value 0 for MAJOR(dev_t). A little more digging got me to this code snippet, the file is kdev_t.h


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

#define MAJOR(dev)      ((unsigned int) ((dev) >> MINORBITS))
#define MINOR(dev)      ((unsigned int) ((dev) & MINORMASK))
#define MKDEV(ma,mi)    (((ma) << MINORBITS) | (mi))

#else /* __KERNEL__ */

Some programs want their definitions of MAJOR and MINOR and MKDEV
from the kernel sources. These must be the externally visible ones.
#define MAJOR(dev)      ((dev)>>8)
#define MINOR(dev)      ((dev) & 0xff)
#define MKDEV(ma,mi)    ((ma)<<8 | (mi))
#endif /* __KERNEL__ */


Since __KERNEL__ is defined in the topmost Makefile, the first definition of macros would be used which is giving me the wrong result. But what I really want is the #else one.

Surprisingly doing a major and minor in user space works. I traced it back to the following code snippet, in file /usr/include/sys/sysmacros.h


# if defined __GNUC__ && __GNUC__ >= 2 && defined __USE_EXTERN_INLINES
__extension__ __extern_inline unsigned int
__NTH (gnu_dev_major (unsigned long long int __dev))
  return ((__dev >> 8) & 0xfff) | ((unsigned int) (__dev >> 32) & ~0xfff);

__extension__ __extern_inline unsigned int
__NTH (gnu_dev_minor (unsigned long long int __dev))
  return (__dev & 0xff) | ((unsigned int) (__dev >> 12) & ~0xff);

# define major(dev) gnu_dev_major (dev)
# define minor(dev) gnu_dev_minor (dev)


So basically the user space code doing stat and then major/minor works because its doing the dev_t>>8.

My questions are,

 1. How does MAJOR, MINOR are able to work within kernel with 32 bit definitions?, since dev_t>>20 would make the major number 0 and get_gendisk should then fail and most of the devices listed like my disks don't report a quite big dev_t when I do stat on them.

 2. Should I be checking for wether or not 32 bits dev_t is in effect? But if I've to do this what's the purpose of using the macros MAJOR and MINOR? Aren't these there to do the same job?

As an example, doing stat reported stat.s_rdev field to be 2065, which accordingly translate to 8,17.

I'm using SLES 11 SP1, kernel 2.6.32

Pranay Kr. Srivastava
Software Engineer
ERS,HCL Technologies
A-5, Sector 24, Noida 201301, U.P. (India)


The contents of this e-mail and any attachment(s) are confidential and intended for the named recipient(s) only.
It shall not attach any liability on the originator or HCL or its affiliates. Any views or opinions presented in
this email are solely those of the author and may not necessarily reflect the opinions of HCL or its affiliates.
Any form of reproduction, dissemination, copying, disclosure, modification, distribution and / or publication of
this message without the prior written consent of the author of this e-mail is strictly prohibited. If you have
received this email in error please delete it and notify the sender immediately. Before opening any mail and
attachments please check them for viruses and defect.


Kernelnewbies mailing list

[Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Photo]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Networking]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]

Add to Google Powered by Linux