上面的文章分析了sysfs中文件的创建过程, 既然文件已经建立起来了,读写它才是我们最终的目的撒,本文就来看看sysfs是咋个通过VFS接口读写sysfs下的文件.
sysfs属性文件操作方法
在函数sysfs_init_inode()中初始化了sysfs属性文件的操作方法为sysfs_file_operations, 下面就拿属性文件操作方法分析sysfs文件读写流程.
const struct file_operations sysfs_file_operations = {
.read = sysfs_read_file,
.write = sysfs_write_file,
.llseek = generic_file_llseek,
.open = sysfs_open_file,
.release = sysfs_release,
.poll = sysfs_poll,
};
关于VFS是如何调到这些回调函数的,在以前的文章中已经分析过了哦,我们下面直接来看看这些函数是
如何实现的.........
sysfs打开属性文件
sysfs定义的属性文件打开操作函数为sysfs_open_file()
323 static int sysfs_open_file(struct inode *inode, struct file *file)
324 {
325 struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
326 struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
327 struct sysfs_buffer *buffer;
328 struct sysfs_ops *ops;
329 int error = -EACCES;
330
331 /* need attr_sd for attr and ops, its parent for kobj */
332 if (!sysfs_get_active_two(attr_sd))
333 return -ENODEV;
334
335 /* every kobject with an attribute needs a ktype assigned */
336 if (kobj->ktype && kobj->ktype->sysfs_ops)
337 ops = kobj->ktype->sysfs_ops;
338 else {
339 printk(KERN_ERR "missing sysfs attribute operations for "
340 "kobject: %s\n", kobject_name(kobj));
341 WARN_ON(1);
342 goto err_out;
343 }
344
……………………
366 error = -ENOMEM;
367 buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL);
368 if (!buffer)
369 goto err_out;
370
371 mutex_init(&buffer->mutex);
372 buffer->needs_read_fill = 1;
373 buffer->ops = ops;
374 file->private_data = buffer;
375
376 /* make sure we have open dirent struct */
377 error = sysfs_get_open_dirent(attr_sd, buffer);
378 if (error)
379 goto err_free;
380
381 /* open succeeded, put active references */
382 sysfs_put_active_two(attr_sd);
383 return 0;
384
385 err_free:
386 kfree(buffer);
387 err_out:
388 sysfs_put_active_two(attr_sd);
389 return error;
390 }
第325-326行函数的目的就是要取出当前文件 父目录对应的kobj对象
第337行代码就是操作sysfs文件的关键地方了,ops = kobj->ktype->sysfs_ops;从这段代码可以看出sysfs文件的操作方法实际上用的是该文件父目录的kobj关联的ktype中定义的sysfs_ops操作方法
struct sysfs_ops {
ssize_t (*show)(struct kobject *, struct attribute *,char *);
ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t);
};
可以看到sysfs下的属性文件只定义了show和store方法.
第367-374行, 先是分配一个sysfs_buffer结构并将上面取到的文件操作方法ops 初始化给buffer->ops,,最后再将buffer结构初始化给file->private_data ,这样我们在后面的读和写中就可以取到它的信息了.
sysfs读属性文件
在打开了文件以后再看看怎么读这个文件.
125 static ssize_t
126 sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos)
127 {
128 struct sysfs_buffer * buffer = file->private_data;
129 ssize_t retval = 0;
130
131 mutex_lock(&buffer->mutex);
132 if (buffer->needs_read_fill || *ppos == 0) {
133 retval = fill_read_buffer(file->f_path.dentry,buffer);
134 if (retval)
135 goto out;
136 }
137 pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n",
138 __func__, count, *ppos, buffer->page);
139 retval = simple_read_from_buffer(buf, count, ppos, buffer->page,
140 buffer->count);
141 out:
142 mutex_unlock(&buffer->mutex);
143 return retval;
144 }
第128行先取出刚才打开时建立的buffer结构.
第133行fill_read_buffer()函数就是调用buffer->ops->show()文件读操作,读到的数据在buffer->page
第139行函数simple_read_from_buffer()函数很简单,这个函数就是把我们读到的数据拷贝到用户空间 ,实现与用户空间的数据交互.
sysfs写属性文件
sysfs属性文件的写操作和读操作都是差不多的.
225 static ssize_t
226 sysfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
227 {
228 struct sysfs_buffer * buffer = file->private_data;
229 ssize_t len;
230
231 mutex_lock(&buffer->mutex);
232 len = fill_write_buffer(buffer, buf, count);
233 if (len > 0)
234 len = flush_write_buffer(file->f_path.dentry, buffer, len);
235 if (len > 0)
236 *ppos += len;
237 mutex_unlock(&buffer->mutex);
238 return len;
239 }
第232行函数首先需要把用户空间的数据拷贝到内核空间
第234行,调用ops->store()写操作回调函数 .
到这里sysfs文件的创建读写操作分析就已经完成了 ,这些都是理解linux设备模型的基础, 也为深入研究linux设备模型提供了条件.