diff options
Diffstat (limited to 'fs/sysfs/file.c')
| -rw-r--r-- | fs/sysfs/file.c | 140 | 
1 files changed, 75 insertions, 65 deletions
| diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index d019d6ac6ad0..42dcf96881b6 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -45,6 +45,9 @@ static int sysfs_kf_seq_show(struct seq_file *sf, void *v)  	ssize_t count;  	char *buf; +	if (WARN_ON_ONCE(!ops->show)) +		return -EINVAL; +  	/* acquire buffer and ensure that it's >= PAGE_SIZE and clear */  	count = seq_get_buf(sf, &buf);  	if (count < PAGE_SIZE) { @@ -53,15 +56,9 @@ static int sysfs_kf_seq_show(struct seq_file *sf, void *v)  	}  	memset(buf, 0, PAGE_SIZE); -	/* -	 * Invoke show().  Control may reach here via seq file lseek even -	 * if @ops->show() isn't implemented. -	 */ -	if (ops->show) { -		count = ops->show(kobj, of->kn->priv, buf); -		if (count < 0) -			return count; -	} +	count = ops->show(kobj, of->kn->priv, buf); +	if (count < 0) +		return count;  	/*  	 * The code works fine with PAGE_SIZE return but it's likely to @@ -255,59 +252,74 @@ static const struct kernfs_ops sysfs_bin_kfops_mmap = {  };  int sysfs_add_file_mode_ns(struct kernfs_node *parent, -			   const struct attribute *attr, bool is_bin, -			   umode_t mode, kuid_t uid, kgid_t gid, const void *ns) +		const struct attribute *attr, umode_t mode, kuid_t uid, +		kgid_t gid, const void *ns)  { +	struct kobject *kobj = parent->priv; +	const struct sysfs_ops *sysfs_ops = kobj->ktype->sysfs_ops;  	struct lock_class_key *key = NULL; -	const struct kernfs_ops *ops; +	const struct kernfs_ops *ops = NULL;  	struct kernfs_node *kn; -	loff_t size; - -	if (!is_bin) { -		struct kobject *kobj = parent->priv; -		const struct sysfs_ops *sysfs_ops = kobj->ktype->sysfs_ops; - -		/* every kobject with an attribute needs a ktype assigned */ -		if (WARN(!sysfs_ops, KERN_ERR -			 "missing sysfs attribute operations for kobject: %s\n", -			 kobject_name(kobj))) -			return -EINVAL; - -		if (sysfs_ops->show && sysfs_ops->store) { -			if (mode & SYSFS_PREALLOC) -				ops = &sysfs_prealloc_kfops_rw; -			else -				ops = &sysfs_file_kfops_rw; -		} else if (sysfs_ops->show) { -			if (mode & SYSFS_PREALLOC) -				ops = &sysfs_prealloc_kfops_ro; -			else -				ops = &sysfs_file_kfops_ro; -		} else if (sysfs_ops->store) { -			if (mode & SYSFS_PREALLOC) -				ops = &sysfs_prealloc_kfops_wo; -			else -				ops = &sysfs_file_kfops_wo; -		} else -			ops = &sysfs_file_kfops_empty; - -		size = PAGE_SIZE; + +	/* every kobject with an attribute needs a ktype assigned */ +	if (WARN(!sysfs_ops, KERN_ERR +			"missing sysfs attribute operations for kobject: %s\n", +			kobject_name(kobj))) +		return -EINVAL; + +	if (mode & SYSFS_PREALLOC) { +		if (sysfs_ops->show && sysfs_ops->store) +			ops = &sysfs_prealloc_kfops_rw; +		else if (sysfs_ops->show) +			ops = &sysfs_prealloc_kfops_ro; +		else if (sysfs_ops->store) +			ops = &sysfs_prealloc_kfops_wo;  	} else { -		struct bin_attribute *battr = (void *)attr; - -		if (battr->mmap) -			ops = &sysfs_bin_kfops_mmap; -		else if (battr->read && battr->write) -			ops = &sysfs_bin_kfops_rw; -		else if (battr->read) -			ops = &sysfs_bin_kfops_ro; -		else if (battr->write) -			ops = &sysfs_bin_kfops_wo; -		else -			ops = &sysfs_file_kfops_empty; - -		size = battr->size; +		if (sysfs_ops->show && sysfs_ops->store) +			ops = &sysfs_file_kfops_rw; +		else if (sysfs_ops->show) +			ops = &sysfs_file_kfops_ro; +		else if (sysfs_ops->store) +			ops = &sysfs_file_kfops_wo; +	} + +	if (!ops) +		ops = &sysfs_file_kfops_empty; + +#ifdef CONFIG_DEBUG_LOCK_ALLOC +	if (!attr->ignore_lockdep) +		key = attr->key ?: (struct lock_class_key *)&attr->skey; +#endif + +	kn = __kernfs_create_file(parent, attr->name, mode & 0777, uid, gid, +				  PAGE_SIZE, ops, (void *)attr, ns, key); +	if (IS_ERR(kn)) { +		if (PTR_ERR(kn) == -EEXIST) +			sysfs_warn_dup(parent, attr->name); +		return PTR_ERR(kn);  	} +	return 0; +} + +int sysfs_add_bin_file_mode_ns(struct kernfs_node *parent, +		const struct bin_attribute *battr, umode_t mode, +		kuid_t uid, kgid_t gid, const void *ns) +{ +	const struct attribute *attr = &battr->attr; +	struct lock_class_key *key = NULL; +	const struct kernfs_ops *ops; +	struct kernfs_node *kn; + +	if (battr->mmap) +		ops = &sysfs_bin_kfops_mmap; +	else if (battr->read && battr->write) +		ops = &sysfs_bin_kfops_rw; +	else if (battr->read) +		ops = &sysfs_bin_kfops_ro; +	else if (battr->write) +		ops = &sysfs_bin_kfops_wo; +	else +		ops = &sysfs_file_kfops_empty;  #ifdef CONFIG_DEBUG_LOCK_ALLOC  	if (!attr->ignore_lockdep) @@ -315,7 +327,7 @@ int sysfs_add_file_mode_ns(struct kernfs_node *parent,  #endif  	kn = __kernfs_create_file(parent, attr->name, mode & 0777, uid, gid, -				  size, ops, (void *)attr, ns, key); +				  battr->size, ops, (void *)attr, ns, key);  	if (IS_ERR(kn)) {  		if (PTR_ERR(kn) == -EEXIST)  			sysfs_warn_dup(parent, attr->name); @@ -340,9 +352,7 @@ int sysfs_create_file_ns(struct kobject *kobj, const struct attribute *attr,  		return -EINVAL;  	kobject_get_ownership(kobj, &uid, &gid); -	return sysfs_add_file_mode_ns(kobj->sd, attr, false, attr->mode, -				      uid, gid, ns); - +	return sysfs_add_file_mode_ns(kobj->sd, attr, attr->mode, uid, gid, ns);  }  EXPORT_SYMBOL_GPL(sysfs_create_file_ns); @@ -385,8 +395,8 @@ int sysfs_add_file_to_group(struct kobject *kobj,  		return -ENOENT;  	kobject_get_ownership(kobj, &uid, &gid); -	error = sysfs_add_file_mode_ns(parent, attr, false, -				       attr->mode, uid, gid, NULL); +	error = sysfs_add_file_mode_ns(parent, attr, attr->mode, uid, gid, +				       NULL);  	kernfs_put(parent);  	return error; @@ -555,8 +565,8 @@ int sysfs_create_bin_file(struct kobject *kobj,  		return -EINVAL;  	kobject_get_ownership(kobj, &uid, &gid); -	return sysfs_add_file_mode_ns(kobj->sd, &attr->attr, true, -				      attr->attr.mode, uid, gid, NULL); +	return sysfs_add_bin_file_mode_ns(kobj->sd, attr, attr->attr.mode, uid, +					   gid, NULL);  }  EXPORT_SYMBOL_GPL(sysfs_create_bin_file); |