⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 file.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	 */	if (kobj->kset && kobj->kset->ktype)		ops = kobj->kset->ktype->sysfs_ops;	else if (kobj->ktype)		ops = kobj->ktype->sysfs_ops;	else		ops = &subsys_sysfs_ops;	error = -EACCES;	/* No sysfs operations, either from having no subsystem,	 * or the subsystem have no operations.	 */	if (!ops)		goto err_out;	/* File needs write support.	 * The inode's perms must say it's ok, 	 * and we must have a store method.	 */	if (file->f_mode & FMODE_WRITE) {		if (!(inode->i_mode & S_IWUGO) || !ops->store)			goto err_out;	}	/* File needs read support.	 * The inode's perms must say it's ok, and we there	 * must be a show method for it.	 */	if (file->f_mode & FMODE_READ) {		if (!(inode->i_mode & S_IRUGO) || !ops->show)			goto err_out;	}	/* No error? Great, allocate a buffer for the file, and store it	 * it in file->private_data for easy access.	 */	error = -ENOMEM;	buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL);	if (!buffer)		goto err_out;	mutex_init(&buffer->mutex);	buffer->needs_read_fill = 1;	buffer->ops = ops;	file->private_data = buffer;	/* make sure we have open dirent struct */	error = sysfs_get_open_dirent(attr_sd, buffer);	if (error)		goto err_free;	/* open succeeded, put active references */	sysfs_put_active_two(attr_sd);	return 0; err_free:	kfree(buffer); err_out:	sysfs_put_active_two(attr_sd);	return error;}static int sysfs_release(struct inode *inode, struct file *filp){	struct sysfs_dirent *sd = filp->f_path.dentry->d_fsdata;	struct sysfs_buffer *buffer = filp->private_data;	sysfs_put_open_dirent(sd, buffer);	if (buffer->page)		free_page((unsigned long)buffer->page);	kfree(buffer);	return 0;}/* Sysfs attribute files are pollable.  The idea is that you read * the content and then you use 'poll' or 'select' to wait for * the content to change.  When the content changes (assuming the * manager for the kobject supports notification), poll will * return POLLERR|POLLPRI, and select will return the fd whether * it is waiting for read, write, or exceptions. * Once poll/select indicates that the value has changed, you * need to close and re-open the file, as simply seeking and reading * again will not get new data, or reset the state of 'poll'. * Reminder: this only works for attributes which actively support * it, and it is not possible to test an attribute from userspace * to see if it supports poll (Neither 'poll' nor 'select' return * an appropriate error code).  When in doubt, set a suitable timeout value. */static unsigned int sysfs_poll(struct file *filp, poll_table *wait){	struct sysfs_buffer * buffer = filp->private_data;	struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata;	struct sysfs_open_dirent *od = attr_sd->s_attr.open;	/* need parent for the kobj, grab both */	if (!sysfs_get_active_two(attr_sd))		goto trigger;	poll_wait(filp, &od->poll, wait);	sysfs_put_active_two(attr_sd);	if (buffer->event != atomic_read(&od->event))		goto trigger;	return 0; trigger:	buffer->needs_read_fill = 1;	return POLLERR|POLLPRI;}void sysfs_notify(struct kobject *k, char *dir, char *attr){	struct sysfs_dirent *sd = k->sd;	mutex_lock(&sysfs_mutex);	if (sd && dir)		sd = sysfs_find_dirent(sd, dir);	if (sd && attr)		sd = sysfs_find_dirent(sd, attr);	if (sd) {		struct sysfs_open_dirent *od;		spin_lock(&sysfs_open_dirent_lock);		od = sd->s_attr.open;		if (od) {			atomic_inc(&od->event);			wake_up_interruptible(&od->poll);		}		spin_unlock(&sysfs_open_dirent_lock);	}	mutex_unlock(&sysfs_mutex);}EXPORT_SYMBOL_GPL(sysfs_notify);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,};int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,		   int type){	umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG;	struct sysfs_addrm_cxt acxt;	struct sysfs_dirent *sd;	int rc;	sd = sysfs_new_dirent(attr->name, mode, type);	if (!sd)		return -ENOMEM;	sd->s_attr.attr = (void *)attr;	sysfs_addrm_start(&acxt, dir_sd);	rc = sysfs_add_one(&acxt, sd);	sysfs_addrm_finish(&acxt);	if (rc)		sysfs_put(sd);	return rc;}/** *	sysfs_create_file - create an attribute file for an object. *	@kobj:	object we're creating for.  *	@attr:	attribute descriptor. */int sysfs_create_file(struct kobject * kobj, const struct attribute * attr){	BUG_ON(!kobj || !kobj->sd || !attr);	return sysfs_add_file(kobj->sd, attr, SYSFS_KOBJ_ATTR);}/** * sysfs_add_file_to_group - add an attribute file to a pre-existing group. * @kobj: object we're acting for. * @attr: attribute descriptor. * @group: group name. */int sysfs_add_file_to_group(struct kobject *kobj,		const struct attribute *attr, const char *group){	struct sysfs_dirent *dir_sd;	int error;	dir_sd = sysfs_get_dirent(kobj->sd, group);	if (!dir_sd)		return -ENOENT;	error = sysfs_add_file(dir_sd, attr, SYSFS_KOBJ_ATTR);	sysfs_put(dir_sd);	return error;}EXPORT_SYMBOL_GPL(sysfs_add_file_to_group);/** * sysfs_chmod_file - update the modified mode value on an object attribute. * @kobj: object we're acting for. * @attr: attribute descriptor. * @mode: file permissions. * */int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode){	struct sysfs_dirent *victim_sd = NULL;	struct dentry *victim = NULL;	struct inode * inode;	struct iattr newattrs;	int rc;	rc = -ENOENT;	victim_sd = sysfs_get_dirent(kobj->sd, attr->name);	if (!victim_sd)		goto out;	mutex_lock(&sysfs_rename_mutex);	victim = sysfs_get_dentry(victim_sd);	mutex_unlock(&sysfs_rename_mutex);	if (IS_ERR(victim)) {		rc = PTR_ERR(victim);		victim = NULL;		goto out;	}	inode = victim->d_inode;	mutex_lock(&inode->i_mutex);	newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);	newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;	rc = notify_change(victim, &newattrs);	if (rc == 0) {		mutex_lock(&sysfs_mutex);		victim_sd->s_mode = newattrs.ia_mode;		mutex_unlock(&sysfs_mutex);	}	mutex_unlock(&inode->i_mutex); out:	dput(victim);	sysfs_put(victim_sd);	return rc;}EXPORT_SYMBOL_GPL(sysfs_chmod_file);/** *	sysfs_remove_file - remove an object attribute. *	@kobj:	object we're acting for. *	@attr:	attribute descriptor. * *	Hash the attribute name and kill the victim. */void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr){	sysfs_hash_and_remove(kobj->sd, attr->name);}/** * sysfs_remove_file_from_group - remove an attribute file from a group. * @kobj: object we're acting for. * @attr: attribute descriptor. * @group: group name. */void sysfs_remove_file_from_group(struct kobject *kobj,		const struct attribute *attr, const char *group){	struct sysfs_dirent *dir_sd;	dir_sd = sysfs_get_dirent(kobj->sd, group);	if (dir_sd) {		sysfs_hash_and_remove(dir_sd, attr->name);		sysfs_put(dir_sd);	}}EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group);struct sysfs_schedule_callback_struct {	struct kobject 		*kobj;	void			(*func)(void *);	void			*data;	struct module		*owner;	struct work_struct	work;};static void sysfs_schedule_callback_work(struct work_struct *work){	struct sysfs_schedule_callback_struct *ss = container_of(work,			struct sysfs_schedule_callback_struct, work);	(ss->func)(ss->data);	kobject_put(ss->kobj);	module_put(ss->owner);	kfree(ss);}/** * sysfs_schedule_callback - helper to schedule a callback for a kobject * @kobj: object we're acting for. * @func: callback function to invoke later. * @data: argument to pass to @func. * @owner: module owning the callback code * * sysfs attribute methods must not unregister themselves or their parent * kobject (which would amount to the same thing).  Attempts to do so will * deadlock, since unregistration is mutually exclusive with driver * callbacks. * * Instead methods can call this routine, which will attempt to allocate * and schedule a workqueue request to call back @func with @data as its * argument in the workqueue's process context.  @kobj will be pinned * until @func returns. * * Returns 0 if the request was submitted, -ENOMEM if storage could not * be allocated, -ENODEV if a reference to @owner isn't available. */int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *),		void *data, struct module *owner){	struct sysfs_schedule_callback_struct *ss;	if (!try_module_get(owner))		return -ENODEV;	ss = kmalloc(sizeof(*ss), GFP_KERNEL);	if (!ss) {		module_put(owner);		return -ENOMEM;	}	kobject_get(kobj);	ss->kobj = kobj;	ss->func = func;	ss->data = data;	ss->owner = owner;	INIT_WORK(&ss->work, sysfs_schedule_callback_work);	schedule_work(&ss->work);	return 0;}EXPORT_SYMBOL_GPL(sysfs_schedule_callback);EXPORT_SYMBOL_GPL(sysfs_create_file);EXPORT_SYMBOL_GPL(sysfs_remove_file);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -