xref: /openbmc/linux/fs/sysfs/file.c (revision c845428b7a9157523103100806bc8130d64769c8)
1619daeeeSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
36d66f5cdSTejun Heo  * fs/sysfs/file.c - sysfs regular (text) file implementation
46d66f5cdSTejun Heo  *
56d66f5cdSTejun Heo  * Copyright (c) 2001-3 Patrick Mochel
66d66f5cdSTejun Heo  * Copyright (c) 2007 SUSE Linux Products GmbH
76d66f5cdSTejun Heo  * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
86d66f5cdSTejun Heo  *
90c1bc6b8SMauro Carvalho Chehab  * Please see Documentation/filesystems/sysfs.rst for more information.
101da177e4SLinus Torvalds  */
111da177e4SLinus Torvalds 
121da177e4SLinus Torvalds #include <linux/module.h>
131da177e4SLinus Torvalds #include <linux/kobject.h>
14c6f87733SRobert P. J. Day #include <linux/slab.h>
1594bebf4dSOliver Neukum #include <linux/list.h>
1652e8c209SDave Young #include <linux/mutex.h>
1713c589d5STejun Heo #include <linux/seq_file.h>
182efc459dSJoe Perches #include <linux/mm.h>
191da177e4SLinus Torvalds 
201da177e4SLinus Torvalds #include "sysfs.h"
21f6acf8bbSTejun Heo 
22f6acf8bbSTejun Heo /*
23324a56e1STejun Heo  * Determine ktype->sysfs_ops for the given kernfs_node.  This function
24375b611eSTejun Heo  * must be called while holding an active reference.
25375b611eSTejun Heo  */
sysfs_file_ops(struct kernfs_node * kn)26324a56e1STejun Heo static const struct sysfs_ops *sysfs_file_ops(struct kernfs_node *kn)
27375b611eSTejun Heo {
28adc5e8b5STejun Heo 	struct kobject *kobj = kn->parent->priv;
29375b611eSTejun Heo 
30df23fc39STejun Heo 	if (kn->flags & KERNFS_LOCKDEP)
31324a56e1STejun Heo 		lockdep_assert_held(kn);
32375b611eSTejun Heo 	return kobj->ktype ? kobj->ktype->sysfs_ops : NULL;
33375b611eSTejun Heo }
34375b611eSTejun Heo 
3513c589d5STejun Heo /*
3613c589d5STejun Heo  * Reads on sysfs are handled through seq_file, which takes care of hairy
3713c589d5STejun Heo  * details like buffering and seeking.  The following function pipes
3813c589d5STejun Heo  * sysfs_ops->show() result through seq_file.
391da177e4SLinus Torvalds  */
sysfs_kf_seq_show(struct seq_file * sf,void * v)40c2b19dafSTejun Heo static int sysfs_kf_seq_show(struct seq_file *sf, void *v)
411da177e4SLinus Torvalds {
42c525aaddSTejun Heo 	struct kernfs_open_file *of = sf->private;
43adc5e8b5STejun Heo 	struct kobject *kobj = of->kn->parent->priv;
44324a56e1STejun Heo 	const struct sysfs_ops *ops = sysfs_file_ops(of->kn);
451da177e4SLinus Torvalds 	ssize_t count;
46c2b19dafSTejun Heo 	char *buf;
471da177e4SLinus Torvalds 
48820879eeSChristoph Hellwig 	if (WARN_ON_ONCE(!ops->show))
49820879eeSChristoph Hellwig 		return -EINVAL;
50820879eeSChristoph Hellwig 
51f5c16f29STejun Heo 	/* acquire buffer and ensure that it's >= PAGE_SIZE and clear */
5213c589d5STejun Heo 	count = seq_get_buf(sf, &buf);
5313c589d5STejun Heo 	if (count < PAGE_SIZE) {
5413c589d5STejun Heo 		seq_commit(sf, -1);
5513c589d5STejun Heo 		return 0;
5613c589d5STejun Heo 	}
57f5c16f29STejun Heo 	memset(buf, 0, PAGE_SIZE);
581da177e4SLinus Torvalds 
59324a56e1STejun Heo 	count = ops->show(kobj, of->kn->priv, buf);
6013c589d5STejun Heo 	if (count < 0)
6113c589d5STejun Heo 		return count;
620ab66088STejun Heo 
638118a859SMiao Xie 	/*
648118a859SMiao Xie 	 * The code works fine with PAGE_SIZE return but it's likely to
658118a859SMiao Xie 	 * indicate truncated result or overflow in normal use cases.
668118a859SMiao Xie 	 */
67815d2d50SAndrew Morton 	if (count >= (ssize_t)PAGE_SIZE) {
689e6d35ffSSergey Senozhatsky 		printk("fill_read_buffer: %pS returned bad count\n",
699e6d35ffSSergey Senozhatsky 				ops->show);
70815d2d50SAndrew Morton 		/* Try to struggle along */
71815d2d50SAndrew Morton 		count = PAGE_SIZE - 1;
72815d2d50SAndrew Morton 	}
7313c589d5STejun Heo 	seq_commit(sf, count);
7413c589d5STejun Heo 	return 0;
751da177e4SLinus Torvalds }
761da177e4SLinus Torvalds 
sysfs_kf_bin_read(struct kernfs_open_file * of,char * buf,size_t count,loff_t pos)77c525aaddSTejun Heo static ssize_t sysfs_kf_bin_read(struct kernfs_open_file *of, char *buf,
78c2b19dafSTejun Heo 				 size_t count, loff_t pos)
792f0c6b75STejun Heo {
80324a56e1STejun Heo 	struct bin_attribute *battr = of->kn->priv;
81adc5e8b5STejun Heo 	struct kobject *kobj = of->kn->parent->priv;
82c2b19dafSTejun Heo 	loff_t size = file_inode(of->file)->i_size;
832f0c6b75STejun Heo 
84c2b19dafSTejun Heo 	if (!count)
852f0c6b75STejun Heo 		return 0;
862f0c6b75STejun Heo 
872f0c6b75STejun Heo 	if (size) {
88eaa5cd92SVladimir Zapolskiy 		if (pos >= size)
892f0c6b75STejun Heo 			return 0;
90c2b19dafSTejun Heo 		if (pos + count > size)
91c2b19dafSTejun Heo 			count = size - pos;
922f0c6b75STejun Heo 	}
932f0c6b75STejun Heo 
94c2b19dafSTejun Heo 	if (!battr->read)
95c2b19dafSTejun Heo 		return -EIO;
96c2b19dafSTejun Heo 
97c2b19dafSTejun Heo 	return battr->read(of->file, kobj, battr, buf, pos, count);
98c2b19dafSTejun Heo }
99c2b19dafSTejun Heo 
1004ef67a8cSNeilBrown /* kernfs read callback for regular sysfs files with pre-alloc */
sysfs_kf_read(struct kernfs_open_file * of,char * buf,size_t count,loff_t pos)1014ef67a8cSNeilBrown static ssize_t sysfs_kf_read(struct kernfs_open_file *of, char *buf,
1024ef67a8cSNeilBrown 			     size_t count, loff_t pos)
1034ef67a8cSNeilBrown {
1044ef67a8cSNeilBrown 	const struct sysfs_ops *ops = sysfs_file_ops(of->kn);
1054ef67a8cSNeilBrown 	struct kobject *kobj = of->kn->parent->priv;
106c8a139d0SNeilBrown 	ssize_t len;
1074ef67a8cSNeilBrown 
1084ef67a8cSNeilBrown 	/*
1094ef67a8cSNeilBrown 	 * If buf != of->prealloc_buf, we don't know how
1104ef67a8cSNeilBrown 	 * large it is, so cannot safely pass it to ->show
1114ef67a8cSNeilBrown 	 */
11217d0774fSKonstantin Khlebnikov 	if (WARN_ON_ONCE(buf != of->prealloc_buf))
1134ef67a8cSNeilBrown 		return 0;
11465da3484SNeilBrown 	len = ops->show(kobj, of->kn->priv, buf);
115c8a139d0SNeilBrown 	if (len < 0)
116c8a139d0SNeilBrown 		return len;
11717d0774fSKonstantin Khlebnikov 	if (pos) {
11817d0774fSKonstantin Khlebnikov 		if (len <= pos)
11917d0774fSKonstantin Khlebnikov 			return 0;
12017d0774fSKonstantin Khlebnikov 		len -= pos;
12117d0774fSKonstantin Khlebnikov 		memmove(buf, buf + pos, len);
12217d0774fSKonstantin Khlebnikov 	}
123c8a139d0SNeilBrown 	return min_t(ssize_t, count, len);
1244ef67a8cSNeilBrown }
1254ef67a8cSNeilBrown 
12650b38ca0STejun Heo /* kernfs write callback for regular sysfs files */
sysfs_kf_write(struct kernfs_open_file * of,char * buf,size_t count,loff_t pos)127c525aaddSTejun Heo static ssize_t sysfs_kf_write(struct kernfs_open_file *of, char *buf,
12850b38ca0STejun Heo 			      size_t count, loff_t pos)
1291da177e4SLinus Torvalds {
130324a56e1STejun Heo 	const struct sysfs_ops *ops = sysfs_file_ops(of->kn);
131adc5e8b5STejun Heo 	struct kobject *kobj = of->kn->parent->priv;
132f9b9a621STejun Heo 
13350b38ca0STejun Heo 	if (!count)
13450b38ca0STejun Heo 		return 0;
13550b38ca0STejun Heo 
136324a56e1STejun Heo 	return ops->store(kobj, of->kn->priv, buf, count);
137f9b9a621STejun Heo }
1380ab66088STejun Heo 
13950b38ca0STejun Heo /* kernfs write callback for bin sysfs files */
sysfs_kf_bin_write(struct kernfs_open_file * of,char * buf,size_t count,loff_t pos)140c525aaddSTejun Heo static ssize_t sysfs_kf_bin_write(struct kernfs_open_file *of, char *buf,
14150b38ca0STejun Heo 				  size_t count, loff_t pos)
14250b38ca0STejun Heo {
143324a56e1STejun Heo 	struct bin_attribute *battr = of->kn->priv;
144adc5e8b5STejun Heo 	struct kobject *kobj = of->kn->parent->priv;
14550b38ca0STejun Heo 	loff_t size = file_inode(of->file)->i_size;
1460ab66088STejun Heo 
14750b38ca0STejun Heo 	if (size) {
14850b38ca0STejun Heo 		if (size <= pos)
14909368960SVladimir Zapolskiy 			return -EFBIG;
15050b38ca0STejun Heo 		count = min_t(ssize_t, count, size - pos);
15150b38ca0STejun Heo 	}
15250b38ca0STejun Heo 	if (!count)
15350b38ca0STejun Heo 		return 0;
15450b38ca0STejun Heo 
15550b38ca0STejun Heo 	if (!battr->write)
15650b38ca0STejun Heo 		return -EIO;
15750b38ca0STejun Heo 
15850b38ca0STejun Heo 	return battr->write(of->file, kobj, battr, buf, pos, count);
1591da177e4SLinus Torvalds }
1601da177e4SLinus Torvalds 
sysfs_kf_bin_mmap(struct kernfs_open_file * of,struct vm_area_struct * vma)161c525aaddSTejun Heo static int sysfs_kf_bin_mmap(struct kernfs_open_file *of,
162fdbffaa4STejun Heo 			     struct vm_area_struct *vma)
163fdbffaa4STejun Heo {
164324a56e1STejun Heo 	struct bin_attribute *battr = of->kn->priv;
165adc5e8b5STejun Heo 	struct kobject *kobj = of->kn->parent->priv;
166fdbffaa4STejun Heo 
167fdbffaa4STejun Heo 	return battr->mmap(of->file, kobj, battr, vma);
168fdbffaa4STejun Heo }
169fdbffaa4STejun Heo 
sysfs_kf_bin_open(struct kernfs_open_file * of)17074b30195SDaniel Vetter static int sysfs_kf_bin_open(struct kernfs_open_file *of)
17174b30195SDaniel Vetter {
17274b30195SDaniel Vetter 	struct bin_attribute *battr = of->kn->priv;
17374b30195SDaniel Vetter 
174f06aff92SKrzysztof Wilczyński 	if (battr->f_mapping)
175f06aff92SKrzysztof Wilczyński 		of->file->f_mapping = battr->f_mapping();
17674b30195SDaniel Vetter 
17774b30195SDaniel Vetter 	return 0;
17874b30195SDaniel Vetter }
17974b30195SDaniel Vetter 
sysfs_notify(struct kobject * kobj,const char * dir,const char * attr)180324a56e1STejun Heo void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr)
181f1282c84SNeil Brown {
182324a56e1STejun Heo 	struct kernfs_node *kn = kobj->sd, *tmp;
183f1282c84SNeil Brown 
184324a56e1STejun Heo 	if (kn && dir)
185324a56e1STejun Heo 		kn = kernfs_find_and_get(kn, dir);
186024f6471STejun Heo 	else
187324a56e1STejun Heo 		kernfs_get(kn);
18851225039STejun Heo 
189324a56e1STejun Heo 	if (kn && attr) {
190324a56e1STejun Heo 		tmp = kernfs_find_and_get(kn, attr);
191324a56e1STejun Heo 		kernfs_put(kn);
192324a56e1STejun Heo 		kn = tmp;
193024f6471STejun Heo 	}
194024f6471STejun Heo 
195324a56e1STejun Heo 	if (kn) {
196324a56e1STejun Heo 		kernfs_notify(kn);
197324a56e1STejun Heo 		kernfs_put(kn);
198024f6471STejun Heo 	}
1994508a7a7SNeilBrown }
2004508a7a7SNeilBrown EXPORT_SYMBOL_GPL(sysfs_notify);
2014508a7a7SNeilBrown 
202f6acf8bbSTejun Heo static const struct kernfs_ops sysfs_file_kfops_empty = {
203f6acf8bbSTejun Heo };
204f6acf8bbSTejun Heo 
205f6acf8bbSTejun Heo static const struct kernfs_ops sysfs_file_kfops_ro = {
206f6acf8bbSTejun Heo 	.seq_show	= sysfs_kf_seq_show,
207f6acf8bbSTejun Heo };
208f6acf8bbSTejun Heo 
209f6acf8bbSTejun Heo static const struct kernfs_ops sysfs_file_kfops_wo = {
210f6acf8bbSTejun Heo 	.write		= sysfs_kf_write,
211f6acf8bbSTejun Heo };
212f6acf8bbSTejun Heo 
213f6acf8bbSTejun Heo static const struct kernfs_ops sysfs_file_kfops_rw = {
214f6acf8bbSTejun Heo 	.seq_show	= sysfs_kf_seq_show,
215f6acf8bbSTejun Heo 	.write		= sysfs_kf_write,
216f6acf8bbSTejun Heo };
217f6acf8bbSTejun Heo 
2184ef67a8cSNeilBrown static const struct kernfs_ops sysfs_prealloc_kfops_ro = {
2194ef67a8cSNeilBrown 	.read		= sysfs_kf_read,
2204ef67a8cSNeilBrown 	.prealloc	= true,
2214ef67a8cSNeilBrown };
2224ef67a8cSNeilBrown 
2232b75869bSNeilBrown static const struct kernfs_ops sysfs_prealloc_kfops_wo = {
2242b75869bSNeilBrown 	.write		= sysfs_kf_write,
2252b75869bSNeilBrown 	.prealloc	= true,
2262b75869bSNeilBrown };
2272b75869bSNeilBrown 
2282b75869bSNeilBrown static const struct kernfs_ops sysfs_prealloc_kfops_rw = {
2294ef67a8cSNeilBrown 	.read		= sysfs_kf_read,
2302b75869bSNeilBrown 	.write		= sysfs_kf_write,
2312b75869bSNeilBrown 	.prealloc	= true,
2322b75869bSNeilBrown };
2332b75869bSNeilBrown 
234f6acf8bbSTejun Heo static const struct kernfs_ops sysfs_bin_kfops_ro = {
235f6acf8bbSTejun Heo 	.read		= sysfs_kf_bin_read,
236f6acf8bbSTejun Heo };
237f6acf8bbSTejun Heo 
238f6acf8bbSTejun Heo static const struct kernfs_ops sysfs_bin_kfops_wo = {
239f6acf8bbSTejun Heo 	.write		= sysfs_kf_bin_write,
240f6acf8bbSTejun Heo };
241f6acf8bbSTejun Heo 
242f6acf8bbSTejun Heo static const struct kernfs_ops sysfs_bin_kfops_rw = {
243f6acf8bbSTejun Heo 	.read		= sysfs_kf_bin_read,
244f6acf8bbSTejun Heo 	.write		= sysfs_kf_bin_write,
2459b2db6e1STejun Heo };
2469b2db6e1STejun Heo 
2479b2db6e1STejun Heo static const struct kernfs_ops sysfs_bin_kfops_mmap = {
2489b2db6e1STejun Heo 	.read		= sysfs_kf_bin_read,
2499b2db6e1STejun Heo 	.write		= sysfs_kf_bin_write,
250f6acf8bbSTejun Heo 	.mmap		= sysfs_kf_bin_mmap,
25174b30195SDaniel Vetter 	.open		= sysfs_kf_bin_open,
252f6acf8bbSTejun Heo };
253f6acf8bbSTejun Heo 
sysfs_add_file_mode_ns(struct kernfs_node * parent,const struct attribute * attr,umode_t mode,kuid_t uid,kgid_t gid,const void * ns)254324a56e1STejun Heo int sysfs_add_file_mode_ns(struct kernfs_node *parent,
2555cf3bb0dSChristoph Hellwig 		const struct attribute *attr, umode_t mode, kuid_t uid,
2565cf3bb0dSChristoph Hellwig 		kgid_t gid, const void *ns)
2571da177e4SLinus Torvalds {
2585cf3bb0dSChristoph Hellwig 	struct kobject *kobj = parent->priv;
2595cf3bb0dSChristoph Hellwig 	const struct sysfs_ops *sysfs_ops = kobj->ktype->sysfs_ops;
260517e64f5STejun Heo 	struct lock_class_key *key = NULL;
261d1a1a960SChristoph Hellwig 	const struct kernfs_ops *ops = NULL;
262324a56e1STejun Heo 	struct kernfs_node *kn;
263f6acf8bbSTejun Heo 
264f6acf8bbSTejun Heo 	/* every kobject with an attribute needs a ktype assigned */
265f6acf8bbSTejun Heo 	if (WARN(!sysfs_ops, KERN_ERR
266f6acf8bbSTejun Heo 			"missing sysfs attribute operations for kobject: %s\n",
267f6acf8bbSTejun Heo 			kobject_name(kobj)))
268f6acf8bbSTejun Heo 		return -EINVAL;
269f6acf8bbSTejun Heo 
270d1a1a960SChristoph Hellwig 	if (mode & SYSFS_PREALLOC) {
271d1a1a960SChristoph Hellwig 		if (sysfs_ops->show && sysfs_ops->store)
2722b75869bSNeilBrown 			ops = &sysfs_prealloc_kfops_rw;
273d1a1a960SChristoph Hellwig 		else if (sysfs_ops->show)
2744ef67a8cSNeilBrown 			ops = &sysfs_prealloc_kfops_ro;
275d1a1a960SChristoph Hellwig 		else if (sysfs_ops->store)
2762b75869bSNeilBrown 			ops = &sysfs_prealloc_kfops_wo;
277d1a1a960SChristoph Hellwig 	} else {
278d1a1a960SChristoph Hellwig 		if (sysfs_ops->show && sysfs_ops->store)
279d1a1a960SChristoph Hellwig 			ops = &sysfs_file_kfops_rw;
280d1a1a960SChristoph Hellwig 		else if (sysfs_ops->show)
281d1a1a960SChristoph Hellwig 			ops = &sysfs_file_kfops_ro;
282d1a1a960SChristoph Hellwig 		else if (sysfs_ops->store)
2832b75869bSNeilBrown 			ops = &sysfs_file_kfops_wo;
284d1a1a960SChristoph Hellwig 	}
285d1a1a960SChristoph Hellwig 
286d1a1a960SChristoph Hellwig 	if (!ops)
287f6acf8bbSTejun Heo 		ops = &sysfs_file_kfops_empty;
288471bd7b7STejun Heo 
2895cf3bb0dSChristoph Hellwig #ifdef CONFIG_DEBUG_LOCK_ALLOC
2905cf3bb0dSChristoph Hellwig 	if (!attr->ignore_lockdep)
2915cf3bb0dSChristoph Hellwig 		key = attr->key ?: (struct lock_class_key *)&attr->skey;
2925cf3bb0dSChristoph Hellwig #endif
2935cf3bb0dSChristoph Hellwig 
2945cf3bb0dSChristoph Hellwig 	kn = __kernfs_create_file(parent, attr->name, mode & 0777, uid, gid,
2955cf3bb0dSChristoph Hellwig 				  PAGE_SIZE, ops, (void *)attr, ns, key);
2965cf3bb0dSChristoph Hellwig 	if (IS_ERR(kn)) {
2975cf3bb0dSChristoph Hellwig 		if (PTR_ERR(kn) == -EEXIST)
2985cf3bb0dSChristoph Hellwig 			sysfs_warn_dup(parent, attr->name);
2995cf3bb0dSChristoph Hellwig 		return PTR_ERR(kn);
3005cf3bb0dSChristoph Hellwig 	}
3015cf3bb0dSChristoph Hellwig 	return 0;
3025cf3bb0dSChristoph Hellwig }
3035cf3bb0dSChristoph Hellwig 
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)3045cf3bb0dSChristoph Hellwig int sysfs_add_bin_file_mode_ns(struct kernfs_node *parent,
3055cf3bb0dSChristoph Hellwig 		const struct bin_attribute *battr, umode_t mode,
3065cf3bb0dSChristoph Hellwig 		kuid_t uid, kgid_t gid, const void *ns)
3075cf3bb0dSChristoph Hellwig {
3085cf3bb0dSChristoph Hellwig 	const struct attribute *attr = &battr->attr;
3095cf3bb0dSChristoph Hellwig 	struct lock_class_key *key = NULL;
3105cf3bb0dSChristoph Hellwig 	const struct kernfs_ops *ops;
3115cf3bb0dSChristoph Hellwig 	struct kernfs_node *kn;
312f6acf8bbSTejun Heo 
3139b2db6e1STejun Heo 	if (battr->mmap)
3149b2db6e1STejun Heo 		ops = &sysfs_bin_kfops_mmap;
3159b2db6e1STejun Heo 	else if (battr->read && battr->write)
316f6acf8bbSTejun Heo 		ops = &sysfs_bin_kfops_rw;
317f6acf8bbSTejun Heo 	else if (battr->read)
318f6acf8bbSTejun Heo 		ops = &sysfs_bin_kfops_ro;
319f6acf8bbSTejun Heo 	else if (battr->write)
320f6acf8bbSTejun Heo 		ops = &sysfs_bin_kfops_wo;
321f6acf8bbSTejun Heo 	else
322f6acf8bbSTejun Heo 		ops = &sysfs_file_kfops_empty;
323471bd7b7STejun Heo 
324517e64f5STejun Heo #ifdef CONFIG_DEBUG_LOCK_ALLOC
325517e64f5STejun Heo 	if (!attr->ignore_lockdep)
326517e64f5STejun Heo 		key = attr->key ?: (struct lock_class_key *)&attr->skey;
327517e64f5STejun Heo #endif
3285f81880dSDmitry Torokhov 
3295f81880dSDmitry Torokhov 	kn = __kernfs_create_file(parent, attr->name, mode & 0777, uid, gid,
3305cf3bb0dSChristoph Hellwig 				  battr->size, ops, (void *)attr, ns, key);
331324a56e1STejun Heo 	if (IS_ERR(kn)) {
332324a56e1STejun Heo 		if (PTR_ERR(kn) == -EEXIST)
333324a56e1STejun Heo 			sysfs_warn_dup(parent, attr->name);
334324a56e1STejun Heo 		return PTR_ERR(kn);
335496f7394STejun Heo 	}
336496f7394STejun Heo 	return 0;
337496f7394STejun Heo }
338496f7394STejun Heo 
3391da177e4SLinus Torvalds /**
34058292cbeSTejun Heo  * sysfs_create_file_ns - create an attribute file for an object with custom ns
34158292cbeSTejun Heo  * @kobj: object we're creating for
34258292cbeSTejun Heo  * @attr: attribute descriptor
34358292cbeSTejun Heo  * @ns: namespace the new file should belong to
3441da177e4SLinus Torvalds  */
sysfs_create_file_ns(struct kobject * kobj,const struct attribute * attr,const void * ns)34558292cbeSTejun Heo int sysfs_create_file_ns(struct kobject *kobj, const struct attribute *attr,
34658292cbeSTejun Heo 			 const void *ns)
3471da177e4SLinus Torvalds {
3485f81880dSDmitry Torokhov 	kuid_t uid;
3495f81880dSDmitry Torokhov 	kgid_t gid;
3505f81880dSDmitry Torokhov 
351de96e9feSGreg Kroah-Hartman 	if (WARN_ON(!kobj || !kobj->sd || !attr))
352de96e9feSGreg Kroah-Hartman 		return -EINVAL;
3531da177e4SLinus Torvalds 
3545f81880dSDmitry Torokhov 	kobject_get_ownership(kobj, &uid, &gid);
3555cf3bb0dSChristoph Hellwig 	return sysfs_add_file_mode_ns(kobj->sd, attr, attr->mode, uid, gid, ns);
3561da177e4SLinus Torvalds }
35758292cbeSTejun Heo EXPORT_SYMBOL_GPL(sysfs_create_file_ns);
3581da177e4SLinus Torvalds 
sysfs_create_files(struct kobject * kobj,const struct attribute * const * ptr)3599ee4685cSJani Nikula int sysfs_create_files(struct kobject *kobj, const struct attribute * const *ptr)
3601c205ae1SAndi Kleen {
3611c205ae1SAndi Kleen 	int err = 0;
3621c205ae1SAndi Kleen 	int i;
3631c205ae1SAndi Kleen 
3641c205ae1SAndi Kleen 	for (i = 0; ptr[i] && !err; i++)
3651c205ae1SAndi Kleen 		err = sysfs_create_file(kobj, ptr[i]);
3661c205ae1SAndi Kleen 	if (err)
3671c205ae1SAndi Kleen 		while (--i >= 0)
3681c205ae1SAndi Kleen 			sysfs_remove_file(kobj, ptr[i]);
3691c205ae1SAndi Kleen 	return err;
3701c205ae1SAndi Kleen }
3711b866757SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(sysfs_create_files);
3721da177e4SLinus Torvalds 
3731da177e4SLinus Torvalds /**
374dfa87c82SAlan Stern  * sysfs_add_file_to_group - add an attribute file to a pre-existing group.
375dfa87c82SAlan Stern  * @kobj: object we're acting for.
376dfa87c82SAlan Stern  * @attr: attribute descriptor.
377dfa87c82SAlan Stern  * @group: group name.
378dfa87c82SAlan Stern  */
sysfs_add_file_to_group(struct kobject * kobj,const struct attribute * attr,const char * group)379dfa87c82SAlan Stern int sysfs_add_file_to_group(struct kobject *kobj,
380dfa87c82SAlan Stern 		const struct attribute *attr, const char *group)
381dfa87c82SAlan Stern {
382324a56e1STejun Heo 	struct kernfs_node *parent;
3835f81880dSDmitry Torokhov 	kuid_t uid;
3845f81880dSDmitry Torokhov 	kgid_t gid;
385dfa87c82SAlan Stern 	int error;
386dfa87c82SAlan Stern 
387ccf73cf3STejun Heo 	if (group) {
388324a56e1STejun Heo 		parent = kernfs_find_and_get(kobj->sd, group);
389ccf73cf3STejun Heo 	} else {
390324a56e1STejun Heo 		parent = kobj->sd;
391324a56e1STejun Heo 		kernfs_get(parent);
392ccf73cf3STejun Heo 	}
39311f24fbdSJames Bottomley 
394324a56e1STejun Heo 	if (!parent)
395608e266aSTejun Heo 		return -ENOENT;
396608e266aSTejun Heo 
3975f81880dSDmitry Torokhov 	kobject_get_ownership(kobj, &uid, &gid);
3985cf3bb0dSChristoph Hellwig 	error = sysfs_add_file_mode_ns(parent, attr, attr->mode, uid, gid,
3995cf3bb0dSChristoph Hellwig 				       NULL);
400324a56e1STejun Heo 	kernfs_put(parent);
401608e266aSTejun Heo 
402dfa87c82SAlan Stern 	return error;
403dfa87c82SAlan Stern }
404dfa87c82SAlan Stern EXPORT_SYMBOL_GPL(sysfs_add_file_to_group);
405dfa87c82SAlan Stern 
4061da177e4SLinus Torvalds /**
40731e5abe9SKay Sievers  * sysfs_chmod_file - update the modified mode value on an object attribute.
40831e5abe9SKay Sievers  * @kobj: object we're acting for.
40931e5abe9SKay Sievers  * @attr: attribute descriptor.
41031e5abe9SKay Sievers  * @mode: file permissions.
41131e5abe9SKay Sievers  *
41231e5abe9SKay Sievers  */
sysfs_chmod_file(struct kobject * kobj,const struct attribute * attr,umode_t mode)41349c19400SJean Delvare int sysfs_chmod_file(struct kobject *kobj, const struct attribute *attr,
41448176a97SAl Viro 		     umode_t mode)
41531e5abe9SKay Sievers {
416324a56e1STejun Heo 	struct kernfs_node *kn;
417bc062b1bSManeesh Soni 	struct iattr newattrs;
41851225039STejun Heo 	int rc;
41931e5abe9SKay Sievers 
420324a56e1STejun Heo 	kn = kernfs_find_and_get(kobj->sd, attr->name);
421324a56e1STejun Heo 	if (!kn)
4225d60418eSTejun Heo 		return -ENOENT;
42351225039STejun Heo 
424adc5e8b5STejun Heo 	newattrs.ia_mode = (mode & S_IALLUGO) | (kn->mode & ~S_IALLUGO);
4254c6974f5SEric W. Biederman 	newattrs.ia_valid = ATTR_MODE;
426f88123eaSTejun Heo 
427324a56e1STejun Heo 	rc = kernfs_setattr(kn, &newattrs);
4285d60418eSTejun Heo 
429324a56e1STejun Heo 	kernfs_put(kn);
43051225039STejun Heo 	return rc;
43131e5abe9SKay Sievers }
43231e5abe9SKay Sievers EXPORT_SYMBOL_GPL(sysfs_chmod_file);
43331e5abe9SKay Sievers 
43431e5abe9SKay Sievers /**
4352afc9166SBart Van Assche  * sysfs_break_active_protection - break "active" protection
4362afc9166SBart Van Assche  * @kobj: The kernel object @attr is associated with.
4372afc9166SBart Van Assche  * @attr: The attribute to break the "active" protection for.
4382afc9166SBart Van Assche  *
4392afc9166SBart Van Assche  * With sysfs, just like kernfs, deletion of an attribute is postponed until
4402afc9166SBart Van Assche  * all active .show() and .store() callbacks have finished unless this function
4412afc9166SBart Van Assche  * is called. Hence this function is useful in methods that implement self
4422afc9166SBart Van Assche  * deletion.
4432afc9166SBart Van Assche  */
sysfs_break_active_protection(struct kobject * kobj,const struct attribute * attr)4442afc9166SBart Van Assche struct kernfs_node *sysfs_break_active_protection(struct kobject *kobj,
4452afc9166SBart Van Assche 						  const struct attribute *attr)
4462afc9166SBart Van Assche {
4472afc9166SBart Van Assche 	struct kernfs_node *kn;
4482afc9166SBart Van Assche 
4492afc9166SBart Van Assche 	kobject_get(kobj);
4502afc9166SBart Van Assche 	kn = kernfs_find_and_get(kobj->sd, attr->name);
4512afc9166SBart Van Assche 	if (kn)
4522afc9166SBart Van Assche 		kernfs_break_active_protection(kn);
453*ac107356SAlan Stern 	else
454*ac107356SAlan Stern 		kobject_put(kobj);
4552afc9166SBart Van Assche 	return kn;
4562afc9166SBart Van Assche }
4572afc9166SBart Van Assche EXPORT_SYMBOL_GPL(sysfs_break_active_protection);
4582afc9166SBart Van Assche 
4592afc9166SBart Van Assche /**
4602afc9166SBart Van Assche  * sysfs_unbreak_active_protection - restore "active" protection
4612afc9166SBart Van Assche  * @kn: Pointer returned by sysfs_break_active_protection().
4622afc9166SBart Van Assche  *
4632afc9166SBart Van Assche  * Undo the effects of sysfs_break_active_protection(). Since this function
4642afc9166SBart Van Assche  * calls kernfs_put() on the kernfs node that corresponds to the 'attr'
4652afc9166SBart Van Assche  * argument passed to sysfs_break_active_protection() that attribute may have
4662afc9166SBart Van Assche  * been removed between the sysfs_break_active_protection() and
4672afc9166SBart Van Assche  * sysfs_unbreak_active_protection() calls, it is not safe to access @kn after
4682afc9166SBart Van Assche  * this function has returned.
4692afc9166SBart Van Assche  */
sysfs_unbreak_active_protection(struct kernfs_node * kn)4702afc9166SBart Van Assche void sysfs_unbreak_active_protection(struct kernfs_node *kn)
4712afc9166SBart Van Assche {
4722afc9166SBart Van Assche 	struct kobject *kobj = kn->parent->priv;
4732afc9166SBart Van Assche 
4742afc9166SBart Van Assche 	kernfs_unbreak_active_protection(kn);
4752afc9166SBart Van Assche 	kernfs_put(kn);
4762afc9166SBart Van Assche 	kobject_put(kobj);
4772afc9166SBart Van Assche }
4782afc9166SBart Van Assche EXPORT_SYMBOL_GPL(sysfs_unbreak_active_protection);
4792afc9166SBart Van Assche 
4802afc9166SBart Van Assche /**
48158292cbeSTejun Heo  * sysfs_remove_file_ns - remove an object attribute with a custom ns tag
48258292cbeSTejun Heo  * @kobj: object we're acting for
48358292cbeSTejun Heo  * @attr: attribute descriptor
48458292cbeSTejun Heo  * @ns: namespace tag of the file to remove
4851da177e4SLinus Torvalds  *
48658292cbeSTejun Heo  * Hash the attribute name and namespace tag and kill the victim.
4871da177e4SLinus Torvalds  */
sysfs_remove_file_ns(struct kobject * kobj,const struct attribute * attr,const void * ns)48858292cbeSTejun Heo void sysfs_remove_file_ns(struct kobject *kobj, const struct attribute *attr,
48958292cbeSTejun Heo 			  const void *ns)
4901da177e4SLinus Torvalds {
491324a56e1STejun Heo 	struct kernfs_node *parent = kobj->sd;
492487505c2SEric W. Biederman 
493324a56e1STejun Heo 	kernfs_remove_by_name_ns(parent, attr->name, ns);
4941da177e4SLinus Torvalds }
49558292cbeSTejun Heo EXPORT_SYMBOL_GPL(sysfs_remove_file_ns);
4961da177e4SLinus Torvalds 
4976b0afc2aSTejun Heo /**
4986b0afc2aSTejun Heo  * sysfs_remove_file_self - remove an object attribute from its own method
4996b0afc2aSTejun Heo  * @kobj: object we're acting for
5006b0afc2aSTejun Heo  * @attr: attribute descriptor
5016b0afc2aSTejun Heo  *
5026b0afc2aSTejun Heo  * See kernfs_remove_self() for details.
5036b0afc2aSTejun Heo  */
sysfs_remove_file_self(struct kobject * kobj,const struct attribute * attr)5046b0afc2aSTejun Heo bool sysfs_remove_file_self(struct kobject *kobj, const struct attribute *attr)
5056b0afc2aSTejun Heo {
5066b0afc2aSTejun Heo 	struct kernfs_node *parent = kobj->sd;
5076b0afc2aSTejun Heo 	struct kernfs_node *kn;
5086b0afc2aSTejun Heo 	bool ret;
5096b0afc2aSTejun Heo 
5106b0afc2aSTejun Heo 	kn = kernfs_find_and_get(parent, attr->name);
5116b0afc2aSTejun Heo 	if (WARN_ON_ONCE(!kn))
5126b0afc2aSTejun Heo 		return false;
5136b0afc2aSTejun Heo 
5146b0afc2aSTejun Heo 	ret = kernfs_remove_self(kn);
5156b0afc2aSTejun Heo 
5166b0afc2aSTejun Heo 	kernfs_put(kn);
5176b0afc2aSTejun Heo 	return ret;
5186b0afc2aSTejun Heo }
5199ddacff1SJack Wang EXPORT_SYMBOL_GPL(sysfs_remove_file_self);
5206b0afc2aSTejun Heo 
sysfs_remove_files(struct kobject * kobj,const struct attribute * const * ptr)5219ee4685cSJani Nikula void sysfs_remove_files(struct kobject *kobj, const struct attribute * const *ptr)
5221c205ae1SAndi Kleen {
5231c205ae1SAndi Kleen 	int i;
5244bd4e92cSStephen Martin 
5251c205ae1SAndi Kleen 	for (i = 0; ptr[i]; i++)
5261c205ae1SAndi Kleen 		sysfs_remove_file(kobj, ptr[i]);
5271c205ae1SAndi Kleen }
5281b866757SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(sysfs_remove_files);
5291da177e4SLinus Torvalds 
530dfa87c82SAlan Stern /**
531dfa87c82SAlan Stern  * sysfs_remove_file_from_group - remove an attribute file from a group.
532dfa87c82SAlan Stern  * @kobj: object we're acting for.
533dfa87c82SAlan Stern  * @attr: attribute descriptor.
534dfa87c82SAlan Stern  * @group: group name.
535dfa87c82SAlan Stern  */
sysfs_remove_file_from_group(struct kobject * kobj,const struct attribute * attr,const char * group)536dfa87c82SAlan Stern void sysfs_remove_file_from_group(struct kobject *kobj,
537dfa87c82SAlan Stern 		const struct attribute *attr, const char *group)
538dfa87c82SAlan Stern {
539324a56e1STejun Heo 	struct kernfs_node *parent;
540dfa87c82SAlan Stern 
541ccf73cf3STejun Heo 	if (group) {
542324a56e1STejun Heo 		parent = kernfs_find_and_get(kobj->sd, group);
543ccf73cf3STejun Heo 	} else {
544324a56e1STejun Heo 		parent = kobj->sd;
545324a56e1STejun Heo 		kernfs_get(parent);
546ccf73cf3STejun Heo 	}
547ccf73cf3STejun Heo 
548324a56e1STejun Heo 	if (parent) {
549324a56e1STejun Heo 		kernfs_remove_by_name(parent, attr->name);
550324a56e1STejun Heo 		kernfs_put(parent);
551dfa87c82SAlan Stern 	}
552dfa87c82SAlan Stern }
553dfa87c82SAlan Stern EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group);
554dfa87c82SAlan Stern 
5553124eb16STejun Heo /**
5563124eb16STejun Heo  *	sysfs_create_bin_file - create binary file for object.
5573124eb16STejun Heo  *	@kobj:	object.
5583124eb16STejun Heo  *	@attr:	attribute descriptor.
5593124eb16STejun Heo  */
sysfs_create_bin_file(struct kobject * kobj,const struct bin_attribute * attr)5603124eb16STejun Heo int sysfs_create_bin_file(struct kobject *kobj,
5613124eb16STejun Heo 			  const struct bin_attribute *attr)
5623124eb16STejun Heo {
5635f81880dSDmitry Torokhov 	kuid_t uid;
5645f81880dSDmitry Torokhov 	kgid_t gid;
5655f81880dSDmitry Torokhov 
566de96e9feSGreg Kroah-Hartman 	if (WARN_ON(!kobj || !kobj->sd || !attr))
567de96e9feSGreg Kroah-Hartman 		return -EINVAL;
5683124eb16STejun Heo 
5695f81880dSDmitry Torokhov 	kobject_get_ownership(kobj, &uid, &gid);
5705cf3bb0dSChristoph Hellwig 	return sysfs_add_bin_file_mode_ns(kobj->sd, attr, attr->attr.mode, uid,
5715cf3bb0dSChristoph Hellwig 					   gid, NULL);
5723124eb16STejun Heo }
5733124eb16STejun Heo EXPORT_SYMBOL_GPL(sysfs_create_bin_file);
5743124eb16STejun Heo 
5753124eb16STejun Heo /**
5763124eb16STejun Heo  *	sysfs_remove_bin_file - remove binary file for object.
5773124eb16STejun Heo  *	@kobj:	object.
5783124eb16STejun Heo  *	@attr:	attribute descriptor.
5793124eb16STejun Heo  */
sysfs_remove_bin_file(struct kobject * kobj,const struct bin_attribute * attr)5803124eb16STejun Heo void sysfs_remove_bin_file(struct kobject *kobj,
5813124eb16STejun Heo 			   const struct bin_attribute *attr)
5823124eb16STejun Heo {
583879f40d1STejun Heo 	kernfs_remove_by_name(kobj->sd, attr->attr.name);
5843124eb16STejun Heo }
5853124eb16STejun Heo EXPORT_SYMBOL_GPL(sysfs_remove_bin_file);
586f70ce185SChristian Brauner 
internal_change_owner(struct kernfs_node * kn,kuid_t kuid,kgid_t kgid)587f70ce185SChristian Brauner static int internal_change_owner(struct kernfs_node *kn, kuid_t kuid,
588f70ce185SChristian Brauner 				 kgid_t kgid)
589f70ce185SChristian Brauner {
590f70ce185SChristian Brauner 	struct iattr newattrs = {
591f70ce185SChristian Brauner 		.ia_valid = ATTR_UID | ATTR_GID,
592f70ce185SChristian Brauner 		.ia_uid = kuid,
593f70ce185SChristian Brauner 		.ia_gid = kgid,
594f70ce185SChristian Brauner 	};
595f70ce185SChristian Brauner 	return kernfs_setattr(kn, &newattrs);
596f70ce185SChristian Brauner }
597f70ce185SChristian Brauner 
598f70ce185SChristian Brauner /**
5990666a3aeSChristian Brauner  *	sysfs_link_change_owner - change owner of a sysfs file.
6000666a3aeSChristian Brauner  *	@kobj:	object of the kernfs_node the symlink is located in.
6010666a3aeSChristian Brauner  *	@targ:	object of the kernfs_node the symlink points to.
6020666a3aeSChristian Brauner  *	@name:	name of the link.
6030666a3aeSChristian Brauner  *	@kuid:	new owner's kuid
6040666a3aeSChristian Brauner  *	@kgid:	new owner's kgid
6050666a3aeSChristian Brauner  *
6060666a3aeSChristian Brauner  * This function looks up the sysfs symlink entry @name under @kobj and changes
6070666a3aeSChristian Brauner  * the ownership to @kuid/@kgid. The symlink is looked up in the namespace of
6080666a3aeSChristian Brauner  * @targ.
6090666a3aeSChristian Brauner  *
6100666a3aeSChristian Brauner  * Returns 0 on success or error code on failure.
6110666a3aeSChristian Brauner  */
sysfs_link_change_owner(struct kobject * kobj,struct kobject * targ,const char * name,kuid_t kuid,kgid_t kgid)6120666a3aeSChristian Brauner int sysfs_link_change_owner(struct kobject *kobj, struct kobject *targ,
6130666a3aeSChristian Brauner 			    const char *name, kuid_t kuid, kgid_t kgid)
6140666a3aeSChristian Brauner {
6150666a3aeSChristian Brauner 	struct kernfs_node *kn = NULL;
6160666a3aeSChristian Brauner 	int error;
6170666a3aeSChristian Brauner 
6180666a3aeSChristian Brauner 	if (!name || !kobj->state_in_sysfs || !targ->state_in_sysfs)
6190666a3aeSChristian Brauner 		return -EINVAL;
6200666a3aeSChristian Brauner 
6210666a3aeSChristian Brauner 	error = -ENOENT;
6220666a3aeSChristian Brauner 	kn = kernfs_find_and_get_ns(kobj->sd, name, targ->sd->ns);
6230666a3aeSChristian Brauner 	if (!kn)
6240666a3aeSChristian Brauner 		goto out;
6250666a3aeSChristian Brauner 
6260666a3aeSChristian Brauner 	error = -EINVAL;
6270666a3aeSChristian Brauner 	if (kernfs_type(kn) != KERNFS_LINK)
6280666a3aeSChristian Brauner 		goto out;
6290666a3aeSChristian Brauner 	if (kn->symlink.target_kn->priv != targ)
6300666a3aeSChristian Brauner 		goto out;
6310666a3aeSChristian Brauner 
6320666a3aeSChristian Brauner 	error = internal_change_owner(kn, kuid, kgid);
6330666a3aeSChristian Brauner 
6340666a3aeSChristian Brauner out:
6350666a3aeSChristian Brauner 	kernfs_put(kn);
6360666a3aeSChristian Brauner 	return error;
6370666a3aeSChristian Brauner }
6380666a3aeSChristian Brauner 
6390666a3aeSChristian Brauner /**
640f70ce185SChristian Brauner  *	sysfs_file_change_owner - change owner of a sysfs file.
641f70ce185SChristian Brauner  *	@kobj:	object.
642f70ce185SChristian Brauner  *	@name:	name of the file to change.
643f70ce185SChristian Brauner  *	@kuid:	new owner's kuid
644f70ce185SChristian Brauner  *	@kgid:	new owner's kgid
645f70ce185SChristian Brauner  *
646f70ce185SChristian Brauner  * This function looks up the sysfs entry @name under @kobj and changes the
647f70ce185SChristian Brauner  * ownership to @kuid/@kgid.
648f70ce185SChristian Brauner  *
649f70ce185SChristian Brauner  * Returns 0 on success or error code on failure.
650f70ce185SChristian Brauner  */
sysfs_file_change_owner(struct kobject * kobj,const char * name,kuid_t kuid,kgid_t kgid)651f70ce185SChristian Brauner int sysfs_file_change_owner(struct kobject *kobj, const char *name, kuid_t kuid,
652f70ce185SChristian Brauner 			    kgid_t kgid)
653f70ce185SChristian Brauner {
654f70ce185SChristian Brauner 	struct kernfs_node *kn;
655f70ce185SChristian Brauner 	int error;
656f70ce185SChristian Brauner 
657f70ce185SChristian Brauner 	if (!name)
658f70ce185SChristian Brauner 		return -EINVAL;
659f70ce185SChristian Brauner 
660f70ce185SChristian Brauner 	if (!kobj->state_in_sysfs)
661f70ce185SChristian Brauner 		return -EINVAL;
662f70ce185SChristian Brauner 
663f70ce185SChristian Brauner 	kn = kernfs_find_and_get(kobj->sd, name);
664f70ce185SChristian Brauner 	if (!kn)
665f70ce185SChristian Brauner 		return -ENOENT;
666f70ce185SChristian Brauner 
667f70ce185SChristian Brauner 	error = internal_change_owner(kn, kuid, kgid);
668f70ce185SChristian Brauner 
669f70ce185SChristian Brauner 	kernfs_put(kn);
670f70ce185SChristian Brauner 
671f70ce185SChristian Brauner 	return error;
672f70ce185SChristian Brauner }
673f70ce185SChristian Brauner EXPORT_SYMBOL_GPL(sysfs_file_change_owner);
6742c4f9401SChristian Brauner 
6752c4f9401SChristian Brauner /**
6762c4f9401SChristian Brauner  *	sysfs_change_owner - change owner of the given object.
6772c4f9401SChristian Brauner  *	@kobj:	object.
6782c4f9401SChristian Brauner  *	@kuid:	new owner's kuid
6792c4f9401SChristian Brauner  *	@kgid:	new owner's kgid
6802c4f9401SChristian Brauner  *
6812c4f9401SChristian Brauner  * Change the owner of the default directory, files, groups, and attributes of
6822c4f9401SChristian Brauner  * @kobj to @kuid/@kgid. Note that sysfs_change_owner mirrors how the sysfs
6832c4f9401SChristian Brauner  * entries for a kobject are added by driver core. In summary,
6842c4f9401SChristian Brauner  * sysfs_change_owner() takes care of the default directory entry for @kobj,
6852c4f9401SChristian Brauner  * the default attributes associated with the ktype of @kobj and the default
6862c4f9401SChristian Brauner  * attributes associated with the ktype of @kobj.
6872c4f9401SChristian Brauner  * Additional properties not added by driver core have to be changed by the
6882c4f9401SChristian Brauner  * driver or subsystem which created them. This is similar to how
6892c4f9401SChristian Brauner  * driver/subsystem specific entries are removed.
6902c4f9401SChristian Brauner  *
6912c4f9401SChristian Brauner  * Returns 0 on success or error code on failure.
6922c4f9401SChristian Brauner  */
sysfs_change_owner(struct kobject * kobj,kuid_t kuid,kgid_t kgid)6932c4f9401SChristian Brauner int sysfs_change_owner(struct kobject *kobj, kuid_t kuid, kgid_t kgid)
6942c4f9401SChristian Brauner {
6952c4f9401SChristian Brauner 	int error;
6962c4f9401SChristian Brauner 	const struct kobj_type *ktype;
6972c4f9401SChristian Brauner 
6982c4f9401SChristian Brauner 	if (!kobj->state_in_sysfs)
6992c4f9401SChristian Brauner 		return -EINVAL;
7002c4f9401SChristian Brauner 
7012c4f9401SChristian Brauner 	/* Change the owner of the kobject itself. */
7022c4f9401SChristian Brauner 	error = internal_change_owner(kobj->sd, kuid, kgid);
7032c4f9401SChristian Brauner 	if (error)
7042c4f9401SChristian Brauner 		return error;
7052c4f9401SChristian Brauner 
7062c4f9401SChristian Brauner 	ktype = get_ktype(kobj);
7072c4f9401SChristian Brauner 	if (ktype) {
7082c4f9401SChristian Brauner 		/*
7092c4f9401SChristian Brauner 		 * Change owner of the default groups associated with the
7102c4f9401SChristian Brauner 		 * ktype of @kobj.
7112c4f9401SChristian Brauner 		 */
7122c4f9401SChristian Brauner 		error = sysfs_groups_change_owner(kobj, ktype->default_groups,
7132c4f9401SChristian Brauner 						  kuid, kgid);
7142c4f9401SChristian Brauner 		if (error)
7152c4f9401SChristian Brauner 			return error;
7162c4f9401SChristian Brauner 	}
7172c4f9401SChristian Brauner 
7182c4f9401SChristian Brauner 	return 0;
7192c4f9401SChristian Brauner }
7202c4f9401SChristian Brauner EXPORT_SYMBOL_GPL(sysfs_change_owner);
7212efc459dSJoe Perches 
7222efc459dSJoe Perches /**
7232efc459dSJoe Perches  *	sysfs_emit - scnprintf equivalent, aware of PAGE_SIZE buffer.
7242efc459dSJoe Perches  *	@buf:	start of PAGE_SIZE buffer.
7252efc459dSJoe Perches  *	@fmt:	format
7262efc459dSJoe Perches  *	@...:	optional arguments to @format
7272efc459dSJoe Perches  *
7282efc459dSJoe Perches  *
7292efc459dSJoe Perches  * Returns number of characters written to @buf.
7302efc459dSJoe Perches  */
sysfs_emit(char * buf,const char * fmt,...)7312efc459dSJoe Perches int sysfs_emit(char *buf, const char *fmt, ...)
7322efc459dSJoe Perches {
7332efc459dSJoe Perches 	va_list args;
7342efc459dSJoe Perches 	int len;
7352efc459dSJoe Perches 
7362efc459dSJoe Perches 	if (WARN(!buf || offset_in_page(buf),
7372efc459dSJoe Perches 		 "invalid sysfs_emit: buf:%p\n", buf))
7382efc459dSJoe Perches 		return 0;
7392efc459dSJoe Perches 
7402efc459dSJoe Perches 	va_start(args, fmt);
7412efc459dSJoe Perches 	len = vscnprintf(buf, PAGE_SIZE, fmt, args);
7422efc459dSJoe Perches 	va_end(args);
7432efc459dSJoe Perches 
7442efc459dSJoe Perches 	return len;
7452efc459dSJoe Perches }
7462efc459dSJoe Perches EXPORT_SYMBOL_GPL(sysfs_emit);
7472efc459dSJoe Perches 
7482efc459dSJoe Perches /**
7492efc459dSJoe Perches  *	sysfs_emit_at - scnprintf equivalent, aware of PAGE_SIZE buffer.
7502efc459dSJoe Perches  *	@buf:	start of PAGE_SIZE buffer.
7512efc459dSJoe Perches  *	@at:	offset in @buf to start write in bytes
7522efc459dSJoe Perches  *		@at must be >= 0 && < PAGE_SIZE
7532efc459dSJoe Perches  *	@fmt:	format
7542efc459dSJoe Perches  *	@...:	optional arguments to @fmt
7552efc459dSJoe Perches  *
7562efc459dSJoe Perches  *
7572efc459dSJoe Perches  * Returns number of characters written starting at &@buf[@at].
7582efc459dSJoe Perches  */
sysfs_emit_at(char * buf,int at,const char * fmt,...)7592efc459dSJoe Perches int sysfs_emit_at(char *buf, int at, const char *fmt, ...)
7602efc459dSJoe Perches {
7612efc459dSJoe Perches 	va_list args;
7622efc459dSJoe Perches 	int len;
7632efc459dSJoe Perches 
7642efc459dSJoe Perches 	if (WARN(!buf || offset_in_page(buf) || at < 0 || at >= PAGE_SIZE,
7652efc459dSJoe Perches 		 "invalid sysfs_emit_at: buf:%p at:%d\n", buf, at))
7662efc459dSJoe Perches 		return 0;
7672efc459dSJoe Perches 
7682efc459dSJoe Perches 	va_start(args, fmt);
7692efc459dSJoe Perches 	len = vscnprintf(buf + at, PAGE_SIZE - at, fmt, args);
7702efc459dSJoe Perches 	va_end(args);
7712efc459dSJoe Perches 
7722efc459dSJoe Perches 	return len;
7732efc459dSJoe Perches }
7742efc459dSJoe Perches EXPORT_SYMBOL_GPL(sysfs_emit_at);
775