I am working on a module to read a files xattributes on open. I have hooked the sys_open and due to this I need to get the dentry of the file without opening the file. In brief I have the inode and the absolute path but having trouble to figure out; how to get a dentry from these. All comments are very much appreciated.
OK. Other answers didn't cover how to obtain a dentry from pathname/absolute path. The following code snippet could it.
int ret = 0;
struct path path;
ret = kern_path("/proc/", LOOKUP_DIRECTORY, &path);
if (ret)
pr_err("Failed to lookup /proc/ err %d\n", ret);
else {
if (PROC_SUPER_MAGIC != path.mnt->mnt_sb->s_magic)
printk("BUG /proc is not mounted as Proc FS, magic %lx\n", path.mnt->mnt_sb->s_magic);
path_put(&path);
}
As per my understating you are trying to get the dentry path from your driver module during the open callback function . If so; then before putting down the way I am adding the structure list which are required to access the the dentry information.
include/linux/fs.h
Struct file{
struct path f_path;
};
include/linux/path.h
struct path {
struct vfsmount *mnt;
struct dentry *dentry;
};
include/linux/dcache.h
struct dentry {
};
So you can do like this.
static int sample_open(struct inode *inode, struct file *file)
{
char *path, *dentry,*par_dentry;
char buff[256];
dentry = file->f_path.dentry->d_iname;
pr_info("dentry :%s\n",dentry);
par_dentry = file->f_path.dentry->d_parent->d_iname;
pr_info("parent dentry :%s\n",par_dentry);
path=dentry_path_raw(file->f_path.dentry,buff,256);
pr_info("Dentry path %s\n",path);
}
Related
With this debugfs API I can create a file in /sys/kernel/debug/parent/name, but it's empty, no matter which data I put in void *data parameter
struct dentry *debugfs_create_file(const char *name, mode_t mode, struct dentry *parent, void *data, struct file_operations *fops);
According to documentation we need to implement file_operations ourself to handle file open and write.
A snippet of code from mine:
static ssize_t myreader(struct file *fp, char __user *user_buffer,
size_t count, loff_t *position)
{
return simple_read_from_buffer(user_buffer, count, position, ker_buf, len);
}
static ssize_t mywriter(struct file *fp, const char __user *user_buffer,
size_t count, loff_t *position)
{
if(count > len )
return -EINVAL;
return simple_write_to_buffer(ker_buf, len, position, user_buffer, count);
}
static const struct file_operations fops_debug = {
.read = myreader,
.write = mywriter,
};
static int __init init_debug(void)
{
dirret = debugfs_create_dir("dell", NULL);
fileret = debugfs_create_file("text", 0644, dirret, "HELLO WORLD", &fops_debug);
debugfs_create_u64("number", 0644, dirret, &intvalue);
return (0);
}
After installing this module to kernel, two files 'text' and 'number' will be created in the folder 'dell'. File 'number' contains the number I passed in as 'intvalue' as expected, but the other file 'text' is empty.
It's written in document that data will be stored in the i_private field of the resulting inode structure
My expectation: The string "HELLO WORLD" will be written in the file after module is loaded.
I think that the problem should be in the read and write operation functions. Is it possible to create a file with a particular content with the debugfs_create_file method?
To answer your question, whatever you are expecting from your code is correct but it is not going to produce the expected result. I believe there are other more efficient and correct ways of doing it, but to explain the current behavior:
You are initializing data as content of file text but you are reading from buffer ker_buf in user_buffer instead of file pointer using simple_read_from_buffer(user_buffer, count, position, ker_buf, len);
Similarly you are writing to kern_buf from user_buffer using simple_write_to_buffer(ker_buf, len, position, user_buffer, count);
With the existing code, if you want to achieve what you are trying to do, then you have to copy the string "HELLO WORLD" to kern_buf in init_debug()
Something like:
strscpy(kern_buf, "HELLO WORLD", strlen("HELLO WORLD") + 1);
or in form of complete function:
static int __init init_debug(void)
{
dirret = debugfs_create_dir("dell", NULL);
fileret = debugfs_create_file("text", 0644, dirret, NULL, &fops_debug);
debugfs_create_u64("number", 0644, dirret, &intvalue);
strscpy(kern_buf, "HELLO WORLD", strlen("HELLO WORLD") + 1);
return (0);
}
Edit:
Referred some online materials and found out that the void *data provided to debugfs_create_file() during initialization gets stored in the i_private field and can be later retrieved from the i_private field of the resulting inode structure.
The inode of the respective file can be fetched from struct file *fp which is the first argument of read() or write() operations.
The struct inode is a member of struct file and i_private is a member of struct inode
To fetch void *data provided during file creation via debugfs_create_file() in read() you can do something similar to as shown below:
static ssize_t myreader(struct file *fp, char __user *user_buffer,
size_t count, loff_t *position)
{
struct inode *l_inode = fp->f_inode;
strscpy(user_buffer, (char *)l_inode->i_private, PAGE_SIZE);
...
}
Can't get fd or dirfd from params, they are always be -100.
The kernel module is developed under CentOS 8.3, Linux kernel version 4.18.
The result is -100
I am a little confused why this will happen.
The reason why I need dfd is I want to get the absolute path, when input pathname alike "../".
asmlinkage int modified_unlinkat(const struct pt_regs *regs) {
int result;
int dfd = (int)regs->di;
char *tmp = (char*)__get_free_page(256);
struct file *files = fget(dfd);
if (!files) {
conivent_printf("%d", dfd);
return -EACCES;
}
char *path = d_path(&files->f_path, tmp, PAGE_SIZE);
conivent_printf("%s", path);
return -EACCESS;
}
If anyone could provide help, I will be extremely appreciate.
I was wondering if it was possible to know if the rootfile system has been mounted from the kernel. Im trying to read a file from /bin but it doesnt work on boot.
static int ret_my_file() is in fs/exec.c
static int ret_my_file()
{
struct file* f;
char *dbtext;
struct path dbpath;
mm_segment_t oldfs;
struct kstat dbstat;
kern_path("/bin/myfile", 0, &dbpath);
vfs_getattr(&dbpath, &dbstat);
dbtext = vmalloc(dbstat.size*sizeof(char));
f=filp_open("/bin/myfile", O_RDONLY, 0);
oldfs=get_fs();
set_fs (KERNEL_DS);
vfs_read(f, dbtext, dbstat.size, &f->f_pos);
set_fs(oldfs);
printk(KERN_CRIT "Db value is");
printk(KERN_CRIT "%s\n",dbtext);
vfree(dbtext);
return 0;
}
called in the function do_execveat_common() also in fs/exec.c as
static int do_execveat_common(int fd, struct filename *filename,
struct user_arg_ptr argv,
struct user_arg_ptr envp,
int flags)
{
char *pathbuf = NULL;
struct linux_binprm *bprm;
struct file *file;
struct files_struct *displaced;
int retval;
retval=ret_my_file();
......}
but the function do_execveat_common() is called during boot up so i wanted to put a condition before retval=ret_my_file(); so that it only runs after the root filesystem has been mounted
I'm not sure what I'm doing incorrectly but it's time for some extra eyes. I make a device with device_create() providing some "extra data" as follows:
pDevice = device_create(ahcip_class, NULL, /*no parent*/
MKDEV(AHCIP_MAJOR, AHCIP_MINOR + i), &mydevs[i],
DRIVER_NAME "%d", AHCIP_MINOR + i);
Expecting that my sysfs attribute function is going to take a pointer to the struct kobject member of struct device I do the following with my attribute function
static ahcip_dev *get_ahcip_dev(struct kobject *ko)
{
ahcip_dev *adev = NULL;
struct device *pdev = container_of(ko, struct device, kobj);
if (!pdev) {
pr_err("%s:%d unable to find device struct in kobject\n",
__func__, __LINE__);
return NULL;
}
/* some debugging stuff */
pr_info("%s:%d mydevs[0] %p\n", __func__, __LINE__, mydevs);
pr_info("%s:%d mydevs[1] %p\n", __func__, __LINE__, mydevs+1);
pr_info("%s:%d mydevs[0].psysfs_dev %p\n", __func__, __LINE__,
mydevs->psysfs_dev);
pr_info("%s:%d mydevs[1].psysfs_dev %p\n", __func__, __LINE__,
(mydevs + 1)->psysfs_dev);
pr_info("%s:%d pdev %p\n", __func__, __LINE__, pdev);
adev = (ahcip_dev*)dev_get_drvdata(pdev);
/* return the pointer anyway, but if it's null, print to klog */
if (!adev)
pr_err("%s:%d no ahcip_dev, private driver data is NULL\n",
__func__, __LINE__);
return adev;
}
static ssize_t pxis_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buff)
{
u32 pi = 0;
ahcip_dev *adev = get_ahcip_dev(kobj);
/* get_ahcip_dev() will print what happened, this needs to return
* error code
*/
if (!adev)
return -EIO;
pi = adev->port_index;
return sprintf(buff, "%08x\n", get_port_reg(adev->hba->ports[pi], 0x10));
}
The output (condensed) from the above function shows:
get_ahcip_dev:175 mydevs[1].psysfs_dev ffff88011b2b4800
get_ahcip_dev:176 pdev ffff88011b2b47f0
pdev in this case should point to the same memory location as mydevs[1].psysfs_dev but it's 16 bytes "earlier". What am I doing wrong?
I don't like to answer my own questions but this seems appropriate in this case. The root of the problem was a faulty assumption of what the attribute function needed to process. Attribute functions have this prototype you can view in context here
ssize_t (*show)(struct kobject *, struct attribute *,char *);
ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t);
Since the device_create() function returns a struct device object defined as follows (excerpt only, see full def here)
struct device {
struct device *parent;
struct device_private *p;
struct kobject kobj;
...
}
I assumed that it was this pointer that my attribute function must process. Reading through the description of the problem shows that when I used the container_of macro to get what I thought was the address of the containing struct device I was 16 bytes "to early." Notice, the first two fields of this structure are pointers. On a 64 bit system, which mine is, this is 16 bytes.
Because the function prototypes are defined as shown above, I assumed I was getting a reference to the kobj field. Instead, I was getting the actual struct device object. In other words, I was getting the address I wanted upon function entry and was still trying to find it.
Something about this may be documented in the labyrinth of Linux kernel documentation. If anyone knows of it, please put a link here. I read much but didn't see this one coming. I hope this question and answer helps some other kernel newbie.
Your example did not show how you created the sysfs attribute nor how your pxis_show() function was associated with it. Since you're trying to connect this attribute to a struct device, might you happen to be calling device_create_file() to create the sysfs node? If so, examining the callback prototypes of struct device_attribute might make more sense. You will see that the show/store callbacks look like:
ssize_t (*show)(struct device *dev, struct device_attribute *attr, char *buf);
ssize_t (*store)(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count);
In which case that might better explain your extra offset issue--the first parameter is actually already pointing to your struct device, and not the embedded kobj member, so that performing a container_of() will take you back an additional 16 bytes.
You might be confusing the device_attribute callbacks with the struct sysfs_ops format, as they look similar, but notice the parameter types are different. In fact, there is a mapping from sysfs_ops to struct device_attribute as can be seen with the wrapper functions dev_attr_show and dev_attr_store as can be found here
I am moving userspace sysfs interaction to the "/dev" using miscregister using ioctl method.
Can we resolve client structure(struct i2c_client) from Inode of please somebody tell how to get client structure inside ioctl. I need to do i2c transfer inside ioctl.
I referred this link :
http://stackoverflow.com/questions/2635038/inode-to-device-information
but coudln get any answer.
please someone give solution.
while you open your device in kernel using your open function. (this part of code is copied from one of the mainline drivers (drivers/i2c/i2c-dev.c) to make things easy for you)
my_i2c_device_open(struct inode *inode, struct file *file)
{
unsigned int minor = iminor(inode);
struct i2c_client *client;
struct i2c_adapter *adap;
struct i2c_dev *i2c_dev;
i2c_dev = i2c_dev_get_by_minor(minor);
if (!i2c_dev)
return -ENODEV;
adap = i2c_get_adapter(i2c_dev->adap->nr);
if (!adap)
return -ENODEV;
client = kzalloc(sizeof(*client), GFP_KERNEL);
if (!client) {
i2c_put_adapter(adap);
return -ENOMEM;
}
snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
client->adapter = adap;
file->private_data = client;
return 0;
}
when you call ioctl you can retrieve the i2c_client from the file pointer of your device:
static long my_i2c_device_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct i2c_client *client = file->private_data;
}
Hope this makes your life easy.'
This reference might help:
Reason to pass data using struct inode and struct file in Linux device driver programming
You build yourself a structure equivalent with "struct scull_dev" in the example above and you store there a reference to the i2c_client structure. In the IOCTL function you can retrieve later on the main control structure and the reference to the i2c_client through container_of.