mirror of
https://github.com/clearlinux/clear-linux-documentation.git
synced 2026-06-30 09:46:42 +00:00
Merge pull request #408 from mvincerx/mv-kernel-development
kernel-dev: Editorial revisions, Sphinx corrections, and BKMs.
This commit is contained in:
@@ -1,49 +1,44 @@
|
||||
.. _kernel-development:
|
||||
|
||||
Kernel development on |CL-ATTR|
|
||||
###############################
|
||||
Kernel development
|
||||
##################
|
||||
|
||||
This document shows how to obtain and compile a Linux kernel source
|
||||
using the |CL-ATTR| development tooling.
|
||||
This document shows how to obtain and compile a Linux* kernel source
|
||||
using |CL-ATTR| development tooling.
|
||||
|
||||
The `kernels available in Clear Linux`_ aim to be performant and practical.
|
||||
In some cases, it may be necessary to modify the kernel to suit your specific
|
||||
needs or test new kernel code as a developer.
|
||||
The `kernels available`_ in |CL| aim to be performant and practical. In some
|
||||
cases, it may be necessary to modify the kernel to suit your specific needs
|
||||
or test new kernel code as a developer.
|
||||
|
||||
.. contents:: :local:
|
||||
:depth: 2
|
||||
.. contents::
|
||||
:local:
|
||||
:depth: 1
|
||||
:backlinks: top
|
||||
|
||||
Source RPM files (SRPM) are also available for all |CL| kernels, and can be
|
||||
used for development instead. The latest source RPM files are available at:
|
||||
`https://download.clearlinux.org/current/source/SRPMS/`_
|
||||
|
||||
Source RPM files (SRPM) are also available for all |CL| kernels, and can be
|
||||
used for development instead. Select this link to view the latest `source RPM files`_.
|
||||
|
||||
Request changes be included with the |CL| kernel
|
||||
************************************************
|
||||
|
||||
If the kernel modification you need is already open source and likely to be
|
||||
If the kernel modification you need is already open source and likely to be
|
||||
useful to others, consider submitting a request to include it in the
|
||||
|CL| kernels.
|
||||
|
||||
If your change request is accepted, you do not need to maintain your own
|
||||
modified kernel.
|
||||
|
||||
Make enhancement requests to the |CL| distribution `on GitHub`_ .
|
||||
|CL| kernels.If your change request is accepted, you do not need to maintain your own modified kernel.
|
||||
|
||||
Make enhancement requests to the |CL| `distribution on GitHub`_ .
|
||||
|
||||
Set up kernel development environment
|
||||
*************************************
|
||||
|
||||
In some cases, it may be necessary to modify the kernel to suit your specific
|
||||
needs or test new kernel code as a developer.
|
||||
In some cases, it may be necessary to modify the kernel to suit your specific
|
||||
needs or to test new kernel code.
|
||||
|
||||
You can build and install a custom kernel, however you must:
|
||||
You can build and install a custom kernel; however you must:
|
||||
|
||||
* Disable Secure Boot
|
||||
* Maintain any updates to the kernel going forward
|
||||
|
||||
To create a custom kernel, start with the |CL| development environment.
|
||||
To create a custom kernel, start with the |CL| development environment.
|
||||
Then make changes to the kernel, build it, and install it.
|
||||
|
||||
|
||||
@@ -54,22 +49,20 @@ Install the |CL| development tooling framework
|
||||
:start-after: install-tooling-after-header:
|
||||
:end-before: install-tooling-end:
|
||||
|
||||
|
||||
|
||||
Clone the kernel package
|
||||
Clone the kernel package
|
||||
========================
|
||||
Clone the existing kernel package repository from |CL| as a starting point.
|
||||
|
||||
#. Clone the Linux kernel package from |CL|.
|
||||
Using the :command:`make clone_<PACKAGENAME>` command within the :file:`clearlinux/`
|
||||
directory clones the package from the `clearlinux-pkgs GitHub`_.
|
||||
#. Clone the Linux kernel package from |CL|. Using the
|
||||
:command:`make clone_<PACKAGENAME>` command in the
|
||||
:file:`clearlinux/` directory clones the package from the
|
||||
`clearlinux-pkgs GitHub`_.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd ~/clearlinux
|
||||
make clone_linux
|
||||
|
||||
|
||||
#. Navigate into the cloned package directory.
|
||||
|
||||
.. code-block:: bash
|
||||
@@ -77,31 +70,24 @@ Clone the existing kernel package repository from |CL| as a starting point.
|
||||
cd ~/clearlinux/packages/linux
|
||||
|
||||
|
||||
The "linux" package is the kernel that comes with |CL| in the kernel-native
|
||||
bundle.You can alternatively use a different kernel variant as the base for
|
||||
The "linux" package is the kernel that comes with |CL| in the `kernel-native`
|
||||
bundle. Alternatively, you can use a different kernel variant as the base for
|
||||
modification. For a list of kernel package names which you can clone instead,
|
||||
see the `clearlinux-pkgs GitHub`_.
|
||||
|
||||
.. note::
|
||||
|
||||
The latest version of the |CL| kernel package is pulled as a starting
|
||||
point. An older version can pulled by switching to different git tag with
|
||||
:command:`git checkout tag/<TAG_NAME>` tag.
|
||||
The latest version of the |CL| kernel package is pulled as a starting
|
||||
point. An older version can pulled by switching to different git tag by using :command:`git checkout tag/<TAG_NAME>`.
|
||||
|
||||
|
||||
|
||||
|
||||
Change the kernel version
|
||||
Change the kernel version
|
||||
=========================
|
||||
|
||||
|CL| tends to use the latest kernel available from `kernel.org`_, the Linux
|
||||
upstream. The kernel version that will be built can be changed in the
|
||||
RPM SPEC file.
|
||||
|
||||
While most packages in Clear Linux are typically packaged using
|
||||
`autospec`_, the kernel is not. This means control files provided
|
||||
by autospec are not available and changes must be made manually.
|
||||
|
||||
|CL| tends to use the latest kernel available from `kernel.org`_, the Linux
|
||||
upstream. The kernel version that will be built can be changed in the
|
||||
RPM SPEC file. While most packages in Clear Linux are typically packaged
|
||||
using :ref:`autospec-about`, the kernel is not. This means control files
|
||||
provided by autospec are not available and changes must be made manually.
|
||||
|
||||
#. Open the Linux kernel package RPM SPEC file in an editor.
|
||||
|
||||
@@ -109,15 +95,14 @@ by autospec are not available and changes must be made manually.
|
||||
|
||||
$EDITOR linux.spec
|
||||
|
||||
|
||||
#. Modify the Version, Release, and Source0 URL entries at the top of the
|
||||
#. Modify the Version, Release, and Source0 URL entries at the top of the
|
||||
file to change the version of Linux kernel that will be compiled.
|
||||
|
||||
A list of current and available kernel release can be found on
|
||||
A list of current and available kernel release can be found on
|
||||
`kernel.org`_.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
|
||||
Name: linux
|
||||
Version: 4.20.8
|
||||
Release: 696
|
||||
@@ -132,41 +117,33 @@ by autospec are not available and changes must be made manually.
|
||||
%define ktarget native
|
||||
|
||||
.. note::
|
||||
- Consider changing the Name from *linux* in the RPM spec file to easily
|
||||
identify a modified kernel.
|
||||
|
||||
- Consider changing the ktarget from *native* in the RPM spec file to easily
|
||||
identify a modified kernel.
|
||||
- Consider changing the Name from *linux* in the RPM spec file to easily identify a modified kernel.
|
||||
|
||||
- Consider changing the ktarget from *native* in the RPM spec file to easily identify a modified kernel.
|
||||
|
||||
#. Commit and save the changes to the file.
|
||||
|
||||
|
||||
Pull a copy of the Linux kernel source code
|
||||
===========================================
|
||||
|
||||
You will need to obtain a local copy of the source code to make modifications
|
||||
against.
|
||||
Obtain a local copy of the source code to make modifications against.
|
||||
|
||||
|
||||
#. Run make sources to pull the kernel source code specified in the RPM
|
||||
SPEC file. In the example, it downloads the
|
||||
:file:`linux-4.20.8.tar.xz` file.
|
||||
#. Run make sources to pull the kernel source code specified in the RPM
|
||||
SPEC file. In the example, it downloads the :file:`linux-4.20.8.tar.xz` file.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
make sources
|
||||
|
||||
|
||||
#. Extract the kernel source code archive. This will create a working copy of
|
||||
the Linux source which you can modify.
|
||||
#. Extract the kernel source code archive. This will create a working copy
|
||||
of the Linux source that you can modify.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
tar -xvf linux-4.20.8.tar.xz
|
||||
|
||||
|
||||
#. Navigate to the extracted directory. In this example, it has been
|
||||
#. Navigate to the extracted directory. In this example, it has been
|
||||
extracted into a :file:`linux-4.20.8` directory.
|
||||
|
||||
.. code-block:: bash
|
||||
@@ -177,94 +154,84 @@ against.
|
||||
Customize the Linux kernel source
|
||||
*********************************
|
||||
|
||||
After the kernel sources have been obtained, customizations to the kernel
|
||||
configuration or source code can be made for inclusion with the kernel
|
||||
build.
|
||||
After the kernel sources have been obtained, customizations to the kernel
|
||||
configuration or source code can be made for inclusion with the kernel
|
||||
build. These customizations are optional.
|
||||
|
||||
These customizations are optional.
|
||||
|
||||
|
||||
Modify kernel configuration
|
||||
Modify kernel configuration
|
||||
===========================
|
||||
|
||||
The kernel source has many configuration options available to pick
|
||||
support for different hardware and software features.
|
||||
The kernel source has many configuration options available to pick support for different hardware and software features.
|
||||
|
||||
These configuration values must be provided in the :file:`.config` file at
|
||||
compile time.
|
||||
|
||||
You will need to make modifications to the :file:`.config` file, and include
|
||||
it in the kernel package.
|
||||
These configuration values must be provided in the :file:`.config` file at
|
||||
compile time. You will need to make modifications to the :file:`.config`
|
||||
file, and include it in the kernel package.
|
||||
|
||||
|
||||
#. Make sure you have followed the steps to
|
||||
`Pull a copy of the Linux kernel source code`_ and are in the kernel
|
||||
#. Make sure you have followed the steps to
|
||||
`Pull a copy of the Linux kernel source code`_ and are in the kernel
|
||||
source working directory.
|
||||
|
||||
|
||||
#. If you have an existing :file:`.config` file from an old kernel, copy it
|
||||
#. If you have an existing :file:`.config` file from an old kernel, copy it
|
||||
into the working directory as :file:`.config` for comparison.
|
||||
Otherwise, use the |CL| kernel configuration file as template
|
||||
Otherwise, use the |CL| kernel configuration file as template
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cp ~/clearlinux/packages/linux/config .config
|
||||
|
||||
|
||||
#. Make any desired changes to the :file:`.config` using a kernel
|
||||
#. Make any desired changes to the :file:`.config` using a kernel
|
||||
configuration tool. Below are some popular options:
|
||||
|
||||
- :command:`$EDITOR .config` - the .config file can be directly edited for
|
||||
simple changes with names that are already known.
|
||||
- :command:`$EDITOR .config` - the .config file can be directly edited
|
||||
for simple changes with names that are already known.
|
||||
|
||||
- :command:`make config` - a text-based tool that asks questions
|
||||
one-by-one to decide configuration options.
|
||||
- :command:`make config` - a text-based tool that asks questions
|
||||
one-by-one to decide configuration options.
|
||||
|
||||
- :command:`make menuconfig` - a terminal user interface that provides
|
||||
- :command:`make menuconfig` - a terminal user interface that provides
|
||||
menus to decide configuration options.
|
||||
|
||||
- :command:`make xconfig` - a graphical user interface that provides
|
||||
- :command:`make xconfig` - a graphical user interface that provides
|
||||
tree views to decide configuration options.
|
||||
|
||||
|
||||
More configuration tools can be found by looking at the make help:
|
||||
More configuration tools can be found by looking at the make help:
|
||||
:command:`make help | grep config`
|
||||
|
||||
|
||||
#. Commit and save the changes to the :file:`.config` file.
|
||||
|
||||
|
||||
#. Copy the :file:`.config` file from the kernel source directory into
|
||||
#. Copy the :file:`.config` file from the kernel source directory into
|
||||
the kernel package directory as :file:`config` for inclusion in the build.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cp .config ../config
|
||||
|
||||
|
||||
|
||||
Modify kernel source code
|
||||
Modify kernel source code
|
||||
=========================
|
||||
|
||||
Changes to kernel code are applied with patch files. Patch files are
|
||||
Changes to kernel code are applied with patch files. Patch files are
|
||||
formatted git commits that can be applied to the main source code.
|
||||
|
||||
You will need to obtain a copy of the source code,
|
||||
make modifications, generate patch file(s), and add them to the RPM SPEC
|
||||
make modifications, generate patch file(s), and add them to the RPM SPEC
|
||||
file for inclusion during the kernel build.
|
||||
|
||||
If you have a large number of patches or a more complex workflow,
|
||||
consider using a patch management tool in addition to Git such as
|
||||
`Quilt`_.
|
||||
If you have a large number of patches or a more complex workflow,
|
||||
consider using a patch management tool in addition to Git such as
|
||||
`Quilt`_.
|
||||
|
||||
|
||||
#. Make sure you have followed the steps to
|
||||
`Pull a copy of the Linux kernel source code`_ and are in the kernel
|
||||
#. Make sure you have followed the steps to
|
||||
`Pull a copy of the Linux kernel source code`_ and are in the kernel
|
||||
source working directory.
|
||||
|
||||
|
||||
#. Initialize the kernel source directory as a new git repo and create a
|
||||
commit with all the existing source files to begin tracking changes.
|
||||
#. Initialize the kernel source directory as a new git repo and create a
|
||||
commit with all the existing source files to begin tracking changes.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@@ -273,7 +240,7 @@ consider using a patch management tool in addition to Git such as
|
||||
git commit -m "Initial commit of Linux kernel source"
|
||||
|
||||
|
||||
#. Apply patches provided by the |CL| kernel package to the kernel source
|
||||
#. Apply patches provided by the |CL| kernel package to the kernel source
|
||||
in the working directory.
|
||||
|
||||
.. code-block:: bash
|
||||
@@ -284,7 +251,7 @@ consider using a patch management tool in addition to Git such as
|
||||
#. Make any of your desired code changes to the Linux source code files.
|
||||
|
||||
|
||||
#. Track and commit your changes to the local git repo.
|
||||
#. Track and commit your changes to the local git repo.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@@ -292,30 +259,28 @@ consider using a patch management tool in addition to Git such as
|
||||
git commit -m "My patch for driver A" <FILENAME>
|
||||
|
||||
|
||||
#. Generate a patch file based on your git commits.
|
||||
<n> represents the number of local commits to create patch file.
|
||||
See the `git-format-patch Documentation`_ for detailed information
|
||||
#. Generate a patch file based on your git commits.
|
||||
<n> represents the number of local commits to create patch file.
|
||||
See the `git-format-patch Documentation`_ for detailed information
|
||||
on using :command:`git format-patch`
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
|
||||
git format-patch -<n>
|
||||
|
||||
|
||||
#. Copy the patch files from the patches directory in the linux
|
||||
#. Copy the patch files from the patches directory in the linux
|
||||
source tree to the RPM build directory.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
|
||||
cp *.patch ~/clearlinux/packages/linux/
|
||||
|
||||
|
||||
#. Navigate back to the RPM build directory.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd ~/clearlinux/packages/linux/
|
||||
|
||||
cd ~/clearlinux/packages/linux/
|
||||
|
||||
#. Open the Linux kernel package RPM SPEC file in an editor.
|
||||
|
||||
@@ -323,11 +288,10 @@ consider using a patch management tool in addition to Git such as
|
||||
|
||||
$EDITOR linux.spec
|
||||
|
||||
|
||||
#. Locate the section of the SPEC file that contains existing patch
|
||||
variable definitions and append your patch file name. Ensure the
|
||||
patch number does not collide with an existing patch.
|
||||
In this example, the patch file is called
|
||||
#. Locate the section of the SPEC file that contains existing patch
|
||||
variable definitions and append your patch file name. Ensure the
|
||||
patch number does not collide with an existing patch.
|
||||
In this example, the patch file is called
|
||||
:file:`2001-my-patch-for-driver-A.patch`
|
||||
|
||||
.. code-block:: bash
|
||||
@@ -347,7 +311,7 @@ consider using a patch management tool in addition to Git such as
|
||||
Patch2001: 2001-my-patch-for-driver-A.patch
|
||||
|
||||
|
||||
#. Locate the section of the SPEC file further down that contains
|
||||
#. Locate the section of the SPEC file further down that contains
|
||||
patch application and append your patch file number used in the step above.
|
||||
In this example, patch2001 is added.
|
||||
|
||||
@@ -368,15 +332,13 @@ consider using a patch management tool in addition to Git such as
|
||||
|
||||
#. Commit and save the changes to the RPM SPEC file.
|
||||
|
||||
|
||||
|
||||
Modify kernel boot parameters
|
||||
=============================
|
||||
The kernel boot options are passed from the bootloader to the kernel with
|
||||
command-line parameters.
|
||||
The kernel boot options are passed from the bootloader to the kernel with
|
||||
command-line parameters.
|
||||
|
||||
While temporary changes can be made to kernel parameters on a running
|
||||
system or on a during boot, you can also modify the default parameters that
|
||||
While temporary changes can be made to kernel parameters on a running
|
||||
system or on a during boot, you can also modify the default parameters that
|
||||
are persistent and distributed with a customized kernel.
|
||||
|
||||
|
||||
@@ -387,64 +349,54 @@ are persistent and distributed with a customized kernel.
|
||||
$EDITOR cmdline
|
||||
|
||||
|
||||
#. Make any desired change to the kernel parameters.
|
||||
For example, you can remove the :command:`quiet` parameter to see more
|
||||
#. Make any desired change to the kernel parameters.
|
||||
For example, you can remove the :command:`quiet` parameter to see more
|
||||
verbose output of kernel log messages during the boot process.
|
||||
|
||||
|
||||
#. Commit and save the changes to the :file:`cmdline` file.
|
||||
|
||||
See the
|
||||
`Kernel parameters documentation`_ for a list of available parameters.
|
||||
|
||||
|
||||
See the `Kernel parameters documentation`_ for a list of available
|
||||
parameters.
|
||||
|
||||
Build and install the kernel
|
||||
****************************
|
||||
After changes have been made to the kernel source and RPM SPEC file,
|
||||
After changes have been made to the kernel source and RPM SPEC file,
|
||||
the kernel is ready to be compiled and packaged into an RPM.
|
||||
|
||||
The |CL| development tooling makes use of :command:`mock` environments to
|
||||
isolate building of packages in a sanitized workspace.
|
||||
The |CL| development tooling makes use of :command:`mock` environments to
|
||||
isolate building of packages in a sanitized workspace.
|
||||
|
||||
|
||||
|
||||
#. Start the compilation process by issuing the :command:`make build` command.
|
||||
This process is typically resource intensive and will take a while.
|
||||
#. Start the compilation process by issuing the :command:`make build`
|
||||
command. This process is typically resource intensive and will take a while.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
|
||||
make build
|
||||
|
||||
|
||||
.. note::
|
||||
The `ccache plugin for mock`_ can be enabled to help speed up any future
|
||||
rebuilds of the kernel package by caching compiler outputs and reusing
|
||||
them.
|
||||
The `ccache plugin for mock`_ can be enabled to help speed up any future rebuilds of the kernel package by caching compiler outputs and reusing them.
|
||||
|
||||
|
||||
#. The result will be multiple :file:`.rpm` files in the :file:`rpms`
|
||||
directory as output.
|
||||
#. The result will be multiple :file:`.rpm` files in the :file:`rpms`
|
||||
directory as output.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
|
||||
ls rpms/
|
||||
|
||||
The kernel RPM will be named :file:`linux<NAME>-<VERSION>-<RELEASE>.x86_64.rpm`
|
||||
The kernel RPM will be named
|
||||
:file:`linux<NAME>-<VERSION>-<RELEASE>.x86_64.rpm`
|
||||
|
||||
|
||||
#. The kernel RPM file can be input to the `mixer tool`_ to create a custom
|
||||
bundle and mix of |CL|.
|
||||
#. The kernel RPM file can be input to the :ref:`mixer` to create a
|
||||
custom bundle and mix of |CL|.
|
||||
|
||||
Alternatively, the kernel RPM bundle can be installed manually on a local
|
||||
machine for testing. This approach works well for individual development or
|
||||
testing. For a more scalable and customizable approach, consider using the
|
||||
:ref:`mixer` to provide a custom kernel with updates.
|
||||
|
||||
|
||||
|
||||
Alternatively, the kernel RPM bundle can be installed manually on a local
|
||||
machine for testing. This approach works well for individual development or
|
||||
testing. For a more scalable and customizable approach, consider using the
|
||||
`mixer tool`_ to provide a custom kernel with updates.
|
||||
|
||||
1. Install the kernel onto the local system by extracting the RPM with the
|
||||
1. Install the kernel onto the local system by extracting the RPM with the
|
||||
:command:`rpm2cpio` command.
|
||||
|
||||
.. code-block:: bash
|
||||
@@ -468,23 +420,28 @@ testing. For a more scalable and customizable approach, consider using the
|
||||
|
||||
uname -a
|
||||
|
||||
|
||||
|
||||
Related topics
|
||||
**************
|
||||
|
||||
* :ref:`kernel-modules`
|
||||
* :ref:`mixer`
|
||||
|
||||
.. _`kernels available in Clear Linux`: https://clearlinux.org/documentation/clear-linux/reference/compatible-kernels
|
||||
.. _`on GitHub`: https://github.com/clearlinux/distribution/issues/new/choose
|
||||
.. _`https://download.clearlinux.org/current/source/SRPMS/`: https://download.clearlinux.org/current/source/SRPMS/
|
||||
.. _`mixer tool`: https://clearlinux.org/features/mixer-tool
|
||||
.. _user-setup script: https://github.com/clearlinux/common/blob/master/user-setup.sh
|
||||
.. _`Quilt`: http://savannah.nongnu.org/projects/quilt
|
||||
.. _`clearlinux-pkgs GitHub`: https://github.com/clearlinux-pkgs?&q=linux
|
||||
.. _`kernel.org`: https://www.kernel.org/
|
||||
.. _`Kernel parameters documentation`: https://www.kernel.org/doc/Documentation/admin-guide/kernel-parameters.txt
|
||||
.. _`ccache plugin for mock`: https://fedoraproject.org/wiki/Mock/Plugin/CCache?rd=Subprojects/Mock/Plugin/CCache
|
||||
.. _`autospec`: https://clearlinux.org/documentation/clear-linux/concepts/autospec-about
|
||||
.. _`git-format-patch Documentation`: https://git-scm.com/docs/git-format-patch
|
||||
.. _kernels available: https://clearlinux.org/documentation/clear-linux/reference/compatible-kernels
|
||||
|
||||
.. _distribution on GitHub: https://github.com/clearlinux/distribution/issues/new/choose
|
||||
|
||||
.. _source RPM files: https://download.clearlinux.org/current/source/SRPMS/
|
||||
|
||||
.. _Quilt: http://savannah.nongnu.org/projects/quilt
|
||||
|
||||
.. _clearlinux-pkgs GitHub: https://github.com/clearlinux-pkgs
|
||||
|
||||
.. _kernel.org: https://www.kernel.org/
|
||||
|
||||
.. _Kernel parameters documentation: https://www.kernel.org/doc/Documentation/admin-guide/kernel-parameters.txt
|
||||
|
||||
.. _ccache plugin for mock: https://fedoraproject.org/wiki/Mock/Plugin/CCache?rd=Subprojects/Mock/Plugin/CCache
|
||||
|
||||
.. _git-format-patch Documentation: https://git-scm.com/docs/git-format-patch
|
||||
|
||||
.. _user-setup script: https://github.com/clearlinux/common/blob/master/user-setup.sh
|
||||
Reference in New Issue
Block a user