cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

file.c (19211B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * fs/sysfs/file.c - sysfs regular (text) file implementation
      4 *
      5 * Copyright (c) 2001-3 Patrick Mochel
      6 * Copyright (c) 2007 SUSE Linux Products GmbH
      7 * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
      8 *
      9 * Please see Documentation/filesystems/sysfs.rst for more information.
     10 */
     11
     12#include <linux/module.h>
     13#include <linux/kobject.h>
     14#include <linux/slab.h>
     15#include <linux/list.h>
     16#include <linux/mutex.h>
     17#include <linux/seq_file.h>
     18#include <linux/mm.h>
     19
     20#include "sysfs.h"
     21
     22/*
     23 * Determine ktype->sysfs_ops for the given kernfs_node.  This function
     24 * must be called while holding an active reference.
     25 */
     26static const struct sysfs_ops *sysfs_file_ops(struct kernfs_node *kn)
     27{
     28	struct kobject *kobj = kn->parent->priv;
     29
     30	if (kn->flags & KERNFS_LOCKDEP)
     31		lockdep_assert_held(kn);
     32	return kobj->ktype ? kobj->ktype->sysfs_ops : NULL;
     33}
     34
     35/*
     36 * Reads on sysfs are handled through seq_file, which takes care of hairy
     37 * details like buffering and seeking.  The following function pipes
     38 * sysfs_ops->show() result through seq_file.
     39 */
     40static int sysfs_kf_seq_show(struct seq_file *sf, void *v)
     41{
     42	struct kernfs_open_file *of = sf->private;
     43	struct kobject *kobj = of->kn->parent->priv;
     44	const struct sysfs_ops *ops = sysfs_file_ops(of->kn);
     45	ssize_t count;
     46	char *buf;
     47
     48	if (WARN_ON_ONCE(!ops->show))
     49		return -EINVAL;
     50
     51	/* acquire buffer and ensure that it's >= PAGE_SIZE and clear */
     52	count = seq_get_buf(sf, &buf);
     53	if (count < PAGE_SIZE) {
     54		seq_commit(sf, -1);
     55		return 0;
     56	}
     57	memset(buf, 0, PAGE_SIZE);
     58
     59	count = ops->show(kobj, of->kn->priv, buf);
     60	if (count < 0)
     61		return count;
     62
     63	/*
     64	 * The code works fine with PAGE_SIZE return but it's likely to
     65	 * indicate truncated result or overflow in normal use cases.
     66	 */
     67	if (count >= (ssize_t)PAGE_SIZE) {
     68		printk("fill_read_buffer: %pS returned bad count\n",
     69				ops->show);
     70		/* Try to struggle along */
     71		count = PAGE_SIZE - 1;
     72	}
     73	seq_commit(sf, count);
     74	return 0;
     75}
     76
     77static ssize_t sysfs_kf_bin_read(struct kernfs_open_file *of, char *buf,
     78				 size_t count, loff_t pos)
     79{
     80	struct bin_attribute *battr = of->kn->priv;
     81	struct kobject *kobj = of->kn->parent->priv;
     82	loff_t size = file_inode(of->file)->i_size;
     83
     84	if (!count)
     85		return 0;
     86
     87	if (size) {
     88		if (pos >= size)
     89			return 0;
     90		if (pos + count > size)
     91			count = size - pos;
     92	}
     93
     94	if (!battr->read)
     95		return -EIO;
     96
     97	return battr->read(of->file, kobj, battr, buf, pos, count);
     98}
     99
    100/* kernfs read callback for regular sysfs files with pre-alloc */
    101static ssize_t sysfs_kf_read(struct kernfs_open_file *of, char *buf,
    102			     size_t count, loff_t pos)
    103{
    104	const struct sysfs_ops *ops = sysfs_file_ops(of->kn);
    105	struct kobject *kobj = of->kn->parent->priv;
    106	ssize_t len;
    107
    108	/*
    109	 * If buf != of->prealloc_buf, we don't know how
    110	 * large it is, so cannot safely pass it to ->show
    111	 */
    112	if (WARN_ON_ONCE(buf != of->prealloc_buf))
    113		return 0;
    114	len = ops->show(kobj, of->kn->priv, buf);
    115	if (len < 0)
    116		return len;
    117	if (pos) {
    118		if (len <= pos)
    119			return 0;
    120		len -= pos;
    121		memmove(buf, buf + pos, len);
    122	}
    123	return min_t(ssize_t, count, len);
    124}
    125
    126/* kernfs write callback for regular sysfs files */
    127static ssize_t sysfs_kf_write(struct kernfs_open_file *of, char *buf,
    128			      size_t count, loff_t pos)
    129{
    130	const struct sysfs_ops *ops = sysfs_file_ops(of->kn);
    131	struct kobject *kobj = of->kn->parent->priv;
    132
    133	if (!count)
    134		return 0;
    135
    136	return ops->store(kobj, of->kn->priv, buf, count);
    137}
    138
    139/* kernfs write callback for bin sysfs files */
    140static ssize_t sysfs_kf_bin_write(struct kernfs_open_file *of, char *buf,
    141				  size_t count, loff_t pos)
    142{
    143	struct bin_attribute *battr = of->kn->priv;
    144	struct kobject *kobj = of->kn->parent->priv;
    145	loff_t size = file_inode(of->file)->i_size;
    146
    147	if (size) {
    148		if (size <= pos)
    149			return -EFBIG;
    150		count = min_t(ssize_t, count, size - pos);
    151	}
    152	if (!count)
    153		return 0;
    154
    155	if (!battr->write)
    156		return -EIO;
    157
    158	return battr->write(of->file, kobj, battr, buf, pos, count);
    159}
    160
    161static int sysfs_kf_bin_mmap(struct kernfs_open_file *of,
    162			     struct vm_area_struct *vma)
    163{
    164	struct bin_attribute *battr = of->kn->priv;
    165	struct kobject *kobj = of->kn->parent->priv;
    166
    167	return battr->mmap(of->file, kobj, battr, vma);
    168}
    169
    170static int sysfs_kf_bin_open(struct kernfs_open_file *of)
    171{
    172	struct bin_attribute *battr = of->kn->priv;
    173
    174	if (battr->f_mapping)
    175		of->file->f_mapping = battr->f_mapping();
    176
    177	return 0;
    178}
    179
    180void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr)
    181{
    182	struct kernfs_node *kn = kobj->sd, *tmp;
    183
    184	if (kn && dir)
    185		kn = kernfs_find_and_get(kn, dir);
    186	else
    187		kernfs_get(kn);
    188
    189	if (kn && attr) {
    190		tmp = kernfs_find_and_get(kn, attr);
    191		kernfs_put(kn);
    192		kn = tmp;
    193	}
    194
    195	if (kn) {
    196		kernfs_notify(kn);
    197		kernfs_put(kn);
    198	}
    199}
    200EXPORT_SYMBOL_GPL(sysfs_notify);
    201
    202static const struct kernfs_ops sysfs_file_kfops_empty = {
    203};
    204
    205static const struct kernfs_ops sysfs_file_kfops_ro = {
    206	.seq_show	= sysfs_kf_seq_show,
    207};
    208
    209static const struct kernfs_ops sysfs_file_kfops_wo = {
    210	.write		= sysfs_kf_write,
    211};
    212
    213static const struct kernfs_ops sysfs_file_kfops_rw = {
    214	.seq_show	= sysfs_kf_seq_show,
    215	.write		= sysfs_kf_write,
    216};
    217
    218static const struct kernfs_ops sysfs_prealloc_kfops_ro = {
    219	.read		= sysfs_kf_read,
    220	.prealloc	= true,
    221};
    222
    223static const struct kernfs_ops sysfs_prealloc_kfops_wo = {
    224	.write		= sysfs_kf_write,
    225	.prealloc	= true,
    226};
    227
    228static const struct kernfs_ops sysfs_prealloc_kfops_rw = {
    229	.read		= sysfs_kf_read,
    230	.write		= sysfs_kf_write,
    231	.prealloc	= true,
    232};
    233
    234static const struct kernfs_ops sysfs_bin_kfops_ro = {
    235	.read		= sysfs_kf_bin_read,
    236};
    237
    238static const struct kernfs_ops sysfs_bin_kfops_wo = {
    239	.write		= sysfs_kf_bin_write,
    240};
    241
    242static const struct kernfs_ops sysfs_bin_kfops_rw = {
    243	.read		= sysfs_kf_bin_read,
    244	.write		= sysfs_kf_bin_write,
    245};
    246
    247static const struct kernfs_ops sysfs_bin_kfops_mmap = {
    248	.read		= sysfs_kf_bin_read,
    249	.write		= sysfs_kf_bin_write,
    250	.mmap		= sysfs_kf_bin_mmap,
    251	.open		= sysfs_kf_bin_open,
    252};
    253
    254int sysfs_add_file_mode_ns(struct kernfs_node *parent,
    255		const struct attribute *attr, umode_t mode, kuid_t uid,
    256		kgid_t gid, const void *ns)
    257{
    258	struct kobject *kobj = parent->priv;
    259	const struct sysfs_ops *sysfs_ops = kobj->ktype->sysfs_ops;
    260	struct lock_class_key *key = NULL;
    261	const struct kernfs_ops *ops = NULL;
    262	struct kernfs_node *kn;
    263
    264	/* every kobject with an attribute needs a ktype assigned */
    265	if (WARN(!sysfs_ops, KERN_ERR
    266			"missing sysfs attribute operations for kobject: %s\n",
    267			kobject_name(kobj)))
    268		return -EINVAL;
    269
    270	if (mode & SYSFS_PREALLOC) {
    271		if (sysfs_ops->show && sysfs_ops->store)
    272			ops = &sysfs_prealloc_kfops_rw;
    273		else if (sysfs_ops->show)
    274			ops = &sysfs_prealloc_kfops_ro;
    275		else if (sysfs_ops->store)
    276			ops = &sysfs_prealloc_kfops_wo;
    277	} else {
    278		if (sysfs_ops->show && sysfs_ops->store)
    279			ops = &sysfs_file_kfops_rw;
    280		else if (sysfs_ops->show)
    281			ops = &sysfs_file_kfops_ro;
    282		else if (sysfs_ops->store)
    283			ops = &sysfs_file_kfops_wo;
    284	}
    285
    286	if (!ops)
    287		ops = &sysfs_file_kfops_empty;
    288
    289#ifdef CONFIG_DEBUG_LOCK_ALLOC
    290	if (!attr->ignore_lockdep)
    291		key = attr->key ?: (struct lock_class_key *)&attr->skey;
    292#endif
    293
    294	kn = __kernfs_create_file(parent, attr->name, mode & 0777, uid, gid,
    295				  PAGE_SIZE, ops, (void *)attr, ns, key);
    296	if (IS_ERR(kn)) {
    297		if (PTR_ERR(kn) == -EEXIST)
    298			sysfs_warn_dup(parent, attr->name);
    299		return PTR_ERR(kn);
    300	}
    301	return 0;
    302}
    303
    304int sysfs_add_bin_file_mode_ns(struct kernfs_node *parent,
    305		const struct bin_attribute *battr, umode_t mode,
    306		kuid_t uid, kgid_t gid, const void *ns)
    307{
    308	const struct attribute *attr = &battr->attr;
    309	struct lock_class_key *key = NULL;
    310	const struct kernfs_ops *ops;
    311	struct kernfs_node *kn;
    312
    313	if (battr->mmap)
    314		ops = &sysfs_bin_kfops_mmap;
    315	else if (battr->read && battr->write)
    316		ops = &sysfs_bin_kfops_rw;
    317	else if (battr->read)
    318		ops = &sysfs_bin_kfops_ro;
    319	else if (battr->write)
    320		ops = &sysfs_bin_kfops_wo;
    321	else
    322		ops = &sysfs_file_kfops_empty;
    323
    324#ifdef CONFIG_DEBUG_LOCK_ALLOC
    325	if (!attr->ignore_lockdep)
    326		key = attr->key ?: (struct lock_class_key *)&attr->skey;
    327#endif
    328
    329	kn = __kernfs_create_file(parent, attr->name, mode & 0777, uid, gid,
    330				  battr->size, ops, (void *)attr, ns, key);
    331	if (IS_ERR(kn)) {
    332		if (PTR_ERR(kn) == -EEXIST)
    333			sysfs_warn_dup(parent, attr->name);
    334		return PTR_ERR(kn);
    335	}
    336	return 0;
    337}
    338
    339/**
    340 * sysfs_create_file_ns - create an attribute file for an object with custom ns
    341 * @kobj: object we're creating for
    342 * @attr: attribute descriptor
    343 * @ns: namespace the new file should belong to
    344 */
    345int sysfs_create_file_ns(struct kobject *kobj, const struct attribute *attr,
    346			 const void *ns)
    347{
    348	kuid_t uid;
    349	kgid_t gid;
    350
    351	if (WARN_ON(!kobj || !kobj->sd || !attr))
    352		return -EINVAL;
    353
    354	kobject_get_ownership(kobj, &uid, &gid);
    355	return sysfs_add_file_mode_ns(kobj->sd, attr, attr->mode, uid, gid, ns);
    356}
    357EXPORT_SYMBOL_GPL(sysfs_create_file_ns);
    358
    359int sysfs_create_files(struct kobject *kobj, const struct attribute * const *ptr)
    360{
    361	int err = 0;
    362	int i;
    363
    364	for (i = 0; ptr[i] && !err; i++)
    365		err = sysfs_create_file(kobj, ptr[i]);
    366	if (err)
    367		while (--i >= 0)
    368			sysfs_remove_file(kobj, ptr[i]);
    369	return err;
    370}
    371EXPORT_SYMBOL_GPL(sysfs_create_files);
    372
    373/**
    374 * sysfs_add_file_to_group - add an attribute file to a pre-existing group.
    375 * @kobj: object we're acting for.
    376 * @attr: attribute descriptor.
    377 * @group: group name.
    378 */
    379int sysfs_add_file_to_group(struct kobject *kobj,
    380		const struct attribute *attr, const char *group)
    381{
    382	struct kernfs_node *parent;
    383	kuid_t uid;
    384	kgid_t gid;
    385	int error;
    386
    387	if (group) {
    388		parent = kernfs_find_and_get(kobj->sd, group);
    389	} else {
    390		parent = kobj->sd;
    391		kernfs_get(parent);
    392	}
    393
    394	if (!parent)
    395		return -ENOENT;
    396
    397	kobject_get_ownership(kobj, &uid, &gid);
    398	error = sysfs_add_file_mode_ns(parent, attr, attr->mode, uid, gid,
    399				       NULL);
    400	kernfs_put(parent);
    401
    402	return error;
    403}
    404EXPORT_SYMBOL_GPL(sysfs_add_file_to_group);
    405
    406/**
    407 * sysfs_chmod_file - update the modified mode value on an object attribute.
    408 * @kobj: object we're acting for.
    409 * @attr: attribute descriptor.
    410 * @mode: file permissions.
    411 *
    412 */
    413int sysfs_chmod_file(struct kobject *kobj, const struct attribute *attr,
    414		     umode_t mode)
    415{
    416	struct kernfs_node *kn;
    417	struct iattr newattrs;
    418	int rc;
    419
    420	kn = kernfs_find_and_get(kobj->sd, attr->name);
    421	if (!kn)
    422		return -ENOENT;
    423
    424	newattrs.ia_mode = (mode & S_IALLUGO) | (kn->mode & ~S_IALLUGO);
    425	newattrs.ia_valid = ATTR_MODE;
    426
    427	rc = kernfs_setattr(kn, &newattrs);
    428
    429	kernfs_put(kn);
    430	return rc;
    431}
    432EXPORT_SYMBOL_GPL(sysfs_chmod_file);
    433
    434/**
    435 * sysfs_break_active_protection - break "active" protection
    436 * @kobj: The kernel object @attr is associated with.
    437 * @attr: The attribute to break the "active" protection for.
    438 *
    439 * With sysfs, just like kernfs, deletion of an attribute is postponed until
    440 * all active .show() and .store() callbacks have finished unless this function
    441 * is called. Hence this function is useful in methods that implement self
    442 * deletion.
    443 */
    444struct kernfs_node *sysfs_break_active_protection(struct kobject *kobj,
    445						  const struct attribute *attr)
    446{
    447	struct kernfs_node *kn;
    448
    449	kobject_get(kobj);
    450	kn = kernfs_find_and_get(kobj->sd, attr->name);
    451	if (kn)
    452		kernfs_break_active_protection(kn);
    453	return kn;
    454}
    455EXPORT_SYMBOL_GPL(sysfs_break_active_protection);
    456
    457/**
    458 * sysfs_unbreak_active_protection - restore "active" protection
    459 * @kn: Pointer returned by sysfs_break_active_protection().
    460 *
    461 * Undo the effects of sysfs_break_active_protection(). Since this function
    462 * calls kernfs_put() on the kernfs node that corresponds to the 'attr'
    463 * argument passed to sysfs_break_active_protection() that attribute may have
    464 * been removed between the sysfs_break_active_protection() and
    465 * sysfs_unbreak_active_protection() calls, it is not safe to access @kn after
    466 * this function has returned.
    467 */
    468void sysfs_unbreak_active_protection(struct kernfs_node *kn)
    469{
    470	struct kobject *kobj = kn->parent->priv;
    471
    472	kernfs_unbreak_active_protection(kn);
    473	kernfs_put(kn);
    474	kobject_put(kobj);
    475}
    476EXPORT_SYMBOL_GPL(sysfs_unbreak_active_protection);
    477
    478/**
    479 * sysfs_remove_file_ns - remove an object attribute with a custom ns tag
    480 * @kobj: object we're acting for
    481 * @attr: attribute descriptor
    482 * @ns: namespace tag of the file to remove
    483 *
    484 * Hash the attribute name and namespace tag and kill the victim.
    485 */
    486void sysfs_remove_file_ns(struct kobject *kobj, const struct attribute *attr,
    487			  const void *ns)
    488{
    489	struct kernfs_node *parent = kobj->sd;
    490
    491	kernfs_remove_by_name_ns(parent, attr->name, ns);
    492}
    493EXPORT_SYMBOL_GPL(sysfs_remove_file_ns);
    494
    495/**
    496 * sysfs_remove_file_self - remove an object attribute from its own method
    497 * @kobj: object we're acting for
    498 * @attr: attribute descriptor
    499 *
    500 * See kernfs_remove_self() for details.
    501 */
    502bool sysfs_remove_file_self(struct kobject *kobj, const struct attribute *attr)
    503{
    504	struct kernfs_node *parent = kobj->sd;
    505	struct kernfs_node *kn;
    506	bool ret;
    507
    508	kn = kernfs_find_and_get(parent, attr->name);
    509	if (WARN_ON_ONCE(!kn))
    510		return false;
    511
    512	ret = kernfs_remove_self(kn);
    513
    514	kernfs_put(kn);
    515	return ret;
    516}
    517EXPORT_SYMBOL_GPL(sysfs_remove_file_self);
    518
    519void sysfs_remove_files(struct kobject *kobj, const struct attribute * const *ptr)
    520{
    521	int i;
    522
    523	for (i = 0; ptr[i]; i++)
    524		sysfs_remove_file(kobj, ptr[i]);
    525}
    526EXPORT_SYMBOL_GPL(sysfs_remove_files);
    527
    528/**
    529 * sysfs_remove_file_from_group - remove an attribute file from a group.
    530 * @kobj: object we're acting for.
    531 * @attr: attribute descriptor.
    532 * @group: group name.
    533 */
    534void sysfs_remove_file_from_group(struct kobject *kobj,
    535		const struct attribute *attr, const char *group)
    536{
    537	struct kernfs_node *parent;
    538
    539	if (group) {
    540		parent = kernfs_find_and_get(kobj->sd, group);
    541	} else {
    542		parent = kobj->sd;
    543		kernfs_get(parent);
    544	}
    545
    546	if (parent) {
    547		kernfs_remove_by_name(parent, attr->name);
    548		kernfs_put(parent);
    549	}
    550}
    551EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group);
    552
    553/**
    554 *	sysfs_create_bin_file - create binary file for object.
    555 *	@kobj:	object.
    556 *	@attr:	attribute descriptor.
    557 */
    558int sysfs_create_bin_file(struct kobject *kobj,
    559			  const struct bin_attribute *attr)
    560{
    561	kuid_t uid;
    562	kgid_t gid;
    563
    564	if (WARN_ON(!kobj || !kobj->sd || !attr))
    565		return -EINVAL;
    566
    567	kobject_get_ownership(kobj, &uid, &gid);
    568	return sysfs_add_bin_file_mode_ns(kobj->sd, attr, attr->attr.mode, uid,
    569					   gid, NULL);
    570}
    571EXPORT_SYMBOL_GPL(sysfs_create_bin_file);
    572
    573/**
    574 *	sysfs_remove_bin_file - remove binary file for object.
    575 *	@kobj:	object.
    576 *	@attr:	attribute descriptor.
    577 */
    578void sysfs_remove_bin_file(struct kobject *kobj,
    579			   const struct bin_attribute *attr)
    580{
    581	kernfs_remove_by_name(kobj->sd, attr->attr.name);
    582}
    583EXPORT_SYMBOL_GPL(sysfs_remove_bin_file);
    584
    585static int internal_change_owner(struct kernfs_node *kn, kuid_t kuid,
    586				 kgid_t kgid)
    587{
    588	struct iattr newattrs = {
    589		.ia_valid = ATTR_UID | ATTR_GID,
    590		.ia_uid = kuid,
    591		.ia_gid = kgid,
    592	};
    593	return kernfs_setattr(kn, &newattrs);
    594}
    595
    596/**
    597 *	sysfs_link_change_owner - change owner of a sysfs file.
    598 *	@kobj:	object of the kernfs_node the symlink is located in.
    599 *	@targ:	object of the kernfs_node the symlink points to.
    600 *	@name:	name of the link.
    601 *	@kuid:	new owner's kuid
    602 *	@kgid:	new owner's kgid
    603 *
    604 * This function looks up the sysfs symlink entry @name under @kobj and changes
    605 * the ownership to @kuid/@kgid. The symlink is looked up in the namespace of
    606 * @targ.
    607 *
    608 * Returns 0 on success or error code on failure.
    609 */
    610int sysfs_link_change_owner(struct kobject *kobj, struct kobject *targ,
    611			    const char *name, kuid_t kuid, kgid_t kgid)
    612{
    613	struct kernfs_node *kn = NULL;
    614	int error;
    615
    616	if (!name || !kobj->state_in_sysfs || !targ->state_in_sysfs)
    617		return -EINVAL;
    618
    619	error = -ENOENT;
    620	kn = kernfs_find_and_get_ns(kobj->sd, name, targ->sd->ns);
    621	if (!kn)
    622		goto out;
    623
    624	error = -EINVAL;
    625	if (kernfs_type(kn) != KERNFS_LINK)
    626		goto out;
    627	if (kn->symlink.target_kn->priv != targ)
    628		goto out;
    629
    630	error = internal_change_owner(kn, kuid, kgid);
    631
    632out:
    633	kernfs_put(kn);
    634	return error;
    635}
    636
    637/**
    638 *	sysfs_file_change_owner - change owner of a sysfs file.
    639 *	@kobj:	object.
    640 *	@name:	name of the file to change.
    641 *	@kuid:	new owner's kuid
    642 *	@kgid:	new owner's kgid
    643 *
    644 * This function looks up the sysfs entry @name under @kobj and changes the
    645 * ownership to @kuid/@kgid.
    646 *
    647 * Returns 0 on success or error code on failure.
    648 */
    649int sysfs_file_change_owner(struct kobject *kobj, const char *name, kuid_t kuid,
    650			    kgid_t kgid)
    651{
    652	struct kernfs_node *kn;
    653	int error;
    654
    655	if (!name)
    656		return -EINVAL;
    657
    658	if (!kobj->state_in_sysfs)
    659		return -EINVAL;
    660
    661	kn = kernfs_find_and_get(kobj->sd, name);
    662	if (!kn)
    663		return -ENOENT;
    664
    665	error = internal_change_owner(kn, kuid, kgid);
    666
    667	kernfs_put(kn);
    668
    669	return error;
    670}
    671EXPORT_SYMBOL_GPL(sysfs_file_change_owner);
    672
    673/**
    674 *	sysfs_change_owner - change owner of the given object.
    675 *	@kobj:	object.
    676 *	@kuid:	new owner's kuid
    677 *	@kgid:	new owner's kgid
    678 *
    679 * Change the owner of the default directory, files, groups, and attributes of
    680 * @kobj to @kuid/@kgid. Note that sysfs_change_owner mirrors how the sysfs
    681 * entries for a kobject are added by driver core. In summary,
    682 * sysfs_change_owner() takes care of the default directory entry for @kobj,
    683 * the default attributes associated with the ktype of @kobj and the default
    684 * attributes associated with the ktype of @kobj.
    685 * Additional properties not added by driver core have to be changed by the
    686 * driver or subsystem which created them. This is similar to how
    687 * driver/subsystem specific entries are removed.
    688 *
    689 * Returns 0 on success or error code on failure.
    690 */
    691int sysfs_change_owner(struct kobject *kobj, kuid_t kuid, kgid_t kgid)
    692{
    693	int error;
    694	const struct kobj_type *ktype;
    695
    696	if (!kobj->state_in_sysfs)
    697		return -EINVAL;
    698
    699	/* Change the owner of the kobject itself. */
    700	error = internal_change_owner(kobj->sd, kuid, kgid);
    701	if (error)
    702		return error;
    703
    704	ktype = get_ktype(kobj);
    705	if (ktype) {
    706		/*
    707		 * Change owner of the default groups associated with the
    708		 * ktype of @kobj.
    709		 */
    710		error = sysfs_groups_change_owner(kobj, ktype->default_groups,
    711						  kuid, kgid);
    712		if (error)
    713			return error;
    714	}
    715
    716	return 0;
    717}
    718EXPORT_SYMBOL_GPL(sysfs_change_owner);
    719
    720/**
    721 *	sysfs_emit - scnprintf equivalent, aware of PAGE_SIZE buffer.
    722 *	@buf:	start of PAGE_SIZE buffer.
    723 *	@fmt:	format
    724 *	@...:	optional arguments to @format
    725 *
    726 *
    727 * Returns number of characters written to @buf.
    728 */
    729int sysfs_emit(char *buf, const char *fmt, ...)
    730{
    731	va_list args;
    732	int len;
    733
    734	if (WARN(!buf || offset_in_page(buf),
    735		 "invalid sysfs_emit: buf:%p\n", buf))
    736		return 0;
    737
    738	va_start(args, fmt);
    739	len = vscnprintf(buf, PAGE_SIZE, fmt, args);
    740	va_end(args);
    741
    742	return len;
    743}
    744EXPORT_SYMBOL_GPL(sysfs_emit);
    745
    746/**
    747 *	sysfs_emit_at - scnprintf equivalent, aware of PAGE_SIZE buffer.
    748 *	@buf:	start of PAGE_SIZE buffer.
    749 *	@at:	offset in @buf to start write in bytes
    750 *		@at must be >= 0 && < PAGE_SIZE
    751 *	@fmt:	format
    752 *	@...:	optional arguments to @fmt
    753 *
    754 *
    755 * Returns number of characters written starting at &@buf[@at].
    756 */
    757int sysfs_emit_at(char *buf, int at, const char *fmt, ...)
    758{
    759	va_list args;
    760	int len;
    761
    762	if (WARN(!buf || offset_in_page(buf) || at < 0 || at >= PAGE_SIZE,
    763		 "invalid sysfs_emit_at: buf:%p at:%d\n", buf, at))
    764		return 0;
    765
    766	va_start(args, fmt);
    767	len = vscnprintf(buf + at, PAGE_SIZE - at, fmt, args);
    768	va_end(args);
    769
    770	return len;
    771}
    772EXPORT_SYMBOL_GPL(sysfs_emit_at);