file.c 18.7 KB
Newer Older
G
Greg Kroah-Hartman 已提交
1
// SPDX-License-Identifier: GPL-2.0
L
Linus Torvalds 已提交
2
/*
T
Tejun Heo 已提交
3 4 5 6 7 8
 * fs/sysfs/file.c - sysfs regular (text) file implementation
 *
 * Copyright (c) 2001-3 Patrick Mochel
 * Copyright (c) 2007 SUSE Linux Products GmbH
 * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
 *
9
 * Please see Documentation/filesystems/sysfs.rst for more information.
L
Linus Torvalds 已提交
10 11 12 13
 */

#include <linux/module.h>
#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>
L
Linus Torvalds 已提交
19 20

#include "sysfs.h"
T
Tejun Heo 已提交
21

T
Tejun Heo 已提交
22
/*
23
 * Determine ktype->sysfs_ops for the given kernfs_node.  This function
T
Tejun Heo 已提交
24 25
 * must be called while holding an active reference.
 */
26
static const struct sysfs_ops *sysfs_file_ops(struct kernfs_node *kn)
T
Tejun Heo 已提交
27
{
28
	struct kobject *kobj = kn->parent->priv;
T
Tejun Heo 已提交
29

T
Tejun Heo 已提交
30
	if (kn->flags & KERNFS_LOCKDEP)
31
		lockdep_assert_held(kn);
T
Tejun Heo 已提交
32 33 34
	return kobj->ktype ? kobj->ktype->sysfs_ops : NULL;
}

35 36 37 38
/*
 * Reads on sysfs are handled through seq_file, which takes care of hairy
 * details like buffering and seeking.  The following function pipes
 * sysfs_ops->show() result through seq_file.
L
Linus Torvalds 已提交
39
 */
40
static int sysfs_kf_seq_show(struct seq_file *sf, void *v)
L
Linus Torvalds 已提交
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);
L
Linus Torvalds 已提交
45
	ssize_t count;
46
	char *buf;
L
Linus Torvalds 已提交
47

48
	/* acquire buffer and ensure that it's >= PAGE_SIZE and clear */
49 50 51 52 53
	count = seq_get_buf(sf, &buf);
	if (count < PAGE_SIZE) {
		seq_commit(sf, -1);
		return 0;
	}
54
	memset(buf, 0, PAGE_SIZE);
L
Linus Torvalds 已提交
55

56
	/*
57 58
	 * Invoke show().  Control may reach here via seq file lseek even
	 * if @ops->show() isn't implemented.
59
	 */
60
	if (ops->show) {
61
		count = ops->show(kobj, of->kn->priv, buf);
62 63 64
		if (count < 0)
			return count;
	}
65

66 67 68 69
	/*
	 * The code works fine with PAGE_SIZE return but it's likely to
	 * indicate truncated result or overflow in normal use cases.
	 */
70
	if (count >= (ssize_t)PAGE_SIZE) {
71 72
		printk("fill_read_buffer: %pS returned bad count\n",
				ops->show);
73 74 75
		/* Try to struggle along */
		count = PAGE_SIZE - 1;
	}
76 77
	seq_commit(sf, count);
	return 0;
L
Linus Torvalds 已提交
78 79
}

80
static ssize_t sysfs_kf_bin_read(struct kernfs_open_file *of, char *buf,
81
				 size_t count, loff_t pos)
T
Tejun Heo 已提交
82
{
83
	struct bin_attribute *battr = of->kn->priv;
84
	struct kobject *kobj = of->kn->parent->priv;
85
	loff_t size = file_inode(of->file)->i_size;
T
Tejun Heo 已提交
86

87
	if (!count)
T
Tejun Heo 已提交
88 89 90
		return 0;

	if (size) {
91
		if (pos >= size)
T
Tejun Heo 已提交
92
			return 0;
93 94
		if (pos + count > size)
			count = size - pos;
T
Tejun Heo 已提交
95 96
	}

97 98 99 100 101 102
	if (!battr->read)
		return -EIO;

	return battr->read(of->file, kobj, battr, buf, pos, count);
}

103 104 105 106 107 108
/* kernfs read callback for regular sysfs files with pre-alloc */
static ssize_t sysfs_kf_read(struct kernfs_open_file *of, char *buf,
			     size_t count, loff_t pos)
{
	const struct sysfs_ops *ops = sysfs_file_ops(of->kn);
	struct kobject *kobj = of->kn->parent->priv;
109
	ssize_t len;
110 111 112 113 114

	/*
	 * If buf != of->prealloc_buf, we don't know how
	 * large it is, so cannot safely pass it to ->show
	 */
115
	if (WARN_ON_ONCE(buf != of->prealloc_buf))
116
		return 0;
117
	len = ops->show(kobj, of->kn->priv, buf);
118 119
	if (len < 0)
		return len;
120 121 122 123 124 125
	if (pos) {
		if (len <= pos)
			return 0;
		len -= pos;
		memmove(buf, buf + pos, len);
	}
126
	return min_t(ssize_t, count, len);
127 128
}

129
/* kernfs write callback for regular sysfs files */
130
static ssize_t sysfs_kf_write(struct kernfs_open_file *of, char *buf,
131
			      size_t count, loff_t pos)
L
Linus Torvalds 已提交
132
{
133
	const struct sysfs_ops *ops = sysfs_file_ops(of->kn);
134
	struct kobject *kobj = of->kn->parent->priv;
135

136 137
	if (!count)
		return 0;
138

139
	return ops->store(kobj, of->kn->priv, buf, count);
140
}
141

142
/* kernfs write callback for bin sysfs files */
143
static ssize_t sysfs_kf_bin_write(struct kernfs_open_file *of, char *buf,
144 145
				  size_t count, loff_t pos)
{
146
	struct bin_attribute *battr = of->kn->priv;
147
	struct kobject *kobj = of->kn->parent->priv;
148
	loff_t size = file_inode(of->file)->i_size;
149

150 151
	if (size) {
		if (size <= pos)
152
			return -EFBIG;
153
		count = min_t(ssize_t, count, size - pos);
154
	}
155 156
	if (!count)
		return 0;
157

158 159
	if (!battr->write)
		return -EIO;
L
Linus Torvalds 已提交
160

161
	return battr->write(of->file, kobj, battr, buf, pos, count);
L
Linus Torvalds 已提交
162 163
}

164
static int sysfs_kf_bin_mmap(struct kernfs_open_file *of,
165 166
			     struct vm_area_struct *vma)
{
167
	struct bin_attribute *battr = of->kn->priv;
168
	struct kobject *kobj = of->kn->parent->priv;
169 170 171 172

	return battr->mmap(of->file, kobj, battr, vma);
}

173 174 175 176 177 178 179 180 181 182
static int sysfs_kf_bin_open(struct kernfs_open_file *of)
{
	struct bin_attribute *battr = of->kn->priv;

	if (battr->mapping)
		of->file->f_mapping = battr->mapping;

	return 0;
}

183
void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr)
184
{
185
	struct kernfs_node *kn = kobj->sd, *tmp;
186

187 188
	if (kn && dir)
		kn = kernfs_find_and_get(kn, dir);
189
	else
190
		kernfs_get(kn);
191

192 193 194 195
	if (kn && attr) {
		tmp = kernfs_find_and_get(kn, attr);
		kernfs_put(kn);
		kn = tmp;
196
	}
197

198 199 200
	if (kn) {
		kernfs_notify(kn);
		kernfs_put(kn);
201
	}
202 203 204
}
EXPORT_SYMBOL_GPL(sysfs_notify);

T
Tejun Heo 已提交
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
static const struct kernfs_ops sysfs_file_kfops_empty = {
};

static const struct kernfs_ops sysfs_file_kfops_ro = {
	.seq_show	= sysfs_kf_seq_show,
};

static const struct kernfs_ops sysfs_file_kfops_wo = {
	.write		= sysfs_kf_write,
};

static const struct kernfs_ops sysfs_file_kfops_rw = {
	.seq_show	= sysfs_kf_seq_show,
	.write		= sysfs_kf_write,
};

221 222 223 224 225
static const struct kernfs_ops sysfs_prealloc_kfops_ro = {
	.read		= sysfs_kf_read,
	.prealloc	= true,
};

226 227 228 229 230 231
static const struct kernfs_ops sysfs_prealloc_kfops_wo = {
	.write		= sysfs_kf_write,
	.prealloc	= true,
};

static const struct kernfs_ops sysfs_prealloc_kfops_rw = {
232
	.read		= sysfs_kf_read,
233 234 235 236
	.write		= sysfs_kf_write,
	.prealloc	= true,
};

T
Tejun Heo 已提交
237 238 239 240 241 242 243 244 245 246 247
static const struct kernfs_ops sysfs_bin_kfops_ro = {
	.read		= sysfs_kf_bin_read,
};

static const struct kernfs_ops sysfs_bin_kfops_wo = {
	.write		= sysfs_kf_bin_write,
};

static const struct kernfs_ops sysfs_bin_kfops_rw = {
	.read		= sysfs_kf_bin_read,
	.write		= sysfs_kf_bin_write,
248 249 250 251 252
};

static const struct kernfs_ops sysfs_bin_kfops_mmap = {
	.read		= sysfs_kf_bin_read,
	.write		= sysfs_kf_bin_write,
T
Tejun Heo 已提交
253
	.mmap		= sysfs_kf_bin_mmap,
254
	.open		= sysfs_kf_bin_open,
T
Tejun Heo 已提交
255 256
};

257
int sysfs_add_file_mode_ns(struct kernfs_node *parent,
258
			   const struct attribute *attr, bool is_bin,
259
			   umode_t mode, kuid_t uid, kgid_t gid, const void *ns)
L
Linus Torvalds 已提交
260
{
261
	struct lock_class_key *key = NULL;
T
Tejun Heo 已提交
262
	const struct kernfs_ops *ops;
263
	struct kernfs_node *kn;
264
	loff_t size;
L
Linus Torvalds 已提交
265

266
	if (!is_bin) {
267
		struct kobject *kobj = parent->priv;
T
Tejun Heo 已提交
268 269 270 271 272 273 274 275
		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;

276 277 278 279 280
		if (sysfs_ops->show && sysfs_ops->store) {
			if (mode & SYSFS_PREALLOC)
				ops = &sysfs_prealloc_kfops_rw;
			else
				ops = &sysfs_file_kfops_rw;
281 282 283 284 285 286
		} 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) {
287 288 289 290 291
			if (mode & SYSFS_PREALLOC)
				ops = &sysfs_prealloc_kfops_wo;
			else
				ops = &sysfs_file_kfops_wo;
		} else
T
Tejun Heo 已提交
292
			ops = &sysfs_file_kfops_empty;
293 294

		size = PAGE_SIZE;
T
Tejun Heo 已提交
295 296 297
	} else {
		struct bin_attribute *battr = (void *)attr;

298 299 300
		if (battr->mmap)
			ops = &sysfs_bin_kfops_mmap;
		else if (battr->read && battr->write)
T
Tejun Heo 已提交
301 302 303 304 305 306 307
			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;
308 309

		size = battr->size;
T
Tejun Heo 已提交
310 311
	}

312 313 314 315
#ifdef CONFIG_DEBUG_LOCK_ALLOC
	if (!attr->ignore_lockdep)
		key = attr->key ?: (struct lock_class_key *)&attr->skey;
#endif
316 317

	kn = __kernfs_create_file(parent, attr->name, mode & 0777, uid, gid,
318
				  size, ops, (void *)attr, ns, key);
319 320 321 322
	if (IS_ERR(kn)) {
		if (PTR_ERR(kn) == -EEXIST)
			sysfs_warn_dup(parent, attr->name);
		return PTR_ERR(kn);
323 324 325 326
	}
	return 0;
}

L
Linus Torvalds 已提交
327
/**
328 329 330 331
 * sysfs_create_file_ns - create an attribute file for an object with custom ns
 * @kobj: object we're creating for
 * @attr: attribute descriptor
 * @ns: namespace the new file should belong to
L
Linus Torvalds 已提交
332
 */
333 334
int sysfs_create_file_ns(struct kobject *kobj, const struct attribute *attr,
			 const void *ns)
L
Linus Torvalds 已提交
335
{
336 337 338
	kuid_t uid;
	kgid_t gid;

339 340
	if (WARN_ON(!kobj || !kobj->sd || !attr))
		return -EINVAL;
L
Linus Torvalds 已提交
341

342 343 344
	kobject_get_ownership(kobj, &uid, &gid);
	return sysfs_add_file_mode_ns(kobj->sd, attr, false, attr->mode,
				      uid, gid, ns);
L
Linus Torvalds 已提交
345 346

}
347
EXPORT_SYMBOL_GPL(sysfs_create_file_ns);
L
Linus Torvalds 已提交
348

349
int sysfs_create_files(struct kobject *kobj, const struct attribute * const *ptr)
350 351 352 353 354 355 356 357 358 359 360
{
	int err = 0;
	int i;

	for (i = 0; ptr[i] && !err; i++)
		err = sysfs_create_file(kobj, ptr[i]);
	if (err)
		while (--i >= 0)
			sysfs_remove_file(kobj, ptr[i]);
	return err;
}
361
EXPORT_SYMBOL_GPL(sysfs_create_files);
L
Linus Torvalds 已提交
362

363 364 365 366 367 368 369 370 371
/**
 * 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)
{
372
	struct kernfs_node *parent;
373 374
	kuid_t uid;
	kgid_t gid;
375 376
	int error;

377
	if (group) {
378
		parent = kernfs_find_and_get(kobj->sd, group);
379
	} else {
380 381
		parent = kobj->sd;
		kernfs_get(parent);
382
	}
383

384
	if (!parent)
385 386
		return -ENOENT;

387
	kobject_get_ownership(kobj, &uid, &gid);
388
	error = sysfs_add_file_mode_ns(parent, attr, false,
389
				       attr->mode, uid, gid, NULL);
390
	kernfs_put(parent);
391

392 393 394 395
	return error;
}
EXPORT_SYMBOL_GPL(sysfs_add_file_to_group);

396 397 398 399 400 401 402
/**
 * sysfs_chmod_file - update the modified mode value on an object attribute.
 * @kobj: object we're acting for.
 * @attr: attribute descriptor.
 * @mode: file permissions.
 *
 */
403
int sysfs_chmod_file(struct kobject *kobj, const struct attribute *attr,
A
Al Viro 已提交
404
		     umode_t mode)
405
{
406
	struct kernfs_node *kn;
407
	struct iattr newattrs;
408 409
	int rc;

410 411
	kn = kernfs_find_and_get(kobj->sd, attr->name);
	if (!kn)
412
		return -ENOENT;
413

414
	newattrs.ia_mode = (mode & S_IALLUGO) | (kn->mode & ~S_IALLUGO);
415
	newattrs.ia_valid = ATTR_MODE;
416

417
	rc = kernfs_setattr(kn, &newattrs);
418

419
	kernfs_put(kn);
420
	return rc;
421 422 423
}
EXPORT_SYMBOL_GPL(sysfs_chmod_file);

424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467
/**
 * sysfs_break_active_protection - break "active" protection
 * @kobj: The kernel object @attr is associated with.
 * @attr: The attribute to break the "active" protection for.
 *
 * With sysfs, just like kernfs, deletion of an attribute is postponed until
 * all active .show() and .store() callbacks have finished unless this function
 * is called. Hence this function is useful in methods that implement self
 * deletion.
 */
struct kernfs_node *sysfs_break_active_protection(struct kobject *kobj,
						  const struct attribute *attr)
{
	struct kernfs_node *kn;

	kobject_get(kobj);
	kn = kernfs_find_and_get(kobj->sd, attr->name);
	if (kn)
		kernfs_break_active_protection(kn);
	return kn;
}
EXPORT_SYMBOL_GPL(sysfs_break_active_protection);

/**
 * sysfs_unbreak_active_protection - restore "active" protection
 * @kn: Pointer returned by sysfs_break_active_protection().
 *
 * Undo the effects of sysfs_break_active_protection(). Since this function
 * calls kernfs_put() on the kernfs node that corresponds to the 'attr'
 * argument passed to sysfs_break_active_protection() that attribute may have
 * been removed between the sysfs_break_active_protection() and
 * sysfs_unbreak_active_protection() calls, it is not safe to access @kn after
 * this function has returned.
 */
void sysfs_unbreak_active_protection(struct kernfs_node *kn)
{
	struct kobject *kobj = kn->parent->priv;

	kernfs_unbreak_active_protection(kn);
	kernfs_put(kn);
	kobject_put(kobj);
}
EXPORT_SYMBOL_GPL(sysfs_unbreak_active_protection);

L
Linus Torvalds 已提交
468
/**
469 470 471 472
 * sysfs_remove_file_ns - remove an object attribute with a custom ns tag
 * @kobj: object we're acting for
 * @attr: attribute descriptor
 * @ns: namespace tag of the file to remove
L
Linus Torvalds 已提交
473
 *
474
 * Hash the attribute name and namespace tag and kill the victim.
L
Linus Torvalds 已提交
475
 */
476 477
void sysfs_remove_file_ns(struct kobject *kobj, const struct attribute *attr,
			  const void *ns)
L
Linus Torvalds 已提交
478
{
479
	struct kernfs_node *parent = kobj->sd;
480

481
	kernfs_remove_by_name_ns(parent, attr->name, ns);
L
Linus Torvalds 已提交
482
}
483
EXPORT_SYMBOL_GPL(sysfs_remove_file_ns);
L
Linus Torvalds 已提交
484

485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506
/**
 * sysfs_remove_file_self - remove an object attribute from its own method
 * @kobj: object we're acting for
 * @attr: attribute descriptor
 *
 * See kernfs_remove_self() for details.
 */
bool sysfs_remove_file_self(struct kobject *kobj, const struct attribute *attr)
{
	struct kernfs_node *parent = kobj->sd;
	struct kernfs_node *kn;
	bool ret;

	kn = kernfs_find_and_get(parent, attr->name);
	if (WARN_ON_ONCE(!kn))
		return false;

	ret = kernfs_remove_self(kn);

	kernfs_put(kn);
	return ret;
}
507
EXPORT_SYMBOL_GPL(sysfs_remove_file_self);
508

509
void sysfs_remove_files(struct kobject *kobj, const struct attribute * const *ptr)
510 511
{
	int i;
512

513 514 515
	for (i = 0; ptr[i]; i++)
		sysfs_remove_file(kobj, ptr[i]);
}
516
EXPORT_SYMBOL_GPL(sysfs_remove_files);
L
Linus Torvalds 已提交
517

518 519 520 521 522 523 524 525 526
/**
 * 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)
{
527
	struct kernfs_node *parent;
528

529
	if (group) {
530
		parent = kernfs_find_and_get(kobj->sd, group);
531
	} else {
532 533
		parent = kobj->sd;
		kernfs_get(parent);
534 535
	}

536 537 538
	if (parent) {
		kernfs_remove_by_name(parent, attr->name);
		kernfs_put(parent);
539 540 541 542
	}
}
EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group);

543 544 545 546 547 548 549 550
/**
 *	sysfs_create_bin_file - create binary file for object.
 *	@kobj:	object.
 *	@attr:	attribute descriptor.
 */
int sysfs_create_bin_file(struct kobject *kobj,
			  const struct bin_attribute *attr)
{
551 552 553
	kuid_t uid;
	kgid_t gid;

554 555
	if (WARN_ON(!kobj || !kobj->sd || !attr))
		return -EINVAL;
556

557 558 559
	kobject_get_ownership(kobj, &uid, &gid);
	return sysfs_add_file_mode_ns(kobj->sd, &attr->attr, true,
				      attr->attr.mode, uid, gid, NULL);
560 561 562 563 564 565 566 567 568 569 570
}
EXPORT_SYMBOL_GPL(sysfs_create_bin_file);

/**
 *	sysfs_remove_bin_file - remove binary file for object.
 *	@kobj:	object.
 *	@attr:	attribute descriptor.
 */
void sysfs_remove_bin_file(struct kobject *kobj,
			   const struct bin_attribute *attr)
{
571
	kernfs_remove_by_name(kobj->sd, attr->attr.name);
572 573
}
EXPORT_SYMBOL_GPL(sysfs_remove_bin_file);
574 575 576 577 578 579 580 581 582 583 584 585

static int internal_change_owner(struct kernfs_node *kn, kuid_t kuid,
				 kgid_t kgid)
{
	struct iattr newattrs = {
		.ia_valid = ATTR_UID | ATTR_GID,
		.ia_uid = kuid,
		.ia_gid = kgid,
	};
	return kernfs_setattr(kn, &newattrs);
}

586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626
/**
 *	sysfs_link_change_owner - change owner of a sysfs file.
 *	@kobj:	object of the kernfs_node the symlink is located in.
 *	@targ:	object of the kernfs_node the symlink points to.
 *	@name:	name of the link.
 *	@kuid:	new owner's kuid
 *	@kgid:	new owner's kgid
 *
 * This function looks up the sysfs symlink entry @name under @kobj and changes
 * the ownership to @kuid/@kgid. The symlink is looked up in the namespace of
 * @targ.
 *
 * Returns 0 on success or error code on failure.
 */
int sysfs_link_change_owner(struct kobject *kobj, struct kobject *targ,
			    const char *name, kuid_t kuid, kgid_t kgid)
{
	struct kernfs_node *kn = NULL;
	int error;

	if (!name || !kobj->state_in_sysfs || !targ->state_in_sysfs)
		return -EINVAL;

	error = -ENOENT;
	kn = kernfs_find_and_get_ns(kobj->sd, name, targ->sd->ns);
	if (!kn)
		goto out;

	error = -EINVAL;
	if (kernfs_type(kn) != KERNFS_LINK)
		goto out;
	if (kn->symlink.target_kn->priv != targ)
		goto out;

	error = internal_change_owner(kn, kuid, kgid);

out:
	kernfs_put(kn);
	return error;
}

627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661
/**
 *	sysfs_file_change_owner - change owner of a sysfs file.
 *	@kobj:	object.
 *	@name:	name of the file to change.
 *	@kuid:	new owner's kuid
 *	@kgid:	new owner's kgid
 *
 * This function looks up the sysfs entry @name under @kobj and changes the
 * ownership to @kuid/@kgid.
 *
 * Returns 0 on success or error code on failure.
 */
int sysfs_file_change_owner(struct kobject *kobj, const char *name, kuid_t kuid,
			    kgid_t kgid)
{
	struct kernfs_node *kn;
	int error;

	if (!name)
		return -EINVAL;

	if (!kobj->state_in_sysfs)
		return -EINVAL;

	kn = kernfs_find_and_get(kobj->sd, name);
	if (!kn)
		return -ENOENT;

	error = internal_change_owner(kn, kuid, kgid);

	kernfs_put(kn);

	return error;
}
EXPORT_SYMBOL_GPL(sysfs_file_change_owner);
662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721

/**
 *	sysfs_change_owner - change owner of the given object.
 *	@kobj:	object.
 *	@kuid:	new owner's kuid
 *	@kgid:	new owner's kgid
 *
 * Change the owner of the default directory, files, groups, and attributes of
 * @kobj to @kuid/@kgid. Note that sysfs_change_owner mirrors how the sysfs
 * entries for a kobject are added by driver core. In summary,
 * sysfs_change_owner() takes care of the default directory entry for @kobj,
 * the default attributes associated with the ktype of @kobj and the default
 * attributes associated with the ktype of @kobj.
 * Additional properties not added by driver core have to be changed by the
 * driver or subsystem which created them. This is similar to how
 * driver/subsystem specific entries are removed.
 *
 * Returns 0 on success or error code on failure.
 */
int sysfs_change_owner(struct kobject *kobj, kuid_t kuid, kgid_t kgid)
{
	int error;
	const struct kobj_type *ktype;

	if (!kobj->state_in_sysfs)
		return -EINVAL;

	/* Change the owner of the kobject itself. */
	error = internal_change_owner(kobj->sd, kuid, kgid);
	if (error)
		return error;

	ktype = get_ktype(kobj);
	if (ktype) {
		struct attribute **kattr;

		/*
		 * Change owner of the default attributes associated with the
		 * ktype of @kobj.
		 */
		for (kattr = ktype->default_attrs; kattr && *kattr; kattr++) {
			error = sysfs_file_change_owner(kobj, (*kattr)->name,
							kuid, kgid);
			if (error)
				return error;
		}

		/*
		 * Change owner of the default groups associated with the
		 * ktype of @kobj.
		 */
		error = sysfs_groups_change_owner(kobj, ktype->default_groups,
						  kuid, kgid);
		if (error)
			return error;
	}

	return 0;
}
EXPORT_SYMBOL_GPL(sysfs_change_owner);
722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775

/**
 *	sysfs_emit - scnprintf equivalent, aware of PAGE_SIZE buffer.
 *	@buf:	start of PAGE_SIZE buffer.
 *	@fmt:	format
 *	@...:	optional arguments to @format
 *
 *
 * Returns number of characters written to @buf.
 */
int sysfs_emit(char *buf, const char *fmt, ...)
{
	va_list args;
	int len;

	if (WARN(!buf || offset_in_page(buf),
		 "invalid sysfs_emit: buf:%p\n", buf))
		return 0;

	va_start(args, fmt);
	len = vscnprintf(buf, PAGE_SIZE, fmt, args);
	va_end(args);

	return len;
}
EXPORT_SYMBOL_GPL(sysfs_emit);

/**
 *	sysfs_emit_at - scnprintf equivalent, aware of PAGE_SIZE buffer.
 *	@buf:	start of PAGE_SIZE buffer.
 *	@at:	offset in @buf to start write in bytes
 *		@at must be >= 0 && < PAGE_SIZE
 *	@fmt:	format
 *	@...:	optional arguments to @fmt
 *
 *
 * Returns number of characters written starting at &@buf[@at].
 */
int sysfs_emit_at(char *buf, int at, const char *fmt, ...)
{
	va_list args;
	int len;

	if (WARN(!buf || offset_in_page(buf) || at < 0 || at >= PAGE_SIZE,
		 "invalid sysfs_emit_at: buf:%p at:%d\n", buf, at))
		return 0;

	va_start(args, fmt);
	len = vscnprintf(buf + at, PAGE_SIZE - at, fmt, args);
	va_end(args);

	return len;
}
EXPORT_SYMBOL_GPL(sysfs_emit_at);