License cleanup: add SPDX GPL-2.0 license identifier to files with no license
Many source files in the tree are missing licensing information, which
makes it harder for compliance tools to determine the correct license.
By default all files without license information are under the default
license of the kernel, which is GPL version 2.
Update the files which contain no license information with the 'GPL-2.0'
SPDX license identifier. The SPDX identifier is a legally binding
shorthand, which can be used instead of the full boiler plate text.
This patch is based on work done by Thomas Gleixner and Kate Stewart and
Philippe Ombredanne.
How this work was done:
Patches were generated and checked against linux-4.14-rc6 for a subset of
the use cases:
- file had no licensing information it it.
- file was a */uapi/* one with no licensing information in it,
- file was a */uapi/* one with existing licensing information,
Further patches will be generated in subsequent months to fix up cases
where non-standard license headers were used, and references to license
had to be inferred by heuristics based on keywords.
The analysis to determine which SPDX License Identifier to be applied to
a file was done in a spreadsheet of side by side results from of the
output of two independent scanners (ScanCode & Windriver) producing SPDX
tag:value files created by Philippe Ombredanne. Philippe prepared the
base worksheet, and did an initial spot review of a few 1000 files.
The 4.13 kernel was the starting point of the analysis with 60,537 files
assessed. Kate Stewart did a file by file comparison of the scanner
results in the spreadsheet to determine which SPDX license identifier(s)
to be applied to the file. She confirmed any determination that was not
immediately clear with lawyers working with the Linux Foundation.
Criteria used to select files for SPDX license identifier tagging was:
- Files considered eligible had to be source code files.
- Make and config files were included as candidates if they contained >5
lines of source
- File already had some variant of a license header in it (even if <5
lines).
All documentation files were explicitly excluded.
The following heuristics were used to determine which SPDX license
identifiers to apply.
- when both scanners couldn't find any license traces, file was
considered to have no license information in it, and the top level
COPYING file license applied.
For non */uapi/* files that summary was:
SPDX license identifier # files
---------------------------------------------------|-------
GPL-2.0 11139
and resulted in the first patch in this series.
If that file was a */uapi/* path one, it was "GPL-2.0 WITH
Linux-syscall-note" otherwise it was "GPL-2.0". Results of that was:
SPDX license identifier # files
---------------------------------------------------|-------
GPL-2.0 WITH Linux-syscall-note 930
and resulted in the second patch in this series.
- if a file had some form of licensing information in it, and was one
of the */uapi/* ones, it was denoted with the Linux-syscall-note if
any GPL family license was found in the file or had no licensing in
it (per prior point). Results summary:
SPDX license identifier # files
---------------------------------------------------|------
GPL-2.0 WITH Linux-syscall-note 270
GPL-2.0+ WITH Linux-syscall-note 169
((GPL-2.0 WITH Linux-syscall-note) OR BSD-2-Clause) 21
((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) 17
LGPL-2.1+ WITH Linux-syscall-note 15
GPL-1.0+ WITH Linux-syscall-note 14
((GPL-2.0+ WITH Linux-syscall-note) OR BSD-3-Clause) 5
LGPL-2.0+ WITH Linux-syscall-note 4
LGPL-2.1 WITH Linux-syscall-note 3
((GPL-2.0 WITH Linux-syscall-note) OR MIT) 3
((GPL-2.0 WITH Linux-syscall-note) AND MIT) 1
and that resulted in the third patch in this series.
- when the two scanners agreed on the detected license(s), that became
the concluded license(s).
- when there was disagreement between the two scanners (one detected a
license but the other didn't, or they both detected different
licenses) a manual inspection of the file occurred.
- In most cases a manual inspection of the information in the file
resulted in a clear resolution of the license that should apply (and
which scanner probably needed to revisit its heuristics).
- When it was not immediately clear, the license identifier was
confirmed with lawyers working with the Linux Foundation.
- If there was any question as to the appropriate license identifier,
the file was flagged for further research and to be revisited later
in time.
In total, over 70 hours of logged manual review was done on the
spreadsheet to determine the SPDX license identifiers to apply to the
source files by Kate, Philippe, Thomas and, in some cases, confirmation
by lawyers working with the Linux Foundation.
Kate also obtained a third independent scan of the 4.13 code base from
FOSSology, and compared selected files where the other two scanners
disagreed against that SPDX file, to see if there was new insights. The
Windriver scanner is based on an older version of FOSSology in part, so
they are related.
Thomas did random spot checks in about 500 files from the spreadsheets
for the uapi headers and agreed with SPDX license identifier in the
files he inspected. For the non-uapi files Thomas did random spot checks
in about 15000 files.
In initial set of patches against 4.14-rc6, 3 files were found to have
copy/paste license identifier errors, and have been fixed to reflect the
correct identifier.
Additionally Philippe spent 10 hours this week doing a detailed manual
inspection and review of the 12,461 patched files from the initial patch
version early this week with:
- a full scancode scan run, collecting the matched texts, detected
license ids and scores
- reviewing anything where there was a license detected (about 500+
files) to ensure that the applied SPDX license was correct
- reviewing anything where there was no detection but the patch license
was not GPL-2.0 WITH Linux-syscall-note to ensure that the applied
SPDX license was correct
This produced a worksheet with 20 files needing minor correction. This
worksheet was then exported into 3 different .csv files for the
different types of files to be modified.
These .csv files were then reviewed by Greg. Thomas wrote a script to
parse the csv files and add the proper SPDX tag to the file, in the
format that the file expected. This script was further refined by Greg
based on the output to detect more types of files automatically and to
distinguish between header and source .c files (which need different
comment types.) Finally Greg ran the script using the .csv files to
generate the patches.
Reviewed-by: Kate Stewart <kstewart@linuxfoundation.org>
Reviewed-by: Philippe Ombredanne <pombredanne@nexb.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2017-11-01 21:07:57 +07:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0 */
|
2005-04-17 05:20:36 +07:00
|
|
|
/*
|
|
|
|
* sysfs.h - definitions for the device driver filesystem
|
|
|
|
*
|
|
|
|
* Copyright (c) 2001,2002 Patrick Mochel
|
|
|
|
* Copyright (c) 2004 Silicon Graphics, Inc.
|
2007-09-20 15:31:38 +07:00
|
|
|
* Copyright (c) 2007 SUSE Linux Products GmbH
|
|
|
|
* Copyright (c) 2007 Tejun Heo <teheo@suse.de>
|
2005-04-17 05:20:36 +07:00
|
|
|
*
|
|
|
|
* Please see Documentation/filesystems/sysfs.txt for more information.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _SYSFS_H_
|
|
|
|
#define _SYSFS_H_
|
|
|
|
|
2013-11-24 21:54:58 +07:00
|
|
|
#include <linux/kernfs.h>
|
2006-08-15 12:43:17 +07:00
|
|
|
#include <linux/compiler.h>
|
2007-03-18 19:58:08 +07:00
|
|
|
#include <linux/errno.h>
|
2007-01-17 23:51:18 +07:00
|
|
|
#include <linux/list.h>
|
2010-02-12 06:21:53 +07:00
|
|
|
#include <linux/lockdep.h>
|
2010-08-11 21:01:02 +07:00
|
|
|
#include <linux/kobject_ns.h>
|
2013-07-15 06:05:59 +07:00
|
|
|
#include <linux/stat.h>
|
2011-07-27 06:09:06 +07:00
|
|
|
#include <linux/atomic.h>
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
struct kobject;
|
|
|
|
struct module;
|
2013-07-15 06:05:55 +07:00
|
|
|
struct bin_attribute;
|
2010-03-31 01:31:26 +07:00
|
|
|
enum kobj_ns_type;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
struct attribute {
|
2007-09-20 14:05:10 +07:00
|
|
|
const char *name;
|
2011-07-24 10:10:46 +07:00
|
|
|
umode_t mode;
|
2010-02-12 06:21:53 +07:00
|
|
|
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
2012-05-15 00:30:03 +07:00
|
|
|
bool ignore_lockdep:1;
|
2010-02-12 06:21:53 +07:00
|
|
|
struct lock_class_key *key;
|
|
|
|
struct lock_class_key skey;
|
|
|
|
#endif
|
2005-04-17 05:20:36 +07:00
|
|
|
};
|
|
|
|
|
2010-02-12 19:35:32 +07:00
|
|
|
/**
|
|
|
|
* sysfs_attr_init - initialize a dynamically allocated sysfs attribute
|
|
|
|
* @attr: struct attribute to initialize
|
|
|
|
*
|
|
|
|
* Initialize a dynamically allocated struct attribute so we can
|
|
|
|
* make lockdep happy. This is a new requirement for attributes
|
|
|
|
* and initially this is only needed when lockdep is enabled.
|
|
|
|
* Lockdep gives a nice error when your attribute is added to
|
|
|
|
* sysfs if you don't have this.
|
|
|
|
*/
|
2010-02-12 06:21:53 +07:00
|
|
|
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
|
|
|
#define sysfs_attr_init(attr) \
|
|
|
|
do { \
|
|
|
|
static struct lock_class_key __key; \
|
|
|
|
\
|
|
|
|
(attr)->key = &__key; \
|
2013-08-22 07:47:05 +07:00
|
|
|
} while (0)
|
2010-02-12 06:21:53 +07:00
|
|
|
#else
|
2013-08-22 07:47:05 +07:00
|
|
|
#define sysfs_attr_init(attr) do {} while (0)
|
2010-02-12 06:21:53 +07:00
|
|
|
#endif
|
|
|
|
|
2015-03-12 20:58:28 +07:00
|
|
|
/**
|
|
|
|
* struct attribute_group - data structure used to declare an attribute group.
|
|
|
|
* @name: Optional: Attribute group name
|
|
|
|
* If specified, the attribute group will be created in
|
|
|
|
* a new subdirectory with this name.
|
|
|
|
* @is_visible: Optional: Function to return permissions associated with an
|
|
|
|
* attribute of the group. Will be called repeatedly for each
|
2015-09-21 20:38:20 +07:00
|
|
|
* non-binary attribute in the group. Only read/write
|
|
|
|
* permissions as well as SYSFS_PREALLOC are accepted. Must
|
|
|
|
* return 0 if an attribute is not visible. The returned value
|
|
|
|
* will replace static permissions defined in struct attribute.
|
|
|
|
* @is_bin_visible:
|
|
|
|
* Optional: Function to return permissions associated with a
|
|
|
|
* binary attribute of the group. Will be called repeatedly
|
|
|
|
* for each binary attribute in the group. Only read/write
|
|
|
|
* permissions as well as SYSFS_PREALLOC are accepted. Must
|
|
|
|
* return 0 if a binary attribute is not visible. The returned
|
|
|
|
* value will replace static permissions defined in
|
|
|
|
* struct bin_attribute.
|
2015-03-12 20:58:28 +07:00
|
|
|
* @attrs: Pointer to NULL terminated list of attributes.
|
|
|
|
* @bin_attrs: Pointer to NULL terminated list of binary attributes.
|
|
|
|
* Either attrs or bin_attrs or both must be provided.
|
|
|
|
*/
|
2005-04-17 05:20:36 +07:00
|
|
|
struct attribute_group {
|
2007-09-20 14:05:10 +07:00
|
|
|
const char *name;
|
2011-07-24 10:11:19 +07:00
|
|
|
umode_t (*is_visible)(struct kobject *,
|
2007-10-31 21:38:04 +07:00
|
|
|
struct attribute *, int);
|
2015-09-21 20:38:20 +07:00
|
|
|
umode_t (*is_bin_visible)(struct kobject *,
|
|
|
|
struct bin_attribute *, int);
|
2007-09-20 14:05:10 +07:00
|
|
|
struct attribute **attrs;
|
2013-07-15 06:05:55 +07:00
|
|
|
struct bin_attribute **bin_attrs;
|
2005-04-17 05:20:36 +07:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Use these macros to make defining attributes easier. See include/linux/device.h
|
|
|
|
* for examples..
|
|
|
|
*/
|
|
|
|
|
2014-10-13 12:41:28 +07:00
|
|
|
#define SYSFS_PREALLOC 010000
|
|
|
|
|
2013-08-22 07:47:05 +07:00
|
|
|
#define __ATTR(_name, _mode, _show, _store) { \
|
2014-03-24 08:30:34 +07:00
|
|
|
.attr = {.name = __stringify(_name), \
|
|
|
|
.mode = VERIFY_OCTAL_PERMISSIONS(_mode) }, \
|
2013-07-15 06:06:00 +07:00
|
|
|
.show = _show, \
|
|
|
|
.store = _store, \
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
2014-10-13 12:41:28 +07:00
|
|
|
#define __ATTR_PREALLOC(_name, _mode, _show, _store) { \
|
|
|
|
.attr = {.name = __stringify(_name), \
|
|
|
|
.mode = SYSFS_PREALLOC | VERIFY_OCTAL_PERMISSIONS(_mode) },\
|
|
|
|
.show = _show, \
|
|
|
|
.store = _store, \
|
|
|
|
}
|
|
|
|
|
2013-07-15 06:06:00 +07:00
|
|
|
#define __ATTR_RO(_name) { \
|
2017-12-20 01:15:06 +07:00
|
|
|
.attr = { .name = __stringify(_name), .mode = 0444 }, \
|
2013-07-15 06:06:00 +07:00
|
|
|
.show = _name##_show, \
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
2017-12-06 16:50:08 +07:00
|
|
|
#define __ATTR_RO_MODE(_name, _mode) { \
|
|
|
|
.attr = { .name = __stringify(_name), \
|
|
|
|
.mode = VERIFY_OCTAL_PERMISSIONS(_mode) }, \
|
|
|
|
.show = _name##_show, \
|
|
|
|
}
|
|
|
|
|
2013-08-24 05:02:01 +07:00
|
|
|
#define __ATTR_WO(_name) { \
|
2017-12-20 01:15:06 +07:00
|
|
|
.attr = { .name = __stringify(_name), .mode = 0200 }, \
|
2013-08-24 05:02:01 +07:00
|
|
|
.store = _name##_store, \
|
|
|
|
}
|
|
|
|
|
2017-12-20 01:15:06 +07:00
|
|
|
#define __ATTR_RW(_name) __ATTR(_name, 0644, _name##_show, _name##_store)
|
2013-07-15 06:05:51 +07:00
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
#define __ATTR_NULL { .attr = { .name = NULL } }
|
2012-05-15 00:30:03 +07:00
|
|
|
|
|
|
|
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
|
|
|
#define __ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store) { \
|
|
|
|
.attr = {.name = __stringify(_name), .mode = _mode, \
|
|
|
|
.ignore_lockdep = true }, \
|
|
|
|
.show = _show, \
|
|
|
|
.store = _store, \
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
#define __ATTR_IGNORE_LOCKDEP __ATTR
|
|
|
|
#endif
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2013-07-15 06:05:59 +07:00
|
|
|
#define __ATTRIBUTE_GROUPS(_name) \
|
|
|
|
static const struct attribute_group *_name##_groups[] = { \
|
|
|
|
&_name##_group, \
|
2013-07-15 06:05:52 +07:00
|
|
|
NULL, \
|
|
|
|
}
|
|
|
|
|
2013-07-15 06:05:59 +07:00
|
|
|
#define ATTRIBUTE_GROUPS(_name) \
|
|
|
|
static const struct attribute_group _name##_group = { \
|
|
|
|
.attrs = _name##_attrs, \
|
|
|
|
}; \
|
|
|
|
__ATTRIBUTE_GROUPS(_name)
|
|
|
|
|
2010-05-13 08:28:57 +07:00
|
|
|
struct file;
|
2005-04-17 05:20:36 +07:00
|
|
|
struct vm_area_struct;
|
|
|
|
|
|
|
|
struct bin_attribute {
|
|
|
|
struct attribute attr;
|
|
|
|
size_t size;
|
|
|
|
void *private;
|
2010-05-13 08:28:57 +07:00
|
|
|
ssize_t (*read)(struct file *, struct kobject *, struct bin_attribute *,
|
2007-06-09 12:57:22 +07:00
|
|
|
char *, loff_t, size_t);
|
2013-08-22 07:47:05 +07:00
|
|
|
ssize_t (*write)(struct file *, struct kobject *, struct bin_attribute *,
|
2007-06-09 12:57:22 +07:00
|
|
|
char *, loff_t, size_t);
|
2010-05-13 08:28:57 +07:00
|
|
|
int (*mmap)(struct file *, struct kobject *, struct bin_attribute *attr,
|
2005-04-17 05:20:36 +07:00
|
|
|
struct vm_area_struct *vma);
|
|
|
|
};
|
|
|
|
|
2010-02-12 19:35:32 +07:00
|
|
|
/**
|
|
|
|
* sysfs_bin_attr_init - initialize a dynamically allocated bin_attribute
|
|
|
|
* @attr: struct bin_attribute to initialize
|
|
|
|
*
|
|
|
|
* Initialize a dynamically allocated struct bin_attribute so we
|
|
|
|
* can make lockdep happy. This is a new requirement for
|
|
|
|
* attributes and initially this is only needed when lockdep is
|
|
|
|
* enabled. Lockdep gives a nice error when your attribute is
|
|
|
|
* added to sysfs if you don't have this.
|
|
|
|
*/
|
2010-03-01 16:38:36 +07:00
|
|
|
#define sysfs_bin_attr_init(bin_attr) sysfs_attr_init(&(bin_attr)->attr)
|
2010-02-12 06:21:53 +07:00
|
|
|
|
2013-07-15 06:05:59 +07:00
|
|
|
/* macros to create static binary attributes easier */
|
|
|
|
#define __BIN_ATTR(_name, _mode, _read, _write, _size) { \
|
|
|
|
.attr = { .name = __stringify(_name), .mode = _mode }, \
|
|
|
|
.read = _read, \
|
|
|
|
.write = _write, \
|
|
|
|
.size = _size, \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define __BIN_ATTR_RO(_name, _size) { \
|
2017-12-20 01:15:06 +07:00
|
|
|
.attr = { .name = __stringify(_name), .mode = 0444 }, \
|
2013-07-15 06:05:59 +07:00
|
|
|
.read = _name##_read, \
|
|
|
|
.size = _size, \
|
2013-07-15 06:05:53 +07:00
|
|
|
}
|
|
|
|
|
2017-12-20 01:15:06 +07:00
|
|
|
#define __BIN_ATTR_RW(_name, _size) \
|
|
|
|
__BIN_ATTR(_name, 0644, _name##_read, _name##_write, _size)
|
2013-07-15 06:05:59 +07:00
|
|
|
|
|
|
|
#define __BIN_ATTR_NULL __ATTR_NULL
|
|
|
|
|
|
|
|
#define BIN_ATTR(_name, _mode, _read, _write, _size) \
|
|
|
|
struct bin_attribute bin_attr_##_name = __BIN_ATTR(_name, _mode, _read, \
|
|
|
|
_write, _size)
|
|
|
|
|
|
|
|
#define BIN_ATTR_RO(_name, _size) \
|
|
|
|
struct bin_attribute bin_attr_##_name = __BIN_ATTR_RO(_name, _size)
|
|
|
|
|
|
|
|
#define BIN_ATTR_RW(_name, _size) \
|
|
|
|
struct bin_attribute bin_attr_##_name = __BIN_ATTR_RW(_name, _size)
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
struct sysfs_ops {
|
2013-08-22 07:47:05 +07:00
|
|
|
ssize_t (*show)(struct kobject *, struct attribute *, char *);
|
|
|
|
ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t);
|
2005-04-17 05:20:36 +07:00
|
|
|
};
|
|
|
|
|
|
|
|
#ifdef CONFIG_SYSFS
|
|
|
|
|
2013-09-12 09:29:05 +07:00
|
|
|
int __must_check sysfs_create_dir_ns(struct kobject *kobj, const void *ns);
|
2007-09-20 14:05:10 +07:00
|
|
|
void sysfs_remove_dir(struct kobject *kobj);
|
2013-09-12 09:29:05 +07:00
|
|
|
int __must_check sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name,
|
|
|
|
const void *new_ns);
|
|
|
|
int __must_check sysfs_move_dir_ns(struct kobject *kobj,
|
|
|
|
struct kobject *new_parent_kobj,
|
|
|
|
const void *new_ns);
|
2015-05-14 04:31:40 +07:00
|
|
|
int __must_check sysfs_create_mount_point(struct kobject *parent_kobj,
|
|
|
|
const char *name);
|
|
|
|
void sysfs_remove_mount_point(struct kobject *parent_kobj,
|
|
|
|
const char *name);
|
2005-04-19 11:57:32 +07:00
|
|
|
|
2013-09-12 09:29:04 +07:00
|
|
|
int __must_check sysfs_create_file_ns(struct kobject *kobj,
|
|
|
|
const struct attribute *attr,
|
|
|
|
const void *ns);
|
2010-01-05 18:48:01 +07:00
|
|
|
int __must_check sysfs_create_files(struct kobject *kobj,
|
|
|
|
const struct attribute **attr);
|
2010-07-02 21:54:05 +07:00
|
|
|
int __must_check sysfs_chmod_file(struct kobject *kobj,
|
2011-07-24 14:40:40 +07:00
|
|
|
const struct attribute *attr, umode_t mode);
|
2013-09-12 09:29:04 +07:00
|
|
|
void sysfs_remove_file_ns(struct kobject *kobj, const struct attribute *attr,
|
|
|
|
const void *ns);
|
kernfs, sysfs, driver-core: implement kernfs_remove_self() and its wrappers
Sometimes it's necessary to implement a node which wants to delete
nodes including itself. This isn't straightforward because of kernfs
active reference. While a file operation is in progress, an active
reference is held and kernfs_remove() waits for all such references to
drain before completing. For a self-deleting node, this is a deadlock
as kernfs_remove() ends up waiting for an active reference that itself
is sitting on top of.
This currently is worked around in the sysfs layer using
sysfs_schedule_callback() which makes such removals asynchronous.
While it works, it's rather cumbersome and inherently breaks
synchronicity of the operation - the file operation which triggered
the operation may complete before the removal is finished (or even
started) and the removal may fail asynchronously. If a removal
operation is immmediately followed by another operation which expects
the specific name to be available (e.g. removal followed by rename
onto the same name), there's no way to make the latter operation
reliable.
The thing is there's no inherent reason for this to be asynchrnous.
All that's necessary to do this synchronous is a dedicated operation
which drops its own active ref and deactivates self. This patch
implements kernfs_remove_self() and its wrappers in sysfs and driver
core. kernfs_remove_self() is to be called from one of the file
operations, drops the active ref the task is holding, removes the self
node, and restores active ref to the dead node so that the ref is
balanced afterwards. __kernfs_remove() is updated so that it takes an
early exit if the target node is already fully removed so that the
active ref restored by kernfs_remove_self() after removal doesn't
confuse the deactivation path.
This makes implementing self-deleting nodes very easy. The normal
removal path doesn't even need to be changed to use
kernfs_remove_self() for the self-deleting node. The method can
invoke kernfs_remove_self() on itself before proceeding the normal
removal path. kernfs_remove() invoked on the node by the normal
deletion path will simply be ignored.
This will replace sysfs_schedule_callback(). A subtle feature of
sysfs_schedule_callback() is that it collapses multiple invocations -
even if multiple removals are triggered, the removal callback is run
only once. An equivalent effect can be achieved by testing the return
value of kernfs_remove_self() - only the one which gets %true return
value should proceed with actual deletion. All other instances of
kernfs_remove_self() will wait till the enclosing kernfs operation
which invoked the winning instance of kernfs_remove_self() finishes
and then return %false. This trivially makes all users of
kernfs_remove_self() automatically show correct synchronous behavior
even when there are multiple concurrent operations - all "echo 1 >
delete" instances will finish only after the whole operation is
completed by one of the instances.
Note that manipulation of active ref is implemented in separate public
functions - kernfs_[un]break_active_protection().
kernfs_remove_self() is the only user at the moment but this will be
used to cater to more complex cases.
v2: For !CONFIG_SYSFS, dummy version kernfs_remove_self() was missing
and sysfs_remove_file_self() had incorrect return type. Fix it.
Reported by kbuild test bot.
v3: kernfs_[un]break_active_protection() separated out from
kernfs_remove_self() and exposed as public API.
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: kbuild test robot <fengguang.wu@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2014-02-04 02:03:01 +07:00
|
|
|
bool sysfs_remove_file_self(struct kobject *kobj, const struct attribute *attr);
|
2010-01-05 18:48:01 +07:00
|
|
|
void sysfs_remove_files(struct kobject *kobj, const struct attribute **attr);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-08-15 12:43:17 +07:00
|
|
|
int __must_check sysfs_create_bin_file(struct kobject *kobj,
|
2009-12-18 20:34:20 +07:00
|
|
|
const struct bin_attribute *attr);
|
|
|
|
void sysfs_remove_bin_file(struct kobject *kobj,
|
|
|
|
const struct bin_attribute *attr);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2007-09-20 14:05:10 +07:00
|
|
|
int __must_check sysfs_create_link(struct kobject *kobj, struct kobject *target,
|
|
|
|
const char *name);
|
2008-06-10 16:09:08 +07:00
|
|
|
int __must_check sysfs_create_link_nowarn(struct kobject *kobj,
|
|
|
|
struct kobject *target,
|
|
|
|
const char *name);
|
2007-09-20 14:05:10 +07:00
|
|
|
void sysfs_remove_link(struct kobject *kobj, const char *name);
|
|
|
|
|
2013-09-12 09:29:06 +07:00
|
|
|
int sysfs_rename_link_ns(struct kobject *kobj, struct kobject *target,
|
|
|
|
const char *old_name, const char *new_name,
|
|
|
|
const void *new_ns);
|
2010-02-13 10:22:25 +07:00
|
|
|
|
2010-03-31 01:31:28 +07:00
|
|
|
void sysfs_delete_link(struct kobject *dir, struct kobject *targ,
|
|
|
|
const char *name);
|
|
|
|
|
2007-09-20 14:05:10 +07:00
|
|
|
int __must_check sysfs_create_group(struct kobject *kobj,
|
|
|
|
const struct attribute_group *grp);
|
2013-08-22 03:47:50 +07:00
|
|
|
int __must_check sysfs_create_groups(struct kobject *kobj,
|
|
|
|
const struct attribute_group **groups);
|
2008-03-21 08:47:52 +07:00
|
|
|
int sysfs_update_group(struct kobject *kobj,
|
|
|
|
const struct attribute_group *grp);
|
2007-09-20 14:05:10 +07:00
|
|
|
void sysfs_remove_group(struct kobject *kobj,
|
|
|
|
const struct attribute_group *grp);
|
2013-08-22 03:47:50 +07:00
|
|
|
void sysfs_remove_groups(struct kobject *kobj,
|
|
|
|
const struct attribute_group **groups);
|
2007-02-21 03:02:44 +07:00
|
|
|
int sysfs_add_file_to_group(struct kobject *kobj,
|
2007-09-20 14:05:10 +07:00
|
|
|
const struct attribute *attr, const char *group);
|
2007-02-21 03:02:44 +07:00
|
|
|
void sysfs_remove_file_from_group(struct kobject *kobj,
|
2007-09-20 14:05:10 +07:00
|
|
|
const struct attribute *attr, const char *group);
|
2010-09-26 04:34:22 +07:00
|
|
|
int sysfs_merge_group(struct kobject *kobj,
|
|
|
|
const struct attribute_group *grp);
|
|
|
|
void sysfs_unmerge_group(struct kobject *kobj,
|
|
|
|
const struct attribute_group *grp);
|
2013-01-26 03:51:13 +07:00
|
|
|
int sysfs_add_link_to_group(struct kobject *kobj, const char *group_name,
|
|
|
|
struct kobject *target, const char *link_name);
|
|
|
|
void sysfs_remove_link_from_group(struct kobject *kobj, const char *group_name,
|
|
|
|
const char *link_name);
|
2015-04-22 23:36:06 +07:00
|
|
|
int __compat_only_sysfs_link_entry_to_kobj(struct kobject *kobj,
|
|
|
|
struct kobject *target_kobj,
|
|
|
|
const char *target_name);
|
2007-02-21 03:02:44 +07:00
|
|
|
|
2008-09-26 06:45:13 +07:00
|
|
|
void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr);
|
2010-03-31 01:31:26 +07:00
|
|
|
|
2008-07-16 05:58:04 +07:00
|
|
|
int __must_check sysfs_init(void);
|
2006-08-15 12:43:23 +07:00
|
|
|
|
2014-02-08 01:32:07 +07:00
|
|
|
static inline void sysfs_enable_ns(struct kernfs_node *kn)
|
|
|
|
{
|
|
|
|
return kernfs_enable_ns(kn);
|
|
|
|
}
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
#else /* CONFIG_SYSFS */
|
|
|
|
|
2013-09-12 09:29:05 +07:00
|
|
|
static inline int sysfs_create_dir_ns(struct kobject *kobj, const void *ns)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-09-20 14:05:10 +07:00
|
|
|
static inline void sysfs_remove_dir(struct kobject *kobj)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2013-09-12 09:29:05 +07:00
|
|
|
static inline int sysfs_rename_dir_ns(struct kobject *kobj,
|
|
|
|
const char *new_name, const void *new_ns)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2008-07-04 08:05:28 +07:00
|
|
|
return 0;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
2013-09-12 09:29:05 +07:00
|
|
|
static inline int sysfs_move_dir_ns(struct kobject *kobj,
|
|
|
|
struct kobject *new_parent_kobj,
|
|
|
|
const void *new_ns)
|
2006-11-20 23:07:51 +07:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-05-14 04:31:40 +07:00
|
|
|
static inline int sysfs_create_mount_point(struct kobject *parent_kobj,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void sysfs_remove_mount_point(struct kobject *parent_kobj,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2013-09-12 09:29:04 +07:00
|
|
|
static inline int sysfs_create_file_ns(struct kobject *kobj,
|
|
|
|
const struct attribute *attr,
|
|
|
|
const void *ns)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-01-05 18:48:01 +07:00
|
|
|
static inline int sysfs_create_files(struct kobject *kobj,
|
|
|
|
const struct attribute **attr)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-09-20 14:05:10 +07:00
|
|
|
static inline int sysfs_chmod_file(struct kobject *kobj,
|
2011-07-24 14:40:40 +07:00
|
|
|
const struct attribute *attr, umode_t mode)
|
2005-04-19 11:57:32 +07:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2013-09-12 09:29:04 +07:00
|
|
|
static inline void sysfs_remove_file_ns(struct kobject *kobj,
|
|
|
|
const struct attribute *attr,
|
|
|
|
const void *ns)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
kernfs, sysfs, driver-core: implement kernfs_remove_self() and its wrappers
Sometimes it's necessary to implement a node which wants to delete
nodes including itself. This isn't straightforward because of kernfs
active reference. While a file operation is in progress, an active
reference is held and kernfs_remove() waits for all such references to
drain before completing. For a self-deleting node, this is a deadlock
as kernfs_remove() ends up waiting for an active reference that itself
is sitting on top of.
This currently is worked around in the sysfs layer using
sysfs_schedule_callback() which makes such removals asynchronous.
While it works, it's rather cumbersome and inherently breaks
synchronicity of the operation - the file operation which triggered
the operation may complete before the removal is finished (or even
started) and the removal may fail asynchronously. If a removal
operation is immmediately followed by another operation which expects
the specific name to be available (e.g. removal followed by rename
onto the same name), there's no way to make the latter operation
reliable.
The thing is there's no inherent reason for this to be asynchrnous.
All that's necessary to do this synchronous is a dedicated operation
which drops its own active ref and deactivates self. This patch
implements kernfs_remove_self() and its wrappers in sysfs and driver
core. kernfs_remove_self() is to be called from one of the file
operations, drops the active ref the task is holding, removes the self
node, and restores active ref to the dead node so that the ref is
balanced afterwards. __kernfs_remove() is updated so that it takes an
early exit if the target node is already fully removed so that the
active ref restored by kernfs_remove_self() after removal doesn't
confuse the deactivation path.
This makes implementing self-deleting nodes very easy. The normal
removal path doesn't even need to be changed to use
kernfs_remove_self() for the self-deleting node. The method can
invoke kernfs_remove_self() on itself before proceeding the normal
removal path. kernfs_remove() invoked on the node by the normal
deletion path will simply be ignored.
This will replace sysfs_schedule_callback(). A subtle feature of
sysfs_schedule_callback() is that it collapses multiple invocations -
even if multiple removals are triggered, the removal callback is run
only once. An equivalent effect can be achieved by testing the return
value of kernfs_remove_self() - only the one which gets %true return
value should proceed with actual deletion. All other instances of
kernfs_remove_self() will wait till the enclosing kernfs operation
which invoked the winning instance of kernfs_remove_self() finishes
and then return %false. This trivially makes all users of
kernfs_remove_self() automatically show correct synchronous behavior
even when there are multiple concurrent operations - all "echo 1 >
delete" instances will finish only after the whole operation is
completed by one of the instances.
Note that manipulation of active ref is implemented in separate public
functions - kernfs_[un]break_active_protection().
kernfs_remove_self() is the only user at the moment but this will be
used to cater to more complex cases.
v2: For !CONFIG_SYSFS, dummy version kernfs_remove_self() was missing
and sysfs_remove_file_self() had incorrect return type. Fix it.
Reported by kbuild test bot.
v3: kernfs_[un]break_active_protection() separated out from
kernfs_remove_self() and exposed as public API.
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: kbuild test robot <fengguang.wu@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2014-02-04 02:03:01 +07:00
|
|
|
static inline bool sysfs_remove_file_self(struct kobject *kobj,
|
|
|
|
const struct attribute *attr)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-01-05 18:48:01 +07:00
|
|
|
static inline void sysfs_remove_files(struct kobject *kobj,
|
|
|
|
const struct attribute **attr)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2007-09-20 14:05:10 +07:00
|
|
|
static inline int sysfs_create_bin_file(struct kobject *kobj,
|
2009-12-18 20:34:20 +07:00
|
|
|
const struct bin_attribute *attr)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-02-20 08:39:02 +07:00
|
|
|
static inline void sysfs_remove_bin_file(struct kobject *kobj,
|
2009-12-18 20:34:20 +07:00
|
|
|
const struct bin_attribute *attr)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2007-09-20 14:05:10 +07:00
|
|
|
static inline int sysfs_create_link(struct kobject *kobj,
|
|
|
|
struct kobject *target, const char *name)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-06-10 16:09:08 +07:00
|
|
|
static inline int sysfs_create_link_nowarn(struct kobject *kobj,
|
|
|
|
struct kobject *target,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-09-20 14:05:10 +07:00
|
|
|
static inline void sysfs_remove_link(struct kobject *kobj, const char *name)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2013-09-12 09:29:06 +07:00
|
|
|
static inline int sysfs_rename_link_ns(struct kobject *k, struct kobject *t,
|
|
|
|
const char *old_name,
|
|
|
|
const char *new_name, const void *ns)
|
2010-02-13 10:22:25 +07:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-03-31 01:31:28 +07:00
|
|
|
static inline void sysfs_delete_link(struct kobject *k, struct kobject *t,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2007-09-20 14:05:10 +07:00
|
|
|
static inline int sysfs_create_group(struct kobject *kobj,
|
|
|
|
const struct attribute_group *grp)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-08-28 07:24:49 +07:00
|
|
|
static inline int sysfs_create_groups(struct kobject *kobj,
|
|
|
|
const struct attribute_group **groups)
|
|
|
|
{
|
2013-08-28 23:51:41 +07:00
|
|
|
return 0;
|
2013-08-28 07:24:49 +07:00
|
|
|
}
|
|
|
|
|
2008-04-30 23:01:17 +07:00
|
|
|
static inline int sysfs_update_group(struct kobject *kobj,
|
|
|
|
const struct attribute_group *grp)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-09-20 14:05:10 +07:00
|
|
|
static inline void sysfs_remove_group(struct kobject *kobj,
|
|
|
|
const struct attribute_group *grp)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2013-08-28 07:24:49 +07:00
|
|
|
static inline void sysfs_remove_groups(struct kobject *kobj,
|
|
|
|
const struct attribute_group **groups)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2007-02-21 03:02:44 +07:00
|
|
|
static inline int sysfs_add_file_to_group(struct kobject *kobj,
|
|
|
|
const struct attribute *attr, const char *group)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void sysfs_remove_file_from_group(struct kobject *kobj,
|
2007-03-01 19:40:21 +07:00
|
|
|
const struct attribute *attr, const char *group)
|
2007-02-21 03:02:44 +07:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2010-09-26 04:34:22 +07:00
|
|
|
static inline int sysfs_merge_group(struct kobject *kobj,
|
|
|
|
const struct attribute_group *grp)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void sysfs_unmerge_group(struct kobject *kobj,
|
|
|
|
const struct attribute_group *grp)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2013-01-26 03:51:13 +07:00
|
|
|
static inline int sysfs_add_link_to_group(struct kobject *kobj,
|
|
|
|
const char *group_name, struct kobject *target,
|
|
|
|
const char *link_name)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void sysfs_remove_link_from_group(struct kobject *kobj,
|
|
|
|
const char *group_name, const char *link_name)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2015-04-22 23:36:06 +07:00
|
|
|
static inline int __compat_only_sysfs_link_entry_to_kobj(
|
|
|
|
struct kobject *kobj,
|
|
|
|
struct kobject *target_kobj,
|
|
|
|
const char *target_name)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-09-26 06:45:13 +07:00
|
|
|
static inline void sysfs_notify(struct kobject *kobj, const char *dir,
|
|
|
|
const char *attr)
|
2006-03-20 13:53:53 +07:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2006-08-15 12:43:23 +07:00
|
|
|
static inline int __must_check sysfs_init(void)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-02-08 01:32:07 +07:00
|
|
|
static inline void sysfs_enable_ns(struct kernfs_node *kn)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
#endif /* CONFIG_SYSFS */
|
|
|
|
|
2013-09-12 09:29:04 +07:00
|
|
|
static inline int __must_check sysfs_create_file(struct kobject *kobj,
|
|
|
|
const struct attribute *attr)
|
|
|
|
{
|
|
|
|
return sysfs_create_file_ns(kobj, attr, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void sysfs_remove_file(struct kobject *kobj,
|
|
|
|
const struct attribute *attr)
|
|
|
|
{
|
2014-04-16 16:56:45 +07:00
|
|
|
sysfs_remove_file_ns(kobj, attr, NULL);
|
2013-09-12 09:29:04 +07:00
|
|
|
}
|
|
|
|
|
2013-09-12 09:29:06 +07:00
|
|
|
static inline int sysfs_rename_link(struct kobject *kobj, struct kobject *target,
|
|
|
|
const char *old_name, const char *new_name)
|
|
|
|
{
|
|
|
|
return sysfs_rename_link_ns(kobj, target, old_name, new_name, NULL);
|
|
|
|
}
|
|
|
|
|
2013-12-12 02:11:53 +07:00
|
|
|
static inline void sysfs_notify_dirent(struct kernfs_node *kn)
|
2013-11-29 02:54:30 +07:00
|
|
|
{
|
2013-12-12 02:11:53 +07:00
|
|
|
kernfs_notify(kn);
|
2013-11-29 02:54:30 +07:00
|
|
|
}
|
|
|
|
|
2013-12-12 02:11:53 +07:00
|
|
|
static inline struct kernfs_node *sysfs_get_dirent(struct kernfs_node *parent,
|
2017-05-21 15:58:07 +07:00
|
|
|
const char *name)
|
2013-09-12 10:19:13 +07:00
|
|
|
{
|
2013-12-12 02:11:53 +07:00
|
|
|
return kernfs_find_and_get(parent, name);
|
2013-09-12 10:19:13 +07:00
|
|
|
}
|
|
|
|
|
2013-12-12 02:11:53 +07:00
|
|
|
static inline struct kernfs_node *sysfs_get(struct kernfs_node *kn)
|
2013-11-29 02:54:27 +07:00
|
|
|
{
|
2013-12-12 02:11:53 +07:00
|
|
|
kernfs_get(kn);
|
|
|
|
return kn;
|
2013-11-29 02:54:30 +07:00
|
|
|
}
|
|
|
|
|
2013-12-12 02:11:53 +07:00
|
|
|
static inline void sysfs_put(struct kernfs_node *kn)
|
2013-11-29 02:54:30 +07:00
|
|
|
{
|
2013-12-12 02:11:53 +07:00
|
|
|
kernfs_put(kn);
|
2013-11-29 02:54:27 +07:00
|
|
|
}
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
#endif /* _SYSFS_H_ */
|